Merge pull request #472 from XinFinOrg/eip3855

core/vm: implement EIP-3855: PUSH0 instruction.
This commit is contained in:
Daniel Liu 2024-03-07 23:01:33 +08:00 committed by GitHub
commit 6a2f753cee
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
9 changed files with 88 additions and 67 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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)
}
}
}

View file

@ -29,7 +29,9 @@ import (
// defined jump tables are not polluted.
func EnableEIP(eipNum int, jt *JumpTable) error {
switch eipNum {
case 3898:
case 3855:
enable3855(jt)
case 3198:
enable3198(jt)
case 2200:
enable2200(jt)
@ -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
}

View file

@ -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:

View file

@ -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{

View file

@ -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.
@ -108,18 +104,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 +297,7 @@ var opCodeToString = [256]string{
MSIZE: "MSIZE",
GAS: "GAS",
JUMPDEST: "JUMPDEST",
PUSH0: "PUSH0",
// 0x60 range - push.
PUSH1: "PUSH1",
@ -462,6 +460,7 @@ var stringToOp = map[string]OpCode{
"MSIZE": MSIZE,
"GAS": GAS,
"JUMPDEST": JUMPDEST,
"PUSH0": PUSH0,
"PUSH1": PUSH1,
"PUSH2": PUSH2,
"PUSH3": PUSH3,

View file

@ -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),
}
}