Skip to content

Commit

Permalink
refactor(engine, tree): connect buffered blocks on pruner finish (#4613)
Browse files Browse the repository at this point in the history
  • Loading branch information
shekhirin authored Sep 19, 2023
1 parent 1406142 commit 57c10e5
Show file tree
Hide file tree
Showing 7 changed files with 63 additions and 36 deletions.
54 changes: 39 additions & 15 deletions crates/blockchain-tree/src/blockchain_tree.rs
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,8 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
}

/// Reads the last `N` canonical hashes from the database and updates the block indices of the
/// tree.
/// tree by attempting to connect the buffered blocks to canonical hashes.
///
///
/// `N` is the `max_reorg_depth` plus the number of block hashes needed to satisfy the
/// `BLOCKHASH` opcode in the EVM.
Expand All @@ -753,21 +754,12 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
///
/// This finalizes `last_finalized_block` prior to reading the canonical hashes (using
/// [`BlockchainTree::finalize_block`]).
pub fn restore_canonical_hashes_and_finalize(
pub fn connect_buffered_blocks_to_canonical_hashes_and_finalize(
&mut self,
last_finalized_block: BlockNumber,
) -> Result<(), Error> {
self.finalize_block(last_finalized_block);

self.restore_canonical_hashes()
}

/// Reads the last `N` canonical hashes from the database and updates the block indices of the
/// tree.
///
/// `N` is the `max_reorg_depth` plus the number of block hashes needed to satisfy the
/// `BLOCKHASH` opcode in the EVM.
pub fn restore_canonical_hashes(&mut self) -> Result<(), Error> {
let num_of_canonical_hashes =
self.config.max_reorg_depth() + self.config.num_of_additional_canonical_block_hashes();

Expand All @@ -790,12 +782,44 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTree<DB, C, EF>
}
}

// check unconnected block buffer for the childs of new added blocks,
for added_block in last_canonical_hashes.into_iter() {
self.connect_buffered_blocks_to_hashes(last_canonical_hashes)?;

Ok(())
}

/// Reads the last `N` canonical hashes from the database and updates the block indices of the
/// tree by attempting to connect the buffered blocks to canonical hashes.
///
/// `N` is the `max_reorg_depth` plus the number of block hashes needed to satisfy the
/// `BLOCKHASH` opcode in the EVM.
pub fn connect_buffered_blocks_to_canonical_hashes(&mut self) -> Result<(), Error> {
let num_of_canonical_hashes =
self.config.max_reorg_depth() + self.config.num_of_additional_canonical_block_hashes();

let last_canonical_hashes = self
.externals
.db
.tx()?
.cursor_read::<tables::CanonicalHeaders>()?
.walk_back(None)?
.take(num_of_canonical_hashes as usize)
.collect::<Result<BTreeMap<BlockNumber, BlockHash>, _>>()?;

self.connect_buffered_blocks_to_hashes(last_canonical_hashes)?;

Ok(())
}

fn connect_buffered_blocks_to_hashes(
&mut self,
hashes: impl IntoIterator<Item = impl Into<BlockNumHash>>,
) -> Result<(), Error> {
// check unconnected block buffer for childs of the canonical hashes
for added_block in hashes.into_iter() {
self.try_connect_buffered_blocks(added_block.into())
}

// 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();
for (_, chain) in self.chains.iter() {
for (&number, blocks) in chain.blocks.iter() {
Expand Down Expand Up @@ -1626,7 +1650,7 @@ mod tests {
.assert(&tree);

// update canonical block to b2, this would make b2a be removed
assert_eq!(tree.restore_canonical_hashes_and_finalize(12), Ok(()));
assert_eq!(tree.connect_buffered_blocks_to_canonical_hashes_and_finalize(12), Ok(()));

assert_eq!(tree.is_block_known(block2.num_hash()).unwrap(), Some(BlockStatus::Valid));

Expand Down
13 changes: 7 additions & 6 deletions crates/blockchain-tree/src/shareable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,21 +66,22 @@ impl<DB: Database, C: Consensus, EF: ExecutorFactory> BlockchainTreeEngine
tree.update_chains_metrics();
}

fn restore_canonical_hashes_and_finalize(
fn connect_buffered_blocks_to_canonical_hashes_and_finalize(
&self,
last_finalized_block: BlockNumber,
) -> Result<(), Error> {
trace!(target: "blockchain_tree", ?last_finalized_block, "Restoring canonical hashes for last finalized block");
trace!(target: "blockchain_tree", ?last_finalized_block, "Connecting buffered blocks to canonical hashes and finalizing the tree");
let mut tree = self.tree.write();
let res = tree.restore_canonical_hashes_and_finalize(last_finalized_block);
let res =
tree.connect_buffered_blocks_to_canonical_hashes_and_finalize(last_finalized_block);
tree.update_chains_metrics();
res
}

fn restore_canonical_hashes(&self) -> Result<(), Error> {
trace!(target: "blockchain_tree", "Restoring canonical hashes");
fn connect_buffered_blocks_to_canonical_hashes(&self) -> Result<(), Error> {
trace!(target: "blockchain_tree", "Connecting buffered blocks to canonical hashes");
let mut tree = self.tree.write();
let res = tree.restore_canonical_hashes();
let res = tree.connect_buffered_blocks_to_canonical_hashes();
tree.update_chains_metrics();
res
}
Expand Down
5 changes: 2 additions & 3 deletions crates/consensus/beacon/src/engine/hooks/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,8 @@ impl EngineHookEvent {
pub enum EngineHookAction {
/// Notify about a [SyncState] update.
UpdateSyncState(SyncState),
/// Read the last relevant canonical hashes from the database and update the block indices of
/// the blockchain tree.
RestoreCanonicalHashes,
/// Connect blocks buffered during the hook execution to canonical hashes.
ConnectBufferedBlocks,
}

/// An error returned by [hook][`EngineHook`].
Expand Down
2 changes: 1 addition & 1 deletion crates/consensus/beacon/src/engine/hooks/prune.rs
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ impl<DB: Database + 'static> PruneHook<DB> {
};

let action = if matches!(event, EngineHookEvent::Finished(Ok(_))) {
Some(EngineHookAction::RestoreCanonicalHashes)
Some(EngineHookAction::ConnectBufferedBlocks)
} else {
None
};
Expand Down
8 changes: 5 additions & 3 deletions crates/consensus/beacon/src/engine/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1334,7 +1334,7 @@ where
let synced_to_finalized = match self.blockchain.block_number(block_hash)? {
Some(number) => {
// Attempt to restore the tree.
self.blockchain.restore_canonical_hashes_and_finalize(number)?;
self.blockchain.connect_buffered_blocks_to_canonical_hashes_and_finalize(number)?;
true
}
None => false,
Expand Down Expand Up @@ -1686,8 +1686,10 @@ where
EngineHookAction::UpdateSyncState(state) => {
self.sync_state_updater.update_sync_state(state)
}
EngineHookAction::RestoreCanonicalHashes => {
if let Err(error) = self.blockchain.restore_canonical_hashes() {
// TODO(alexey): always connect buffered blocks if hook had the
// `EngineHookDBAccessLevel::ReadWrite`
EngineHookAction::ConnectBufferedBlocks => {
if let Err(error) = self.blockchain.connect_buffered_blocks_to_canonical_hashes() {
error!(target: "consensus::engine", ?error, "Error restoring blockchain tree state");
return Err(error.into())
}
Expand Down
9 changes: 5 additions & 4 deletions crates/interfaces/src/blockchain_tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,8 @@ pub trait BlockchainTreeEngine: BlockchainTreeViewer + Send + Sync {
fn finalize_block(&self, finalized_block: BlockNumber);

/// Reads the last `N` canonical hashes from the database and updates the block indices of the
/// tree.
/// tree by attempting to connect the buffered blocks to canonical hashes.
///
///
/// `N` is the `max_reorg_depth` plus the number of block hashes needed to satisfy the
/// `BLOCKHASH` opcode in the EVM.
Expand All @@ -62,17 +63,17 @@ pub trait BlockchainTreeEngine: BlockchainTreeViewer + Send + Sync {
///
/// This finalizes `last_finalized_block` prior to reading the canonical hashes (using
/// [`BlockchainTreeEngine::finalize_block`]).
fn restore_canonical_hashes_and_finalize(
fn connect_buffered_blocks_to_canonical_hashes_and_finalize(
&self,
last_finalized_block: BlockNumber,
) -> Result<(), Error>;

/// Reads the last `N` canonical hashes from the database and updates the block indices of the
/// tree.
/// tree by attempting to connect the buffered blocks to canonical hashes.
///
/// `N` is the `max_reorg_depth` plus the number of block hashes needed to satisfy the
/// `BLOCKHASH` opcode in the EVM.
fn restore_canonical_hashes(&self) -> Result<(), Error>;
fn connect_buffered_blocks_to_canonical_hashes(&self) -> Result<(), Error>;

/// Make a block and its parent chain part of the canonical chain by committing it to the
/// database.
Expand Down
8 changes: 4 additions & 4 deletions crates/storage/provider/src/providers/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -549,15 +549,15 @@ where
self.tree.finalize_block(finalized_block)
}

fn restore_canonical_hashes_and_finalize(
fn connect_buffered_blocks_to_canonical_hashes_and_finalize(
&self,
last_finalized_block: BlockNumber,
) -> Result<()> {
self.tree.restore_canonical_hashes_and_finalize(last_finalized_block)
self.tree.connect_buffered_blocks_to_canonical_hashes_and_finalize(last_finalized_block)
}

fn restore_canonical_hashes(&self) -> Result<()> {
self.tree.restore_canonical_hashes()
fn connect_buffered_blocks_to_canonical_hashes(&self) -> Result<()> {
self.tree.connect_buffered_blocks_to_canonical_hashes()
}

fn make_canonical(&self, block_hash: &BlockHash) -> Result<CanonicalOutcome> {
Expand Down

0 comments on commit 57c10e5

Please sign in to comment.