feat: support block overrides (#3080)

This commit is contained in:
Matthias Seitz
2023-06-09 19:33:23 +02:00
committed by GitHub
parent 9924b47250
commit b414eee015
5 changed files with 99 additions and 24 deletions

View File

@ -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);

View File

@ -59,7 +59,7 @@ where
.transact_call_at(
request,
block_number.unwrap_or(BlockId::Number(BlockNumberOrTag::Latest)),
state_overrides,
state_overrides.into(),
)
.await?;

View File

@ -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>(

View File

@ -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

View File

@ -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)?;