Skip to content

Commit e5873c8

Browse files
committed
wip
1 parent ad3b860 commit e5873c8

File tree

12 files changed

+343
-101
lines changed

12 files changed

+343
-101
lines changed

crates/rpc/Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ tower-http = { version = "0.6.2", features = ["cors"] }
4141
tracing.workspace = true
4242
serde_json.workspace = true
4343
futures-util = "0.3.31"
44+
itertools.workspace = true
45+
revm-inspectors = "0.26.5"
4446

4547
[dev-dependencies]
4648
signet-zenith.workspace = true

crates/rpc/src/ctx/full.rs

Lines changed: 87 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
11
use crate::{RuRevmState, SignetCtx};
2-
use alloy::{
3-
consensus::{BlockHeader, Header},
4-
eips::BlockId,
5-
};
2+
use alloy::{consensus::Header, eips::BlockId};
63
use reth::{
74
providers::{ProviderFactory, ProviderResult},
5+
revm::Inspector,
86
rpc::server_types::eth::{EthApiError, EthConfig},
7+
rpc::types::BlockNumberOrTag,
98
tasks::{TaskExecutor, TaskSpawner},
109
};
1110
use reth_node_api::FullNodeComponents;
@@ -14,6 +13,59 @@ use signet_node_types::Pnt;
1413
use signet_tx_cache::client::TxCache;
1514
use signet_types::constants::SignetSystemConstants;
1615
use std::sync::Arc;
16+
use trevm::helpers::Ctx;
17+
18+
/// State location when instantiating an EVM instance.
19+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
20+
#[repr(i8)]
21+
pub enum LoadState {
22+
Before = -1,
23+
After = 0,
24+
}
25+
26+
impl LoadState {
27+
/// Adjust the height based on the state location.
28+
pub const fn adjust_height(&self, height: u64) -> u64 {
29+
match self {
30+
LoadState::Before => height.saturating_sub(1),
31+
LoadState::After => height,
32+
}
33+
}
34+
35+
/// Returns `true` if the state location is before the block.
36+
pub const fn is_before_block(&self) -> bool {
37+
matches!(self, Self::Before)
38+
}
39+
40+
/// Returns `true` if the state location is after the block.
41+
pub const fn is_after_block(&self) -> bool {
42+
matches!(self, Self::After)
43+
}
44+
}
45+
46+
impl From<BlockId> for LoadState {
47+
fn from(value: BlockId) -> Self {
48+
match value {
49+
BlockId::Number(no) => no.into(),
50+
_ => LoadState::After,
51+
}
52+
}
53+
}
54+
55+
impl From<BlockNumberOrTag> for LoadState {
56+
fn from(value: BlockNumberOrTag) -> Self {
57+
match value {
58+
BlockNumberOrTag::Pending => LoadState::Before,
59+
_ => LoadState::After,
60+
}
61+
}
62+
}
63+
64+
impl From<LoadState> for bool {
65+
fn from(value: LoadState) -> Self {
66+
matches!(value, LoadState::Before)
67+
}
68+
}
1769

1870
/// RPC context. Contains all necessary host and signet components for serving
1971
/// RPC requests.
@@ -114,26 +166,45 @@ where
114166
self.host.task_executor()
115167
}
116168

117-
/// Create a trevm instance.
118-
pub fn trevm(
169+
/// Instantiate a trevm instance with a custom inspector.
170+
///
171+
/// The `header` argument is used to fill the block context of the EVM. If
172+
/// the `block_id` is `Pending` the EVM state will be the block BEFORE the
173+
/// `header`. I.e. if the block number of the `header` is `n`, the state
174+
/// will be after block `n-1`, (effectively the state at the start of block
175+
/// `n`).
176+
///
177+
/// if the `block_id` is `Pending` the state will be based on the
178+
/// and `block` arguments
179+
pub fn trevm_with_inspector<I: Inspector<Ctx<RuRevmState>>>(
119180
&self,
120-
block_id: BlockId,
121-
block: &Header,
122-
) -> Result<EvmNeedsTx<RuRevmState>, EthApiError> {
123-
// decrement if the id is pending, so that the state is on the latest block
124-
let height = block.number() - block_id.is_pending() as u64;
125-
let spec_id = self.signet.evm_spec_id(block);
181+
state: LoadState,
182+
header: &Header,
183+
inspector: I,
184+
) -> Result<EvmNeedsTx<RuRevmState, I>, EthApiError> {
185+
let load_height = state.adjust_height(header.number);
186+
let spec_id = self.signet.evm_spec_id(header);
126187

127-
let db = self.signet.state_provider_database(height)?;
188+
let db = self.signet.state_provider_database(load_height)?;
128189

129-
let mut trevm = signet_evm::signet_evm(db, self.signet.constants().clone())
130-
.fill_cfg(&self.signet)
131-
.fill_block(block);
190+
let mut trevm =
191+
signet_evm::signet_evm_with_inspector(db, inspector, self.signet.constants().clone())
192+
.fill_cfg(&self.signet)
193+
.fill_block(header);
132194

133195
trevm.set_spec_id(spec_id);
134196

135197
Ok(trevm)
136198
}
199+
200+
/// Create a trevm instance.
201+
pub fn trevm(
202+
&self,
203+
state: LoadState,
204+
header: &Header,
205+
) -> Result<EvmNeedsTx<RuRevmState>, EthApiError> {
206+
self.trevm_with_inspector(state, header, trevm::revm::inspector::NoOpInspector)
207+
}
137208
}
138209

139210
// Some code in this file has been copied and modified from reth

crates/rpc/src/ctx/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ mod signet;
22
pub use signet::SignetCtx;
33

44
mod full;
5-
pub use full::RpcCtx;
5+
pub use full::{LoadState, RpcCtx};
66

77
mod fee_hist;
88
pub(crate) use fee_hist::strip_signet_system_txns;

crates/rpc/src/debug/endpoints.rs

Lines changed: 73 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,48 +1,93 @@
11
use crate::{
2-
RpcCtx, TraceError,
3-
utils::{await_jh_option_response, response_tri},
2+
DebugError, RpcCtx,
3+
utils::{await_handler, response_tri},
44
};
55
use ajj::{HandlerCtx, ResponsePayload};
6-
use alloy::eips::BlockId;
6+
use alloy::primitives::B256;
7+
use itertools::Itertools;
78
use reth::rpc::{
89
server_types::eth::EthApiError,
9-
types::trace::geth::{GethDebugTracingOptions, TraceResult},
10+
types::trace::geth::{GethDebugTracingOptions, GethTrace},
1011
};
1112
use reth_node_api::FullNodeComponents;
13+
use signet_evm::EvmErrored;
1214
use signet_node_types::Pnt;
1315

14-
/// Params for the `debug_traceBlockByNumber` and `debug_traceBlockByHash`
15-
/// endpoints.
16-
#[derive(Debug, serde::Deserialize)]
17-
pub(super) struct TraceBlockParams<T>(T, #[serde(default)] Option<GethDebugTracingOptions>);
16+
// /// Params for the `debug_traceBlockByNumber` and `debug_traceBlockByHash`
17+
// /// endpoints.
18+
// #[derive(Debug, serde::Deserialize)]
19+
// pub(super) struct TraceBlockParams<T>(T, #[serde(default)] Option<GethDebugTracingOptions>);
1820

19-
/// `debug_traceBlockByNumber` and `debug_traceBlockByHash` endpoint handler.
20-
pub(super) async fn trace_block<T, Host, Signet>(
21+
// /// `debug_traceBlockByNumber` and `debug_traceBlockByHash` endpoint handler.
22+
// pub(super) async fn trace_block<T, Host, Signet>(
23+
// hctx: HandlerCtx,
24+
// TraceBlockParams(id, opts): TraceBlockParams<T>,
25+
// ctx: RpcCtx<Host, Signet>,
26+
// ) -> ResponsePayload<Vec<TraceResult>, TraceError>
27+
// where
28+
// T: Into<BlockId>,
29+
// Host: FullNodeComponents,
30+
// Signet: Pnt,
31+
// {
32+
// let id = id.into();
33+
34+
// let fut = async move {
35+
// // Fetch the block by ID
36+
// let Some((hash, block)) = response_tri!(ctx.signet().raw_block(id).await) else {
37+
// return ResponsePayload::internal_error_message(
38+
// EthApiError::HeaderNotFound(id).to_string().into(),
39+
// );
40+
// };
41+
// // Instantiate the EVM with the block
42+
// let evm = response_tri!(ctx.trevm(id, block.header()));
43+
44+
// todo!()
45+
46+
// // ResponsePayload::Success(vec![])
47+
// };
48+
49+
// await_jh_option_response!(hctx.spawn_blocking(fut))
50+
// }
51+
52+
/// Handle for `debug_traceTransaction`.
53+
pub(super) async fn trace_transaction<Host, Signet>(
2154
hctx: HandlerCtx,
22-
TraceBlockParams(id, opts): TraceBlockParams<T>,
55+
(tx_hash, opts): (B256, Option<GethDebugTracingOptions>),
2356
ctx: RpcCtx<Host, Signet>,
24-
) -> ResponsePayload<Vec<TraceResult>, TraceError>
57+
) -> ResponsePayload<GethTrace, DebugError>
2558
where
26-
T: Into<BlockId>,
2759
Host: FullNodeComponents,
2860
Signet: Pnt,
2961
{
30-
let id = id.into();
31-
3262
let fut = async move {
33-
// Fetch the block by ID
34-
let Some((hash, block)) = response_tri!(ctx.signet().raw_block(id).await) else {
35-
return ResponsePayload::internal_error_message(
36-
EthApiError::HeaderNotFound(id).to_string().into(),
37-
);
38-
};
39-
// Instantiate the EVM with the block
40-
let evm = response_tri!(ctx.trevm(id, block.header()));
41-
42-
todo!()
43-
44-
// ResponsePayload::Success(vec![])
63+
let (tx, meta) = response_tri!(
64+
response_tri!(ctx.signet().raw_transaction_by_hash(tx_hash))
65+
.ok_or(EthApiError::TransactionNotFound)
66+
);
67+
68+
let res = response_tri!(ctx.signet().raw_block(meta.block_hash).await);
69+
let (_, block) =
70+
response_tri!(res.ok_or_else(|| EthApiError::HeaderNotFound(meta.block_hash.into())));
71+
72+
// Load trevm at the start of the block (i.e. before any transactions are applied)
73+
let mut trevm = response_tri!(
74+
ctx.trevm(crate::LoadState::Before, block.header()).map_err(EthApiError::from)
75+
);
76+
77+
let mut txns = block.body().transactions().peekable();
78+
79+
for tx in txns.by_ref().peeking_take_while(|t| t.hash() != tx.hash()) {
80+
// Apply all transactions before the target one
81+
trevm = response_tri!(trevm.run_tx(tx).map_err(EvmErrored::into_error)).accept_state();
82+
}
83+
84+
let tx = response_tri!(txns.next().ok_or(EthApiError::TransactionNotFound));
85+
let trevm = trevm.fill_tx(tx);
86+
87+
let res = response_tri!(crate::debug::tracer::trace(trevm, &opts.unwrap_or_default()));
88+
89+
ResponsePayload::Success(res)
4590
};
4691

47-
await_jh_option_response!(hctx.spawn_blocking(fut))
92+
await_handler!(@response_option hctx.spawn_blocking(fut))
4893
}

crates/rpc/src/debug/error.rs

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,42 +2,55 @@ use reth::{
22
providers::ProviderError,
33
rpc::{eth::filter::EthFilterError, server_types::eth::EthApiError},
44
};
5+
use std::borrow::Cow;
56

67
/// Errors that can occur when interacting with the `eth_` namespace.
78
#[derive(Debug, thiserror::Error, Clone)]
8-
pub enum TraceError {
9+
pub enum DebugError {
910
/// Provider error: [`ProviderError`].
1011
#[error("Provider error: {0}")]
1112
Provider(#[from] ProviderError),
1213
/// Filter error [`EthFilterError`].
1314
#[error("Filter error: {0}")]
14-
Filter(String),
15+
Filter(Cow<'static, str>),
1516
/// Eth API error: [`EthApiError`].
1617
#[error("Eth API error: {0}")]
17-
Rpc(String),
18+
Rpc(Cow<'static, str>),
1819
}
1920

20-
impl From<EthFilterError> for TraceError {
21+
impl DebugError {
22+
/// Create a new filter error.
23+
pub const fn filter_error(msg: Cow<'static, str>) -> Self {
24+
Self::Filter(msg)
25+
}
26+
27+
/// Create a new RPC error.
28+
pub const fn rpc_error(msg: Cow<'static, str>) -> Self {
29+
Self::Rpc(msg)
30+
}
31+
}
32+
33+
impl From<EthFilterError> for DebugError {
2134
fn from(err: EthFilterError) -> Self {
22-
TraceError::Filter(err.to_string())
35+
Self::filter_error(err.to_string().into())
2336
}
2437
}
2538

26-
impl From<EthApiError> for TraceError {
39+
impl From<EthApiError> for DebugError {
2740
fn from(err: EthApiError) -> Self {
28-
TraceError::Rpc(err.to_string())
41+
Self::rpc_error(err.to_string().into())
2942
}
3043
}
3144

32-
impl TraceError {
45+
impl DebugError {
3346
/// Turn into a string by value, allows for `.map_err(EthError::to_string)`
3447
/// to be used.
3548
pub fn into_string(self) -> String {
3649
ToString::to_string(&self)
3750
}
3851
}
3952

40-
impl serde::Serialize for TraceError {
53+
impl serde::Serialize for DebugError {
4154
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
4255
where
4356
S: serde::Serializer,

crates/rpc/src/debug/mod.rs

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,9 @@ mod endpoints;
22
use endpoints::*;
33

44
mod error;
5-
pub use error::TraceError;
5+
pub use error::DebugError;
6+
7+
mod tracer;
68

79
use crate::ctx::RpcCtx;
810
use alloy::primitives::{B256, U64};
@@ -16,6 +18,7 @@ where
1618
Signet: Pnt,
1719
{
1820
ajj::Router::new()
19-
.route("traceBlockByNumber", trace_block::<U64, _, _>)
20-
.route("traceBlockByHash", trace_block::<B256, _, _>)
21+
// .route("traceBlockByNumber", trace_block::<U64, _, _>)
22+
// .route("traceBlockByHash", trace_block::<B256, _, _>)
23+
.route("traceTransaction", trace_transaction)
2124
}

0 commit comments

Comments
 (0)