Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions crates/block-processor/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,6 @@ signet-storage-types.workspace = true

alloy.workspace = true

reth.workspace = true

eyre.workspace = true
metrics.workspace = true
tracing.workspace = true
58 changes: 3 additions & 55 deletions crates/block-processor/src/alias.rs
Original file line number Diff line number Diff line change
@@ -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.
Expand All @@ -14,35 +7,6 @@ pub trait AliasOracle {
fn should_alias(&self, address: Address) -> eyre::Result<bool>;
}

/// 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<bool> {
// 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<Address> {
fn should_alias(&self, address: Address) -> eyre::Result<bool> {
Ok(self.contains(&address))
Expand All @@ -51,9 +15,8 @@ impl AliasOracle for HashSet<Address> {

/// Factory trait to create new [`AliasOracle`] instances.
///
/// The default implementation on `Box<dyn StateProviderFactory>` 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
Expand All @@ -67,21 +30,6 @@ pub trait AliasOracleFactory: Send + Sync + 'static {
fn create(&self) -> eyre::Result<Self::Oracle>;
}

impl AliasOracleFactory for Box<dyn StateProviderFactory> {
type Oracle = StateProviderBox;

fn create(&self) -> eyre::Result<Self::Oracle> {
// 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<Address> {
type Oracle = HashSet<Address>;
Expand Down
7 changes: 3 additions & 4 deletions crates/block-processor/src/v1/processor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand All @@ -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,
};

Expand All @@ -32,7 +31,7 @@ type HotRevmState<H> = State<RevmRead<<H as HotKv>::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<H, Alias = Box<dyn StateProviderFactory>>
pub struct SignetBlockProcessor<H, Alias>
where
H: HotKv,
{
Expand All @@ -56,7 +55,7 @@ where
blob_cacher: CacheHandle,
}

impl<H> fmt::Debug for SignetBlockProcessor<H>
impl<H, Alias> fmt::Debug for SignetBlockProcessor<H, Alias>
where
H: HotKv,
{
Expand Down
79 changes: 79 additions & 0 deletions crates/node/src/alias.rs
Original file line number Diff line number Diff line change
@@ -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<bool> {
// 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<dyn StateProviderFactory>`.
///
/// Creates [`RethAliasOracle`] instances from the latest host chain state.
pub struct RethAliasOracleFactory(Box<dyn StateProviderFactory>);

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<dyn StateProviderFactory>) -> Self {
Self(provider)
}
}

impl AliasOracleFactory for RethAliasOracleFactory {
type Oracle = RethAliasOracle;

fn create(&self) -> eyre::Result<Self::Oracle> {
// 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)
}
}
4 changes: 2 additions & 2 deletions crates/node/src/builder.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -170,7 +170,7 @@ where
self.prebuild().await?;
let ctx = self.ctx.unwrap();
let provider = ctx.provider().clone();
let alias_oracle: Box<dyn StateProviderFactory> = Box::new(provider);
let alias_oracle = RethAliasOracleFactory::new(Box::new(provider));

SignetNode::new_unsafe(
ctx,
Expand Down
3 changes: 3 additions & 0 deletions crates/node/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down
6 changes: 3 additions & 3 deletions crates/node/src/node.rs
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -29,7 +29,7 @@ type ExExNotification<Host> = reth_exex::ExExNotification<PrimitivesOf<Host>>;
type Chain<Host> = reth::providers::Chain<PrimitivesOf<Host>>;

/// Signet context and configuration.
pub struct SignetNode<Host, H, AliasOracle = Box<dyn StateProviderFactory>>
pub struct SignetNode<Host, H, AliasOracle = RethAliasOracleFactory>
where
Host: FullNodeComponents,
Host::Types: NodeTypes<Primitives = EthPrimitives>,
Expand Down