Skip to content

Commit

Permalink
feat(engine): invalid block hooks crate (#10629)
Browse files Browse the repository at this point in the history
Co-authored-by: Dan Cline <[email protected]>
  • Loading branch information
shekhirin and Rjected committed Sep 3, 2024
1 parent 6b509dd commit 9d46b06
Show file tree
Hide file tree
Showing 12 changed files with 137 additions and 31 deletions.
7 changes: 4 additions & 3 deletions .github/assets/check_wasm.sh
Original file line number Diff line number Diff line change
Expand Up @@ -66,17 +66,18 @@ exclude_crates=(
reth-stages
reth-storage-errors
# The following are not supposed to be working
reth # all of the crates below
reth # all of the crates below
reth-db # mdbx
reth-invalid-block-hooks # reth-provider
reth-libmdbx # mdbx
reth-mdbx-sys # mdbx
reth-nippy-jar # sucds
reth-provider # reth-db, reth-nippy-jar
reth-prune # reth-db
reth-stages-api # reth-provider, reth-prune
reth-static-file # reth-nippy-jar
reth-static-file # reth-nippy-jar
reth-transaction-pool # c-kzg
reth-trie-db # reth-db
reth-trie-db # reth-db
reth-trie-parallel # reth-db
)

Expand Down
10 changes: 10 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ members = [
"crates/consensus/consensus/",
"crates/consensus/debug-client/",
"crates/e2e-test-utils/",
"crates/engine/invalid-block-hooks/",
"crates/engine/primitives/",
"crates/engine/service",
"crates/engine/tree/",
Expand Down Expand Up @@ -330,6 +331,7 @@ reth-exex = { path = "crates/exex/exex" }
reth-exex-test-utils = { path = "crates/exex/test-utils" }
reth-exex-types = { path = "crates/exex/types" }
reth-fs-util = { path = "crates/fs-util" }
reth-invalid-block-hooks = { path = "crates/engine/invalid-block-hooks" }
reth-ipc = { path = "crates/rpc/ipc" }
reth-libmdbx = { path = "crates/storage/libmdbx-rs" }
reth-mdbx-sys = { path = "crates/storage/libmdbx-rs/mdbx-sys" }
Expand Down
17 changes: 17 additions & 0 deletions crates/engine/invalid-block-hooks/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[package]
name = "reth-invalid-block-hooks"
version.workspace = true
edition.workspace = true
rust-version.workspace = true
license.workspace = true
homepage.workspace = true
repository.workspace = true

[lints]
workspace = true

[dependencies]
# reth
reth-primitives.workspace = true
reth-provider.workspace = true
reth-trie.workspace = true
5 changes: 5 additions & 0 deletions crates/engine/invalid-block-hooks/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
//! Invalid block hook implementations.

mod witness;

pub use witness::witness;
13 changes: 13 additions & 0 deletions crates/engine/invalid-block-hooks/src/witness.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader, B256};
use reth_provider::BlockExecutionOutput;
use reth_trie::updates::TrieUpdates;

/// Generates a witness for the given block and saves it to a file.
pub fn witness(
_block: &SealedBlockWithSenders,
_header: &SealedHeader,
_output: &BlockExecutionOutput<Receipt>,
_trie_updates: Option<(&TrieUpdates, B256)>,
) {
unimplemented!("witness generation is not supported")
}
55 changes: 39 additions & 16 deletions crates/engine/tree/src/tree/invalid_block_hook.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,29 +7,29 @@ pub trait InvalidBlockHook: Send + Sync {
/// Invoked when a bad block is encountered.
fn on_invalid_block(
&self,
block: SealedBlockWithSenders,
header: SealedHeader,
output: BlockExecutionOutput<Receipt>,
trie_updates: Option<(TrieUpdates, B256)>,
block: &SealedBlockWithSenders,
header: &SealedHeader,
output: &BlockExecutionOutput<Receipt>,
trie_updates: Option<(&TrieUpdates, B256)>,
);
}

impl<F> InvalidBlockHook for F
where
F: Fn(
SealedBlockWithSenders,
SealedHeader,
BlockExecutionOutput<Receipt>,
Option<(TrieUpdates, B256)>,
&SealedBlockWithSenders,
&SealedHeader,
&BlockExecutionOutput<Receipt>,
Option<(&TrieUpdates, B256)>,
) + Send
+ Sync,
{
fn on_invalid_block(
&self,
block: SealedBlockWithSenders,
header: SealedHeader,
output: BlockExecutionOutput<Receipt>,
trie_updates: Option<(TrieUpdates, B256)>,
block: &SealedBlockWithSenders,
header: &SealedHeader,
output: &BlockExecutionOutput<Receipt>,
trie_updates: Option<(&TrieUpdates, B256)>,
) {
self(block, header, output, trie_updates)
}
Expand All @@ -43,10 +43,33 @@ pub struct NoopInvalidBlockHook;
impl InvalidBlockHook for NoopInvalidBlockHook {
fn on_invalid_block(
&self,
_block: SealedBlockWithSenders,
_header: SealedHeader,
_output: BlockExecutionOutput<Receipt>,
_trie_updates: Option<(TrieUpdates, B256)>,
_block: &SealedBlockWithSenders,
_header: &SealedHeader,
_output: &BlockExecutionOutput<Receipt>,
_trie_updates: Option<(&TrieUpdates, B256)>,
) {
}
}

/// Multiple [`InvalidBlockHook`]s that are executed in order.
pub struct InvalidBlockHooks(pub Vec<Box<dyn InvalidBlockHook>>);

impl std::fmt::Debug for InvalidBlockHooks {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("InvalidBlockHooks").field("len", &self.0.len()).finish()
}
}

impl InvalidBlockHook for InvalidBlockHooks {
fn on_invalid_block(
&self,
block: &SealedBlockWithSenders,
header: &SealedHeader,
output: &BlockExecutionOutput<Receipt>,
trie_updates: Option<(&TrieUpdates, B256)>,
) {
for hook in &self.0 {
hook.on_invalid_block(block, header, output, trie_updates);
}
}
}
17 changes: 11 additions & 6 deletions crates/engine/tree/src/tree/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,7 @@ mod invalid_block_hook;
mod metrics;
use crate::{engine::EngineApiRequest, tree::metrics::EngineApiMetrics};
pub use config::TreeConfig;
pub use invalid_block_hook::{InvalidBlockHook, NoopInvalidBlockHook};
pub use invalid_block_hook::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};

/// Keeps track of the state of the tree.
///
Expand Down Expand Up @@ -1909,7 +1909,12 @@ where
PostExecutionInput::new(&output.receipts, &output.requests),
) {
// call post-block hook
self.invalid_block_hook.on_invalid_block(block.seal_slow(), parent_block, output, None);
self.invalid_block_hook.on_invalid_block(
&block.seal_slow(),
&parent_block,
&output,
None,
);
return Err(err.into())
}

Expand All @@ -1921,10 +1926,10 @@ where
if state_root != block.state_root {
// call post-block hook
self.invalid_block_hook.on_invalid_block(
block.clone().seal_slow(),
parent_block,
output,
Some((trie_output, state_root)),
&block.clone().seal_slow(),
&parent_block,
&output,
Some((&trie_output, state_root)),
);
return Err(ConsensusError::BodyStateRootDiff(
GotExpected { got: state_root, expected: block.state_root }.into(),
Expand Down
1 change: 1 addition & 0 deletions crates/node/builder/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ reth-payload-validator.workspace = true
reth-engine-service.workspace = true
reth-tokio-util.workspace = true
reth-engine-tree.workspace = true
reth-invalid-block-hooks.workspace = true

## ethereum
alloy-network.workspace = true
Expand Down
28 changes: 27 additions & 1 deletion crates/node/builder/src/launch/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ use reth_consensus::Consensus;
use reth_db_api::{database::Database, database_metrics::DatabaseMetrics};
use reth_db_common::init::{init_genesis, InitDatabaseError};
use reth_downloaders::{bodies::noop::NoopBodiesDownloader, headers::noop::NoopHeaderDownloader};
use reth_engine_tree::tree::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};
use reth_evm::noop::NoopBlockExecutorProvider;
use reth_network_p2p::headers::client::HeadersClient;
use reth_node_api::FullNodeTypes;
Expand Down Expand Up @@ -813,7 +814,7 @@ where
inconsistent_stage_checkpoint = stage_checkpoint,
"Pipeline sync progress is inconsistent"
);
return self.blockchain_db().block_hash(first_stage_checkpoint)
return self.blockchain_db().block_hash(first_stage_checkpoint);
}
}

Expand All @@ -839,6 +840,31 @@ where
pub const fn components(&self) -> &CB::Components {
&self.node_adapter().components
}

/// Returns the [`InvalidBlockHook`] to use for the node.
pub fn invalid_block_hook(&self) -> eyre::Result<Box<dyn InvalidBlockHook>> {
Ok(if let Some(ref hook) = self.node_config().debug.invalid_block_hook {
let hooks = hook
.iter()
.copied()
.map(|hook| {
Ok(match hook {
reth_node_core::args::InvalidBlockHook::Witness => {
Box::new(reth_invalid_block_hooks::witness) as Box<dyn InvalidBlockHook>
}
reth_node_core::args::InvalidBlockHook::PreState |
reth_node_core::args::InvalidBlockHook::Opcode => {
eyre::bail!("invalid block hook {hook:?} is not implemented yet")
}
})
})
.collect::<Result<_, _>>()?;

Box::new(InvalidBlockHooks(hooks))
} else {
Box::new(NoopInvalidBlockHook::default())
})
}
}

/// Joins two attachments together.
Expand Down
6 changes: 2 additions & 4 deletions crates/node/builder/src/launch/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use reth_chainspec::ChainSpec;
use reth_engine_service::service::{ChainEvent, EngineService};
use reth_engine_tree::{
engine::{EngineApiRequest, EngineRequestHandler},
tree::{NoopInvalidBlockHook, TreeConfig},
tree::TreeConfig,
};
use reth_engine_util::EngineMessageStreamExt;
use reth_exex::ExExManagerHandle;
Expand Down Expand Up @@ -207,8 +207,6 @@ where
warn!(target: "reth::cli", ?hook_type, "Invalid block hooks are not implemented yet! The `debug.invalid-block-hook` flag will do nothing for now.");
}

let invalid_block_hook = Box::new(NoopInvalidBlockHook::default());

// Configure the consensus engine
let mut eth_service = EngineService::new(
ctx.consensus(),
Expand All @@ -223,7 +221,7 @@ where
pruner,
ctx.components().payload_builder().clone(),
TreeConfig::default(),
invalid_block_hook,
ctx.invalid_block_hook()?,
);

let event_sender = EventSender::default();
Expand Down
7 changes: 6 additions & 1 deletion crates/node/core/src/args/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,7 @@ pub struct DebugArgs {
/// use reth_node_core::args::{InvalidBlockHook, InvalidBlockSelection};
/// let config: InvalidBlockSelection = vec![InvalidBlockHook::Witness].into();
/// ```
#[derive(Debug, Clone, PartialEq, Eq)]
#[derive(Debug, Clone, PartialEq, Eq, derive_more::Deref)]
pub struct InvalidBlockSelection(HashSet<InvalidBlockHook>);

impl InvalidBlockSelection {
Expand Down Expand Up @@ -135,6 +135,11 @@ impl InvalidBlockSelection {
{
selection.into_iter().map(TryInto::try_into).collect()
}

/// Clones the set of configured [`InvalidBlockHook`].
pub fn to_selection(&self) -> HashSet<InvalidBlockHook> {
self.0.clone()
}
}

impl From<&[InvalidBlockHook]> for InvalidBlockSelection {
Expand Down

0 comments on commit 9d46b06

Please sign in to comment.