From ab8a805e60fbf21c1b9e08e3b603beb5f9d0e372 Mon Sep 17 00:00:00 2001 From: georgehao Date: Mon, 20 Oct 2025 11:40:59 +0800 Subject: [PATCH 1/5] enable eip7939 opcode CLZ --- src/builder.rs | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/src/builder.rs b/src/builder.rs index bff0a29..a79d8df 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -61,6 +61,7 @@ impl DefaultScrollContext for ScrollContext { let mut cfg = CfgEnv::new_with_spec(spec); cfg.enable_eip7702 = spec >= ScrollSpecId::EUCLID; cfg.enable_eip7623 = spec >= ScrollSpecId::FEYNMAN; + cfg.enable_eip7939 = spec >= ScrollSpecId::GALILEO; Context::mainnet() .with_tx(ScrollTransaction::default()) @@ -81,6 +82,12 @@ pub trait FeynmanEipActivations: EuclidEipActivations { fn maybe_with_eip_7623(self) -> Self; } +/// Activates specific EIP's for Galileo. +pub trait GalileoEipActivations: FeynmanEipActivations { + /// Activates EIP-7939 if the spec is at least at Galileo. + fn maybe_with_eip_7939(self) -> Self; +} + impl EuclidEipActivations for ScrollContext { fn maybe_with_eip_7702(mut self) -> Self { self.cfg.enable_eip7702 = self.cfg.spec >= ScrollSpecId::EUCLID; @@ -95,5 +102,12 @@ impl FeynmanEipActivations for ScrollContext { } } +impl GalileoEipActivations for ScrollContext { + fn maybe_with_eip_7939(mut self) -> Self { + self.cfg.enable_eip7939 = self.cfg.spec >= ScrollSpecId::GALILEO; + self + } +} + pub type ScrollContext = Context, CfgEnv, DB, Journal, L1BlockInfo>; From f4c9cea7c04d153193e221e94a2d6fde52c2c118 Mon Sep 17 00:00:00 2001 From: georgehao Date: Mon, 20 Oct 2025 11:44:05 +0800 Subject: [PATCH 2/5] update --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f8e27a0..15fbe7f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # revm -revm = { git = "https://github.com/scroll-tech/revm", default-features = false, features = ["enable_eip7702", "enable_eip7623"] } +revm = { git = "https://github.com/scroll-tech/revm", default-features = false, features = ["enable_eip7702", "enable_eip7623", "enable_eip7939"] } revm-primitives = { git = "https://github.com/scroll-tech/revm", default-features = false } revm-inspector = { git = "https://github.com/scroll-tech/revm", default-features = false } From 2251a5eb3a7cd4dcaf6134e2af41684d1f975fb0 Mon Sep 17 00:00:00 2001 From: georgehao Date: Mon, 20 Oct 2025 18:12:53 +0800 Subject: [PATCH 3/5] update --- Cargo.toml | 2 +- src/builder.rs | 14 -------------- src/instructions.rs | 19 +++++++++++++++++++ 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 15fbe7f..f8e27a0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ license = "MIT OR Apache-2.0" [dependencies] # revm -revm = { git = "https://github.com/scroll-tech/revm", default-features = false, features = ["enable_eip7702", "enable_eip7623", "enable_eip7939"] } +revm = { git = "https://github.com/scroll-tech/revm", default-features = false, features = ["enable_eip7702", "enable_eip7623"] } revm-primitives = { git = "https://github.com/scroll-tech/revm", default-features = false } revm-inspector = { git = "https://github.com/scroll-tech/revm", default-features = false } diff --git a/src/builder.rs b/src/builder.rs index a79d8df..bff0a29 100644 --- a/src/builder.rs +++ b/src/builder.rs @@ -61,7 +61,6 @@ impl DefaultScrollContext for ScrollContext { let mut cfg = CfgEnv::new_with_spec(spec); cfg.enable_eip7702 = spec >= ScrollSpecId::EUCLID; cfg.enable_eip7623 = spec >= ScrollSpecId::FEYNMAN; - cfg.enable_eip7939 = spec >= ScrollSpecId::GALILEO; Context::mainnet() .with_tx(ScrollTransaction::default()) @@ -82,12 +81,6 @@ pub trait FeynmanEipActivations: EuclidEipActivations { fn maybe_with_eip_7623(self) -> Self; } -/// Activates specific EIP's for Galileo. -pub trait GalileoEipActivations: FeynmanEipActivations { - /// Activates EIP-7939 if the spec is at least at Galileo. - fn maybe_with_eip_7939(self) -> Self; -} - impl EuclidEipActivations for ScrollContext { fn maybe_with_eip_7702(mut self) -> Self { self.cfg.enable_eip7702 = self.cfg.spec >= ScrollSpecId::EUCLID; @@ -102,12 +95,5 @@ impl FeynmanEipActivations for ScrollContext { } } -impl GalileoEipActivations for ScrollContext { - fn maybe_with_eip_7939(mut self) -> Self { - self.cfg.enable_eip7939 = self.cfg.spec >= ScrollSpecId::GALILEO; - self - } -} - pub type ScrollContext = Context, CfgEnv, DB, Journal, L1BlockInfo>; diff --git a/src/instructions.rs b/src/instructions.rs index fd2c606..4cfa01c 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -69,6 +69,7 @@ where /// - `SELFDESTRUCT` /// - `MCOPY` /// - `DIFFICULTY` +/// - `CLZ` pub fn make_scroll_instruction_table( ) -> InstructionTable { let mut table = instruction_table::(); @@ -82,6 +83,7 @@ pub fn make_scroll_instruction_table, 0); table[opcode::MCOPY as usize] = Instruction::new(mcopy::, 0); table[opcode::DIFFICULTY as usize] = Instruction::new(difficulty::, 2); + table[opcode::CLZ as usize] = Instruction::new(clz::, 5); table } @@ -245,6 +247,23 @@ pub fn difficulty( push!(context.interpreter, DIFFICULTY); } +/// Implements the CLZ instruction +/// +/// EIP-7939 count leading zeros. +fn clz(context: InstructionContext<'_, H, WIRE>) { + let host = context.host; + let interpreter = context.interpreter; + if !host.cfg().spec().is_enabled_in(ScrollSpecId::GALILEO) { + interpreter.halt(InstructionResult::NotActivated); + return; + } + + popn_top!([], op1, context.interpreter); + + let leading_zeros = op1.leading_zeros(); + *op1 = U256::from(leading_zeros); +} + // HELPER FUNCTIONS // ================================================================================================ From 6357cf3e35511be249f28665f5fb405c27efb80d Mon Sep 17 00:00:00 2001 From: georgehao Date: Mon, 20 Oct 2025 19:33:42 +0800 Subject: [PATCH 4/5] add clz test --- src/instructions.rs | 65 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/src/instructions.rs b/src/instructions.rs index 4cfa01c..72d8e2e 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -279,7 +279,7 @@ fn compute_block_hash(chain_id: u64, block_number: u64) -> U256 { #[cfg(test)] mod tests { - use super::{compute_block_hash, make_scroll_instruction_table}; + use super::{clz, compute_block_hash, make_scroll_instruction_table}; use crate::{ builder::{DefaultScrollContext, ScrollContext}, instructions::HISTORY_STORAGE_ADDRESS, @@ -289,7 +289,7 @@ mod tests { use revm::{ bytecode::{opcode::*, Bytecode}, database::{EmptyDB, InMemoryDB}, - interpreter::Interpreter, + interpreter::{push, InstructionContext, Interpreter}, primitives::{Bytes, U256}, DatabaseRef, }; @@ -380,4 +380,65 @@ mod tests { let actual_gas_used = interpreter.gas.used(); assert_eq!(actual_gas_used, expected_gas_used); } + + #[test] + fn test_clz() { + use revm::primitives::uint; + + let spec = GALILEO; + let db = EmptyDB::new(); + let mut scroll_context = ScrollContext::scroll().with_db(InMemoryDB::new(db)); + scroll_context.modify_cfg(|cfg| cfg.spec = spec); + + let mut interpreter = Interpreter::default(); + + struct TestCase { + value: U256, + expected: U256, + } + + uint! { + let test_cases = [ + TestCase { value: 0x0_U256, expected: 256_U256 }, + TestCase { value: 0x1_U256, expected: 255_U256 }, + TestCase { value: 0x2_U256, expected: 254_U256 }, + TestCase { value: 0x3_U256, expected: 254_U256 }, + TestCase { value: 0x4_U256, expected: 253_U256 }, + TestCase { value: 0x7_U256, expected: 253_U256 }, + TestCase { value: 0x8_U256, expected: 252_U256 }, + TestCase { value: 0xff_U256, expected: 248_U256 }, + TestCase { value: 0x100_U256, expected: 247_U256 }, + TestCase { value: 0xffff_U256, expected: 240_U256 }, + TestCase { + value: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, // U256::MAX + expected: 0_U256, + }, + TestCase { + value: 0x8000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 255 + expected: 0_U256, + }, + TestCase { // Smallest value with 1 leading zero + value: 0x4000000000000000000000000000000000000000000000000000000000000000_U256, // 1 << 254 + expected: 1_U256, + }, + TestCase { // Value just below 1 << 255 + value: 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff_U256, + expected: 1_U256, + }, + ]; + } + + for test in test_cases { + push!(interpreter, test.value); + let context = + InstructionContext { host: &mut scroll_context, interpreter: &mut interpreter }; + clz(context); + let res = interpreter.stack.pop().unwrap(); + assert_eq!( + res, test.expected, + "CLZ for value {:#x} failed. Expected: {}, Got: {}", + test.value, test.expected, res + ); + } + } } From 10d8d9ac9db6b041275086786dbee4ed9b842ded Mon Sep 17 00:00:00 2001 From: georgehao Date: Tue, 21 Oct 2025 17:23:18 +0800 Subject: [PATCH 5/5] fix error --- src/instructions.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/instructions.rs b/src/instructions.rs index 72d8e2e..8aebd7a 100644 --- a/src/instructions.rs +++ b/src/instructions.rs @@ -258,7 +258,7 @@ fn clz(context: InstructionContext<' return; } - popn_top!([], op1, context.interpreter); + popn_top!([], op1, interpreter); let leading_zeros = op1.leading_zeros(); *op1 = U256::from(leading_zeros);