Skip to content

Commit c9009df

Browse files
feat(sync): derive filter request window from wallet birth height and config; expose earliest_required_height on WalletInterface
1 parent 1e5263f commit c9009df

File tree

3 files changed

+61
-9
lines changed

3 files changed

+61
-9
lines changed

dash-spv/src/client/filter_sync.rs

Lines changed: 29 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -69,25 +69,46 @@ impl<
6969
let tip_height =
7070
self.storage.get_filter_tip_height().await.map_err(SpvError::Storage)?.unwrap_or(0);
7171

72-
// TODO: Get earliest height from wallet's birth height or earliest address usage
73-
// For now, default to last 100 blocks
74-
let earliest_height = tip_height.saturating_sub(99);
75-
76-
let num_blocks = num_blocks.unwrap_or(100);
72+
// Determine how many blocks to request
73+
let num_blocks = num_blocks.unwrap_or(100).max(1);
7774
let default_start = tip_height.saturating_sub(num_blocks - 1);
78-
let start_height = earliest_height.min(default_start); // Go back to the earliest required height
79-
let actual_count = tip_height - start_height + 1; // Actual number of blocks available
75+
76+
// Ask the wallet for an earliest rescan height, falling back to the default window.
77+
let wallet_hint = self.sync_manager.wallet_birth_height_hint().await;
78+
let mut start_height = wallet_hint.unwrap_or(default_start).min(default_start);
79+
80+
// Respect any user-provided start height hint from the configuration.
81+
if let Some(config_start) = self.sync_manager.config_start_height() {
82+
let capped = config_start.min(tip_height);
83+
start_height = start_height.max(capped);
84+
}
85+
86+
// Make sure we never request past the current tip
87+
start_height = start_height.min(tip_height);
88+
89+
let actual_count = if start_height <= tip_height {
90+
tip_height - start_height + 1
91+
} else {
92+
0
93+
};
8094

8195
tracing::info!(
8296
"Requesting filters from height {} to {} ({} blocks based on filter tip height)",
8397
start_height,
8498
tip_height,
8599
actual_count
86100
);
101+
if let Some(hint) = wallet_hint {
102+
tracing::debug!("Wallet hint for earliest required height: {}", hint);
103+
}
87104
tracing::info!("Filter processing and matching will happen automatically in background thread as CFilter messages arrive");
88105

89106
// Send filter requests - processing will happen automatically in the background
90-
self.sync_filters_coordinated(start_height, actual_count).await?;
107+
if actual_count > 0 {
108+
self.sync_filters_coordinated(start_height, actual_count).await?;
109+
} else {
110+
tracing::debug!("No filters requested because calculated range is empty");
111+
}
91112

92113
// Return empty vector since matching happens asynchronously in the filter processor thread
93114
// Actual matches will be processed and blocks requested automatically when CFilter messages arrive

dash-spv/src/sync/sequential/mod.rs

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::sync::{
2626
};
2727
use crate::types::ChainState;
2828
use crate::types::{SharedFilterHeights, SyncProgress};
29-
use key_wallet_manager::wallet_interface::WalletInterface;
29+
use key_wallet_manager::{wallet_interface::WalletInterface, Network as WalletNetwork};
3030
use std::sync::Arc;
3131
use tokio::sync::RwLock;
3232

@@ -142,6 +142,27 @@ impl<
142142
self.header_sync.get_chain_height()
143143
}
144144

145+
/// Get the earliest wallet birth height hint for the configured network, if available.
146+
pub async fn wallet_birth_height_hint(&self) -> Option<u32> {
147+
let wallet_network = match self.config.network {
148+
dashcore::Network::Dash => WalletNetwork::Dash,
149+
dashcore::Network::Testnet => WalletNetwork::Testnet,
150+
dashcore::Network::Devnet => WalletNetwork::Devnet,
151+
dashcore::Network::Regtest => WalletNetwork::Regtest,
152+
_ => WalletNetwork::Dash,
153+
};
154+
155+
let wallet_guard = self.wallet.read().await;
156+
let result = wallet_guard.earliest_required_height(wallet_network).await;
157+
drop(wallet_guard);
158+
result
159+
}
160+
161+
/// Get the configured start height hint, if any.
162+
pub fn config_start_height(&self) -> Option<u32> {
163+
self.config.start_from_height
164+
}
165+
145166
/// Start the sequential sync process
146167
pub async fn start_sync(&mut self, network: &mut N, storage: &mut S) -> SyncResult<bool> {
147168
if self.current_phase.is_syncing() {

key-wallet-manager/src/wallet_interface.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,4 +39,14 @@ pub trait WalletInterface: Send + Sync {
3939
block_hash: &dashcore::BlockHash,
4040
network: Network,
4141
) -> bool;
42+
43+
/// Return the earliest block height that should be scanned for this wallet on the
44+
/// specified network. Implementations can use the wallet's birth height or other
45+
/// metadata to provide a more precise rescan starting point.
46+
///
47+
/// The default implementation returns `None`, which signals that the caller should
48+
/// fall back to its existing behaviour.
49+
async fn earliest_required_height(&self, _network: Network) -> Option<CoreBlockHeight> {
50+
None
51+
}
4252
}

0 commit comments

Comments
 (0)