Skip to content

Commit 0b9609c

Browse files
prestwichclaude
andauthored
refactor: remove reth dependency from signet-block-processor (#93)
Move reth-specific AliasOracle/AliasOracleFactory impls into signet-node as RethAliasOracle/RethAliasOracleFactory newtypes, decoupling the block processor from the node runtime. Replace reth::revm::db::StateBuilder with trevm::revm::database::StateBuilder. ENG-1918 Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent a2e43de commit 0b9609c

7 files changed

Lines changed: 93 additions & 66 deletions

File tree

crates/block-processor/Cargo.toml

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,6 @@ signet-storage-types.workspace = true
2525

2626
alloy.workspace = true
2727

28-
reth.workspace = true
29-
3028
eyre.workspace = true
3129
metrics.workspace = true
3230
tracing.workspace = true

crates/block-processor/src/alias.rs

Lines changed: 3 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,4 @@
1-
use alloy::{
2-
consensus::constants::KECCAK_EMPTY,
3-
primitives::{Address, map::HashSet},
4-
};
5-
use eyre::OptionExt;
6-
#[cfg(doc)]
7-
use reth::providers::StateProvider;
8-
use reth::providers::{StateProviderBox, StateProviderFactory};
1+
use alloy::primitives::{Address, map::HashSet};
92
use std::sync::{Arc, Mutex};
103

114
/// Simple trait to allow checking if an address should be aliased.
@@ -14,35 +7,6 @@ pub trait AliasOracle {
147
fn should_alias(&self, address: Address) -> eyre::Result<bool>;
158
}
169

17-
/// Default implementation of [`AliasOracle`] for any type implementing
18-
/// [`StateProvider`]. This implementation checks if the address has bytecode
19-
/// associated with it, and if so, whether that bytecode matches the pattern
20-
/// for a 7702 delegation contract. If it is a delegation contract, it is not
21-
/// aliased; otherwise, it is aliased.
22-
impl AliasOracle for StateProviderBox {
23-
fn should_alias(&self, address: Address) -> eyre::Result<bool> {
24-
// No account at this address.
25-
let Some(acct) = self.basic_account(&address)? else { return Ok(false) };
26-
// Get the bytecode hash for this account.
27-
let bch = match acct.bytecode_hash {
28-
Some(hash) => hash,
29-
// No bytecode hash; not a contract.
30-
None => return Ok(false),
31-
};
32-
// No code at this address.
33-
if bch == KECCAK_EMPTY {
34-
return Ok(false);
35-
}
36-
// Fetch the code associated with this bytecode hash.
37-
let code = self
38-
.bytecode_by_hash(&bch)?
39-
.ok_or_eyre("code not found. This indicates a corrupted database")?;
40-
41-
// If not a 7702 delegation contract, alias it.
42-
Ok(!code.is_eip7702())
43-
}
44-
}
45-
4610
impl AliasOracle for HashSet<Address> {
4711
fn should_alias(&self, address: Address) -> eyre::Result<bool> {
4812
Ok(self.contains(&address))
@@ -51,9 +15,8 @@ impl AliasOracle for HashSet<Address> {
5115

5216
/// Factory trait to create new [`AliasOracle`] instances.
5317
///
54-
/// The default implementation on `Box<dyn StateProviderFactory>` creates
55-
/// [`AliasOracle`] instances backed by the state provider for a given block
56-
/// height. It will error if that state provider cannot be obtained.
18+
/// See `signet-node` for the reth-backed implementation that creates
19+
/// [`AliasOracle`] instances backed by the host chain state provider.
5720
///
5821
/// This trait is primarily intended to allow injecting test implementations
5922
/// of [`AliasOracle`] into the Signet Node for testing purposes. The test
@@ -67,21 +30,6 @@ pub trait AliasOracleFactory: Send + Sync + 'static {
6730
fn create(&self) -> eyre::Result<Self::Oracle>;
6831
}
6932

70-
impl AliasOracleFactory for Box<dyn StateProviderFactory> {
71-
type Oracle = StateProviderBox;
72-
73-
fn create(&self) -> eyre::Result<Self::Oracle> {
74-
// NB: This becomes a problem if anyone ever birthday attacks a
75-
// contract/EOA pair (c.f. EIP-3607). In practice this is unlikely to
76-
// happen for the foreseeable future, and if it does we can revisit
77-
// this decision.
78-
// We considered taking the host height as an argument to this method,
79-
// but this would require all nodes to be archive nodes in order to
80-
// sync, which is less than ideal
81-
self.state_by_block_number_or_tag(alloy::eips::BlockNumberOrTag::Latest).map_err(Into::into)
82-
}
83-
}
84-
8533
/// This implementation is primarily for testing purposes.
8634
impl AliasOracleFactory for HashSet<Address> {
8735
type Oracle = HashSet<Address>;

crates/block-processor/src/v1/processor.rs

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use alloy::{
66
use core::fmt;
77
use eyre::{ContextCompat, WrapErr};
88
use init4_bin_base::utils::calc::SlotCalculator;
9-
use reth::{providers::StateProviderFactory, revm::db::StateBuilder};
109
use signet_blobber::{CacheHandle, ExtractableChainShim};
1110
use signet_constants::SignetSystemConstants;
1211
use signet_evm::{BlockResult, EthereumHardfork, EvmNeedsCfg, SignetDriver};
@@ -19,7 +18,7 @@ use signet_storage_types::{DbSignetEvent, DbZenithHeader, ExecutedBlock, Execute
1918
use std::collections::VecDeque;
2019
use tracing::{error, instrument};
2120
use trevm::revm::{
22-
database::{DBErrorMarker, State},
21+
database::{DBErrorMarker, State, StateBuilder},
2322
primitives::hardfork::SpecId,
2423
};
2524

@@ -32,7 +31,7 @@ type HotRevmState<H> = State<RevmRead<<H as HotKv>::RoTx>>;
3231
/// The processor is a stateless executor: it reads state from hot storage,
3332
/// runs the EVM, and returns an [`ExecutedBlock`]. The caller (node) handles
3433
/// extraction, persistence, and orchestrates the per-block loop.
35-
pub struct SignetBlockProcessor<H, Alias = Box<dyn StateProviderFactory>>
34+
pub struct SignetBlockProcessor<H, Alias>
3635
where
3736
H: HotKv,
3837
{
@@ -56,7 +55,7 @@ where
5655
blob_cacher: CacheHandle,
5756
}
5857

59-
impl<H> fmt::Debug for SignetBlockProcessor<H>
58+
impl<H, Alias> fmt::Debug for SignetBlockProcessor<H, Alias>
6059
where
6160
H: HotKv,
6261
{

crates/node/src/alias.rs

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
use alloy::{consensus::constants::KECCAK_EMPTY, primitives::Address};
2+
use core::fmt;
3+
use eyre::OptionExt;
4+
use reth::providers::{StateProviderBox, StateProviderFactory};
5+
use signet_block_processor::{AliasOracle, AliasOracleFactory};
6+
7+
/// An [`AliasOracle`] backed by a reth [`StateProviderBox`].
8+
///
9+
/// Checks whether an address has non-delegation bytecode, indicating it
10+
/// should be aliased during transaction processing.
11+
pub struct RethAliasOracle(StateProviderBox);
12+
13+
impl fmt::Debug for RethAliasOracle {
14+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
15+
f.debug_struct("RethAliasOracle").finish_non_exhaustive()
16+
}
17+
}
18+
19+
impl AliasOracle for RethAliasOracle {
20+
fn should_alias(&self, address: Address) -> eyre::Result<bool> {
21+
// No account at this address.
22+
let Some(acct) = self.0.basic_account(&address)? else { return Ok(false) };
23+
// Get the bytecode hash for this account.
24+
let bch = match acct.bytecode_hash {
25+
Some(hash) => hash,
26+
// No bytecode hash; not a contract.
27+
None => return Ok(false),
28+
};
29+
// No code at this address.
30+
if bch == KECCAK_EMPTY {
31+
return Ok(false);
32+
}
33+
// Fetch the code associated with this bytecode hash.
34+
let code = self
35+
.0
36+
.bytecode_by_hash(&bch)?
37+
.ok_or_eyre("code not found. This indicates a corrupted database")?;
38+
39+
// If not a 7702 delegation contract, alias it.
40+
Ok(!code.is_eip7702())
41+
}
42+
}
43+
44+
/// An [`AliasOracleFactory`] backed by a `Box<dyn StateProviderFactory>`.
45+
///
46+
/// Creates [`RethAliasOracle`] instances from the latest host chain state.
47+
pub struct RethAliasOracleFactory(Box<dyn StateProviderFactory>);
48+
49+
impl fmt::Debug for RethAliasOracleFactory {
50+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
51+
f.debug_struct("RethAliasOracleFactory").finish_non_exhaustive()
52+
}
53+
}
54+
55+
impl RethAliasOracleFactory {
56+
/// Create a new [`RethAliasOracleFactory`] from a boxed state provider
57+
/// factory.
58+
pub fn new(provider: Box<dyn StateProviderFactory>) -> Self {
59+
Self(provider)
60+
}
61+
}
62+
63+
impl AliasOracleFactory for RethAliasOracleFactory {
64+
type Oracle = RethAliasOracle;
65+
66+
fn create(&self) -> eyre::Result<Self::Oracle> {
67+
// NB: This becomes a problem if anyone ever birthday attacks a
68+
// contract/EOA pair (c.f. EIP-3607). In practice this is unlikely to
69+
// happen for the foreseeable future, and if it does we can revisit
70+
// this decision.
71+
// We considered taking the host height as an argument to this method,
72+
// but this would require all nodes to be archive nodes in order to
73+
// sync, which is less than ideal
74+
self.0
75+
.state_by_block_number_or_tag(alloy::eips::BlockNumberOrTag::Latest)
76+
.map(RethAliasOracle)
77+
.map_err(Into::into)
78+
}
79+
}

crates/node/src/builder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
#![allow(clippy::type_complexity)]
22

3-
use crate::{NodeStatus, SignetNode};
3+
use crate::{NodeStatus, RethAliasOracleFactory, SignetNode};
44
use eyre::OptionExt;
55
use reth::{primitives::EthPrimitives, providers::StateProviderFactory};
66
use reth_exex::ExExContext;
@@ -170,7 +170,7 @@ where
170170
self.prebuild().await?;
171171
let ctx = self.ctx.unwrap();
172172
let provider = ctx.provider().clone();
173-
let alias_oracle: Box<dyn StateProviderFactory> = Box::new(provider);
173+
let alias_oracle = RethAliasOracleFactory::new(Box::new(provider));
174174

175175
SignetNode::new_unsafe(
176176
ctx,

crates/node/src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@
1111
#![deny(unused_must_use, rust_2018_idioms)]
1212
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
1313

14+
mod alias;
15+
pub use alias::{RethAliasOracle, RethAliasOracleFactory};
16+
1417
mod builder;
1518
pub use builder::SignetNodeBuilder;
1619

crates/node/src/node.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
use crate::{NodeStatus, metrics};
1+
use crate::{NodeStatus, RethAliasOracleFactory, metrics};
22
use alloy::consensus::BlockHeader;
33
use eyre::Context;
44
use futures_util::StreamExt;
55
use reth::{
66
chainspec::EthChainSpec,
77
primitives::EthPrimitives,
8-
providers::{BlockIdReader, BlockReader, HeaderProvider, StateProviderFactory},
8+
providers::{BlockIdReader, BlockReader, HeaderProvider},
99
};
1010
use reth_exex::{ExExContext, ExExEvent, ExExHead, ExExNotificationsStream};
1111
use reth_node_api::{FullNodeComponents, FullNodeTypes, NodeTypes};
@@ -29,7 +29,7 @@ type ExExNotification<Host> = reth_exex::ExExNotification<PrimitivesOf<Host>>;
2929
type Chain<Host> = reth::providers::Chain<PrimitivesOf<Host>>;
3030

3131
/// Signet context and configuration.
32-
pub struct SignetNode<Host, H, AliasOracle = Box<dyn StateProviderFactory>>
32+
pub struct SignetNode<Host, H, AliasOracle = RethAliasOracleFactory>
3333
where
3434
Host: FullNodeComponents,
3535
Host::Types: NodeTypes<Primitives = EthPrimitives>,

0 commit comments

Comments
 (0)