mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-08 03:01:12 -04:00
chore(BlockchainTree): unwind function (#1775)
Co-authored-by: Georgios Konstantopoulos <me@gakonst.com>
This commit is contained in:
@@ -9,6 +9,7 @@ use std::collections::{hash_map::Entry, BTreeMap, BTreeSet, HashMap, HashSet};
|
||||
///
|
||||
/// It contains list of canonical block hashes, forks to childs blocks
|
||||
/// and block hash to chain id.
|
||||
#[derive(Debug)]
|
||||
pub struct BlockIndices {
|
||||
/// Last finalized block.
|
||||
last_finalized_block: BlockNumber,
|
||||
@@ -241,6 +242,16 @@ impl BlockIndices {
|
||||
self.canonical_chain.extend(blocks.iter().map(|(number, block)| (*number, block.hash())))
|
||||
}
|
||||
|
||||
/// this is function that is going to remove N number of last canonical hashes.
|
||||
///
|
||||
/// NOTE: This is not safe standalone, as it will not disconnect
|
||||
/// blocks that deppends on unwinded canonical chain. And should be
|
||||
/// used when canonical chain is reinserted inside Tree.
|
||||
fn unwind_canonical_chain(&mut self, unwind_to: BlockNumber) {
|
||||
// this will remove all blocks numbers that are going to be replaced.
|
||||
self.canonical_chain.retain(|num, _| *num <= unwind_to);
|
||||
}
|
||||
|
||||
/// Used for finalization of block.
|
||||
/// Return list of chains for removal that depend on finalized canonical chain.
|
||||
pub fn finalize_canonical_blocks(
|
||||
|
||||
@@ -462,15 +462,10 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
|
||||
unreachable!("all chains should point to canonical chain.");
|
||||
}
|
||||
|
||||
// revert `N` blocks from current canonical chain and put them inside BlockchanTree
|
||||
// This is main reorgs on tables.
|
||||
let old_canon_chain = self.revert_canonical(canon_fork.number)?;
|
||||
// commit new canonical chain.
|
||||
self.commit_canonical(new_canon_chain)?;
|
||||
|
||||
// TODO we can potentially merge now reverted canonical chain with
|
||||
// one of the chain from the tree. Low priority.
|
||||
|
||||
// insert old canonical chain to BlockchainTree.
|
||||
// insert old canon chain
|
||||
self.insert_chain(old_canon_chain);
|
||||
}
|
||||
|
||||
@@ -497,6 +492,26 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Unwind tables and put it inside state
|
||||
pub fn unwind(&mut self, unwind_to: BlockNumber) -> Result<(), Error> {
|
||||
// nothing to be done if unwind_to is higher then the tip
|
||||
if self.block_indices.canonical_tip().number <= unwind_to {
|
||||
return Ok(())
|
||||
}
|
||||
// revert `N` blocks from current canonical chain and put them inside BlockchanTree
|
||||
let old_canon_chain = self.revert_canonical(unwind_to)?;
|
||||
|
||||
// check if there is block in chain
|
||||
if old_canon_chain.blocks().is_empty() {
|
||||
return Ok(())
|
||||
}
|
||||
self.block_indices.unwind_canonical_chain(unwind_to);
|
||||
// insert old canonical chain to BlockchainTree.
|
||||
self.insert_chain(old_canon_chain);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Revert canonical blocks from database and insert them to pending table
|
||||
/// Revert should be non inclusive, and revert_until should stay in db.
|
||||
/// Return the chain that represent reverted canonical blocks.
|
||||
@@ -874,6 +889,43 @@ mod tests {
|
||||
.with_fork_to_child(HashMap::from([(block1.hash(), HashSet::from([block2a_hash]))]))
|
||||
.assert(&tree);
|
||||
|
||||
// unwind canonical
|
||||
assert_eq!(tree.unwind(block1.number), Ok(()));
|
||||
// Trie state:
|
||||
// b2 b2a (pending block)
|
||||
// / /
|
||||
// / /
|
||||
// / /
|
||||
// b1 (canonical block)
|
||||
// |
|
||||
// |
|
||||
// g1 (canonical blocks)
|
||||
// |
|
||||
TreeTester::default()
|
||||
.with_chain_num(2)
|
||||
.with_block_to_chain(HashMap::from([(block2a_hash, 4), (block2.hash, 6)]))
|
||||
.with_fork_to_child(HashMap::from([(
|
||||
block1.hash(),
|
||||
HashSet::from([block2a_hash, block2.hash]),
|
||||
)]))
|
||||
.assert(&tree);
|
||||
|
||||
// commit b2a
|
||||
assert_eq!(tree.make_canonical(&block2.hash), Ok(()));
|
||||
// Trie state:
|
||||
// b2 b2a (side chain)
|
||||
// | /
|
||||
// | /
|
||||
// b1 (canon)
|
||||
// |
|
||||
// g1 (10)
|
||||
// |
|
||||
TreeTester::default()
|
||||
.with_chain_num(1)
|
||||
.with_block_to_chain(HashMap::from([(block2a_hash, 4)]))
|
||||
.with_fork_to_child(HashMap::from([(block1.hash(), HashSet::from([block2a_hash]))]))
|
||||
.assert(&tree);
|
||||
|
||||
// update canonical block to b2, this would make b2a be removed
|
||||
assert_eq!(tree.restore_canonical_hashes(12), Ok(()));
|
||||
// Trie state:
|
||||
|
||||
Reference in New Issue
Block a user