Transaction prev = null; for (Transaction transaction : transactions) { if (transaction.equals(targetTransaction)) { System.out.println("Previous transaction: " + (prev = null ? "[none]" : prev)); } prev = transaction; }
Transaction last = null; for (Transaction transaction : transactions) { if (transaction.equals(targetTransaction)) { System.out.println("Previous transaction: " + last); } last = transaction; }
/** * Finds transactions in the specified candidates that double spend "tx". Not a general check, but it can work even if * the double spent inputs are not ours. * @return The set of transactions that double spend "tx". */ private Set<Transaction> findDoubleSpendsAgainst(Transaction tx, Map<Sha256Hash, Transaction> candidates) { checkState(lock.isHeldByCurrentThread()); if (tx.isCoinBase()) return Sets.newHashSet(); // Compile a set of outpoints that are spent by tx. HashSet<TransactionOutPoint> outpoints = new HashSet<>(); for (TransactionInput input : tx.getInputs()) { outpoints.add(input.getOutpoint()); } // Now for each pending transaction, see if it shares any outpoints with this tx. Set<Transaction> doubleSpendTxns = Sets.newHashSet(); for (Transaction p : candidates.values()) { if (p.equals(tx)) continue; for (TransactionInput input : p.getInputs()) { // This relies on the fact that TransactionOutPoint equality is defined at the protocol not object // level - outpoints from two different inputs that point to the same output compare the same. TransactionOutPoint outpoint = input.getOutpoint(); if (outpoints.contains(outpoint)) { // It does, it's a double spend against the candidates, which makes it relevant. doubleSpendTxns.add(p); } } } return doubleSpendTxns; }
/** * Adds to txSet all the txns in txPool spending outputs of txns in txSet, * and all txns spending the outputs of those txns, recursively. */ void addTransactionsDependingOn(Set<Transaction> txSet, Set<Transaction> txPool) { Map<Sha256Hash, Transaction> txQueue = new LinkedHashMap<>(); for (Transaction tx : txSet) { txQueue.put(tx.getHash(), tx); } while(!txQueue.isEmpty()) { Transaction tx = txQueue.remove(txQueue.keySet().iterator().next()); for (Transaction anotherTx : txPool) { if (anotherTx.equals(tx)) continue; for (TransactionInput input : anotherTx.getInputs()) { if (input.getOutpoint().getHash().equals(tx.getHash())) { if (txQueue.get(anotherTx.getHash()) == null) { txQueue.put(anotherTx.getHash(), anotherTx); txSet.add(anotherTx); } } } } } }
/** * Adds to txSet all the txns in txPool spending outputs of txns in txSet, * and all txns spending the outputs of those txns, recursively. */ void addTransactionsDependingOn(Set<Transaction> txSet, Set<Transaction> txPool) { Map<Sha256Hash, Transaction> txQueue = new LinkedHashMap<Sha256Hash, Transaction>(); for (Transaction tx : txSet) { txQueue.put(tx.getHash(), tx); } while(!txQueue.isEmpty()) { Transaction tx = txQueue.remove(txQueue.keySet().iterator().next()); for (Transaction anotherTx : txPool) { if (anotherTx.equals(tx)) continue; for (TransactionInput input : anotherTx.getInputs()) { if (input.getOutpoint().getHash().equals(tx.getHash())) { if (txQueue.get(anotherTx.getHash()) == null) { txQueue.put(anotherTx.getHash(), anotherTx); txSet.add(anotherTx); } } } } } }
/** * Adds to txSet all the txns in txPool spending outputs of txns in txSet, * and all txns spending the outputs of those txns, recursively. */ void addTransactionsDependingOn(Set<Transaction> txSet, Set<Transaction> txPool) { Map<Sha256Hash, Transaction> txQueue = new LinkedHashMap<Sha256Hash, Transaction>(); for (Transaction tx : txSet) { txQueue.put(tx.getHash(), tx); } while(!txQueue.isEmpty()) { Transaction tx = txQueue.remove(txQueue.keySet().iterator().next()); for (Transaction anotherTx : txPool) { if (anotherTx.equals(tx)) continue; for (TransactionInput input : anotherTx.getInputs()) { if (input.getOutpoint().getHash().equals(tx.getHash())) { if (txQueue.get(anotherTx.getHash()) == null) { txQueue.put(anotherTx.getHash(), anotherTx); txSet.add(anotherTx); } } } } } }
/** * Adds to txSet all the txns in txPool spending outputs of txns in txSet, * and all txns spending the outputs of those txns, recursively. */ void addTransactionsDependingOn(Set<Transaction> txSet, Set<Transaction> txPool) { Map<Sha256Hash, Transaction> txQueue = new LinkedHashMap<>(); for (Transaction tx : txSet) { txQueue.put(tx.getHash(), tx); } while(!txQueue.isEmpty()) { Transaction tx = txQueue.remove(txQueue.keySet().iterator().next()); for (Transaction anotherTx : txPool) { if (anotherTx.equals(tx)) continue; for (TransactionInput input : anotherTx.getInputs()) { if (input.getOutpoint().getHash().equals(tx.getHash())) { if (txQueue.get(anotherTx.getHash()) == null) { txQueue.put(anotherTx.getHash(), anotherTx); txSet.add(anotherTx); } } } } } }
@Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; AuxPoW input = (AuxPoW) o; if (!transaction.equals(input.transaction)) return false; if (!hashBlock.equals(input.hashBlock)) return false; if (!coinbaseBranch.equals(input.coinbaseBranch)) return false; if (!chainMerkleBranch.equals(input.chainMerkleBranch)) return false; if (!parentBlockHeader.equals(input.parentBlockHeader)) return false; return getHash().equals(input.getHash()); }
@Test public void testTheTXByHeightComparator() { Transaction tx1 = FakeTxBuilder.createFakeTx(PARAMS); tx1.getConfidence().setAppearedAtChainHeight(1); Transaction tx2 = FakeTxBuilder.createFakeTx(PARAMS); tx2.getConfidence().setAppearedAtChainHeight(2); Transaction tx3 = FakeTxBuilder.createFakeTx(PARAMS); tx3.getConfidence().setAppearedAtChainHeight(3); SortedSet<Transaction> set = new TreeSet<>(Transaction.SORT_TX_BY_HEIGHT); set.add(tx2); set.add(tx1); set.add(tx3); Iterator<Transaction> iterator = set.iterator(); assertEquals(tx1.equals(tx2), false); assertEquals(tx1.equals(tx3), false); assertEquals(tx1.equals(tx1), true); assertEquals(iterator.next().equals(tx3), true); assertEquals(iterator.next().equals(tx2), true); assertEquals(iterator.next().equals(tx1), true); assertEquals(iterator.hasNext(), false); }
/** * 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; }
/** * 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; }
/** * 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; }
/** * 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; }
@Test public void testSimplePayment() throws Exception { // Create a PaymentRequest and make sure the correct values are parsed by the PaymentSession. MockPaymentSession paymentSession = new MockPaymentSession(newSimplePaymentRequest("test")); assertEquals(paymentRequestMemo, paymentSession.getMemo()); assertEquals(coin, paymentSession.getValue()); assertEquals(simplePaymentUrl, paymentSession.getPaymentUrl()); assertTrue(new Date(time * 1000L).equals(paymentSession.getDate())); assertTrue(paymentSession.getSendRequest().tx.equals(tx)); assertFalse(paymentSession.isExpired()); // Send the payment and verify that the correct information is sent. // Add a dummy input to tx so it is considered valid. tx.addInput(new TransactionInput(PARAMS, tx, outputToMe.getScriptBytes())); ArrayList<Transaction> txns = new ArrayList<>(); txns.add(tx); Address refundAddr = new Address(PARAMS, serverKey.getPubKeyHash()); paymentSession.sendPayment(txns, refundAddr, paymentMemo); assertEquals(1, paymentSession.getPaymentLog().size()); assertEquals(simplePaymentUrl, paymentSession.getPaymentLog().get(0).getUrl().toString()); Protos.Payment payment = paymentSession.getPaymentLog().get(0).getPayment(); assertEquals(paymentMemo, payment.getMemo()); assertEquals(merchantData, payment.getMerchantData()); assertEquals(1, payment.getRefundToCount()); assertEquals(coin.value, payment.getRefundTo(0).getAmount()); TransactionOutput refundOutput = new TransactionOutput(PARAMS, null, coin, refundAddr); ByteString refundScript = ByteString.copyFrom(refundOutput.getScriptBytes()); assertTrue(refundScript.equals(payment.getRefundTo(0).getScript())); }
@SuppressWarnings("ConstantConditions") public void completeTxPartiallySigned(Wallet.MissingSigsMode missSigMode, byte[] expectedSig) throws Exception { // Check the wallet will write dummy scriptSigs for inputs that we have only pubkeys for without the privkey. ECKey priv = new ECKey(); ECKey pub = ECKey.fromPublicOnly(priv.getPubKeyPoint()); wallet.importKey(pub); ECKey priv2 = wallet.freshReceiveKey(); // Send three transactions, with one being an address type and the other being a raw CHECKSIG type pubkey only, // and the final one being a key we do have. We expect the first two inputs to be dummy values and the last // to be signed correctly. Transaction t1 = sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, pub.toAddress(PARAMS)); Transaction t2 = sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, pub); Transaction t3 = sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, CENT, priv2); SendRequest req = SendRequest.emptyWallet(OTHER_ADDRESS); req.missingSigsMode = missSigMode; wallet.completeTx(req); byte[] dummySig = TransactionSignature.dummy().encodeToBitcoin(); // Selected inputs can be in any order. for (int i = 0; i < req.tx.getInputs().size(); i++) { TransactionInput input = req.tx.getInput(i); if (input.getConnectedOutput().getParentTransaction().equals(t1)) { assertArrayEquals(expectedSig, input.getScriptSig().getChunks().get(0).data); } else if (input.getConnectedOutput().getParentTransaction().equals(t2)) { assertArrayEquals(expectedSig, input.getScriptSig().getChunks().get(0).data); } else if (input.getConnectedOutput().getParentTransaction().equals(t3)) { input.getScriptSig().correctlySpends(req.tx, i, t3.getOutput(0).getScriptPubKey()); } } assertTrue(TransactionSignature.isEncodingCanonical(dummySig)); }
checkState(b61.block.getTransactions().get(0).equals(b60.block.getTransactions().get(0)));