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

This commit is contained in:
Daniel Liu 2026-02-10 19:21:20 +08:00 committed by GitHub
parent 7dc82dde0f
commit ec697ddbdb
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 71 additions and 3 deletions

View file

@ -40,6 +40,7 @@ var activators = map[int]func(*JumpTable){
1344: enable1344,
1153: enable1153,
7702: enable7702,
7939: enable7939,
}
// EnableEIP enables the given EIP on the config.
@ -282,6 +283,13 @@ func opBlobBaseFee(pc *uint64, evm *EVM, scope *ScopeContext) ([]byte, error) {
return nil, nil
}
// opCLZ implements the CLZ opcode (count leading zero bits)
func opCLZ(pc *uint64, evm *EVM, 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{
@ -292,6 +300,16 @@ func enable4844(jt *JumpTable) {
}
}
// 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),
}
}
// enable7516 applies EIP-7516 (BLOBBASEFEE opcode)
func enable7516(jt *JumpTable) {
jt[BLOBBASEFEE] = &operation{

View file

@ -149,6 +149,8 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, tradingStat
evm.precompiles = activePrecompiledContracts(evm.chainRules)
switch {
case evm.chainRules.IsOsaka:
evm.table = &osakaInstructionSet
case evm.chainRules.IsPrague:
evm.table = &pragueInstructionSet
case evm.chainRules.IsCancun:

View file

@ -907,3 +907,43 @@ func TestOpMCopy(t *testing.T) {
}
}
}
func TestOpCLZ(t *testing.T) {
evm := NewEVM(BlockContext{}, TxContext{}, nil, 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, &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)
}
}
}

View file

@ -59,6 +59,7 @@ var (
eip1559InstructionSet = newEip1559InstructionSet()
cancunInstructionSet = newCancunInstructionSet()
pragueInstructionSet = newPragueInstructionSet()
osakaInstructionSet = newOsakaInstructionSet()
)
// JumpTable contains the EVM opcodes supported at a given fork.
@ -82,6 +83,12 @@ func validate(jt JumpTable) JumpTable {
return jt
}
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

View file

@ -17,8 +17,6 @@
package vm
import (
"errors"
"github.com/XinFinOrg/XDPoSChain/params"
)
@ -27,7 +25,7 @@ import (
func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
switch {
case rules.IsOsaka:
return newPragueInstructionSet(), errors.New("osaka-fork not defined yet")
return newOsakaInstructionSet(), nil
case rules.IsPrague:
return newPragueInstructionSet(), nil
case rules.IsCancun:

View file

@ -60,6 +60,7 @@ const (
SHL OpCode = 0x1b
SHR OpCode = 0x1c
SAR OpCode = 0x1d
CLZ OpCode = 0x1e
)
// 0x20 range - crypto.
@ -252,6 +253,7 @@ var opCodeToString = [256]string{
SHL: "SHL",
SHR: "SHR",
SAR: "SAR",
CLZ: "CLZ",
ADDMOD: "ADDMOD",
MULMOD: "MULMOD",
@ -431,6 +433,7 @@ var stringToOp = map[string]OpCode{
"SHL": SHL,
"SHR": SHR,
"SAR": SAR,
"CLZ": CLZ,
"ADDMOD": ADDMOD,
"MULMOD": MULMOD,
"KECCAK256": KECCAK256,