From a0555817136e4ef5a36272cb311123e0bce54657 Mon Sep 17 00:00:00 2001 From: =?utf8?q?=E5=BF=97=E5=AE=87?= Date: Fri, 23 May 2025 15:44:35 +1000 Subject: [PATCH] feat(chain): `KeychainTxOutIndex`: Make spk cache optional Also added staging changes to `ChangeSet::spk_cache`. This way, we can avoid returning `ChangeSet`s for `apply_changeset` and `insert_descriptor`. * `KeychainTxOutIndex::new` now takes in an additional `use_spk_cache` parameter. * Fixed `reveal_to_target` method to actually return `None` if the keychain does not exist. --- crates/bitcoind_rpc/examples/filter_iter.rs | 5 +- crates/chain/benches/canonicalization.rs | 4 +- crates/chain/src/indexer/keychain_txout.rs | 286 ++++++++++-------- crates/chain/src/spk_iter.rs | 6 +- crates/chain/tests/test_indexed_tx_graph.rs | 43 +-- .../chain/tests/test_keychain_txout_index.rs | 28 +- examples/example_cli/src/lib.rs | 7 +- 7 files changed, 204 insertions(+), 175 deletions(-) diff --git a/crates/bitcoind_rpc/examples/filter_iter.rs b/crates/bitcoind_rpc/examples/filter_iter.rs index b80542bc..21300e70 100644 --- a/crates/bitcoind_rpc/examples/filter_iter.rs +++ b/crates/bitcoind_rpc/examples/filter_iter.rs @@ -33,9 +33,8 @@ fn main() -> anyhow::Result<()> { let (mut chain, _) = LocalChain::from_genesis_hash(genesis_block(NETWORK).block_hash()); let mut graph = IndexedTxGraph::>::new({ let mut index = KeychainTxOutIndex::default(); - // TODO: Properly deal with these changesets. - let _ = index.insert_descriptor("external", descriptor.clone())?; - let _ = index.insert_descriptor("internal", change_descriptor.clone())?; + index.insert_descriptor("external", descriptor.clone())?; + index.insert_descriptor("internal", change_descriptor.clone())?; index }); diff --git a/crates/chain/benches/canonicalization.rs b/crates/chain/benches/canonicalization.rs index 4cb26c6b..df9c08b0 100644 --- a/crates/chain/benches/canonicalization.rs +++ b/crates/chain/benches/canonicalization.rs @@ -82,8 +82,8 @@ fn setup(f: F) -> (KeychainTxGraph, Lo let (desc, _) = >::parse_descriptor(&Secp256k1::new(), DESC).unwrap(); - let mut index = KeychainTxOutIndex::new(10); - let _ = index.insert_descriptor((), desc).unwrap(); + let mut index = KeychainTxOutIndex::new(10, true); + index.insert_descriptor((), desc).unwrap(); let mut tx_graph = KeychainTxGraph::new(index); f(&mut tx_graph, &chain); diff --git a/crates/chain/src/indexer/keychain_txout.rs b/crates/chain/src/indexer/keychain_txout.rs index 55486e9e..6332faae 100644 --- a/crates/chain/src/indexer/keychain_txout.rs +++ b/crates/chain/src/indexer/keychain_txout.rs @@ -132,12 +132,14 @@ pub struct KeychainTxOutIndex { last_revealed: HashMap, lookahead: u32, + use_spk_cache: bool, spk_cache: BTreeMap>, + spk_cache_stage: BTreeMap>, } impl Default for KeychainTxOutIndex { fn default() -> Self { - Self::new(DEFAULT_LOOKAHEAD) + Self::new(DEFAULT_LOOKAHEAD, false) } } @@ -152,31 +154,18 @@ impl Indexer for KeychainTxOutIndex { fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::ChangeSet { let mut changeset = ChangeSet::default(); - if let Some((keychain, index)) = self.inner.scan_txout(outpoint, txout).cloned() { - let did = self - .keychain_to_descriptor_id - .get(&keychain) - .expect("invariant"); - if self.last_revealed.get(did) < Some(&index) { - self.last_revealed.insert(*did, index); - changeset.last_revealed.insert(*did, index); - self.replenish_inner_index( - *did, - &keychain, - self.lookahead, - changeset.spk_cache.entry(*did).or_default(), - ); - } - } + self._index_txout(&mut changeset, outpoint, txout); + self._empty_stage_into_changeset(&mut changeset); changeset } fn index_tx(&mut self, tx: &bitcoin::Transaction) -> Self::ChangeSet { let mut changeset = ChangeSet::default(); let txid = tx.compute_txid(); - for (op, txout) in tx.output.iter().enumerate() { - changeset.merge(self.index_txout(OutPoint::new(txid, op as u32), txout)); + for (vout, txout) in tx.output.iter().enumerate() { + self._index_txout(&mut changeset, OutPoint::new(txid, vout as u32), txout); } + self._empty_stage_into_changeset(&mut changeset); changeset } @@ -206,7 +195,9 @@ impl Indexer for KeychainTxOutIndex { } impl KeychainTxOutIndex { - /// Construct a [`KeychainTxOutIndex`] with the given `lookahead`. + /// Construct a [`KeychainTxOutIndex`] with the given `lookahead` and `use_spk_cache` boolean. + /// + /// # 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 @@ -216,7 +207,11 @@ impl KeychainTxOutIndex { /// of the last revealed script pubkey actually is. /// /// Refer to [struct-level docs](KeychainTxOutIndex) for more about `lookahead`. - pub fn new(lookahead: u32) -> Self { + /// + /// # Script pubkey cache + /// + /// The `use_spk_cache` parameter enables the internal script pubkey cache. + pub fn new(lookahead: u32, use_spk_cache: bool) -> Self { Self { inner: SpkTxOutIndex::default(), keychain_to_descriptor_id: Default::default(), @@ -224,7 +219,9 @@ impl KeychainTxOutIndex { descriptor_id_to_keychain: Default::default(), last_revealed: Default::default(), lookahead, + use_spk_cache, spk_cache: Default::default(), + spk_cache_stage: Default::default(), } } @@ -237,12 +234,63 @@ impl KeychainTxOutIndex { /// Methods that are *re-exposed* from the internal [`SpkTxOutIndex`]. impl KeychainTxOutIndex { /// Construct `KeychainTxOutIndex` from the given `changeset`. - pub fn from_changeset(changeset: ChangeSet) -> Self { - let mut out = Self::default(); + /// + /// Shorthand for called [`new`] and then [`apply_changeset`]. + /// + /// [`new`]: Self::new + /// [`apply_changeset`]: Self::apply_changeset + pub fn from_changeset(lookahead: u32, use_spk_cache: bool, changeset: ChangeSet) -> Self { + let mut out = Self::new(lookahead, use_spk_cache); out.apply_changeset(changeset); out } + fn _index_txout(&mut self, changeset: &mut ChangeSet, outpoint: OutPoint, txout: &TxOut) { + if let Some((keychain, index)) = self.inner.scan_txout(outpoint, txout).cloned() { + let did = self + .keychain_to_descriptor_id + .get(&keychain) + .expect("invariant"); + let index_updated = match self.last_revealed.entry(*did) { + hash_map::Entry::Occupied(mut e) if e.get() < &index => { + e.insert(index); + true + } + hash_map::Entry::Vacant(e) => { + e.insert(index); + true + } + _ => false, + }; + if index_updated { + changeset.last_revealed.insert(*did, index); + self.replenish_inner_index(*did, &keychain, self.lookahead); + } + } + } + + fn _empty_stage_into_changeset(&mut self, changeset: &mut ChangeSet) { + if !self.use_spk_cache { + return; + } + for (did, spks) in core::mem::take(&mut self.spk_cache_stage) { + debug_assert!( + { + let desc = self.descriptors.get(&did).expect("invariant"); + spks.iter().all(|(i, spk)| { + let exp_spk = desc + .at_derivation_index(*i) + .expect("must derive") + .script_pubkey(); + &exp_spk == spk + }) + }, + "all staged spks must be correct" + ); + changeset.spk_cache.entry(did).or_default().extend(spks); + } + } + /// Get the set of indexed outpoints, corresponding to tracked keychains. pub fn outpoints(&self) -> &BTreeSet> { self.inner.outpoints() @@ -393,9 +441,7 @@ impl KeychainTxOutIndex { &mut self, keychain: K, descriptor: Descriptor, - ) -> Result<(bool, ChangeSet), InsertDescriptorError> { - let mut changeset = ChangeSet::default(); - + ) -> Result> { let did = descriptor.descriptor_id(); if !self.keychain_to_descriptor_id.contains_key(&keychain) && !self.descriptor_id_to_keychain.contains_key(&did) @@ -403,13 +449,8 @@ impl KeychainTxOutIndex { self.descriptors.insert(did, descriptor.clone()); self.keychain_to_descriptor_id.insert(keychain.clone(), did); self.descriptor_id_to_keychain.insert(did, keychain.clone()); - self.replenish_inner_index( - did, - &keychain, - self.lookahead, - changeset.spk_cache.entry(did).or_default(), - ); - return Ok((true, changeset)); + self.replenish_inner_index(did, &keychain, self.lookahead); + return Ok(true); } if let Some(existing_desc_id) = self.keychain_to_descriptor_id.get(&keychain) { @@ -433,7 +474,7 @@ impl KeychainTxOutIndex { } } - Ok((false, changeset)) + Ok(false) } /// Gets the descriptor associated with the keychain. Returns `None` if the keychain doesn't @@ -463,50 +504,27 @@ impl KeychainTxOutIndex { .filter(|&index| index > 0); if let Some(temp_lookahead) = temp_lookahead { - let did = self - .keychain_to_descriptor_id - .get(&keychain) - .expect("invariant"); - self.replenish_inner_index_keychain( - keychain, - temp_lookahead, - changeset.spk_cache.entry(*did).or_default(), - ); + self.replenish_inner_index_keychain(keychain, temp_lookahead); } } + self._empty_stage_into_changeset(&mut changeset); changeset } - fn replenish_inner_index_did( - &mut self, - did: DescriptorId, - lookahead: u32, - derived_spks: &mut impl Extend>, - ) { + fn replenish_inner_index_did(&mut self, did: DescriptorId, lookahead: u32) { if let Some(keychain) = self.descriptor_id_to_keychain.get(&did).cloned() { - self.replenish_inner_index(did, &keychain, lookahead, derived_spks); + self.replenish_inner_index(did, &keychain, lookahead); } } - fn replenish_inner_index_keychain( - &mut self, - keychain: K, - lookahead: u32, - derived_spks: &mut impl Extend>, - ) { + fn replenish_inner_index_keychain(&mut self, keychain: K, lookahead: u32) { if let Some(did) = self.keychain_to_descriptor_id.get(&keychain) { - self.replenish_inner_index(*did, &keychain, lookahead, derived_spks); + self.replenish_inner_index(*did, &keychain, lookahead); } } /// Syncs the state of the inner spk index after changes to a keychain - fn replenish_inner_index( - &mut self, - did: DescriptorId, - keychain: &K, - lookahead: u32, - derived_spks: &mut impl Extend>, - ) { + fn replenish_inner_index(&mut self, did: DescriptorId, keychain: &K, lookahead: u32) { let descriptor = self.descriptors.get(&did).expect("invariant"); let mut next_index = self @@ -524,43 +542,52 @@ impl KeychainTxOutIndex { 1 }; - let derive_spk = { - let secp = Secp256k1::verification_only(); - let _desc = &descriptor; - move |spk_i: u32| -> ScriptBuf { - _desc - .derived_descriptor(&secp, spk_i) - .expect("The descriptor cannot have hardened derivation") - .script_pubkey() - } - }; - - let cached_spk_iter = core::iter::from_fn({ - let spk_cache = self.spk_cache.entry(did).or_default(); - let _i = &mut next_index; - move || -> Option> { - if *_i >= stop_index { - return None; + if self.use_spk_cache { + let derive_spk = { + let secp = Secp256k1::verification_only(); + let _desc = &descriptor; + move |spk_i: u32| -> ScriptBuf { + _desc + .derived_descriptor(&secp, spk_i) + .expect("The descriptor cannot have hardened derivation") + .script_pubkey() } - let spk_i = *_i; - *_i = spk_i.saturating_add(1); + }; + let cached_spk_iter = core::iter::from_fn({ + let spk_cache = self.spk_cache.entry(did).or_default(); + let spk_stage = self.spk_cache_stage.entry(did).or_default(); + let _i = &mut next_index; + move || -> Option> { + if *_i >= stop_index { + return None; + } + let spk_i = *_i; + *_i = spk_i.saturating_add(1); - if let Some(spk) = spk_cache.get(&spk_i) { - debug_assert_eq!(spk, &derive_spk(spk_i), "cached spk must equal derived"); - return Some((spk_i, spk.clone())); + if let Some(spk) = spk_cache.get(&spk_i) { + debug_assert_eq!(spk, &derive_spk(spk_i), "cached spk must equal derived"); + return Some((spk_i, spk.clone())); + } + let spk = derive_spk(spk_i); + spk_stage.push((spk_i, spk.clone())); + spk_cache.insert(spk_i, spk.clone()); + Some((spk_i, spk)) } - let spk = derive_spk(spk_i); - derived_spks.extend(core::iter::once((spk_i, spk.clone()))); - spk_cache.insert(spk_i, spk.clone()); - Some((spk_i, spk)) + }); + for (new_index, new_spk) in cached_spk_iter { + let _inserted = self + .inner + .insert_spk((keychain.clone(), new_index), new_spk); + debug_assert!(_inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_index={}", keychain, lookahead, next_index); + } + } else { + let spk_iter = SpkIterator::new_with_range(descriptor, next_index..stop_index); + for (new_index, new_spk) in spk_iter { + let _inserted = self + .inner + .insert_spk((keychain.clone(), new_index), new_spk); + debug_assert!(_inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_index={}", keychain, lookahead, next_index); } - }); - - for (new_index, new_spk) in cached_spk_iter { - let _inserted = self - .inner - .insert_spk((keychain.clone(), new_index), new_spk); - debug_assert!(_inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_index={}", keychain, lookahead, next_index); } } @@ -729,11 +756,10 @@ impl KeychainTxOutIndex { let mut changeset = ChangeSet::default(); for (keychain, &index) in keychains { - if let Some((_, new_changeset)) = self.reveal_to_target(keychain.clone(), index) { - changeset.merge(new_changeset); - } + self._reveal_to_target(&mut changeset, keychain.clone(), index); } + self._empty_stage_into_changeset(&mut changeset); changeset } @@ -756,21 +782,28 @@ impl KeychainTxOutIndex { target_index: u32, ) -> Option<(Vec>, ChangeSet)> { let mut changeset = ChangeSet::default(); + let revealed_spks = self._reveal_to_target(&mut changeset, keychain, target_index)?; + self._empty_stage_into_changeset(&mut changeset); + Some((revealed_spks, changeset)) + } + fn _reveal_to_target( + &mut self, + changeset: &mut ChangeSet, + keychain: K, + target_index: u32, + ) -> Option>> { let mut spks: Vec> = vec![]; - while let Some((i, new)) = self.next_index(keychain.clone()) { + loop { + let (i, new) = self.next_index(keychain.clone())?; if !new || i > target_index { break; } - match self.reveal_next_spk(keychain.clone()) { - Some(((i, spk), change)) => { - spks.push((i, spk)); - changeset.merge(change); - } + match self._reveal_next_spk(changeset, keychain.clone()) { + Some(indexed_spk) => spks.push(indexed_spk), None => break, } } - - Some((spks, changeset)) + Some(spks) } /// Attempts to reveal the next script pubkey for `keychain`. @@ -786,25 +819,28 @@ impl KeychainTxOutIndex { /// 2. The descriptor has already revealed scripts up to the numeric bound. /// 3. There is no descriptor associated with the given keychain. pub fn reveal_next_spk(&mut self, keychain: K) -> Option<(Indexed, ChangeSet)> { - let (next_index, new) = self.next_index(keychain.clone())?; let mut changeset = ChangeSet::default(); - + let indexed_spk = self._reveal_next_spk(&mut changeset, keychain)?; + self._empty_stage_into_changeset(&mut changeset); + Some((indexed_spk, changeset)) + } + fn _reveal_next_spk( + &mut self, + changeset: &mut ChangeSet, + keychain: K, + ) -> Option> { + let (next_index, new) = self.next_index(keychain.clone())?; if new { let did = self.keychain_to_descriptor_id.get(&keychain)?; self.last_revealed.insert(*did, next_index); changeset.last_revealed.insert(*did, next_index); - self.replenish_inner_index( - *did, - &keychain, - self.lookahead, - changeset.spk_cache.entry(*did).or_default(), - ); + self.replenish_inner_index(*did, &keychain, self.lookahead); } let script = self .inner .spk_at_index(&(keychain.clone(), next_index)) .expect("we just inserted it"); - Some(((next_index, script), changeset)) + Some((next_index, script)) } /// Gets the next unused script pubkey in the keychain. I.e., the script pubkey with the lowest @@ -821,12 +857,14 @@ impl KeychainTxOutIndex { /// /// [`reveal_next_spk`]: Self::reveal_next_spk pub fn next_unused_spk(&mut self, keychain: K) -> Option<(Indexed, ChangeSet)> { + let mut changeset = ChangeSet::default(); let next_unused = self .unused_keychain_spks(keychain.clone()) .next() - .map(|(i, spk)| ((i, spk.to_owned()), ChangeSet::default())); - - next_unused.or_else(|| self.reveal_next_spk(keychain)) + .map(|(i, spk)| (i, spk.to_owned())); + let spk = next_unused.or_else(|| self._reveal_next_spk(&mut changeset, keychain))?; + self._empty_stage_into_changeset(&mut changeset); + Some((spk, changeset)) } /// Iterate over all [`OutPoint`]s that have `TxOut`s with script pubkeys derived from @@ -887,10 +925,12 @@ impl KeychainTxOutIndex { for (did, index) in changeset.last_revealed { let v = self.last_revealed.entry(did).or_default(); *v = index.max(*v); - self.replenish_inner_index_did(did, self.lookahead, &mut Vec::new()); + self.replenish_inner_index_did(did, self.lookahead); } - for (did, spks) in changeset.spk_cache { - self.spk_cache.entry(did).or_default().extend(spks); + if self.use_spk_cache { + for (did, spks) in changeset.spk_cache { + self.spk_cache.entry(did).or_default().extend(spks); + } } } } diff --git a/crates/chain/src/spk_iter.rs b/crates/chain/src/spk_iter.rs index 33d78c33..64f38c6d 100644 --- a/crates/chain/src/spk_iter.rs +++ b/crates/chain/src/spk_iter.rs @@ -153,16 +153,16 @@ mod test { Descriptor, Descriptor, ) { - let mut txout_index = KeychainTxOutIndex::::new(0); + let mut txout_index = KeychainTxOutIndex::::new(0, true); let secp = Secp256k1::signing_only(); let (external_descriptor,_) = Descriptor::::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap(); let (internal_descriptor,_) = Descriptor::::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap(); - let _ = txout_index + txout_index .insert_descriptor(TestKeychain::External, external_descriptor.clone()) .unwrap(); - let _ = txout_index + txout_index .insert_descriptor(TestKeychain::Internal, internal_descriptor.clone()) .unwrap(); diff --git a/crates/chain/tests/test_indexed_tx_graph.rs b/crates/chain/tests/test_indexed_tx_graph.rs index abc2c823..5f23af55 100644 --- a/crates/chain/tests/test_indexed_tx_graph.rs +++ b/crates/chain/tests/test_indexed_tx_graph.rs @@ -36,24 +36,13 @@ fn insert_relevant_txs() { let lookahead = 10; let mut graph = IndexedTxGraph::>::new( - KeychainTxOutIndex::new(lookahead), + KeychainTxOutIndex::new(lookahead, true), ); - let (is_inserted, changeset) = graph + let is_inserted = graph .index .insert_descriptor((), descriptor.clone()) .unwrap(); assert!(is_inserted); - assert_eq!( - changeset, - keychain_txout::ChangeSet { - spk_cache: [( - descriptor.descriptor_id(), - SpkIterator::new_with_range(&descriptor, 0..lookahead).collect() - )] - .into(), - ..Default::default() - } - ); let tx_a = Transaction { output: vec![ @@ -98,7 +87,9 @@ fn insert_relevant_txs() { let index_after_spk_1 = 9 /* index of spk_1 */ + 1; SpkIterator::new_with_range( &descriptor, - index_after_spk_1..index_after_spk_1 + lookahead, + // This will also persist the staged spk cache inclusions from prev call to + // `.insert_descriptor`. + 0..index_after_spk_1 + lookahead, ) .collect() })] @@ -170,23 +161,17 @@ fn test_list_owned_txouts() { Descriptor::parse_descriptor(&Secp256k1::signing_only(), DESCRIPTORS[3]).unwrap(); let mut graph = IndexedTxGraph::>::new( - KeychainTxOutIndex::new(10), + KeychainTxOutIndex::new(10, true), ); - assert!( - graph - .index - .insert_descriptor("keychain_1".into(), desc_1) - .unwrap() - .0 - ); - assert!( - graph - .index - .insert_descriptor("keychain_2".into(), desc_2) - .unwrap() - .0 - ); + assert!(graph + .index + .insert_descriptor("keychain_1".into(), desc_1) + .unwrap()); + assert!(graph + .index + .insert_descriptor("keychain_2".into(), desc_2) + .unwrap()); // Get trusted and untrusted addresses diff --git a/crates/chain/tests/test_keychain_txout_index.rs b/crates/chain/tests/test_keychain_txout_index.rs index 6619d5c2..0cce8476 100644 --- a/crates/chain/tests/test_keychain_txout_index.rs +++ b/crates/chain/tests/test_keychain_txout_index.rs @@ -29,8 +29,9 @@ fn init_txout_index( external_descriptor: Descriptor, internal_descriptor: Descriptor, lookahead: u32, + use_spk_cache: bool, ) -> KeychainTxOutIndex { - let mut txout_index = KeychainTxOutIndex::::new(lookahead); + let mut txout_index = KeychainTxOutIndex::::new(lookahead, use_spk_cache); let _ = txout_index .insert_descriptor(TestKeychain::External, external_descriptor) @@ -108,6 +109,7 @@ fn test_set_all_derivation_indices() { external_descriptor.clone(), internal_descriptor.clone(), lookahead, + true, ); let derive_to: BTreeMap<_, _> = [(TestKeychain::External, 12), (TestKeychain::Internal, 24)].into(); @@ -152,6 +154,7 @@ fn test_lookahead() { external_descriptor.clone(), internal_descriptor.clone(), lookahead, + true, ); // given: @@ -333,8 +336,12 @@ fn test_lookahead() { fn test_scan_with_lookahead() { let external_descriptor = parse_descriptor(DESCRIPTORS[0]); let internal_descriptor = parse_descriptor(DESCRIPTORS[1]); - let mut txout_index = - init_txout_index(external_descriptor.clone(), internal_descriptor.clone(), 10); + let mut txout_index = init_txout_index( + external_descriptor.clone(), + internal_descriptor.clone(), + 10, + true, + ); let spks: BTreeMap = [0, 10, 20, 30] .into_iter() @@ -390,7 +397,7 @@ fn test_scan_with_lookahead() { fn test_wildcard_derivations() { let external_descriptor = parse_descriptor(DESCRIPTORS[0]); let internal_descriptor = parse_descriptor(DESCRIPTORS[1]); - let mut txout_index = init_txout_index(external_descriptor.clone(), internal_descriptor.clone(), 0); + let mut txout_index = init_txout_index(external_descriptor.clone(), internal_descriptor.clone(), 0, true); let external_spk_0 = external_descriptor.at_derivation_index(0).unwrap().script_pubkey(); let external_spk_16 = external_descriptor.at_derivation_index(16).unwrap().script_pubkey(); let external_spk_26 = external_descriptor.at_derivation_index(26).unwrap().script_pubkey(); @@ -448,7 +455,7 @@ fn test_wildcard_derivations() { #[test] fn test_non_wildcard_derivations() { - let mut txout_index = KeychainTxOutIndex::::new(0); + let mut txout_index = KeychainTxOutIndex::::new(0, true); let secp = bitcoin::secp256k1::Secp256k1::signing_only(); let (no_wildcard_descriptor, _) = @@ -574,6 +581,7 @@ fn lookahead_to_target() { external_descriptor.clone(), internal_descriptor.clone(), t.lookahead, + true, ); if let Some(last_revealed) = t.external_last_revealed { @@ -632,7 +640,7 @@ fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() { }, ]; - let mut indexer_a = KeychainTxOutIndex::::new(0); + let mut indexer_a = KeychainTxOutIndex::::new(0, true); let _ = indexer_a .insert_descriptor(TestKeychain::External, desc.clone()) .expect("must insert keychain"); @@ -640,7 +648,7 @@ fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() { indexer_a.apply_changeset(changeset.clone()); } - let mut indexer_b = KeychainTxOutIndex::::new(0); + let mut indexer_b = KeychainTxOutIndex::::new(0, true); let _ = indexer_b .insert_descriptor(TestKeychain::External, desc.clone()) .expect("must insert keychain"); @@ -675,7 +683,7 @@ fn applying_changesets_one_by_one_vs_aggregate_must_have_same_result() { #[test] fn assigning_same_descriptor_to_multiple_keychains_should_error() { let desc = parse_descriptor(DESCRIPTORS[0]); - let mut indexer = KeychainTxOutIndex::::new(0); + let mut indexer = KeychainTxOutIndex::::new(0, true); let _ = indexer .insert_descriptor(TestKeychain::Internal, desc.clone()) .unwrap(); @@ -688,7 +696,7 @@ fn assigning_same_descriptor_to_multiple_keychains_should_error() { fn reassigning_keychain_to_a_new_descriptor_should_error() { let desc1 = parse_descriptor(DESCRIPTORS[0]); let desc2 = parse_descriptor(DESCRIPTORS[1]); - let mut indexer = KeychainTxOutIndex::::new(0); + let mut indexer = KeychainTxOutIndex::::new(0, true); let _ = indexer.insert_descriptor(TestKeychain::Internal, desc1); assert!(indexer .insert_descriptor(TestKeychain::Internal, desc2) @@ -697,7 +705,7 @@ fn reassigning_keychain_to_a_new_descriptor_should_error() { #[test] fn when_querying_over_a_range_of_keychains_the_utxos_should_show_up() { - let mut indexer = KeychainTxOutIndex::::new(0); + let mut indexer = KeychainTxOutIndex::::new(0, true); let mut tx = new_tx(0); for (i, descriptor) in DESCRIPTORS.iter().enumerate() { diff --git a/examples/example_cli/src/lib.rs b/examples/example_cli/src/lib.rs index 1fb1abc3..d432d12b 100644 --- a/examples/example_cli/src/lib.rs +++ b/examples/example_cli/src/lib.rs @@ -836,13 +836,10 @@ pub fn init_or_load( // insert descriptors and apply loaded changeset let mut index = KeychainTxOutIndex::default(); if let Some(desc) = changeset.descriptor { - // TODO: We should apply changeset to the graph before inserting descriptors. - // TODO: Then persist the new _changesets returned to db. - let (_, _changeset) = index.insert_descriptor(Keychain::External, desc)?; + index.insert_descriptor(Keychain::External, desc)?; } if let Some(change_desc) = changeset.change_descriptor { - let (_, _changeset) = - index.insert_descriptor(Keychain::Internal, change_desc)?; + index.insert_descriptor(Keychain::Internal, change_desc)?; } let mut graph = KeychainTxGraph::new(index); graph.apply_changeset(indexed_tx_graph::ChangeSet { -- 2.49.0