-
Notifications
You must be signed in to change notification settings - Fork 5
Description
Description
When running in ScanMode::Continuous, the scanner never processes the last batch of blocks returned by scan_blocks. This means any transactions in new blocks at the chain tip are never detected until the app is restarted and catches up from scratch.
Root Cause
In run_scan_loop (src/scan/scan.rs around line 564), the !more_blocks check skips block processing entirely:
let (scanned_blocks, more_blocks) = scanner_context.scan_blocks_with_timeout(retry_config).await?;
let batch_size = scanned_blocks.len();
total_scanned += batch_size as u64;
if scanned_blocks.is_empty() || !more_blocks {
// Jumps straight to Completed + wait_for_next_poll_cycle
// Block processing (process_blocks) is NEVER called
// last_scanned_height is NEVER updated
continue;
}
// process_blocks and last_scanned_height update only happens here
// but this code is unreachable when more_blocks = falseWhen at the chain tip, scan_blocks returns blocks with more_blocks = false. The condition !more_blocks is true, so the code skips process_blocks() and never updates last_scanned_height. The scanner then re-polls from the same height, gets the same blocks, skips them again — stuck in an infinite loop.
Evidence
From statuses.log, every poll cycle starts and completes at the exact same height:
Scan started for account 1 from height 528675
Scan completed at height 528675, total blocks scanned 20
Scan waiting, will resume in 20s
Scan started for account 1 from height 528675
Scan completed at height 528675, total blocks scanned 20
Scan waiting, will resume in 20s
It scans 20 blocks every cycle but the height never advances. No TransactionsReady events are emitted. Restarting the app triggers a fresh initial scan that processes everything correctly (because during catch-up, more_blocks = true for most batches).
Suggested Fix
Move block processing before the !more_blocks check, something like:
let (scanned_blocks, more_blocks) = scanner_context.scan_blocks_with_timeout(retry_config).await?;
let batch_size = scanned_blocks.len();
total_scanned += batch_size as u64;
// Process blocks first, regardless of more_blocks
if !scanned_blocks.is_empty() {
let processing_events = db_handler
.process_blocks(scanned_blocks.clone(), ...)
.await?;
all_events.extend(processing_events);
if let Some(last_block) = scanned_blocks.last() {
last_scanned_height = last_block.height;
// ... monitor, reorg checks, etc.
}
}
// Then check if we should wait for more
if scanned_blocks.is_empty() || !more_blocks {
// Completed + continuous wait
}