@@ -5,12 +5,13 @@ use crate::{
55 spk_iter:: BIP32_MAX_INDEX ,
66 SpkIterator , SpkTxOutIndex ,
77} ;
8- use alloc:: vec:: Vec ;
98use bitcoin:: { OutPoint , Script , TxOut } ;
109use core:: { fmt:: Debug , ops:: Deref } ;
1110
1211use crate :: Append ;
1312
13+ const DEFAULT_LOOKAHEAD : u32 = 1_000 ;
14+
1415/// A convenient wrapper around [`SpkTxOutIndex`] that relates script pubkeys to miniscript public
1516/// [`Descriptor`]s.
1617///
@@ -46,7 +47,7 @@ use crate::Append;
4647/// # let secp = bdk_chain::bitcoin::secp256k1::Secp256k1::signing_only();
4748/// # let (external_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/0/*)").unwrap();
4849/// # let (internal_descriptor,_) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/1/*)").unwrap();
49- /// # let descriptor_for_user_42 = external_descriptor.clone ();
50+ /// # let ( descriptor_for_user_42, _) = Descriptor::<DescriptorPublicKey>::parse_descriptor(&secp, "tr([73c5da0a/86'/0'/0']xprv9xgqHN7yz9MwCkxsBPN5qetuNdQSUttZNKw1dcYTV4mkaAFiBVGQziHs3NRSWMkCzvgjEe3n9xV8oYywvM8at9yRqyaZVz6TYYhX98VjsUk/2/*)").unwrap ();
5051/// txout_index.add_keychain(MyKeychain::External, external_descriptor);
5152/// txout_index.add_keychain(MyKeychain::Internal, internal_descriptor);
5253/// txout_index.add_keychain(MyKeychain::MyAppUser { user_id: 42 }, descriptor_for_user_42);
@@ -65,17 +66,12 @@ pub struct KeychainTxOutIndex<K> {
6566 // last revealed indexes
6667 last_revealed : BTreeMap < K , u32 > ,
6768 // lookahead settings for each keychain
68- lookahead : BTreeMap < K , u32 > ,
69+ lookahead : u32 ,
6970}
7071
7172impl < K > Default for KeychainTxOutIndex < K > {
7273 fn default ( ) -> Self {
73- Self {
74- inner : SpkTxOutIndex :: default ( ) ,
75- keychains : BTreeMap :: default ( ) ,
76- last_revealed : BTreeMap :: default ( ) ,
77- lookahead : BTreeMap :: default ( ) ,
78- }
74+ Self :: new ( DEFAULT_LOOKAHEAD )
7975 }
8076}
8177
@@ -118,6 +114,24 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
118114 }
119115}
120116
117+ impl < K > KeychainTxOutIndex < K > {
118+ /// Construct a [`KeychainTxOutIndex`] with the given `lookahead`.
119+ ///
120+ /// The lookahead is the number of scripts to cache ahead of the last revealed script index.
121+ /// This is useful to find outputs you own when processing block data that lie beyond the last
122+ /// revealed index. In certain situations, such as when performing an initial scan of the
123+ /// blockchain during wallet import, it may be uncertain or unknown what the last revealed index
124+ /// is.
125+ pub fn new ( lookahead : u32 ) -> Self {
126+ Self {
127+ inner : SpkTxOutIndex :: default ( ) ,
128+ keychains : BTreeMap :: new ( ) ,
129+ last_revealed : BTreeMap :: new ( ) ,
130+ lookahead,
131+ }
132+ }
133+ }
134+
121135impl < K : Clone + Ord + Debug > KeychainTxOutIndex < K > {
122136 /// Return a reference to the internal [`SpkTxOutIndex`].
123137 pub fn inner ( & self ) -> & SpkTxOutIndex < ( K , u32 ) > {
@@ -142,57 +156,23 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
142156 /// # Panics
143157 ///
144158 /// This will panic if a different `descriptor` is introduced to the same `keychain`.
159+ ///
160+ /// [`add_keychain_with_lookahead`]: Self::add_keychain_with_lookahead
145161 pub fn add_keychain ( & mut self , keychain : K , descriptor : Descriptor < DescriptorPublicKey > ) {
146162 let old_descriptor = & * self
147163 . keychains
148- . entry ( keychain)
164+ . entry ( keychain. clone ( ) )
149165 . or_insert_with ( || descriptor. clone ( ) ) ;
150166 assert_eq ! (
151167 & descriptor, old_descriptor,
152168 "keychain already contains a different descriptor"
153169 ) ;
170+ self . replenish_lookahead ( & keychain, self . lookahead ) ;
154171 }
155172
156- /// Return the lookahead setting for each keychain.
157- ///
158- /// Refer to [`set_lookahead`] for a deeper explanation of the `lookahead`.
159- ///
160- /// [`set_lookahead`]: Self::set_lookahead
161- pub fn lookaheads ( & self ) -> & BTreeMap < K , u32 > {
162- & self . lookahead
163- }
164-
165- /// Convenience method to call [`set_lookahead`] for all keychains.
166- ///
167- /// [`set_lookahead`]: Self::set_lookahead
168- pub fn set_lookahead_for_all ( & mut self , lookahead : u32 ) {
169- for keychain in & self . keychains . keys ( ) . cloned ( ) . collect :: < Vec < _ > > ( ) {
170- self . set_lookahead ( keychain, lookahead) ;
171- }
172- }
173-
174- /// Set the lookahead count for `keychain`.
175- ///
176- /// The lookahead is the number of scripts to cache ahead of the last revealed script index. This
177- /// is useful to find outputs you own when processing block data that lie beyond the last revealed
178- /// index. In certain situations, such as when performing an initial scan of the blockchain during
179- /// wallet import, it may be uncertain or unknown what the last revealed index is.
180- ///
181- /// # Panics
182- ///
183- /// This will panic if the `keychain` does not exist.
184- pub fn set_lookahead ( & mut self , keychain : & K , lookahead : u32 ) {
185- self . lookahead . insert ( keychain. clone ( ) , lookahead) ;
186- self . replenish_lookahead ( keychain) ;
187- }
188-
189- /// Convenience method to call [`lookahead_to_target`] for multiple keychains.
190- ///
191- /// [`lookahead_to_target`]: Self::lookahead_to_target
192- pub fn lookahead_to_target_multi ( & mut self , target_indexes : BTreeMap < K , u32 > ) {
193- for ( keychain, target_index) in target_indexes {
194- self . lookahead_to_target ( & keychain, target_index)
195- }
173+ /// Return the lookahead setting.
174+ pub fn lookahead ( & self ) -> u32 {
175+ self . lookahead
196176 }
197177
198178 /// Store lookahead scripts until `target_index`.
@@ -201,22 +181,14 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
201181 pub fn lookahead_to_target ( & mut self , keychain : & K , target_index : u32 ) {
202182 let next_index = self . next_store_index ( keychain) ;
203183 if let Some ( temp_lookahead) = target_index. checked_sub ( next_index) . filter ( |& v| v > 0 ) {
204- let old_lookahead = self . lookahead . insert ( keychain. clone ( ) , temp_lookahead) ;
205- self . replenish_lookahead ( keychain) ;
206-
207- // revert
208- match old_lookahead {
209- Some ( lookahead) => self . lookahead . insert ( keychain. clone ( ) , lookahead) ,
210- None => self . lookahead . remove ( keychain) ,
211- } ;
184+ self . replenish_lookahead ( keychain, temp_lookahead) ;
212185 }
213186 }
214187
215- fn replenish_lookahead ( & mut self , keychain : & K ) {
188+ fn replenish_lookahead ( & mut self , keychain : & K , lookahead : u32 ) {
216189 let descriptor = self . keychains . get ( keychain) . expect ( "keychain must exist" ) ;
217190 let next_store_index = self . next_store_index ( keychain) ;
218191 let next_reveal_index = self . last_revealed . get ( keychain) . map_or ( 0 , |v| * v + 1 ) ;
219- let lookahead = self . lookahead . get ( keychain) . map_or ( 0 , |v| * v) ;
220192
221193 for ( new_index, new_spk) in
222194 SpkIterator :: new_with_range ( descriptor, next_store_index..next_reveal_index + lookahead)
@@ -388,25 +360,21 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
388360
389361 let target_index = if has_wildcard { target_index } else { 0 } ;
390362 let next_reveal_index = self . last_revealed . get ( keychain) . map_or ( 0 , |v| * v + 1 ) ;
391- let lookahead = self . lookahead . get ( keychain) . map_or ( 0 , |v| * v) ;
392363
393- debug_assert_eq ! (
394- next_reveal_index + lookahead,
395- self . next_store_index( keychain)
396- ) ;
364+ debug_assert ! ( next_reveal_index + self . lookahead >= self . next_store_index( keychain) ) ;
397365
398366 // if we need to reveal new indices, the latest revealed index goes here
399367 let mut reveal_to_index = None ;
400368
401369 // if the target is not yet revealed, but is already stored (due to lookahead), we need to
402370 // set the `reveal_to_index` as target here (as the `for` loop below only updates
403371 // `reveal_to_index` for indexes that are NOT stored)
404- if next_reveal_index <= target_index && target_index < next_reveal_index + lookahead {
372+ if next_reveal_index <= target_index && target_index < next_reveal_index + self . lookahead {
405373 reveal_to_index = Some ( target_index) ;
406374 }
407375
408376 // we range over indexes that are not stored
409- let range = next_reveal_index + lookahead..=target_index + lookahead;
377+ let range = next_reveal_index + self . lookahead ..=target_index + self . lookahead ;
410378 for ( new_index, new_spk) in SpkIterator :: new_with_range ( descriptor, range) {
411379 let _inserted = self
412380 . inner
0 commit comments