Class KeyChainGroup
- All Implemented Interfaces:
KeyBag
A KeyChainGroup is used by the Wallet
and manages: a BasicKeyChain
object
(which will normally be empty), and zero or more DeterministicKeyChain
s. The last added
deterministic keychain is always the default active keychain, that's the one we normally derive keys and
addresses from.
There can be active keychains for each output script type. However this class almost entirely only works on
the default active keychain (see getActiveKeyChain()
). The other active keychains
(see getActiveKeyChain(ScriptType, long)
) are meant as fallback for if a sender doesn't understand a
certain new script type (e.g. P2WPKH which comes with the new Bech32 address format). Active keychains
share the same seed, so that upgrading the wallet
(see upgradeToDeterministic(ScriptType, KeyChainGroupStructure, long, AesKey)
) to understand
a new script type doesn't require a fresh backup.
If a key rotation time is set, it may be necessary to add a new DeterministicKeyChain with a fresh seed and also preserve the old one, so funds can be swept from the rotating keys. In this case, there may be more than one deterministic chain. The latest chain is called the active chain and is where new keys are served from.
The wallet delegates most key management tasks to this class. It is not thread safe and requires external locking, i.e. by the wallet lock. The group then in turn delegates most operations to the key chain objects, combining their responses together when necessary.
Deterministic key chains have a concept of a lookahead size and threshold. Please see the discussion in the
class docs for DeterministicKeyChain
for more information on this topic.
-
Nested Class Summary
-
Field Summary
-
Method Summary
Modifier and TypeMethodDescriptionvoid
Adds an HD chain to the chains list, and make it the default chain (from which keys are issued).void
Removes a listener for events that are run when a current key and/or address changes.void
addCurrentKeyChangeEventListener
(CurrentKeyChangeEventListener listener, Executor executor) Adds a listener for events that are run when a current key and/or address changes, on the given executor.void
addEventListener
(KeyChainEventListener listener) Adds a listener for events that are run when keys are added, on the user thread.void
addEventListener
(KeyChainEventListener listener, Executor executor) Adds a listener for events that are run when keys are added, on the given executor.static KeyChainGroup.Builder
static KeyChainGroup.Builder
builder
(Network network, KeyChainGroupStructure structure) static KeyChainGroup.Builder
builder
(NetworkParameters params) Deprecated.static KeyChainGroup.Builder
builder
(NetworkParameters params, KeyChainGroupStructure structure) Deprecated.boolean
checkAESKey
(AesKey aesKey) boolean
checkPassword
(CharSequence password) static KeyChainGroup
createBasic
(Network network) Creates a keychain group with just a basic chain.static KeyChainGroup
createBasic
(NetworkParameters params) Deprecated.currentAddress
(KeyChain.KeyPurpose purpose) Returns address for acurrentKey(KeyChain.KeyPurpose)
currentKey
(KeyChain.KeyPurpose purpose) Returns a key that hasn't been seen in a transaction yet, and which is suitable for displaying in a wallet user interface as "a convenient key to receive funds on" when the purpose parameter isKeyChain.KeyPurpose.RECEIVE_FUNDS
.void
Decrypt the keys in the group using the previously given key crypter and the AES key.Gets the earliest time for which full block must be downloaded.void
encrypt
(KeyCrypter keyCrypter, AesKey aesKey) Encrypt the keys in the group using the KeyCrypter and the AES key.findKeyFromPubKey
(byte[] pubKey) Locates a keypair from the keychain given the raw public key bytes.findKeyFromPubKeyHash
(byte[] pubKeyHash, ScriptType scriptType) Locates a keypair from the keychain given the hash of the public key, and (optionally) by usage for a specific script type.findRedeemDataFromScriptHash
(byte[] scriptHash) Locates a redeem data (redeem script and keys) from the keychain given the hash of the script.freshAddress
(KeyChain.KeyPurpose purpose) Returns address for afreshKey(KeyChain.KeyPurpose)
freshAddress
(KeyChain.KeyPurpose purpose, ScriptType outputScriptType, long keyRotationTimeSecs) Deprecated.freshAddress
(KeyChain.KeyPurpose purpose, ScriptType outputScriptType, Instant keyRotationTime) Returns a fresh address for a givenKeyChain.KeyPurpose
and of a givenScriptType
.freshKey
(KeyChain.KeyPurpose purpose) Returns a key that has not been returned by this method before (fresh).freshKeys
(KeyChain.KeyPurpose purpose, int numberOfKeys) Returns a key/s that have not been returned by this method before (fresh).static KeyChainGroup
fromProtobufEncrypted
(Network network, List<org.bitcoinj.protobuf.wallet.Protos.Key> keys, KeyCrypter crypter, KeyChainFactory factory) static KeyChainGroup
fromProtobufUnencrypted
(Network network, List<org.bitcoinj.protobuf.wallet.Protos.Key> keys, KeyChainFactory factory) final DeterministicKeyChain
Returns the key chain that's used for generation of default fresh/current keys.final DeterministicKeyChain
getActiveKeyChain
(ScriptType outputScriptType, long keyRotationTimeSecs) Deprecated.final DeterministicKeyChain
getActiveKeyChain
(ScriptType outputScriptType, Instant keyRotationTime) Returns the key chain that's used for generation of fresh/current keys of the given type.getActiveKeyChains
(long keyRotationTimeSecs) Deprecated.getActiveKeyChains
(Instant keyRotationTime) Returns the key chains that are used for generation of fresh/current keys, in the order of how they were added.getBloomFilter
(int size, double falsePositiveRate, int nTweak) int
int
Returns a counter that increases (by an arbitrary amount) each time new keys have been calculated due to lookahead and thus the Bloom filter that was previously calculated has become stale.Returns a copy of the current list of chains.long
Deprecated.Returns a list of the non-deterministic keys that have been imported into the wallet, or the empty list if none.Returns the key crypter or null if the group is not encrypted.int
Gets the current lookahead size being used for ALL deterministic key chains.int
Gets the current lookahead threshold being used for ALL deterministic key chains.boolean
int
importKeys
(List<ECKey> keys) Imports the given keys into the basic chain, creating it if necessary.int
importKeys
(ECKey... keys) Imports the given keys into the basic chain, creating it if necessary.int
importKeysAndEncrypt
(List<ECKey> keys, AesKey aesKey) Imports the given unencrypted keys into the basic chain, encrypting them along the way with the given key.boolean
isDeterministicUpgradeRequired
(ScriptType preferredScriptType, long keyRotationTimeSecs) Deprecated.boolean
isDeterministicUpgradeRequired
(ScriptType preferredScriptType, Instant keyRotationTime) Returns true if a call toupgradeToDeterministic(ScriptType, KeyChainGroupStructure, long, AesKey)
is required in order to have an active deterministic keychain of the desired script type.boolean
Returns true if the group is encrypted.boolean
boolean
Deprecated.boolean
Returns whether this chain has only watching keys (unencrypted keys with no private part).void
markP2SHAddressAsUsed
(LegacyAddress address) void
markPubKeyAsUsed
(byte[] pubkey) Mark the DeterministicKeys as used, if they match the pubkey SeeDeterministicKeyChain.markKeyAsUsed(DeterministicKey)
for more info on this.void
markPubKeyHashAsUsed
(byte[] pubKeyHash) Mark the DeterministicKeys as used, if they match the pubKeyHash SeeDeterministicKeyChain.markKeyAsUsed(DeterministicKey)
for more info on this.final void
mergeActiveKeyChains
(KeyChainGroup from, long keyRotationTimeSecs) Deprecated.final void
mergeActiveKeyChains
(KeyChainGroup from, Instant keyRotationTime) Merge all active chains from the given keychain group into this keychain group.int
numKeys()
Returns the number of keys managed by this group, including the lookahead buffers.boolean
Removes a listener for events that are run when a current key and/or address changes.boolean
removeEventListener
(KeyChainEventListener listener) Removes a listener for events that are run when keys are added.boolean
removeImportedKey
(ECKey key) Removes a key that was imported into the basic key chain.List<org.bitcoinj.protobuf.wallet.Protos.Key>
Return a list of key protobufs obtained by merging the chains.boolean
Are any deterministic keychains supported?void
upgradeToDeterministic
(ScriptType preferredScriptType, KeyChainGroupStructure structure, long keyRotationTimeSecs, AesKey aesKey) void
upgradeToDeterministic
(ScriptType preferredScriptType, KeyChainGroupStructure structure, Instant keyRotationTime, AesKey aesKey) This method will upgrade the wallet along the following path:Basic --> P2PKH --> P2WPKH
-
Field Details
-
chains
-
-
Method Details
-
createBasic
Creates a keychain group with just a basic chain. No deterministic chains will be created automatically. -
createBasic
Deprecated. -
builder
-
builder
Deprecated.usebuilder(Network)
-
builder
-
builder
@Deprecated public static KeyChainGroup.Builder builder(NetworkParameters params, KeyChainGroupStructure structure) Deprecated. -
supportsDeterministicChains
public boolean supportsDeterministicChains()Are any deterministic keychains supported?- Returns:
- true if it contains any deterministic keychain
-
isSupportsDeterministicChains
Deprecated.- Returns:
- true if it contains any deterministic keychain
-
addAndActivateHDChain
Adds an HD chain to the chains list, and make it the default chain (from which keys are issued). Useful for adding a complex pre-configured keychain, such as a married wallet. -
currentKey
Returns a key that hasn't been seen in a transaction yet, and which is suitable for displaying in a wallet user interface as "a convenient key to receive funds on" when the purpose parameter isKeyChain.KeyPurpose.RECEIVE_FUNDS
. The returned key is stable until it's actually seen in a pending or confirmed transaction, at which point this method will start returning a different key (for each purpose independently). -
currentAddress
Returns address for acurrentKey(KeyChain.KeyPurpose)
-
freshKey
Returns a key that has not been returned by this method before (fresh). You can think of this as being a newly created key, although the notion of "create" is not really valid for aDeterministicKeyChain
. When the parameter isKeyChain.KeyPurpose.RECEIVE_FUNDS
the returned key is suitable for being put into a receive coins wizard type UI. You should use this when the user is definitely going to hand this key out to someone who wishes to send money.This method is not supposed to be used for married keychains and will throw UnsupportedOperationException if the active chain is married. For married keychains use
freshAddress(KeyChain.KeyPurpose)
to get a proper P2SH address -
freshKeys
Returns a key/s that have not been returned by this method before (fresh). You can think of this as being newly created key/s, although the notion of "create" is not really valid for aDeterministicKeyChain
. When the parameter isKeyChain.KeyPurpose.RECEIVE_FUNDS
the returned key is suitable for being put into a receive coins wizard type UI. You should use this when the user is definitely going to hand this key out to someone who wishes to send money. -
freshAddress
public Address freshAddress(KeyChain.KeyPurpose purpose, ScriptType outputScriptType, @Nullable Instant keyRotationTime) Returns a fresh address for a given
KeyChain.KeyPurpose
and of a givenScriptType
.This method is meant for when you really need a fallback address. Normally, you should be using
freshAddress(KeyChain.KeyPurpose)
orcurrentAddress(KeyChain.KeyPurpose)
. -
freshAddress
@Deprecated public Address freshAddress(KeyChain.KeyPurpose purpose, ScriptType outputScriptType, long keyRotationTimeSecs) Deprecated. -
freshAddress
Returns address for afreshKey(KeyChain.KeyPurpose)
-
getActiveKeyChains
Returns the key chains that are used for generation of fresh/current keys, in the order of how they were added. The default active chain will come last in the list.- Parameters:
keyRotationTime
- key rotation to take into account
-
getActiveKeyChains
Deprecated. -
getActiveKeyChain
public final DeterministicKeyChain getActiveKeyChain(ScriptType outputScriptType, Instant keyRotationTime) Returns the key chain that's used for generation of fresh/current keys of the given type. If it's not the default type and no active chain for this type exists,null
is returned. No upgrade or downgrade is tried. -
getActiveKeyChain
@Deprecated public final DeterministicKeyChain getActiveKeyChain(ScriptType outputScriptType, long keyRotationTimeSecs) Deprecated. -
getActiveKeyChain
Returns the key chain that's used for generation of default fresh/current keys. This is always the newest deterministic chain. If no deterministic chain is present but imported keys instead, a deterministic upgrade is tried. -
mergeActiveKeyChains
Merge all active chains from the given keychain group into this keychain group. -
mergeActiveKeyChains
Deprecated. -
getLookaheadSize
public int getLookaheadSize()Gets the current lookahead size being used for ALL deterministic key chains. SeeDeterministicKeyChain.setLookaheadSize(int)
for more information. -
getLookaheadThreshold
public int getLookaheadThreshold()Gets the current lookahead threshold being used for ALL deterministic key chains. SeeDeterministicKeyChain.setLookaheadThreshold(int)
for more information. -
importKeys
Imports the given keys into the basic chain, creating it if necessary. -
importKeys
Imports the given keys into the basic chain, creating it if necessary. -
checkPassword
-
checkAESKey
-
importKeysAndEncrypt
Imports the given unencrypted keys into the basic chain, encrypting them along the way with the given key. -
findRedeemDataFromScriptHash
Description copied from interface:KeyBag
Locates a redeem data (redeem script and keys) from the keychain given the hash of the script. This is needed when finding out which key and script we need to use to locally sign a P2SH transaction input. It is assumed that wallet should not have more than one private key for a single P2SH tx for security reasons. Returns RedeemData object or null if no such data was found.- Specified by:
findRedeemDataFromScriptHash
in interfaceKeyBag
-
markP2SHAddressAsUsed
-
findKeyFromPubKeyHash
Description copied from interface:KeyBag
Locates a keypair from the keychain given the hash of the public key, and (optionally) by usage for a specific script type. This is needed when finding out which key we need to use to redeem a transaction output.- Specified by:
findKeyFromPubKeyHash
in interfaceKeyBag
- Parameters:
pubKeyHash
- hash of the keypair to look forscriptType
- only look for given usage (currentlyScriptType.P2PKH
orScriptType.P2WPKH
) ornull
if we don't care- Returns:
- found key or null if no such key was found.
-
markPubKeyHashAsUsed
public void markPubKeyHashAsUsed(byte[] pubKeyHash) Mark the DeterministicKeys as used, if they match the pubKeyHash SeeDeterministicKeyChain.markKeyAsUsed(DeterministicKey)
for more info on this. -
hasKey
-
findKeyFromPubKey
Description copied from interface:KeyBag
Locates a keypair from the keychain given the raw public key bytes.- Specified by:
findKeyFromPubKey
in interfaceKeyBag
- Returns:
- ECKey or null if no such key was found.
-
markPubKeyAsUsed
public void markPubKeyAsUsed(byte[] pubkey) Mark the DeterministicKeys as used, if they match the pubkey SeeDeterministicKeyChain.markKeyAsUsed(DeterministicKey)
for more info on this. -
numKeys
public int numKeys()Returns the number of keys managed by this group, including the lookahead buffers. -
removeImportedKey
Removes a key that was imported into the basic key chain. You cannot remove deterministic keys.- Throws:
IllegalArgumentException
- if the key is deterministic.
-
encrypt
Encrypt the keys in the group using the KeyCrypter and the AES key. A good default KeyCrypter to use isKeyCrypterScrypt
.- Throws:
KeyCrypterException
- Thrown if the wallet encryption fails for some reason, leaving the group unchanged.DeterministicUpgradeRequiredException
- Thrown if there are random keys but no HD chain.
-
decrypt
Decrypt the keys in the group using the previously given key crypter and the AES key. A good default KeyCrypter to use isKeyCrypterScrypt
.- Throws:
KeyCrypterException
- Thrown if the wallet decryption fails for some reason, leaving the group unchanged.
-
isEncrypted
public boolean isEncrypted()Returns true if the group is encrypted. -
isWatching
public boolean isWatching()Returns whether this chain has only watching keys (unencrypted keys with no private part). Mixed chains are forbidden.- Throws:
IllegalStateException
- if there are no keys, or if there is a mix between watching and non-watching keys.
-
getKeyCrypter
Returns the key crypter or null if the group is not encrypted. -
getImportedKeys
Returns a list of the non-deterministic keys that have been imported into the wallet, or the empty list if none. -
earliestKeyCreationTime
Gets the earliest time for which full block must be downloaded.- Returns:
- earliest creation times of keys in this group,
Instant.EPOCH
if at least one time is unknown,Instant.MAX
if no keys in this group
-
getEarliestKeyCreationTime
Deprecated. -
getBloomFilterElementCount
public int getBloomFilterElementCount() -
getBloomFilter
-
isRequiringUpdateAllBloomFilter
public boolean isRequiringUpdateAllBloomFilter() -
addEventListener
Adds a listener for events that are run when keys are added, on the user thread. -
addEventListener
Adds a listener for events that are run when keys are added, on the given executor. -
removeEventListener
Removes a listener for events that are run when keys are added. -
addCurrentKeyChangeEventListener
Removes a listener for events that are run when a current key and/or address changes. -
addCurrentKeyChangeEventListener
public void addCurrentKeyChangeEventListener(CurrentKeyChangeEventListener listener, Executor executor) Adds a listener for events that are run when a current key and/or address changes, on the given executor. -
removeCurrentKeyChangeEventListener
Removes a listener for events that are run when a current key and/or address changes. -
serializeToProtobuf
Return a list of key protobufs obtained by merging the chains.- Returns:
- a list of key protobufs (treat as unmodifiable, will change in future release)
-
fromProtobufUnencrypted
public static KeyChainGroup fromProtobufUnencrypted(Network network, List<org.bitcoinj.protobuf.wallet.Protos.Key> keys, KeyChainFactory factory) throws UnreadableWalletException - Throws:
UnreadableWalletException
-
fromProtobufEncrypted
public static KeyChainGroup fromProtobufEncrypted(Network network, List<org.bitcoinj.protobuf.wallet.Protos.Key> keys, KeyCrypter crypter, KeyChainFactory factory) throws UnreadableWalletException - Throws:
UnreadableWalletException
-
upgradeToDeterministic
public void upgradeToDeterministic(ScriptType preferredScriptType, KeyChainGroupStructure structure, @Nullable Instant keyRotationTime, @Nullable AesKey aesKey) throws DeterministicUpgradeRequiresPassword This method will upgrade the wallet along the following path:
Basic --> P2PKH --> P2WPKH
It won't skip any steps in that upgrade path because the user might be restoring from a backup and still expects money on the P2PKH chain.
It will extract and reuse the seed from the current wallet, so that a fresh backup isn't required after upgrading. If coming from a basic chain containing only random keys this means it will pick the oldest non-rotating private key as a seed.
Note that for upgrading an encrypted wallet, the decryption key is needed. In future, we could skip that requirement for a
P2PKH --> P2WPKH
upgrade and just clone the encryped seed, but currently the key is needed even for that.- Parameters:
preferredScriptType
- desired script type for the active keychainstructure
- keychain group structure to derive an account path fromkeyRotationTime
- If non-empty, time for which keys created before this are assumed to be compromised or weak, those keys will not be used for deterministic upgrade.aesKey
- If non-null, the encryption key the keychain is encrypted under. If the keychain is encrypted and this is not supplied, an exception is thrown letting you know you should ask the user for their password, turn it into a key, and then try again.- Throws:
IllegalStateException
- if there is already a deterministic key chain present or if there are no random keys (i.e. this is not an upgrade scenario), or if aesKey is provided but the wallet is not encrypted.IllegalArgumentException
- if the rotation time specified excludes all keys.DeterministicUpgradeRequiresPassword
- if the key chain group is encrypted and you should provide the users encryption key.
-
upgradeToDeterministic
@Deprecated public void upgradeToDeterministic(ScriptType preferredScriptType, KeyChainGroupStructure structure, long keyRotationTimeSecs, @Nullable AesKey aesKey) -
isDeterministicUpgradeRequired
public boolean isDeterministicUpgradeRequired(ScriptType preferredScriptType, @Nullable Instant keyRotationTime) Returns true if a call toupgradeToDeterministic(ScriptType, KeyChainGroupStructure, long, AesKey)
is required in order to have an active deterministic keychain of the desired script type. -
isDeterministicUpgradeRequired
@Deprecated public boolean isDeterministicUpgradeRequired(ScriptType preferredScriptType, long keyRotationTimeSecs) Deprecated. -
toString
-
getDeterministicKeyChains
Returns a copy of the current list of chains. -
getCombinedKeyLookaheadEpochs
public int getCombinedKeyLookaheadEpochs()Returns a counter that increases (by an arbitrary amount) each time new keys have been calculated due to lookahead and thus the Bloom filter that was previously calculated has become stale.
-
builder(Network)