global: snapshot

This commit is contained in:
nym21
2026-04-14 22:53:10 +02:00
parent 904ec93668
commit 39da441d14
57 changed files with 2886 additions and 1668 deletions
+19 -21
View File
@@ -1,3 +1,4 @@
use brk_error::{Error, Result};
use brk_types::Block;
use crate::State;
@@ -11,7 +12,7 @@ impl BlockIterator {
}
impl Iterator for BlockIterator {
type Item = Block;
type Item = Result<Block>;
fn next(&mut self) -> Option<Self::Item> {
match &mut self.0 {
@@ -21,35 +22,32 @@ impl Iterator for BlockIterator {
prev_hash,
} => {
let height = heights.next()?;
let hash = client.get_block_hash(height).ok()?;
let block = client.get_block(&hash).ok()?;
let hash = match client.get_block_hash(height) {
Ok(h) => h,
Err(e) => return Some(Err(e)),
};
let block = match client.get_block(&hash) {
Ok(b) => b,
Err(e) => return Some(Err(e)),
};
if prev_hash
.as_ref()
.is_some_and(|prev_hash| block.header.prev_blockhash != prev_hash.into())
.is_some_and(|prev| block.header.prev_blockhash != prev.into())
{
return None;
return Some(Err(Error::Internal(
"rpc iterator: chain continuity broken (likely reorg mid-iteration)",
)));
}
prev_hash.replace(hash.clone());
Some(Block::from((height, hash, block)))
}
State::Reader {
receiver,
after_hash,
} => {
let block = Block::from(receiver.recv().ok()?);
// Only validate the first block (Reader validates the rest)
if let Some(expected_prev) = after_hash.take()
&& block.header.prev_blockhash != expected_prev.into()
{
return None;
}
Some(block)
Some(Ok(Block::from((height, hash, block))))
}
State::Reader { receiver } => match receiver.recv().ok()? {
Ok(b) => Some(Ok(Block::from(b))),
Err(e) => Some(Err(e)),
},
}
}
}
+16 -6
View File
@@ -12,8 +12,7 @@ pub enum State {
prev_hash: Option<BlockHash>,
},
Reader {
receiver: Receiver<ReadBlock>,
after_hash: Option<BlockHash>,
receiver: Receiver<Result<ReadBlock>>,
},
}
@@ -36,15 +35,26 @@ impl State {
}
}
/// `after_hash` selects between the two Reader entry points:
///
/// * `Some(anchor)` → [`Reader::after`], which seeds the pipeline's
/// continuity check with `anchor` so the very first emitted
/// block is verified against it. This is what stops a stale
/// anchor (tip of a reorged-out chain) from silently producing
/// a stitched stream.
/// * `None` → [`Reader::range`], which has no anchor to verify
/// against and just streams the canonical blocks at the given
/// heights.
pub fn new_reader(
reader: Reader,
start: Height,
end: Height,
after_hash: Option<BlockHash>,
) -> Result<Self> {
Ok(State::Reader {
receiver: reader.range(start, end)?,
after_hash,
})
let receiver = match after_hash {
Some(hash) => reader.after(Some(hash))?,
None => reader.range(start, end)?,
};
Ok(State::Reader { receiver })
}
}