Skip to content

Commit f8875d8

Browse files
committed
add get_batch_unused_addresses
Signed-off-by: nickfarrow <[email protected]>
1 parent df0e410 commit f8875d8

File tree

2 files changed

+87
-0
lines changed

2 files changed

+87
-0
lines changed

CHANGELOG.md

+3
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1616
- Add `get_internal_address` to allow you to get internal addresses just as you get external addresses.
1717
- added `ensure_addresses_cached` to `Wallet` to let offline wallets load and cache addresses in their database
1818
- Add `is_spent` field to `LocalUtxo`; when we notice that a utxo has been spent we set `is_spent` field to true instead of deleting it from the db.
19+
- Changed `AddressIndex::LastUnused` to look back further than `current_index`, and only return a new address if all have been used.
20+
- Add `AddressIndex::FirstUnused` to get unused addresses from the beginning of the keychain.
21+
- Add `wallet.get_batch_unused_addresses` to return vector of N unused addresses, populating any remaining with new addresses.
1922

2023
### Sync API change
2124

src/wallet/mod.rs

+84
Original file line numberDiff line numberDiff line change
@@ -457,6 +457,39 @@ where
457457
Ok(new_addresses_cached)
458458
}
459459

460+
/// Return vector of n unused addresses from the [`KeychainKind`].
461+
/// If less than n unused addresses are returned, the rest will be populated by new addresses.
462+
/// The unused addresses returned are in order of oldest in keychain first, with increasing index.
463+
pub fn get_batch_unused_addresses(
464+
&self,
465+
n: usize,
466+
keychain: KeychainKind,
467+
) -> Result<Vec<AddressInfo>, Error> {
468+
let unused_key_indexes = self.get_unused_key_indexes(keychain)?;
469+
let mut addresses = unused_key_indexes
470+
.iter()
471+
.map(|i| {
472+
let derived_key = self
473+
.get_descriptor_for_keychain(keychain)
474+
.as_derived(*i, &self.secp);
475+
476+
derived_key
477+
.address(self.network)
478+
.map(|address| AddressInfo {
479+
address,
480+
index: *i,
481+
keychain,
482+
})
483+
.map_err(|_| Error::ScriptDoesntHaveAddressForm)
484+
})
485+
.take(n)
486+
.collect::<Result<Vec<_>, _>>()?;
487+
for _ in 0..(n - addresses.len()) {
488+
addresses.push(self.get_new_address(keychain)?)
489+
}
490+
Ok(addresses)
491+
}
492+
460493
/// Return whether or not a `script` is part of this wallet (either internal or external)
461494
pub fn is_mine(&self, script: &Script) -> Result<bool, Error> {
462495
self.database.borrow().is_mine(script)
@@ -3970,6 +4003,57 @@ pub(crate) mod test {
39704003
);
39714004
}
39724005

4006+
#[test]
4007+
fn test_batch_unused_addresses() {
4008+
let descriptor = "wpkh(tpubEBr4i6yk5nf5DAaJpsi9N2pPYBeJ7fZ5Z9rmN4977iYLCGco1VyjB9tvvuvYtfZzjD5A8igzgw3HeWeeKFmanHYqksqZXYXGsw5zjnj7KM9/*)";
4009+
let descriptors = testutils!(@descriptors (descriptor));
4010+
let wallet = Wallet::new(
4011+
&descriptors.0,
4012+
None,
4013+
Network::Testnet,
4014+
MemoryDatabase::new(),
4015+
)
4016+
.unwrap();
4017+
4018+
// get first two addresses, moving index
4019+
for _ in 0..2 {
4020+
let _ = wallet.get_address(New);
4021+
}
4022+
4023+
// use the second address
4024+
crate::populate_test_db!(
4025+
wallet.database.borrow_mut(),
4026+
testutils! (@tx ( (@external descriptors, 1) => 25_000 ) (@confirmations 1)),
4027+
Some(100),
4028+
);
4029+
4030+
assert_eq!(
4031+
wallet
4032+
.get_batch_unused_addresses(3, KeychainKind::External)
4033+
.unwrap(),
4034+
vec![
4035+
AddressInfo {
4036+
index: 0,
4037+
address: Address::from_str("tb1q6yn66vajcctph75pvylgkksgpp6nq04ppwct9a")
4038+
.unwrap(),
4039+
keychain: KeychainKind::External,
4040+
},
4041+
AddressInfo {
4042+
index: 2,
4043+
address: Address::from_str("tb1qzntf2mqex4ehwkjlfdyy3ewdlk08qkvkvrz7x2")
4044+
.unwrap(),
4045+
keychain: KeychainKind::External,
4046+
},
4047+
AddressInfo {
4048+
index: 3,
4049+
address: Address::from_str("tb1q32a23q6u3yy89l8svrt80a54h06qvn7gnuvsen")
4050+
.unwrap(),
4051+
keychain: KeychainKind::External,
4052+
}
4053+
]
4054+
);
4055+
}
4056+
39734057
#[test]
39744058
fn test_peek_address_at_index() {
39754059
let db = MemoryDatabase::new();

0 commit comments

Comments
 (0)