@@ -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)
@@ -3925,6 +3954,54 @@ pub(crate) mod test {
3925
3954
) ;
3926
3955
}
3927
3956
3957
+ #[ test]
3958
+ fn test_batch_unused_addresses ( ) {
3959
+ let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)" ;
3960
+ let descriptors = testutils ! ( @descriptors ( descriptor) ) ;
3961
+ let wallet = Wallet :: new_offline (
3962
+ & descriptors. 0 ,
3963
+ None ,
3964
+ Network :: Testnet ,
3965
+ MemoryDatabase :: new ( ) ,
3966
+ )
3967
+ . unwrap ( ) ;
3968
+
3969
+ // get first two addresses, moving index
3970
+ for _ in 0 ..2 {
3971
+ let _ = wallet. get_address ( New ) ;
3972
+ }
3973
+
3974
+ // use the second address
3975
+ crate :: populate_test_db!(
3976
+ wallet. database. borrow_mut( ) ,
3977
+ testutils! ( @tx ( ( @external descriptors, 1 ) => 25_000 ) ( @confirmations 1 ) ) ,
3978
+ Some ( 100 ) ,
3979
+ ) ;
3980
+
3981
+ assert_eq ! (
3982
+ wallet
3983
+ . get_batch_unused_addresses( 3 , KeychainKind :: External )
3984
+ . unwrap( ) ,
3985
+ vec![
3986
+ AddressInfo {
3987
+ index: 0 ,
3988
+ address: Address :: from_str( "tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a" )
3989
+ . unwrap( ) ,
3990
+ } ,
3991
+ AddressInfo {
3992
+ index: 2 ,
3993
+ address: Address :: from_str( "tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2" )
3994
+ . unwrap( ) ,
3995
+ } ,
3996
+ AddressInfo {
3997
+ index: 3 ,
3998
+ address: Address :: from_str( "tb1q32a23q6u3yy89l8svrt80a54h06qvn7gnuvsen" )
3999
+ . unwrap( ) ,
4000
+ }
4001
+ ]
4002
+ ) ;
4003
+ }
4004
+
3928
4005
#[ test]
3929
4006
fn test_peek_address_at_index ( ) {
3930
4007
let db = MemoryDatabase :: new ( ) ;
0 commit comments