22//! indexes [`TxOut`]s with them.
33
44use crate :: {
5+ alloc:: boxed:: Box ,
56 collections:: * ,
67 miniscript:: { Descriptor , DescriptorPublicKey } ,
78 spk_client:: { FullScanRequestBuilder , SyncRequestBuilder } ,
@@ -10,7 +11,9 @@ use crate::{
1011 DescriptorExt , DescriptorId , Indexed , Indexer , KeychainIndexed , SpkIterator ,
1112} ;
1213use alloc:: { borrow:: ToOwned , vec:: Vec } ;
13- use bitcoin:: { Amount , OutPoint , ScriptBuf , SignedAmount , Transaction , TxOut , Txid } ;
14+ use bitcoin:: {
15+ key:: Secp256k1 , Amount , OutPoint , ScriptBuf , SignedAmount , Transaction , TxOut , Txid ,
16+ } ;
1417use core:: {
1518 fmt:: Debug ,
1619 ops:: { Bound , RangeBounds } ,
@@ -128,6 +131,8 @@ pub struct KeychainTxOutIndex<K> {
128131 descriptors : HashMap < DescriptorId , Descriptor < DescriptorPublicKey > > ,
129132 last_revealed : HashMap < DescriptorId , u32 > ,
130133 lookahead : u32 ,
134+
135+ spk_cache : BTreeMap < DescriptorId , HashMap < u32 , ScriptBuf > > ,
131136}
132137
133138impl < K > Default for KeychainTxOutIndex < K > {
@@ -155,7 +160,12 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
155160 if self . last_revealed . get ( did) < Some ( & index) {
156161 self . last_revealed . insert ( * did, index) ;
157162 changeset. last_revealed . insert ( * did, index) ;
158- self . replenish_inner_index ( * did, & keychain, self . lookahead ) ;
163+ self . replenish_inner_index (
164+ * did,
165+ & keychain,
166+ self . lookahead ,
167+ changeset. spk_cache . entry ( * did) . or_default ( ) ,
168+ ) ;
159169 }
160170 }
161171 changeset
@@ -173,6 +183,16 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
173183 fn initial_changeset ( & self ) -> Self :: ChangeSet {
174184 ChangeSet {
175185 last_revealed : self . last_revealed . clone ( ) . into_iter ( ) . collect ( ) ,
186+ spk_cache : self
187+ . spk_cache
188+ . iter ( )
189+ . map ( |( desc, spks) | {
190+ (
191+ * desc,
192+ spks. iter ( ) . map ( |( i, spk) | ( * i, spk. clone ( ) ) ) . collect ( ) ,
193+ )
194+ } )
195+ . collect ( ) ,
176196 }
177197 }
178198
@@ -204,6 +224,7 @@ impl<K> KeychainTxOutIndex<K> {
204224 descriptor_id_to_keychain : Default :: default ( ) ,
205225 last_revealed : Default :: default ( ) ,
206226 lookahead,
227+ spk_cache : Default :: default ( ) ,
207228 }
208229 }
209230
@@ -365,23 +386,30 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
365386 & mut self ,
366387 keychain : K ,
367388 descriptor : Descriptor < DescriptorPublicKey > ,
368- ) -> Result < bool , InsertDescriptorError < K > > {
389+ ) -> Result < ( bool , ChangeSet ) , InsertDescriptorError < K > > {
390+ let mut changeset = ChangeSet :: default ( ) ;
391+
369392 let did = descriptor. descriptor_id ( ) ;
370393 if !self . keychain_to_descriptor_id . contains_key ( & keychain)
371394 && !self . descriptor_id_to_keychain . contains_key ( & did)
372395 {
373396 self . descriptors . insert ( did, descriptor. clone ( ) ) ;
374397 self . keychain_to_descriptor_id . insert ( keychain. clone ( ) , did) ;
375398 self . descriptor_id_to_keychain . insert ( did, keychain. clone ( ) ) ;
376- self . replenish_inner_index ( did, & keychain, self . lookahead ) ;
377- return Ok ( true ) ;
399+ self . replenish_inner_index (
400+ did,
401+ & keychain,
402+ self . lookahead ,
403+ changeset. spk_cache . entry ( did) . or_default ( ) ,
404+ ) ;
405+ return Ok ( ( true , changeset) ) ;
378406 }
379407
380408 if let Some ( existing_desc_id) = self . keychain_to_descriptor_id . get ( & keychain) {
381409 let descriptor = self . descriptors . get ( existing_desc_id) . expect ( "invariant" ) ;
382410 if * existing_desc_id != did {
383411 return Err ( InsertDescriptorError :: KeychainAlreadyAssigned {
384- existing_assignment : descriptor. clone ( ) ,
412+ existing_assignment : Box :: new ( descriptor. clone ( ) ) ,
385413 keychain,
386414 } ) ;
387415 }
@@ -393,12 +421,12 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
393421 if * existing_keychain != keychain {
394422 return Err ( InsertDescriptorError :: DescriptorAlreadyAssigned {
395423 existing_assignment : existing_keychain. clone ( ) ,
396- descriptor,
424+ descriptor : Box :: new ( descriptor ) ,
397425 } ) ;
398426 }
399427 }
400428
401- Ok ( false )
429+ Ok ( ( false , changeset ) )
402430 }
403431
404432 /// Gets the descriptor associated with the keychain. Returns `None` if the keychain doesn't
@@ -420,47 +448,100 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
420448 /// Store lookahead scripts until `target_index` (inclusive).
421449 ///
422450 /// This does not change the global `lookahead` setting.
423- pub fn lookahead_to_target ( & mut self , keychain : K , target_index : u32 ) {
451+ pub fn lookahead_to_target (
452+ & mut self ,
453+ keychain : K ,
454+ target_index : u32 ,
455+ derived_spks : & mut impl Extend < Indexed < ScriptBuf > > ,
456+ ) {
424457 if let Some ( ( next_index, _) ) = self . next_index ( keychain. clone ( ) ) {
425458 let temp_lookahead = ( target_index + 1 )
426459 . checked_sub ( next_index)
427460 . filter ( |& index| index > 0 ) ;
428461
429462 if let Some ( temp_lookahead) = temp_lookahead {
430- self . replenish_inner_index_keychain ( keychain, temp_lookahead) ;
463+ self . replenish_inner_index_keychain ( keychain, temp_lookahead, derived_spks ) ;
431464 }
432465 }
433466 }
434467
435- fn replenish_inner_index_did ( & mut self , did : DescriptorId , lookahead : u32 ) {
468+ fn replenish_inner_index_did (
469+ & mut self ,
470+ did : DescriptorId ,
471+ lookahead : u32 ,
472+ derived_spks : & mut impl Extend < Indexed < ScriptBuf > > ,
473+ ) {
436474 if let Some ( keychain) = self . descriptor_id_to_keychain . get ( & did) . cloned ( ) {
437- self . replenish_inner_index ( did, & keychain, lookahead) ;
475+ self . replenish_inner_index ( did, & keychain, lookahead, derived_spks ) ;
438476 }
439477 }
440478
441- fn replenish_inner_index_keychain ( & mut self , keychain : K , lookahead : u32 ) {
479+ fn replenish_inner_index_keychain (
480+ & mut self ,
481+ keychain : K ,
482+ lookahead : u32 ,
483+ derived_spks : & mut impl Extend < Indexed < ScriptBuf > > ,
484+ ) {
442485 if let Some ( did) = self . keychain_to_descriptor_id . get ( & keychain) {
443- self . replenish_inner_index ( * did, & keychain, lookahead) ;
486+ self . replenish_inner_index ( * did, & keychain, lookahead, derived_spks ) ;
444487 }
445488 }
446489
447490 /// Syncs the state of the inner spk index after changes to a keychain
448- fn replenish_inner_index ( & mut self , did : DescriptorId , keychain : & K , lookahead : u32 ) {
491+ fn replenish_inner_index (
492+ & mut self ,
493+ did : DescriptorId ,
494+ keychain : & K ,
495+ lookahead : u32 ,
496+ derived_spks : & mut impl Extend < Indexed < ScriptBuf > > ,
497+ ) {
449498 let descriptor = self . descriptors . get ( & did) . expect ( "invariant" ) ;
450- let next_store_index = self
499+
500+ let mut next_index = self
451501 . inner
452502 . all_spks ( )
453503 . range ( & ( keychain. clone ( ) , u32:: MIN ) ..=& ( keychain. clone ( ) , u32:: MAX ) )
454504 . last ( )
455505 . map_or ( 0 , |( ( _, index) , _) | * index + 1 ) ;
456- let next_reveal_index = self . last_revealed . get ( & did) . map_or ( 0 , |v| * v + 1 ) ;
457- for ( new_index, new_spk) in
458- SpkIterator :: new_with_range ( descriptor, next_store_index..next_reveal_index + lookahead)
459- {
506+
507+ // Exclusive: index to stop at.
508+ let stop_index = if descriptor. has_wildcard ( ) {
509+ let next_reveal_index = self . last_revealed . get ( & did) . map_or ( 0 , |v| * v + 1 ) ;
510+ ( next_reveal_index + lookahead) . min ( BIP32_MAX_INDEX )
511+ } else {
512+ 1
513+ } ;
514+
515+ let cached_spk_iter = core:: iter:: from_fn ( {
516+ let secp = Secp256k1 :: verification_only ( ) ;
517+ let _desc = & descriptor;
518+ let spk_cache = self . spk_cache . entry ( did) . or_default ( ) ;
519+ let _i = & mut next_index;
520+ move || -> Option < Indexed < ScriptBuf > > {
521+ if * _i >= stop_index {
522+ return None ;
523+ }
524+ let spk_i = * _i;
525+ * _i = spk_i. saturating_add ( 1 ) ;
526+
527+ if let Some ( spk) = spk_cache. get ( _i) {
528+ return Some ( ( spk_i, spk. clone ( ) ) ) ;
529+ }
530+ let spk = _desc
531+ . derived_descriptor ( & secp, spk_i)
532+ . expect ( "The descriptor cannot have hardened derivation" )
533+ . script_pubkey ( ) ;
534+ derived_spks. extend ( core:: iter:: once ( ( spk_i, spk. clone ( ) ) ) ) ;
535+ spk_cache. insert ( spk_i, spk. clone ( ) ) ;
536+ Some ( ( spk_i, spk. clone ( ) ) )
537+ }
538+ } ) ;
539+
540+ for ( new_index, new_spk) in cached_spk_iter {
460541 let _inserted = self
461542 . inner
462543 . insert_spk ( ( keychain. clone ( ) , new_index) , new_spk) ;
463- debug_assert ! ( _inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_store_index ={}, next_reveal_index={} " , keychain, lookahead, next_store_index , next_reveal_index ) ;
544+ debug_assert ! ( _inserted, "replenish lookahead: must not have existing spk: keychain={:?}, lookahead={}, next_index ={}" , keychain, lookahead, next_index ) ;
464545 }
465546 }
466547
@@ -693,7 +774,12 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
693774 let did = self . keychain_to_descriptor_id . get ( & keychain) ?;
694775 self . last_revealed . insert ( * did, next_index) ;
695776 changeset. last_revealed . insert ( * did, next_index) ;
696- self . replenish_inner_index ( * did, & keychain, self . lookahead ) ;
777+ self . replenish_inner_index (
778+ * did,
779+ & keychain,
780+ self . lookahead ,
781+ changeset. spk_cache . entry ( * did) . or_default ( ) ,
782+ ) ;
697783 }
698784 let script = self
699785 . inner
@@ -779,10 +865,13 @@ impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
779865
780866 /// Applies the `ChangeSet<K>` to the [`KeychainTxOutIndex<K>`]
781867 pub fn apply_changeset ( & mut self , changeset : ChangeSet ) {
782- for ( & desc_id , & index) in & changeset. last_revealed {
783- let v = self . last_revealed . entry ( desc_id ) . or_default ( ) ;
868+ for ( did , index) in changeset. last_revealed {
869+ let v = self . last_revealed . entry ( did ) . or_default ( ) ;
784870 * v = index. max ( * v) ;
785- self . replenish_inner_index_did ( desc_id, self . lookahead ) ;
871+ self . replenish_inner_index_did ( did, self . lookahead , & mut Vec :: new ( ) ) ;
872+ }
873+ for ( did, spks) in changeset. spk_cache {
874+ self . spk_cache . entry ( did) . or_default ( ) . extend ( spks) ;
786875 }
787876 }
788877}
@@ -793,7 +882,7 @@ pub enum InsertDescriptorError<K> {
793882 /// The descriptor has already been assigned to a keychain so you can't assign it to another
794883 DescriptorAlreadyAssigned {
795884 /// The descriptor you have attempted to reassign
796- descriptor : Descriptor < DescriptorPublicKey > ,
885+ descriptor : Box < Descriptor < DescriptorPublicKey > > ,
797886 /// The keychain that the descriptor is already assigned to
798887 existing_assignment : K ,
799888 } ,
@@ -802,7 +891,7 @@ pub enum InsertDescriptorError<K> {
802891 /// The keychain that you have attempted to reassign
803892 keychain : K ,
804893 /// The descriptor that the keychain is already assigned to
805- existing_assignment : Descriptor < DescriptorPublicKey > ,
894+ existing_assignment : Box < Descriptor < DescriptorPublicKey > > ,
806895 } ,
807896}
808897
@@ -852,6 +941,10 @@ impl<K: core::fmt::Debug> std::error::Error for InsertDescriptorError<K> {}
852941pub struct ChangeSet {
853942 /// Contains for each descriptor_id the last revealed index of derivation
854943 pub last_revealed : BTreeMap < DescriptorId , u32 > ,
944+
945+ /// Spk cache.
946+ #[ cfg_attr( feature = "serde" , serde( default ) ) ]
947+ pub spk_cache : BTreeMap < DescriptorId , BTreeMap < u32 , ScriptBuf > > ,
855948}
856949
857950impl Merge for ChangeSet {
@@ -872,11 +965,15 @@ impl Merge for ChangeSet {
872965 }
873966 }
874967 }
968+
969+ for ( did, spks) in other. spk_cache {
970+ self . spk_cache . entry ( did) . or_default ( ) . extend ( spks) ;
971+ }
875972 }
876973
877974 /// Returns whether the changeset are empty.
878975 fn is_empty ( & self ) -> bool {
879- self . last_revealed . is_empty ( )
976+ self . last_revealed . is_empty ( ) && self . spk_cache . is_empty ( )
880977 }
881978}
882979
0 commit comments