diff --git a/crates/config/src/configuration.rs b/crates/config/src/configuration.rs index a8d8227ca2..bd0afeb87b 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_height, (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,10 @@ impl Configuration { } params.transition_heights.align_evm = self.raw_conf.align_evm_transition_height; + + // hardfork (V3.1) + params.transition_heights.eip7939 = + self.raw_conf.eip7939_transition_height.unwrap_or(u64::MAX); // Disabled by default } } 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..b971ebc803 100644 --- a/crates/execution/executor/src/spec.rs +++ b/crates/execution/executor/src/spec.rs @@ -158,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 { @@ -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 = height >= self.transition_heights.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..5ce57536de 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,13 +431,17 @@ 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 !cip645 { &*INSTRUCTIONS_CANCUN - } else { + } else if !eip7939 { &*INSTRUCTIONS_CIP645 + } else { + &*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.") @@ -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..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) => { @@ -568,19 +556,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 +567,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 +589,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 +1292,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 +1537,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 } 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