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 TxOuts 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>

source

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>

Methods that are re-exposed from the internal SpkTxOutIndex.

source

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.

source

pub fn outpoints(&self) -> &BTreeSet<KeychainIndexed<K, OutPoint>>

Get the set of indexed outpoints, corresponding to tracked keychains.

source

pub fn txouts( &self ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, (OutPoint, &TxOut)>> + ExactSizeIterator

Iterate over known txouts that spend to tracked script pubkeys.

source

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.

source

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.

source

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.

source

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.

source

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.

source

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.

source

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.

source

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.

source

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>

source

pub fn keychains( &self ) -> impl DoubleEndedIterator<Item = (K, &Descriptor<DescriptorPublicKey>)> + ExactSizeIterator + '_

Return all keychains and their corresponding descriptors.

source

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.

source

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.

source

pub fn lookahead(&self) -> u32

Get the lookahead setting.

Refer to new for more information on the lookahead.

source

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.

source

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

source

pub fn all_unbounded_spk_iters( &self ) -> BTreeMap<K, SpkIterator<Descriptor<DescriptorPublicKey>>>

Get unbounded spk iterators for all keychains.

source

pub fn revealed_spks( &self, range: impl RangeBounds<K> ) -> impl Iterator<Item = KeychainIndexed<K, ScriptBuf>> + '_

Iterate over revealed spks of keychains in range

source

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.

source

pub fn unused_spks( &self ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, ScriptBuf>> + Clone + '_

Iterate over revealed, but unused, spks of all keychains.

source

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.

source

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):

  1. The keychain’s descriptor has no wildcard, and a script has already been revealed.
  2. 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.

source

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.

source

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.

source

pub fn reveal_to_target_multi( &mut self, keychains: &BTreeMap<K, u32> ) -> ChangeSet

Convenience method to call Self::reveal_to_target on multiple keychains.

source

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.

source

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:

  1. The descriptor has no wildcard and already has one script revealed.
  2. The descriptor has already revealed scripts up to the numeric bound.
  3. There is no descriptor associated with the given keychain.
source

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).

source

pub fn keychain_outpoints( &self, keychain: K ) -> impl DoubleEndedIterator<Item = Indexed<OutPoint>> + '_

Iterate over all OutPoints that have TxOuts with script pubkeys derived from keychain.

source

pub fn keychain_outpoints_in_range<'a>( &'a self, range: impl RangeBounds<K> + 'a ) -> impl DoubleEndedIterator<Item = KeychainIndexed<K, OutPoint>> + 'a

Iterate over OutPoints that have script pubkeys derived from keychains in range.

source

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.

source

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.

source

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>

source§

fn clone(&self) -> KeychainTxOutIndex<K>

Returns a copy of the value. Read more
1.0.0 · source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
source§

impl<K: Debug> Debug for KeychainTxOutIndex<K>

source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
source§

impl<K> Default for KeychainTxOutIndex<K>

source§

fn default() -> Self

Returns the “default value” for a type. Read more
source§

impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K>

§

type ChangeSet = ChangeSet

The resultant “changeset” when new transaction data is indexed.
source§

fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet

Scan and index the given outpoint and txout.
source§

fn index_tx(&mut self, tx: &Transaction) -> Self::ChangeSet

Scans a transaction for relevant outpoints, which are stored and indexed internally.
source§

fn initial_changeset(&self) -> Self::ChangeSet

Determines the ChangeSet between self and an empty Indexer.
source§

fn apply_changeset(&mut self, changeset: Self::ChangeSet)

Apply changeset to itself.
source§

fn is_tx_relevant(&self, tx: &Transaction) -> bool

Determines whether the transaction should be included in the index.

Auto Trait Implementations§

§

impl<K> Freeze for KeychainTxOutIndex<K>

§

impl<K> RefUnwindSafe for KeychainTxOutIndex<K>
where K: RefUnwindSafe,

§

impl<K> Send for KeychainTxOutIndex<K>
where K: Send,

§

impl<K> Sync for KeychainTxOutIndex<K>
where K: Sync,

§

impl<K> Unpin for KeychainTxOutIndex<K>
where K: Unpin,

§

impl<K> UnwindSafe for KeychainTxOutIndex<K>

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T> ToOwned for T
where T: Clone,

§

type Owned = T

The resulting type after obtaining ownership.
source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

§

fn vzip(self) -> V