diff --git a/etherlink/kernel_latest/kernel/src/apply.rs b/etherlink/kernel_latest/kernel/src/apply.rs index 0c86df2ede52362f86c851812323458276c06995..5a25cfffaf405e134b010f4be9be6ce6f79692cb 100644 --- a/etherlink/kernel_latest/kernel/src/apply.rs +++ b/etherlink/kernel_latest/kernel/src/apply.rs @@ -24,6 +24,7 @@ use evm_execution::trace::{ get_tracer_configuration, CallTrace, CallTracerConfig, CallTracerInput, TracerInput, }; use primitive_types::{H160, H256, U256}; +use revm::primitives::hardfork::SpecId; use std::borrow::Cow; use tezos_ethereum::access_list::{AccessList, AccessListItem}; use tezos_ethereum::block::BlockConstants; @@ -267,14 +268,10 @@ fn is_valid_ethereum_transaction_common( return Ok(Validity::InvalidPrePay); } - // TODO: Whenever the configuration/spec id of our EVM - // is properly propagated to REVM, re-adjust this condition. - if let Ok(false) = is_revm_enabled(host) { - // The sender does not have code, see EIP3607. - if code_exists { - log!(host, Benchmarking, "Transaction status: ERROR_CODE."); - return Ok(Validity::InvalidCode); - } + // The sender does not have code, see EIP3607. + if code_exists { + log!(host, Benchmarking, "Transaction status: ERROR_CODE."); + return Ok(Validity::InvalidCode); } // check that enough gas is provided to cover fees @@ -308,6 +305,17 @@ fn log_transaction_type(host: &Host, to: Option, data: &[u8 } } +fn config_to_revm_specid(config: &Config) -> revm::primitives::hardfork::SpecId { + // This is a hack-ish way to derive the spec id from Sputnik's + // configuration. The last case is the very first EVM version + // that we supported (:= Shanghai). + if config.selfdestruct_deprecated { + SpecId::CANCUN + } else { + SpecId::SHANGHAI + } +} + #[allow(clippy::too_many_arguments)] pub fn revm_run_transaction( host: &mut Host, @@ -319,6 +327,7 @@ pub fn revm_run_transaction( call_data: Vec, effective_gas_price: U256, access_list: AccessList, + config: &Config, ) -> Result, anyhow::Error> { // Disclaimer: // The following code is over-complicated because we maintain @@ -348,6 +357,7 @@ pub fn revm_run_transaction( }; match revm_etherlink::run_transaction( host, + config_to_revm_specid(config), block_constants, &mut world_state_handler, revm_etherlink::precompile_provider::EtherlinkPrecompiles::new(), @@ -558,6 +568,7 @@ fn apply_ethereum_transaction_common( call_data, effective_gas_price, transaction.access_list.clone(), + evm_configuration, ) { Ok(outcome) => outcome, Err(err) => { diff --git a/etherlink/kernel_latest/kernel/src/simulation.rs b/etherlink/kernel_latest/kernel/src/simulation.rs index e3ae25e7e784869fcd0b8a50d1bdca1174288eb8..0152ffca6ee2a41d47fc17f74490fd631d25963b 100644 --- a/etherlink/kernel_latest/kernel/src/simulation.rs +++ b/etherlink/kernel_latest/kernel/src/simulation.rs @@ -489,6 +489,7 @@ impl Evaluation { gas_price, // TODO: Replace this by the decoded access lists if any. empty_access_list(), + evm_configuration, ) { Ok(Some(outcome)) if !self.with_da_fees => { let result: SimulationResult = diff --git a/etherlink/kernel_latest/revm/src/lib.rs b/etherlink/kernel_latest/revm/src/lib.rs index 656b32e147412be30a166dd6352f640cc50f33c7..2e249d2c9876e9c974c30124418fc0860e413b03 100644 --- a/etherlink/kernel_latest/revm/src/lib.rs +++ b/etherlink/kernel_latest/revm/src/lib.rs @@ -34,8 +34,6 @@ mod code_storage; mod database; mod storage_helpers; -const DEFAULT_SPEC_ID: SpecId = SpecId::PRAGUE; - #[derive(Error, Debug)] pub enum Error { #[error("Runtime error: {0}")] @@ -145,10 +143,9 @@ fn evm<'a, Host: Runtime>( tx: &'a TxEnv, precompiles: EtherlinkPrecompiles, chain_id: u64, + spec_id: SpecId, ) -> EvmContext<'a, Host> { - let cfg = CfgEnv::new() - .with_chain_id(chain_id) - .with_spec(DEFAULT_SPEC_ID); + let cfg = CfgEnv::new().with_chain_id(chain_id).with_spec(spec_id); let context: Context< BlockEnv, @@ -158,7 +155,7 @@ fn evm<'a, Host: Runtime>( Journal>, (), LocalContext, - > = Context::new(db, DEFAULT_SPEC_ID); + > = Context::new(db, spec_id); let evm = context .with_block(block) @@ -172,6 +169,7 @@ fn evm<'a, Host: Runtime>( #[allow(clippy::too_many_arguments)] pub fn run_transaction<'a, Host: Runtime>( host: &'a mut Host, + spec_id: SpecId, block_constants: &'a BlockConstants, world_state_handler: &'a mut WorldStateHandler, precompiles: EtherlinkPrecompiles, @@ -211,6 +209,7 @@ pub fn run_transaction<'a, Host: Runtime>( &tx, precompiles, block_constants.chain_id.as_u64(), + spec_id, ); evm.db_mut().initialize_storage()?; @@ -249,7 +248,9 @@ mod test { }; use serde_json::Value; use tezos_evm_runtime::runtime::MockKernelHost; - use utilities::{block_constants_with_fees, block_constants_with_no_fees}; + use utilities::{ + block_constants_with_fees, block_constants_with_no_fees, DEFAULT_SPEC_ID, + }; use crate::world_state_handler::new_world_state_handler; use crate::{ @@ -259,7 +260,15 @@ mod test { mod utilities { use primitive_types::{H160 as PH160, U256 as PU256}; + use revm::primitives::hardfork::SpecId; use tezos_ethereum::block::{BlockConstants, BlockFees}; + + // The default SpecId is set to Cancun. + // It isn't modular like it was in the previous evm execution. + // This value was normally retrived from the old execution storage. Once we fully + // make the switch to REVM this part will become modular again. + // For now we keep it at Cancun which is the latest EVM version Etherlink supports. + pub(crate) const DEFAULT_SPEC_ID: SpecId = SpecId::CANCUN; const ETHERLINK_CHAIN_ID: u64 = 42793; pub(crate) fn block_constants_with_fees() -> BlockConstants { @@ -320,6 +329,7 @@ mod test { let execution_result = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, precompiles, @@ -399,6 +409,7 @@ mod test { let execution_result = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, precompiles, @@ -453,6 +464,7 @@ mod test { let result = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, precompiles, @@ -536,6 +548,7 @@ mod test { // Deploy XTZWithdrawal let ExecutionOutcome { result, .. } = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, EtherlinkPrecompiles::new(), @@ -567,6 +580,7 @@ mod test { withdrawals, } = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, EtherlinkPrecompiles::new(), @@ -624,6 +638,7 @@ mod test { let result_create = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, EtherlinkPrecompiles::new(), @@ -651,6 +666,7 @@ mod test { let result_call = run_transaction( &mut host, + DEFAULT_SPEC_ID, &block_constants, &mut world_state_handler, EtherlinkPrecompiles::new(), diff --git a/etherlink/kernel_latest/revm/src/world_state_handler.rs b/etherlink/kernel_latest/revm/src/world_state_handler.rs index 280fc2379c3f80700eb0323ba671bb73de61e7c1..cd338e4ef0aa95935857a825fc956cba9602a8f7 100644 --- a/etherlink/kernel_latest/revm/src/world_state_handler.rs +++ b/etherlink/kernel_latest/revm/src/world_state_handler.rs @@ -154,7 +154,14 @@ impl StorageAccount { Ok(()) } else { let code_hash = match code { - None => KECCAK_EMPTY, + // There is nothing to store if there's no code or if the legacy analyzed + // bytecode is just the STOP instruction (0x00). + None => return Ok(()), + Some(Bytecode::LegacyAnalyzed(bytecode)) + if bytecode.bytecode() == &Bytes::from_static(&[0]) => + { + return Ok(()) + } Some(code) => CodeStorage::add(host, code.original_byte_slice())?, }; let code_hash_bytes: [u8; 32] = code_hash.into();