Skip to content

Commit

Permalink
Utilize block executor within debug_execution_witness
Browse files Browse the repository at this point in the history
  • Loading branch information
0x00101010 committed Sep 6, 2024
1 parent d29590b commit 0ef0198
Show file tree
Hide file tree
Showing 6 changed files with 41 additions and 127 deletions.
2 changes: 0 additions & 2 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 0 additions & 2 deletions crates/ethereum/evm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,14 +20,12 @@ reth-revm.workspace = true
reth-ethereum-consensus.workspace = true
reth-prune-types.workspace = true
reth-execution-types.workspace = true
reth-trie.workspace = true

# Ethereum
revm-primitives.workspace = true

# Alloy
alloy-eips.workspace = true
alloy-rlp.workspace = true
alloy-sol-types.workspace = true

[dev-dependencies]
Expand Down
55 changes: 10 additions & 45 deletions crates/ethereum/evm/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,17 +23,11 @@ use reth_primitives::{
BlockNumber, BlockWithSenders, EthereumHardfork, Header, Receipt, Request, U256,
};
use reth_prune_types::PruneModes;
use reth_revm::{
batch::BlockBatchRecord, db::states::bundle_state::BundleRetention,
state_change::post_block_balance_increments, Evm, State,
};
use reth_trie::{HashedPostState, HashedStorage};
use reth_revm::{batch::BlockBatchRecord, state_change::post_block_balance_increments, Evm, State};
use revm_primitives::{
db::{Database, DatabaseCommit},
BlockEnv, Bytes, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, FixedBytes, ResultAndState,
B256,
BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg, ResultAndState,
};
use revm_primitives::{keccak256, HashMap};

#[cfg(not(feature = "std"))]
use alloc::{boxed::Box, sync::Arc, vec, vec::Vec};
Expand Down Expand Up @@ -381,43 +375,14 @@ where
let EthExecuteOutput { receipts, requests, gas_used } =
self.execute_without_verification(block, total_difficulty)?;

// NOTE: we need to merge keep the reverts for the bundle retention
self.state.merge_transitions(BundleRetention::Reverts);

let mut hashed_state = HashedPostState::from_bundle_state(&self.state.bundle_state.state);
let mut state_preimages: HashMap<FixedBytes<32>, Bytes> = HashMap::new();

for (address, account) in &self.state.cache.accounts {
let hashed_address = keccak256(address);
hashed_state
.accounts
.insert(hashed_address, account.account.as_ref().map(|a| a.info.clone().into()));

let storage = hashed_state
.storages
.entry(hashed_address)
.or_insert_with(|| HashedStorage::new(account.status.was_destroyed()));

if let Some(account) = &account.account {
state_preimages.insert(hashed_address, alloy_rlp::encode(address).into());

for (slot, value) in &account.storage {
let slot = B256::from(*slot);
let hashed_slot = keccak256(slot);
storage.storage.insert(hashed_slot, *value);

state_preimages.insert(hashed_slot, alloy_rlp::encode(slot).into());
}
}
}
println!("state_preimages: {:?}", state_preimages);

// let state_provider = self.state.database.into_inner();
// let witness =
// state_provider.witness(HashedPostState::default(), hashed_state).map_err(Into::into)?;
// println!("witness: {:?}", witness);

Ok(BlockExecutionOutput { state: self.state.take_bundle(), receipts, requests, gas_used })
let cache = core::mem::take(&mut self.state.cache);
Ok(BlockExecutionOutput {
state: self.state.take_bundle(),
cache,
receipts,
requests,
gas_used,
})
}
}

Expand Down
4 changes: 3 additions & 1 deletion crates/evm/execution-types/src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use reth_primitives::{Request, U256};
use revm::db::BundleState;
use revm::{db::BundleState, CacheState};

/// A helper type for ethereum block inputs that consists of a block and the total difficulty.
#[derive(Debug)]
Expand Down Expand Up @@ -30,6 +30,8 @@ impl<'a, Block> From<(&'a Block, U256)> for BlockExecutionInput<'a, Block> {
pub struct BlockExecutionOutput<T> {
/// The changed state of the block after execution.
pub state: BundleState,
/// cache state of the block after execution.
pub cache: CacheState,
/// All the receipts of the transactions in the block.
pub receipts: Vec<T>,
/// All the EIP-7685 requests of the transactions in the block.
Expand Down
15 changes: 9 additions & 6 deletions crates/optimism/evm/src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -142,19 +142,19 @@ where
// The sum of the transaction’s gas limit, Tg, and the gas utilized in this block prior,
// must be no greater than the block’s gasLimit.
let block_available_gas = block.header.gas_limit - cumulative_gas_used;
if transaction.gas_limit() > block_available_gas &&
(is_regolith || !transaction.is_system_transaction())
if transaction.gas_limit() > block_available_gas
&& (is_regolith || !transaction.is_system_transaction())
{
return Err(BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas {
transaction_gas_limit: transaction.gas_limit(),
block_available_gas,
}
.into())
.into());
}

// An optimism block should never contain blob transactions.
if matches!(transaction.tx_type(), TxType::Eip4844) {
return Err(OptimismBlockExecutionError::BlobTransactionRejected.into())
return Err(OptimismBlockExecutionError::BlobTransactionRejected.into());
}

// Cache the depositor account prior to the state transition for the deposit nonce.
Expand Down Expand Up @@ -212,8 +212,9 @@ where
// The deposit receipt version was introduced in Canyon to indicate an update to how
// receipt hashes should be computed when set. The state transition process ensures
// this is only set for post-Canyon deposit transactions.
deposit_receipt_version: (transaction.is_deposit() &&
self.chain_spec
deposit_receipt_version: (transaction.is_deposit()
&& self
.chain_spec
.is_fork_active_at_timestamp(OptimismHardfork::Canyon, block.timestamp))
.then_some(1),
});
Expand Down Expand Up @@ -352,8 +353,10 @@ where
// NOTE: we need to merge keep the reverts for the bundle retention
self.state.merge_transitions(BundleRetention::Reverts);

let cache = core::mem::take(&mut self.state.cache);
Ok(BlockExecutionOutput {
state: self.state.take_bundle(),
cache,
receipts,
requests: vec![],
gas_used,
Expand Down
90 changes: 19 additions & 71 deletions crates/rpc/rpc/src/debug.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,7 @@ use alloy_rlp::{Decodable, Encodable};
use async_trait::async_trait;
use jsonrpsee::core::RpcResult;
use reth_chainspec::{ChainSpec, EthereumHardforks};
use reth_evm::{
execute::BlockExecutorProvider,
system_calls::{pre_block_beacon_root_contract_call, pre_block_blockhashes_contract_call},
ConfigureEvmEnv,
};
use reth_evm::{execute::BlockExecutorProvider, execute::Executor, ConfigureEvmEnv};
use reth_primitives::{
Address, Block, BlockId, BlockNumberOrTag, Bytes, TransactionSignedEcRecovered, B256, U256,
};
Expand Down Expand Up @@ -34,9 +30,8 @@ use reth_rpc_types::{
use reth_tasks::pool::BlockingTaskGuard;
use reth_trie::{HashedPostState, HashedStorage};
use revm::{
db::{states::bundle_state::BundleRetention, CacheDB},
db::CacheDB,
primitives::{db::DatabaseCommit, BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg},
StateBuilder,
};
use revm_inspectors::tracing::{
FourByteInspector, MuxInspector, TracingInspector, TracingInspectorConfig, TransactionContext,
Expand Down Expand Up @@ -578,71 +573,26 @@ where
block_id: BlockNumberOrTag,
include_preimages: bool,
) -> Result<ExecutionWitness, Eth::Error> {
let ((cfg, block_env, _), maybe_block) = futures::try_join!(
self.inner.eth_api.evm_env_at(block_id.into()),
self.inner.eth_api.block_with_senders(block_id.into()),
)?;
let block = maybe_block.ok_or(EthApiError::UnknownBlockNumber)?;
let block = self
.inner
.eth_api
.block_with_senders(block_id.into())
.await?
.ok_or(EthApiError::UnknownBlockNumber)?;

let this = self.clone();

self.inner
.eth_api
.spawn_with_state_at_block(block.parent_hash.into(), move |state| {
let evm_config = Call::evm_config(this.eth_api()).clone();
let mut db = StateBuilder::new()
.with_database(StateProviderDatabase::new(&state))
.with_bundle_update()
.build();

// let block_executor = this.inner.block_executor.executor(db);
// let block_execution_output = block_executor
// .execute((&block.clone().unseal(), block.difficulty).into())
// .map_err(|err| EthApiError::Internal(err.into()))?;
// let bundle_state = block_execution_output.state;

pre_block_beacon_root_contract_call(
&mut db,
&evm_config,
&this.inner.provider.chain_spec(),
&cfg,
&block_env,
block.parent_beacon_block_root,
)
.map_err(|err| EthApiError::Internal(err.into()))?;

// apply eip-2935 blockhashes update
pre_block_blockhashes_contract_call(
&mut db,
&evm_config,
&this.inner.provider.chain_spec(),
&cfg,
&block_env,
block.parent_hash,
)
.map_err(|err| EthApiError::Internal(err.into()))?;

// Re-execute all of the transactions in the block to load all touched accounts into
// the cache DB.
for tx in block.into_transactions_ecrecovered() {
let env = EnvWithHandlerCfg {
env: Env::boxed(
cfg.cfg_env.clone(),
block_env.clone(),
evm_config.tx_env(&tx),
),
handler_cfg: cfg.handler_cfg,
};

let (res, _) = this.inner.eth_api.transact(&mut db, env)?;
db.commit(res.state);
}

// Merge all state transitions
db.merge_transitions(BundleRetention::Reverts);
let db = StateProviderDatabase::new(&state);
let block_executor = this.inner.block_executor.executor(db);
let block_execution_output = block_executor
.execute((&block.clone().unseal(), block.difficulty).into())
.map_err(|err| EthApiError::Internal(err.into()))?;

// Take the bundle state
let bundle_state = db.take_bundle();
let bundle_state = block_execution_output.state;
let cache_state = block_execution_output.cache;

// Initialize a map of preimages.
let mut state_preimages: HashMap<revm_primitives::FixedBytes<32>, Bytes> =
Expand All @@ -653,7 +603,7 @@ where
// Note: We grab *all* accounts in the cache here, as the `BundleState` prunes
// referenced accounts + storage slots.
let mut hashed_state = HashedPostState::from_bundle_state(&bundle_state.state);
for (address, account) in db.cache.accounts {
for (address, account) in cache_state.accounts {
let hashed_address = keccak256(address);
hashed_state.accounts.insert(
hashed_address,
Expand Down Expand Up @@ -685,12 +635,11 @@ where

// Generate an execution witness for the aggregated state of accessed accounts.
// Destruct the cache database to retrieve the state provider.
// let state_provider = db.database.into_inner();
// let witness =
// state.witness(HashedPostState::default(), hashed_state).map_err(Into::into)?;
let witness =
state.witness(HashedPostState::default(), hashed_state).map_err(Into::into)?;

Ok(ExecutionWitness {
witness: HashMap::new(),
witness,
state_preimages: include_preimages.then_some(state_preimages),
})
})
Expand Down Expand Up @@ -1224,7 +1173,6 @@ struct DebugApiInner<Provider, Eth, BlockExecutor> {
/// The implementation of `eth` API
eth_api: Eth,
/// block executor for debug & trace apis
#[allow(dead_code)]
block_executor: BlockExecutor,
// restrict the number of concurrent calls to blocking calls
blocking_task_guard: BlockingTaskGuard,
Expand Down

0 comments on commit 0ef0198

Please sign in to comment.