Skip to content

Commit bdd8dba

Browse files
authored
Merge pull request #2416 from CortexFoundation/dev
clz
2 parents c5a4d0d + 78d1949 commit bdd8dba

6 files changed

Lines changed: 93 additions & 4 deletions

File tree

core/vm/eips.go

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ var activators = map[int]func(*JumpTable){
3030
2200: enable2200,
3131
1884: enable1884,
3232
1344: enable1344,
33+
7939: enable7939,
3334
}
3435

3536
// EnableEIP enables the given EIP on the config.
@@ -49,6 +50,21 @@ func EnableEIP(eipNum int, jt *JumpTable) error {
4950
return nil
5051
}
5152

53+
// opCLZ implements the CLZ opcode (count leading zero bytes)
54+
func opCLZ(pc *uint64, interpreter *CVMInterpreter, scope *ScopeContext) ([]byte, error) {
55+
x := scope.Stack.peek()
56+
x.SetUint64(256 - uint64(x.BitLen()))
57+
return nil, nil
58+
}
59+
60+
func enable7939(jt *JumpTable) {
61+
jt[CLZ] = &operation{
62+
execute: opCLZ,
63+
gasCost: constGasFunc(GasFastestStep),
64+
validateStack: makeStackFunc(1, 1),
65+
}
66+
}
67+
5268
// enable5656 enables EIP-5656 (MCOPY opcode)
5369
// https://eips.cortex.org/EIPS/eip-5656
5470
func enable5656(jt *JumpTable) {

core/vm/instructions_test.go

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -721,3 +721,43 @@ func TestPush(t *testing.T) {
721721
}
722722
}
723723
}
724+
725+
func TestOpCLZ(t *testing.T) {
726+
evm := NewCVM(BlockContext{}, nil, params.TestChainConfig, Config{})
727+
728+
tests := []struct {
729+
inputHex string
730+
want uint64 // expected CLZ result
731+
}{
732+
{"0x0", 256},
733+
{"0x1", 255},
734+
{"0x6ff", 245}, // 0x6ff = 0b11011111111 (11 bits), so 256-11 = 245
735+
{"0xffffffffff", 216}, // 40 bits, so 256-40 = 216
736+
{"0x4000000000000000000000000000000000000000000000000000000000000000", 1},
737+
{"0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 1},
738+
{"0x8000000000000000000000000000000000000000000000000000000000000000", 0},
739+
{"0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff", 0},
740+
}
741+
for _, tc := range tests {
742+
// prepare a fresh stack and PC
743+
stack := newstack()
744+
pc := uint64(0)
745+
746+
// parse input
747+
val := new(uint256.Int)
748+
if err := val.SetFromHex(tc.inputHex); err != nil {
749+
t.Fatal("invalid hex uint256:", tc.inputHex)
750+
}
751+
752+
stack.push(val)
753+
opCLZ(&pc, evm.interpreter, &ScopeContext{Stack: stack})
754+
755+
if gotLen := stack.len(); gotLen != 1 {
756+
t.Fatalf("stack length = %d; want 1", gotLen)
757+
}
758+
result := stack.pop()
759+
if got := result.Uint64(); got != tc.want {
760+
t.Fatalf("clz(%q) = %d; want %d", tc.inputHex, got, tc.want)
761+
}
762+
}
763+
}

core/vm/interpreter.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ func NewCVMInterpreter(cvm *CVM) *CVMInterpreter {
8585
// If jump table was not initialised we set the default one.
8686
var table *JumpTable
8787
switch {
88+
case cvm.chainRules.IsOsaka:
89+
table = &osakaInstructionSet
8890
case cvm.chainRules.IsMerge:
8991
table = &mergeInstructionSet
9092
case cvm.chainRules.IsNeo:

core/vm/jump_table.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ var (
5353
neoInstructionSet = newNeoInstructionSet()
5454

5555
mergeInstructionSet = newMergeInstructionSet()
56+
osakaInstructionSet = newOsakaInstructionSet()
5657
)
5758

5859
// JumpTable contains the CVM opcodes supported at a given fork.
@@ -67,6 +68,12 @@ func validate(jt JumpTable) JumpTable {
6768
return jt
6869
}
6970

71+
func newOsakaInstructionSet() JumpTable {
72+
instructionSet := newMergeInstructionSet()
73+
enable7939(&instructionSet) // EIP-7939 (CLZ opcode)
74+
return validate(instructionSet)
75+
}
76+
7077
func newMergeInstructionSet() JumpTable {
7178
instructionSet := newNeoInstructionSet()
7279
instructionSet[PREVRANDAO] = &operation{

core/vm/opcodes.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ const (
5959
SHL OpCode = 0x1b
6060
SHR OpCode = 0x1c
6161
SAR OpCode = 0x1d
62+
CLZ OpCode = 0x1e
6263
)
6364

6465
// 0x20 range - crypto.
@@ -248,6 +249,7 @@ var opCodeToString = [256]string{
248249
SHL: "SHL",
249250
SHR: "SHR",
250251
SAR: "SAR",
252+
CLZ: "CLZ",
251253
ADDMOD: "ADDMOD",
252254
MULMOD: "MULMOD",
253255

@@ -426,6 +428,7 @@ var stringToOp = map[string]OpCode{
426428
"SHL": SHL,
427429
"SHR": SHR,
428430
"SAR": SAR,
431+
"CLZ": CLZ,
429432
"ADDMOD": ADDMOD,
430433
"MULMOD": MULMOD,
431434
"KECCAK256": KECCAK256,

params/config.go

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -131,6 +131,8 @@ var (
131131
PetersburgBlock: big.NewInt(0),
132132
IstanbulBlock: big.NewInt(3_230_000),
133133
NeoBlock: big.NewInt(4_650_000),
134+
MergeBlock: nil,
135+
OsakaTime: nil,
134136
TerminalTotalDifficulty: nil,
135137
TerminalTotalDifficultyPassed: false,
136138
Cuckoo: new(CuckooConfig),
@@ -151,6 +153,8 @@ var (
151153
PetersburgBlock: big.NewInt(0),
152154
IstanbulBlock: big.NewInt(0),
153155
NeoBlock: big.NewInt(5_000_000),
156+
MergeBlock: nil,
157+
OsakaTime: nil,
154158
TerminalTotalDifficulty: nil,
155159
TerminalTotalDifficultyPassed: false,
156160
Clique: &CliqueConfig{
@@ -174,6 +178,8 @@ var (
174178
PetersburgBlock: big.NewInt(0),
175179
IstanbulBlock: big.NewInt(0),
176180
NeoBlock: big.NewInt(0),
181+
MergeBlock: nil,
182+
OsakaTime: nil,
177183
TerminalTotalDifficulty: nil,
178184
TerminalTotalDifficultyPassed: false,
179185
Cuckoo: new(CuckooConfig),
@@ -194,6 +200,8 @@ var (
194200
PetersburgBlock: big.NewInt(0),
195201
IstanbulBlock: big.NewInt(0),
196202
NeoBlock: big.NewInt(0),
203+
MergeBlock: nil,
204+
OsakaTime: nil,
197205
TerminalTotalDifficulty: nil,
198206
TerminalTotalDifficultyPassed: false,
199207
Clique: &CliqueConfig{
@@ -221,6 +229,8 @@ var (
221229
PetersburgBlock: big.NewInt(0),
222230
IstanbulBlock: nil,
223231
NeoBlock: nil,
232+
MergeBlock: nil,
233+
OsakaTime: nil,
224234
TerminalTotalDifficulty: nil,
225235
TerminalTotalDifficultyPassed: false,
226236
Cuckoo: new(CuckooConfig),
@@ -231,9 +241,9 @@ var (
231241
//
232242
// This configuration is intentionally not using keyed fields to force anyone
233243
// adding flags to the config to also have to set these fields.
234-
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
244+
AllCliqueProtocolChanges = &ChainConfig{big.NewInt(1337), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, false, nil, &CliqueConfig{Period: 0, Epoch: 30000}}
235245

236-
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, false, new(CuckooConfig), nil}
246+
TestChainConfig = &ChainConfig{big.NewInt(1), big.NewInt(0), nil, false, big.NewInt(0), common.Hash{}, big.NewInt(0), big.NewInt(0), big.NewInt(0), big.NewInt(0), nil, nil, nil, nil, nil, nil, false, new(CuckooConfig), nil}
237247
TestRules = TestChainConfig.Rules(new(big.Int), false, 0)
238248
)
239249

@@ -269,6 +279,8 @@ type ChainConfig struct {
269279
PetersburgBlock *big.Int `json:"petersburgBlock,omitempty"` // Petersburg switch block (nil = same as Constantinople)
270280
IstanbulBlock *big.Int `json:"istanbulBlock,omitempty"` // Istanbul switch block (nil = no fork, 0 = already on istanbul)
271281
NeoBlock *big.Int `json:"neoBlock,omitempty"`
282+
MergeBlock *big.Int `json:"mergeBlock,omitempty"`
283+
OsakaTime *uint64 `json:"osakaTime,omitempty"` // Osaka switch time (nil = no fork, 0 = already on osaka)
272284
// TerminalTotalDifficulty is the amount of total difficulty reached by
273285
// the network that triggers the consensus upgrade.
274286
TerminalTotalDifficulty *big.Int `json:"terminalTotalDifficulty,omitempty"`
@@ -378,6 +390,10 @@ func (c *ChainConfig) IsNeo(num *big.Int) bool {
378390
return isForked(c.NeoBlock, num)
379391
}
380392

393+
func (c *ChainConfig) IsMerge(num *big.Int) bool {
394+
return isForked(c.MergeBlock, num)
395+
}
396+
381397
// IsTerminalPoWBlock returns whether the given block is the last block of PoW stage.
382398
func (c *ChainConfig) IsTerminalPoWBlock(parentTotalDiff *big.Int, totalDiff *big.Int) bool {
383399
if c.TerminalTotalDifficulty == nil {
@@ -625,7 +641,7 @@ type Rules struct {
625641
ChainID *big.Int
626642
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
627643
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul, IsNeo bool
628-
IsMerge bool
644+
IsMerge, IsOsaka bool
629645
}
630646

631647
// Rules ensures c's ChainID is not nil.
@@ -634,7 +650,7 @@ func (c *ChainConfig) Rules(num *big.Int, isMerge bool, timestamp uint64) Rules
634650
if chainID == nil {
635651
chainID = new(big.Int)
636652
}
637-
return Rules{ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num), IsPetersburg: c.IsPetersburg(num), IsIstanbul: c.IsIstanbul(num), IsNeo: c.IsNeo(num), IsMerge: isMerge}
653+
return Rules{ChainID: new(big.Int).Set(chainID), IsHomestead: c.IsHomestead(num), IsEIP150: c.IsEIP150(num), IsEIP155: c.IsEIP155(num), IsEIP158: c.IsEIP158(num), IsByzantium: c.IsByzantium(num), IsPetersburg: c.IsPetersburg(num), IsIstanbul: c.IsIstanbul(num), IsNeo: c.IsNeo(num), IsMerge: isMerge, IsOsaka: isMerge && c.IsOsaka(num, timestamp)}
638654
}
639655

640656
// Get Mature Block
@@ -648,6 +664,11 @@ func (c *ChainConfig) GetMatureBlock() int64 {
648664
return MatureBlks
649665
}
650666

667+
// IsOsaka returns whether time is either equal to the Osaka fork time or greater.
668+
func (c *ChainConfig) IsOsaka(num *big.Int, time uint64) bool {
669+
return c.IsMerge(num) && isTimestampForked(c.OsakaTime, time)
670+
}
671+
651672
// Get Block uploading quota
652673
func (c *ChainConfig) GetBlockQuota(num *big.Int) uint64 {
653674
if c.ChainID.Uint64() == 42 {

0 commit comments

Comments
 (0)