ref(chain)!: create module indexer

and replace keychain module with `balance.rs`
This commit is contained in:
valued mammal
2024-06-28 09:07:36 -04:00
parent a112b4d97c
commit c3fc1dd123
25 changed files with 133 additions and 136 deletions

View File

@@ -1,20 +1,4 @@
//! Module for keychain related structures.
//!
//! A keychain here is a set of application-defined indexes for a miniscript descriptor where we can
//! derive script pubkeys at a particular derivation index. The application's index is simply
//! anything that implements `Ord`.
//!
//! [`KeychainTxOutIndex`] indexes script pubkeys of keychains and scans in relevant outpoints (that
//! has a `txout` containing an indexed script pubkey). Internally, this uses [`SpkTxOutIndex`], but
//! also maintains "revealed" and "lookahead" index counts per keychain.
//!
//! [`SpkTxOutIndex`]: crate::SpkTxOutIndex
#[cfg(feature = "miniscript")]
mod txout_index;
use bitcoin::{Amount, ScriptBuf};
#[cfg(feature = "miniscript")]
pub use txout_index::*;
use bitcoin::Amount;
/// Balance, differentiated into various categories.
#[derive(Debug, PartialEq, Eq, Clone, Default)]
@@ -49,11 +33,6 @@ impl Balance {
}
}
/// A tuple of keychain index and `T` representing the indexed value.
pub type Indexed<T> = (u32, T);
/// A tuple of keychain `K`, derivation index (`u32`) and a `T` associated with them.
pub type KeychainIndexed<K, T> = ((K, u32), T);
impl core::fmt::Display for Balance {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(

View File

@@ -16,7 +16,8 @@ pub struct CombinedChangeSet<K, A> {
/// Changes to the [`LocalChain`](crate::local_chain::LocalChain).
pub chain: crate::local_chain::ChangeSet,
/// Changes to [`IndexedTxGraph`](crate::indexed_tx_graph::IndexedTxGraph).
pub indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>,
pub indexed_tx_graph:
crate::indexed_tx_graph::ChangeSet<A, crate::indexer::keychain_txout::ChangeSet<K>>,
/// Stores the network type of the transaction data.
pub network: Option<bitcoin::Network>,
}
@@ -62,11 +63,14 @@ impl<K, A> From<crate::local_chain::ChangeSet> for CombinedChangeSet<K, A> {
}
#[cfg(feature = "miniscript")]
impl<K, A> From<crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>>
impl<K, A> From<crate::indexed_tx_graph::ChangeSet<A, crate::indexer::keychain_txout::ChangeSet<K>>>
for CombinedChangeSet<K, A>
{
fn from(
indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>,
indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<
A,
crate::indexer::keychain_txout::ChangeSet<K>,
>,
) -> Self {
Self {
indexed_tx_graph,
@@ -76,8 +80,8 @@ impl<K, A> From<crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet
}
#[cfg(feature = "miniscript")]
impl<K, A> From<crate::keychain::ChangeSet<K>> for CombinedChangeSet<K, A> {
fn from(indexer: crate::keychain::ChangeSet<K>) -> Self {
impl<K, A> From<crate::indexer::keychain_txout::ChangeSet<K>> for CombinedChangeSet<K, A> {
fn from(indexer: crate::indexer::keychain_txout::ChangeSet<K>) -> Self {
Self {
indexed_tx_graph: crate::indexed_tx_graph::ChangeSet {
indexer,

View File

@@ -5,7 +5,7 @@ use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid};
use crate::{
tx_graph::{self, TxGraph},
Anchor, AnchorFromBlockPosition, Append, BlockId,
Anchor, AnchorFromBlockPosition, Append, BlockId, Indexer,
};
/// The [`IndexedTxGraph`] combines a [`TxGraph`] and an [`Indexer`] implementation.
@@ -320,8 +320,10 @@ impl<A, IA: Default> From<tx_graph::ChangeSet<A>> for ChangeSet<A, IA> {
}
#[cfg(feature = "miniscript")]
impl<A, K> From<crate::keychain::ChangeSet<K>> for ChangeSet<A, crate::keychain::ChangeSet<K>> {
fn from(indexer: crate::keychain::ChangeSet<K>) -> Self {
impl<A, K> From<crate::indexer::keychain_txout::ChangeSet<K>>
for ChangeSet<A, crate::indexer::keychain_txout::ChangeSet<K>>
{
fn from(indexer: crate::indexer::keychain_txout::ChangeSet<K>) -> Self {
Self {
graph: Default::default(),
indexer,
@@ -329,30 +331,6 @@ impl<A, K> From<crate::keychain::ChangeSet<K>> for ChangeSet<A, crate::keychain:
}
}
/// Utilities for indexing transaction data.
///
/// Types which implement this trait can be used to construct an [`IndexedTxGraph`].
/// This trait's methods should rarely be called directly.
pub trait Indexer {
/// The resultant "changeset" when new transaction data is indexed.
type ChangeSet;
/// Scan and index the given `outpoint` and `txout`.
fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet;
/// Scans a transaction for relevant outpoints, which are stored and indexed internally.
fn index_tx(&mut self, tx: &Transaction) -> Self::ChangeSet;
/// Apply changeset to itself.
fn apply_changeset(&mut self, changeset: Self::ChangeSet);
/// Determines the [`ChangeSet`] between `self` and an empty [`Indexer`].
fn initial_changeset(&self) -> Self::ChangeSet;
/// Determines whether the transaction should be included in the index.
fn is_tx_relevant(&self, tx: &Transaction) -> bool;
}
impl<A, I> AsRef<TxGraph<A>> for IndexedTxGraph<A, I> {
fn as_ref(&self) -> &TxGraph<A> {
&self.graph

View File

@@ -0,0 +1,33 @@
//! [`Indexer`] provides utilities for indexing transaction data.
use bitcoin::{OutPoint, Transaction, TxOut};
#[cfg(feature = "miniscript")]
pub mod keychain_txout;
pub mod spk_txout;
/// Utilities for indexing transaction data.
///
/// Types which implement this trait can be used to construct an [`IndexedTxGraph`].
/// This trait's methods should rarely be called directly.
///
/// [`IndexedTxGraph`]: crate::IndexedTxGraph
pub trait Indexer {
/// The resultant "changeset" when new transaction data is indexed.
type ChangeSet;
/// Scan and index the given `outpoint` and `txout`.
fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet;
/// Scans a transaction for relevant outpoints, which are stored and indexed internally.
fn index_tx(&mut self, tx: &Transaction) -> Self::ChangeSet;
/// Apply changeset to itself.
fn apply_changeset(&mut self, changeset: Self::ChangeSet);
/// Determines the [`ChangeSet`](Indexer::ChangeSet) between `self` and an empty [`Indexer`].
fn initial_changeset(&self) -> Self::ChangeSet;
/// Determines whether the transaction should be included in the index.
fn is_tx_relevant(&self, tx: &Transaction) -> bool;
}

View File

@@ -1,18 +1,19 @@
//! [`KeychainTxOutIndex`] controls how script pubkeys are revealed for multiple keychains and
//! indexes [`TxOut`]s with them.
use crate::{
collections::*,
indexed_tx_graph::Indexer,
miniscript::{Descriptor, DescriptorPublicKey},
spk_iter::BIP32_MAX_INDEX,
DescriptorExt, DescriptorId, SpkIterator, SpkTxOutIndex,
DescriptorExt, DescriptorId, Indexed, Indexer, KeychainIndexed, SpkIterator, SpkTxOutIndex,
};
use alloc::{borrow::ToOwned, vec::Vec};
use bitcoin::{Amount, OutPoint, Script, SignedAmount, Transaction, TxOut, Txid};
use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
use core::{
fmt::Debug,
ops::{Bound, RangeBounds},
};
use super::*;
use crate::Append;
/// The default lookahead for a [`KeychainTxOutIndex`]
@@ -73,7 +74,7 @@ pub const DEFAULT_LOOKAHEAD: u32 = 25;
/// ## Synopsis
///
/// ```
/// use bdk_chain::keychain::KeychainTxOutIndex;
/// use bdk_chain::indexer::keychain_txout::KeychainTxOutIndex;
/// # use bdk_chain::{ miniscript::{Descriptor, DescriptorPublicKey} };
/// # use core::str::FromStr;
///
@@ -98,7 +99,7 @@ pub const DEFAULT_LOOKAHEAD: u32 = 25;
/// 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 });
/// # Ok::<_, bdk_chain::keychain::InsertDescriptorError<_>>(())
/// # Ok::<_, bdk_chain::indexer::keychain_txout::InsertDescriptorError<_>>(())
/// ```
///
/// [`Ord`]: core::cmp::Ord
@@ -859,8 +860,7 @@ impl<K: core::fmt::Debug> std::error::Error for InsertDescriptorError<K> {}
/// `keychains_added` is *not* monotone, once it is set any attempt to change it is subject to the
/// same *one-to-one* keychain <-> descriptor mapping invariant as [`KeychainTxOutIndex`] itself.
///
/// [`KeychainTxOutIndex`]: crate::keychain::KeychainTxOutIndex
/// [`apply_changeset`]: crate::keychain::KeychainTxOutIndex::apply_changeset
/// [`apply_changeset`]: KeychainTxOutIndex::apply_changeset
/// [`append`]: Self::append
#[derive(Clone, Debug, PartialEq)]
#[cfg_attr(

View File

@@ -1,8 +1,10 @@
//! [`SpkTxOutIndex`] is an index storing [`TxOut`]s that have a script pubkey that matches those in a list.
use core::ops::RangeBounds;
use crate::{
collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap},
indexed_tx_graph::Indexer,
Indexer,
};
use bitcoin::{Amount, OutPoint, Script, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};

View File

@@ -21,14 +21,15 @@
#![warn(missing_docs)]
pub use bitcoin;
mod spk_txout_index;
pub use spk_txout_index::*;
mod balance;
pub use balance::*;
mod chain_data;
pub use chain_data::*;
pub mod indexed_tx_graph;
pub use indexed_tx_graph::IndexedTxGraph;
pub mod keychain;
pub use keychain::{Indexed, KeychainIndexed};
pub mod indexer;
pub use indexer::spk_txout::*;
pub use indexer::Indexer;
pub mod local_chain;
mod tx_data_traits;
pub mod tx_graph;
@@ -98,3 +99,8 @@ pub mod collections {
/// How many confirmations are needed f or a coinbase output to be spent.
pub const COINBASE_MATURITY: u32 = 100;
/// A tuple of keychain index and `T` representing the indexed value.
pub type Indexed<T> = (u32, T);
/// A tuple of keychain `K`, derivation index (`u32`) and a `T` associated with them.
pub type KeychainIndexed<K, T> = ((K, u32), T);

View File

@@ -1,8 +1,7 @@
//! Helper types for spk-based blockchain clients.
use crate::{
collections::BTreeMap, keychain::Indexed, local_chain::CheckPoint,
ConfirmationTimeHeightAnchor, TxGraph,
collections::BTreeMap, local_chain::CheckPoint, ConfirmationTimeHeightAnchor, Indexed, TxGraph,
};
use alloc::boxed::Box;
use bitcoin::{OutPoint, Script, ScriptBuf, Txid};
@@ -160,7 +159,7 @@ impl SyncRequest {
#[must_use]
pub fn populate_with_revealed_spks<K: Clone + Ord + core::fmt::Debug + Send + Sync>(
self,
index: &crate::keychain::KeychainTxOutIndex<K>,
index: &crate::indexer::keychain_txout::KeychainTxOutIndex<K>,
spk_range: impl core::ops::RangeBounds<K>,
) -> Self {
use alloc::borrow::ToOwned;
@@ -216,12 +215,12 @@ impl<K: Ord + Clone> FullScanRequest<K> {
/// [`KeychainTxOutIndex::all_unbounded_spk_iters`] and is used to populate the
/// [`FullScanRequest`].
///
/// [`KeychainTxOutIndex::all_unbounded_spk_iters`]: crate::keychain::KeychainTxOutIndex::all_unbounded_spk_iters
/// [`KeychainTxOutIndex::all_unbounded_spk_iters`]: crate::indexer::keychain_txout::KeychainTxOutIndex::all_unbounded_spk_iters
#[cfg(feature = "miniscript")]
#[must_use]
pub fn from_keychain_txout_index(
chain_tip: CheckPoint,
index: &crate::keychain::KeychainTxOutIndex<K>,
index: &crate::indexer::keychain_txout::KeychainTxOutIndex<K>,
) -> Self
where
K: core::fmt::Debug,

View File

@@ -1,7 +1,7 @@
use crate::{
bitcoin::{secp256k1::Secp256k1, ScriptBuf},
keychain::Indexed,
miniscript::{Descriptor, DescriptorPublicKey},
Indexed,
};
use core::{borrow::Borrow, ops::Bound, ops::RangeBounds};
@@ -137,7 +137,7 @@ where
mod test {
use crate::{
bitcoin::secp256k1::Secp256k1,
keychain::KeychainTxOutIndex,
indexer::keychain_txout::KeychainTxOutIndex,
miniscript::{Descriptor, DescriptorPublicKey},
spk_iter::{SpkIterator, BIP32_MAX_INDEX},
};

View File

@@ -89,8 +89,7 @@
//! [`insert_txout`]: TxGraph::insert_txout
use crate::{
collections::*, keychain::Balance, Anchor, Append, BlockId, ChainOracle, ChainPosition,
FullTxOut,
collections::*, Anchor, Append, Balance, BlockId, ChainOracle, ChainPosition, FullTxOut,
};
use alloc::collections::vec_deque::VecDeque;
use alloc::sync::Arc;

View File

@@ -8,9 +8,9 @@ use std::{collections::BTreeSet, sync::Arc};
use crate::common::DESCRIPTORS;
use bdk_chain::{
indexed_tx_graph::{self, IndexedTxGraph},
keychain::{self, Balance, KeychainTxOutIndex},
indexer::keychain_txout::KeychainTxOutIndex,
local_chain::LocalChain,
tx_graph, Append, ChainPosition, ConfirmationHeightAnchor, DescriptorExt,
tx_graph, Append, Balance, ChainPosition, ConfirmationHeightAnchor, DescriptorExt,
};
use bitcoin::{
secp256k1::Secp256k1, Amount, OutPoint, Script, ScriptBuf, Transaction, TxIn, TxOut,
@@ -26,6 +26,7 @@ use miniscript::Descriptor;
/// agnostic.
#[test]
fn insert_relevant_txs() {
use bdk_chain::indexer::keychain_txout;
let (descriptor, _) = Descriptor::parse_descriptor(&Secp256k1::signing_only(), DESCRIPTORS[0])
.expect("must be valid");
let spk_0 = descriptor.at_derivation_index(0).unwrap().script_pubkey();
@@ -76,7 +77,7 @@ fn insert_relevant_txs() {
txs: txs.iter().cloned().map(Arc::new).collect(),
..Default::default()
},
indexer: keychain::ChangeSet {
indexer: keychain_txout::ChangeSet {
last_revealed: [(descriptor.descriptor_id(), 9_u32)].into(),
keychains_added: [].into(),
},
@@ -90,7 +91,7 @@ fn insert_relevant_txs() {
// The initial changeset will also contain info about the keychain we added
let initial_changeset = indexed_tx_graph::ChangeSet {
graph: changeset.graph,
indexer: keychain::ChangeSet {
indexer: keychain_txout::ChangeSet {
last_revealed: changeset.indexer.last_revealed,
keychains_added: [((), descriptor)].into(),
},

View File

@@ -4,9 +4,8 @@
mod common;
use bdk_chain::{
collections::BTreeMap,
indexed_tx_graph::Indexer,
keychain::{self, ChangeSet, KeychainTxOutIndex},
Append, DescriptorExt, DescriptorId,
indexer::keychain_txout::{ChangeSet, KeychainTxOutIndex},
Append, DescriptorExt, DescriptorId, Indexer,
};
use bitcoin::{secp256k1::Secp256k1, Amount, OutPoint, ScriptBuf, Transaction, TxOut};
@@ -31,8 +30,8 @@ fn init_txout_index(
external_descriptor: Descriptor<DescriptorPublicKey>,
internal_descriptor: Descriptor<DescriptorPublicKey>,
lookahead: u32,
) -> bdk_chain::keychain::KeychainTxOutIndex<TestKeychain> {
let mut txout_index = bdk_chain::keychain::KeychainTxOutIndex::<TestKeychain>::new(lookahead);
) -> KeychainTxOutIndex<TestKeychain> {
let mut txout_index = KeychainTxOutIndex::<TestKeychain>::new(lookahead);
let _ = txout_index
.insert_descriptor(TestKeychain::External, external_descriptor)
@@ -146,8 +145,6 @@ fn when_apply_contradictory_changesets_they_are_ignored() {
#[test]
fn test_set_all_derivation_indices() {
use bdk_chain::indexed_tx_graph::Indexer;
let external_descriptor = parse_descriptor(DESCRIPTORS[0]);
let internal_descriptor = parse_descriptor(DESCRIPTORS[1]);
let mut txout_index =
@@ -169,7 +166,7 @@ fn test_set_all_derivation_indices() {
assert_eq!(txout_index.last_revealed_indices(), derive_to);
assert_eq!(
txout_index.reveal_to_target_multi(&derive_to),
keychain::ChangeSet::default(),
ChangeSet::default(),
"no changes if we set to the same thing"
);
assert_eq!(txout_index.initial_changeset().last_revealed, last_revealed);
@@ -304,7 +301,7 @@ fn test_lookahead() {
],
..common::new_tx(external_index)
};
assert_eq!(txout_index.index_tx(&tx), keychain::ChangeSet::default());
assert_eq!(txout_index.index_tx(&tx), ChangeSet::default());
assert_eq!(
txout_index.last_revealed_index(&TestKeychain::External),
Some(last_external_index)
@@ -643,14 +640,14 @@ fn insert_descriptor_no_change() {
let mut txout_index = KeychainTxOutIndex::<()>::default();
assert_eq!(
txout_index.insert_descriptor((), desc.clone()),
Ok(keychain::ChangeSet {
Ok(ChangeSet {
keychains_added: [((), desc.clone())].into(),
last_revealed: Default::default()
}),
);
assert_eq!(
txout_index.insert_descriptor((), desc.clone()),
Ok(keychain::ChangeSet::default()),
Ok(ChangeSet::default()),
"inserting the same descriptor for keychain should return an empty changeset",
);
}

View File

@@ -1,4 +1,4 @@
use bdk_chain::{indexed_tx_graph::Indexer, SpkTxOutIndex};
use bdk_chain::{Indexer, SpkTxOutIndex};
use bitcoin::{
absolute, transaction, Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxIn, TxOut,
};

View File

@@ -5,7 +5,7 @@ mod common;
use std::collections::{BTreeSet, HashSet};
use bdk_chain::{keychain::Balance, BlockId};
use bdk_chain::{Balance, BlockId};
use bitcoin::{Amount, OutPoint, Script};
use common::*;