mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-02-26 15:47:21 +00:00
core/vm: implement EIP-7939 - CLZ opcode (#31989)
https://eips.ethereum.org/EIPS/eip-7939 --------- Co-authored-by: spencer-tb <spencer@spencertaylorbrown.uk> Co-authored-by: Felix Lange <fjl@twurst.com>
This commit is contained in:
parent
bdf47f4557
commit
90c6197d2f
6 changed files with 70 additions and 1 deletions
|
|
@ -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.
|
||||
|
|
@ -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{
|
||||
|
|
@ -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{
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ var (
|
|||
cancunInstructionSet = newCancunInstructionSet()
|
||||
verkleInstructionSet = newVerkleInstructionSet()
|
||||
pragueInstructionSet = newPragueInstructionSet()
|
||||
osakaInstructionSet = newOsakaInstructionSet()
|
||||
)
|
||||
|
||||
// JumpTable contains the EVM opcodes supported at a given fork.
|
||||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ const (
|
|||
SHL OpCode = 0x1b
|
||||
SHR OpCode = 0x1c
|
||||
SAR OpCode = 0x1d
|
||||
CLZ OpCode = 0x1e
|
||||
)
|
||||
|
||||
// 0x20 range - crypto.
|
||||
|
|
@ -282,6 +283,7 @@ var opCodeToString = [256]string{
|
|||
SHL: "SHL",
|
||||
SHR: "SHR",
|
||||
SAR: "SAR",
|
||||
CLZ: "CLZ",
|
||||
ADDMOD: "ADDMOD",
|
||||
MULMOD: "MULMOD",
|
||||
|
||||
|
|
@ -484,6 +486,7 @@ var stringToOp = map[string]OpCode{
|
|||
"SHL": SHL,
|
||||
"SHR": SHR,
|
||||
"SAR": SAR,
|
||||
"CLZ": CLZ,
|
||||
"ADDMOD": ADDMOD,
|
||||
"MULMOD": MULMOD,
|
||||
"KECCAK256": KECCAK256,
|
||||
|
|
|
|||
Loading…
Reference in a new issue