Skip to content
Merged
Changes from 6 commits
Commits
Show all changes
56 commits
Select commit Hold shift + click to select a range
21c4a6e
feat: add common ancestor to notif
LeoPatOZ Dec 4, 2025
5ef900b
fix: update test for new reorg notif
LeoPatOZ Dec 4, 2025
c956b43
feat: update common fn with new ancestor block notif
LeoPatOZ Dec 4, 2025
4bc5b1f
feat: add reorg streaming and log removal logic
LeoPatOZ Dec 4, 2025
567ddda
ref: move reorg check to internal
LeoPatOZ Dec 4, 2025
31c0e5a
feat: finalized tip reorg opt
LeoPatOZ Dec 4, 2025
5af945c
format: common rs
LeoPatOZ Dec 5, 2025
4737724
Merge branch 'main' into reorg-log-opt
LeoPatOZ Dec 5, 2025
e0286f2
ref: simplify if else
LeoPatOZ Dec 5, 2025
8f204d5
test: latest roerg logic
LeoPatOZ Dec 5, 2025
637fa87
doc: add note about possible opt
LeoPatOZ Dec 5, 2025
3633605
doc: fix comment
LeoPatOZ Dec 5, 2025
11c71aa
Merge branch 'main' into reorg-log-opt
LeoPatOZ Dec 5, 2025
aa6c884
ref: ignore reorg tests for now (add comment why)
LeoPatOZ Dec 8, 2025
c27b70d
ref: remove from in handle reorg
LeoPatOZ Dec 8, 2025
c74e6d5
fix: only send reorg range but continue rewind from previous batch to
LeoPatOZ Dec 8, 2025
e357412
ref: remove retain
LeoPatOZ Dec 8, 2025
b0eaf4b
ref: better reorg block included test + naming
LeoPatOZ Dec 8, 2025
87ad933
ref: use skip_while
LeoPatOZ Dec 8, 2025
3be4d69
feat: maintain proper log ordering + tests
LeoPatOZ Dec 8, 2025
c7584ae
Merge branch 'main' into reorg-log-opt
LeoPatOZ Dec 8, 2025
d8a7fb0
Merge branch 'reorg-log-opt' into maintain-log-order-rewind
LeoPatOZ Dec 8, 2025
81875e4
doc: add comment about reorg handling
LeoPatOZ Dec 8, 2025
d8ffb21
Merge branch 'reorg-log-opt' into maintain-log-order-rewind
LeoPatOZ Dec 9, 2025
ea42f53
ref: use range end instead + remove clone
LeoPatOZ Dec 9, 2025
b216fa7
comment: explain ignored test in comment
LeoPatOZ Dec 9, 2025
ffe122e
test: add BRS tests (ignored until ack channel)
LeoPatOZ Dec 9, 2025
f695d40
Merge branch 'reorg-log-opt' into maintain-log-order-rewind
LeoPatOZ Dec 9, 2025
3370ebe
feat: reverse rewind range to maintain event order
LeoPatOZ Dec 10, 2025
67293ce
feat: add batch iterator helper
LeoPatOZ Dec 10, 2025
1de069d
ref: use for loop
LeoPatOZ Dec 10, 2025
500405e
fix: small bug with batch start
LeoPatOZ Dec 10, 2025
26c0fce
Merge branch 'main' into abstract-loop
LeoPatOZ Dec 11, 2025
12de3ea
fix: merge
LeoPatOZ Dec 11, 2025
f396bc9
fix: doc
LeoPatOZ Dec 11, 2025
3abc3ad
fix: fmt
LeoPatOZ Dec 11, 2025
b20e9b7
Merge branch 'main' into abstract-loop
LeoPatOZ Dec 15, 2025
7a5692c
Merge branch 'main' into abstract-loop
LeoPatOZ Dec 15, 2025
51a29e0
ref: remove example
LeoPatOZ Dec 15, 2025
47134df
ref: use typestate pattern
LeoPatOZ Dec 15, 2025
e38ed39
Merge branch 'main' into abstract-loop
LeoPatOZ Dec 15, 2025
01b0706
ref: remove dead code clippy
LeoPatOZ Dec 15, 2025
1b23f99
feat: add total batches and remove option current
LeoPatOZ Dec 16, 2025
17cbcca
ref: remove tests
LeoPatOZ Dec 16, 2025
a9b4e43
ref: remove unused fns
LeoPatOZ Dec 16, 2025
526ba75
ref: use pub const
LeoPatOZ Dec 16, 2025
2131781
feat: add size hint
LeoPatOZ Dec 16, 2025
217626b
Merge branch 'main' into abstract-loop
LeoPatOZ Dec 16, 2025
3cd38d1
revert: exact size + fix size_hint
LeoPatOZ Dec 17, 2025
606cf4b
ref: use consitent end logic
LeoPatOZ Dec 17, 2025
628aae6
feat: size hint for foward
LeoPatOZ Dec 17, 2025
41469b9
ref: batch --> range
LeoPatOZ Dec 18, 2025
e76aded
remove reference to taiko constant values
0xNeshi Dec 18, 2025
cc39627
add newline between DEFAULT_MAX_BLOCK_RANGE and DEFAULT_BLOCK_CONFIRM…
0xNeshi Dec 18, 2025
6c326f6
Merge branch 'main' into abstract-loop
LeoPatOZ Dec 18, 2025
aced50f
Merge branch 'main' into abstract-loop
0xNeshi Dec 18, 2025
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
110 changes: 34 additions & 76 deletions src/block_range_scanner/batch_iterator.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
#![allow(dead_code)]
use alloy::primitives::BlockNumber;
use std::{marker::PhantomData, ops::RangeInclusive};
use tracing::debug;
Expand All @@ -9,10 +8,11 @@ pub struct Reverse;
/// An iterator that yields block ranges in batches of a configurable size.
#[derive(Debug, Clone)]
pub struct BatchIterator<D> {
current: Option<BlockNumber>,
current: BlockNumber,
end: BlockNumber,
batch_size: u64,
batch_count: u64,
total_batches: u64,
_direction: PhantomData<D>,
}

Expand All @@ -25,13 +25,15 @@ impl BatchIterator<Forward> {
///
/// Panics if `max_block_range` is 0.
#[must_use]
pub fn forward(start: BlockNumber, end: BlockNumber, max_block_range: u64) -> Self {
pub const fn forward(start: BlockNumber, end: BlockNumber, max_block_range: u64) -> Self {
assert!(max_block_range >= 1, "max_block_range must be at least 1");
let total_batches = if start > end { 0 } else { (end - start) / max_block_range + 1 };
Self {
current: if start > end { None } else { Some(start) },
current: start,
end,
batch_size: max_block_range,
batch_count: 0,
total_batches,
_direction: PhantomData,
}
}
Expand All @@ -40,7 +42,12 @@ impl BatchIterator<Forward> {
///
/// Useful after detecting a reorg to rescan from a common ancestor.
pub fn reset_to(&mut self, block: BlockNumber) {
self.current = if block > self.end { None } else { Some(block) };
self.current = block;
self.total_batches = if block > self.end {
self.batch_count + (block - self.end) / self.batch_size + 1
} else {
self.batch_count
};
}
}

Expand All @@ -54,23 +61,18 @@ impl BatchIterator<Reverse> {
///
/// Panics if `max_block_range` is 0.
#[must_use]
pub fn reverse(start: BlockNumber, end: BlockNumber, max_block_range: u64) -> Self {
pub const fn reverse(start: BlockNumber, end: BlockNumber, max_block_range: u64) -> Self {
assert!(max_block_range >= 1, "max_block_range must be at least 1");
let total_batches = if start < end { 0 } else { (start - end) / max_block_range + 1 };
Self {
current: if start < end { None } else { Some(start) },
current: start,
end,
batch_size: max_block_range,
batch_count: 0,
total_batches,
_direction: PhantomData,
}
}

/// Resets the iterator to continue from a new position.
///
/// Useful after detecting a reorg to rescan from a common ancestor.
pub fn reset_to(&mut self, block: BlockNumber) {
self.current = if block < self.end { None } else { Some(block) };
}
}

impl<D> BatchIterator<D> {
Expand All @@ -79,34 +81,24 @@ impl<D> BatchIterator<D> {
pub fn batch_count(&self) -> u64 {
self.batch_count
}

/// Returns the current position, or `None` if exhausted.
#[must_use]
pub fn current(&self) -> Option<BlockNumber> {
self.current
}

/// Returns the end boundary.
#[must_use]
pub fn end(&self) -> BlockNumber {
self.end
}
}

impl Iterator for BatchIterator<Forward> {
type Item = RangeInclusive<BlockNumber>;

fn next(&mut self) -> Option<Self::Item> {
let batch_start = self.current?;
if self.current > self.end {
return None;
}

self.batch_count += 1;
if self.batch_count % 10 == 0 {
debug!(batch_count = self.batch_count, "Processed batches");
}

let batch_start = self.current;
let batch_end = batch_start.saturating_add(self.batch_size - 1).min(self.end);

self.current = if batch_end >= self.end { None } else { Some(batch_end + 1) };
self.current = batch_end + 1;

Some(batch_start..=batch_end)
}
Expand All @@ -116,21 +108,31 @@ impl Iterator for BatchIterator<Reverse> {
type Item = RangeInclusive<BlockNumber>;

fn next(&mut self) -> Option<Self::Item> {
let batch_high = self.current?;
if self.batch_count >= self.total_batches {
return None;
}

self.batch_count += 1;
if self.batch_count % 10 == 0 {
debug!(batch_count = self.batch_count, "Processed batches");
}

let batch_high = self.current;
let batch_low = batch_high.saturating_sub(self.batch_size - 1).max(self.end);

self.current = if batch_low <= self.end { None } else { Some(batch_low - 1) };
self.current = batch_low.saturating_sub(1);

Some(batch_low..=batch_high)
}

fn size_hint(&self) -> (usize, Option<usize>) {
let remaining =
usize::try_from(self.total_batches - self.batch_count).unwrap_or(usize::MAX);
(remaining, Some(remaining))
}
}

impl ExactSizeIterator for BatchIterator<Reverse> {}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -245,22 +247,6 @@ mod tests {
assert_eq!(iter.next(), None);
}

#[test]
fn reset_to_rewinds_reverse_iteration() {
let mut iter = BatchIterator::reverse(300, 100, 50);
assert_eq!(iter.next(), Some(251..=300));
assert_eq!(iter.next(), Some(201..=250));

// Reset to re-scan from a higher block (simulating reorg detection)
iter.reset_to(280);

assert_eq!(iter.next(), Some(231..=280));
assert_eq!(iter.next(), Some(181..=230));
assert_eq!(iter.next(), Some(131..=180));
assert_eq!(iter.next(), Some(100..=130));
assert_eq!(iter.next(), None);
}

#[test]
fn reset_to_after_exhausted() {
let mut iter = BatchIterator::forward(100, 120, 50);
Expand All @@ -283,34 +269,6 @@ mod tests {
assert_eq!(iter.next(), None);
}

#[test]
fn reset_to_beyond_end_exhausts_reverse() {
let mut iter = BatchIterator::reverse(200, 100, 50);
assert_eq!(iter.next(), Some(151..=200));

iter.reset_to(50);

assert_eq!(iter.next(), None);
}

#[test]
fn current_returns_position() {
let mut iter = BatchIterator::forward(100, 300, 50);
assert_eq!(iter.current(), Some(100));

iter.next();
assert_eq!(iter.current(), Some(150));

iter.next();
assert_eq!(iter.current(), Some(200));
}

#[test]
fn end_returns_boundary() {
let iter = BatchIterator::forward(100, 300, 50);
assert_eq!(iter.end(), 300);
}

#[test]
fn forward_starting_from_zero() {
let mut iter = BatchIterator::forward(0, 100, 50);
Expand Down