From 0f33cb2fdd385b92a2acb70ca983f2d12feabd13 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Thu, 18 Dec 2025 14:46:06 +1100 Subject: [PATCH 1/2] Improve `test_gap_limit_maintenance` --- .../src/managed_account/address_pool.rs | 45 ++++++++++++++----- 1 file changed, 34 insertions(+), 11 deletions(-) diff --git a/key-wallet/src/managed_account/address_pool.rs b/key-wallet/src/managed_account/address_pool.rs index 50100d3be..683ce2493 100644 --- a/key-wallet/src/managed_account/address_pool.rs +++ b/key-wallet/src/managed_account/address_pool.rs @@ -1229,21 +1229,44 @@ mod tests { #[test] fn test_gap_limit_maintenance() { let base_path = DerivationPath::from(vec![ChildNumber::from_normal_idx(0).unwrap()]); - let mut pool = AddressPool::new_without_generation( - base_path, - AddressPoolType::External, - 5, - Network::Testnet, - ); let key_source = test_key_source(); + let gap_limit = 5; + + // Create pool with gap_limit addresses already generated + let mut pool = + AddressPool::new(base_path, AddressPoolType::External, gap_limit, Network::Testnet, &key_source) + .unwrap(); + + // Verify gap_limit addresses generated, none used + assert_eq!(pool.highest_generated, Some(gap_limit - 1)); + assert_eq!(pool.highest_used, None); + assert_eq!(pool.addresses.len(), gap_limit as usize); + + // Calling maintain_gap_limit should not generate any new addresses when none are used + let new_addresses = pool.maintain_gap_limit(&key_source).unwrap(); + assert_eq!(new_addresses.len(), 0); + assert_eq!(pool.highest_generated, Some(gap_limit - 1)); + assert_eq!(pool.addresses.len(), gap_limit as usize); + + // Mark address at index 0 as used + pool.mark_index_used(0); + assert_eq!(pool.highest_used, Some(0)); + + // Should generate exactly 1 address to maintain gap_limit unused after index 0 + let new_addresses = pool.maintain_gap_limit(&key_source).unwrap(); + assert_eq!(new_addresses.len(), 1); + assert_eq!(pool.highest_generated, Some(gap_limit)); + assert_eq!(pool.addresses.len(), gap_limit as usize + 1); - // Generate initial addresses - pool.generate_addresses(3, &key_source, true).unwrap(); + // Mark address at index 1 and 2 as used pool.mark_index_used(1); + pool.mark_index_used(2); - // Maintain gap limit - let _new_addrs = pool.maintain_gap_limit(&key_source).unwrap(); - assert!(pool.highest_generated.unwrap_or(0) >= 6); // Should have at least index 1 + gap limit 5 + // Should generate exactly 2 more addresses + let new_addresses = pool.maintain_gap_limit(&key_source).unwrap(); + assert_eq!(new_addresses.len(), 2); + assert_eq!(pool.highest_generated, Some(gap_limit + 2)); + assert_eq!(pool.addresses.len(), gap_limit as usize + 3); } #[test] From caf9231cfc71f35388712041ff45b527090a6f90 Mon Sep 17 00:00:00 2001 From: xdustinface Date: Thu, 18 Dec 2025 14:40:28 +1100 Subject: [PATCH 2/2] fix: `maintain_gap_limit` target calculation off by one The target index was calculated incorrectly, causing one extra address to be generated. See the test added which fails without the fix. --- key-wallet/src/managed_account/address_pool.rs | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/key-wallet/src/managed_account/address_pool.rs b/key-wallet/src/managed_account/address_pool.rs index 683ce2493..a4709bd74 100644 --- a/key-wallet/src/managed_account/address_pool.rs +++ b/key-wallet/src/managed_account/address_pool.rs @@ -885,8 +885,8 @@ impl AddressPool { /// Generate addresses to maintain the gap limit pub fn maintain_gap_limit(&mut self, key_source: &KeySource) -> Result> { let target = match self.highest_used { - None => self.gap_limit, - Some(highest) => highest + self.gap_limit + 1, + None => self.gap_limit - 1, + Some(highest) => highest + self.gap_limit, }; let mut new_addresses = Vec::new(); @@ -1233,9 +1233,14 @@ mod tests { let gap_limit = 5; // Create pool with gap_limit addresses already generated - let mut pool = - AddressPool::new(base_path, AddressPoolType::External, gap_limit, Network::Testnet, &key_source) - .unwrap(); + let mut pool = AddressPool::new( + base_path, + AddressPoolType::External, + gap_limit, + Network::Testnet, + &key_source, + ) + .unwrap(); // Verify gap_limit addresses generated, none used assert_eq!(pool.highest_generated, Some(gap_limit - 1));