A deterministic key chain is a
KeyChain that uses the
BIP 32 standard, as implemented by
org.bitcoinj.crypto.DeterministicHierarchy, to derive all the keys in the keychain from a master seed.
This type of wallet is extremely convenient and flexible. Although backing up full wallet files is always a good
idea, to recover money only the root seed needs to be preserved and that is a number small enough that it can be
written down on paper or, when represented using a BIP 39
dictated over the phone (possibly even memorized).
Deterministic key chains have other advantages: parts of the key tree can be selectively revealed to allow
for auditing, and new public keys can be generated without access to the private keys, yielding a highly secure
configuration for web servers which can accept payments into a wallet but not spend from them. This does not work
quite how you would expect due to a quirk of elliptic curve mathematics and the techniques used to deal with it.
A watching wallet is not instantiated using the public part of the master key as you may imagine. Instead, you
need to take the account key (first child of the master key) and provide the public part of that to the watching
wallet instead. You can do this by calling
#getWatchingKey() and then serializing it with
org.bitcoinj.crypto.DeterministicKey#serializePubB58(org.bitcoinj.core.NetworkParameters). The resulting "xpub..." string encodes
sufficient information about the account key to create a watching chain via
org.bitcoinj.crypto.DeterministicKey#deserializeB58(org.bitcoinj.crypto.DeterministicKey,String,org.bitcoinj.core.NetworkParameters)(with null as the first parameter) and then
This class builds on
org.bitcoinj.crypto.DeterministicKey by adding support for serialization to and from protobufs,
and encryption of parts of the key tree. Internally it arranges itself as per the BIP 32 spec, with the seed being
used to derive a master key, which is then used to derive an account key, the account key is used to derive two
child keys called the internal and external parent keys (for change and handing out addresses respectively)
and finally the actual leaf keys that users use hanging off the end. The leaf keys are special in that they don't
internally store the private part at all, instead choosing to rederive the private key from the parent when
needed for signing. This simplifies the design for encrypted key chains.
The key chain manages a lookahead zone. This zone is required because when scanning the chain, you don't
know exactly which keys might receive payments. The user may have handed out several addresses and received payments
on them, but for latency reasons the block chain is requested from remote peers in bulk, meaning you must
"look ahead" when calculating keys to put in the Bloom filter. The default lookahead zone is 100 keys, meaning if
the user hands out more than 100 addresses and receives payment on them before the chain is next scanned, some
transactions might be missed. 100 is a reasonable choice for consumer wallets running on CPU constrained devices.
For industrial wallets that are receiving keys all the time, a higher value is more appropriate. Ideally DKC and the
wallet would know how to adjust this value automatically, but that's not implemented at the moment.
In fact the real size of the lookahead zone is larger than requested, by default, it's one third larger. This
is because the act of deriving new keys means recalculating the Bloom filters and this is an expensive operation.
Thus, to ensure we don't have to recalculate on every single new key/address requested or seen we add more buffer
space and only extend the lookahead zone when that buffer is exhausted. For example with a lookahead zone of 100
keys, you can request 33 keys before more keys will be calculated and the Bloom filter rebuilt and rebroadcast.
But even when you are requesting the 33rd key, you will still be looking 100 keys ahead.