From 0e36b5be4210c9c604097792a8c1d32ec218d216 Mon Sep 17 00:00:00 2001 From: Wang Gerui Date: Tue, 5 Mar 2024 00:31:14 +0800 Subject: [PATCH 1/3] fix typo in EIPs --- core/vm/eips.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/vm/eips.go b/core/vm/eips.go index 77dc30a910..d096d5a3a8 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -29,7 +29,7 @@ import ( // defined jump tables are not polluted. func EnableEIP(eipNum int, jt *JumpTable) error { switch eipNum { - case 3898: + case 3198: enable3198(jt) case 2200: enable2200(jt) From 968440ce3de7e36b6ab85e8a1ec85ab3e7e5704f Mon Sep 17 00:00:00 2001 From: geruiwang Date: Thu, 7 Mar 2024 21:44:37 +0800 Subject: [PATCH 2/3] core/vm: implement EIP-3855: PUSH0 instruction. --- common/constants.go | 1 + common/constants/constants.go.devnet | 1 + common/constants/constants.go.testnet | 1 + core/vm/eips.go | 19 +++++++++++++++++++ core/vm/interpreter.go | 2 ++ core/vm/jump_table.go | 7 +++++++ core/vm/opcodes.go | 27 +++++++++++++++------------ params/config.go | 11 +++++++++-- 8 files changed, 55 insertions(+), 14 deletions(-) diff --git a/common/constants.go b/common/constants.go index c923eeea8d..803443a781 100644 --- a/common/constants.go +++ b/common/constants.go @@ -49,6 +49,7 @@ var TIPXDCXDISABLE = big.NewInt(99999999900) var BerlinBlock = big.NewInt(9999999999) var LondonBlock = big.NewInt(9999999999) var MergeBlock = big.NewInt(9999999999) +var ShanghaiBlock = big.NewInt(9999999999) var TIPXDCXTestnet = big.NewInt(38383838) var IsTestnet bool = false diff --git a/common/constants/constants.go.devnet b/common/constants/constants.go.devnet index e80dda351f..2bbd3ac06a 100644 --- a/common/constants/constants.go.devnet +++ b/common/constants/constants.go.devnet @@ -49,6 +49,7 @@ var TIPXDCXDISABLE = big.NewInt(15894900) var BerlinBlock = big.NewInt(9999999999) var LondonBlock = big.NewInt(9999999999) var MergeBlock = big.NewInt(9999999999) +var ShanghaiBlock = big.NewInt(9999999999) var TIPXDCXTestnet = big.NewInt(0) var IsTestnet bool = false diff --git a/common/constants/constants.go.testnet b/common/constants/constants.go.testnet index 9a0125e701..3b2811ade9 100644 --- a/common/constants/constants.go.testnet +++ b/common/constants/constants.go.testnet @@ -49,6 +49,7 @@ var TIPXDCXDISABLE = big.NewInt(99999999900) var BerlinBlock = big.NewInt(9999999999) var LondonBlock = big.NewInt(9999999999) var MergeBlock = big.NewInt(9999999999) +var ShanghaiBlock = big.NewInt(9999999999) var TIPXDCXTestnet = big.NewInt(23779191) var IsTestnet bool = false diff --git a/core/vm/eips.go b/core/vm/eips.go index d096d5a3a8..48ffb0d691 100644 --- a/core/vm/eips.go +++ b/core/vm/eips.go @@ -29,6 +29,8 @@ import ( // defined jump tables are not polluted. func EnableEIP(eipNum int, jt *JumpTable) error { switch eipNum { + case 3855: + enable3855(jt) case 3198: enable3198(jt) case 2200: @@ -112,3 +114,20 @@ func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([ callContext.stack.push(baseFee) return nil, nil } + +// enable3855 applies EIP-3855 (PUSH0 opcode) +func enable3855(jt *JumpTable) { + // New opcode + jt[PUSH0] = &operation{ + execute: opPush0, + constantGas: GasQuickStep, + minStack: minStack(0, 1), + maxStack: maxStack(0, 1), + } +} + +// opPush0 implements the PUSH0 opcode +func opPush0(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) { + callContext.stack.push(new(uint256.Int)) + return nil, nil +} diff --git a/core/vm/interpreter.go b/core/vm/interpreter.go index 29fc4a2cb7..23cc5a03fe 100644 --- a/core/vm/interpreter.go +++ b/core/vm/interpreter.go @@ -93,6 +93,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter { // If jump table was not initialised we set the default one. if cfg.JumpTable == nil { switch { + case evm.chainRules.IsShanghai: + cfg.JumpTable = &shanghaiInstructionSet case evm.chainRules.IsMerge: cfg.JumpTable = &mergeInstructionSet case evm.chainRules.IsLondon: diff --git a/core/vm/jump_table.go b/core/vm/jump_table.go index 298ec63ab3..2302a439df 100644 --- a/core/vm/jump_table.go +++ b/core/vm/jump_table.go @@ -53,11 +53,18 @@ var ( berlinInstructionSet = newBerlinInstructionSet() londonInstructionSet = newLondonInstructionSet() mergeInstructionSet = newMergeInstructionSet() + shanghaiInstructionSet = newShanghaiInstructionSet() ) // JumpTable contains the EVM opcodes supported at a given fork. type JumpTable [256]*operation +func newShanghaiInstructionSet() JumpTable { + instructionSet := newMergeInstructionSet() + enable3855(&instructionSet) // PUSH0 instruction + return instructionSet +} + func newMergeInstructionSet() JumpTable { instructionSet := newLondonInstructionSet() instructionSet[PREVRANDAO] = &operation{ diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 3b123f3a49..969354cf59 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -108,18 +108,19 @@ const ( // 0x50 range - 'storage' and execution. const ( - POP OpCode = 0x50 + iota - MLOAD - MSTORE - MSTORE8 - SLOAD - SSTORE - JUMP - JUMPI - PC - MSIZE - GAS - JUMPDEST + POP OpCode = 0x50 + MLOAD OpCode = 0x51 + MSTORE OpCode = 0x52 + MSTORE8 OpCode = 0x53 + SLOAD OpCode = 0x54 + SSTORE OpCode = 0x55 + JUMP OpCode = 0x56 + JUMPI OpCode = 0x57 + PC OpCode = 0x58 + MSIZE OpCode = 0x59 + GAS OpCode = 0x5a + JUMPDEST OpCode = 0x5b + PUSH0 OpCode = 0x5f ) // 0x60 range - pushes. @@ -300,6 +301,7 @@ var opCodeToString = [256]string{ MSIZE: "MSIZE", GAS: "GAS", JUMPDEST: "JUMPDEST", + PUSH0: "PUSH0", // 0x60 range - push. PUSH1: "PUSH1", @@ -462,6 +464,7 @@ var stringToOp = map[string]OpCode{ "MSIZE": MSIZE, "GAS": GAS, "JUMPDEST": JUMPDEST, + "PUSH0": PUSH0, "PUSH1": PUSH1, "PUSH2": PUSH2, "PUSH3": PUSH3, diff --git a/params/config.go b/params/config.go index 0a46f710f3..933d5f2980 100644 --- a/params/config.go +++ b/params/config.go @@ -498,7 +498,7 @@ func (c *ChainConfig) String() string { default: engine = "unknown" } - return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Istanbul: %v BerlinBlock: %v LondonBlock: %v MergeBlock: %v Engine: %v}", + return fmt.Sprintf("{ChainID: %v Homestead: %v DAO: %v DAOSupport: %v EIP150: %v EIP155: %v EIP158: %v Byzantium: %v Constantinople: %v Istanbul: %v BerlinBlock: %v LondonBlock: %v MergeBlock: %v ShanghaiBlock: %v Engine: %v}", c.ChainId, c.HomesteadBlock, c.DAOForkBlock, @@ -512,6 +512,7 @@ func (c *ChainConfig) String() string { common.BerlinBlock, common.LondonBlock, common.MergeBlock, + common.ShanghaiBlock, engine, ) } @@ -574,6 +575,11 @@ func (c *ChainConfig) IsMerge(num *big.Int) bool { return isForked(common.MergeBlock, num) } +// IsShanghai returns whether num is either equal to the Shanghai fork block or greater. +func (c *ChainConfig) IsShanghai(num *big.Int) bool { + return isForked(common.ShanghaiBlock, num) +} + func (c *ChainConfig) IsTIP2019(num *big.Int) bool { return isForked(common.TIP2019Block, num) } @@ -742,7 +748,7 @@ type Rules struct { IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsBerlin, IsLondon bool - IsMerge bool + IsMerge, IsShanghai bool } func (c *ChainConfig) Rules(num *big.Int) Rules { @@ -763,5 +769,6 @@ func (c *ChainConfig) Rules(num *big.Int) Rules { IsBerlin: c.IsBerlin(num), IsLondon: c.IsLondon(num), IsMerge: c.IsMerge(num), + IsShanghai: c.IsShanghai(num), } } From 863d4f14e307a5e0e8add31de9a3f59ad21ba187 Mon Sep 17 00:00:00 2001 From: geruiwang Date: Thu, 7 Mar 2024 22:31:19 +0800 Subject: [PATCH 3/3] eth/tracers/js: fix isPush for push0 (#28520) Fixes so that `push0` opcode is correctly reported as `true` by the `IsPush` function --------- Co-authored-by: Martin Holst Swende --- core/asm/asm_test.go | 78 ++++++++++++++++++-------------------------- core/vm/opcodes.go | 6 +--- 2 files changed, 32 insertions(+), 52 deletions(-) diff --git a/core/asm/asm_test.go b/core/asm/asm_test.go index 92b26b67a5..cd7520ec63 100644 --- a/core/asm/asm_test.go +++ b/core/asm/asm_test.go @@ -22,53 +22,37 @@ import ( "encoding/hex" ) -// Tests disassembling the instructions for valid evm code -func TestInstructionIteratorValid(t *testing.T) { - cnt := 0 - script, _ := hex.DecodeString("61000000") +// Tests disassembling instructions +func TestInstructionIterator(t *testing.T) { + for i, tc := range []struct { + want int + code string + wantErr string + }{ + {2, "61000000", ""}, // valid code + {0, "6100", "incomplete push instruction at 0"}, // invalid code + {2, "5900", ""}, // push0 + {0, "", ""}, // empty - it := NewInstructionIterator(script) - for it.Next() { - cnt++ - } - - if err := it.Error(); err != nil { - t.Errorf("Expected 2, but encountered error %v instead.", err) - } - if cnt != 2 { - t.Errorf("Expected 2, but got %v instead.", cnt) - } -} - -// Tests disassembling the instructions for invalid evm code -func TestInstructionIteratorInvalid(t *testing.T) { - cnt := 0 - script, _ := hex.DecodeString("6100") - - it := NewInstructionIterator(script) - for it.Next() { - cnt++ - } - - if it.Error() == nil { - t.Errorf("Expected an error, but got %v instead.", cnt) - } -} - -// Tests disassembling the instructions for empty evm code -func TestInstructionIteratorEmpty(t *testing.T) { - cnt := 0 - script, _ := hex.DecodeString("") - - it := NewInstructionIterator(script) - for it.Next() { - cnt++ - } - - if err := it.Error(); err != nil { - t.Errorf("Expected 0, but encountered error %v instead.", err) - } - if cnt != 0 { - t.Errorf("Expected 0, but got %v instead.", cnt) + } { + var ( + have int + code, _ = hex.DecodeString(tc.code) + it = NewInstructionIterator(code) + ) + for it.Next() { + have++ + } + var haveErr = "" + if it.Error() != nil { + haveErr = it.Error().Error() + } + if haveErr != tc.wantErr { + t.Errorf("test %d: encountered error: %q want %q", i, haveErr, tc.wantErr) + continue + } + if have != tc.want { + t.Errorf("wrong instruction count, have %d want %d", have, tc.want) + } } } diff --git a/core/vm/opcodes.go b/core/vm/opcodes.go index 969354cf59..26523e53ce 100644 --- a/core/vm/opcodes.go +++ b/core/vm/opcodes.go @@ -25,11 +25,7 @@ type OpCode byte // IsPush specifies if an opcode is a PUSH opcode. func (op OpCode) IsPush() bool { - switch op { - case PUSH1, PUSH2, PUSH3, PUSH4, PUSH5, PUSH6, PUSH7, PUSH8, PUSH9, PUSH10, PUSH11, PUSH12, PUSH13, PUSH14, PUSH15, PUSH16, PUSH17, PUSH18, PUSH19, PUSH20, PUSH21, PUSH22, PUSH23, PUSH24, PUSH25, PUSH26, PUSH27, PUSH28, PUSH29, PUSH30, PUSH31, PUSH32: - return true - } - return false + return PUSH0 <= op && op <= PUSH32 } // 0x0 range - arithmetic ops.