mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat(engine, tree): witness invalid block hook (#10685)
This commit is contained in:
36
Cargo.lock
generated
36
Cargo.lock
generated
@ -2370,6 +2370,12 @@ dependencies = [
|
||||
"unicode-xid",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "diff"
|
||||
version = "0.1.13"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "56254986775e3233ffa9c4d7d3faaf6d36a2c09d30b20687e9f88bc8bafc16c8"
|
||||
|
||||
[[package]]
|
||||
name = "digest"
|
||||
version = "0.9.0"
|
||||
@ -5568,6 +5574,16 @@ dependencies = [
|
||||
"termtree",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "pretty_assertions"
|
||||
version = "1.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "af7cee1a6c8a5b9208b3cb1061f10c0cb689087b3d8ce85fb9d2dd7a29b6ba66"
|
||||
dependencies = [
|
||||
"diff",
|
||||
"yansi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "prettyplease"
|
||||
version = "0.2.22"
|
||||
@ -6870,7 +6886,10 @@ name = "reth-engine-primitives"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"reth-chainspec",
|
||||
"reth-execution-types",
|
||||
"reth-payload-primitives",
|
||||
"reth-primitives",
|
||||
"reth-trie",
|
||||
"serde",
|
||||
]
|
||||
|
||||
@ -7306,9 +7325,19 @@ dependencies = [
|
||||
name = "reth-invalid-block-hooks"
|
||||
version = "1.0.6"
|
||||
dependencies = [
|
||||
"alloy-rlp",
|
||||
"alloy-rpc-types-debug",
|
||||
"eyre",
|
||||
"pretty_assertions",
|
||||
"reth-chainspec",
|
||||
"reth-engine-primitives",
|
||||
"reth-evm",
|
||||
"reth-primitives",
|
||||
"reth-provider",
|
||||
"reth-revm",
|
||||
"reth-tracing",
|
||||
"reth-trie",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@ -7591,6 +7620,7 @@ dependencies = [
|
||||
"reth-engine-util",
|
||||
"reth-evm",
|
||||
"reth-exex",
|
||||
"reth-fs-util",
|
||||
"reth-invalid-block-hooks",
|
||||
"reth-network",
|
||||
"reth-network-api",
|
||||
@ -11254,6 +11284,12 @@ dependencies = [
|
||||
"tap",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "yansi"
|
||||
version = "0.5.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "09041cd90cf85f7f8b2df60c646f853b7f535ce68f85244eb6731cf89fa498ec"
|
||||
|
||||
[[package]]
|
||||
name = "yoke"
|
||||
version = "0.7.4"
|
||||
|
||||
@ -12,6 +12,20 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-chainspec.workspace = true
|
||||
reth-engine-primitives.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-trie.workspace = true
|
||||
reth-revm.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-trie = { workspace = true, features = ["serde"] }
|
||||
|
||||
# alloy
|
||||
alloy-rlp.workspace = true
|
||||
alloy-rpc-types-debug.workspace = true
|
||||
|
||||
# misc
|
||||
eyre.workspace = true
|
||||
pretty_assertions = "1.4"
|
||||
serde_json.workspace = true
|
||||
|
||||
@ -2,4 +2,4 @@
|
||||
|
||||
mod witness;
|
||||
|
||||
pub use witness::witness;
|
||||
pub use witness::InvalidBlockWitnessHook;
|
||||
|
||||
@ -1,13 +1,226 @@
|
||||
use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader, B256};
|
||||
use reth_provider::BlockExecutionOutput;
|
||||
use reth_trie::updates::TrieUpdates;
|
||||
use std::{collections::HashMap, fmt::Debug, fs::File, io::Write, path::PathBuf};
|
||||
|
||||
use alloy_rpc_types_debug::ExecutionWitness;
|
||||
use eyre::OptionExt;
|
||||
use pretty_assertions::Comparison;
|
||||
use reth_chainspec::ChainSpec;
|
||||
use reth_engine_primitives::InvalidBlockHook;
|
||||
use reth_evm::{
|
||||
system_calls::{apply_beacon_root_contract_call, apply_blockhashes_contract_call},
|
||||
ConfigureEvm,
|
||||
};
|
||||
use reth_primitives::{keccak256, Receipt, SealedBlockWithSenders, SealedHeader, B256, U256};
|
||||
use reth_provider::{BlockExecutionOutput, ChainSpecProvider, StateProviderFactory};
|
||||
use reth_revm::{
|
||||
database::StateProviderDatabase,
|
||||
db::states::bundle_state::BundleRetention,
|
||||
primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg},
|
||||
DatabaseCommit, StateBuilder,
|
||||
};
|
||||
use reth_tracing::tracing::warn;
|
||||
use reth_trie::{updates::TrieUpdates, HashedPostState, HashedStorage};
|
||||
|
||||
/// 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")
|
||||
#[derive(Debug)]
|
||||
pub struct InvalidBlockWitnessHook<P, EvmConfig> {
|
||||
/// The directory to write the witness to. Additionally, diff files will be written to this
|
||||
/// directory in case of failed sanity checks.
|
||||
output_directory: PathBuf,
|
||||
/// The provider to read the historical state and do the EVM execution.
|
||||
provider: P,
|
||||
/// The EVM configuration to use for the execution.
|
||||
evm_config: EvmConfig,
|
||||
}
|
||||
|
||||
impl<P, EvmConfig> InvalidBlockWitnessHook<P, EvmConfig> {
|
||||
/// Creates a new witness hook.
|
||||
pub const fn new(output_directory: PathBuf, provider: P, evm_config: EvmConfig) -> Self {
|
||||
Self { output_directory, provider, evm_config }
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, EvmConfig> InvalidBlockWitnessHook<P, EvmConfig>
|
||||
where
|
||||
P: StateProviderFactory + ChainSpecProvider<ChainSpec = ChainSpec> + Send + Sync + 'static,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
fn on_invalid_block(
|
||||
&self,
|
||||
parent_header: &SealedHeader,
|
||||
block: &SealedBlockWithSenders,
|
||||
output: &BlockExecutionOutput<Receipt>,
|
||||
trie_updates: Option<(&TrieUpdates, B256)>,
|
||||
) -> eyre::Result<()> {
|
||||
// TODO(alexey): unify with `DebugApi::debug_execution_witness`
|
||||
|
||||
// Setup database.
|
||||
let mut db = StateBuilder::new()
|
||||
.with_database(StateProviderDatabase::new(
|
||||
self.provider.state_by_block_hash(parent_header.hash())?,
|
||||
))
|
||||
.with_bundle_update()
|
||||
.build();
|
||||
|
||||
// Setup environment for the execution.
|
||||
let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
|
||||
let mut block_env = BlockEnv::default();
|
||||
self.evm_config.fill_cfg_and_block_env(
|
||||
&mut cfg,
|
||||
&mut block_env,
|
||||
&self.provider.chain_spec(),
|
||||
block.header(),
|
||||
U256::MAX,
|
||||
);
|
||||
|
||||
// Setup EVM
|
||||
let mut evm = self.evm_config.evm_with_env(
|
||||
&mut db,
|
||||
EnvWithHandlerCfg::new_with_cfg_env(cfg, block_env, Default::default()),
|
||||
);
|
||||
|
||||
// Apply pre-block system contract calls.
|
||||
apply_beacon_root_contract_call(
|
||||
&self.evm_config,
|
||||
&self.provider.chain_spec(),
|
||||
block.timestamp,
|
||||
block.number,
|
||||
block.parent_beacon_block_root,
|
||||
&mut evm,
|
||||
)?;
|
||||
apply_blockhashes_contract_call(
|
||||
&self.evm_config,
|
||||
&self.provider.chain_spec(),
|
||||
block.timestamp,
|
||||
block.number,
|
||||
block.parent_hash,
|
||||
&mut evm,
|
||||
)?;
|
||||
|
||||
// Re-execute all of the transactions in the block to load all touched accounts into
|
||||
// the cache DB.
|
||||
for tx in block.transactions() {
|
||||
self.evm_config.fill_tx_env(
|
||||
evm.tx_mut(),
|
||||
tx,
|
||||
tx.recover_signer().ok_or_eyre("failed to recover sender")?,
|
||||
);
|
||||
let result = evm.transact()?;
|
||||
evm.db_mut().commit(result.state);
|
||||
}
|
||||
|
||||
drop(evm);
|
||||
|
||||
// Merge all state transitions
|
||||
db.merge_transitions(BundleRetention::Reverts);
|
||||
|
||||
// Take the bundle state
|
||||
let bundle_state = db.take_bundle();
|
||||
|
||||
// Initialize a map of preimages.
|
||||
let mut state_preimages = HashMap::new();
|
||||
|
||||
// Grab all account proofs for the data accessed during block execution.
|
||||
//
|
||||
// Note: We grab *all* accounts in the cache here, as the `BundleState` prunes
|
||||
// referenced accounts + storage slots.
|
||||
let mut hashed_state = HashedPostState::from_bundle_state(&bundle_state.state);
|
||||
for (address, account) in db.cache.accounts {
|
||||
let hashed_address = keccak256(address);
|
||||
hashed_state
|
||||
.accounts
|
||||
.insert(hashed_address, account.account.as_ref().map(|a| a.info.clone().into()));
|
||||
|
||||
let storage = hashed_state
|
||||
.storages
|
||||
.entry(hashed_address)
|
||||
.or_insert_with(|| HashedStorage::new(account.status.was_destroyed()));
|
||||
|
||||
if let Some(account) = account.account {
|
||||
state_preimages.insert(hashed_address, alloy_rlp::encode(address).into());
|
||||
|
||||
for (slot, value) in account.storage {
|
||||
let slot = B256::from(slot);
|
||||
let hashed_slot = keccak256(slot);
|
||||
storage.storage.insert(hashed_slot, value);
|
||||
|
||||
state_preimages.insert(hashed_slot, alloy_rlp::encode(slot).into());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Generate an execution witness for the aggregated state of accessed accounts.
|
||||
// Destruct the cache database to retrieve the state provider.
|
||||
let state_provider = db.database.into_inner();
|
||||
let witness = state_provider.witness(HashedPostState::default(), hashed_state.clone())?;
|
||||
|
||||
// Write the witness to the output directory.
|
||||
let mut file = File::options()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(self.output_directory.join(format!("{}_{}.json", block.number, block.hash())))?;
|
||||
let response = ExecutionWitness { witness, state_preimages: Some(state_preimages) };
|
||||
file.write_all(serde_json::to_string(&response)?.as_bytes())?;
|
||||
|
||||
// The bundle state after re-execution should match the original one.
|
||||
if bundle_state != output.state {
|
||||
let filename = format!("{}_{}.bundle_state.diff", block.number, block.hash());
|
||||
let path = self.save_diff(filename, &bundle_state, &output.state)?;
|
||||
warn!(target: "engine::invalid_block_hooks::witness", path = %path.display(), "Bundle state mismatch after re-execution");
|
||||
}
|
||||
|
||||
// Calculate the state root and trie updates after re-execution. They should match
|
||||
// the original ones.
|
||||
let (state_root, trie_output) = state_provider.state_root_with_updates(hashed_state)?;
|
||||
if let Some(trie_updates) = trie_updates {
|
||||
if state_root != trie_updates.1 {
|
||||
let filename = format!("{}_{}.state_root.diff", block.number, block.hash());
|
||||
let path = self.save_diff(filename, &state_root, &trie_updates.1)?;
|
||||
warn!(target: "engine::invalid_block_hooks::witness", path = %path.display(), "State root mismatch after re-execution");
|
||||
}
|
||||
|
||||
if &trie_output != trie_updates.0 {
|
||||
let filename = format!("{}_{}.trie_updates.diff", block.number, block.hash());
|
||||
let path = self.save_diff(filename, &trie_output, trie_updates.0)?;
|
||||
warn!(target: "engine::invalid_block_hooks::witness", path = %path.display(), "Trie updates mismatch after re-execution");
|
||||
}
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Saves the diff of two values into a file with the given name in the output directory.
|
||||
fn save_diff<T: PartialEq + Debug>(
|
||||
&self,
|
||||
filename: String,
|
||||
original: &T,
|
||||
new: &T,
|
||||
) -> eyre::Result<PathBuf> {
|
||||
let path = self.output_directory.join(filename);
|
||||
let diff = Comparison::new(original, new);
|
||||
File::options()
|
||||
.write(true)
|
||||
.create_new(true)
|
||||
.open(&path)?
|
||||
.write_all(diff.to_string().as_bytes())?;
|
||||
|
||||
Ok(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<P, EvmConfig> InvalidBlockHook for InvalidBlockWitnessHook<P, EvmConfig>
|
||||
where
|
||||
P: StateProviderFactory + ChainSpecProvider<ChainSpec = ChainSpec> + Send + Sync + 'static,
|
||||
EvmConfig: ConfigureEvm,
|
||||
{
|
||||
fn on_invalid_block(
|
||||
&self,
|
||||
parent_header: &SealedHeader,
|
||||
block: &SealedBlockWithSenders,
|
||||
output: &BlockExecutionOutput<Receipt>,
|
||||
trie_updates: Option<(&TrieUpdates, B256)>,
|
||||
) {
|
||||
if let Err(err) = self.on_invalid_block(parent_header, block, output, trie_updates) {
|
||||
warn!(target: "engine::invalid_block_hooks::witness", %err, "Failed to invoke hook");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -13,7 +13,10 @@ workspace = true
|
||||
[dependencies]
|
||||
# reth
|
||||
reth-chainspec.workspace = true
|
||||
reth-execution-types.workspace = true
|
||||
reth-payload-primitives.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-trie.workspace = true
|
||||
|
||||
# misc
|
||||
serde.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
36
crates/engine/primitives/src/invalid_block_hook.rs
Normal file
36
crates/engine/primitives/src/invalid_block_hook.rs
Normal file
@ -0,0 +1,36 @@
|
||||
use reth_execution_types::BlockExecutionOutput;
|
||||
use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader, B256};
|
||||
use reth_trie::updates::TrieUpdates;
|
||||
|
||||
/// An invalid block hook.
|
||||
pub trait InvalidBlockHook: Send + Sync {
|
||||
/// Invoked when an invalid block is encountered.
|
||||
fn on_invalid_block(
|
||||
&self,
|
||||
parent_header: &SealedHeader,
|
||||
block: &SealedBlockWithSenders,
|
||||
output: &BlockExecutionOutput<Receipt>,
|
||||
trie_updates: Option<(&TrieUpdates, B256)>,
|
||||
);
|
||||
}
|
||||
|
||||
impl<F> InvalidBlockHook for F
|
||||
where
|
||||
F: Fn(
|
||||
&SealedHeader,
|
||||
&SealedBlockWithSenders,
|
||||
&BlockExecutionOutput<Receipt>,
|
||||
Option<(&TrieUpdates, B256)>,
|
||||
) + Send
|
||||
+ Sync,
|
||||
{
|
||||
fn on_invalid_block(
|
||||
&self,
|
||||
parent_header: &SealedHeader,
|
||||
block: &SealedBlockWithSenders,
|
||||
output: &BlockExecutionOutput<Receipt>,
|
||||
trie_updates: Option<(&TrieUpdates, B256)>,
|
||||
) {
|
||||
self(parent_header, block, output, trie_updates)
|
||||
}
|
||||
}
|
||||
@ -8,6 +8,9 @@
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
|
||||
mod invalid_block_hook;
|
||||
pub use invalid_block_hook::InvalidBlockHook;
|
||||
|
||||
use reth_chainspec::ChainSpec;
|
||||
pub use reth_payload_primitives::{
|
||||
BuiltPayload, EngineApiMessageVersion, EngineObjectValidationError, PayloadOrAttributes,
|
||||
|
||||
@ -1,40 +1,8 @@
|
||||
use reth_engine_primitives::InvalidBlockHook;
|
||||
use reth_primitives::{Receipt, SealedBlockWithSenders, SealedHeader, B256};
|
||||
use reth_provider::BlockExecutionOutput;
|
||||
use reth_trie::updates::TrieUpdates;
|
||||
|
||||
/// A bad block hook.
|
||||
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)>,
|
||||
);
|
||||
}
|
||||
|
||||
impl<F> InvalidBlockHook for F
|
||||
where
|
||||
F: Fn(
|
||||
&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)>,
|
||||
) {
|
||||
self(block, header, output, trie_updates)
|
||||
}
|
||||
}
|
||||
|
||||
/// A no-op [`InvalidBlockHook`] that does nothing.
|
||||
#[derive(Debug, Default)]
|
||||
#[non_exhaustive]
|
||||
@ -43,8 +11,8 @@ pub struct NoopInvalidBlockHook;
|
||||
impl InvalidBlockHook for NoopInvalidBlockHook {
|
||||
fn on_invalid_block(
|
||||
&self,
|
||||
_parent_header: &SealedHeader,
|
||||
_block: &SealedBlockWithSenders,
|
||||
_header: &SealedHeader,
|
||||
_output: &BlockExecutionOutput<Receipt>,
|
||||
_trie_updates: Option<(&TrieUpdates, B256)>,
|
||||
) {
|
||||
@ -63,13 +31,13 @@ impl std::fmt::Debug for InvalidBlockHooks {
|
||||
impl InvalidBlockHook for InvalidBlockHooks {
|
||||
fn on_invalid_block(
|
||||
&self,
|
||||
parent_header: &SealedHeader,
|
||||
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);
|
||||
hook.on_invalid_block(parent_header, block, output, trie_updates);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -63,7 +63,8 @@ mod invalid_block_hook;
|
||||
mod metrics;
|
||||
use crate::{engine::EngineApiRequest, tree::metrics::EngineApiMetrics};
|
||||
pub use config::TreeConfig;
|
||||
pub use invalid_block_hook::{InvalidBlockHook, InvalidBlockHooks, NoopInvalidBlockHook};
|
||||
pub use invalid_block_hook::{InvalidBlockHooks, NoopInvalidBlockHook};
|
||||
pub use reth_engine_primitives::InvalidBlockHook;
|
||||
|
||||
/// Keeps track of the state of the tree.
|
||||
///
|
||||
@ -490,7 +491,7 @@ pub struct EngineApiTreeHandler<P, E, T: EngineTypes> {
|
||||
config: TreeConfig,
|
||||
/// Metrics for the engine api.
|
||||
metrics: EngineApiMetrics,
|
||||
/// A bad block hook.
|
||||
/// An invalid block hook.
|
||||
invalid_block_hook: Box<dyn InvalidBlockHook>,
|
||||
}
|
||||
|
||||
@ -2156,8 +2157,8 @@ where
|
||||
) {
|
||||
// call post-block hook
|
||||
self.invalid_block_hook.on_invalid_block(
|
||||
&block.seal_slow(),
|
||||
&parent_block,
|
||||
&block.seal_slow(),
|
||||
&output,
|
||||
None,
|
||||
);
|
||||
@ -2172,8 +2173,8 @@ where
|
||||
if state_root != block.state_root {
|
||||
// call post-block hook
|
||||
self.invalid_block_hook.on_invalid_block(
|
||||
&block.clone().seal_slow(),
|
||||
&parent_block,
|
||||
&block.clone().seal_slow(),
|
||||
&output,
|
||||
Some((&trie_output, state_root)),
|
||||
);
|
||||
|
||||
@ -13,48 +13,49 @@ workspace = true
|
||||
|
||||
[dependencies]
|
||||
## reth
|
||||
reth-chainspec.workspace = true
|
||||
reth-auto-seal-consensus.workspace = true
|
||||
reth-beacon-consensus.workspace = true
|
||||
reth-blockchain-tree.workspace = true
|
||||
reth-db-common.workspace = true
|
||||
reth-exex.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-chainspec.workspace = true
|
||||
reth-cli-util.workspace = true
|
||||
reth-config.workspace = true
|
||||
reth-consensus-debug-client.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
reth-db = { workspace = true, features = ["mdbx"], optional = true }
|
||||
reth-db-api.workspace = true
|
||||
reth-rpc-engine-api.workspace = true
|
||||
reth-rpc.workspace = true
|
||||
reth-rpc-builder.workspace = true
|
||||
reth-rpc-layer.workspace = true
|
||||
reth-db-common.workspace = true
|
||||
reth-downloaders.workspace = true
|
||||
reth-engine-service.workspace = true
|
||||
reth-engine-tree.workspace = true
|
||||
reth-engine-util.workspace = true
|
||||
reth-evm.workspace = true
|
||||
reth-exex.workspace = true
|
||||
reth-fs-util.workspace = true
|
||||
reth-invalid-block-hooks.workspace = true
|
||||
reth-network-api.workspace = true
|
||||
reth-network-p2p.workspace = true
|
||||
reth-network.workspace = true
|
||||
reth-node-api.workspace = true
|
||||
reth-node-core.workspace = true
|
||||
reth-node-metrics.workspace = true
|
||||
reth-network.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-payload-builder.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
reth-tasks.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-network-p2p.workspace = true
|
||||
reth-static-file.workspace = true
|
||||
reth-prune.workspace = true
|
||||
reth-stages.workspace = true
|
||||
reth-config.workspace = true
|
||||
reth-downloaders.workspace = true
|
||||
reth-node-events.workspace = true
|
||||
reth-consensus.workspace = true
|
||||
reth-consensus-debug-client.workspace = true
|
||||
reth-rpc-types.workspace = true
|
||||
reth-engine-util.workspace = true
|
||||
reth-cli-util.workspace = true
|
||||
reth-rpc-eth-types.workspace = true
|
||||
reth-network-api.workspace = true
|
||||
reth-node-metrics.workspace = true
|
||||
reth-payload-builder.workspace = true
|
||||
reth-payload-validator.workspace = true
|
||||
reth-engine-service.workspace = true
|
||||
reth-primitives.workspace = true
|
||||
reth-provider.workspace = true
|
||||
reth-prune.workspace = true
|
||||
reth-rpc-builder.workspace = true
|
||||
reth-rpc-engine-api.workspace = true
|
||||
reth-rpc-eth-types.workspace = true
|
||||
reth-rpc-layer.workspace = true
|
||||
reth-rpc-types.workspace = true
|
||||
reth-rpc.workspace = true
|
||||
reth-stages.workspace = true
|
||||
reth-static-file.workspace = true
|
||||
reth-tasks.workspace = true
|
||||
reth-tokio-util.workspace = true
|
||||
reth-engine-tree.workspace = true
|
||||
reth-invalid-block-hooks.workspace = true
|
||||
reth-tracing.workspace = true
|
||||
reth-transaction-pool.workspace = true
|
||||
|
||||
## ethereum
|
||||
alloy-network.workspace = true
|
||||
|
||||
@ -17,6 +17,8 @@ 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_fs_util as fs;
|
||||
use reth_invalid_block_hooks::InvalidBlockWitnessHook;
|
||||
use reth_network_p2p::headers::client::HeadersClient;
|
||||
use reth_node_api::{FullNodeTypes, NodeTypes, NodeTypesWithDB};
|
||||
use reth_node_core::{
|
||||
@ -35,8 +37,9 @@ use reth_node_metrics::{
|
||||
use reth_primitives::{BlockNumber, Head, B256};
|
||||
use reth_provider::{
|
||||
providers::{BlockchainProvider, BlockchainProvider2, StaticFileProvider},
|
||||
BlockHashReader, CanonStateNotificationSender, ProviderFactory, ProviderResult,
|
||||
StageCheckpointReader, StaticFileProviderFactory, TreeViewer,
|
||||
BlockHashReader, CanonStateNotificationSender, ChainSpecProvider, ProviderFactory,
|
||||
ProviderResult, StageCheckpointReader, StateProviderFactory, StaticFileProviderFactory,
|
||||
TreeViewer,
|
||||
};
|
||||
use reth_prune::{PruneModes, PrunerBuilder};
|
||||
use reth_rpc_builder::config::RethRpcServerConfig;
|
||||
@ -837,17 +840,34 @@ where
|
||||
pub const fn components(&self) -> &CB::Components {
|
||||
&self.node_adapter().components
|
||||
}
|
||||
}
|
||||
|
||||
impl<T, CB> LaunchContextWith<Attached<WithConfigs, WithComponents<T, CB>>>
|
||||
where
|
||||
T: FullNodeTypes<
|
||||
Provider: WithTree + StateProviderFactory + ChainSpecProvider<ChainSpec = ChainSpec>,
|
||||
Types: NodeTypes<ChainSpec = ChainSpec>,
|
||||
>,
|
||||
CB: NodeComponentsBuilder<T>,
|
||||
{
|
||||
/// 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 output_directory = self.data_dir().invalid_block_hooks();
|
||||
let hooks = hook
|
||||
.iter()
|
||||
.copied()
|
||||
.map(|hook| {
|
||||
let output_directory = output_directory.join(hook.to_string());
|
||||
fs::create_dir_all(&output_directory)?;
|
||||
|
||||
Ok(match hook {
|
||||
reth_node_core::args::InvalidBlockHook::Witness => {
|
||||
Box::new(reth_invalid_block_hooks::witness) as Box<dyn InvalidBlockHook>
|
||||
Box::new(InvalidBlockWitnessHook::new(
|
||||
output_directory,
|
||||
self.blockchain_db().clone(),
|
||||
self.components().evm_config().clone(),
|
||||
)) as Box<dyn InvalidBlockHook>
|
||||
}
|
||||
reth_node_core::args::InvalidBlockHook::PreState |
|
||||
reth_node_core::args::InvalidBlockHook::Opcode => {
|
||||
|
||||
@ -33,7 +33,7 @@ use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
|
||||
use reth_rpc_types::{engine::ClientVersionV1, WithOtherFields};
|
||||
use reth_tasks::TaskExecutor;
|
||||
use reth_tokio_util::EventSender;
|
||||
use reth_tracing::tracing::{debug, error, info, warn};
|
||||
use reth_tracing::tracing::{debug, error, info};
|
||||
use std::sync::Arc;
|
||||
use tokio::sync::{mpsc::unbounded_channel, oneshot};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
@ -204,11 +204,6 @@ where
|
||||
let pruner_events = pruner.events();
|
||||
info!(target: "reth::cli", prune_config=?ctx.prune_config().unwrap_or_default(), "Pruner initialized");
|
||||
|
||||
// TODO: implement methods which convert this value into an actual function
|
||||
if let Some(ref hook_type) = ctx.node_config().debug.invalid_block_hook {
|
||||
warn!(target: "reth::cli", ?hook_type, "Invalid block hooks are not implemented yet! The `debug.invalid-block-hook` flag will do nothing for now.");
|
||||
}
|
||||
|
||||
// Configure the consensus engine
|
||||
let mut eth_service = EngineService::new(
|
||||
ctx.consensus(),
|
||||
|
||||
@ -36,7 +36,7 @@ use reth_provider::providers::BlockchainProvider;
|
||||
use reth_rpc_engine_api::{capabilities::EngineCapabilities, EngineApi};
|
||||
use reth_rpc_types::{engine::ClientVersionV1, WithOtherFields};
|
||||
use reth_tasks::TaskExecutor;
|
||||
use reth_tracing::tracing::{debug, info, warn};
|
||||
use reth_tracing::tracing::{debug, info};
|
||||
use reth_transaction_pool::TransactionPool;
|
||||
use tokio::sync::{mpsc::unbounded_channel, oneshot};
|
||||
use tokio_stream::wrappers::UnboundedReceiverStream;
|
||||
@ -210,10 +210,6 @@ where
|
||||
let max_block = ctx.max_block(network_client.clone()).await?;
|
||||
let mut hooks = EngineHooks::new();
|
||||
|
||||
if let Some(ref hook_type) = ctx.node_config().debug.invalid_block_hook {
|
||||
warn!(target: "reth::cli", ?hook_type, "Bad block hooks are not implemented yet! The `debug.bad-block-hook` flag will do nothing for now.");
|
||||
}
|
||||
|
||||
let static_file_producer = ctx.static_file_producer();
|
||||
let static_file_producer_events = static_file_producer.lock().events();
|
||||
hooks.add(StaticFileHook::new(
|
||||
|
||||
@ -343,6 +343,13 @@ impl<D> ChainPath<D> {
|
||||
pub fn jwt(&self) -> PathBuf {
|
||||
self.data_dir().join("jwt.hex")
|
||||
}
|
||||
|
||||
/// Returns the path to the invalid block hooks directory for this chain.
|
||||
///
|
||||
/// `<DIR>/<CHAIN_ID>/invalid_block_hooks`
|
||||
pub fn invalid_block_hooks(&self) -> PathBuf {
|
||||
self.data_dir().join("invalid_block_hooks")
|
||||
}
|
||||
}
|
||||
|
||||
impl<D> AsRef<Path> for ChainPath<D> {
|
||||
|
||||
@ -140,7 +140,7 @@ pub trait StateProviderFactory: BlockIdReader + Send + Sync {
|
||||
/// Note: this only looks at historical blocks, not pending blocks.
|
||||
fn history_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
|
||||
|
||||
/// Returns _any_[StateProvider] with matching block hash.
|
||||
/// Returns _any_ [StateProvider] with matching block hash.
|
||||
///
|
||||
/// This will return a [StateProvider] for either a historical or pending block.
|
||||
fn state_by_block_hash(&self, block: BlockHash) -> ProviderResult<StateProviderBox>;
|
||||
|
||||
Reference in New Issue
Block a user