From 4e0a251efe37a613bb3e3ea26191384c8f08cf47 Mon Sep 17 00:00:00 2001 From: georgehao Date: Mon, 13 Oct 2025 18:14:02 +0800 Subject: [PATCH 1/2] Cherry pick eip7939 --- core/vm/eips.go | 17 ++++++++ core/vm/instructions_test.go | 40 +++++++++++++++++++ core/vm/interpreter.go | 2 + core/vm/jump_table.go | 10 +++++ core/vm/opcodes.go | 3 ++ params/config.go | 8 +++- .../export-headers-toolkit/go.mod | 2 +- .../export-headers-toolkit/go.sum | 1 + 8 files changed, 81 insertions(+), 2 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 829c3206a32..0d30b255e07 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -39,6 +39,7 @@ var activators = map[int]func(*JumpTable){ 1344: enable1344, 1153: enable1153, 7702: enable7702, + 7939: enable7939, } // EnableEIP enables the given EIP on the config. @@ -280,3 +281,19 @@ func enable7702(jt *JumpTable) { jt[STATICCALL].dynamicGas = gasStaticCallEIP7702 jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702 } + +// opCLZ implements the CLZ opcode (count leading zero bytes) +func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { + x := scope.Stack.peek() + x.SetUint64(256 - uint64(x.BitLen())) + return nil, nil +} + +func enable7939(jt *JumpTable) { + jt[CLZ] = &operation{ + execute: opCLZ, + constantGas: GasFastestStep, + minStack: minStack(1, 1), + maxStack: maxStack(1, 1), + } +} diff --git a/core/vm/instructions_test.go b/core/vm/instructions_test.go index 513222b3053..a8b3e420657 100644 --- a/core/vm/instructions_test.go +++ b/core/vm/instructions_test.go @@ -848,3 +848,43 @@ func TestOpMCopy(t *testing.T) { } } } + +func TestOpCLZ(t *testing.T) { + evm := NewEVM(BlockContext{}, TxContext{}, nil, params.TestChainConfig, Config{}) + + tests := []struct { + inputHex string + want uint64 // expected CLZ result + }{ + {"0x0", 256}, + {"0x1", 255}, + {"0x6ff", 245}, // 0x6ff = 0b11011111111 (11 bits), so 256-11 = 245 + {"0xffffffffff", 216}, // 40 bits, so 256-40 = 216 + {"0x4000000000000000000000000000000000000000000000000000000000000000", 1}, + {"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 1}, + {"0x8000000000000000000000000000000000000000000000000000000000000000", 0}, + {"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0}, + } + for _, tc := range tests { + // prepare a fresh stack and PC + stack := newstack() + pc := uint64(0) + + // parse input + val := new(uint256.Int) + if err := val.SetFromHex(tc.inputHex); err != nil { + t.Fatal("invalid hex uint256:", tc.inputHex) + } + + stack.push(val) + opCLZ(&pc, evm.interpreter, &ScopeContext{Stack: stack}) + + if gotLen := stack.len(); gotLen != 1 { + t.Fatalf("stack length = %d; want 1", gotLen) + } + result := stack.pop() + if got := result.Uint64(); got != tc.want { + t.Fatalf("clz(%q) = %d; want %d", tc.inputHex, got, tc.want) + } + } +} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 28b5972e7d8..beee422a2b0 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -74,6 +74,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { if cfg.JumpTable[STOP] == nil { var jt JumpTable switch { + case evm.chainRules.IsGalileo: + jt = galileoInstructionSet case evm.chainRules.IsFeynman: jt = feynmanInstructionSet case evm.chainRules.IsEuclidV2: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 92a1a8c7900..f3010c9da43 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -63,11 +63,21 @@ var ( darwinInstructionSet = newDarwinInstructionSet() euclidV2InstructionSet = newEuclidV2InstructionSet() feynmanInstructionSet = newFeynmanInstructionSet() + galileoInstructionSet = newGalileoInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. type JumpTable [256]*operation +// newGalileoInstructionSet returns the frontier, homestead, byzantium, +// contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin, euclidV2, +// feynman and galileo instructions. +func newGalileoInstructionSet() JumpTable { + instructionSet := newFeynmanInstructionSet() + enable7939(&instructionSet) // EIP-7939 (CLZ opcode) + return instructionSet +} + // newFeynmanInstructionSet returns the frontier, homestead, byzantium, // contantinople, istanbul, petersburg, berlin, london, shanghai, curie, darwin, euclidV2, // and feynman instructions. diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index c4ced9ad55b..e5297902889 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -69,6 +69,7 @@ const ( SHL OpCode = 0x1b SHR OpCode = 0x1c SAR OpCode = 0x1d + CLZ OpCode = 0x1e SHA3 OpCode = 0x20 ) @@ -255,6 +256,7 @@ var opCodeToString = map[OpCode]string{ SHL: "SHL", SHR: "SHR", SAR: "SAR", + CLZ: "CLZ", ADDMOD: "ADDMOD", MULMOD: "MULMOD", @@ -430,6 +432,7 @@ var stringToOp = map[string]OpCode{ "SHL": SHL, "SHR": SHR, "SAR": SAR, + "CLZ": CLZ, "ADDMOD": ADDMOD, "MULMOD": MULMOD, "SHA3": SHA3, diff --git a/params/config.go b/params/config.go index 04584f8e890..3d18fedb608 100644 --- a/params/config.go +++ b/params/config.go @@ -670,6 +670,7 @@ type ChainConfig struct { EuclidTime *uint64 `json:"euclidTime,omitempty"` // Euclid switch time (nil = no fork, 0 = already on euclid) EuclidV2Time *uint64 `json:"euclidv2Time,omitempty"` // EuclidV2 switch time (nil = no fork, 0 = already on euclidv2) FeynmanTime *uint64 `json:"feynmanTime,omitempty"` // Feynman switch time (nil = no fork, 0 = already on feynman) + GalileoTime *uint64 `json:"galileoTime,omitempty"` // Galileo switch time (nil = no fork, 0 = already on galileo) // TerminalTotalDifficulty is the amount of total difficulty reached by // the network that triggers the consensus upgrade. @@ -1014,6 +1015,10 @@ func (c *ChainConfig) IsFeynman(now uint64) bool { return isForkedTime(now, c.FeynmanTime) } +func (c *ChainConfig) IsGalileo(now uint64) bool { + return isForkedTime(now, c.GalileoTime) +} + // IsFeynmanTransitionBlock returns whether the given block timestamp corresponds to the first Feynman block. func (c *ChainConfig) IsFeynmanTransitionBlock(blockTimestamp uint64, parentTimestamp uint64) bool { return isForkedTime(blockTimestamp, c.FeynmanTime) && !isForkedTime(parentTimestamp, c.FeynmanTime) @@ -1247,7 +1252,7 @@ type Rules struct { IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon, IsArchimedes, IsShanghai bool IsBernoulli, IsCurie, IsDarwin, IsEuclid, IsEuclidV2 bool - IsFeynman bool + IsFeynman, IsGalileo bool } // Rules ensures c's ChainID is not nil. @@ -1276,5 +1281,6 @@ func (c *ChainConfig) Rules(num *big.Int, time uint64) Rules { IsEuclid: c.IsEuclid(time), IsEuclidV2: c.IsEuclidV2(time), IsFeynman: c.IsFeynman(time), + IsGalileo: c.IsGalileo(time), } } diff --git a/rollup/missing_header_fields/export-headers-toolkit/go.mod b/rollup/missing_header_fields/export-headers-toolkit/go.mod index ba453d6830c..76667dac62a 100644 --- a/rollup/missing_header_fields/export-headers-toolkit/go.mod +++ b/rollup/missing_header_fields/export-headers-toolkit/go.mod @@ -5,7 +5,7 @@ go 1.22 replace github.com/scroll-tech/go-ethereum => ../../.. require ( - github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6 + github.com/scroll-tech/da-codec v0.1.3-0.20250825071838-cddc263e5ef6 github.com/scroll-tech/go-ethereum v1.10.14-0.20250625112225-a67863c65587 github.com/spf13/cobra v1.9.1 github.com/stretchr/testify v1.10.0 diff --git a/rollup/missing_header_fields/export-headers-toolkit/go.sum b/rollup/missing_header_fields/export-headers-toolkit/go.sum index ae95e7a7f7a..6264c393aa1 100644 --- a/rollup/missing_header_fields/export-headers-toolkit/go.sum +++ b/rollup/missing_header_fields/export-headers-toolkit/go.sum @@ -173,6 +173,7 @@ github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQD github.com/scroll-tech/da-codec v0.1.3-0.20250313120912-344f2d5e33e1 h1:Dhd58LE1D+dnoxpgLVeQBMF9uweL/fhQfZHWtWSiOlE= github.com/scroll-tech/da-codec v0.1.3-0.20250313120912-344f2d5e33e1/go.mod h1:yhTS9OVC0xQGhg7DN5iV5KZJvnSIlFWAxDdp+6jxQtY= github.com/scroll-tech/da-codec v0.1.3-0.20250626091118-58b899494da6/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= +github.com/scroll-tech/da-codec v0.1.3-0.20250825071838-cddc263e5ef6/go.mod h1:Z6kN5u2khPhiqHyk172kGB7o38bH/nj7Ilrb/46wZGg= github.com/scroll-tech/zktrie v0.8.4 h1:UagmnZ4Z3ITCk+aUq9NQZJNAwnWl4gSxsLb2Nl7IgRE= github.com/scroll-tech/zktrie v0.8.4/go.mod h1:XvNo7vAk8yxNyTjBDj5WIiFzYW4bx/gJ78+NK6Zn6Uk= github.com/shirou/gopsutil v3.21.11+incompatible h1:+1+c1VGhc88SSonWP6foOcLhvnKlUeu/erjjvaPEYiI= From 310e4881f5157e2a7cca2ed2fec6dcfb2dd16735 Mon Sep 17 00:00:00 2001 From: georgehao Date: Fri, 17 Oct 2025 10:40:53 +0800 Subject: [PATCH 2/2] sync latest --- core/vm/eips.go | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 0d30b255e07..1e0754afca1 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -282,17 +282,18 @@ func enable7702(jt *JumpTable) { jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702 } -// opCLZ implements the CLZ opcode (count leading zero bytes) +// opCLZ implements the CLZ opcode (count leading zero bits) func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) { x := scope.Stack.peek() x.SetUint64(256 - uint64(x.BitLen())) return nil, nil } +// enable7939 enables EIP-7939 (CLZ opcode) func enable7939(jt *JumpTable) { jt[CLZ] = &operation{ execute: opCLZ, - constantGas: GasFastestStep, + constantGas: GasFastStep, minStack: minStack(1, 1), maxStack: maxStack(1, 1), }