Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -280,3 +281,20 @@ func enable7702(jt *JumpTable) {
jt[STATICCALL].dynamicGas = gasStaticCallEIP7702
jt[DELEGATECALL].dynamicGas = gasDelegateCallEIP7702
}

// 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: GasFastStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
}
}
40 changes: 40 additions & 0 deletions core/vm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
}
}
2 changes: 2 additions & 0 deletions core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
10 changes: 10 additions & 0 deletions core/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down
3 changes: 3 additions & 0 deletions core/vm/opcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ const (
SHL OpCode = 0x1b
SHR OpCode = 0x1c
SAR OpCode = 0x1d
CLZ OpCode = 0x1e

SHA3 OpCode = 0x20
)
Expand Down Expand Up @@ -255,6 +256,7 @@ var opCodeToString = map[OpCode]string{
SHL: "SHL",
SHR: "SHR",
SAR: "SAR",
CLZ: "CLZ",
ADDMOD: "ADDMOD",
MULMOD: "MULMOD",

Expand Down Expand Up @@ -430,6 +432,7 @@ var stringToOp = map[string]OpCode{
"SHL": SHL,
"SHR": SHR,
"SAR": SAR,
"CLZ": CLZ,
"ADDMOD": ADDMOD,
"MULMOD": MULMOD,
"SHA3": SHA3,
Expand Down
8 changes: 7 additions & 1 deletion params/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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),
}
}
2 changes: 1 addition & 1 deletion rollup/missing_header_fields/export-headers-toolkit/go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions rollup/missing_header_fields/export-headers-toolkit/go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
Loading