public void serializeUnencrypted(SimpleHDKeyChain keyChain, String expectedSerialization)
      throws UnreadableWalletException {
    keyChain.setLookaheadSize(10);

    keyChain.maybeLookAhead();
    DeterministicKey key1 = keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key2 = keyChain.getKey(KeyChain.KeyPurpose.RECEIVE_FUNDS);
    DeterministicKey key3 = keyChain.getKey(KeyChain.KeyPurpose.CHANGE);
    List<Protos.Key> keys = keyChain.toProtobuf();
    // 1 master key, 1 account key, 2 internal keys, 3 derived, 20 lookahead and 5 lookahead
    // threshold.
    int numItems =
        1 // master key/account key
            + 2 // ext/int parent keys
            + (keyChain.getLookaheadSize() + keyChain.getLookaheadThreshold())
                * 2 // lookahead zone on each chain
        ;
    assertEquals(numItems, keys.size());

    // Get another key that will be lost during round-tripping, to ensure we can derive it again.
    DeterministicKey key4 = keyChain.getKey(KeyChain.KeyPurpose.CHANGE);

    String sb = protoToString(keys);
    assertEquals(expectedSerialization, sb);

    // Round trip the data back and forth to check it is preserved.
    int oldLookaheadSize = keyChain.getLookaheadSize();
    keyChain = SimpleHDKeyChain.fromProtobuf(keys, null);
    assertEquals(expectedSerialization, protoToString(keyChain.toProtobuf()));
    assertEquals(key1, keyChain.findKeyFromPubHash(key1.getPubKeyHash()));
    assertEquals(key2, keyChain.findKeyFromPubHash(key2.getPubKeyHash()));
    assertEquals(key3, keyChain.findKeyFromPubHash(key3.getPubKeyHash()));
    assertEquals(key4, keyChain.getKey(KeyChain.KeyPurpose.CHANGE));
    key1.sign(Sha256Hash.ZERO_HASH);
    key2.sign(Sha256Hash.ZERO_HASH);
    key3.sign(Sha256Hash.ZERO_HASH);
    key4.sign(Sha256Hash.ZERO_HASH);
    assertEquals(oldLookaheadSize, keyChain.getLookaheadSize());
  }
  @Test
  public void events() throws Exception {
    // Check that we get the right events at the right time.
    final List<List<ECKey>> listenerKeys = Lists.newArrayList();
    long secs = 1389353062L;
    chain.addEventListener(
        new AbstractKeyChainEventListener() {
          @Override
          public void onKeysAdded(List<ECKey> keys) {
            listenerKeys.add(keys);
          }
        },
        Threading.SAME_THREAD);
    assertEquals(0, listenerKeys.size());
    chain.setLookaheadSize(5);
    assertEquals(0, listenerKeys.size());
    ECKey key = chain.getKey(SimpleHDKeyChain.KeyPurpose.CHANGE);
    assertEquals(1, listenerKeys.size()); // 1 event
    final List<ECKey> firstEvent = listenerKeys.get(0);
    assertEquals(1, firstEvent.size());
    assertTrue(firstEvent.contains(key)); // order is not specified.
    listenerKeys.clear();

    chain.maybeLookAhead();
    final List<ECKey> secondEvent = listenerKeys.get(0);
    assertEquals(12, secondEvent.size()); // (5 lookahead keys, +1 lookahead threshold) * 2 chains
    listenerKeys.clear();

    chain.getKey(SimpleHDKeyChain.KeyPurpose.CHANGE);
    // At this point we've entered the threshold zone so more keys won't immediately trigger more
    // generations.
    assertEquals(0, listenerKeys.size()); // 1 event
    final int lookaheadThreshold = chain.getLookaheadThreshold() + chain.getLookaheadSize();
    for (int i = 0; i < lookaheadThreshold; i++) chain.getKey(SimpleHDKeyChain.KeyPurpose.CHANGE);
    assertEquals(1, listenerKeys.size()); // 1 event
    assertEquals(1, listenerKeys.get(0).size()); // 1 key.
  }