Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(tree): minor Chain modifications #5487

Merged
merged 3 commits into from
Nov 18, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 10 additions & 11 deletions crates/blockchain-tree/src/blockchain_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -546,8 +546,9 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
let Some(chain) = self.state.chains.get(&chain_id) else { return hashes };
hashes.extend(chain.blocks().values().map(|b| (b.number, b.hash())));

let fork_block = chain.fork_block_hash();
if let Some(next_chain_id) = self.block_indices().get_blocks_chain_id(&fork_block) {
let fork_block = chain.fork_block();
if let Some(next_chain_id) = self.block_indices().get_blocks_chain_id(&fork_block.hash)
{
chain_id = next_chain_id;
} else {
// if there is no fork block that point to other chains, break the loop.
Expand Down Expand Up @@ -794,7 +795,7 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
// check unconnected block buffer for childs of the chains
let mut all_chain_blocks = Vec::new();
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 })
}
}
Expand Down Expand Up @@ -946,18 +947,16 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
let canonical = self.split_chain(chain_id, chain, ChainSplitTarget::Hash(*block_hash));
durations_recorder.record_relative(MakeCanonicalAction::SplitChain);

let mut block_fork = canonical.fork_block();
let mut block_fork_number = canonical.fork_block_number();
let mut fork_block = canonical.fork_block();
let mut chains_to_promote = vec![canonical];

// loop while fork blocks are found in Tree.
while let Some(chain_id) = self.block_indices().get_blocks_chain_id(&block_fork.hash) {
let chain = self.state.chains.remove(&chain_id).expect("To fork to be present");
block_fork = chain.fork_block();
while let Some(chain_id) = self.block_indices().get_blocks_chain_id(&fork_block.hash) {
let chain = self.state.chains.remove(&chain_id).expect("fork is present");
// canonical chain is lower part of the chain.
let canonical =
self.split_chain(chain_id, chain, ChainSplitTarget::Number(block_fork_number));
block_fork_number = canonical.fork_block_number();
self.split_chain(chain_id, chain, ChainSplitTarget::Number(fork_block.number));
fork_block = canonical.fork_block();
Comment on lines -950 to +959
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this change preserves old behavior because chain.fork_block() equals to canonical.fork_block() as canonical is just a lower part of the chain

chains_to_promote.push(canonical);
}
durations_recorder.record_relative(MakeCanonicalAction::SplitChainForks);
Expand Down Expand Up @@ -989,7 +988,7 @@ impl<DB: Database, EF: ExecutorFactory> BlockchainTree<DB, EF> {
);

// 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 =
CanonStateNotification::Commit { new: Arc::new(new_canon_chain.clone()) };
// append to database
Expand Down
14 changes: 5 additions & 9 deletions crates/blockchain-tree/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
state.revert_to(parent.number);
Expand All @@ -169,11 +169,8 @@ impl AppendableChain {
.map_err(|err| InsertBlockError::new(block.block.clone(), err.into()))?;
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.
Ok(chain)
Ok(Self { chain: Chain::from_block(block, state) })
}

/// Validate and execute the given block that _extends the canonical chain_, validating its
Expand Down Expand Up @@ -280,10 +277,10 @@ impl AppendableChain {
DB: Database,
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 {
state: &self.state,
state: self.state(),
sidechain_block_hashes: &side_chain_block_hashes,
canonical_block_hashes,
canonical_fork,
Expand All @@ -299,8 +296,7 @@ impl AppendableChain {
)
.map_err(|err| InsertBlockError::new(block.block.clone(), err.into()))?;
// extend the state.
self.state.extend(block_state);
self.blocks.insert(block.number, block);
self.chain.append_block(block, block_state);
Ok(())
}
}
Expand Down
54 changes: 29 additions & 25 deletions crates/storage/provider/src/chain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,16 +16,29 @@ use std::{borrow::Cow, collections::BTreeMap, fmt};
/// Used inside the BlockchainTree.
#[derive(Clone, Debug, Default, PartialEq, Eq)]
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
/// [Chain::first] to [Chain::tip], inclusive.
///
/// This state also contains the individual changes that lead to the current state.
pub state: BundleStateWithReceipts,
/// All blocks in this chain.
pub blocks: BTreeMap<BlockNumber, SealedBlockWithSenders>,
state: BundleStateWithReceipts,
}

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.
pub fn blocks(&self) -> &BTreeMap<BlockNumber, SealedBlockWithSenders> {
&self.blocks
Expand Down Expand Up @@ -96,18 +109,6 @@ impl Chain {
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.
#[track_caller]
pub fn first(&self) -> &SealedBlockWithSenders {
Expand All @@ -124,11 +125,6 @@ impl Chain {
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.
pub fn len(&self) -> usize {
self.blocks.len()
Expand Down Expand Up @@ -160,22 +156,30 @@ impl Chain {
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.
///
/// 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();
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 {
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())
}

// Insert blocks from other chain
self.blocks.extend(chain.blocks);
self.state.extend(chain.state);
self.blocks.extend(other.blocks);
self.state.extend(other.state);

Ok(())
}
Expand Down
Loading