From e730ec9c2f9d5ff6d089d921153d5af7028403a2 Mon Sep 17 00:00:00 2001 From: refcell Date: Tue, 28 Jan 2025 13:28:14 -0500 Subject: [PATCH 1/2] feat(executor): eip-7002 syscall support --- Cargo.lock | 64 ++++++---- crates/executor/src/executor/mod.rs | 14 ++- crates/executor/src/syscalls/eip7002.rs | 154 ++++++++++++++++++++++++ crates/executor/src/syscalls/mod.rs | 3 + 4 files changed, 213 insertions(+), 22 deletions(-) create mode 100644 crates/executor/src/syscalls/eip7002.rs diff --git a/Cargo.lock b/Cargo.lock index 2bc93a8df5..d25360cd0d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1057,9 +1057,9 @@ dependencies = [ [[package]] name = "bumpalo" -version = "3.16.0" +version = "3.17.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "79296716171880943b8470b5f8d03aa55eb2e645a4874bdbb28adb49162e012c" +checksum = "1628fb46dfa0b37568d12e5edd512553eccf6a22a78e8bde00bb4aed84d5bdbf" [[package]] name = "byte-slice-cast" @@ -1291,6 +1291,26 @@ version = "0.9.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +[[package]] +name = "const_format" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "126f97965c8ad46d6d9163268ff28432e8f6a1196a55578867832e3049df63dd" +dependencies = [ + "const_format_proc_macros", +] + +[[package]] +name = "const_format_proc_macros" +version = "0.2.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d57c2eccfb16dbac1f4e61e206105db5820c9d26c3c472bc17c774259ef7744" +dependencies = [ + "proc-macro2", + "quote", + "unicode-xid", +] + [[package]] name = "core-foundation" version = "0.9.4" @@ -2870,9 +2890,9 @@ dependencies = [ [[package]] name = "maili-genesis" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b555c1fab6c4f01f4defc6543b52377c3ee904a712dd1e21efbc0d7843c6207" +checksum = "b247c993ac2d89a7171eac22086cf18e2d6e5a0a654d6902d9ee834772af1b25" dependencies = [ "alloy-consensus", "alloy-eips", @@ -2886,9 +2906,9 @@ dependencies = [ [[package]] name = "maili-protocol" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db659969c6618849ee212e7425c35bcd88cdc7cd7b9d10dcb9b1ae00d01a8cdd" +checksum = "2a7d7fdcf313d5671a931c7c5a7969dfa8c4d6d3fb34da29ea731eb2364560c9" dependencies = [ "alloc-no-stdlib", "alloy-consensus", @@ -2914,9 +2934,9 @@ dependencies = [ [[package]] name = "maili-registry" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3d6a3435074b73cdaf1c4e468ed4508e08cb21aa5dba88082914bdadac60e2b3" +checksum = "c2b4709306d9532c7a0c84de7765f4bc5ed7068350e54444e28aaad4d7c88dc2" dependencies = [ "alloy-primitives", "lazy_static", @@ -2929,9 +2949,9 @@ dependencies = [ [[package]] name = "maili-rpc" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b6651c695539b1e31a1c8e7eae2c301a6a70200675483a9490086e991efd8a4" +checksum = "79c62dbe6d8b8765d5dda1a798cefb702bebd59038a8eb95a9e2275db973589e" dependencies = [ "alloy-eips", "alloy-primitives", @@ -2942,9 +2962,9 @@ dependencies = [ [[package]] name = "maili-serde" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "06f2217f2efdc5132167512db12ce9bf0a087d20f8d5ebf0f2a2a0b836a668d8" +checksum = "908a6a1352249f55d8c982dbf868d54c86e2aa461c94d56c4e1bd0f74cae9714" dependencies = [ "alloy-primitives", "serde", @@ -2953,9 +2973,9 @@ dependencies = [ [[package]] name = "maili-superchain" -version = "0.1.8" +version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1b99c2c73b9bd8d28dbbf490dd3566193e857fbbeea28574e618a7335f006bac" +checksum = "552cbfa042beb2ee9b283ac54d97f8ec0cb38d929fe2ec60c329e84cfe8181c4" dependencies = [ "alloy-primitives", "maili-genesis", @@ -3329,28 +3349,30 @@ dependencies = [ [[package]] name = "parity-scale-codec" -version = "3.6.12" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "306800abfa29c7f16596b5970a588435e3d5b3149683d00c12b699cc19f895ee" +checksum = "b91c2d9a6a6004e205b7e881856fb1a0f5022d382acc2c01b52185f7b6f65997" dependencies = [ "arrayvec", "bitvec", "byte-slice-cast", + "const_format", "impl-trait-for-tuples", "parity-scale-codec-derive", + "rustversion", "serde", ] [[package]] name = "parity-scale-codec-derive" -version = "3.6.12" +version = "3.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d830939c76d294956402033aee57a6da7b438f2294eb94864c37b0569053a42c" +checksum = "77555fd9d578b6470470463fded832619a5fec5ad6cbc551fe4d7507ce50cd3a" dependencies = [ "proc-macro-crate", "proc-macro2", "quote", - "syn 1.0.109", + "syn 2.0.96", ] [[package]] @@ -4324,9 +4346,9 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.137" +version = "1.0.138" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "930cfb6e6abf99298aaad7d29abbef7a9999a9a8806a40088f55f0dcec03146b" +checksum = "d434192e7da787e94a6ea7e9670b26a036d0ca41e0b7efb2676dd32bae872949" dependencies = [ "indexmap", "itoa", diff --git a/crates/executor/src/executor/mod.rs b/crates/executor/src/executor/mod.rs index 26af1c07fb..b480db61a5 100644 --- a/crates/executor/src/executor/mod.rs +++ b/crates/executor/src/executor/mod.rs @@ -4,7 +4,10 @@ use crate::{ constants::{L2_TO_L1_BRIDGE, OUTPUT_ROOT_VERSION}, db::TrieDB, errors::TrieDBError, - syscalls::{ensure_create2_deployer_canyon, pre_block_beacon_root_contract_call}, + syscalls::{ + ensure_create2_deployer_canyon, pre_block_beacon_root_contract_call, + pre_block_withdrawals_request_contract_call, + }, ExecutorError, ExecutorResult, TrieDBProvider, }; use alloc::vec::Vec; @@ -133,6 +136,15 @@ where &payload, )?; + // Apply the pre-block EIP-7002 contract call. + pre_block_withdrawals_request_contract_call( + &mut state, + self.config, + &initialized_cfg, + &initialized_block_env, + &payload, + )?; + // Ensure that the create2 contract is deployed upon transition to the Canyon hardfork. ensure_create2_deployer_canyon( &mut state, diff --git a/crates/executor/src/syscalls/eip7002.rs b/crates/executor/src/syscalls/eip7002.rs new file mode 100644 index 0000000000..4892c9ed68 --- /dev/null +++ b/crates/executor/src/syscalls/eip7002.rs @@ -0,0 +1,154 @@ +//! Contains the logic for executing the pre-block withdrawals request call. + +use crate::{ + db::TrieDB, + errors::{ExecutorError, ExecutorResult}, + TrieDBProvider, +}; +use alloc::{boxed::Box, vec::Vec}; +use alloy_primitives::{Address, Bytes, U256}; +use kona_mpt::TrieHinter; +use maili_genesis::RollupConfig; +use op_alloy_rpc_types_engine::OpPayloadAttributes; +use revm::{ + db::State, + primitives::{ + BlockEnv, CfgEnvWithHandlerCfg, Env, EnvWithHandlerCfg, OptimismFields, TransactTo, TxEnv, + }, + DatabaseCommit, Evm, +}; + +/// Execute the EIP-7002 pre-block withdrawals request contract call. +pub(crate) fn pre_block_withdrawals_request_contract_call( + db: &mut State<&mut TrieDB>, + config: &RollupConfig, + initialized_cfg: &CfgEnvWithHandlerCfg, + initialized_block_env: &BlockEnv, + payload: &OpPayloadAttributes, +) -> ExecutorResult<()> +where + F: TrieDBProvider, + H: TrieHinter, +{ + // apply pre-block EIP-4788 contract call + let mut evm_pre_block = 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(); + + // initialize a block from the env, because the pre block call needs the block itself + apply_withdrawals_request_contract_call( + config, + payload.payload_attributes.timestamp, + &mut evm_pre_block, + ) +} + +/// Apply the EIP-7002 pre-block withdrawals request contract call to a given EVM instance. +fn apply_withdrawals_request_contract_call( + config: &RollupConfig, + timestamp: u64, + evm: &mut Evm<'_, (), &mut State<&mut TrieDB>>, +) -> ExecutorResult<()> +where + F: TrieDBProvider, + H: TrieHinter, +{ + if !config.is_isthmus_active(timestamp) { + return Ok(()); + } + + // Get the previous environment + let previous_env = Box::new(evm.context.evm.env().clone()); + + // modify env for pre block call + fill_tx_env_with_withdrawals_request_contract_call(&mut evm.context.evm.env); + + let mut state = match evm.transact() { + Ok(res) => res.state, + Err(e) => { + evm.context.evm.env = previous_env; + return Err(ExecutorError::ExecutionError(e)); + } + }; + + state.remove(&alloy_eips::eip7002::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(()) +} + +/// Fill transaction environment with the EIP-7002 system contract message data. +/// +/// This requirements for the beacon root contract call are defined by +/// [EIP-7002](https://eips.ethereum.org/EIPS/eip-7002). +fn fill_tx_env_with_withdrawals_request_contract_call(env: &mut Env) { + fill_tx_env_with_system_contract_call( + env, + alloy_eips::eip7002::SYSTEM_ADDRESS, + alloy_eips::eip7002::WITHDRAWAL_REQUEST_PREDEPLOY_ADDRESS, + Bytes::new(), + ); +} + +/// 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(), + authorization_list: None, + // blob fields can be None for this tx + blob_hashes: Vec::new(), + max_fee_per_blob_gas: None, + optimism: OptimismFields { + source_hash: None, + mint: None, + is_system_transaction: Some(false), + // The L1 fee is not charged for the EIP-4788 transaction, submit zero bytes for the + // enveloped tx size. + enveloped_tx: Some(Bytes::default()), + }, + }; + + // 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/crates/executor/src/syscalls/mod.rs b/crates/executor/src/syscalls/mod.rs index 425aca27ca..a848d17fc3 100644 --- a/crates/executor/src/syscalls/mod.rs +++ b/crates/executor/src/syscalls/mod.rs @@ -1,5 +1,8 @@ //! Optimism EVM System calls. +mod eip7002; +pub(crate) use eip7002::pre_block_withdrawals_request_contract_call; + mod eip4788; pub(crate) use eip4788::pre_block_beacon_root_contract_call; From 85acf14ae77b747b5e8ad4f22bdf5630402c5101 Mon Sep 17 00:00:00 2001 From: refcell Date: Tue, 28 Jan 2025 14:04:07 -0500 Subject: [PATCH 2/2] fix: lints --- crates/executor/src/executor/mod.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/crates/executor/src/executor/mod.rs b/crates/executor/src/executor/mod.rs index 0362ee9722..31682ed95f 100644 --- a/crates/executor/src/executor/mod.rs +++ b/crates/executor/src/executor/mod.rs @@ -6,8 +6,7 @@ use crate::{ errors::TrieDBError, syscalls::{ ensure_create2_deployer_canyon, pre_block_beacon_root_contract_call, - pre_block_withdrawals_request_contract_call, - pre_block_block_hash_contract_call, + pre_block_block_hash_contract_call, pre_block_withdrawals_request_contract_call, }, ExecutorError, ExecutorResult, TrieDBProvider, }; @@ -149,7 +148,7 @@ where parent_block_hash, &payload, )?; - + // Apply the pre-block EIP-7002 contract call. pre_block_withdrawals_request_contract_call( &mut state,