From 478319cfd6167d3f3c170ccf63cad595bae8e887 Mon Sep 17 00:00:00 2001 From: Pana Date: Tue, 28 Oct 2025 10:49:59 +0800 Subject: [PATCH 1/4] add clz opcode misc reuse code --- crates/config/src/configuration.rs | 10 ++++- crates/execution/executor/src/context.rs | 21 --------- crates/execution/executor/src/spec.rs | 3 ++ .../execution/vm-interpreter/src/factory.rs | 6 ++- .../vm-interpreter/src/instructions.rs | 18 +++++++- .../vm-interpreter/src/interpreter/mod.rs | 45 ++++--------------- crates/execution/vm-interpreter/src/lib.rs | 4 +- crates/execution/vm-types/src/context.rs | 22 --------- crates/execution/vm-types/src/spec.rs | 3 ++ crates/execution/vm-types/src/tests.rs | 6 --- 10 files changed, 46 insertions(+), 92 deletions(-) diff --git a/crates/config/src/configuration.rs b/crates/config/src/configuration.rs index a8d8227ca2..8086a95d26 100644 --- a/crates/config/src/configuration.rs +++ b/crates/config/src/configuration.rs @@ -201,6 +201,8 @@ build_config! { (cip145_fix_transition_height, (Option), None) // For test only (align_evm_transition_height, (u64), u64::MAX) + // V3.1 + (eip7939_transition_number, (Option), None) // Mining section. @@ -1531,7 +1533,7 @@ impl Configuration { .unwrap_or(default_transition_time); // - // 7702 hardfork (V2.6) + // 7702 hardfork (V3.0) // set_conf!( self.raw_conf.eoa_code_transition_height.unwrap_or(default_transition_time); @@ -1548,6 +1550,12 @@ impl Configuration { } params.transition_heights.align_evm = self.raw_conf.align_evm_transition_height; + + // hardfork (V3.1) + params.transition_numbers.eip7939 = self + .raw_conf + .eip7939_transition_number + .unwrap_or(default_transition_time); } } diff --git a/crates/execution/executor/src/context.rs b/crates/execution/executor/src/context.rs index b72700d47f..cc9c8aadc0 100644 --- a/crates/execution/executor/src/context.rs +++ b/crates/execution/executor/src/context.rs @@ -533,27 +533,6 @@ impl<'a> ContextTrait for Context<'a> { fn depth(&self) -> usize { self.depth } - // fn trace_next_instruction( - // &mut self, _pc: usize, _instruction: u8, _current_gas: U256, - // ) -> bool { - // // TODO - // false - // } - - // fn trace_prepare_execute( - // &mut self, _pc: usize, _instruction: u8, _gas_cost: U256, - // _mem_written: Option<(usize, usize)>, - // _store_written: Option<(U256, U256)>, - // ) { - // // TODO - // } - - // fn trace_executed( - // &mut self, _gas_used: U256, _stack_push: &[U256], _mem: &[u8], - // ) { - // // TODO - // } - fn trace_step(&mut self, interpreter: &dyn vm::InterpreterInfo) { self.tracer.step(interpreter); } diff --git a/crates/execution/executor/src/spec.rs b/crates/execution/executor/src/spec.rs index a9e4ddfd2b..ea8af4ce16 100644 --- a/crates/execution/executor/src/spec.rs +++ b/crates/execution/executor/src/spec.rs @@ -115,6 +115,8 @@ pub struct TransitionsBlockNumber { pub cip144: BlockNumber, /// CIP-145: Fix Receipts upon `NotEnoughBalance` Error pub cip145: BlockNumber, + /// EIP-7939: Count Leading Zeros Instruction + pub eip7939: BlockHeight, } #[derive(Default, Debug, Clone)] @@ -229,6 +231,7 @@ impl CommonParams { spec.cip_c2_fix = height >= self.transition_heights.cip_c2_fix; spec.cancun_opcodes = number >= self.transition_numbers.cancun_opcodes; spec.align_evm = height >= self.transition_heights.align_evm && cip645; + spec.eip7939 = number >= self.transition_numbers.eip7939; spec.overwrite_gas_plan_by_cip(); diff --git a/crates/execution/vm-interpreter/src/factory.rs b/crates/execution/vm-interpreter/src/factory.rs index b868448a39..6edf67038a 100644 --- a/crates/execution/vm-interpreter/src/factory.rs +++ b/crates/execution/vm-interpreter/src/factory.rs @@ -19,7 +19,10 @@ // See http://www.gnu.org/licenses/ //! Evm factory. -use super::{interpreter::SharedCache, vmtype::VMType}; +use super::{ + interpreter::{Interpreter, SharedCache}, + vmtype::VMType, +}; use cfx_types::U256; #[cfg(test)] use cfx_vm_types::CallType; @@ -40,7 +43,6 @@ impl Factory { pub fn create( &self, params: ActionParams, spec: &Spec, depth: usize, ) -> Box { - use super::interpreter::Interpreter; // Assert there is only one type. Parity Ethereum is dead and no more // types will be added. match self.evm { diff --git a/crates/execution/vm-interpreter/src/instructions.rs b/crates/execution/vm-interpreter/src/instructions.rs index 9f76e9bb06..5a5753d5e3 100644 --- a/crates/execution/vm-interpreter/src/instructions.rs +++ b/crates/execution/vm-interpreter/src/instructions.rs @@ -106,6 +106,8 @@ enum_with_from_u8! { SHR = 0x1c, #[doc = "arithmetic shift right operation"] SAR = 0x1d, + #[doc = "count leading zeros"] + CLZ = 0x1e, #[doc = "compute SHA3-256 hash"] SHA3 = 0x20, @@ -380,6 +382,9 @@ impl Instruction { if instruction == Some(BASEFEE) && !spec.cip1559 { instruction = None; } + if instruction == Some(CLZ) && !spec.eip7939 { + instruction = None; + } return instruction; } @@ -426,9 +431,13 @@ impl Instruction { } /// Returns the instruction info. - pub fn info(&self, cip645: bool) -> &InstructionInfo { + pub fn info( + &self, cip645: bool, eip7939: bool, + ) -> &InstructionInfo { let instrs = if !CANCUN { &*INSTRUCTIONS + } else if eip7939 { + &*INSTRUCTIONS_EIP7939 } else if !cip645 { &*INSTRUCTIONS_CANCUN } else { @@ -672,6 +681,13 @@ lazy_static! { arr }; + + pub static ref INSTRUCTIONS_EIP7939: [Option; 0x100] = { + let mut arr = *INSTRUCTIONS_CIP645; + arr[CLZ as usize] = Some(InstructionInfo::new("CLZ", 1, 1, GasPriceTier::Low)); + + arr + }; } /// Maximal number of topics for log instructions diff --git a/crates/execution/vm-interpreter/src/interpreter/mod.rs b/crates/execution/vm-interpreter/src/interpreter/mod.rs index e1f51b711a..4cee9eb2fb 100644 --- a/crates/execution/vm-interpreter/src/interpreter/mod.rs +++ b/crates/execution/vm-interpreter/src/interpreter/mod.rs @@ -568,19 +568,6 @@ impl Interpreter { Instruction::from_u8_versioned(opcode, context.spec()); self.reader.position += 1; - // TODO: make compile-time removable if too much of a - // performance hit. - // self.do_trace = self.do_trace - // && context.trace_next_instruction( - // self.reader.position - 1, - // opcode, - // self.gasometer - // .as_mut() - // .expect(GASOMETER_PROOF) - // .current_gas - // .as_u256(), - // ); - let instruction = match instruction { Some(i) => i, None => { @@ -592,8 +579,10 @@ impl Interpreter { } }; - let info = - instruction.info::(context.spec().cip645.opcode_update); + let info = instruction.info::( + context.spec().cip645.opcode_update, + context.spec().eip7939, + ); self.last_stack_ret_len = info.ret; if let Err(e) = self.verify_instruction(context, instruction, info) { return Err(InterpreterResult::Done(Err(e))); @@ -612,15 +601,6 @@ impl Interpreter { Ok(t) => t, Err(e) => return Err(InterpreterResult::Done(Err(e))), }; - // if self.do_trace { - // context.trace_prepare_execute( - // self.reader.position - 1, - // opcode, - // requirements.gas_cost.as_u256(), - // Self::mem_written(instruction, &self.stack), - // Self::store_written(instruction, &self.stack), - // ); - // } if let Err(e) = gasometer.verify_gas(&requirements.gas_cost) { return Err(InterpreterResult::Done(Err(e))); @@ -1324,19 +1304,6 @@ impl Interpreter { let b = self.stack.pop_back(); self.stack.push( if !b.is_zero() { - // match b { - // ONE => a, - // TWO => a >> 1, - // TWO_POW_5 => a >> 5, - // TWO_POW_8 => a >> 8, - // TWO_POW_16 => a >> 16, - // TWO_POW_24 => a >> 24, - // TWO_POW_64 => a >> 64, - // TWO_POW_96 => a >> 96, - // TWO_POW_224 => a >> 224, - // TWO_POW_248 => a >> 248, - // _ => a / b, - // } if b == ONE { a } else if b == TWO { @@ -1582,6 +1549,10 @@ impl Interpreter { }; self.stack.push(result); } + instructions::CLZ => { + let value = self.stack.pop_back(); + self.stack.push(U256::from(value.leading_zeros())) + } }; Ok(InstructionResult::Ok) } diff --git a/crates/execution/vm-interpreter/src/lib.rs b/crates/execution/vm-interpreter/src/lib.rs index 3937ef9f42..895d42aa5d 100644 --- a/crates/execution/vm-interpreter/src/lib.rs +++ b/crates/execution/vm-interpreter/src/lib.rs @@ -4,6 +4,8 @@ #[macro_use] extern crate log; +#[macro_use] +extern crate lazy_static; mod evm; #[macro_use] @@ -11,8 +13,6 @@ pub mod factory; pub mod instructions; mod interpreter; mod vmtype; -#[macro_use] -extern crate lazy_static; #[cfg(test)] mod tests; diff --git a/crates/execution/vm-types/src/context.rs b/crates/execution/vm-types/src/context.rs index 2190174350..19827ccc34 100644 --- a/crates/execution/vm-types/src/context.rs +++ b/crates/execution/vm-types/src/context.rs @@ -173,28 +173,6 @@ pub trait Context { fn is_warm_storage_entry(&self, key: &H256) -> Result; - // /// Decide if any more operations should be traced. Passthrough for the - // VM /// trace. - // fn trace_next_instruction( - // &mut self, _pc: usize, _instruction: u8, _current_gas: U256, - // ) -> bool { - // false - // } - - // /// Prepare to trace an operation. Passthrough for the VM trace. - // fn trace_prepare_execute( - // &mut self, _pc: usize, _instruction: u8, _gas_cost: U256, - // _mem_written: Option<(usize, usize)>, - // _store_written: Option<(U256, U256)>, - // ) { - // } - - // /// Trace the finalised execution of a single instruction. - // fn trace_executed( - // &mut self, _gas_used: U256, _stack_push: &[U256], _mem: &[u8], - // ) { - // } - fn trace_step(&mut self, interpreter: &dyn InterpreterInfo) { let _ = interpreter; } diff --git a/crates/execution/vm-types/src/spec.rs b/crates/execution/vm-types/src/spec.rs index 64593d8c2c..263140bde7 100644 --- a/crates/execution/vm-types/src/spec.rs +++ b/crates/execution/vm-types/src/spec.rs @@ -204,6 +204,8 @@ pub struct Spec { pub eip7623: bool, pub align_evm: bool, pub cip_c2_fix: bool, + /// EIP-7939: Count Leading Zeros Instruction + pub eip7939: bool, } /// Represents the feature flags for CIP-645 implementation. @@ -415,6 +417,7 @@ impl Spec { eip7623: false, cip_c2_fix: false, align_evm: false, + eip7939: false, } } diff --git a/crates/execution/vm-types/src/tests.rs b/crates/execution/vm-types/src/tests.rs index d0bbd9a365..c8ecffc526 100644 --- a/crates/execution/vm-types/src/tests.rs +++ b/crates/execution/vm-types/src/tests.rs @@ -249,12 +249,6 @@ impl Context for MockContext { // reentrancy check. fn is_static_or_reentrancy(&self) -> bool { self.is_static } - // fn trace_next_instruction( - // &mut self, _pc: usize, _instruction: u8, _gas: U256, - // ) -> bool { - // self.tracing - // } - fn space(&self) -> Space { Space::Native } fn blockhash_source(&self) -> BlockHashSource { BlockHashSource::Env } From 66f62ec7f0aac22aa31cd17100b81c2328039876 Mon Sep 17 00:00:00 2001 From: Pana Date: Tue, 28 Oct 2025 14:09:25 +0800 Subject: [PATCH 2/4] reuse code --- crates/execution/vm-interpreter/src/instructions.rs | 10 +++++----- .../execution/vm-interpreter/src/interpreter/mod.rs | 12 ------------ 2 files changed, 5 insertions(+), 17 deletions(-) diff --git a/crates/execution/vm-interpreter/src/instructions.rs b/crates/execution/vm-interpreter/src/instructions.rs index 5a5753d5e3..68558cc60f 100644 --- a/crates/execution/vm-interpreter/src/instructions.rs +++ b/crates/execution/vm-interpreter/src/instructions.rs @@ -434,14 +434,14 @@ impl Instruction { pub fn info( &self, cip645: bool, eip7939: bool, ) -> &InstructionInfo { - let instrs = if !CANCUN { - &*INSTRUCTIONS - } else if eip7939 { + let instrs = if eip7939 { &*INSTRUCTIONS_EIP7939 - } else if !cip645 { + } else if cip645 { + &*INSTRUCTIONS_CIP645 + } else if CANCUN { &*INSTRUCTIONS_CANCUN } else { - &*INSTRUCTIONS_CIP645 + &*INSTRUCTIONS }; instrs[*self as usize].as_ref().expect("A instruction is defined in Instruction enum, but it is not found in InstructionInfo struct; this indicates a logic failure in the code.") diff --git a/crates/execution/vm-interpreter/src/interpreter/mod.rs b/crates/execution/vm-interpreter/src/interpreter/mod.rs index 4cee9eb2fb..a17583565a 100644 --- a/crates/execution/vm-interpreter/src/interpreter/mod.rs +++ b/crates/execution/vm-interpreter/src/interpreter/mod.rs @@ -395,18 +395,6 @@ impl Interpreter { + *gas; } - // if self.do_trace { - // context.trace_executed( - // self.gasometer - // .as_mut() - // .expect(GASOMETER_PROOF) - // .current_gas - // .as_u256(), - // self.stack.peek_top(self.last_stack_ret_len), - // &self.mem, - // ); - // } - // Advance match result { InstructionResult::JumpToPosition(position) => { From f4e149c4d88d9f4c5bc749da79be31d45d2b9231 Mon Sep 17 00:00:00 2001 From: Pana Date: Tue, 28 Oct 2025 14:44:46 +0800 Subject: [PATCH 3/4] update activate logic --- crates/config/src/configuration.rs | 2 +- crates/execution/executor/src/spec.rs | 6 +++--- crates/execution/vm-interpreter/src/instructions.rs | 12 ++++++------ 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/crates/config/src/configuration.rs b/crates/config/src/configuration.rs index 8086a95d26..30c9a038f4 100644 --- a/crates/config/src/configuration.rs +++ b/crates/config/src/configuration.rs @@ -1552,7 +1552,7 @@ impl Configuration { self.raw_conf.align_evm_transition_height; // hardfork (V3.1) - params.transition_numbers.eip7939 = self + params.transition_heights.eip7939 = self .raw_conf .eip7939_transition_number .unwrap_or(default_transition_time); diff --git a/crates/execution/executor/src/spec.rs b/crates/execution/executor/src/spec.rs index ea8af4ce16..b971ebc803 100644 --- a/crates/execution/executor/src/spec.rs +++ b/crates/execution/executor/src/spec.rs @@ -115,8 +115,6 @@ pub struct TransitionsBlockNumber { pub cip144: BlockNumber, /// CIP-145: Fix Receipts upon `NotEnoughBalance` Error pub cip145: BlockNumber, - /// EIP-7939: Count Leading Zeros Instruction - pub eip7939: BlockHeight, } #[derive(Default, Debug, Clone)] @@ -160,6 +158,8 @@ pub struct TransitionsEpochHeight { pub eip7623: BlockHeight, pub cip_c2_fix: BlockHeight, pub cip145_fix: BlockHeight, + /// EIP-7939: Count Leading Zeros Instruction + pub eip7939: BlockHeight, } impl Default for CommonParams { @@ -231,7 +231,7 @@ impl CommonParams { spec.cip_c2_fix = height >= self.transition_heights.cip_c2_fix; spec.cancun_opcodes = number >= self.transition_numbers.cancun_opcodes; spec.align_evm = height >= self.transition_heights.align_evm && cip645; - spec.eip7939 = number >= self.transition_numbers.eip7939; + spec.eip7939 = height >= self.transition_heights.eip7939; spec.overwrite_gas_plan_by_cip(); diff --git a/crates/execution/vm-interpreter/src/instructions.rs b/crates/execution/vm-interpreter/src/instructions.rs index 68558cc60f..5ce57536de 100644 --- a/crates/execution/vm-interpreter/src/instructions.rs +++ b/crates/execution/vm-interpreter/src/instructions.rs @@ -434,14 +434,14 @@ impl Instruction { pub fn info( &self, cip645: bool, eip7939: bool, ) -> &InstructionInfo { - let instrs = if eip7939 { - &*INSTRUCTIONS_EIP7939 - } else if cip645 { - &*INSTRUCTIONS_CIP645 - } else if CANCUN { + let instrs = if !CANCUN { + &*INSTRUCTIONS + } else if !cip645 { &*INSTRUCTIONS_CANCUN + } else if !eip7939 { + &*INSTRUCTIONS_CIP645 } else { - &*INSTRUCTIONS + &*INSTRUCTIONS_EIP7939 }; instrs[*self as usize].as_ref().expect("A instruction is defined in Instruction enum, but it is not found in InstructionInfo struct; this indicates a logic failure in the code.") From 4e6fac9b419309f0d80e2e0398a13adf435b5c0c Mon Sep 17 00:00:00 2001 From: Pana Date: Thu, 30 Oct 2025 17:25:23 +0800 Subject: [PATCH 4/4] disable eip7939 by default --- crates/config/src/configuration.rs | 8 +++----- docs/commands/evm-spec-tester.md | 3 +++ 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/crates/config/src/configuration.rs b/crates/config/src/configuration.rs index 30c9a038f4..bd0afeb87b 100644 --- a/crates/config/src/configuration.rs +++ b/crates/config/src/configuration.rs @@ -202,7 +202,7 @@ build_config! { // For test only (align_evm_transition_height, (u64), u64::MAX) // V3.1 - (eip7939_transition_number, (Option), None) + (eip7939_transition_height, (Option), None) // Mining section. @@ -1552,10 +1552,8 @@ impl Configuration { self.raw_conf.align_evm_transition_height; // hardfork (V3.1) - params.transition_heights.eip7939 = self - .raw_conf - .eip7939_transition_number - .unwrap_or(default_transition_time); + params.transition_heights.eip7939 = + self.raw_conf.eip7939_transition_height.unwrap_or(u64::MAX); // Disabled by default } } diff --git a/docs/commands/evm-spec-tester.md b/docs/commands/evm-spec-tester.md index ba1a917888..b6b7c5ba62 100644 --- a/docs/commands/evm-spec-tester.md +++ b/docs/commands/evm-spec-tester.md @@ -44,6 +44,9 @@ One copy of the state test cases is included in the `testdata` directory. Which cd testdata # make sure you have zstd installed tar --use-compress-program="zstd --long=31" -xvf evm-spec-test.tar.zst +# or decompress in two steps +zstd -k -d --long=31 evm-spec-test.tar.zst +tar -xvf evm-spec-test.tar ``` ### How to run the statetest