feat: relax bounds for eth_simulateV1 (#13232)

This commit is contained in:
Arsenii Kulikov
2024-12-09 23:08:49 +04:00
committed by GitHub
parent 3af2afe995
commit c7c84f2d3f
16 changed files with 172 additions and 200 deletions

View File

@ -26,7 +26,6 @@ reth-rpc-types-compat.workspace = true
reth-tasks = { workspace = true, features = ["rayon"] }
reth-transaction-pool.workspace = true
reth-chainspec.workspace = true
reth-execution-types.workspace = true
reth-rpc-eth-types.workspace = true
reth-rpc-server-types.workspace = true
reth-network-api.workspace = true

View File

@ -13,7 +13,6 @@ use alloy_rpc_types_eth::{
};
use alloy_serde::JsonStorageKey;
use jsonrpsee::{core::RpcResult, proc_macros::rpc};
use reth_provider::BlockReader;
use reth_rpc_server_types::{result::internal_rpc_err, ToRpcResult};
use tracing::trace;
@ -372,12 +371,7 @@ impl<T>
RpcHeader<T::NetworkTypes>,
> for T
where
T: FullEthApi<
Provider: BlockReader<
Header = alloy_consensus::Header,
Transaction = reth_primitives::TransactionSigned,
>,
>,
T: FullEthApi,
jsonrpsee_types::error::ErrorObject<'static>: From<T::Error>,
{
/// Handler for: `eth_protocolVersion`

View File

@ -20,9 +20,7 @@ use reth_chainspec::EthChainSpec;
use reth_evm::{ConfigureEvm, ConfigureEvmEnv};
use reth_node_api::BlockBody;
use reth_primitives_traits::SignedTransaction;
use reth_provider::{
BlockIdReader, BlockReader, ChainSpecProvider, HeaderProvider, ProviderHeader,
};
use reth_provider::{BlockIdReader, ChainSpecProvider, HeaderProvider, ProviderHeader};
use reth_revm::{
database::StateProviderDatabase,
db::CacheDB,
@ -50,7 +48,7 @@ pub type SimulatedBlocksResult<N, E> = Result<Vec<SimulatedBlock<RpcBlock<N>>>,
/// Execution related functions for the [`EthApiServer`](crate::EthApiServer) trait in
/// the `eth_` namespace.
pub trait EthCall: EstimateCall + Call + LoadPendingBlock {
pub trait EthCall: EstimateCall + Call + LoadPendingBlock + LoadBlock + FullEthApiTypes {
/// Estimate gas needed for execution of the `request` at the [`BlockId`].
fn estimate_gas_at(
&self,
@ -70,15 +68,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock {
&self,
payload: SimulatePayload,
block: Option<BlockId>,
) -> impl Future<Output = SimulatedBlocksResult<Self::NetworkTypes, Self::Error>> + Send
where
Self: LoadBlock<
Provider: BlockReader<
Header = alloy_consensus::Header,
Transaction = reth_primitives::TransactionSigned,
>,
> + FullEthApiTypes,
{
) -> impl Future<Output = SimulatedBlocksResult<Self::NetworkTypes, Self::Error>> + Send {
async move {
if payload.block_state_calls.len() > self.max_simulate_blocks() as usize {
return Err(EthApiError::InvalidParams("too many blocks.".to_string()).into())
@ -171,9 +161,11 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock {
block_env.gas_limit.to(),
cfg.chain_id,
&mut db,
this.tx_resp_builder(),
)?;
let mut calls = calls.into_iter().peekable();
let mut senders = Vec::with_capacity(transactions.len());
let mut results = Vec::with_capacity(calls.len());
while let Some(tx) = calls.next() {
@ -197,18 +189,27 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock {
db.commit(res.state);
}
results.push((env.tx.caller, res.result));
senders.push(env.tx.caller);
results.push(res.result);
}
let (block, _) = this.assemble_block_and_receipts(
&block_env,
parent_hash,
// state root calculation is skipped for performance reasons
B256::ZERO,
transactions,
results.clone(),
);
let block: SimulatedBlock<RpcBlock<Self::NetworkTypes>> =
simulate::build_block(
simulate::build_simulated_block(
senders,
results,
transactions,
&block_env,
parent_hash,
total_difficulty,
return_full_transactions,
this.tx_resp_builder(),
block,
)?;
parent_hash = block.inner.header.hash;
@ -245,10 +246,7 @@ pub trait EthCall: EstimateCall + Call + LoadPendingBlock {
bundle: Bundle,
state_context: Option<StateContext>,
mut state_override: Option<StateOverride>,
) -> impl Future<Output = Result<Vec<EthCallResponse>, Self::Error>> + Send
where
Self: LoadBlock,
{
) -> impl Future<Output = Result<Vec<EthCallResponse>, Self::Error>> + Send {
async move {
let Bundle { transactions, block_override } = bundle;
if transactions.is_empty() {
@ -608,7 +606,7 @@ pub trait Call:
f: F,
) -> impl Future<Output = Result<Option<R>, Self::Error>> + Send
where
Self: LoadBlock + LoadPendingBlock + LoadTransaction,
Self: LoadBlock + LoadTransaction,
F: FnOnce(TransactionInfo, ResultAndState, StateCacheDb<'_>) -> Result<R, Self::Error>
+ Send
+ 'static,

View File

@ -42,12 +42,9 @@ pub use transaction::{EthTransactions, LoadTransaction};
use crate::FullEthApiTypes;
/// Extension trait that bundles traits needed for tracing transactions.
pub trait TraceExt:
LoadTransaction + LoadBlock + LoadPendingBlock + SpawnBlocking + Trace + Call
{
}
pub trait TraceExt: LoadTransaction + LoadBlock + SpawnBlocking + Trace + Call {}
impl<T> TraceExt for T where T: LoadTransaction + LoadBlock + LoadPendingBlock + Trace + Call {}
impl<T> TraceExt for T where T: LoadTransaction + LoadBlock + Trace + Call {}
/// Helper trait to unify all `eth` rpc server building block traits, for simplicity.
///

View File

@ -15,8 +15,7 @@ use reth_evm::{
state_change::post_block_withdrawals_balance_increments, system_calls::SystemCaller,
ConfigureEvm, ConfigureEvmEnv, NextBlockEnvAttributes,
};
use reth_execution_types::ExecutionOutcome;
use reth_primitives::{BlockExt, InvalidTransactionError, RecoveredTx, SealedBlockWithSenders};
use reth_primitives::{BlockExt, InvalidTransactionError, SealedBlockWithSenders};
use reth_primitives_traits::receipt::ReceiptExt;
use reth_provider::{
BlockReader, BlockReaderIdExt, ChainSpecProvider, EvmEnvProvider, ProviderBlock, ProviderError,
@ -199,7 +198,7 @@ pub trait LoadPendingBlock:
/// Assembles a receipt for a transaction, based on its [`ExecutionResult`].
fn assemble_receipt(
&self,
tx: &RecoveredTx<ProviderTx<Self::Provider>>,
tx: &ProviderTx<Self::Provider>,
result: ExecutionResult,
cumulative_gas_used: u64,
) -> ProviderReceipt<Self::Provider>;
@ -207,14 +206,36 @@ pub trait LoadPendingBlock:
/// Assembles a pending block.
fn assemble_block(
&self,
cfg: CfgEnvWithHandlerCfg,
block_env: BlockEnv,
block_env: &BlockEnv,
parent_hash: revm_primitives::B256,
state_root: revm_primitives::B256,
transactions: Vec<ProviderTx<Self::Provider>>,
receipts: &[ProviderReceipt<Self::Provider>],
) -> ProviderBlock<Self::Provider>;
/// Helper to invoke both [`Self::assemble_block`] and [`Self::assemble_receipt`].
fn assemble_block_and_receipts(
&self,
block_env: &BlockEnv,
parent_hash: revm_primitives::B256,
state_root: revm_primitives::B256,
transactions: Vec<ProviderTx<Self::Provider>>,
results: Vec<ExecutionResult>,
) -> (ProviderBlock<Self::Provider>, Vec<ProviderReceipt<Self::Provider>>) {
let mut cumulative_gas_used = 0;
let mut receipts = Vec::with_capacity(results.len());
for (tx, outcome) in transactions.iter().zip(results) {
cumulative_gas_used += outcome.gas_used();
receipts.push(self.assemble_receipt(tx, outcome, cumulative_gas_used));
}
let block =
self.assemble_block(block_env, parent_hash, state_root, transactions, &receipts);
(block, receipts)
}
/// Builds a pending block using the configured provider and pool.
///
/// If the origin is the actual pending block, the block is built with withdrawals.
@ -248,7 +269,6 @@ pub trait LoadPendingBlock:
let mut sum_blob_gas_used = 0;
let block_gas_limit: u64 = block_env.gas_limit.to::<u64>();
let base_fee = block_env.basefee.to::<u64>();
let block_number = block_env.number.to::<u64>();
let mut executed_txs = Vec::new();
let mut senders = Vec::new();
@ -266,7 +286,7 @@ pub trait LoadPendingBlock:
.pre_block_blockhashes_contract_call(&mut db, &cfg, &block_env, parent_hash)
.map_err(|err| EthApiError::Internal(err.into()))?;
let mut receipts = Vec::new();
let mut results = Vec::new();
while let Some(pool_tx) = best_txs.next() {
// ensure we still have capacity for this transaction
@ -374,13 +394,11 @@ pub trait LoadPendingBlock:
// add gas used by the transaction to cumulative gas used, before creating the receipt
cumulative_gas_used += gas_used;
// Push transaction changeset and calculate header bloom filter for receipt.
receipts.push(Some(self.assemble_receipt(&tx, result, cumulative_gas_used)));
// append transaction to the list of executed transactions
let (tx, sender) = tx.to_components();
executed_txs.push(tx);
senders.push(sender);
results.push(result);
}
// executes the withdrawals and commits them to the Database and BundleState.
@ -396,22 +414,19 @@ pub trait LoadPendingBlock:
// merge all transitions into bundle state.
db.merge_transitions(BundleRetention::PlainState);
let execution_outcome: ExecutionOutcome<ProviderReceipt<Self::Provider>> =
ExecutionOutcome::new(
db.take_bundle(),
vec![receipts.clone()].into(),
block_number,
Vec::new(),
);
let hashed_state = db.database.hashed_post_state(execution_outcome.state());
let bundle_state = db.take_bundle();
let hashed_state = db.database.hashed_post_state(&bundle_state);
// calculate the state root
let state_root = db.database.state_root(hashed_state).map_err(Self::Error::from_eth_err)?;
// Convert Vec<Option<Receipt>> to Vec<Receipt>
let receipts: Vec<_> = receipts.into_iter().flatten().collect();
let block =
self.assemble_block(cfg, block_env, parent_hash, state_root, executed_txs, &receipts);
let (block, receipts) = self.assemble_block_and_receipts(
&block_env,
parent_hash,
state_root,
executed_txs,
results,
);
Ok((SealedBlockWithSenders { block: block.seal_slow(), senders }, receipts))
}

View File

@ -25,9 +25,7 @@ use reth_rpc_types_compat::transaction::{from_recovered, from_recovered_with_blo
use reth_transaction_pool::{PoolTransaction, TransactionOrigin, TransactionPool};
use std::sync::Arc;
use super::{
EthApiSpec, EthSigner, LoadBlock, LoadPendingBlock, LoadReceipt, LoadState, SpawnBlocking,
};
use super::{EthApiSpec, EthSigner, LoadBlock, LoadReceipt, LoadState, SpawnBlocking};
use crate::{
helpers::estimate::EstimateCall, FromEthApiError, FullEthApiTypes, IntoEthApiError,
RpcNodeCore, RpcNodeCoreExt, RpcReceipt, RpcTransaction,
@ -365,7 +363,7 @@ pub trait EthTransactions: LoadTransaction<Provider: BlockReaderIdExt> {
mut request: TransactionRequest,
) -> impl Future<Output = Result<B256, Self::Error>> + Send
where
Self: EthApiSpec + LoadBlock + LoadPendingBlock + EstimateCall,
Self: EthApiSpec + LoadBlock + EstimateCall,
{
async move {
let from = match request.from {