Skip to content

Commit

Permalink
Run Gnosis custom system calls on the payload builder (#11)
Browse files Browse the repository at this point in the history
* Run Gnosis custom system calls on the payload builder

* Fix withdrawals

* lint
  • Loading branch information
dapplion authored Sep 28, 2024
1 parent 2b1aeef commit 7e83d93
Show file tree
Hide file tree
Showing 6 changed files with 767 additions and 99 deletions.
4 changes: 4 additions & 0 deletions Cargo.lock

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

4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,10 @@ reth-chainspec = { git = "https://github.com/paradigmxyz/reth", rev = "d59939377
reth-consensus = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
reth-auto-seal-consensus = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
reth-prune-types = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
reth-basic-payload-builder = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
reth-ethereum-payload-builder = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
reth-provider = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
reth-errors = { git = "https://github.com/paradigmxyz/reth", rev = "d599393771f9d7d137ea4abf271e1bd118184c73" }
eyre = "0.6.12"
clap = { version = "4.5.6", features = ["derive"] }
alloy-sol-macro = "0.7.6"
Expand Down
117 changes: 84 additions & 33 deletions src/execute.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::ethereum::{EthEvmExecutor, EthExecuteOutput};
use crate::gnosis::{apply_block_rewards_contract_call, apply_withdrawals_contract_call};
use eyre::eyre;
use reth::primitives::Withdrawals;
use reth::providers::ExecutionOutcome;
use reth::{
api::ConfigureEvm,
Expand All @@ -20,8 +21,9 @@ use reth_evm::execute::{
BlockExecutorProvider, BlockValidationError, Executor,
};
use reth_prune_types::PruneModes;
use revm::Evm;
use std::fmt::Display;
use std::{collections::HashMap, sync::Arc};
use std::sync::Arc;

#[derive(Debug, Clone)]
pub struct GnosisExecutorProvider<EvmConfig: Clone> {
Expand Down Expand Up @@ -206,7 +208,7 @@ where
self.state.set_state_clear_flag(state_clear_flag);
}

/// Apply post execution state changes that do not require an such as: block
/// Apply post execution state changes that do not require an evm such as: block
/// rewards, withdrawals, and irregular DAO hardfork state change
// [Gnosis/fork:DIFF]
pub fn post_execution(
Expand All @@ -225,43 +227,92 @@ where
// - Call block rewards contract for bridged xDAI mint

let chain_spec = self.chain_spec_clone();
let mut cfg = CfgEnvWithHandlerCfg::new(Default::default(), Default::default());
let mut block_env = BlockEnv::default();
self.executor.evm_config.fill_cfg_and_block_env(
&mut cfg,
&mut block_env,
self.chain_spec(),
&block.header,
total_difficulty,
);

if chain_spec.is_shanghai_active_at_timestamp(block.timestamp) {
if let Some(withdrawals) = block.withdrawals.as_ref() {
let env = self.evm_env_for_block(&block.header, total_difficulty);
let mut evm = self.executor.evm_config.evm_with_env(&mut self.state, env);

apply_withdrawals_contract_call(
&chain_spec,
block.timestamp,
withdrawals,
&mut evm,
)?;
}
}

// TODO: Only post merge?
let balance_increments: HashMap<Address, u128> = {
let env = self.evm_env_for_block(&block.header, total_difficulty);
let mut evm = self.executor.evm_config.evm_with_env(&mut self.state, env);

apply_block_rewards_contract_call(
self.block_rewards_contract,
block.timestamp,
block.beneficiary,
&mut evm,
)?
};

// increment balances
self.state
.increment_balances(balance_increments)
.map_err(|_| BlockValidationError::IncrementBalanceFailed)?;
gnosis_post_block_system_calls::<EvmConfig, DB>(
&chain_spec,
&self.executor.evm_config,
&mut self.state,
&cfg,
&block_env,
self.block_rewards_contract,
block.timestamp,
block.withdrawals.as_ref(),
block.beneficiary,
)?;

Ok(())
}
}

#[allow(clippy::too_many_arguments)]
pub(crate) fn gnosis_post_block_system_calls<EvmConfig, 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>
where
EvmConfig: ConfigureEvm,
DB: Database<Error: Into<ProviderError> + 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();

// [Gnosis/fork:DIFF]: Upstream code in EthBlockExecutor computes balance changes for:
// - Pre-merge omer and block rewards
// - Beacon withdrawal mints
// - DAO hardfork drain balances
//
// For gnosis instead:
// - Do NOT credit withdrawals as native token mint
// - Call into deposit contract with withdrawal data
// - Call block rewards contract for bridged xDAI mint

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

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

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

Ok(())
}

// Trait required by BlockExecutorProvider associated type Executor
impl<EvmConfig, DB> Executor<DB> for GnosisBlockExecutor<EvmConfig, DB>
where
Expand Down
66 changes: 13 additions & 53 deletions src/gnosis.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use std::collections::HashMap;
use alloy_sol_macro::sol;
use alloy_sol_types::SolCall;
use reth::{
primitives::{address, Address, Bytes, Withdrawal, U256},
primitives::{address, Address, Withdrawal, U256},
revm::{
interpreter::Host,
primitives::{Env, ExecutionResult, Output, ResultAndState, TransactTo, TxEnv},
primitives::{ExecutionResult, Output, ResultAndState},
Database, DatabaseCommit, Evm,
},
};
use reth_chainspec::ChainSpec;
use reth_evm::execute::BlockExecutionError;
use reth_evm::{execute::BlockExecutionError, ConfigureEvm};

pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe");

Expand Down Expand Up @@ -39,14 +39,16 @@ sol!(
///
/// Ref: <https://github.com/gnosischain/specs/blob/master/execution/withdrawals.md>
#[inline]
pub fn apply_withdrawals_contract_call<EXT, DB: Database + DatabaseCommit>(
pub fn apply_withdrawals_contract_call<EvmConfig, EXT, DB>(
evm_config: &EvmConfig,
chain_spec: &ChainSpec,
_block_timestamp: u64,
withdrawals: &[Withdrawal],
evm: &mut Evm<'_, EXT, DB>,
) -> Result<(), BlockExecutionError>
where
DB: Database + DatabaseCommit,
DB::Error: std::fmt::Display,
EvmConfig: ConfigureEvm,
{
// TODO: how is the deposit contract address passed to here?
let withdrawal_contract_address = chain_spec
Expand All @@ -64,7 +66,7 @@ where
let previous_env = Box::new(evm.context.env().clone());

// modify env for pre block call
fill_tx_env_with_system_contract_call(
evm_config.fill_tx_env_system_contract_call(
&mut evm.context.evm.env,
SYSTEM_ADDRESS,
withdrawal_contract_address,
Expand Down Expand Up @@ -104,20 +106,23 @@ where
///
/// Ref: <https://github.com/gnosischain/specs/blob/master/execution/posdao-post-merge.md>
#[inline]
pub fn apply_block_rewards_contract_call<EXT, DB: Database + DatabaseCommit>(
pub fn apply_block_rewards_contract_call<EvmConfig, EXT, DB>(
evm_config: &EvmConfig,
block_rewards_contract: Address,
_block_timestamp: u64,
coinbase: Address,
evm: &mut Evm<'_, EXT, DB>,
) -> Result<HashMap<Address, u128>, BlockExecutionError>
where
DB: Database + DatabaseCommit,
DB::Error: std::fmt::Display,
EvmConfig: ConfigureEvm,
{
// get previous env
let previous_env = Box::new(evm.context.env().clone());

// modify env for pre block call
fill_tx_env_with_system_contract_call(
evm_config.fill_tx_env_system_contract_call(
&mut evm.context.evm.env,
SYSTEM_ADDRESS,
block_rewards_contract,
Expand Down Expand Up @@ -189,48 +194,3 @@ where

Ok(balance_increments)
}

/// Fill transaction environment with the system caller and the system contract address and message
/// data.
///
/// This is a system operation and therefore:
/// * the call must execute to completion
/// * the call does not count against the block’s gas limit
/// * the call does not follow the EIP-1559 burn semantics - no value should be transferred as part
/// of the call
/// * if no code exists at the provided address, the call will fail silently
fn fill_tx_env_with_system_contract_call(
env: &mut Env,
caller: Address,
contract: Address,
data: Bytes,
) {
env.tx = TxEnv {
caller,
transact_to: TransactTo::Call(contract),
// Explicitly set nonce to None so revm does not do any nonce checks
nonce: None,
gas_limit: 30_000_000,
value: U256::ZERO,
data,
// Setting the gas price to zero enforces that no value is transferred as part of the call,
// and that the call will not count against the block's gas limit
gas_price: U256::ZERO,
// The chain ID check is not relevant here and is disabled if set to None
chain_id: None,
// Setting the gas priority fee to None ensures the effective gas price is derived from the
// `gas_price` field, which we need to be zero
gas_priority_fee: None,
access_list: Vec::new(),
// blob fields can be None for this tx
blob_hashes: Vec::new(),
max_fee_per_blob_gas: None,
authorization_list: None,
};

// ensure the block gas limit is >= the tx
env.block.gas_limit = U256::from(env.tx.gas_limit);

// disable the base fee check for this call by setting the base fee to zero
env.block.basefee = U256::ZERO;
}
Loading

0 comments on commit 7e83d93

Please sign in to comment.