mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
feat: support block overrides (#3080)
This commit is contained in:
@ -1,7 +1,7 @@
|
||||
use crate::{
|
||||
eth::{
|
||||
error::{EthApiError, EthResult},
|
||||
revm_utils::{inspect, replay_transactions_until},
|
||||
revm_utils::{inspect, replay_transactions_until, EvmOverrides},
|
||||
EthTransactions, TransactionSource,
|
||||
},
|
||||
result::{internal_rpc_err, ToRpcResult},
|
||||
@ -254,9 +254,9 @@ where
|
||||
opts: GethDebugTracingCallOptions,
|
||||
) -> EthResult<GethTraceFrame> {
|
||||
let at = block_id.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest));
|
||||
// TODO(mattsse) apply block overrides
|
||||
let GethDebugTracingCallOptions { tracing_options, state_overrides, block_overrides: _ } =
|
||||
let GethDebugTracingCallOptions { tracing_options, state_overrides, block_overrides } =
|
||||
opts;
|
||||
let overrides = EvmOverrides::new(state_overrides, block_overrides);
|
||||
let GethDebugTracingOptions { config, tracer, tracer_config, .. } = tracing_options;
|
||||
|
||||
if let Some(tracer) = tracer {
|
||||
@ -274,7 +274,7 @@ where
|
||||
let (_res, _) = self
|
||||
.inner
|
||||
.eth_api
|
||||
.inspect_call_at(call, at, state_overrides, &mut inspector)
|
||||
.inspect_call_at(call, at, overrides, &mut inspector)
|
||||
.await?;
|
||||
return Ok(FourByteFrame::from(inspector).into())
|
||||
}
|
||||
@ -290,7 +290,7 @@ where
|
||||
let _ = self
|
||||
.inner
|
||||
.eth_api
|
||||
.inspect_call_at(call, at, state_overrides, &mut inspector)
|
||||
.inspect_call_at(call, at, overrides, &mut inspector)
|
||||
.await?;
|
||||
|
||||
let frame = inspector.into_geth_builder().geth_call_traces(call_config);
|
||||
@ -314,7 +314,7 @@ where
|
||||
let mut inspector = TracingInspector::new(inspector_config);
|
||||
|
||||
let (res, _) =
|
||||
self.inner.eth_api.inspect_call_at(call, at, state_overrides, &mut inspector).await?;
|
||||
self.inner.eth_api.inspect_call_at(call, at, overrides, &mut inspector).await?;
|
||||
let gas_used = res.result.gas_used();
|
||||
|
||||
let frame = inspector.into_geth_builder().geth_traces(gas_used, config);
|
||||
|
||||
@ -59,7 +59,7 @@ where
|
||||
.transact_call_at(
|
||||
request,
|
||||
block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)),
|
||||
state_overrides,
|
||||
state_overrides.into(),
|
||||
)
|
||||
.await?;
|
||||
|
||||
|
||||
@ -9,6 +9,7 @@ use crate::{
|
||||
};
|
||||
use async_trait::async_trait;
|
||||
|
||||
use crate::eth::revm_utils::EvmOverrides;
|
||||
use reth_network_api::NetworkInfo;
|
||||
use reth_primitives::{
|
||||
Address, BlockId, BlockNumberOrTag, Bytes, FromRecoveredTransaction, Header,
|
||||
@ -23,8 +24,8 @@ use reth_revm::{
|
||||
tracing::{TracingInspector, TracingInspectorConfig},
|
||||
};
|
||||
use reth_rpc_types::{
|
||||
state::StateOverride, CallRequest, Index, Log, Transaction, TransactionInfo,
|
||||
TransactionReceipt, TransactionRequest, TypedTransactionRequest,
|
||||
CallRequest, Index, Log, Transaction, TransactionInfo, TransactionReceipt, TransactionRequest,
|
||||
TypedTransactionRequest,
|
||||
};
|
||||
use reth_transaction_pool::{TransactionOrigin, TransactionPool};
|
||||
use revm::{
|
||||
@ -117,7 +118,7 @@ pub trait EthTransactions: Send + Sync {
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
f: F,
|
||||
) -> EthResult<R>
|
||||
where
|
||||
@ -128,7 +129,7 @@ pub trait EthTransactions: Send + Sync {
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
) -> EthResult<(ResultAndState, Env)>;
|
||||
|
||||
/// Executes the call request at the given [BlockId]
|
||||
@ -136,7 +137,7 @@ pub trait EthTransactions: Send + Sync {
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
inspector: I,
|
||||
) -> EthResult<(ResultAndState, Env)>
|
||||
where
|
||||
@ -431,7 +432,7 @@ where
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
f: F,
|
||||
) -> EthResult<R>
|
||||
where
|
||||
@ -441,7 +442,7 @@ where
|
||||
let state = self.state_at(at)?;
|
||||
let mut db = SubState::new(State::new(state));
|
||||
|
||||
let env = prepare_call_env(cfg, block_env, request, &mut db, state_overrides)?;
|
||||
let env = prepare_call_env(cfg, block_env, request, &mut db, overrides)?;
|
||||
f(db, env)
|
||||
}
|
||||
|
||||
@ -449,22 +450,22 @@ where
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
) -> EthResult<(ResultAndState, Env)> {
|
||||
self.with_call_at(request, at, state_overrides, |mut db, env| transact(&mut db, env)).await
|
||||
self.with_call_at(request, at, overrides, |mut db, env| transact(&mut db, env)).await
|
||||
}
|
||||
|
||||
async fn inspect_call_at<I>(
|
||||
&self,
|
||||
request: CallRequest,
|
||||
at: BlockId,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
inspector: I,
|
||||
) -> EthResult<(ResultAndState, Env)>
|
||||
where
|
||||
I: for<'r> Inspector<CacheDB<State<StateProviderBox<'r>>>> + Send,
|
||||
{
|
||||
self.with_call_at(request, at, state_overrides, |db, env| inspect(db, env, inspector)).await
|
||||
self.with_call_at(request, at, overrides, |db, env| inspect(db, env, inspector)).await
|
||||
}
|
||||
|
||||
fn trace_at<F, R>(
|
||||
|
||||
@ -7,7 +7,7 @@ use reth_primitives::{
|
||||
use reth_revm::env::{fill_tx_env, fill_tx_env_with_recovered};
|
||||
use reth_rpc_types::{
|
||||
state::{AccountOverride, StateOverride},
|
||||
CallRequest,
|
||||
BlockOverrides, CallRequest,
|
||||
};
|
||||
use revm::{
|
||||
db::CacheDB,
|
||||
@ -21,10 +21,42 @@ use revm_primitives::{
|
||||
};
|
||||
use tracing::trace;
|
||||
|
||||
/// Helper type that bundles various overrides for EVM Execution.
|
||||
///
|
||||
/// By `Default`, no overrides are included.
|
||||
#[derive(Debug, Clone, Default)]
|
||||
pub struct EvmOverrides {
|
||||
/// Applies overrides to the state before execution.
|
||||
pub state: Option<StateOverride>,
|
||||
/// Applies overrides to the block before execution.
|
||||
///
|
||||
/// This is a `Box` because less common and only available in debug trace endpoints.
|
||||
pub block: Option<Box<BlockOverrides>>,
|
||||
}
|
||||
|
||||
impl EvmOverrides {
|
||||
/// Creates a new instance with the given overrides
|
||||
pub fn new(state: Option<StateOverride>, block: Option<BlockOverrides>) -> Self {
|
||||
Self { state, block: block.map(Box::new) }
|
||||
}
|
||||
|
||||
/// Creates a new instance with the given state overrides.
|
||||
pub fn state(state: Option<StateOverride>) -> Self {
|
||||
Self { state, block: None }
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Option<StateOverride>> for EvmOverrides {
|
||||
fn from(state: Option<StateOverride>) -> Self {
|
||||
Self::state(state)
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper type to work with different transaction types when configuring the EVM env.
|
||||
///
|
||||
/// This makes it easier to handle errors.
|
||||
pub(crate) trait FillableTransaction {
|
||||
/// Returns the hash of the transaction.
|
||||
fn hash(&self) -> TxHash;
|
||||
|
||||
/// Fill the transaction environment with the given transaction.
|
||||
@ -145,7 +177,7 @@ pub(crate) fn prepare_call_env<DB>(
|
||||
block: BlockEnv,
|
||||
request: CallRequest,
|
||||
db: &mut CacheDB<DB>,
|
||||
state_overrides: Option<StateOverride>,
|
||||
overrides: EvmOverrides,
|
||||
) -> EthResult<Env>
|
||||
where
|
||||
DB: DatabaseRef,
|
||||
@ -169,10 +201,15 @@ where
|
||||
let mut env = build_call_evm_env(cfg, block, request)?;
|
||||
|
||||
// apply state overrides
|
||||
if let Some(state_overrides) = state_overrides {
|
||||
if let Some(state_overrides) = overrides.state {
|
||||
apply_state_overrides(state_overrides, db)?;
|
||||
}
|
||||
|
||||
// apply block overrides
|
||||
if let Some(block_overrides) = overrides.block {
|
||||
apply_block_overrides(*block_overrides, &mut env.block);
|
||||
}
|
||||
|
||||
if request_gas.is_none() && env.tx.gas_price > U256::ZERO {
|
||||
trace!(target: "rpc::eth::call", ?env, "Applying gas limit cap");
|
||||
// no gas limit was provided in the request, so we need to cap the request's gas limit
|
||||
@ -324,6 +361,34 @@ impl CallFees {
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given block overrides to the env
|
||||
fn apply_block_overrides(overrides: BlockOverrides, env: &mut BlockEnv) {
|
||||
let BlockOverrides { number, difficulty, time, gas_limit, coinbase, random, base_fee } =
|
||||
overrides;
|
||||
|
||||
if let Some(number) = number {
|
||||
env.number = number;
|
||||
}
|
||||
if let Some(difficulty) = difficulty {
|
||||
env.difficulty = difficulty;
|
||||
}
|
||||
if let Some(time) = time {
|
||||
env.timestamp = U256::from(time.as_u64());
|
||||
}
|
||||
if let Some(gas_limit) = gas_limit {
|
||||
env.gas_limit = U256::from(gas_limit.as_u64());
|
||||
}
|
||||
if let Some(coinbase) = coinbase {
|
||||
env.coinbase = coinbase;
|
||||
}
|
||||
if let Some(random) = random {
|
||||
env.prevrandao = Some(random);
|
||||
}
|
||||
if let Some(base_fee) = base_fee {
|
||||
env.basefee = base_fee;
|
||||
}
|
||||
}
|
||||
|
||||
/// Applies the given state overrides (a set of [AccountOverride]) to the [CacheDB].
|
||||
fn apply_state_overrides<DB>(overrides: StateOverride, db: &mut CacheDB<DB>) -> EthResult<()>
|
||||
where
|
||||
|
||||
@ -117,7 +117,11 @@ where
|
||||
let config = tracing_config(&trace_types);
|
||||
let mut inspector = TracingInspector::new(config);
|
||||
|
||||
let (res, _) = self.inner.eth_api.inspect_call_at(call, at, None, &mut inspector).await?;
|
||||
let (res, _) = self
|
||||
.inner
|
||||
.eth_api
|
||||
.inspect_call_at(call, at, Default::default(), &mut inspector)
|
||||
.await?;
|
||||
|
||||
let trace_res =
|
||||
inspector.into_parity_builder().into_trace_results(res.result, &trace_types);
|
||||
@ -172,8 +176,13 @@ where
|
||||
let mut db = SubState::new(State::new(state));
|
||||
|
||||
for (call, trace_types) in calls {
|
||||
let env =
|
||||
prepare_call_env(cfg.clone(), block_env.clone(), call, &mut db, None)?;
|
||||
let env = prepare_call_env(
|
||||
cfg.clone(),
|
||||
block_env.clone(),
|
||||
call,
|
||||
&mut db,
|
||||
Default::default(),
|
||||
)?;
|
||||
let config = tracing_config(&trace_types);
|
||||
let mut inspector = TracingInspector::new(config);
|
||||
let (res, _) = inspect(&mut db, env, &mut inspector)?;
|
||||
|
||||
Reference in New Issue
Block a user