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
17 changes: 17 additions & 0 deletions core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ var activators = map[int]func(*JumpTable){
1153: enable1153,
4762: enable4762,
7702: enable7702,
7939: enable7939,
}

// EnableEIP enables the given EIP on the config.
Expand Down Expand Up @@ -293,6 +294,13 @@ func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
return nil, nil
}

// 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
}

// enable4844 applies EIP-4844 (BLOBHASH opcode)
func enable4844(jt *JumpTable) {
jt[BLOBHASH] = &operation{
Expand All @@ -303,6 +311,15 @@ func enable4844(jt *JumpTable) {
}
}

func enable7939(jt *JumpTable) {
jt[CLZ] = &operation{
execute: opCLZ,
constantGas: GasFastestStep,
minStack: minStack(1, 1),
maxStack: maxStack(1, 1),
}
}

// enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
func enable7516(jt *JumpTable) {
jt[BLOBBASEFEE] = &operation{
Expand Down
40 changes: 40 additions & 0 deletions core/vm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,3 +972,43 @@ func TestPush(t *testing.T) {
}
}
}

func TestOpCLZ(t *testing.T) {
evm := NewEVM(BlockContext{}, 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 @@ -106,6 +106,8 @@ func NewEVMInterpreter(evm *EVM) *EVMInterpreter {
// If jump table was not initialised we set the default one.
var table *JumpTable
switch {
case evm.chainRules.IsOsaka:
table = &osakaInstructionSet
case evm.chainRules.IsVerkle:
// TODO replace with proper instruction set when fork is specified
table = &verkleInstructionSet
Expand Down
7 changes: 7 additions & 0 deletions core/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ var (
cancunInstructionSet = newCancunInstructionSet()
verkleInstructionSet = newVerkleInstructionSet()
pragueInstructionSet = newPragueInstructionSet()
osakaInstructionSet = newOsakaInstructionSet()
)

// JumpTable contains the EVM opcodes supported at a given fork.
Expand Down Expand Up @@ -91,6 +92,12 @@ func newVerkleInstructionSet() JumpTable {
return validate(instructionSet)
}

func newOsakaInstructionSet() JumpTable {
instructionSet := newPragueInstructionSet()
enable7939(&instructionSet) // EIP-7939 (CLZ opcode)
return validate(instructionSet)
}

func newPragueInstructionSet() JumpTable {
instructionSet := newCancunInstructionSet()
enable7702(&instructionSet) // EIP-7702 Setcode transaction type
Expand Down
2 changes: 1 addition & 1 deletion core/vm/jump_table_export.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
case rules.IsVerkle:
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
case rules.IsOsaka:
return newPragueInstructionSet(), errors.New("osaka-fork not defined yet")
return newOsakaInstructionSet(), nil
case rules.IsPrague:
return newPragueInstructionSet(), nil
case rules.IsCancun:
Expand Down
3 changes: 3 additions & 0 deletions core/vm/opcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ const (
SHL OpCode = 0x1b
SHR OpCode = 0x1c
SAR OpCode = 0x1d
CLZ OpCode = 0x1e
)

// 0x20 range - crypto.
Expand Down Expand Up @@ -282,6 +283,7 @@ var opCodeToString = [256]string{
SHL: "SHL",
SHR: "SHR",
SAR: "SAR",
CLZ: "CLZ",
ADDMOD: "ADDMOD",
MULMOD: "MULMOD",

Expand Down Expand Up @@ -484,6 +486,7 @@ var stringToOp = map[string]OpCode{
"SHL": SHL,
"SHR": SHR,
"SAR": SAR,
"CLZ": CLZ,
"ADDMOD": ADDMOD,
"MULMOD": MULMOD,
"KECCAK256": KECCAK256,
Expand Down