mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-10 18:48:13 -07:00
global: snapshot
This commit is contained in:
@@ -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)),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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 })
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user