@@ -200,7 +200,7 @@ impl<K: Clone + Ord + Debug> Indexer for KeychainTxOutIndex<K> {
200
200
}
201
201
202
202
impl < K > KeychainTxOutIndex < K > {
203
- /// Construct a [`KeychainTxOutIndex`] with the given `lookahead` and `use_spk_cache ` boolean.
203
+ /// Construct a [`KeychainTxOutIndex`] with the given `lookahead` and `persist_spks ` boolean.
204
204
///
205
205
/// # Lookahead
206
206
///
@@ -221,10 +221,10 @@ impl<K> KeychainTxOutIndex<K> {
221
221
///
222
222
/// ```rust
223
223
/// # use bdk_chain::keychain_txout::KeychainTxOutIndex;
224
- /// // Derive 20 future addresses per chain and persist + reload script pubkeys via ChangeSets:
224
+ /// // Derive 20 future addresses per keychain and persist + reload script pubkeys via ChangeSets:
225
225
/// let idx = KeychainTxOutIndex::<&'static str>::new(20, true);
226
226
///
227
- /// // Derive 10 future addresses per chain without persistence:
227
+ /// // Derive 10 future addresses per keychain without persistence:
228
228
/// let idx = KeychainTxOutIndex::<&'static str>::new(10, false);
229
229
/// ```
230
230
pub fn new ( lookahead : u32 , persist_spks : bool ) -> Self {
@@ -251,7 +251,7 @@ impl<K> KeychainTxOutIndex<K> {
251
251
impl < K : Clone + Ord + Debug > KeychainTxOutIndex < K > {
252
252
/// Construct `KeychainTxOutIndex<K>` from the given `changeset`.
253
253
///
254
- /// Shorthand for called [`new`] and then [`apply_changeset`].
254
+ /// Shorthand for calling [`new`] and then [`apply_changeset`].
255
255
///
256
256
/// [`new`]: Self::new
257
257
/// [`apply_changeset`]: Self::apply_changeset
@@ -1002,7 +1002,7 @@ impl<K: core::fmt::Debug> std::error::Error for InsertDescriptorError<K> {}
1002
1002
///
1003
1003
/// It tracks:
1004
1004
/// 1. `last_revealed`: the highest derivation index revealed per descriptor.
1005
- /// 2. `spks `: the cache of derived script pubkeys to persist across runs.
1005
+ /// 2. `spk_cache `: the cache of derived script pubkeys to persist across runs.
1006
1006
///
1007
1007
/// You can apply a `ChangeSet` to a `KeychainTxOutIndex` via
1008
1008
/// [`KeychainTxOutIndex::apply_changeset`], or merge two change sets with [`ChangeSet::merge`].
@@ -1011,7 +1011,7 @@ impl<K: core::fmt::Debug> std::error::Error for InsertDescriptorError<K> {}
1011
1011
///
1012
1012
/// - `last_revealed` is monotonic: merging retains the maximum index for each descriptor and never
1013
1013
/// decreases.
1014
- /// - `spks ` accumulates entries: once a script pubkey is persisted, it remains available for
1014
+ /// - `spk_cache ` accumulates entries: once a script pubkey is persisted, it remains available for
1015
1015
/// reload. If the same descriptor and index appear again with a new script pubkey, the latter
1016
1016
/// value overrides the former.
1017
1017
///
@@ -1107,3 +1107,70 @@ impl<K: Clone + Ord + core::fmt::Debug> FullScanRequestBuilderExt<K> for FullSca
1107
1107
self
1108
1108
}
1109
1109
}
1110
+
1111
+ #[ cfg( test) ]
1112
+ mod test {
1113
+ use super :: * ;
1114
+
1115
+ use bdk_testenv:: utils:: DESCRIPTORS ;
1116
+ use bitcoin:: secp256k1:: Secp256k1 ;
1117
+ use miniscript:: Descriptor ;
1118
+
1119
+ // Test that `KeychainTxOutIndex` uses the spk cache.
1120
+ // And the indexed spks are as expected.
1121
+ #[ test]
1122
+ fn test_spk_cache ( ) {
1123
+ let lookahead = 10 ;
1124
+ let use_cache = true ;
1125
+ let mut index = KeychainTxOutIndex :: new ( lookahead, use_cache) ;
1126
+ let s = DESCRIPTORS [ 0 ] ;
1127
+
1128
+ let desc = Descriptor :: parse_descriptor ( & Secp256k1 :: new ( ) , s)
1129
+ . unwrap ( )
1130
+ . 0 ;
1131
+
1132
+ let did = desc. descriptor_id ( ) ;
1133
+
1134
+ let reveal_to = 2 ;
1135
+ let end_index = reveal_to + lookahead;
1136
+
1137
+ let _ = index. insert_descriptor ( 0i32 , desc. clone ( ) ) ;
1138
+ assert_eq ! ( index. spk_cache. get( & did) . unwrap( ) . len( ) as u32 , lookahead) ;
1139
+ assert_eq ! ( index. next_index( 0 ) , Some ( ( 0 , true ) ) ) ;
1140
+
1141
+ // Now reveal some scripts
1142
+ for _ in 0 ..=reveal_to {
1143
+ let _ = index. reveal_next_spk ( 0 ) . unwrap ( ) ;
1144
+ }
1145
+ assert_eq ! ( index. last_revealed_index( 0 ) , Some ( reveal_to) ) ;
1146
+
1147
+ let spk_cache = & index. spk_cache ;
1148
+ assert ! ( !spk_cache. is_empty( ) ) ;
1149
+
1150
+ for ( & did, cached_spks) in spk_cache {
1151
+ assert_eq ! ( did, desc. descriptor_id( ) ) ;
1152
+ for ( & i, cached_spk) in cached_spks {
1153
+ // Cached spk matches derived
1154
+ let exp_spk = desc. at_derivation_index ( i) . unwrap ( ) . script_pubkey ( ) ;
1155
+ assert_eq ! ( & exp_spk, cached_spk) ;
1156
+ // Also matches the inner index
1157
+ assert_eq ! ( index. spk_at_index( 0 , i) , Some ( cached_spk. clone( ) ) ) ;
1158
+ }
1159
+ }
1160
+
1161
+ let init_cs = index. initial_changeset ( ) ;
1162
+ assert_eq ! (
1163
+ init_cs. spk_cache. get( & did) . unwrap( ) . len( ) as u32 ,
1164
+ end_index + 1
1165
+ ) ;
1166
+
1167
+ // Now test load from changeset
1168
+ let recovered =
1169
+ KeychainTxOutIndex :: < & str > :: from_changeset ( lookahead, use_cache, init_cs. clone ( ) ) ;
1170
+ assert_eq ! ( & recovered. spk_cache, spk_cache) ;
1171
+
1172
+ // The cache is optional at load time
1173
+ let index = KeychainTxOutIndex :: < i32 > :: from_changeset ( lookahead, false , init_cs) ;
1174
+ assert ! ( index. spk_cache. is_empty( ) ) ;
1175
+ }
1176
+ }
0 commit comments