@@ -391,6 +391,35 @@ where
391
391
}
392
392
}
393
393
394
+ /// Return vector of n unused addresses from the [`KeychainKind`].
395
+ /// If less than n unused addresses are returned, the rest will be populated by new addresses.
396
+ /// The unused addresses returned are in order of oldest in keychain first, with increasing index.
397
+ pub fn get_batch_unused_addresses (
398
+ & self ,
399
+ n : usize ,
400
+ keychain : KeychainKind ,
401
+ ) -> Result < Vec < AddressInfo > , Error > {
402
+ let unused_key_indexes = self . get_unused_key_indexes ( keychain) ?;
403
+ let mut addresses = unused_key_indexes
404
+ . iter ( )
405
+ . map ( |i| {
406
+ let derived_key = self
407
+ . get_descriptor_for_keychain ( keychain)
408
+ . as_derived ( * i, & self . secp ) ;
409
+
410
+ derived_key
411
+ . address ( self . network )
412
+ . map ( |address| AddressInfo { address, index : * i } )
413
+ . map_err ( |_| Error :: ScriptDoesntHaveAddressForm )
414
+ } )
415
+ . take ( n)
416
+ . collect :: < Result < Vec < _ > , _ > > ( ) ?;
417
+ for _ in 0 ..( n - addresses. len ( ) ) {
418
+ addresses. push ( self . get_new_address ( keychain) ?)
419
+ }
420
+ Ok ( addresses)
421
+ }
422
+
394
423
/// Return whether or not a `script` is part of this wallet (either internal or external)
395
424
pub fn is_mine ( & self , script : & Script ) -> Result < bool , Error > {
396
425
self . database . borrow ( ) . is_mine ( script)
@@ -3943,6 +3972,54 @@ pub(crate) mod test {
3943
3972
) ;
3944
3973
}
3945
3974
3975
+ #[ test]
3976
+ fn test_batch_unused_addresses ( ) {
3977
+ let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" ;
3978
+ let descriptors = testutils ! ( @descriptors ( descriptor) ) ;
3979
+ let wallet = Wallet :: new_offline (
3980
+ & descriptors. 0 ,
3981
+ None ,
3982
+ Network :: Testnet ,
3983
+ MemoryDatabase :: new ( ) ,
3984
+ )
3985
+ . unwrap ( ) ;
3986
+
3987
+ // get first two addresses, moving index
3988
+ for _ in 0 ..2 {
3989
+ let _ = wallet. get_address ( New ) ;
3990
+ }
3991
+
3992
+ // use the second address
3993
+ crate :: populate_test_db!(
3994
+ wallet. database. borrow_mut( ) ,
3995
+ testutils! ( @tx ( ( @external descriptors, 1 ) => 25_000 ) ( @confirmations 1 ) ) ,
3996
+ Some ( 100 ) ,
3997
+ ) ;
3998
+
3999
+ assert_eq ! (
4000
+ wallet
4001
+ . get_batch_unused_addresses( 3 , KeychainKind :: External )
4002
+ . unwrap( ) ,
4003
+ vec![
4004
+ AddressInfo {
4005
+ index: 0 ,
4006
+ address: Address :: from_str( "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" )
4007
+ . unwrap( ) ,
4008
+ } ,
4009
+ AddressInfo {
4010
+ index: 2 ,
4011
+ address: Address :: from_str( "tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2" )
4012
+ . unwrap( ) ,
4013
+ } ,
4014
+ AddressInfo {
4015
+ index: 3 ,
4016
+ address: Address :: from_str( "tb1q32a23q6u3yy89l8svrt80a54h06qvn7gnuvsen" )
4017
+ . unwrap( ) ,
4018
+ }
4019
+ ]
4020
+ ) ;
4021
+ }
4022
+
3946
4023
#[ test]
3947
4024
fn test_peek_address_at_index ( ) {
3948
4025
let db = MemoryDatabase :: new ( ) ;
0 commit comments