@Test
 public void tags() throws Exception {
   myWallet.setTag("foo", ByteString.copyFromUtf8("bar"));
   assertEquals("bar", myWallet.getTag("foo").toStringUtf8());
   myWallet = roundTrip(myWallet);
   assertEquals("bar", myWallet.getTag("foo").toStringUtf8());
 }
  @Test
  public void extensionsWithError() throws Exception {
    WalletExtension extension =
        new WalletExtension() {
          @Override
          public String getWalletExtensionID() {
            return "test";
          }

          @Override
          public boolean isWalletExtensionMandatory() {
            return false;
          }

          @Override
          public byte[] serializeWalletExtension() {
            return new byte[0];
          }

          @Override
          public void deserializeWalletExtension(Wallet containingWallet, byte[] data)
              throws Exception {
            throw new NullPointerException(); // Something went wrong!
          }
        };
    myWallet.addExtension(extension);
    Protos.Wallet proto = new WalletProtobufSerializer().walletToProto(myWallet);
    Wallet wallet =
        new WalletProtobufSerializer().readWallet(params, new WalletExtension[] {extension}, proto);
    assertEquals(0, wallet.getExtensions().size());
  }
  @Test
  public void oneTx() throws Exception {
    // Check basic tx serialization.
    Coin v1 = COIN;
    Transaction t1 = createFakeTx(params, v1, myAddress);
    t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("1.2.3.4")));
    t1.getConfidence().markBroadcastBy(new PeerAddress(InetAddress.getByName("5.6.7.8")));
    t1.getConfidence().setSource(TransactionConfidence.Source.NETWORK);
    myWallet.receivePending(t1, null);
    Wallet wallet1 = roundTrip(myWallet);
    assertEquals(1, wallet1.getTransactions(true).size());
    assertEquals(v1, wallet1.getBalance(Wallet.BalanceType.ESTIMATED));
    Transaction t1copy = wallet1.getTransaction(t1.getHash());
    assertArrayEquals(t1.bitcoinSerialize(), t1copy.bitcoinSerialize());
    assertEquals(2, t1copy.getConfidence().numBroadcastPeers());
    assertEquals(TransactionConfidence.Source.NETWORK, t1copy.getConfidence().getSource());

    Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(myWallet);
    assertEquals(Protos.Key.Type.ORIGINAL, walletProto.getKey(0).getType());
    assertEquals(0, walletProto.getExtensionCount());
    assertEquals(1, walletProto.getTransactionCount());
    assertEquals(6, walletProto.getKeyCount());

    Protos.Transaction t1p = walletProto.getTransaction(0);
    assertEquals(0, t1p.getBlockHashCount());
    assertArrayEquals(t1.getHash().getBytes(), t1p.getHash().toByteArray());
    assertEquals(Protos.Transaction.Pool.PENDING, t1p.getPool());
    assertFalse(t1p.hasLockTime());
    assertFalse(t1p.getTransactionInput(0).hasSequence());
    assertArrayEquals(
        t1.getInputs().get(0).getOutpoint().getHash().getBytes(),
        t1p.getTransactionInput(0).getTransactionOutPointHash().toByteArray());
    assertEquals(0, t1p.getTransactionInput(0).getTransactionOutPointIndex());
    assertEquals(t1p.getTransactionOutput(0).getValue(), v1.value);
  }
  @Test
  public void test_Wallets_Save() throws Exception {
    Wallet wallet = this.getJohnsWallet();
    wallet.Description = "New description to test";

    Wallet saveWallet = this._api.Wallets.update(wallet);

    assertEquals(wallet.Id, saveWallet.Id);
    assertEquals("New description to test", saveWallet.Description);
  }
  @Test
  public void testLastBlockSeenHash() throws Exception {
    // Test the lastBlockSeenHash field works.

    // LastBlockSeenHash should be empty if never set.
    Wallet wallet = new Wallet(params);
    Protos.Wallet walletProto = new WalletProtobufSerializer().walletToProto(wallet);
    ByteString lastSeenBlockHash = walletProto.getLastSeenBlockHash();
    assertTrue(lastSeenBlockHash.isEmpty());

    // Create a block.
    Block block = params.getDefaultSerializer().makeBlock(BlockTest.blockBytes);
    Sha256Hash blockHash = block.getHash();
    wallet.setLastBlockSeenHash(blockHash);
    wallet.setLastBlockSeenHeight(1);

    // Roundtrip the wallet and check it has stored the blockHash.
    Wallet wallet1 = roundTrip(wallet);
    assertEquals(blockHash, wallet1.getLastBlockSeenHash());
    assertEquals(1, wallet1.getLastBlockSeenHeight());

    // Test the Satoshi genesis block (hash of all zeroes) is roundtripped ok.
    Block genesisBlock = MainNetParams.get().getGenesisBlock();
    wallet.setLastBlockSeenHash(genesisBlock.getHash());
    Wallet wallet2 = roundTrip(wallet);
    assertEquals(genesisBlock.getHash(), wallet2.getLastBlockSeenHash());
  }
 @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());
 }
예제 #7
0
 public void timeLockedTransaction(boolean useNotFound) throws Exception {
   connectWithVersion(useNotFound ? 70001 : 60001);
   // Test that if we receive a relevant transaction that has a lock time, it doesn't result in a
   // notification
   // until we explicitly opt in to seeing those.
   ECKey key = new ECKey();
   Wallet wallet = new Wallet(unitTestParams);
   wallet.addKey(key);
   peer.addWallet(wallet);
   final Transaction[] vtx = new Transaction[1];
   wallet.addEventListener(
       new AbstractWalletEventListener() {
         @Override
         public void onCoinsReceived(
             Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
           vtx[0] = tx;
         }
       });
   // Send a normal relevant transaction, it's received correctly.
   Transaction t1 = TestUtils.createFakeTx(unitTestParams, Utils.toNanoCoins(1, 0), key);
   inbound(writeTarget, t1);
   GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
   if (useNotFound) {
     inbound(writeTarget, new NotFoundMessage(unitTestParams, getdata.getItems()));
   } else {
     bouncePing();
   }
   pingAndWait(writeTarget);
   Threading.waitForUserCode();
   assertNotNull(vtx[0]);
   vtx[0] = null;
   // Send a timelocked transaction, nothing happens.
   Transaction t2 = TestUtils.createFakeTx(unitTestParams, Utils.toNanoCoins(2, 0), key);
   t2.setLockTime(999999);
   inbound(writeTarget, t2);
   Threading.waitForUserCode();
   assertNull(vtx[0]);
   // Now we want to hear about them. Send another, we are told about it.
   wallet.setAcceptRiskyTransactions(true);
   inbound(writeTarget, t2);
   getdata = (GetDataMessage) outbound(writeTarget);
   if (useNotFound) {
     inbound(writeTarget, new NotFoundMessage(unitTestParams, getdata.getItems()));
   } else {
     bouncePing();
   }
   pingAndWait(writeTarget);
   Threading.waitForUserCode();
   assertEquals(t2, vtx[0]);
 }
  @Before
  public void setUp() throws Exception {
    unitTestParams = UnitTestParams.get();
    wallet = new Wallet(unitTestParams);
    wallet.addKey(new ECKey());

    resetBlockStore();

    Transaction tx1 =
        createFakeTx(
            unitTestParams,
            Utils.toNanoCoins(2, 0),
            wallet.getKeys().get(0).toAddress(unitTestParams));

    // add a second input so can test granularity of byte cache.
    Transaction prevTx = new Transaction(unitTestParams);
    TransactionOutput prevOut =
        new TransactionOutput(
            unitTestParams,
            prevTx,
            Utils.toNanoCoins(1, 0),
            wallet.getKeys().get(0).toAddress(unitTestParams));
    prevTx.addOutput(prevOut);
    // Connect it.
    tx1.addInput(prevOut);

    Transaction tx2 =
        createFakeTx(
            unitTestParams, Utils.toNanoCoins(1, 0), new ECKey().toAddress(unitTestParams));

    Block b1 = createFakeBlock(blockStore, tx1, tx2).block;

    BitcoinSerializer bs = new BitcoinSerializer(unitTestParams);

    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    bs.serialize(tx1, bos);
    tx1BytesWithHeader = bos.toByteArray();
    tx1Bytes = tx1.bitcoinSerialize();

    bos.reset();
    bs.serialize(tx2, bos);
    tx2BytesWithHeader = bos.toByteArray();
    tx2Bytes = tx2.bitcoinSerialize();

    bos.reset();
    bs.serialize(b1, bos);
    b1BytesWithHeader = bos.toByteArray();
    b1Bytes = b1.bitcoinSerialize();
  }
 @Test
 public void testKeys() throws Exception {
   for (int i = 0; i < 20; i++) {
     myKey = new ECKey();
     myAddress = myKey.toAddress(params);
     myWallet = new Wallet(params);
     myWallet.importKey(myKey);
     Wallet wallet1 = roundTrip(myWallet);
     assertArrayEquals(
         myKey.getPubKey(), wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPubKey());
     assertArrayEquals(
         myKey.getPrivKeyBytes(),
         wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPrivKeyBytes());
   }
 }
 @Before
 public void setUp() throws Exception {
   BriefLogFormatter.initVerbose();
   Context ctx = new Context(params);
   myWatchedKey = new ECKey();
   myWallet = new Wallet(params);
   myKey = new ECKey();
   myKey.setCreationTimeSeconds(123456789L);
   myWallet.importKey(myKey);
   myAddress = myKey.toAddress(params);
   myWallet = new Wallet(params);
   myWallet.importKey(myKey);
   mScriptCreationTime = new Date().getTime() / 1000 - 1234;
   myWallet.addWatchedAddress(myWatchedKey.toAddress(params), mScriptCreationTime);
   myWallet.setDescription(WALLET_DESCRIPTION);
 }
  @Test
  public void extensions() throws Exception {
    myWallet.addExtension(new FooWalletExtension("com.whatever.required", true));
    Protos.Wallet proto = new WalletProtobufSerializer().walletToProto(myWallet);
    // Initial extension is mandatory: try to read it back into a wallet that doesn't know about it.
    try {
      new WalletProtobufSerializer().readWallet(params, null, proto);
      fail();
    } catch (UnreadableWalletException e) {
      assertTrue(e.getMessage().contains("mandatory"));
    }
    Wallet wallet =
        new WalletProtobufSerializer()
            .readWallet(
                params,
                new WalletExtension[] {new FooWalletExtension("com.whatever.required", true)},
                proto);
    assertTrue(wallet.getExtensions().containsKey("com.whatever.required"));

    // Non-mandatory extensions are ignored if the wallet doesn't know how to read them.
    Wallet wallet2 = new Wallet(params);
    wallet2.addExtension(new FooWalletExtension("com.whatever.optional", false));
    Protos.Wallet proto2 = new WalletProtobufSerializer().walletToProto(wallet2);
    Wallet wallet5 = new WalletProtobufSerializer().readWallet(params, null, proto2);
    assertEquals(0, wallet5.getExtensions().size());
  }
 @Test
 public void empty() throws Exception {
   // Check the base case of a wallet with one key and no transactions.
   Wallet wallet1 = roundTrip(myWallet);
   assertEquals(0, wallet1.getTransactions(true).size());
   assertEquals(Coin.ZERO, wallet1.getBalance());
   assertArrayEquals(
       myKey.getPubKey(), wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPubKey());
   assertArrayEquals(
       myKey.getPrivKeyBytes(),
       wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPrivKeyBytes());
   assertEquals(
       myKey.getCreationTimeSeconds(),
       wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getCreationTimeSeconds());
   assertEquals(mScriptCreationTime, wallet1.getWatchedScripts().get(0).getCreationTimeSeconds());
   assertEquals(1, wallet1.getWatchedScripts().size());
   assertEquals(
       ScriptBuilder.createOutputScript(myWatchedKey.toAddress(params)),
       wallet1.getWatchedScripts().get(0));
   assertEquals(WALLET_DESCRIPTION, wallet1.getDescription());
 }
 @Test
 public void coinbaseTxns() throws Exception {
   // Covers issue 420 where the outpoint index of a coinbase tx input was being mis-serialized.
   Block b =
       params
           .getGenesisBlock()
           .createNextBlockWithCoinbase(
               Block.BLOCK_VERSION_GENESIS,
               myKey.getPubKey(),
               FIFTY_COINS,
               Block.BLOCK_HEIGHT_GENESIS);
   Transaction coinbase = b.getTransactions().get(0);
   assertTrue(coinbase.isCoinBase());
   BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params));
   assertTrue(chain.add(b));
   // Wallet now has a coinbase tx in it.
   assertEquals(1, myWallet.getTransactions(true).size());
   assertTrue(myWallet.getTransaction(coinbase.getHash()).isCoinBase());
   Wallet wallet2 = roundTrip(myWallet);
   assertEquals(1, wallet2.getTransactions(true).size());
   assertTrue(wallet2.getTransaction(coinbase.getHash()).isCoinBase());
 }
 @Test
 public void testRoundTripNormalWallet() throws Exception {
   Wallet wallet1 = roundTrip(myWallet);
   assertEquals(0, wallet1.getTransactions(true).size());
   assertEquals(Coin.ZERO, wallet1.getBalance());
   assertArrayEquals(
       myKey.getPubKey(), wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPubKey());
   assertArrayEquals(
       myKey.getPrivKeyBytes(),
       wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getPrivKeyBytes());
   assertEquals(
       myKey.getCreationTimeSeconds(),
       wallet1.findKeyFromPubHash(myKey.getPubKeyHash()).getCreationTimeSeconds());
 }
예제 #15
0
  @Test
  public void testReceiveCoinbaseTransaction() throws Exception {
    // Block 169482 (hash 0000000000000756935f1ee9d5987857b604046f846d3df56d024cdb5f368665)
    // contains coinbase transactions that are mining pool shares.
    // The private key MINERS_KEY is used to check transactions are received by a wallet correctly.

    // The address for this private key is 1GqtGtn4fctXuKxsVzRPSLmYWN1YioLi9y.
    final String MINING_PRIVATE_KEY = "5JDxPrBRghF1EvSBjDigywqfmAjpHPmTJxYtQTYJxJRHLLQA4mG";

    final long BLOCK_NONCE = 3973947400L;
    final Coin BALANCE_AFTER_BLOCK = Coin.valueOf(22223642);
    final NetworkParameters PARAMS = MainNetParams.get();

    Block block169482 =
        PARAMS
            .getDefaultSerializer()
            .makeBlock(ByteStreams.toByteArray(getClass().getResourceAsStream("block169482.dat")));

    // Check block.
    assertNotNull(block169482);
    block169482.verify(169482, EnumSet.noneOf(Block.VerifyFlag.class));
    assertEquals(BLOCK_NONCE, block169482.getNonce());

    StoredBlock storedBlock =
        new StoredBlock(block169482, BigInteger.ONE, 169482); // Nonsense work - not used in test.

    // Create a wallet contain the miner's key that receives a spend from a coinbase.
    ECKey miningKey = DumpedPrivateKey.fromBase58(PARAMS, MINING_PRIVATE_KEY).getKey();
    assertNotNull(miningKey);
    Context context = new Context(PARAMS);
    Wallet wallet = new Wallet(context);
    wallet.importKey(miningKey);

    // Initial balance should be zero by construction.
    assertEquals(Coin.ZERO, wallet.getBalance());

    // Give the wallet the first transaction in the block - this is the coinbase tx.
    List<Transaction> transactions = block169482.getTransactions();
    assertNotNull(transactions);
    wallet.receiveFromBlock(transactions.get(0), storedBlock, NewBlockType.BEST_CHAIN, 0);

    // Coinbase transaction should have been received successfully but be unavailable to spend (too
    // young).
    assertEquals(BALANCE_AFTER_BLOCK, wallet.getBalance(BalanceType.ESTIMATED));
    assertEquals(Coin.ZERO, wallet.getBalance(BalanceType.AVAILABLE));
  }
  @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 testRoundTripMarriedWallet() throws Exception {
    // create 2-of-2 married wallet
    myWallet = new Wallet(params);
    final DeterministicKeyChain partnerChain = new DeterministicKeyChain(new SecureRandom());
    DeterministicKey partnerKey =
        DeterministicKey.deserializeB58(
            null, partnerChain.getWatchingKey().serializePubB58(params), params);
    MarriedKeyChain chain =
        MarriedKeyChain.builder()
            .random(new SecureRandom())
            .followingKeys(partnerKey)
            .threshold(2)
            .build();
    myWallet.addAndActivateHDChain(chain);

    myAddress = myWallet.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS);

    Wallet wallet1 = roundTrip(myWallet);
    assertEquals(0, wallet1.getTransactions(true).size());
    assertEquals(Coin.ZERO, wallet1.getBalance());
    assertEquals(2, wallet1.getActiveKeyChain().getSigsRequiredToSpend());
    assertEquals(myAddress, wallet1.currentAddress(KeyChain.KeyPurpose.RECEIVE_FUNDS));
  }
  @Test
  public void testUTXOProviderWithWallet() throws Exception {
    final int UNDOABLE_BLOCKS_STORED = 10;
    store = createStore(params, UNDOABLE_BLOCKS_STORED);
    chain = new FullPrunedBlockChain(params, store);

    // Check that we aren't accidentally leaving any references
    // to the full StoredUndoableBlock's lying around (ie memory leaks)
    ECKey outKey = new ECKey();
    int height = 1;

    // Build some blocks on genesis block to create a spendable output.
    Block rollingBlock =
        params
            .getGenesisBlock()
            .createNextBlockWithCoinbase(Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
    chain.add(rollingBlock);
    Transaction transaction = rollingBlock.getTransactions().get(0);
    TransactionOutPoint spendableOutput = new TransactionOutPoint(params, 0, transaction.getHash());
    byte[] spendableOutputScriptPubKey = transaction.getOutputs().get(0).getScriptBytes();
    for (int i = 1; i < params.getSpendableCoinbaseDepth(); i++) {
      rollingBlock =
          rollingBlock.createNextBlockWithCoinbase(
              Block.BLOCK_VERSION_GENESIS, outKey.getPubKey(), height++);
      chain.add(rollingBlock);
    }
    rollingBlock = rollingBlock.createNextBlock(null);

    // Create 1 BTC spend to a key in this wallet (to ourselves).
    Wallet wallet = new Wallet(params);
    assertEquals(
        "Available balance is incorrect",
        Coin.ZERO,
        wallet.getBalance(Wallet.BalanceType.AVAILABLE));
    assertEquals(
        "Estimated balance is incorrect",
        Coin.ZERO,
        wallet.getBalance(Wallet.BalanceType.ESTIMATED));

    wallet.setUTXOProvider(store);
    ECKey toKey = wallet.freshReceiveKey();
    Coin amount = Coin.valueOf(100000000);

    Transaction t = new Transaction(params);
    t.addOutput(new TransactionOutput(params, t, amount, toKey));
    t.addSignedInput(spendableOutput, new Script(spendableOutputScriptPubKey), outKey);
    rollingBlock.addTransaction(t);
    rollingBlock.solve();
    chain.add(rollingBlock);

    // Create another spend of 1/2 the value of BTC we have available using the wallet (store coin
    // selector).
    ECKey toKey2 = new ECKey();
    Coin amount2 = amount.divide(2);
    Address address2 = new Address(params, toKey2.getPubKeyHash());
    Wallet.SendRequest req = Wallet.SendRequest.to(address2, amount2);
    wallet.completeTx(req);
    wallet.commitTx(req.tx);
    Coin fee = req.fee;

    // There should be one pending tx (our spend).
    assertEquals(
        "Wrong number of PENDING.4", 1, wallet.getPoolSize(WalletTransaction.Pool.PENDING));
    Coin totalPendingTxAmount = Coin.ZERO;
    for (Transaction tx : wallet.getPendingTransactions()) {
      totalPendingTxAmount = totalPendingTxAmount.add(tx.getValueSentToMe(wallet));
    }

    // The availbale balance should be the 0 (as we spent the 1 BTC that's pending) and estimated
    // should be 1/2 - fee BTC
    assertEquals(
        "Available balance is incorrect",
        Coin.ZERO,
        wallet.getBalance(Wallet.BalanceType.AVAILABLE));
    assertEquals(
        "Estimated balance is incorrect",
        amount2.subtract(fee),
        wallet.getBalance(Wallet.BalanceType.ESTIMATED));
    assertEquals("Pending tx amount is incorrect", amount2.subtract(fee), totalPendingTxAmount);
    try {
      store.close();
    } catch (Exception e) {
    }
  }
예제 #19
0
 private void checkTimeLockedDependency(boolean shouldAccept, boolean useNotFound)
     throws Exception {
   // Initial setup.
   connectWithVersion(useNotFound ? 70001 : 60001);
   ECKey key = new ECKey();
   Wallet wallet = new Wallet(unitTestParams);
   wallet.addKey(key);
   wallet.setAcceptRiskyTransactions(shouldAccept);
   peer.addWallet(wallet);
   final Transaction[] vtx = new Transaction[1];
   wallet.addEventListener(
       new AbstractWalletEventListener() {
         @Override
         public void onCoinsReceived(
             Wallet wallet, Transaction tx, BigInteger prevBalance, BigInteger newBalance) {
           vtx[0] = tx;
         }
       });
   // t1 -> t2 [locked] -> t3 (not available)
   Transaction t2 = new Transaction(unitTestParams);
   t2.setLockTime(999999);
   // Add a fake input to t3 that goes nowhere.
   Sha256Hash t3 = Sha256Hash.create("abc".getBytes(Charset.forName("UTF-8")));
   t2.addInput(
       new TransactionInput(
           unitTestParams, t2, new byte[] {}, new TransactionOutPoint(unitTestParams, 0, t3)));
   t2.getInput(0).setSequenceNumber(0xDEADBEEF);
   t2.addOutput(Utils.toNanoCoins(1, 0), new ECKey());
   Transaction t1 = new Transaction(unitTestParams);
   t1.addInput(t2.getOutput(0));
   t1.addOutput(Utils.toNanoCoins(1, 0), key); // Make it relevant.
   // Announce t1.
   InventoryMessage inv = new InventoryMessage(unitTestParams);
   inv.addTransaction(t1);
   inbound(writeTarget, inv);
   // Send it.
   GetDataMessage getdata = (GetDataMessage) outbound(writeTarget);
   assertEquals(t1.getHash(), getdata.getItems().get(0).hash);
   inbound(writeTarget, t1);
   // Nothing arrived at our event listener yet.
   assertNull(vtx[0]);
   // We request t2.
   getdata = (GetDataMessage) outbound(writeTarget);
   assertEquals(t2.getHash(), getdata.getItems().get(0).hash);
   inbound(writeTarget, t2);
   if (!useNotFound) bouncePing();
   // We request t3.
   getdata = (GetDataMessage) outbound(writeTarget);
   assertEquals(t3, getdata.getItems().get(0).hash);
   // Can't find it: bottom of tree.
   if (useNotFound) {
     NotFoundMessage notFound = new NotFoundMessage(unitTestParams);
     notFound.addItem(new InventoryItem(InventoryItem.Type.Transaction, t3));
     inbound(writeTarget, notFound);
   } else {
     bouncePing();
   }
   pingAndWait(writeTarget);
   Threading.waitForUserCode();
   // We're done but still not notified because it was timelocked.
   if (shouldAccept) assertNotNull(vtx[0]);
   else assertNull(vtx[0]);
 }
  @Test
  public void testAppearedAtChainHeightDepthAndWorkDone() throws Exception {
    // Test the TransactionConfidence appearedAtChainHeight, depth and workDone field are stored.

    BlockChain chain = new BlockChain(params, myWallet, new MemoryBlockStore(params));

    final ArrayList<Transaction> txns = new ArrayList<Transaction>(2);
    myWallet.addEventListener(
        new AbstractWalletEventListener() {
          @Override
          public void onCoinsReceived(
              Wallet wallet, Transaction tx, Coin prevBalance, Coin newBalance) {
            txns.add(tx);
          }
        });

    // Start by building two blocks on top of the genesis block.
    Block b1 = params.getGenesisBlock().createNextBlock(myAddress);
    BigInteger work1 = b1.getWork();
    assertTrue(work1.signum() > 0);

    Block b2 = b1.createNextBlock(myAddress);
    BigInteger work2 = b2.getWork();
    assertTrue(work2.signum() > 0);

    assertTrue(chain.add(b1));
    assertTrue(chain.add(b2));

    // We now have the following chain:
    //     genesis -> b1 -> b2

    // Check the transaction confidence levels are correct before wallet roundtrip.
    Threading.waitForUserCode();
    assertEquals(2, txns.size());

    TransactionConfidence confidence0 = txns.get(0).getConfidence();
    TransactionConfidence confidence1 = txns.get(1).getConfidence();

    assertEquals(1, confidence0.getAppearedAtChainHeight());
    assertEquals(2, confidence1.getAppearedAtChainHeight());

    assertEquals(2, confidence0.getDepthInBlocks());
    assertEquals(1, confidence1.getDepthInBlocks());

    // Roundtrip the wallet and check it has stored the depth and workDone.
    Wallet rebornWallet = roundTrip(myWallet);

    Set<Transaction> rebornTxns = rebornWallet.getTransactions(false);
    assertEquals(2, rebornTxns.size());

    // The transactions are not guaranteed to be in the same order so sort them to be in chain
    // height order if required.
    Iterator<Transaction> it = rebornTxns.iterator();
    Transaction txA = it.next();
    Transaction txB = it.next();

    Transaction rebornTx0, rebornTx1;
    if (txA.getConfidence().getAppearedAtChainHeight() == 1) {
      rebornTx0 = txA;
      rebornTx1 = txB;
    } else {
      rebornTx0 = txB;
      rebornTx1 = txA;
    }

    TransactionConfidence rebornConfidence0 = rebornTx0.getConfidence();
    TransactionConfidence rebornConfidence1 = rebornTx1.getConfidence();

    assertEquals(1, rebornConfidence0.getAppearedAtChainHeight());
    assertEquals(2, rebornConfidence1.getAppearedAtChainHeight());

    assertEquals(2, rebornConfidence0.getDepthInBlocks());
    assertEquals(1, rebornConfidence1.getDepthInBlocks());
  }