Skip to content

core/vm: implement EIP-7939: CLZ opcode #31989

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
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
16 changes: 16 additions & 0 deletions core/vm/eips.go
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,13 @@ func opBlobBaseFee(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
return nil, nil
}

func opCLZ(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
x := scope.Stack.pop()
// count leading zero bits in x
scope.Stack.push(new(uint256.Int).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 +310,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
44 changes: 44 additions & 0 deletions core/vm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -972,3 +972,47 @@ func TestPush(t *testing.T) {
}
}
}

func TestOpCLZ(t *testing.T) {
// set up once
evm := NewEVM(BlockContext{}, nil, params.TestChainConfig, Config{})

tests := []struct {
name string
inputHex string // hexadecimal input for clarity
want uint64 // expected CLZ result
}{
{"zero", "0x0", 256},
{"one", "0x1", 255},
{"all-ones (256 bits)", "0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0},
{"low-10-bytes ones", "0xffffffffff", 216}, // 10 bytes = 80 bits, so 256-80=176? Actually input is 0xffffffffff = 40 bits so 256-40=216
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {

// prepare a fresh stack and PC
stack := newstack()
pc := uint64(0)

// parse input
val := new(uint256.Int)
if _, err := fmt.Sscan(tc.inputHex, val); err != nil {
// fallback: try hex
val.SetFromHex(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)
}
})
}
}
6 changes: 6 additions & 0 deletions core/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ func newEOFInstructionSetForTesting() 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