Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dash-spv/src/sync/legacy/message_handlers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,8 @@ impl<S: StorageManager, N: NetworkManager, W: WalletInterface> SyncManager<S, N,
.await
.map_err(|e| SyncError::Storage(format!("Failed to store filter: {}", e)))?;

self.wallet.write().await.update_synced_height(height);

let key = FilterMatchKey::new(height, cfilter.block_hash);
let input = HashMap::from([(key, BlockFilter::new(&cfilter.filter))]);
let addresses = self.wallet.read().await.monitored_addresses();
Expand Down
2 changes: 2 additions & 0 deletions dash-spv/src/sync/legacy/post_sync.rs
Original file line number Diff line number Diff line change
Expand Up @@ -451,6 +451,8 @@ impl<S: StorageManager, N: NetworkManager, W: WalletInterface> SyncManager<S, N,
.await
.map_err(|e| SyncError::Storage(format!("Failed to store filter: {}", e)))?;

self.wallet.write().await.update_synced_height(height);

// TODO: Check filter against wallet instead of watch items
// This will be integrated with wallet's check_compact_filter method
tracing::debug!("Filter checking disabled until wallet integration is complete");
Expand Down
2 changes: 1 addition & 1 deletion key-wallet-ffi/src/wallet_manager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -831,7 +831,7 @@ pub unsafe extern "C" fn wallet_manager_current_height(
// Get current height from network state if it exists
let height = manager_ref.runtime.block_on(async {
let manager_guard = manager_ref.manager.read().await;
manager_guard.current_height()
manager_guard.synced_height()
});

FFIError::set_success(error);
Expand Down
5 changes: 3 additions & 2 deletions key-wallet-ffi/src/wallet_manager_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
mod tests {
use crate::error::{FFIError, FFIErrorCode};
use crate::{wallet, wallet_manager, FFINetwork};
use key_wallet_manager::wallet_interface::WalletInterface;
use std::ffi::{CStr, CString};
use std::ptr;
use std::slice;
Expand Down Expand Up @@ -441,7 +442,7 @@ mod tests {
}

#[test]
fn test_wallet_manager_current_height() {
fn test_wallet_manager_synced_height() {
let mut error = FFIError::success();
let error = &mut error as *mut FFIError;

Expand All @@ -458,7 +459,7 @@ mod tests {
let manager_ref = &*manager;
manager_ref.runtime.block_on(async {
let mut manager_guard = manager_ref.manager.write().await;
manager_guard.update_height(new_height);
manager_guard.update_synced_height(new_height);
});
}

Expand Down
7 changes: 4 additions & 3 deletions key-wallet-manager/examples/wallet_creation.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ use key_wallet::wallet::initialization::WalletAccountCreationOptions;
use key_wallet::wallet::managed_wallet_info::transaction_building::AccountTypePreference;
use key_wallet::wallet::managed_wallet_info::ManagedWalletInfo;
use key_wallet::{AccountType, Network};
use key_wallet_manager::wallet_interface::WalletInterface;
use key_wallet_manager::wallet_manager::WalletManager;

fn main() {
Expand Down Expand Up @@ -141,11 +142,11 @@ fn main() {
// Example 7: Block height tracking
println!("\n7. Block height tracking...");

println!(" Current height (Testnet): {}", manager.current_height());
println!(" Current height (Testnet): {:?}", manager.synced_height());

// Update height
manager.update_height(850_000);
println!(" Updated height to: {}", manager.current_height());
manager.update_synced_height(850_000);
println!(" Updated height to: {:?}", manager.synced_height());

println!("\n=== Summary ===");
println!("Total wallets created: {}", manager.wallet_count());
Expand Down
27 changes: 25 additions & 2 deletions key-wallet-manager/src/test_utils/wallet.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use crate::{wallet_interface::WalletInterface, BlockProcessingResult};
use dashcore::prelude::CoreBlockHeight;
use dashcore::{Address, Block, Transaction, Txid};
use std::{collections::BTreeMap, sync::Arc};
use tokio::sync::Mutex;
Expand All @@ -12,6 +13,7 @@ pub struct MockWallet {
processed_transactions: Arc<Mutex<Vec<dashcore::Txid>>>,
// Map txid -> (net_amount, addresses)
effects: TransactionEffectsMap,
synced_height: CoreBlockHeight,
}

impl MockWallet {
Expand All @@ -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,
}
}

Expand Down Expand Up @@ -67,15 +70,27 @@ impl WalletInterface for MockWallet {
fn monitored_addresses(&self) -> Vec<Address> {
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,
}
}
}

Expand All @@ -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()
}
Expand Down
6 changes: 6 additions & 0 deletions key-wallet-manager/src/wallet_interface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
27 changes: 7 additions & 20 deletions key-wallet-manager/src/wallet_manager/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,8 @@ pub struct CheckTransactionsResult {
pub struct WalletManager<T: WalletInfoInterface = ManagedWalletInfo> {
/// 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<WalletId, Wallet>,
/// Mutable wallet info indexed by wallet ID
Expand All @@ -83,7 +83,7 @@ impl<T: WalletInfoInterface> WalletManager<T> {
pub fn new(network: Network) -> Self {
Self {
network,
current_height: 0,
synced_height: 0,
wallets: BTreeMap::new(),
wallet_infos: BTreeMap::new(),
}
Expand Down Expand Up @@ -272,7 +272,7 @@ impl<T: WalletInfoInterface> WalletManager<T> {

// 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);
Expand Down Expand Up @@ -364,7 +364,7 @@ impl<T: WalletInfoInterface> WalletManager<T> {

// 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);
Expand Down Expand Up @@ -411,7 +411,7 @@ impl<T: WalletInfoInterface> WalletManager<T> {

// 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);
Expand Down Expand Up @@ -455,7 +455,7 @@ impl<T: WalletInfoInterface> WalletManager<T> {
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);
Expand Down Expand Up @@ -950,19 +950,6 @@ impl<T: WalletInfoInterface> WalletManager<T> {
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<Address> {
let mut addresses = Vec::new();
Expand Down
36 changes: 35 additions & 1 deletion key-wallet-manager/src/wallet_manager/process_block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@ impl<T: WalletInfoInterface + Send + Sync + 'static> WalletInterface for WalletM
result.new_addresses.extend(check_result.new_addresses);
}

self.update_height(height);
self.update_synced_height(height);

result
}
Expand Down Expand Up @@ -105,6 +105,17 @@ impl<T: WalletInfoInterface + Send + Sync + 'static> 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 {
Expand Down Expand Up @@ -134,3 +145,26 @@ impl<T: WalletInfoInterface + Send + Sync + 'static> 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<ManagedWalletInfo> = 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);
}
}
19 changes: 10 additions & 9 deletions key-wallet-manager/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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]
Expand All @@ -16,7 +17,7 @@ fn test_wallet_manager_creation() {
let manager = WalletManager::<ManagedWalletInfo>::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
}

Expand Down Expand Up @@ -157,11 +158,11 @@ fn test_block_height_tracking() {
let mut manager = WalletManager::<ManagedWalletInfo>::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
Expand Down Expand Up @@ -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();
Expand All @@ -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);
Expand All @@ -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);
Expand Down
2 changes: 1 addition & 1 deletion key-wallet-manager/tests/spv_integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ async fn test_block_processing_result_empty() {
}

fn assert_wallet_heights(manager: &WalletManager<ManagedWalletInfo>, 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(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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<DashAddress>;

Expand Down Expand Up @@ -103,6 +100,9 @@ pub trait WalletInfoInterface: Sized + WalletTransactionChecker + ManagedAccount
current_block_height: u32,
) -> Result<Transaction, TransactionError>;

/// 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);
Expand Down
Loading