mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-04-30 03:01:58 -04:00
feat(engine): invalid block hooks crate (#10629)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
7
.github/assets/check_wasm.sh
vendored
7
.github/assets/check_wasm.sh
vendored
@@ -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
|
||||
)
|
||||
|
||||
|
||||
10
Cargo.lock
generated
10
Cargo.lock
generated
@@ -7250,6 +7250,15 @@ dependencies = [
|
||||
"thiserror",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-invalid-block-hooks"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"reth-primitives",
|
||||
"reth-provider",
|
||||
"reth-trie",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "reth-ipc"
|
||||
version = "1.0.6"
|
||||
@@ -7533,6 +7542,7 @@ dependencies = [
|
||||
"reth-engine-util",
|
||||
"reth-evm",
|
||||
"reth-exex",
|
||||
"reth-invalid-block-hooks",
|
||||
"reth-network",
|
||||
"reth-network-api",
|
||||
"reth-network-p2p",
|
||||
|
||||
@@ -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/",
|
||||
@@ -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" }
|
||||
|
||||
17
crates/engine/invalid-block-hooks/Cargo.toml
Normal file
17
crates/engine/invalid-block-hooks/Cargo.toml
Normal file
@@ -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
crates/engine/invalid-block-hooks/src/lib.rs
Normal file
5
crates/engine/invalid-block-hooks/src/lib.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
//! Invalid block hook implementations.
|
||||
|
||||
mod witness;
|
||||
|
||||
pub use witness::witness;
|
||||
13
crates/engine/invalid-block-hooks/src/witness.rs
Normal file
13
crates/engine/invalid-block-hooks/src/witness.rs
Normal file
@@ -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")
|
||||
}
|
||||
@@ -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)
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
@@ -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())
|
||||
}
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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;
|
||||
@@ -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(),
|
||||
@@ -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();
|
||||
|
||||
@@ -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 {
|
||||
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user