@@ -236,11 +236,11 @@ where
236
236
}
237
237
238
238
// Return a newly derived address using the external descriptor
239
- fn get_new_address ( & self ) -> Result < AddressInfo , Error > {
240
- let incremented_index = self . fetch_and_increment_index ( KeychainKind :: External ) ?;
239
+ fn get_new_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
240
+ let incremented_index = self . fetch_and_increment_index ( keychain ) ?;
241
241
242
242
let address_result = self
243
- . descriptor
243
+ . get_descriptor_for_keychain ( keychain )
244
244
. as_derived ( incremented_index, & self . secp )
245
245
. address ( self . network ) ;
246
246
@@ -252,12 +252,14 @@ where
252
252
. map_err ( |_| Error :: ScriptDoesntHaveAddressForm )
253
253
}
254
254
255
- // Return the the last previously derived address if it has not been used in a received
256
- // transaction. Otherwise return a new address using [`Wallet::get_new_address`].
257
- fn get_unused_address ( & self ) -> Result < AddressInfo , Error > {
258
- let current_index = self . fetch_index ( KeychainKind :: External ) ?;
255
+ // Return the the last previously derived address for `keychain` if it has not been used in a
256
+ // received transaction. Otherwise return a new address using [`Wallet::get_new_address`].
257
+ fn get_unused_address ( & self , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
258
+ let current_index = self . fetch_index ( keychain ) ?;
259
259
260
- let derived_key = self . descriptor . as_derived ( current_index, & self . secp ) ;
260
+ let derived_key = self
261
+ . get_descriptor_for_keychain ( keychain)
262
+ . as_derived ( current_index, & self . secp ) ;
261
263
262
264
let script_pubkey = derived_key. script_pubkey ( ) ;
263
265
@@ -269,7 +271,7 @@ where
269
271
. any ( |o| o. script_pubkey == script_pubkey) ;
270
272
271
273
if found_used {
272
- self . get_new_address ( )
274
+ self . get_new_address ( keychain )
273
275
} else {
274
276
derived_key
275
277
. address ( self . network )
@@ -281,21 +283,21 @@ where
281
283
}
282
284
}
283
285
284
- // Return derived address for the external descriptor at a specific index
285
- fn peek_address ( & self , index : u32 ) -> Result < AddressInfo , Error > {
286
- self . descriptor
286
+ // Return derived address for the descriptor of given [`KeychainKind`] at a specific index
287
+ fn peek_address ( & self , index : u32 , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
288
+ self . get_descriptor_for_keychain ( keychain )
287
289
. as_derived ( index, & self . secp )
288
290
. address ( self . network )
289
291
. map ( |address| AddressInfo { index, address } )
290
292
. map_err ( |_| Error :: ScriptDoesntHaveAddressForm )
291
293
}
292
294
293
- // Return derived address for the external descriptor at a specific index and reset current
295
+ // Return derived address for `keychain` at a specific index and reset current
294
296
// address index
295
- fn reset_address ( & self , index : u32 ) -> Result < AddressInfo , Error > {
296
- self . set_index ( KeychainKind :: External , index) ?;
297
+ fn reset_address ( & self , index : u32 , keychain : KeychainKind ) -> Result < AddressInfo , Error > {
298
+ self . set_index ( keychain , index) ?;
297
299
298
- self . descriptor
300
+ self . get_descriptor_for_keychain ( keychain )
299
301
. as_derived ( index, & self . secp )
300
302
. address ( self . network )
301
303
. map ( |address| AddressInfo { index, address } )
@@ -306,12 +308,75 @@ where
306
308
/// available address index selection strategies. If none of the keys in the descriptor are derivable
307
309
/// (ie. does not end with /*) then the same address will always be returned for any [`AddressIndex`].
308
310
pub fn get_address ( & self , address_index : AddressIndex ) -> Result < AddressInfo , Error > {
311
+ self . _get_address ( address_index, KeychainKind :: External )
312
+ }
313
+
314
+ /// Return a derived address using the internal (change) descriptor.
315
+ ///
316
+ /// If the wallet doesn't have an internal descriptor it will use the external descriptor.
317
+ ///
318
+ /// see [`AddressIndex`] for available address index selection strategies. If none of the keys
319
+ /// in the descriptor are derivable (ie. does not end with /*) then the same address will always
320
+ /// be returned for any [`AddressIndex`].
321
+ pub fn get_internal_address ( & self , address_index : AddressIndex ) -> Result < AddressInfo , Error > {
322
+ self . _get_address ( address_index, KeychainKind :: Internal )
323
+ }
324
+
325
+ fn _get_address (
326
+ & self ,
327
+ address_index : AddressIndex ,
328
+ keychain : KeychainKind ,
329
+ ) -> Result < AddressInfo , Error > {
309
330
match address_index {
310
- AddressIndex :: New => self . get_new_address ( ) ,
311
- AddressIndex :: LastUnused => self . get_unused_address ( ) ,
312
- AddressIndex :: Peek ( index) => self . peek_address ( index) ,
313
- AddressIndex :: Reset ( index) => self . reset_address ( index) ,
331
+ AddressIndex :: New => self . get_new_address ( keychain) ,
332
+ AddressIndex :: LastUnused => self . get_unused_address ( keychain) ,
333
+ AddressIndex :: Peek ( index) => self . peek_address ( index, keychain) ,
334
+ AddressIndex :: Reset ( index) => self . reset_address ( index, keychain) ,
335
+ }
336
+ }
337
+
338
+ /// Ensures that there are at least `max_addresses` addresses cached in the database if the
339
+ /// descriptor is derivable, or 1 address if it is not.
340
+ /// Will return `Ok(true)` if there are new addresses generated (either external or internal),
341
+ /// and `Ok(false)` if all the required addresses are already cached. This function is useful to
342
+ /// explicitly cache addresses in a wallet to do things like check [`Wallet::is_mine`] on
343
+ /// transaction output scripts.
344
+ pub fn ensure_addresses_cached ( & self , max_addresses : u32 ) -> Result < bool , Error > {
345
+ let mut new_addresses_cached = false ;
346
+ let max_address = match self . descriptor . is_deriveable ( ) {
347
+ false => 0 ,
348
+ true => max_addresses,
349
+ } ;
350
+ debug ! ( "max_address {}" , max_address) ;
351
+ if self
352
+ . database
353
+ . borrow ( )
354
+ . get_script_pubkey_from_path ( KeychainKind :: External , max_address. saturating_sub ( 1 ) ) ?
355
+ . is_none ( )
356
+ {
357
+ debug ! ( "caching external addresses" ) ;
358
+ new_addresses_cached = true ;
359
+ self . cache_addresses ( KeychainKind :: External , 0 , max_address) ?;
314
360
}
361
+
362
+ if let Some ( change_descriptor) = & self . change_descriptor {
363
+ let max_address = match change_descriptor. is_deriveable ( ) {
364
+ false => 0 ,
365
+ true => max_addresses,
366
+ } ;
367
+
368
+ if self
369
+ . database
370
+ . borrow ( )
371
+ . get_script_pubkey_from_path ( KeychainKind :: Internal , max_address. saturating_sub ( 1 ) ) ?
372
+ . is_none ( )
373
+ {
374
+ debug ! ( "caching internal addresses" ) ;
375
+ new_addresses_cached = true ;
376
+ self . cache_addresses ( KeychainKind :: Internal , 0 , max_address) ?;
377
+ }
378
+ }
379
+ Ok ( new_addresses_cached)
315
380
}
316
381
317
382
/// Return whether or not a `script` is part of this wallet (either internal or external)
@@ -660,7 +725,10 @@ where
660
725
let mut drain_output = {
661
726
let script_pubkey = match params. drain_to {
662
727
Some ( ref drain_recipient) => drain_recipient. clone ( ) ,
663
- None => self . get_change_address ( ) ?,
728
+ None => self
729
+ . get_internal_address ( AddressIndex :: New ) ?
730
+ . address
731
+ . script_pubkey ( ) ,
664
732
} ;
665
733
666
734
TxOut {
@@ -1093,13 +1161,6 @@ where
1093
1161
. map ( |( desc, child) | desc. as_derived ( child, & self . secp ) ) )
1094
1162
}
1095
1163
1096
- fn get_change_address ( & self ) -> Result < Script , Error > {
1097
- let ( desc, keychain) = self . _get_descriptor_for_keychain ( KeychainKind :: Internal ) ;
1098
- let index = self . fetch_and_increment_index ( keychain) ?;
1099
-
1100
- Ok ( desc. as_derived ( index, & self . secp ) . script_pubkey ( ) )
1101
- }
1102
-
1103
1164
fn fetch_and_increment_index ( & self , keychain : KeychainKind ) -> Result < u32 , Error > {
1104
1165
let ( descriptor, keychain) = self . _get_descriptor_for_keychain ( keychain) ;
1105
1166
let index = match descriptor. is_deriveable ( ) {
@@ -1463,46 +1524,14 @@ where
1463
1524
) -> Result < ( ) , Error > {
1464
1525
debug ! ( "Begin sync..." ) ;
1465
1526
1466
- let mut run_setup = false ;
1467
1527
let SyncOptions {
1468
1528
max_addresses,
1469
1529
progress,
1470
1530
} = sync_opts;
1471
1531
let progress = progress. unwrap_or_else ( || Box :: new ( NoopProgress ) ) ;
1472
1532
1473
- let max_address = match self . descriptor . is_deriveable ( ) {
1474
- false => 0 ,
1475
- true => max_addresses. unwrap_or ( CACHE_ADDR_BATCH_SIZE ) ,
1476
- } ;
1477
- debug ! ( "max_address {}" , max_address) ;
1478
- if self
1479
- . database
1480
- . borrow ( )
1481
- . get_script_pubkey_from_path ( KeychainKind :: External , max_address. saturating_sub ( 1 ) ) ?
1482
- . is_none ( )
1483
- {
1484
- debug ! ( "caching external addresses" ) ;
1485
- run_setup = true ;
1486
- self . cache_addresses ( KeychainKind :: External , 0 , max_address) ?;
1487
- }
1488
-
1489
- if let Some ( change_descriptor) = & self . change_descriptor {
1490
- let max_address = match change_descriptor. is_deriveable ( ) {
1491
- false => 0 ,
1492
- true => max_addresses. unwrap_or ( CACHE_ADDR_BATCH_SIZE ) ,
1493
- } ;
1494
-
1495
- if self
1496
- . database
1497
- . borrow ( )
1498
- . get_script_pubkey_from_path ( KeychainKind :: Internal , max_address. saturating_sub ( 1 ) ) ?
1499
- . is_none ( )
1500
- {
1501
- debug ! ( "caching internal addresses" ) ;
1502
- run_setup = true ;
1503
- self . cache_addresses ( KeychainKind :: Internal , 0 , max_address) ?;
1504
- }
1505
- }
1533
+ let run_setup =
1534
+ self . ensure_addresses_cached ( max_addresses. unwrap_or ( CACHE_ADDR_BATCH_SIZE ) ) ?;
1506
1535
1507
1536
debug ! ( "run_setup: {}" , run_setup) ;
1508
1537
// TODO: what if i generate an address first and cache some addresses?
@@ -3953,6 +3982,48 @@ pub(crate) mod test {
3953
3982
builder. add_recipient ( addr. script_pubkey ( ) , 45_000 ) ;
3954
3983
builder. finish ( ) . unwrap ( ) ;
3955
3984
}
3985
+
3986
+ #[ test]
3987
+ fn test_get_address ( ) {
3988
+ use crate :: descriptor:: template:: Bip84 ;
3989
+ let key = bitcoin:: util:: bip32:: ExtendedPrivKey :: from_str ( "tprv8ZgxMBicQKsPcx5nBGsR63Pe8KnRUqmbJNENAfGftF3yuXoMMoVJJcYeUw5eVkm9WBPjWYt6HMWYJNesB5HaNVBaFc1M6dRjWSYnmewUMYy" ) . unwrap ( ) ;
3990
+ let wallet = Wallet :: new (
3991
+ Bip84 ( key, KeychainKind :: External ) ,
3992
+ Some ( Bip84 ( key, KeychainKind :: Internal ) ) ,
3993
+ Network :: Regtest ,
3994
+ MemoryDatabase :: default ( ) ,
3995
+ )
3996
+ . unwrap ( ) ;
3997
+
3998
+ assert_eq ! (
3999
+ wallet. get_address( AddressIndex :: New ) . unwrap( ) . address,
4000
+ Address :: from_str( "bcrt1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvwtjf8s" ) . unwrap( )
4001
+ ) ;
4002
+ assert_eq ! (
4003
+ wallet
4004
+ . get_internal_address( AddressIndex :: New )
4005
+ . unwrap( )
4006
+ . address,
4007
+ Address :: from_str( "bcrt1qtrwtz00wxl69e5xex7amy4xzlxkaefg3gfdkxa" ) . unwrap( )
4008
+ ) ;
4009
+
4010
+ let wallet = Wallet :: new (
4011
+ Bip84 ( key, KeychainKind :: External ) ,
4012
+ None ,
4013
+ Network :: Regtest ,
4014
+ MemoryDatabase :: default ( ) ,
4015
+ )
4016
+ . unwrap ( ) ;
4017
+
4018
+ assert_eq ! (
4019
+ wallet
4020
+ . get_internal_address( AddressIndex :: New )
4021
+ . unwrap( )
4022
+ . address,
4023
+ Address :: from_str( "bcrt1qkmvk2nadgplmd57ztld8nf8v2yxkzmdvwtjf8s" ) . unwrap( ) ,
4024
+ "when there's no internal descriptor it should just use external"
4025
+ ) ;
4026
+ }
3956
4027
}
3957
4028
3958
4029
/// Deterministically generate a unique name given the descriptors defining the wallet
0 commit comments