chore(tree): minor Chain modifications (#5487)

This commit is contained in:
Roman Krasiuk
2023-11-18 02:45:48 -08:00
committed by GitHub
parent 6e6e873d88
commit 49d69c66cc
3 changed files with 44 additions and 45 deletions

View File

@ -546,8 +546,9 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
let Some(chain) = self.state.chains.get(&chain_id) else { return hashes }; let Some(chain) = self.state.chains.get(&chain_id) else { return hashes };
hashes.extend(chain.blocks().values().map(|b| (b.number, b.hash()))); hashes.extend(chain.blocks().values().map(|b| (b.number, b.hash())));
let fork_block = chain.fork_block_hash(); let fork_block = chain.fork_block();
if let Some(next_chain_id) = self.block_indices().get_blocks_chain_id(&fork_block) { if let Some(next_chain_id) = self.block_indices().get_blocks_chain_id(&fork_block.hash)
{
chain_id = next_chain_id; chain_id = next_chain_id;
} else { } else {
// if there is no fork block that point to other chains, break the loop. // if there is no fork block that point to other chains, break the loop.
@ -794,7 +795,7 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
// check unconnected block buffer for childs of the chains // check unconnected block buffer for childs of the chains
let mut all_chain_blocks = Vec::new(); let mut all_chain_blocks = Vec::new();
for (_, chain) in self.state.chains.iter() { for (_, chain) in self.state.chains.iter() {
for (&number, blocks) in chain.blocks.iter() { for (&number, blocks) in chain.blocks().iter() {
all_chain_blocks.push(BlockNumHash { number, hash: blocks.hash }) all_chain_blocks.push(BlockNumHash { number, hash: blocks.hash })
} }
} }
@ -946,18 +947,16 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
let canonical = self.split_chain(chain_id, chain, ChainSplitTarget::Hash(*block_hash)); let canonical = self.split_chain(chain_id, chain, ChainSplitTarget::Hash(*block_hash));
durations_recorder.record_relative(MakeCanonicalAction::SplitChain); durations_recorder.record_relative(MakeCanonicalAction::SplitChain);
let mut block_fork = canonical.fork_block(); let mut fork_block = canonical.fork_block();
let mut block_fork_number = canonical.fork_block_number();
let mut chains_to_promote = vec![canonical]; let mut chains_to_promote = vec![canonical];
// loop while fork blocks are found in Tree. // loop while fork blocks are found in Tree.
while let Some(chain_id) = self.block_indices().get_blocks_chain_id(&block_fork.hash) { while let Some(chain_id) = self.block_indices().get_blocks_chain_id(&fork_block.hash) {
let chain = self.state.chains.remove(&chain_id).expect("To fork to be present"); let chain = self.state.chains.remove(&chain_id).expect("fork is present");
block_fork = chain.fork_block();
// canonical chain is lower part of the chain. // canonical chain is lower part of the chain.
let canonical = let canonical =
self.split_chain(chain_id, chain, ChainSplitTarget::Number(block_fork_number)); self.split_chain(chain_id, chain, ChainSplitTarget::Number(fork_block.number));
block_fork_number = canonical.fork_block_number(); fork_block = canonical.fork_block();
chains_to_promote.push(canonical); chains_to_promote.push(canonical);
} }
durations_recorder.record_relative(MakeCanonicalAction::SplitChainForks); durations_recorder.record_relative(MakeCanonicalAction::SplitChainForks);
@ -989,7 +988,7 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
); );
// if joins to the tip; // if joins to the tip;
if new_canon_chain.fork_block_hash() == old_tip.hash { if new_canon_chain.fork_block().hash == old_tip.hash {
chain_notification = chain_notification =
CanonStateNotification::Commit { new: Arc::new(new_canon_chain.clone()) }; CanonStateNotification::Commit { new: Arc::new(new_canon_chain.clone()) };
// append to database // append to database

View File

@ -152,7 +152,7 @@ impl AppendableChain {
) )
})?; })?;
let mut state = self.state.clone(); let mut state = self.state().clone();
// Revert state to the state after execution of the parent block // Revert state to the state after execution of the parent block
state.revert_to(parent.number); state.revert_to(parent.number);
@ -169,11 +169,8 @@ impl AppendableChain {
.map_err(|err| InsertBlockError::new(block.block.clone(), err.into()))?; .map_err(|err| InsertBlockError::new(block.block.clone(), err.into()))?;
state.extend(block_state); state.extend(block_state);
let chain =
Self { chain: Chain { state, blocks: BTreeMap::from([(block.number, block)]) } };
// If all is okay, return new chain back. Present chain is not modified. // If all is okay, return new chain back. Present chain is not modified.
Ok(chain) Ok(Self { chain: Chain::from_block(block, state) })
} }
/// Validate and execute the given block that _extends the canonical chain_, validating its /// Validate and execute the given block that _extends the canonical chain_, validating its
@ -280,10 +277,10 @@ impl AppendableChain {
DB: Database, DB: Database,
EF: ExecutorFactory, EF: ExecutorFactory,
{ {
let (_, parent_block) = self.blocks.last_key_value().expect("Chain has at least one block"); let parent_block = self.chain.tip();
let post_state_data = BundleStateDataRef { let post_state_data = BundleStateDataRef {
state: &self.state, state: self.state(),
sidechain_block_hashes: &side_chain_block_hashes, sidechain_block_hashes: &side_chain_block_hashes,
canonical_block_hashes, canonical_block_hashes,
canonical_fork, canonical_fork,
@ -299,8 +296,7 @@ impl AppendableChain {
) )
.map_err(|err| InsertBlockError::new(block.block.clone(), err.into()))?; .map_err(|err| InsertBlockError::new(block.block.clone(), err.into()))?;
// extend the state. // extend the state.
self.state.extend(block_state); self.chain.append_block(block, block_state);
self.blocks.insert(block.number, block);
Ok(()) Ok(())
} }
} }

View File

@ -16,16 +16,29 @@ use std::{borrow::Cow, collections::BTreeMap, fmt};
/// Used inside the BlockchainTree. /// Used inside the BlockchainTree.
#[derive(Clone, Debug, Default, PartialEq, Eq)] #[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Chain { pub struct Chain {
/// All blocks in this chain.
blocks: BTreeMap<BlockNumber, SealedBlockWithSenders>,
/// The state of all accounts after execution of the _all_ blocks in this chain's range from /// The state of all accounts after execution of the _all_ blocks in this chain's range from
/// [Chain::first] to [Chain::tip], inclusive. /// [Chain::first] to [Chain::tip], inclusive.
/// ///
/// This state also contains the individual changes that lead to the current state. /// This state also contains the individual changes that lead to the current state.
pub state: BundleStateWithReceipts, state: BundleStateWithReceipts,
/// All blocks in this chain.
pub blocks: BTreeMap<BlockNumber, SealedBlockWithSenders>,
} }
impl Chain { impl Chain {
/// Create new Chain from blocks and state.
pub fn new(
blocks: impl IntoIterator<Item = SealedBlockWithSenders>,
state: BundleStateWithReceipts,
) -> Self {
Self { blocks: BTreeMap::from_iter(blocks.into_iter().map(|b| (b.number, b))), state }
}
/// Create new Chain from a single block and its state.
pub fn from_block(block: SealedBlockWithSenders, state: BundleStateWithReceipts) -> Self {
Self::new([block], state)
}
/// Get the blocks in this chain. /// Get the blocks in this chain.
pub fn blocks(&self) -> &BTreeMap<BlockNumber, SealedBlockWithSenders> { pub fn blocks(&self) -> &BTreeMap<BlockNumber, SealedBlockWithSenders> {
&self.blocks &self.blocks
@ -96,18 +109,6 @@ impl Chain {
ForkBlock { number: first.number.saturating_sub(1), hash: first.parent_hash } ForkBlock { number: first.number.saturating_sub(1), hash: first.parent_hash }
} }
/// Get the block number at which this chain forked.
#[track_caller]
pub fn fork_block_number(&self) -> BlockNumber {
self.first().number.saturating_sub(1)
}
/// Get the block hash at which this chain forked.
#[track_caller]
pub fn fork_block_hash(&self) -> BlockHash {
self.first().parent_hash
}
/// Get the first block in this chain. /// Get the first block in this chain.
#[track_caller] #[track_caller]
pub fn first(&self) -> &SealedBlockWithSenders { pub fn first(&self) -> &SealedBlockWithSenders {
@ -124,11 +125,6 @@ impl Chain {
self.blocks.last_key_value().expect("Chain should have at least one block").1 self.blocks.last_key_value().expect("Chain should have at least one block").1
} }
/// Create new chain with given blocks and post state.
pub fn new(blocks: Vec<SealedBlockWithSenders>, state: BundleStateWithReceipts) -> Self {
Self { state, blocks: blocks.into_iter().map(|b| (b.number, b)).collect() }
}
/// Returns length of the chain. /// Returns length of the chain.
pub fn len(&self) -> usize { pub fn len(&self) -> usize {
self.blocks.len() self.blocks.len()
@ -160,22 +156,30 @@ impl Chain {
receipt_attch receipt_attch
} }
/// Append a single block with state to the chain.
/// This method assumes that blocks attachment to the chain has already been validated.
pub fn append_block(&mut self, block: SealedBlockWithSenders, state: BundleStateWithReceipts) {
self.blocks.insert(block.number, block);
self.state.extend(state);
}
/// Merge two chains by appending the given chain into the current one. /// Merge two chains by appending the given chain into the current one.
/// ///
/// The state of accounts for this chain is set to the state of the newest chain. /// The state of accounts for this chain is set to the state of the newest chain.
pub fn append_chain(&mut self, chain: Chain) -> RethResult<()> { pub fn append_chain(&mut self, other: Chain) -> RethResult<()> {
let chain_tip = self.tip(); let chain_tip = self.tip();
if chain_tip.hash != chain.fork_block_hash() { let other_fork_block = other.fork_block();
if chain_tip.hash != other_fork_block.hash {
return Err(BlockExecutionError::AppendChainDoesntConnect { return Err(BlockExecutionError::AppendChainDoesntConnect {
chain_tip: Box::new(chain_tip.num_hash()), chain_tip: Box::new(chain_tip.num_hash()),
other_chain_fork: Box::new(chain.fork_block()), other_chain_fork: Box::new(other_fork_block),
} }
.into()) .into())
} }
// Insert blocks from other chain // Insert blocks from other chain
self.blocks.extend(chain.blocks); self.blocks.extend(other.blocks);
self.state.extend(chain.state); self.state.extend(other.state);
Ok(()) Ok(())
} }