/** * Returns true if any of the outputs is marked as spent. */ public boolean isAnyOutputSpent() { for (TransactionOutput output : outputs) { if (!output.isAvailableForSpending()) return true; } return false; }
/** * Returns true if any of the outputs is marked as spent. */ public boolean isAnyOutputSpent() { for (TransactionOutput output : outputs) { if (!output.isAvailableForSpending()) return true; } return false; }
/** * Returns true if any of the outputs is marked as spent. */ public boolean isAnyOutputSpent() { for (TransactionOutput output : outputs) { if (!output.isAvailableForSpending()) return true; } return false; }
/** * Returns true if any of the outputs is marked as spent. */ public boolean isAnyOutputSpent() { for (TransactionOutput output : outputs) { if (!output.isAvailableForSpending()) return true; } return false; }
/** * Returns false if this transaction has at least one output that is owned by the given wallet and unspent, true * otherwise. */ public boolean isEveryOwnedOutputSpent(TransactionBag transactionBag) { for (TransactionOutput output : outputs) { if (output.isAvailableForSpending() && output.isMineOrWatched(transactionBag)) return false; } return true; }
/** * Returns false if this transaction has at least one output that is owned by the given wallet and unspent, true * otherwise. */ public boolean isEveryOwnedOutputSpent(TransactionBag transactionBag) { for (TransactionOutput output : outputs) { if (output.isAvailableForSpending() && output.isMineOrWatched(transactionBag)) return false; } return true; }
/** * Returns false if this transaction has at least one output that is owned by the given wallet and unspent, true * otherwise. */ public boolean isEveryOwnedOutputSpent(TransactionBag transactionBag) { for (TransactionOutput output : outputs) { if (output.isAvailableForSpending() && output.isMineOrWatched(transactionBag)) return false; } return true; }
/** * Returns false if this transaction has at least one output that is owned by the given wallet and unspent, true * otherwise. */ public boolean isEveryOwnedOutputSpent(TransactionBag transactionBag) { for (TransactionOutput output : outputs) { if (output.isAvailableForSpending() && output.isMineOrWatched(transactionBag)) return false; } return true; }
/** * Returns all the outputs that match addresses or scripts added via {@link #addWatchedAddress(Address)} or * {@link #addWatchedScripts(java.util.List)}. * @param excludeImmatureCoinbases Whether to ignore outputs that are unspendable due to being immature. */ public List<TransactionOutput> getWatchedOutputs(boolean excludeImmatureCoinbases) { lock.lock(); keyChainGroupLock.lock(); try { LinkedList<TransactionOutput> candidates = Lists.newLinkedList(); for (Transaction tx : Iterables.concat(unspent.values(), pending.values())) { if (excludeImmatureCoinbases && !tx.isMature()) continue; for (TransactionOutput output : tx.getOutputs()) { if (!output.isAvailableForSpending()) continue; try { Script scriptPubKey = output.getScriptPubKey(); if (!watchedScripts.contains(scriptPubKey)) continue; candidates.add(output); } catch (ScriptException e) { // Ignore } } } return candidates; } finally { keyChainGroupLock.unlock(); lock.unlock(); } }
@VisibleForTesting boolean isTxConsistent(final Transaction tx, final boolean isSpent) { boolean isActuallySpent = true; for (TransactionOutput o : tx.getOutputs()) { if (o.isAvailableForSpending()) { if (o.isMineOrWatched(this)) isActuallySpent = false; if (o.getSpentBy() != null) { log.error("isAvailableForSpending != spentBy"); return false; } } else { if (o.getSpentBy() == null) { log.error("isAvailableForSpending != spentBy"); return false; } } } return isActuallySpent == isSpent; }
@VisibleForTesting boolean isTxConsistent(final Transaction tx, final boolean isSpent) { boolean isActuallySpent = true; for (TransactionOutput o : tx.getOutputs()) { if (o.isAvailableForSpending()) { if (o.isMineOrWatched(this)) isActuallySpent = false; if (o.getSpentBy() != null) { log.error("isAvailableForSpending != spentBy"); return false; } } else { if (o.getSpentBy() == null) { log.error("isAvailableForSpending != spentBy"); return false; } } } return isActuallySpent == isSpent; }
@VisibleForTesting boolean isTxConsistent(final Transaction tx, final boolean isSpent) { boolean isActuallySpent = true; for (TransactionOutput o : tx.getOutputs()) { if (o.isAvailableForSpending()) { if (o.isMineOrWatched(this)) isActuallySpent = false; if (o.getSpentBy() != null) { log.error("isAvailableForSpending != spentBy"); return false; } } else { if (o.getSpentBy() == null) { log.error("isAvailableForSpending != spentBy"); return false; } } } return isActuallySpent == isSpent; }
@VisibleForTesting boolean isTxConsistent(final Transaction tx, final boolean isSpent) { boolean isActuallySpent = true; for (TransactionOutput o : tx.getOutputs()) { if (o.isAvailableForSpending()) { if (o.isMineOrWatched(this)) isActuallySpent = false; if (o.getSpentBy() != null) { log.error("isAvailableForSpending != spentBy"); return false; } } else { if (o.getSpentBy() == null) { log.error("isAvailableForSpending != spentBy"); return false; } } } return isActuallySpent == isSpent; }
@Test public void isTxConsistentReturnsFalseAsExpected_WhenAvailableForSpendingEqualsFalse() { Wallet wallet = new Wallet(PARAMS); TransactionOutput to = createMock(TransactionOutput.class); EasyMock.expect(to.isAvailableForSpending()).andReturn(false); EasyMock.expect(to.getSpentBy()).andReturn(null); Transaction tx = FakeTxBuilder.createFakeTxWithoutChange(PARAMS, to); replay(to); boolean isConsistent = wallet.isTxConsistent(tx, false); assertFalse(isConsistent); }
@Test public void isTxConsistentReturnsFalseAsExpected() { Wallet wallet = new Wallet(PARAMS); TransactionOutput to = createMock(TransactionOutput.class); EasyMock.expect(to.isAvailableForSpending()).andReturn(true); EasyMock.expect(to.isMineOrWatched(wallet)).andReturn(true); EasyMock.expect(to.getSpentBy()).andReturn(new TransactionInput(PARAMS, null, new byte[0])); Transaction tx = FakeTxBuilder.createFakeTxWithoutChange(PARAMS, to); replay(to); boolean isConsistent = wallet.isTxConsistent(tx, false); assertFalse(isConsistent); }
/** * Construct a SendRequest for a CPFP (child-pays-for-parent) transaction. The resulting transaction is already * completed, so you should directly proceed to signing and broadcasting/committing the transaction. CPFP is * currently only supported by a few miners, so use with care. */ public static SendRequest childPaysForParent(Wallet wallet, Transaction parentTransaction, Coin feeRaise) { TransactionOutput outputToSpend = null; for (final TransactionOutput output : parentTransaction.getOutputs()) { if (output.isMine(wallet) && output.isAvailableForSpending() && output.getValue().isGreaterThan(feeRaise)) { outputToSpend = output; break; } } // TODO spend another confirmed output of own wallet if needed checkNotNull(outputToSpend, "Can't find adequately sized output that spends to us"); final Transaction tx = new Transaction(parentTransaction.getParams()); tx.addInput(outputToSpend); tx.addOutput(outputToSpend.getValue().subtract(feeRaise), wallet.freshAddress(KeyPurpose.CHANGE)); tx.setPurpose(Transaction.Purpose.RAISE_FEE); final SendRequest req = forTx(tx); req.completed = true; return req; }
/** * Construct a SendRequest for a CPFP (child-pays-for-parent) transaction. The resulting transaction is already * completed, so you should directly proceed to signing and broadcasting/committing the transaction. CPFP is * currently only supported by a few miners, so use with care. */ public static SendRequest childPaysForParent(Wallet wallet, Transaction parentTransaction, Coin feeRaise) { TransactionOutput outputToSpend = null; for (final TransactionOutput output : parentTransaction.getOutputs()) { if (output.isMine(wallet) && output.isAvailableForSpending() && output.getValue().isGreaterThan(feeRaise)) { outputToSpend = output; break; } } // TODO spend another confirmed output of own wallet if needed checkNotNull(outputToSpend, "Can't find adequately sized output that spends to us"); final Transaction tx = new Transaction(parentTransaction.getParams()); tx.addInput(outputToSpend); tx.addOutput(outputToSpend.getValue().subtract(feeRaise), wallet.freshAddress(KeyPurpose.CHANGE)); tx.setPurpose(Transaction.Purpose.RAISE_FEE); final SendRequest req = forTx(tx); req.completed = true; return req; }
/** * Construct a SendRequest for a CPFP (child-pays-for-parent) transaction. The resulting transaction is already * completed, so you should directly proceed to signing and broadcasting/committing the transaction. CPFP is * currently only supported by a few miners, so use with care. */ public static SendRequest childPaysForParent(Wallet wallet, Transaction parentTransaction, Coin feeRaise) { TransactionOutput outputToSpend = null; for (final TransactionOutput output : parentTransaction.getOutputs()) { if (output.isMine(wallet) && output.isAvailableForSpending() && output.getValue().isGreaterThan(feeRaise)) { outputToSpend = output; break; } } // TODO spend another confirmed output of own wallet if needed checkNotNull(outputToSpend, "Can't find adequately sized output that spends to us"); final Transaction tx = new Transaction(parentTransaction.getParams()); tx.addInput(outputToSpend); tx.addOutput(outputToSpend.getValue().subtract(feeRaise), wallet.freshAddress(KeyPurpose.CHANGE)); tx.setPurpose(Transaction.Purpose.RAISE_FEE); final SendRequest req = forTx(tx); req.completed = true; return req; }
/** * Construct a SendRequest for a CPFP (child-pays-for-parent) transaction. The resulting transaction is already * completed, so you should directly proceed to signing and broadcasting/committing the transaction. CPFP is * currently only supported by a few miners, so use with care. */ public static SendRequest childPaysForParent(Wallet wallet, Transaction parentTransaction, Coin feeRaise) { TransactionOutput outputToSpend = null; for (final TransactionOutput output : parentTransaction.getOutputs()) { if (output.isMine(wallet) && output.isAvailableForSpending() && output.getValue().isGreaterThan(feeRaise)) { outputToSpend = output; break; } } // TODO spend another confirmed output of own wallet if needed checkNotNull(outputToSpend, "Can't find adequately sized output that spends to us"); final Transaction tx = new Transaction(parentTransaction.getParams()); tx.addInput(outputToSpend); tx.addOutput(outputToSpend.getValue().subtract(feeRaise), wallet.freshAddress(KeyPurpose.CHANGE)); tx.setPurpose(Transaction.Purpose.RAISE_FEE); final SendRequest req = forTx(tx); req.completed = true; return req; }
/** * Connects this input to the relevant output of the referenced transaction. * Connecting means updating the internal pointers and spent flags. If the mode is to ABORT_ON_CONFLICT then * the spent output won't be changed, but the outpoint.fromTx pointer will still be updated. * * @param transaction The transaction to try. * @param mode Whether to abort if there's a pre-existing connection or not. * @return NO_SUCH_TX if transaction is not the prevtx, ALREADY_SPENT if there was a conflict, SUCCESS if not. */ public ConnectionResult connect(Transaction transaction, ConnectMode mode) { if (!transaction.getHash().equals(outpoint.getHash())) return ConnectionResult.NO_SUCH_TX; checkElementIndex((int) outpoint.getIndex(), transaction.getOutputs().size(), "Corrupt transaction"); TransactionOutput out = transaction.getOutput((int) outpoint.getIndex()); if (!out.isAvailableForSpending()) { if (getParentTransaction().equals(outpoint.fromTx)) { // Already connected. return ConnectionResult.SUCCESS; } else if (mode == ConnectMode.DISCONNECT_ON_CONFLICT) { out.markAsUnspent(); } else if (mode == ConnectMode.ABORT_ON_CONFLICT) { outpoint.fromTx = out.getParentTransaction(); return TransactionInput.ConnectionResult.ALREADY_SPENT; } } connect(out); return TransactionInput.ConnectionResult.SUCCESS; }