Skip to content

Commit

Permalink
fix evm execution (#39)
Browse files Browse the repository at this point in the history
  • Loading branch information
debjit-bw authored Dec 11, 2024
1 parent d37780b commit 0d4ec11
Show file tree
Hide file tree
Showing 5 changed files with 88 additions and 53 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ path = "src/main.rs"
[dependencies]
reth = { git = "https://github.com/paradigmxyz/reth", rev = "8f61af0136e1a20119832925081c341ae89b93f0" }
reth-evm = { git = "https://github.com/paradigmxyz/reth", rev = "8f61af0136e1a20119832925081c341ae89b93f0" }
reth-revm = { git = "https://github.com/paradigmxyz/reth", rev = "8f61af0136e1a20119832925081c341ae89b93f0" }
reth-engine-primitives = { git = "https://github.com/paradigmxyz/reth", rev = "8f61af0136e1a20119832925081c341ae89b93f0" }
reth-node-ethereum = { git = "https://github.com/paradigmxyz/reth", rev = "8f61af0136e1a20119832925081c341ae89b93f0" }
reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", rev = "8f61af0136e1a20119832925081c341ae89b93f0" }
Expand Down
34 changes: 24 additions & 10 deletions src/execute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ use reth_chainspec::EthereumHardforks;
use reth_errors::ConsensusError;
use reth_ethereum_consensus::validate_block_post_execution;
use reth_evm::system_calls::OnStateHook;
use reth_evm::TxEnvOverrides;
use reth_evm::{
execute::{
BlockExecutionError, BlockExecutionStrategy, BlockExecutionStrategyFactory,
Expand All @@ -24,7 +25,7 @@ use reth_evm_ethereum::eip6110::parse_deposits_from_receipts;
use reth_node_ethereum::BasicBlockExecutorProvider;
use reth_primitives::EthPrimitives;
use reth_primitives::{BlockWithSenders, Receipt};
use revm::State;
use reth_revm::db::State;
use revm_primitives::{
db::{Database, DatabaseCommit},
BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState, U256,
Expand Down Expand Up @@ -100,6 +101,8 @@ where
system_caller: SystemCaller<EvmConfig, ChainSpec>,
/// BlockRewards contract address
block_rewards_contract: Address,
/// Optional overrides for the transactions environment.
tx_env_overrides: Option<Box<dyn TxEnvOverrides>>,
}

impl<DB, EvmConfig> GnosisExecutionStrategy<DB, EvmConfig>
Expand All @@ -123,6 +126,7 @@ where
evm_config,
system_caller,
block_rewards_contract,
tx_env_overrides: None,
}
}
}
Expand Down Expand Up @@ -155,7 +159,9 @@ where

type Primitives = EthPrimitives;

fn init(&mut self, _tx_env_overrides: Box<dyn reth_evm::TxEnvOverrides>) {}
fn init(&mut self, tx_env_overrides: Box<dyn TxEnvOverrides>) {
self.tx_env_overrides = Some(tx_env_overrides);
}

fn apply_pre_execution_changes(
&mut self,
Expand All @@ -180,7 +186,7 @@ where
&mut self,
block: &BlockWithSenders,
total_difficulty: U256,
) -> Result<ExecuteOutput, Self::Error> {
) -> Result<ExecuteOutput<Receipt>, Self::Error> {
let env = self.evm_env_for_block(&block.header, total_difficulty);
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);

Expand All @@ -203,6 +209,10 @@ where
self.evm_config
.fill_tx_env(evm.tx_mut(), transaction, *sender);

if let Some(tx_env_overrides) = &mut self.tx_env_overrides {
tx_env_overrides.apply(evm.tx_mut());
}

// Execute transaction.
let result_and_state = evm.transact().map_err(move |err| {
let new_err = err.map_db_err(|e| e.into());
Expand Down Expand Up @@ -243,24 +253,28 @@ where
fn apply_post_execution_changes(
&mut self,
block: &BlockWithSenders,
_total_difficulty: U256,
total_difficulty: U256,
receipts: &[Receipt],
) -> Result<Requests, Self::Error> {
let cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
let block_env = BlockEnv::default();
let env = self.evm_env_for_block(&block.header, total_difficulty);
let mut evm = self.evm_config.evm_with_env(&mut self.state, env);

apply_post_block_system_calls::<EvmConfig, DB>(
let balance_increments = apply_post_block_system_calls(
&self.chain_spec,
&self.evm_config,
&mut self.state,
&cfg,
&block_env,
self.block_rewards_contract,
block.timestamp,
block.body.withdrawals.as_ref(),
block.beneficiary,
&mut evm,
)?;

drop(evm);

self.state
.increment_balances(balance_increments.clone())
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;

let requests = if self
.chain_spec
.is_prague_active_at_timestamp(block.timestamp)
Expand Down
44 changes: 14 additions & 30 deletions src/gnosis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,22 +3,23 @@ use std::collections::HashMap;
use crate::errors::GnosisBlockExecutionError;
use alloy_consensus::constants::KECCAK_EMPTY;
use alloy_eips::eip4895::{Withdrawal, Withdrawals};
use alloy_primitives::{address, Address, U256};
use alloy_primitives::{address, Address};
use alloy_sol_macro::sol;
use alloy_sol_types::SolCall;
use reth::revm::{
interpreter::Host,
primitives::{ExecutionResult, Output, ResultAndState},
Database, DatabaseCommit, Evm, State,
primitives::{ExecutionResult, Output},
Evm,
};
use reth_chainspec::ChainSpec;
use reth_chainspec::EthereumHardforks;
use reth_errors::BlockValidationError;
use reth_evm::{execute::BlockExecutionError, ConfigureEvm};
use reth_provider::ProviderError;
use revm_primitives::{
Account, AccountInfo, AccountStatus, BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg,
db::{Database, DatabaseCommit},
ResultAndState, U256,
};
use revm_primitives::{Account, AccountInfo, AccountStatus};
use std::fmt::Display;

pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe");
Expand Down Expand Up @@ -249,51 +250,34 @@ where
// - Call into deposit contract with withdrawal data
// - Call block rewards contract for bridged xDAI mint
#[allow(clippy::too_many_arguments)]
pub(crate) fn apply_post_block_system_calls<EvmConfig, DB>(
pub(crate) fn apply_post_block_system_calls<EvmConfig, EXT, DB>(
chain_spec: &ChainSpec,
evm_config: &EvmConfig,
db: &mut State<DB>,
initialized_cfg: &CfgEnvWithHandlerCfg,
initialized_block_env: &BlockEnv,
block_rewards_contract: Address,
block_timestamp: u64,
withdrawals: Option<&Withdrawals>,
coinbase: Address,
) -> Result<(), BlockExecutionError>
evm: &mut Evm<'_, EXT, DB>,
) -> Result<HashMap<alloy_primitives::Address, u128>, BlockExecutionError>
where
EvmConfig: ConfigureEvm,
DB: Database<Error: Into<ProviderError> + Display>,
DB: Database + DatabaseCommit,
DB::Error: Display,
{
let mut evm = Evm::builder()
.with_db(db)
.with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
Default::default(),
))
.build();

if chain_spec.is_shanghai_active_at_timestamp(block_timestamp) {
let withdrawals = withdrawals.ok_or(GnosisBlockExecutionError::CustomErrorMessage {
message: "block has no withdrawals field".to_owned(),
})?;
apply_withdrawals_contract_call(evm_config, chain_spec, withdrawals, &mut evm)?;
apply_withdrawals_contract_call(evm_config, chain_spec, withdrawals, evm)?;
}

let balance_increments = apply_block_rewards_contract_call(
evm_config,
block_rewards_contract,
block_timestamp,
coinbase,
&mut evm,
evm,
)?;

// increment balances
evm.context
.evm
.db
.increment_balances(balance_increments)
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;

Ok(())
Ok(balance_increments)
}
61 changes: 48 additions & 13 deletions src/payload_builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,10 @@ use reth_provider::{
CanonStateSubscriptions, ChainSpecProvider, ExecutionOutcome, StateProviderFactory,
};
use reth_trie::HashedPostState;
use revm::{db::states::bundle_state::BundleRetention, DatabaseCommit, State};
use revm::{
db::{states::bundle_state::BundleRetention, State},
Database, DatabaseCommit, Evm,
};
use revm_primitives::{
calc_excess_blob_gas, Address, BlockEnv, CfgEnvWithHandlerCfg, EVMError, EnvWithHandlerCfg,
InvalidTransaction, ResultAndState, U256,
Expand All @@ -50,6 +53,24 @@ type BestTransactionsIter<Pool> = Box<
dyn BestTransactions<Item = Arc<ValidPoolTransaction<<Pool as TransactionPool>::Transaction>>>,
>;

fn initialize_evm<'a, DB>(
db: &'a mut DB,
initialized_cfg: &'a CfgEnvWithHandlerCfg,
initialized_block_env: &'a BlockEnv,
) -> Evm<'a, (), &'a mut DB>
where
DB: Database,
{
Evm::builder()
.with_db(db)
.with_env_with_handler_cfg(EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
Default::default(),
))
.build()
}

/// A basic Gnosis payload service builder
#[derive(Debug, Default, Clone)]
pub struct GnosisPayloadServiceBuilder {
Expand Down Expand Up @@ -325,6 +346,8 @@ where
PayloadBuilderError::Internal(err.into())
})?;

let mut evm = initialize_evm(&mut db, &initialized_cfg, &initialized_block_env);

let mut receipts = Vec::new();
while let Some(pool_tx) = best_txs.next() {
// ensure we still have capacity for this transaction
Expand Down Expand Up @@ -368,14 +391,8 @@ where
}
}

let env = EnvWithHandlerCfg::new_with_cfg_env(
initialized_cfg.clone(),
initialized_block_env.clone(),
evm_config.tx_env(tx.as_signed(), tx.signer()),
);

// Configure the environment for the block.
let mut evm = evm_config.evm_with_env(&mut db, env);
// Configure the environment for the tx.
*evm.tx_mut() = evm_config.tx_env(tx.as_signed(), tx.signer());

let ResultAndState { result, state } = match evm.transact() {
Ok(res) => res,
Expand Down Expand Up @@ -446,6 +463,9 @@ where
executed_txs.push(tx.into_signed());
}

// Release db
drop(evm);

// check if we have a better block
if !is_better_payload(best_payload.as_ref(), total_fees) {
// can skip building the block
Expand All @@ -455,21 +475,36 @@ where
});
}

let mut evm = initialize_evm(&mut db, &initialized_cfg, &initialized_block_env);

// < GNOSIS SPECIFIC
apply_post_block_system_calls(
let balance_increments = apply_post_block_system_calls(
&chain_spec,
&evm_config,
&mut db,
&initialized_cfg,
&initialized_block_env,
block_rewards_contract,
attributes.timestamp,
Some(&attributes.withdrawals),
attributes.suggested_fee_recipient,
&mut evm,
)
.map_err(|err| PayloadBuilderError::Internal(err.into()))?;
// GNOSIS SPECIFIC >

evm.context
.evm
.db
.increment_balances(balance_increments)
.map_err(|err| {
warn!(target: "payload_builder",
parent_hash=%parent_header.hash(),
%err,
"failed to increment balances for payload"
);
PayloadBuilderError::Internal(err.into())
})?;

drop(evm);

// calculate the requests and the requests root
let requests = if chain_spec.is_prague_active_at_timestamp(attributes.timestamp) {
let deposit_requests = parse_deposits_from_receipts(&chain_spec, receipts.iter().flatten())
Expand Down

0 comments on commit 0d4ec11

Please sign in to comment.