Struct bdk_chain::indexer::keychain_txout::KeychainTxOutIndex
source · pub struct KeychainTxOutIndex<K> { /* private fields */ }
Expand description
KeychainTxOutIndex
controls how script pubkeys are revealed for multiple keychains, and
indexes TxOut
s with them.
A single keychain is a chain of script pubkeys derived from a single Descriptor
. Keychains
are identified using the K
generic. Script pubkeys are identified by the keychain that they
are derived from K
, as well as the derivation index u32
.
There is a strict 1-to-1 relationship between descriptors and keychains. Each keychain has one
and only one descriptor and each descriptor has one and only one keychain. The
insert_descriptor
method will return an error if you try and violate this invariant. This
rule is a proxy for a stronger rule: no two descriptors should produce the same script pubkey.
Having two descriptors produce the same script pubkey should cause whichever keychain derives
the script pubkey first to be the effective owner of it but you should not rely on this
behaviour. ⚠ It is up you, the developer, not to violate this invariant.
§Revealed script pubkeys
Tracking how script pubkeys are revealed is useful for collecting chain data. For example, if the user has requested 5 script pubkeys (to receive money with), we only need to use those script pubkeys to scan for chain data.
Call reveal_to_target
or reveal_next_spk
to reveal more script pubkeys.
Call revealed_keychain_spks
or revealed_spks
to iterate through revealed script pubkeys.
§Lookahead script pubkeys
When an user first recovers a wallet (i.e. from a recovery phrase and/or descriptor), we will
NOT have knowledge of which script pubkeys are revealed. So when we index a transaction or
txout (using index_tx
/index_txout
) we scan the txouts against script pubkeys derived
above the last revealed index. These additionally-derived script pubkeys are called the
lookahead.
The KeychainTxOutIndex
is constructed with the lookahead
and cannot be altered. See
DEFAULT_LOOKAHEAD
for the value used in the Default
implementation. Use new
to set a
custom lookahead
.
§Unbounded script pubkey iterator
For script-pubkey-based chain sources (such as Electrum/Esplora), an initial scan is best done by iterating though derived script pubkeys one by one and requesting transaction histories for each script pubkey. We will stop after x-number of script pubkeys have empty histories. An unbounded script pubkey iterator is useful to pass to such a chain source because it doesn’t require holding a reference to the index.
Call unbounded_spk_iter
to get an unbounded script pubkey iterator for a given keychain.
Call all_unbounded_spk_iters
to get unbounded script pubkey iterators for all keychains.
§Change sets
Methods that can update the last revealed index or add keychains will return ChangeSet
to report
these changes. This should be persisted for future recovery.
§Synopsis
use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex;
// imagine our service has internal and external addresses but also addresses for users
#[derive(Clone, Debug, PartialEq, Eq, Ord, PartialOrd)]
enum MyKeychain {
External,
Internal,
MyAppUser {
user_id: u32
}
}
let mut txout_index = KeychainTxOutIndex::<MyKeychain>::default();
let _ = txout_index.insert_descriptor(MyKeychain::External, external_descriptor)?;
let _ = txout_index.insert_descriptor(MyKeychain::Internal, internal_descriptor)?;
let _ = txout_index.insert_descriptor(MyKeychain::MyAppUser { user_id: 42 }, descriptor_42)?;
let new_spk_for_user = txout_index.reveal_next_spk(MyKeychain::MyAppUser{ user_id: 42 });
Implementations§
source§impl<K> KeychainTxOutIndex<K>
impl<K> KeychainTxOutIndex<K>
sourcepub fn new(lookahead: u32) -> Self
pub fn new(lookahead: u32) -> Self
Construct a KeychainTxOutIndex
with the given lookahead
.
The lookahead
is the number of script pubkeys to derive and cache from the internal
descriptors over and above the last revealed script index. Without a lookahead the index
will miss outputs you own when processing transactions whose output script pubkeys lie
beyond the last revealed index. In certain situations, such as when performing an initial
scan of the blockchain during wallet import, it may be uncertain or unknown what the index
of the last revealed script pubkey actually is.
Refer to struct-level docs for more about lookahead
.
source§impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K>
impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K>
Methods that are re-exposed from the internal SpkTxOutIndex
.
sourcepub fn inner(&self) -> &SpkTxOutIndex<(K, u32)>
pub fn inner(&self) -> &SpkTxOutIndex<(K, u32)>
Return a reference to the internal SpkTxOutIndex
.
WARNING: The internal index will contain lookahead spks. Refer to
struct-level docs for more about lookahead
.
sourcepub fn outpoints(&self) -> &BTreeSet<KeychainIndexed<K, OutPoint>>
pub fn outpoints(&self) -> &BTreeSet<KeychainIndexed<K, OutPoint>>
Get the set of indexed outpoints, corresponding to tracked keychains.
sourcepub fn txouts(
&self
) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, (OutPoint, &TxOut)>> + ExactSizeIterator
pub fn txouts( &self ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, (OutPoint, &TxOut)>> + ExactSizeIterator
Iterate over known txouts that spend to tracked script pubkeys.
sourcepub fn txouts_in_tx(
&self,
txid: Txid
) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, (OutPoint, &TxOut)>>
pub fn txouts_in_tx( &self, txid: Txid ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, (OutPoint, &TxOut)>>
Finds all txouts on a transaction that has previously been scanned and indexed.
sourcepub fn txout(&self, outpoint: OutPoint) -> Option<KeychainIndexed<K, &TxOut>>
pub fn txout(&self, outpoint: OutPoint) -> Option<KeychainIndexed<K, &TxOut>>
Return the TxOut
of outpoint
if it has been indexed, and if it corresponds to a
tracked keychain.
The associated keychain and keychain index of the txout’s spk is also returned.
This calls SpkTxOutIndex::txout
internally.
sourcepub fn spk_at_index(&self, keychain: K, index: u32) -> Option<ScriptBuf>
pub fn spk_at_index(&self, keychain: K, index: u32) -> Option<ScriptBuf>
Return the script that exists under the given keychain
’s index
.
This calls SpkTxOutIndex::spk_at_index
internally.
sourcepub fn index_of_spk(&self, script: ScriptBuf) -> Option<&(K, u32)>
pub fn index_of_spk(&self, script: ScriptBuf) -> Option<&(K, u32)>
Returns the keychain and keychain index associated with the spk.
This calls SpkTxOutIndex::index_of_spk
internally.
sourcepub fn is_used(&self, keychain: K, index: u32) -> bool
pub fn is_used(&self, keychain: K, index: u32) -> bool
Returns whether the spk under the keychain
’s index
has been used.
Here, “unused” means that after the script pubkey was stored in the index, the index has never scanned a transaction output with it.
This calls SpkTxOutIndex::is_used
internally.
sourcepub fn mark_used(&mut self, keychain: K, index: u32) -> bool
pub fn mark_used(&mut self, keychain: K, index: u32) -> bool
Marks the script pubkey at index
as used even though the tracker hasn’t seen an output
with it.
This only has an effect when the index
had been added to self
already and was unused.
Returns whether the spk under the given keychain
and index
is successfully
marked as used. Returns false either when there is no descriptor under the given
keychain, or when the spk is already marked as used.
This is useful when you want to reserve a script pubkey for something but don’t want to add
the transaction output using it to the index yet. Other callers will consider index
on
keychain
used until you call unmark_used
.
This calls SpkTxOutIndex::mark_used
internally.
sourcepub fn unmark_used(&mut self, keychain: K, index: u32) -> bool
pub fn unmark_used(&mut self, keychain: K, index: u32) -> bool
Undoes the effect of mark_used
. Returns whether the index
is inserted back into
unused
.
Note that if self
has scanned an output with this script pubkey, then this will have no
effect.
This calls SpkTxOutIndex::unmark_used
internally.
sourcepub fn sent_and_received(
&self,
tx: &Transaction,
range: impl RangeBounds<K>
) -> (Amount, Amount)
pub fn sent_and_received( &self, tx: &Transaction, range: impl RangeBounds<K> ) -> (Amount, Amount)
Computes the total value transfer effect tx
has on the script pubkeys belonging to the
keychains in range
. Value is sent when a script pubkey in the range
is on an input and
received when it is on an output. For sent
to be computed correctly, the output being
spent must have already been scanned by the index. Calculating received just uses the
Transaction
outputs directly, so it will be correct even if it has not been scanned.
sourcepub fn net_value(
&self,
tx: &Transaction,
range: impl RangeBounds<K>
) -> SignedAmount
pub fn net_value( &self, tx: &Transaction, range: impl RangeBounds<K> ) -> SignedAmount
Computes the net value that this transaction gives to the script pubkeys in the index and
takes from the transaction outputs in the index. Shorthand for calling
sent_and_received
and subtracting sent from received.
This calls SpkTxOutIndex::net_value
internally.
source§impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K>
impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K>
sourcepub fn keychains(
&self
) -> impl DoubleEndedIterator<Item = (K, &Descriptor<DescriptorPublicKey>)> + ExactSizeIterator + '_
pub fn keychains( &self ) -> impl DoubleEndedIterator<Item = (K, &Descriptor<DescriptorPublicKey>)> + ExactSizeIterator + '_
Return all keychains and their corresponding descriptors.
sourcepub fn insert_descriptor(
&mut self,
keychain: K,
descriptor: Descriptor<DescriptorPublicKey>
) -> Result<bool, InsertDescriptorError<K>>
pub fn insert_descriptor( &mut self, keychain: K, descriptor: Descriptor<DescriptorPublicKey> ) -> Result<bool, InsertDescriptorError<K>>
Insert a descriptor with a keychain associated to it.
Adding a descriptor means you will be able to derive new script pubkeys under it and the txout index will discover transaction outputs with those script pubkeys (once they’ve been derived and added to the index).
keychain <-> descriptor is a one-to-one mapping that cannot be changed. Attempting to do so
will return a InsertDescriptorError<K>
.
KeychainTxOutIndex
will prevent you from inserting two descriptors which derive the same
script pubkey at index 0, but it’s up to you to ensure that descriptors don’t collide at
other indices. If they do nothing catastrophic happens at the KeychainTxOutIndex
level
(one keychain just becomes the defacto owner of that spk arbitrarily) but this may have
subtle implications up the application stack like one UTXO being missing from one keychain
because it has been assigned to another which produces the same script pubkey.
sourcepub fn get_descriptor(
&self,
keychain: K
) -> Option<&Descriptor<DescriptorPublicKey>>
pub fn get_descriptor( &self, keychain: K ) -> Option<&Descriptor<DescriptorPublicKey>>
Gets the descriptor associated with the keychain. Returns None
if the keychain doesn’t
have a descriptor associated with it.
sourcepub fn lookahead(&self) -> u32
pub fn lookahead(&self) -> u32
Get the lookahead setting.
Refer to new
for more information on the lookahead
.
sourcepub fn lookahead_to_target(&mut self, keychain: K, target_index: u32)
pub fn lookahead_to_target(&mut self, keychain: K, target_index: u32)
Store lookahead scripts until target_index
(inclusive).
This does not change the global lookahead
setting.
sourcepub fn unbounded_spk_iter(
&self,
keychain: K
) -> Option<SpkIterator<Descriptor<DescriptorPublicKey>>>
pub fn unbounded_spk_iter( &self, keychain: K ) -> Option<SpkIterator<Descriptor<DescriptorPublicKey>>>
Get an unbounded spk iterator over a given keychain
. Returns None
if the provided
keychain doesn’t exist
sourcepub fn all_unbounded_spk_iters(
&self
) -> BTreeMap<K, SpkIterator<Descriptor<DescriptorPublicKey>>>
pub fn all_unbounded_spk_iters( &self ) -> BTreeMap<K, SpkIterator<Descriptor<DescriptorPublicKey>>>
Get unbounded spk iterators for all keychains.
sourcepub fn revealed_spks(
&self,
range: impl RangeBounds<K>
) -> impl Iterator<Item = KeychainIndexed<K, ScriptBuf>> + '_
pub fn revealed_spks( &self, range: impl RangeBounds<K> ) -> impl Iterator<Item = KeychainIndexed<K, ScriptBuf>> + '_
Iterate over revealed spks of keychains in range
sourcepub fn revealed_keychain_spks(
&self,
keychain: K
) -> impl DoubleEndedIterator<Item = Indexed<ScriptBuf>> + '_
pub fn revealed_keychain_spks( &self, keychain: K ) -> impl DoubleEndedIterator<Item = Indexed<ScriptBuf>> + '_
Iterate over revealed spks of the given keychain
with ascending indices.
This is a double ended iterator so you can easily reverse it to get an iterator where the script pubkeys that were most recently revealed are first.
sourcepub fn unused_spks(
&self
) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, ScriptBuf>> + Clone + '_
pub fn unused_spks( &self ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, ScriptBuf>> + Clone + '_
Iterate over revealed, but unused, spks of all keychains.
sourcepub fn unused_keychain_spks(
&self,
keychain: K
) -> impl DoubleEndedIterator<Item = Indexed<ScriptBuf>> + Clone + '_
pub fn unused_keychain_spks( &self, keychain: K ) -> impl DoubleEndedIterator<Item = Indexed<ScriptBuf>> + Clone + '_
Iterate over revealed, but unused, spks of the given keychain
.
Returns an empty iterator if the provided keychain doesn’t exist.
sourcepub fn next_index(&self, keychain: K) -> Option<(u32, bool)>
pub fn next_index(&self, keychain: K) -> Option<(u32, bool)>
Get the next derivation index for keychain
. The next index is the index after the last revealed
derivation index.
The second field in the returned tuple represents whether the next derivation index is new. There are two scenarios where the next derivation index is reused (not new):
- The keychain’s descriptor has no wildcard, and a script has already been revealed.
- The number of revealed scripts has already reached 2^31 (refer to BIP-32).
Not checking the second field of the tuple may result in address reuse.
Returns None if the provided keychain
doesn’t exist.
sourcepub fn last_revealed_indices(&self) -> BTreeMap<K, u32>
pub fn last_revealed_indices(&self) -> BTreeMap<K, u32>
Get the last derivation index that is revealed for each keychain.
Keychains with no revealed indices will not be included in the returned BTreeMap
.
sourcepub fn last_revealed_index(&self, keychain: K) -> Option<u32>
pub fn last_revealed_index(&self, keychain: K) -> Option<u32>
Get the last derivation index revealed for keychain
. Returns None if the keychain doesn’t
exist, or if the keychain doesn’t have any revealed scripts.
sourcepub fn reveal_to_target_multi(
&mut self,
keychains: &BTreeMap<K, u32>
) -> ChangeSet
pub fn reveal_to_target_multi( &mut self, keychains: &BTreeMap<K, u32> ) -> ChangeSet
Convenience method to call Self::reveal_to_target
on multiple keychains.
sourcepub fn reveal_to_target(
&mut self,
keychain: K,
target_index: u32
) -> Option<(Vec<Indexed<ScriptBuf>>, ChangeSet)>
pub fn reveal_to_target( &mut self, keychain: K, target_index: u32 ) -> Option<(Vec<Indexed<ScriptBuf>>, ChangeSet)>
Reveals script pubkeys of the keychain
’s descriptor up to and including the
target_index
.
If the target_index
cannot be reached (due to the descriptor having no wildcard and/or
the target_index
is in the hardened index range), this method will make a best-effort and
reveal up to the last possible index.
This returns list of newly revealed indices (alongside their scripts) and a
ChangeSet
, which reports updates to the latest revealed index. If no new script
pubkeys are revealed, then both of these will be empty.
Returns None if the provided keychain
doesn’t exist.
sourcepub fn reveal_next_spk(
&mut self,
keychain: K
) -> Option<(Indexed<ScriptBuf>, ChangeSet)>
pub fn reveal_next_spk( &mut self, keychain: K ) -> Option<(Indexed<ScriptBuf>, ChangeSet)>
Attempts to reveal the next script pubkey for keychain
.
Returns the derivation index of the revealed script pubkey, the revealed script pubkey and a
ChangeSet
which represents changes in the last revealed index (if any).
Returns None if the provided keychain doesn’t exist.
When a new script cannot be revealed, we return the last revealed script and an empty
ChangeSet
. There are two scenarios when a new script pubkey cannot be derived:
- The descriptor has no wildcard and already has one script revealed.
- The descriptor has already revealed scripts up to the numeric bound.
- There is no descriptor associated with the given keychain.
sourcepub fn next_unused_spk(
&mut self,
keychain: K
) -> Option<(Indexed<ScriptBuf>, ChangeSet)>
pub fn next_unused_spk( &mut self, keychain: K ) -> Option<(Indexed<ScriptBuf>, ChangeSet)>
Gets the next unused script pubkey in the keychain. I.e., the script pubkey with the lowest index that has not been used yet.
This will derive and reveal a new script pubkey if no more unused script pubkeys exist.
If the descriptor has no wildcard and already has a used script pubkey or if a descriptor has used all scripts up to the derivation bounds, then the last derived script pubkey will be returned.
Returns None
if there are no script pubkeys that have been used and no new script pubkey
could be revealed (see reveal_next_spk
for when this happens).
sourcepub fn keychain_outpoints(
&self,
keychain: K
) -> impl DoubleEndedIterator<Item = Indexed<OutPoint>> + '_
pub fn keychain_outpoints( &self, keychain: K ) -> impl DoubleEndedIterator<Item = Indexed<OutPoint>> + '_
Iterate over all OutPoint
s that have TxOut
s with script pubkeys derived from
keychain
.
sourcepub fn keychain_outpoints_in_range<'a>(
&'a self,
range: impl RangeBounds<K> + 'a
) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, OutPoint>> + 'a
pub fn keychain_outpoints_in_range<'a>( &'a self, range: impl RangeBounds<K> + 'a ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, OutPoint>> + 'a
Iterate over OutPoint
s that have script pubkeys derived from keychains in range
.
sourcepub fn last_used_index(&self, keychain: K) -> Option<u32>
pub fn last_used_index(&self, keychain: K) -> Option<u32>
Returns the highest derivation index of the keychain
where KeychainTxOutIndex
has
found a TxOut
with it’s script pubkey.
sourcepub fn last_used_indices(&self) -> BTreeMap<K, u32>
pub fn last_used_indices(&self) -> BTreeMap<K, u32>
Returns the highest derivation index of each keychain that KeychainTxOutIndex
has found
a TxOut
with it’s script pubkey.
sourcepub fn apply_changeset(&mut self, changeset: ChangeSet)
pub fn apply_changeset(&mut self, changeset: ChangeSet)
Applies the ChangeSet<K>
to the KeychainTxOutIndex<K>
Trait Implementations§
source§impl<K: Clone> Clone for KeychainTxOutIndex<K>
impl<K: Clone> Clone for KeychainTxOutIndex<K>
source§fn clone(&self) -> KeychainTxOutIndex<K>
fn clone(&self) -> KeychainTxOutIndex<K>
1.0.0 · source§fn clone_from(&mut self, source: &Self)
fn clone_from(&mut self, source: &Self)
source
. Read moresource§impl<K: Debug> Debug for KeychainTxOutIndex<K>
impl<K: Debug> Debug for KeychainTxOutIndex<K>
source§impl<K> Default for KeychainTxOutIndex<K>
impl<K> Default for KeychainTxOutIndex<K>
source§impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K>
impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K>
source§fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet
fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet
outpoint
and txout
.