Skip to content

Commit

Permalink
sc-state-db: Keep track of LAST_PRUNED after warp syncing (#2228)
Browse files Browse the repository at this point in the history
When warp syncing we import the target block with all its state.
However, we didn't store the `LAST_PRUNED` block which would then lead
to `pruning` to forget about the imported block after a restart of the
node. We just set `LAST_PRUNED` to the parent block of the warp sync
target block to fix this issue.
  • Loading branch information
bkchr authored Nov 9, 2023
1 parent e8029a7 commit b0d0fb3
Showing 1 changed file with 40 additions and 2 deletions.
42 changes: 40 additions & 2 deletions substrate/client/state-db/src/pruning.rs
Original file line number Diff line number Diff line change
Expand Up @@ -406,12 +406,24 @@ impl<BlockHash: Hash, Key: Hash, D: MetaDb> RefWindow<BlockHash, Key, D> {
commit: &mut CommitSet<Key>,
) -> Result<(), Error<D::Error>> {
if self.base == 0 && self.is_empty() && number > 0 {
// assume that parent was canonicalized
// This branch is taken if the node imports the target block of a warp sync.
// assume that the block was canonicalized
self.base = number;
// The parent of the block was the last block that got pruned.
commit
.meta
.inserted
.push((to_meta_key(LAST_PRUNED, &()), (number - 1).encode()));
} else if (self.base + self.window_size()) != number {
return Err(Error::StateDb(StateDbError::InvalidBlockNumber))
}
trace!(target: "state-db", "Adding to pruning window: {:?} ({} inserted, {} deleted)", hash, commit.data.inserted.len(), commit.data.deleted.len());
trace!(
target: "state-db",
"Adding to pruning window: {:?} ({} inserted, {} deleted)",
hash,
commit.data.inserted.len(),
commit.data.deleted.len(),
);
let inserted = if matches!(self.queue, DeathRowQueue::Mem { .. }) {
commit.data.inserted.iter().map(|(k, _)| k.clone()).collect()
} else {
Expand Down Expand Up @@ -869,4 +881,30 @@ mod tests {
pruning.prune_one(&mut commit).unwrap();
db.commit(&commit);
}

/// Ensure that after warp syncing the state is stored correctly in the db. The warp sync target
/// block is imported with all its state at once. This test ensures that after a restart
/// `pruning` still knows that this block was imported.
#[test]
fn store_correct_state_after_warp_syncing() {
for count_insertions in [true, false] {
let mut db = make_db(&[]);
let mut pruning: RefWindow<u64, H256, TestDb> =
RefWindow::new(db.clone(), DEFAULT_MAX_BLOCK_CONSTRAINT, count_insertions).unwrap();
let block = 10000;

// import blocks
let mut commit = make_commit(&[], &[]);
pruning.note_canonical(&block, block, &mut commit).unwrap();
push_last_canonicalized(block, &mut commit);
db.commit(&commit);

// load a new queue from db
// `cache` should be the same
let pruning: RefWindow<u64, H256, TestDb> =
RefWindow::new(db, DEFAULT_MAX_BLOCK_CONSTRAINT, count_insertions).unwrap();

assert_eq!(HaveBlock::Yes, pruning.have_block(&block, block));
}
}
}

0 comments on commit b0d0fb3

Please sign in to comment.