/** * <p>Called when we have found a transaction (via network broadcast or otherwise) that is relevant to this wallet * and want to record it. Note that we <b>cannot verify these transactions at all</b>, they may spend fictional * coins or be otherwise invalid. They are useful to inform the user about coins they can expect to receive soon, * and if you trust the sender of the transaction you can choose to assume they are in fact valid and will not * be double spent as an optimization.</p> * * <p>Before this method is called, {@link Wallet#isPendingTransactionRelevant(Transaction)} should have been * called to decide whether the wallet cares about the transaction - if it does, then this method expects the * transaction and any dependencies it has which are still in the memory pool.</p> */ public void receivePending(Transaction tx, @Nullable List<Transaction> dependencies) throws VerificationException { receivePending(tx, dependencies, false); }
/** * <p>Called when we have found a transaction (via network broadcast or otherwise) that is relevant to this wallet * and want to record it. Note that we <b>cannot verify these transactions at all</b>, they may spend fictional * coins or be otherwise invalid. They are useful to inform the user about coins they can expect to receive soon, * and if you trust the sender of the transaction you can choose to assume they are in fact valid and will not * be double spent as an optimization.</p> * * <p>Before this method is called, {@link Wallet#isPendingTransactionRelevant(Transaction)} should have been * called to decide whether the wallet cares about the transaction - if it does, then this method expects the * transaction and any dependencies it has which are still in the memory pool.</p> */ public void receivePending(Transaction tx, @Nullable List<Transaction> dependencies) throws VerificationException { receivePending(tx, dependencies, false); }
/** * <p>Called when we have found a transaction (via network broadcast or otherwise) that is relevant to this wallet * and want to record it. Note that we <b>cannot verify these transactions at all</b>, they may spend fictional * coins or be otherwise invalid. They are useful to inform the user about coins they can expect to receive soon, * and if you trust the sender of the transaction you can choose to assume they are in fact valid and will not * be double spent as an optimization.</p> * * <p>Before this method is called, {@link Wallet#isPendingTransactionRelevant(Transaction)} should have been * called to decide whether the wallet cares about the transaction - if it does, then this method expects the * transaction and any dependencies it has which are still in the memory pool.</p> */ public void receivePending(Transaction tx, @Nullable List<Transaction> dependencies) throws VerificationException { receivePending(tx, dependencies, false); }
/** * <p>Called when we have found a transaction (via network broadcast or otherwise) that is relevant to this wallet * and want to record it. Note that we <b>cannot verify these transactions at all</b>, they may spend fictional * coins or be otherwise invalid. They are useful to inform the user about coins they can expect to receive soon, * and if you trust the sender of the transaction you can choose to assume they are in fact valid and will not * be double spent as an optimization.</p> * * <p>Before this method is called, {@link Wallet#isPendingTransactionRelevant(Transaction)} should have been * called to decide whether the wallet cares about the transaction - if it does, then this method expects the * transaction and any dependencies it has which are still in the memory pool.</p> */ public void receivePending(Transaction tx, @Nullable List<Transaction> dependencies) throws VerificationException { receivePending(tx, dependencies, false); }
@Override public void onSuccess(Transaction transaction) { log.info("Successfully broadcast multisig contract {}. Channel now open.", transaction.getHashAsString()); try { // Manually add the contract to the wallet, overriding the isRelevant checks so we can track // it and check for double-spends later wallet.receivePending(contract, null, true); } catch (VerificationException e) { throw new RuntimeException(e); // Cannot happen, we already called contract.verify() } stateMachine.transition(State.READY); future.set(PaymentChannelServerState.this); }
@Override public void onSuccess(Transaction transaction) { log.info("Successfully broadcast multisig contract {}. Channel now open.", transaction.getHashAsString()); try { // Manually add the contract to the wallet, overriding the isRelevant checks so we can track // it and check for double-spends later wallet.receivePending(contract, null, true); } catch (VerificationException e) { throw new RuntimeException(e); // Cannot happen, we already called contract.verify() } stateMachine.transition(State.READY); future.set(PaymentChannelServerState.this); }
@Override public void onSuccess(Transaction transaction) { log.info("Successfully broadcast multisig contract {}. Channel now open.", transaction.getHashAsString()); try { // Manually add the contract to the wallet, overriding the isRelevant checks so we can track // it and check for double-spends later wallet.receivePending(contract, null, true); } catch (VerificationException e) { throw new RuntimeException(e); // Cannot happen, we already called contract.verify() } stateMachine.transition(State.READY); future.set(PaymentChannelServerState.this); }
@Override public void onSuccess(Transaction transaction) { log.info("Successfully broadcast multisig contract {}. Channel now open.", transaction.getHashAsString()); try { // Manually add the contract to the wallet, overriding the isRelevant checks so we can track // it and check for double-spends later wallet.receivePending(contract, null, true); } catch (VerificationException e) { throw new RuntimeException(e); // Cannot happen, we already called contract.verify() } stateMachine.transition(State.READY); future.set(PaymentChannelServerState.this); }
@Override public void onSuccess(List<Transaction> dependencies) { try { log.info("{}: Dependency download complete!", getAddress()); wallet.receivePending(tx, dependencies); } catch (VerificationException e) { log.error("{}: Wallet failed to process pending transaction {}", getAddress(), tx.getHash()); log.error("Error was: ", e); // Not much more we can do at this point. } }
@Override public void onSuccess(List<Transaction> dependencies) { try { log.info("{}: Dependency download complete!", getAddress()); wallet.receivePending(tx, dependencies); } catch (VerificationException e) { log.error("{}: Wallet failed to process pending transaction {}", getAddress(), tx.getHash()); log.error("Error was: ", e); // Not much more we can do at this point. } }
@Override public void onSuccess(Transaction result) { try { wallet.receivePending(result, null); } catch (VerificationException e) { throw new RuntimeException(e); } }
@Override public void onSuccess(List<Transaction> dependencies) { try { log.info("{}: Dependency download complete!", getAddress()); wallet.receivePending(tx, dependencies); } catch (VerificationException e) { log.error("{}: Wallet failed to process pending transaction {}", getAddress(), tx.getHash()); log.error("Error was: ", e); // Not much more we can do at this point. } }
@Override public void onSuccess(List<Transaction> dependencies) { try { log.info("{}: Dependency download complete!", getAddress()); wallet.receivePending(tx, dependencies); if(tx instanceof TransactionLockRequest) { context.instantSend.acceptLockRequest((TransactionLockRequest)tx); } } catch (VerificationException e) { log.error("{}: Wallet failed to process pending transaction {}", getAddress(), tx.getHash()); log.error("Error was: ", e); // Not much more we can do at this point. } }
@Test public void transactionInBlockNotification() { final Transaction tx = createFakeTx(PARAMS, COIN, myAddress); StoredBlock block = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS, tx).storedBlock; wallet.receivePending(tx, null); boolean notification = wallet.notifyTransactionIsInBlock(tx.getHash(), block, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); assertTrue(notification); final Transaction tx2 = createFakeTx(PARAMS, COIN, OTHER_ADDRESS); wallet.receivePending(tx2, null); StoredBlock block2 = createFakeBlock(blockStore, Block.BLOCK_HEIGHT_GENESIS + 1, tx2).storedBlock; boolean notification2 = wallet.notifyTransactionIsInBlock(tx2.getHash(), block2, AbstractBlockChain.NewBlockType.BEST_CHAIN, 1); assertFalse(notification2); }
@Test public void raiseFeeTx() throws Exception { // Check basic tx serialization. Coin v1 = COIN; Transaction t1 = createFakeTx(PARAMS, v1, myAddress); t1.setPurpose(Purpose.RAISE_FEE); myWallet.receivePending(t1, null); Wallet wallet1 = roundTrip(myWallet); Transaction t1copy = wallet1.getTransaction(t1.getHash()); assertEquals(Purpose.RAISE_FEE, t1copy.getPurpose()); }
@Test public void testSequenceNumber() throws Exception { Wallet wallet = new Wallet(PARAMS); Transaction tx1 = createFakeTx(PARAMS, Coin.COIN, wallet.currentReceiveAddress()); tx1.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE); wallet.receivePending(tx1, null); Transaction tx2 = createFakeTx(PARAMS, Coin.COIN, wallet.currentReceiveAddress()); tx2.getInput(0).setSequenceNumber(TransactionInput.NO_SEQUENCE - 1); wallet.receivePending(tx2, null); Wallet walletCopy = roundTrip(wallet); Transaction tx1copy = checkNotNull(walletCopy.getTransaction(tx1.getHash())); assertEquals(TransactionInput.NO_SEQUENCE, tx1copy.getInput(0).getSequenceNumber()); Transaction tx2copy = checkNotNull(walletCopy.getTransaction(tx2.getHash())); assertEquals(TransactionInput.NO_SEQUENCE - 1, tx2copy.getInput(0).getSequenceNumber()); }
@Test public void doubleSpendForBuildingTx() throws Exception { CoinSelector originalCoinSelector = wallet.getCoinSelector(); try { wallet.allowSpendingUnconfirmedTransactions(); sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, valueOf(2, 0)); Transaction send1 = checkNotNull(wallet.createSend(OTHER_ADDRESS, valueOf(1, 0))); Transaction send2 = checkNotNull(wallet.createSend(OTHER_ADDRESS, valueOf(1, 20))); sendMoneyToWallet(AbstractBlockChain.NewBlockType.BEST_CHAIN, send1); assertUnspent(send1); wallet.receivePending(send2, null); assertUnspent(send1); assertDead(send2); } finally { wallet.setCoinSelector(originalCoinSelector); } }
@Test public void doubleSpend() throws Exception { // Check that we can serialize double spends correctly, as this is a slightly tricky case. FakeTxBuilder.DoubleSpends doubleSpends = FakeTxBuilder.createFakeDoubleSpendTxns(PARAMS, myAddress); // t1 spends to our wallet. myWallet.receivePending(doubleSpends.t1, null); // t2 rolls back t1 and spends somewhere else. myWallet.receiveFromBlock(doubleSpends.t2, null, BlockChain.NewBlockType.BEST_CHAIN, 0); Wallet wallet1 = roundTrip(myWallet); assertEquals(1, wallet1.getTransactions(true).size()); Transaction t1 = wallet1.getTransaction(doubleSpends.t1.getHash()); assertEquals(ConfidenceType.DEAD, t1.getConfidence().getConfidenceType()); assertEquals(Coin.ZERO, wallet1.getBalance()); // TODO: Wallet should store overriding transactions even if they are not wallet-relevant. // assertEquals(doubleSpends.t2, t1.getConfidence().getOverridingTransaction()); }
@Test public void autosaveImmediate() throws Exception { // Test that the wallet will save itself automatically when it changes. File f = File.createTempFile("bitcoinj-unit-test", null); Sha256Hash hash1 = Sha256Hash.of(f); // Start with zero delay and ensure the wallet file changes after adding a key. wallet.autosaveToFile(f, 0, TimeUnit.SECONDS, null); ECKey key = wallet.freshReceiveKey(); Sha256Hash hash2 = Sha256Hash.of(f); assertFalse("Wallet not saved after generating fresh key", hash1.equals(hash2)); // File has changed. Transaction t1 = createFakeTx(PARAMS, valueOf(5, 0), key); if (wallet.isPendingTransactionRelevant(t1)) wallet.receivePending(t1, null); Sha256Hash hash3 = Sha256Hash.of(f); assertFalse("Wallet not saved after receivePending", hash2.equals(hash3)); // File has changed again. }
@Test public void testStandardWalletDisconnect() throws Exception { NetworkParameters params = UnitTestParams.get(); Wallet w = new Wallet(new Context(params)); w.setCoinSelector(new AllowUnconfirmedCoinSelector()); Address a = w.currentReceiveAddress(); Transaction tx1 = FakeTxBuilder.createFakeTxWithoutChangeAddress(params, Coin.COIN, a); w.receivePending(tx1, null); Transaction tx2 = new Transaction(params); tx2.addOutput(Coin.valueOf(99000000), new ECKey()); w.completeTx(SendRequest.forTx(tx2)); TransactionInput txInToDisconnect = tx2.getInput(0); assertEquals(tx1, txInToDisconnect.getOutpoint().fromTx); assertNull(txInToDisconnect.getOutpoint().connectedOutput); txInToDisconnect.disconnect(); assertNull(txInToDisconnect.getOutpoint().fromTx); assertNull(txInToDisconnect.getOutpoint().connectedOutput); }