diff --git a/crates/block-processor/Cargo.toml b/crates/block-processor/Cargo.toml index a916963..c236402 100644 --- a/crates/block-processor/Cargo.toml +++ b/crates/block-processor/Cargo.toml @@ -25,8 +25,6 @@ signet-storage-types.workspace = true alloy.workspace = true -reth.workspace = true - eyre.workspace = true metrics.workspace = true tracing.workspace = true diff --git a/crates/block-processor/src/alias.rs b/crates/block-processor/src/alias.rs index f9daaab..04e79cd 100644 --- a/crates/block-processor/src/alias.rs +++ b/crates/block-processor/src/alias.rs @@ -1,11 +1,4 @@ -use alloy::{ - consensus::constants::KECCAK_EMPTY, - primitives::{Address, map::HashSet}, -}; -use eyre::OptionExt; -#[cfg(doc)] -use reth::providers::StateProvider; -use reth::providers::{StateProviderBox, StateProviderFactory}; +use alloy::primitives::{Address, map::HashSet}; use std::sync::{Arc, Mutex}; /// Simple trait to allow checking if an address should be aliased. @@ -14,35 +7,6 @@ pub trait AliasOracle { fn should_alias(&self, address: Address) -> eyre::Result; } -/// Default implementation of [`AliasOracle`] for any type implementing -/// [`StateProvider`]. This implementation checks if the address has bytecode -/// associated with it, and if so, whether that bytecode matches the pattern -/// for a 7702 delegation contract. If it is a delegation contract, it is not -/// aliased; otherwise, it is aliased. -impl AliasOracle for StateProviderBox { - fn should_alias(&self, address: Address) -> eyre::Result { - // No account at this address. - let Some(acct) = self.basic_account(&address)? else { return Ok(false) }; - // Get the bytecode hash for this account. - let bch = match acct.bytecode_hash { - Some(hash) => hash, - // No bytecode hash; not a contract. - None => return Ok(false), - }; - // No code at this address. - if bch == KECCAK_EMPTY { - return Ok(false); - } - // Fetch the code associated with this bytecode hash. - let code = self - .bytecode_by_hash(&bch)? - .ok_or_eyre("code not found. This indicates a corrupted database")?; - - // If not a 7702 delegation contract, alias it. - Ok(!code.is_eip7702()) - } -} - impl AliasOracle for HashSet
{ fn should_alias(&self, address: Address) -> eyre::Result { Ok(self.contains(&address)) @@ -51,9 +15,8 @@ impl AliasOracle for HashSet
{ /// Factory trait to create new [`AliasOracle`] instances. /// -/// The default implementation on `Box` creates -/// [`AliasOracle`] instances backed by the state provider for a given block -/// height. It will error if that state provider cannot be obtained. +/// See `signet-node` for the reth-backed implementation that creates +/// [`AliasOracle`] instances backed by the host chain state provider. /// /// This trait is primarily intended to allow injecting test implementations /// of [`AliasOracle`] into the Signet Node for testing purposes. The test @@ -67,21 +30,6 @@ pub trait AliasOracleFactory: Send + Sync + 'static { fn create(&self) -> eyre::Result; } -impl AliasOracleFactory for Box { - type Oracle = StateProviderBox; - - fn create(&self) -> eyre::Result { - // NB: This becomes a problem if anyone ever birthday attacks a - // contract/EOA pair (c.f. EIP-3607). In practice this is unlikely to - // happen for the foreseeable future, and if it does we can revisit - // this decision. - // We considered taking the host height as an argument to this method, - // but this would require all nodes to be archive nodes in order to - // sync, which is less than ideal - self.state_by_block_number_or_tag(alloy::eips::BlockNumberOrTag::Latest).map_err(Into::into) - } -} - /// This implementation is primarily for testing purposes. impl AliasOracleFactory for HashSet
{ type Oracle = HashSet
; diff --git a/crates/block-processor/src/v1/processor.rs b/crates/block-processor/src/v1/processor.rs index c0ffc55..e28588f 100644 --- a/crates/block-processor/src/v1/processor.rs +++ b/crates/block-processor/src/v1/processor.rs @@ -6,7 +6,6 @@ use alloy::{ use core::fmt; use eyre::{ContextCompat, WrapErr}; use init4_bin_base::utils::calc::SlotCalculator; -use reth::{providers::StateProviderFactory, revm::db::StateBuilder}; use signet_blobber::{CacheHandle, ExtractableChainShim}; use signet_constants::SignetSystemConstants; use signet_evm::{BlockResult, EthereumHardfork, EvmNeedsCfg, SignetDriver}; @@ -19,7 +18,7 @@ use signet_storage_types::{DbSignetEvent, DbZenithHeader, ExecutedBlock, Execute use std::collections::VecDeque; use tracing::{error, instrument}; use trevm::revm::{ - database::{DBErrorMarker, State}, + database::{DBErrorMarker, State, StateBuilder}, primitives::hardfork::SpecId, }; @@ -32,7 +31,7 @@ type HotRevmState = State::RoTx>>; /// The processor is a stateless executor: it reads state from hot storage, /// runs the EVM, and returns an [`ExecutedBlock`]. The caller (node) handles /// extraction, persistence, and orchestrates the per-block loop. -pub struct SignetBlockProcessor> +pub struct SignetBlockProcessor where H: HotKv, { @@ -56,7 +55,7 @@ where blob_cacher: CacheHandle, } -impl fmt::Debug for SignetBlockProcessor +impl fmt::Debug for SignetBlockProcessor where H: HotKv, { diff --git a/crates/node/src/alias.rs b/crates/node/src/alias.rs new file mode 100644 index 0000000..8a06344 --- /dev/null +++ b/crates/node/src/alias.rs @@ -0,0 +1,79 @@ +use alloy::{consensus::constants::KECCAK_EMPTY, primitives::Address}; +use core::fmt; +use eyre::OptionExt; +use reth::providers::{StateProviderBox, StateProviderFactory}; +use signet_block_processor::{AliasOracle, AliasOracleFactory}; + +/// An [`AliasOracle`] backed by a reth [`StateProviderBox`]. +/// +/// Checks whether an address has non-delegation bytecode, indicating it +/// should be aliased during transaction processing. +pub struct RethAliasOracle(StateProviderBox); + +impl fmt::Debug for RethAliasOracle { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RethAliasOracle").finish_non_exhaustive() + } +} + +impl AliasOracle for RethAliasOracle { + fn should_alias(&self, address: Address) -> eyre::Result { + // No account at this address. + let Some(acct) = self.0.basic_account(&address)? else { return Ok(false) }; + // Get the bytecode hash for this account. + let bch = match acct.bytecode_hash { + Some(hash) => hash, + // No bytecode hash; not a contract. + None => return Ok(false), + }; + // No code at this address. + if bch == KECCAK_EMPTY { + return Ok(false); + } + // Fetch the code associated with this bytecode hash. + let code = self + .0 + .bytecode_by_hash(&bch)? + .ok_or_eyre("code not found. This indicates a corrupted database")?; + + // If not a 7702 delegation contract, alias it. + Ok(!code.is_eip7702()) + } +} + +/// An [`AliasOracleFactory`] backed by a `Box`. +/// +/// Creates [`RethAliasOracle`] instances from the latest host chain state. +pub struct RethAliasOracleFactory(Box); + +impl fmt::Debug for RethAliasOracleFactory { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RethAliasOracleFactory").finish_non_exhaustive() + } +} + +impl RethAliasOracleFactory { + /// Create a new [`RethAliasOracleFactory`] from a boxed state provider + /// factory. + pub fn new(provider: Box) -> Self { + Self(provider) + } +} + +impl AliasOracleFactory for RethAliasOracleFactory { + type Oracle = RethAliasOracle; + + fn create(&self) -> eyre::Result { + // NB: This becomes a problem if anyone ever birthday attacks a + // contract/EOA pair (c.f. EIP-3607). In practice this is unlikely to + // happen for the foreseeable future, and if it does we can revisit + // this decision. + // We considered taking the host height as an argument to this method, + // but this would require all nodes to be archive nodes in order to + // sync, which is less than ideal + self.0 + .state_by_block_number_or_tag(alloy::eips::BlockNumberOrTag::Latest) + .map(RethAliasOracle) + .map_err(Into::into) + } +} diff --git a/crates/node/src/builder.rs b/crates/node/src/builder.rs index 2b319e8..490c542 100644 --- a/crates/node/src/builder.rs +++ b/crates/node/src/builder.rs @@ -1,6 +1,6 @@ #![allow(clippy::type_complexity)] -use crate::{NodeStatus, SignetNode}; +use crate::{NodeStatus, RethAliasOracleFactory, SignetNode}; use eyre::OptionExt; use reth::{primitives::EthPrimitives, providers::StateProviderFactory}; use reth_exex::ExExContext; @@ -170,7 +170,7 @@ where self.prebuild().await?; let ctx = self.ctx.unwrap(); let provider = ctx.provider().clone(); - let alias_oracle: Box = Box::new(provider); + let alias_oracle = RethAliasOracleFactory::new(Box::new(provider)); SignetNode::new_unsafe( ctx, diff --git a/crates/node/src/lib.rs b/crates/node/src/lib.rs index 4af3110..c8e7c60 100644 --- a/crates/node/src/lib.rs +++ b/crates/node/src/lib.rs @@ -11,6 +11,9 @@ #![deny(unused_must_use, rust_2018_idioms)] #![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))] +mod alias; +pub use alias::{RethAliasOracle, RethAliasOracleFactory}; + mod builder; pub use builder::SignetNodeBuilder; diff --git a/crates/node/src/node.rs b/crates/node/src/node.rs index bff288a..078b4b8 100644 --- a/crates/node/src/node.rs +++ b/crates/node/src/node.rs @@ -1,11 +1,11 @@ -use crate::{NodeStatus, metrics}; +use crate::{NodeStatus, RethAliasOracleFactory, metrics}; use alloy::consensus::BlockHeader; use eyre::Context; use futures_util::StreamExt; use reth::{ chainspec::EthChainSpec, primitives::EthPrimitives, - providers::{BlockIdReader, BlockReader, HeaderProvider, StateProviderFactory}, + providers::{BlockIdReader, BlockReader, HeaderProvider}, }; use reth_exex::{ExExContext, ExExEvent, ExExHead, ExExNotificationsStream}; use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes}; @@ -29,7 +29,7 @@ type ExExNotification = reth_exex::ExExNotification>; type Chain = reth::providers::Chain>; /// Signet context and configuration. -pub struct SignetNode> +pub struct SignetNode where Host: FullNodeComponents, Host::Types: NodeTypes,