fix(indexer): walk down to nearest breakpoint

This commit is contained in:
erhant 2026-07-09 11:25:27 +03:00
parent 55a7ab8587
commit 14da3e04c8
3 changed files with 60 additions and 3 deletions

View File

@ -156,11 +156,26 @@ impl RocksDBIO {
));
}
let br_id = closest_breakpoint_id(block_id);
let mut state = self.get_breakpoint(br_id)?;
// walk down to the nearest snapshot that exists
let mut breakpoint_id = closest_breakpoint_id(block_id);
let mut state = loop {
match self.get_breakpoint_opt(breakpoint_id)? {
Some(state) => break state,
None if breakpoint_id == 0 => {
return Err(DbError::db_interaction_error(
"Breakpoint 0 is missing".to_owned(),
));
}
None => {
breakpoint_id = breakpoint_id
.checked_sub(1)
.expect("breakpoint_id > 0 checked above");
}
}
};
let start = u64::from(BREAKPOINT_INTERVAL)
.checked_mul(br_id)
.checked_mul(breakpoint_id)
.expect("Reached maximum breakpoint id");
for block in self.get_block_batch_seq(

View File

@ -55,6 +55,11 @@ impl RocksDBIO {
self.get::<BreakpointCellOwned>(br_id).map(|cell| cell.0)
}
pub fn get_breakpoint_opt(&self, br_id: u64) -> DbResult<Option<V03State>> {
self.get_opt::<BreakpointCellOwned>(br_id)
.map(|opt| opt.map(|cell| cell.0))
}
// Mappings
pub fn get_block_id_by_hash(&self, hash: [u8; 32]) -> DbResult<Option<u64>> {

View File

@ -197,6 +197,43 @@ fn put_block_stores_breakpoint_in_same_batch() {
);
}
#[test]
fn state_replay_falls_back_over_missing_breakpoints() {
let temp_dir = tempdir().unwrap();
let dbio = RocksDBIO::open_or_create(temp_dir.path(), &initial_state()).unwrap();
let from = acc1();
let to = acc2();
let sign_key = acc1_sign_key();
for i in 1..=u64::from(BREAKPOINT_INTERVAL) + 1 {
let prev_hash = dbio.get_meta_last_block_id_in_db().unwrap().map(|last_id| {
let last_block = dbio.get_block(last_id).unwrap().unwrap();
last_block.header.hash
});
let transfer_tx = common::test_utils::create_transaction_native_token_transfer(
from,
(i - 1).into(),
to,
1,
&sign_key,
);
let block = produce_dummy_block(i, prev_hash, vec![transfer_tx]);
dbio.put_block(&block, [0; 32], 0, None).unwrap();
}
assert!(dbio.get_breakpoint_opt(1).unwrap().is_none());
let final_state = dbio.final_state().unwrap();
assert_eq!(
10000 - final_state.get_account_by_id(acc1()).balance,
u128::from(BREAKPOINT_INTERVAL) + 1
);
assert_eq!(
final_state.get_account_by_id(acc2()).balance - 20000,
u128::from(BREAKPOINT_INTERVAL) + 1
);
}
#[test]
fn simple_maps() {
let temp_dir = tempdir().unwrap();