From e8df529668bc70b2c67f76ae41c43c55537d1461 Mon Sep 17 00:00:00 2001 From: Daniela Brozzoni Date: Wed, 16 Aug 2023 17:39:35 +0200 Subject: [PATCH] feat(chain): Add `initial_changeset` to graphs Add `initial_changeset` to TxGraph and IndexedTxGraph --- crates/chain/src/indexed_tx_graph.rs | 10 ++++++++++ crates/chain/src/keychain.rs | 1 + crates/chain/src/keychain/txout_index.rs | 4 ++++ crates/chain/src/spk_txout_index.rs | 2 ++ crates/chain/src/tx_graph.rs | 5 +++++ crates/chain/tests/test_indexed_tx_graph.rs | 20 +++++++++++-------- .../chain/tests/test_keychain_txout_index.rs | 3 +++ crates/chain/tests/test_tx_graph.rs | 15 ++++++++++++-- 8 files changed, 50 insertions(+), 10 deletions(-) diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index e21e53530b..e64f4c0fca 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -61,6 +61,13 @@ impl IndexedTxGraph { self.graph.apply_changeset(graph); } + + /// Determines the changeset between self and the empty [`IndexedTxGraph`]. + pub fn initial_changeset(&self) -> ChangeSet { + let graph = self.graph.initial_changeset(); + let indexer = self.index.initial_changeset(); + ChangeSet { graph, indexer } + } } impl IndexedTxGraph @@ -234,6 +241,9 @@ pub trait Indexer { /// Apply changeset to itself. fn apply_changeset(&mut self, changeset: Self::ChangeSet); + /// Determines the changeset between self and the 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; } diff --git a/crates/chain/src/keychain.rs b/crates/chain/src/keychain.rs index 1a2adab881..64d68d81e9 100644 --- a/crates/chain/src/keychain.rs +++ b/crates/chain/src/keychain.rs @@ -20,6 +20,7 @@ mod txout_index; pub use txout_index::*; /// Represents updates to the derivation index of a [`KeychainTxOutIndex`]. +/// It maps each keychain `K` to its last revealed index. /// /// It can be applied to [`KeychainTxOutIndex`] with [`apply_changeset`]. [`ChangeSet] are /// monotone in that they will never decrease the revealed derivation index. diff --git a/crates/chain/src/keychain/txout_index.rs b/crates/chain/src/keychain/txout_index.rs index 456fb4c0c2..9b38a7ade4 100644 --- a/crates/chain/src/keychain/txout_index.rs +++ b/crates/chain/src/keychain/txout_index.rs @@ -98,6 +98,10 @@ impl Indexer for KeychainTxOutIndex { self.scan(tx) } + fn initial_changeset(&self) -> Self::ChangeSet { + super::ChangeSet(self.last_revealed.clone()) + } + fn apply_changeset(&mut self, changeset: Self::ChangeSet) { self.apply_changeset(changeset) } diff --git a/crates/chain/src/spk_txout_index.rs b/crates/chain/src/spk_txout_index.rs index e9e5e16a58..db749f44c7 100644 --- a/crates/chain/src/spk_txout_index.rs +++ b/crates/chain/src/spk_txout_index.rs @@ -66,6 +66,8 @@ impl Indexer for SpkTxOutIndex { Default::default() } + fn initial_changeset(&self) -> Self::ChangeSet {} + fn apply_changeset(&mut self, _changeset: Self::ChangeSet) { // This applies nothing. } diff --git a/crates/chain/src/tx_graph.rs b/crates/chain/src/tx_graph.rs index 028a84ee7f..054a1f3e7b 100644 --- a/crates/chain/src/tx_graph.rs +++ b/crates/chain/src/tx_graph.rs @@ -438,6 +438,11 @@ impl TxGraph { changeset } + /// Determines the changeset between self and the empty [`TxGraph`]. + pub fn initial_changeset(&self) -> ChangeSet { + Self::default().apply_update(self.clone()) + } + /// Applies [`ChangeSet`] to [`TxGraph`]. pub fn apply_changeset(&mut self, changeset: ChangeSet) { for tx in changeset.txs { diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs index 85c79950ad..84506ec118 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -65,16 +65,20 @@ fn insert_relevant_txs() { let txs = [tx_c, tx_b, tx_a]; + let changeset = indexed_tx_graph::ChangeSet { + graph: tx_graph::ChangeSet { + txs: txs.clone().into(), + ..Default::default() + }, + indexer: keychain::ChangeSet([((), 9_u32)].into()), + }; + assert_eq!( graph.insert_relevant_txs(txs.iter().map(|tx| (tx, None)), None), - indexed_tx_graph::ChangeSet { - graph: tx_graph::ChangeSet { - txs: txs.into(), - ..Default::default() - }, - indexer: keychain::ChangeSet([((), 9_u32)].into()), - } - ) + changeset, + ); + + assert_eq!(graph.initial_changeset(), changeset,); } #[test] diff --git a/crates/chain/tests/test_keychain_txout_index.rs b/crates/chain/tests/test_keychain_txout_index.rs index 937dd6e789..96a1afd1ac 100644 --- a/crates/chain/tests/test_keychain_txout_index.rs +++ b/crates/chain/tests/test_keychain_txout_index.rs @@ -43,6 +43,8 @@ fn spk_at_index(descriptor: &Descriptor, index: u32) -> Scr #[test] fn test_set_all_derivation_indices() { + use bdk_chain::indexed_tx_graph::Indexer; + let (mut txout_index, _, _) = init_txout_index(); let derive_to: BTreeMap<_, _> = [(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into(); @@ -56,6 +58,7 @@ fn test_set_all_derivation_indices() { keychain::ChangeSet::default(), "no changes if we set to the same thing" ); + assert_eq!(txout_index.initial_changeset().as_inner(), &derive_to); } #[test] diff --git a/crates/chain/tests/test_tx_graph.rs b/crates/chain/tests/test_tx_graph.rs index e3c7d7ff47..1db1f05f97 100644 --- a/crates/chain/tests/test_tx_graph.rs +++ b/crates/chain/tests/test_tx_graph.rs @@ -141,14 +141,14 @@ fn insert_txouts() { changeset, ChangeSet { txs: [update_txs.clone()].into(), - txouts: update_ops.into(), + txouts: update_ops.clone().into(), anchors: [(conf_anchor, update_txs.txid()), (unconf_anchor, h!("tx2"))].into(), last_seen: [(h!("tx2"), 1000000)].into() } ); // Apply changeset and check the new graph counts. - graph.apply_changeset(changeset); + graph.apply_changeset(changeset.clone()); assert_eq!(graph.all_txouts().count(), 4); assert_eq!(graph.full_txs().count(), 1); assert_eq!(graph.floating_txouts().count(), 3); @@ -186,6 +186,17 @@ fn insert_txouts() { )] .into() ); + + // Check that the initial_changeset is correct + assert_eq!( + graph.initial_changeset(), + ChangeSet { + txs: [update_txs.clone()].into(), + txouts: update_ops.into_iter().chain(original_ops).collect(), + anchors: [(conf_anchor, update_txs.txid()), (unconf_anchor, h!("tx2"))].into(), + last_seen: [(h!("tx2"), 1000000)].into() + } + ); } #[test]