mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(engine): invalid block hooks crate (#10629)
Co-authored-by: Dan Cline <6798349+Rjected@users.noreply.github.com>
This commit is contained in:
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