Skip to content

Commit c5ae92c

Browse files
committed
avoid re-downloading filters during SyncPhase::DownloadingFilters
1 parent c76ddbb commit c5ae92c

File tree

4 files changed

+89
-30
lines changed

4 files changed

+89
-30
lines changed

dash-spv/src/storage/disk/state.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -553,6 +553,10 @@ impl StorageManager for DiskStorageManager {
553553
Self::get_filter_tip_height(self).await
554554
}
555555

556+
async fn get_stored_filter_height(&self) -> StorageResult<Option<u32>> {
557+
Self::get_stored_filter_height(self).await
558+
}
559+
556560
async fn store_masternode_state(&mut self, state: &MasternodeState) -> StorageResult<()> {
557561
Self::store_masternode_state(self, state).await
558562
}

dash-spv/src/storage/memory.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -258,6 +258,15 @@ impl StorageManager for MemoryStorageManager {
258258
}
259259
}
260260

261+
async fn get_stored_filter_height(&self) -> StorageResult<Option<u32>> {
262+
// For memory storage, find the highest filter in the HashMap
263+
if self.filters.is_empty() {
264+
Ok(None)
265+
} else {
266+
Ok(self.filters.keys().max().copied())
267+
}
268+
}
269+
261270
async fn store_masternode_state(&mut self, state: &MasternodeState) -> StorageResult<()> {
262271
self.masternode_state = Some(state.clone());
263272
Ok(())

dash-spv/src/storage/mod.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,10 @@ pub trait StorageManager: Send + Sync {
127127
/// Get the current filter tip blockchain height.
128128
async fn get_filter_tip_height(&self) -> StorageResult<Option<u32>>;
129129

130+
/// Get the highest stored compact filter height by checking which filters are persisted.
131+
/// This is distinct from filter header tip - it shows which filters are actually downloaded.
132+
async fn get_stored_filter_height(&self) -> StorageResult<Option<u32>>;
133+
130134
/// Store masternode state.
131135
async fn store_masternode_state(&mut self, state: &MasternodeState) -> StorageResult<()>;
132136

dash-spv/src/sync/phase_execution.rs

Lines changed: 72 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -149,42 +149,84 @@ impl<
149149
.map_err(|e| SyncError::Storage(format!("Failed to get filter tip: {}", e)))?
150150
.unwrap_or(0);
151151

152-
if filter_header_tip > 0 {
153-
// Download all filters for complete blockchain history
154-
// This ensures the wallet can find transactions from any point in history
155-
let start_height = self.header_sync.get_sync_base_height().max(1);
156-
let count = filter_header_tip - start_height + 1;
152+
// No filter headers available, skip to next phase
153+
if filter_header_tip <= 0 {
154+
self.transition_to_next_phase(storage, network, "No filter headers available")
155+
.await?;
156+
return Ok(());
157+
}
157158

158-
tracing::info!(
159-
"Starting filter download from height {} to {} ({} filters)",
160-
start_height,
161-
filter_header_tip,
162-
count
163-
);
159+
tracing::info!(
160+
"🔍 Filter download check: filter_header_tip={}, sync_base_height={}",
161+
filter_header_tip,
162+
self.header_sync.get_sync_base_height()
163+
);
164164

165-
// Update the phase to track the expected total
166-
if let SyncPhase::DownloadingFilters {
167-
total_filters,
168-
..
169-
} = &mut self.current_phase
170-
{
171-
*total_filters = count;
172-
}
165+
// Check what filters are already stored to resume download
166+
let stored_filter_height =
167+
storage.get_stored_filter_height().await.map_err(|e| {
168+
SyncError::Storage(format!("Failed to get stored filter height: {}", e))
169+
})?;
173170

174-
// Use the filter sync manager to download filters
175-
self.filter_sync
176-
.sync_filters_with_flow_control(
177-
network,
178-
storage,
179-
Some(start_height),
180-
Some(count),
181-
)
182-
.await?;
171+
tracing::info!(
172+
"🔍 Stored filter height from disk scan: {:?}",
173+
stored_filter_height
174+
);
175+
176+
// Resume from the next height after the last stored filter
177+
// If no filters are stored, start from sync_base_height or 1
178+
let start_height = if let Some(stored_height) = stored_filter_height {
179+
tracing::info!(
180+
"Found stored filters up to height {}, resuming from height {}",
181+
stored_height,
182+
stored_height + 1
183+
);
184+
stored_height + 1
183185
} else {
184-
// No filter headers available, skip to next phase
185-
self.transition_to_next_phase(storage, network, "No filter headers available")
186+
let base_height = self.header_sync.get_sync_base_height().max(1);
187+
tracing::info!("No stored filters found, starting from height {}", base_height);
188+
base_height
189+
};
190+
191+
// If we've already downloaded all filters, skip to next phase
192+
if start_height > filter_header_tip {
193+
tracing::info!(
194+
"All filters already downloaded (stored up to {}, tip is {}), skipping to next phase",
195+
start_height - 1,
196+
filter_header_tip
197+
);
198+
self.transition_to_next_phase(storage, network, "Filters already synced")
186199
.await?;
200+
return Ok(());
201+
}
202+
203+
let count = filter_header_tip - start_height + 1;
204+
205+
tracing::info!(
206+
"Starting filter download from height {} to {} ({} filters)",
207+
start_height,
208+
filter_header_tip,
209+
count
210+
);
211+
212+
// Update the phase to track the expected total
213+
if let SyncPhase::DownloadingFilters {
214+
total_filters,
215+
..
216+
} = &mut self.current_phase
217+
{
218+
*total_filters = count;
187219
}
220+
221+
// Use the filter sync manager to download filters
222+
self.filter_sync
223+
.sync_filters_with_flow_control(
224+
network,
225+
storage,
226+
Some(start_height),
227+
Some(count),
228+
)
229+
.await?;
188230
}
189231

190232
SyncPhase::DownloadingBlocks {

0 commit comments

Comments
 (0)