diff --git a/Cargo.lock b/Cargo.lock index 14c64b6..d4d5ea8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -198,9 +198,9 @@ dependencies = [ [[package]] name = "alloy-primitives" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5277af0cbcc483ee6ad2c1e818090b5928d27f04fd6580680f31c1cf8068bcc2" +checksum = "f783611babedbbe90db3478c120fb5f5daacceffc210b39adc0af4fe0da70bad" dependencies = [ "alloy-rlp", "arbitrary", @@ -329,9 +329,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30708a79919b082f2692423c8cc72fc250477e4a2ecb0d4a7244cd3cdb299965" +checksum = "4bad41a7c19498e3f6079f7744656328699f8ea3e783bdd10d85788cd439f572" dependencies = [ "alloy-sol-macro-expander", "alloy-sol-macro-input", @@ -343,9 +343,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-expander" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1c7a679ac01774ab7e00a567a918d4231ae692c5c8cedaf4e16956c3116d7896" +checksum = "fd9899da7d011b4fe4c406a524ed3e3f963797dbc93b45479d60341d3a27b252" dependencies = [ "alloy-sol-macro-input", "const-hex", @@ -361,9 +361,9 @@ dependencies = [ [[package]] name = "alloy-sol-macro-input" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "356da0c2228aa6675a5faaa08a3e4061b967f924753983d72b9a18d9a3fad44e" +checksum = "d32d595768fdc61331a132b6f65db41afae41b9b97d36c21eb1b955c422a7e60" dependencies = [ "const-hex", "dunce", @@ -385,9 +385,9 @@ dependencies = [ [[package]] name = "alloy-sol-types" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6eb5e6234c0b62514992589fe1578f64d418dbc8ef5cd1ab2d7f2f568f599698" +checksum = "a49042c6d3b66a9fe6b2b5a8bf0d39fc2ae1ee0310a2a26ffedd79fb097878dd" dependencies = [ "alloy-primitives", "alloy-sol-macro", @@ -6485,6 +6485,8 @@ dependencies = [ name = "reth_gnosis" version = "0.1.0" dependencies = [ + "alloy-sol-macro", + "alloy-sol-types", "clap", "eyre", "libc", @@ -7489,9 +7491,9 @@ dependencies = [ [[package]] name = "syn-solidity" -version = "0.7.5" +version = "0.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6fe08d08d84f2c0a77f1e7c46518789d745c2e87a2721791ed7c3c9bc78df28" +checksum = "8d71e19bca02c807c9faa67b5a47673ff231b6e7449b251695188522f1dc44b2" dependencies = [ "paste", "proc-macro2", diff --git a/Cargo.toml b/Cargo.toml index f622320..6a5302e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ reth-evm-ethereum = { git = "https://github.com/paradigmxyz/reth", rev = "7b435e reth-ethereum-consensus = { git = "https://github.com/paradigmxyz/reth", rev = "7b435e0d6dede497dca211090d95a4cfa387dd1b" } eyre = "0.6.12" clap = { version = "4.5.6", features = ["derive"] } +alloy-sol-macro = "0.7.6" +alloy-sol-types = "0.7.6" [target.'cfg(unix)'.dependencies] tikv-jemallocator = { version = "0.5.0", optional = true } diff --git a/README.md b/README.md new file mode 100644 index 0000000..0c459c3 --- /dev/null +++ b/README.md @@ -0,0 +1,13 @@ +# Reth @ Gnosis 🍴 + +Gnosis compatible Reth client. Not a fork, but an extension with the `NodeBuilder` API. + +Refer to the Reth's documentation to run a node: https://reth.rs/ + +## Implementation progress + +- [ ] Pre-merge POSDAO / AuRa +- [ ] [EIP-1559 modifications](https://github.com/gnosischain/specs/blob/master/network-upgrades/london.md) +- [x] [Post-merge POSDAO](https://github.com/gnosischain/specs/blob/master/execution/posdao-post-merge.md) +- [x] [Gnosis withdrawals](https://github.com/gnosischain/specs/blob/master/execution/withdrawals.md) + diff --git a/src/ethereum.rs b/src/ethereum.rs new file mode 100644 index 0000000..8741f52 --- /dev/null +++ b/src/ethereum.rs @@ -0,0 +1,141 @@ +//! This module is exactly identical to + +use reth::{ + primitives::{BlockWithSenders, ChainSpec, Receipt, Request}, + providers::ProviderError, + revm::{ + primitives::ResultAndState, + state_change::{ + apply_beacon_root_contract_call, apply_blockhashes_update, + apply_withdrawal_requests_contract_call, + }, + Database, DatabaseCommit, Evm, State, + }, +}; +use reth_evm::{ + execute::{BlockExecutionError, BlockValidationError}, + ConfigureEvm, +}; +use reth_evm_ethereum::eip6110::parse_deposits_from_receipts; +use std::sync::Arc; + +/// Helper type for the output of executing a block. +#[derive(Debug, Clone)] +pub struct EthExecuteOutput { + pub receipts: Vec, + pub requests: Vec, + pub gas_used: u64, +} + +/// Helper container type for EVM with chain spec. +#[derive(Debug, Clone)] +pub struct EthEvmExecutor { + /// The chainspec + pub chain_spec: Arc, + /// How to create an EVM. + pub evm_config: EvmConfig, +} + +impl EthEvmExecutor +where + EvmConfig: ConfigureEvm, +{ + /// Executes the transactions in the block and returns the receipts of the transactions in the + /// block, the total gas used and the list of EIP-7685 [requests](Request). + /// + /// This applies the pre-execution and post-execution changes that require an [EVM](Evm), and + /// executes the transactions. + pub fn execute_state_transitions( + &self, + block: &BlockWithSenders, + mut evm: Evm<'_, Ext, &mut State>, + ) -> Result + where + DB: Database, + { + // apply pre execution changes + apply_beacon_root_contract_call( + &self.chain_spec, + block.timestamp, + block.number, + block.parent_beacon_block_root, + &mut evm, + )?; + apply_blockhashes_update( + evm.db_mut(), + &self.chain_spec, + block.timestamp, + block.number, + block.parent_hash, + )?; + + // execute transactions + let mut cumulative_gas_used = 0; + let mut receipts = Vec::with_capacity(block.body.len()); + for (sender, transaction) in block.transactions_with_sender() { + // 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 { + return Err( + BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { + transaction_gas_limit: transaction.gas_limit(), + block_available_gas, + } + .into(), + ); + } + + EvmConfig::fill_tx_env(evm.tx_mut(), transaction, *sender); + + // Execute transaction. + let ResultAndState { result, state } = evm.transact().map_err(move |err| { + // Ensure hash is calculated for error log, if not already done + BlockValidationError::EVM { + hash: transaction.recalculate_hash(), + error: err.into(), + } + })?; + evm.db_mut().commit(state); + + // append gas used + cumulative_gas_used += result.gas_used(); + + // Push transaction changeset and calculate header bloom filter for receipt. + receipts.push( + #[allow(clippy::needless_update)] // side-effect of optimism fields + Receipt { + tx_type: transaction.tx_type(), + // Success flag was added in `EIP-658: Embedding transaction status code in + // receipts`. + success: result.is_success(), + cumulative_gas_used, + // convert to reth log + logs: result.into_logs(), + ..Default::default() + }, + ); + } + + let requests = if self + .chain_spec + .is_prague_active_at_timestamp(block.timestamp) + { + // Collect all EIP-6110 deposits + let deposit_requests = parse_deposits_from_receipts(&self.chain_spec, &receipts)?; + + // Collect all EIP-7685 requests + let withdrawal_requests = apply_withdrawal_requests_contract_call(&mut evm)?; + + [deposit_requests, withdrawal_requests].concat() + } else { + vec![] + }; + + Ok(EthExecuteOutput { + receipts, + requests, + gas_used: cumulative_gas_used, + }) + } +} diff --git a/src/execute.rs b/src/execute.rs index 5b32c4a..8bba6e1 100644 --- a/src/execute.rs +++ b/src/execute.rs @@ -1,19 +1,17 @@ +use crate::ethereum::{EthEvmExecutor, EthExecuteOutput}; +use crate::gnosis::{apply_block_rewards_contract_call, apply_withdrawals_contract_call}; use reth::{ api::ConfigureEvm, primitives::{ - BlockNumber, BlockWithSenders, ChainSpec, Hardfork, Header, PruneModes, Receipt, Receipts, - Request, Withdrawals, U256, + Address, BlockNumber, BlockWithSenders, ChainSpec, Header, PruneModes, Receipt, Receipts, + U256, }, providers::ProviderError, revm::{ batch::{BlockBatchRecord, BlockExecutorStats}, db::states::bundle_state::BundleRetention, - primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg, ResultAndState}, - state_change::{ - apply_beacon_root_contract_call, apply_blockhashes_update, - apply_withdrawal_requests_contract_call, post_block_balance_increments, - }, - Database, DatabaseCommit, Evm, State, + primitives::{BlockEnv, CfgEnvWithHandlerCfg, EnvWithHandlerCfg}, + Database, State, }, }; use reth_ethereum_consensus::validate_block_post_execution; @@ -21,122 +19,7 @@ use reth_evm::execute::{ BatchBlockExecutionOutput, BatchExecutor, BlockExecutionError, BlockExecutionInput, BlockExecutionOutput, BlockExecutorProvider, BlockValidationError, Executor, }; -use reth_evm_ethereum::{ - dao_fork::{DAO_HARDFORK_BENEFICIARY, DAO_HARDKFORK_ACCOUNTS}, - eip6110::parse_deposits_from_receipts, -}; -use std::sync::Arc; - -/// Helper container type for EVM with chain spec. -// [Gnosis/fork] Copy paste code from crates/ethereum/evm/src/execute.rs::EthBatchExecutor -#[derive(Debug, Clone)] -struct GnosisEvmExecutor { - /// The chainspec - chain_spec: Arc, - /// How to create an EVM. - evm_config: EvmConfig, -} - -// [Gnosis/fork] Copy paste code from crates/ethereum/evm/src/execute.rs::EthBatchExecutor -impl GnosisEvmExecutor -where - EvmConfig: ConfigureEvm, -{ - // [Gnosis/fork] Copy paste code from crates/ethereum/evm/src/execute.rs::EthEvmExecutor - fn execute_state_transitions( - &self, - block: &BlockWithSenders, - mut evm: Evm<'_, Ext, &mut State>, - ) -> Result - where - DB: Database, - { - // apply pre execution changes - apply_beacon_root_contract_call( - &self.chain_spec, - block.timestamp, - block.number, - block.parent_beacon_block_root, - &mut evm, - )?; - apply_blockhashes_update( - evm.db_mut(), - &self.chain_spec, - block.timestamp, - block.number, - block.parent_hash, - )?; - - // execute transactions - let mut cumulative_gas_used = 0; - let mut receipts = Vec::with_capacity(block.body.len()); - for (sender, transaction) in block.transactions_with_sender() { - // 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 { - return Err( - BlockValidationError::TransactionGasLimitMoreThanAvailableBlockGas { - transaction_gas_limit: transaction.gas_limit(), - block_available_gas, - } - .into(), - ); - } - - EvmConfig::fill_tx_env(evm.tx_mut(), transaction, *sender); - - // Execute transaction. - let ResultAndState { result, state } = evm.transact().map_err(move |err| { - // Ensure hash is calculated for error log, if not already done - BlockValidationError::EVM { - hash: transaction.recalculate_hash(), - error: err.into(), - } - })?; - evm.db_mut().commit(state); - - // append gas used - cumulative_gas_used += result.gas_used(); - - // Push transaction changeset and calculate header bloom filter for receipt. - receipts.push( - #[allow(clippy::needless_update)] // side-effect of optimism fields - Receipt { - tx_type: transaction.tx_type(), - // Success flag was added in `EIP-658: Embedding transaction status code in - // receipts`. - success: result.is_success(), - cumulative_gas_used, - // convert to reth log - logs: result.into_logs(), - ..Default::default() - }, - ); - } - - let requests = if self - .chain_spec - .is_prague_active_at_timestamp(block.timestamp) - { - // Collect all EIP-6110 deposits - let deposit_requests = parse_deposits_from_receipts(&self.chain_spec, &receipts)?; - - // Collect all EIP-7685 requests - let withdrawal_requests = apply_withdrawal_requests_contract_call(&mut evm)?; - - [deposit_requests, withdrawal_requests].concat() - } else { - vec![] - }; - - Ok(EthExecuteOutput { - receipts, - requests, - gas_used: cumulative_gas_used, - }) - } -} +use std::{collections::HashMap, sync::Arc}; #[derive(Debug, Clone)] pub struct GnosisExecutorProvider { @@ -209,7 +92,7 @@ where #[derive(Debug)] pub struct GnosisBlockExecutor { /// Chain specific evm config that's used to execute a block. - executor: GnosisEvmExecutor, + executor: EthEvmExecutor, /// The state to use for execution state: State, } @@ -219,7 +102,7 @@ impl GnosisBlockExecutor { /// Creates a new Ethereum block executor. pub fn new(chain_spec: Arc, evm_config: EvmConfig, state: State) -> Self { Self { - executor: GnosisEvmExecutor { + executor: EthEvmExecutor { chain_spec, evm_config, }, @@ -232,6 +115,10 @@ impl GnosisBlockExecutor { &self.executor.chain_spec } + fn chain_spec_clone(&self) -> Arc { + self.executor.chain_spec.clone() + } + /// Returns mutable reference to the state that wraps the underlying database. #[allow(unused)] fn state_mut(&mut self) -> &mut State { @@ -293,43 +180,55 @@ where self.state.set_state_clear_flag(state_clear_flag); } - /// Apply post execution state changes that do not require an [EVM](Evm), such as: block + /// Apply post execution state changes that do not require an such as: block /// rewards, withdrawals, and irregular DAO hardfork state change + // [Gnosis/fork:DIFF] pub fn post_execution( &mut self, block: &BlockWithSenders, total_difficulty: U256, ) -> Result<(), BlockExecutionError> { - let mut balance_increments = post_block_balance_increments( - self.chain_spec(), - block.number, - block.difficulty, - block.beneficiary, - block.timestamp, - total_difficulty, - &block.ommers, - block.withdrawals.as_ref().map(Withdrawals::as_ref), - ); + // [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 + + let chain_spec = self.chain_spec_clone(); - // Irregular state change at Ethereum DAO hardfork - if self - .chain_spec() - .fork(Hardfork::Dao) - .transitions_at_block(block.number) { - // drain balances from hardcoded addresses. - let drained_balance: u128 = self - .state - .drain_balances(DAO_HARDKFORK_ACCOUNTS) - .map_err(|_| BlockValidationError::IncrementBalanceFailed)? - .into_iter() - .sum(); - - // return balance to DAO beneficiary. - *balance_increments - .entry(DAO_HARDFORK_BENEFICIARY) - .or_default() += drained_balance; + 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, + block + .withdrawals + .as_ref() + .ok_or(BlockExecutionError::Other( + "block has no withdrawals field".to_owned().into(), + ))?, + &mut evm, + )?; } + + let balance_increments: HashMap = { + 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( + &chain_spec, + block.timestamp, + block.beneficiary, + &mut evm, + )? + }; + // increment balances self.state .increment_balances(balance_increments) @@ -339,15 +238,6 @@ where } } -/// Helper type for the output of executing a block. -// [Gnosis/fork] Copy paste code from crates/ethereum/evm/src/execute.rs::EthExecuteOutput -#[derive(Debug, Clone)] -struct EthExecuteOutput { - receipts: Vec, - requests: Vec, - gas_used: u64, -} - // Trait required by BlockExecutorProvider associated type Executor impl Executor for GnosisBlockExecutor where diff --git a/src/gnosis.rs b/src/gnosis.rs new file mode 100644 index 0000000..0d9dfa3 --- /dev/null +++ b/src/gnosis.rs @@ -0,0 +1,232 @@ +use std::collections::HashMap; + +use alloy_sol_macro::sol; +use alloy_sol_types::SolCall; +use reth::{ + primitives::{address, Address, Bytes, ChainSpec, Withdrawal, U256}, + revm::{ + interpreter::Host, + primitives::{Env, ExecutionResult, Output, ResultAndState, TransactTo, TxEnv}, + Database, DatabaseCommit, Evm, + }, +}; +use reth_evm::execute::BlockExecutionError; + +pub const SYSTEM_ADDRESS: Address = address!("fffffffffffffffffffffffffffffffffffffffe"); + +// TODO: customize from genesis or somewhere +pub const BLOCK_REWARDS_CONTRACT: Address = address!("481c034c6d9441db23ea48de68bcae812c5d39ba"); + +// Codegen from https://github.com/gnosischain/specs/blob/master/execution/withdrawals.md +sol!( + function executeSystemWithdrawals( + uint256 maxFailedWithdrawalsToProcess, + uint64[] calldata _amounts, + address[] calldata _addresses + ); +); + +sol!( + function reward( + address[] benefactors, + uint16[] kind + ) returns( + address[] receiversNative, + uint256[] memory rewardsNative + ); +); + +/// Applies the post-block call to the withdrawal / deposit contract, using the given block, +/// [`ChainSpec`], EVM. +/// +/// Ref: +#[inline] +pub fn apply_withdrawals_contract_call( + chain_spec: &ChainSpec, + _block_timestamp: u64, + withdrawals: &[Withdrawal], + evm: &mut Evm<'_, EXT, DB>, +) -> Result<(), BlockExecutionError> +where + DB::Error: std::fmt::Display, +{ + // TODO: how is the deposit contract address passed to here? + let withdrawal_contract_address = chain_spec + .deposit_contract + .as_ref() + .ok_or(BlockExecutionError::Other( + "deposit_contract not set".to_owned().into(), + ))? + .address; + + // TODO: Only do the call post-merge + // TODO: Should this call be made for the genesis block? + + // 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( + &mut evm.context.evm.env, + SYSTEM_ADDRESS, + withdrawal_contract_address, + executeSystemWithdrawalsCall { + maxFailedWithdrawalsToProcess: U256::from(4), + _amounts: withdrawals.iter().map(|w| w.amount).collect::>(), + _addresses: withdrawals.iter().map(|w| w.address).collect::>(), + } + .abi_encode() + .into(), + ); + + let mut state = match evm.transact() { + Ok(res) => res.state, + Err(e) => { + evm.context.evm.env = previous_env; + return Err(BlockExecutionError::Other( + format!("withdrawal contract system call revert: {}", e).into(), + )); + } + }; + + // TODO: Should check the execution is successful? Is an Ok from transact() enough? + + // Clean-up post system tx context + state.remove(&SYSTEM_ADDRESS); + state.remove(&evm.block().coinbase); + evm.context.evm.db.commit(state); + // re-set the previous env + evm.context.evm.env = previous_env; + + Ok(()) +} + +/// Applies the post-block call to the block rewards POSDAO contract, using the given block, +/// [`ChainSpec`], EVM. +/// +/// Ref: +#[inline] +pub fn apply_block_rewards_contract_call( + _chain_spec: &ChainSpec, + _block_timestamp: u64, + coinbase: Address, + evm: &mut Evm<'_, EXT, DB>, +) -> Result, BlockExecutionError> +where + DB::Error: std::fmt::Display, +{ + // 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( + &mut evm.context.evm.env, + SYSTEM_ADDRESS, + BLOCK_REWARDS_CONTRACT, + rewardCall { + benefactors: vec![coinbase], + // Type 0 = RewardAuthor + kind: vec![0], + } + .abi_encode() + .into(), + ); + + let ResultAndState { result, mut state } = match evm.transact() { + Ok(res) => res, + Err(e) => { + evm.context.evm.env = previous_env; + return Err(BlockExecutionError::Other( + format!("withdrawal contract system call error: {}", e).into(), + )); + } + }; + + let output_bytes = match result { + ExecutionResult::Success { output, .. } => match output { + Output::Call(output_bytes) | + // Should never happen, we craft a transaction without constructor code + Output::Create(output_bytes, _) => output_bytes, + }, + ExecutionResult::Revert { output, .. } => { + return Err(BlockExecutionError::Other( + format!("withdrawal contract system call revert {}", output).into(), + )); + } + ExecutionResult::Halt { reason, .. } => { + return Err(BlockExecutionError::Other( + format!("withdrawal contract system call halt {:?}", reason).into(), + )); + } + }; + + let result = rewardCall::abi_decode_returns(output_bytes.as_ref(), true).map_err(|e| { + BlockExecutionError::Other( + format!("error parsing withdrawal contract system call return {}", e).into(), + ) + })?; + + // Clean-up post system tx context + state.remove(&SYSTEM_ADDRESS); + state.remove(&evm.block().coinbase); + evm.context.evm.db.commit(state); + // re-set the previous env + evm.context.evm.env = previous_env; + + // TODO: How to get function return call from evm.transact()? + let mut balance_increments = HashMap::new(); + for (address, amount) in result + .receiversNative + .iter() + .zip(result.rewardsNative.iter()) + { + // TODO: .to panics if the return value is too large + balance_increments.insert(*address, amount.to::()); + } + + 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, + }; + + // 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; +} diff --git a/src/lib.rs b/src/lib.rs index 00a2d27..882ffdf 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -13,7 +13,9 @@ use reth_node_ethereum::{ EthEngineTypes, EthereumNode, }; +mod ethereum; mod execute; +mod gnosis; #[derive(Debug, Clone, Default, PartialEq, Eq, clap::Args)] #[command(next_help_heading = "Gnosis")]