mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-22 20:56:42 +00:00
EIP7939: Count leading zeros (CLZ) opcode (#1246)
* Cherry pick eip7939 * sync latest
This commit is contained in:
parent
9aa8b3f38f
commit
9668c2c322
8 changed files with 82 additions and 2 deletions
|
|
@ -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.
|
||||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -69,6 +69,7 @@ const (
|
|||
SHL OpCode = 0x1b
|
||||
SHR OpCode = 0x1c
|
||||
SAR OpCode = 0x1d
|
||||
CLZ OpCode = 0x1e
|
||||
|
||||
SHA3 OpCode = 0x20
|
||||
)
|
||||
|
|
@ -255,6 +256,7 @@ var opCodeToString = map[OpCode]string{
|
|||
SHL: "SHL",
|
||||
SHR: "SHR",
|
||||
SAR: "SAR",
|
||||
CLZ: "CLZ",
|
||||
ADDMOD: "ADDMOD",
|
||||
MULMOD: "MULMOD",
|
||||
|
||||
|
|
@ -430,6 +432,7 @@ var stringToOp = map[string]OpCode{
|
|||
"SHL": SHL,
|
||||
"SHR": SHR,
|
||||
"SAR": SAR,
|
||||
"CLZ": CLZ,
|
||||
"ADDMOD": ADDMOD,
|
||||
"MULMOD": MULMOD,
|
||||
"SHA3": SHA3,
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
@ -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)
|
||||
|
|
@ -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.
|
||||
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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=
|
||||
|
|
|
|||
Loading…
Reference in a new issue