From 469fed1292007bff59ab9ebdece82b55a919eebe Mon Sep 17 00:00:00 2001 From: xdustinface Date: Thu, 29 Jan 2026 03:17:18 +0100 Subject: [PATCH] feat: add synced height to the wallet interface Add the height management to the interface to make it more accessible and rename it in the same go to `synced_height` since it's more to the point. --- dash-spv/src/sync/legacy/message_handlers.rs | 2 ++ dash-spv/src/sync/legacy/post_sync.rs | 2 ++ key-wallet-ffi/src/wallet_manager.rs | 2 +- key-wallet-ffi/src/wallet_manager_tests.rs | 5 +-- .../examples/wallet_creation.rs | 7 ++-- key-wallet-manager/src/test_utils/wallet.rs | 27 ++++++++++++-- key-wallet-manager/src/wallet_interface.rs | 6 ++++ key-wallet-manager/src/wallet_manager/mod.rs | 27 ++++---------- .../src/wallet_manager/process_block.rs | 36 ++++++++++++++++++- key-wallet-manager/tests/integration_test.rs | 19 +++++----- .../tests/spv_integration_tests.rs | 2 +- .../wallet_info_interface.rs | 6 ++-- 12 files changed, 99 insertions(+), 42 deletions(-) diff --git a/dash-spv/src/sync/legacy/message_handlers.rs b/dash-spv/src/sync/legacy/message_handlers.rs index 6e2ef1a4d..86db624d5 100644 --- a/dash-spv/src/sync/legacy/message_handlers.rs +++ b/dash-spv/src/sync/legacy/message_handlers.rs @@ -513,6 +513,8 @@ impl SyncManager SyncManager>>, // Map txid -> (net_amount, addresses) effects: TransactionEffectsMap, + synced_height: CoreBlockHeight, } impl MockWallet { @@ -20,6 +22,7 @@ impl MockWallet { processed_blocks: Arc::new(Mutex::new(Vec::new())), processed_transactions: Arc::new(Mutex::new(Vec::new())), effects: Arc::new(Mutex::new(BTreeMap::new())), + synced_height: 0, } } @@ -67,15 +70,27 @@ impl WalletInterface for MockWallet { fn monitored_addresses(&self) -> Vec
{ Vec::new() } + + fn synced_height(&self) -> CoreBlockHeight { + self.synced_height + } + + fn update_synced_height(&mut self, height: CoreBlockHeight) { + self.synced_height = height; + } } /// Mock wallet that returns false for filter checks #[derive(Default)] -pub struct NonMatchingMockWallet {} +pub struct NonMatchingMockWallet { + synced_height: CoreBlockHeight, +} impl NonMatchingMockWallet { pub fn new() -> Self { - Self {} + Self { + synced_height: 0, + } } } @@ -91,6 +106,14 @@ impl WalletInterface for NonMatchingMockWallet { Vec::new() } + fn synced_height(&self) -> CoreBlockHeight { + self.synced_height + } + + fn update_synced_height(&mut self, height: CoreBlockHeight) { + self.synced_height = height; + } + async fn describe(&self) -> String { "NonMatchingWallet (test implementation)".to_string() } diff --git a/key-wallet-manager/src/wallet_interface.rs b/key-wallet-manager/src/wallet_interface.rs index e043a1095..2cabc2dfc 100644 --- a/key-wallet-manager/src/wallet_interface.rs +++ b/key-wallet-manager/src/wallet_interface.rs @@ -69,6 +69,12 @@ pub trait WalletInterface: Send + Sync + 'static { 0 } + /// Return the last fully processed height of the wallet. + fn synced_height(&self) -> CoreBlockHeight; + + /// Update the wallet's synced height. This also triggers balance updates. + fn update_synced_height(&mut self, height: CoreBlockHeight); + /// Provide a human-readable description of the wallet implementation. /// /// Implementations are encouraged to include high-level state such as the diff --git a/key-wallet-manager/src/wallet_manager/mod.rs b/key-wallet-manager/src/wallet_manager/mod.rs index ebcbd1896..9a79831bb 100644 --- a/key-wallet-manager/src/wallet_manager/mod.rs +++ b/key-wallet-manager/src/wallet_manager/mod.rs @@ -70,8 +70,8 @@ pub struct CheckTransactionsResult { pub struct WalletManager { /// Network the managed wallets are used for network: Network, - /// Current block height for this network - current_height: CoreBlockHeight, + /// Last fully processed block height. + synced_height: CoreBlockHeight, /// Immutable wallets indexed by wallet ID wallets: BTreeMap, /// Mutable wallet info indexed by wallet ID @@ -83,7 +83,7 @@ impl WalletManager { pub fn new(network: Network) -> Self { Self { network, - current_height: 0, + synced_height: 0, wallets: BTreeMap::new(), wallet_infos: BTreeMap::new(), } @@ -272,7 +272,7 @@ impl WalletManager { // Create managed wallet info let mut managed_info = T::from_wallet(&wallet); - managed_info.set_birth_height(self.current_height); + managed_info.set_birth_height(self.synced_height); managed_info.set_first_loaded_at(current_timestamp()); self.wallets.insert(wallet_id, wallet); @@ -364,7 +364,7 @@ impl WalletManager { // Create managed wallet info let mut managed_info = T::from_wallet(&wallet); - managed_info.set_birth_height(self.current_height); + managed_info.set_birth_height(self.synced_height); managed_info.set_first_loaded_at(current_timestamp()); self.wallets.insert(wallet_id, wallet); @@ -411,7 +411,7 @@ impl WalletManager { // Create managed wallet info let mut managed_info = T::from_wallet(&wallet); - managed_info.set_birth_height(self.current_height); + managed_info.set_birth_height(self.synced_height); managed_info.set_first_loaded_at(current_timestamp()); self.wallets.insert(wallet_id, wallet); @@ -455,7 +455,7 @@ impl WalletManager { let mut managed_info = T::from_wallet(&wallet); // Use the current height as the birth height since we don't know when it was originally created - managed_info.set_birth_height(self.current_height); + managed_info.set_birth_height(self.synced_height); managed_info.set_first_loaded_at(current_timestamp()); self.wallets.insert(wallet_id, wallet); @@ -950,19 +950,6 @@ impl WalletManager { self.network } - /// Get current block height for a specific network - pub fn current_height(&self) -> u32 { - self.current_height - } - - /// Update current block height and propagate to all wallet infos - pub fn update_height(&mut self, height: u32) { - self.current_height = height; - for info in self.wallet_infos.values_mut() { - info.update_synced_height(height); - } - } - /// Get monitored addresses for all wallets for a specific network pub fn monitored_addresses(&self) -> Vec
{ let mut addresses = Vec::new(); diff --git a/key-wallet-manager/src/wallet_manager/process_block.rs b/key-wallet-manager/src/wallet_manager/process_block.rs index c281d69ec..515fc48bd 100644 --- a/key-wallet-manager/src/wallet_manager/process_block.rs +++ b/key-wallet-manager/src/wallet_manager/process_block.rs @@ -42,7 +42,7 @@ impl WalletInterface for WalletM result.new_addresses.extend(check_result.new_addresses); } - self.update_height(height); + self.update_synced_height(height); result } @@ -105,6 +105,17 @@ impl WalletInterface for WalletM self.wallet_infos.values().map(|info| info.birth_height()).min().unwrap_or(0) } + fn synced_height(&self) -> CoreBlockHeight { + self.synced_height + } + + fn update_synced_height(&mut self, height: CoreBlockHeight) { + self.synced_height = height; + for info in self.wallet_infos.values_mut() { + info.update_synced_height(height); + } + } + async fn describe(&self) -> String { let wallet_count = self.wallet_infos.len(); if wallet_count == 0 { @@ -134,3 +145,26 @@ impl WalletInterface for WalletM ) } } + +#[cfg(test)] +mod tests { + use super::*; + use dashcore::Network; + use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo; + + #[tokio::test] + async fn test_synced_height() { + let mut manager: WalletManager = WalletManager::new(Network::Testnet); + // Initial state + assert_eq!(manager.synced_height(), 0); + // Inrease synced height + manager.update_synced_height(1000); + assert_eq!(manager.synced_height(), 1000); + //Increase synced height again + manager.update_synced_height(5000); + assert_eq!(manager.synced_height(), 5000); + // Decrease synced height + manager.update_synced_height(10); + assert_eq!(manager.synced_height(), 10); + } +} diff --git a/key-wallet-manager/tests/integration_test.rs b/key-wallet-manager/tests/integration_test.rs index 6730fec83..8a9a7014f 100644 --- a/key-wallet-manager/tests/integration_test.rs +++ b/key-wallet-manager/tests/integration_test.rs @@ -8,6 +8,7 @@ use key_wallet::wallet::managed_wallet_info::transaction_building::AccountTypePr use key_wallet::wallet::managed_wallet_info::wallet_info_interface::WalletInfoInterface; use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo; use key_wallet::{mnemonic::Language, Mnemonic, Network}; +use key_wallet_manager::wallet_interface::WalletInterface; use key_wallet_manager::wallet_manager::{WalletError, WalletManager}; #[test] @@ -16,7 +17,7 @@ fn test_wallet_manager_creation() { let manager = WalletManager::::new(Network::Testnet); // WalletManager::new returns Self, not Result - assert_eq!(manager.current_height(), 0); + assert_eq!(manager.synced_height(), 0); assert_eq!(manager.wallet_count(), 0); // No wallets created yet } @@ -157,11 +158,11 @@ fn test_block_height_tracking() { let mut manager = WalletManager::::new(Network::Testnet); // Initial state - assert_eq!(manager.current_height(), 0); + assert_eq!(manager.synced_height(), 0); // Set height before adding wallets - manager.update_height(1000); - assert_eq!(manager.current_height(), 1000); + manager.update_synced_height(1000); + assert_eq!(manager.synced_height(), 1000); let mnemonic1 = Mnemonic::generate(12, Language::English).unwrap(); let wallet_id1 = manager @@ -191,8 +192,8 @@ fn test_block_height_tracking() { } // Update height - should propagate to all wallets - manager.update_height(12345); - assert_eq!(manager.current_height(), 12345); + manager.update_synced_height(12345); + assert_eq!(manager.synced_height(), 12345); // Verify all wallets got updated let wallet_info1 = manager.get_wallet_info(&wallet_id1).unwrap(); @@ -201,8 +202,8 @@ fn test_block_height_tracking() { assert_eq!(wallet_info2.synced_height(), 12345); // Update again - verify subsequent updates work - manager.update_height(20000); - assert_eq!(manager.current_height(), 20000); + manager.update_synced_height(20000); + assert_eq!(manager.synced_height(), 20000); for wallet_info in manager.get_all_wallet_infos().values() { assert_eq!(wallet_info.synced_height(), 20000); @@ -222,7 +223,7 @@ fn test_block_height_tracking() { assert_eq!(wallet_info2.synced_height(), 25000); // Manager update_height still syncs all wallets - manager.update_height(40000); + manager.update_synced_height(40000); let wallet_info1 = manager.get_wallet_info(&wallet_id1).unwrap(); let wallet_info2 = manager.get_wallet_info(&wallet_id2).unwrap(); assert_eq!(wallet_info1.synced_height(), 40000); diff --git a/key-wallet-manager/tests/spv_integration_tests.rs b/key-wallet-manager/tests/spv_integration_tests.rs index be32f4764..2ce763687 100644 --- a/key-wallet-manager/tests/spv_integration_tests.rs +++ b/key-wallet-manager/tests/spv_integration_tests.rs @@ -69,7 +69,7 @@ async fn test_block_processing_result_empty() { } fn assert_wallet_heights(manager: &WalletManager, expected_height: u32) { - assert_eq!(manager.current_height(), expected_height, "height should be {}", expected_height); + assert_eq!(manager.synced_height(), expected_height, "height should be {}", expected_height); for wallet_info in manager.get_all_wallet_infos().values() { assert_eq!( wallet_info.synced_height(), diff --git a/key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs b/key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs index 128e2a1a3..5f2a84955 100644 --- a/key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs +++ b/key-wallet/src/wallet/managed_wallet_info/wallet_info_interface.rs @@ -61,9 +61,6 @@ pub trait WalletInfoInterface: Sized + WalletTransactionChecker + ManagedAccount /// Update last synced timestamp fn update_last_synced(&mut self, timestamp: u64); - /// Get the synced height - fn synced_height(&self) -> CoreBlockHeight; - /// Get all monitored addresses fn monitored_addresses(&self) -> Vec; @@ -103,6 +100,9 @@ pub trait WalletInfoInterface: Sized + WalletTransactionChecker + ManagedAccount current_block_height: u32, ) -> Result; + /// Return the last fully processed height of the wallet. + fn synced_height(&self) -> CoreBlockHeight; + /// Update chain state and process any matured transactions /// This should be called when the chain tip advances to a new height fn update_synced_height(&mut self, current_height: u32);