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 BerlinBlock = big.NewInt(9999999999)
var LondonBlock = big.NewInt(9999999999) var LondonBlock = big.NewInt(9999999999)
var MergeBlock = big.NewInt(9999999999) var MergeBlock = big.NewInt(9999999999)
var ShanghaiBlock = big.NewInt(9999999999)
var TIPXDCXTestnet = big.NewInt(38383838) var TIPXDCXTestnet = big.NewInt(38383838)
var IsTestnet bool = false var IsTestnet bool = false

View file

@ -49,6 +49,7 @@ var TIPXDCXDISABLE = big.NewInt(15894900)
var BerlinBlock = big.NewInt(9999999999) var BerlinBlock = big.NewInt(9999999999)
var LondonBlock = big.NewInt(9999999999) var LondonBlock = big.NewInt(9999999999)
var MergeBlock = big.NewInt(9999999999) var MergeBlock = big.NewInt(9999999999)
var ShanghaiBlock = big.NewInt(9999999999)
var TIPXDCXTestnet = big.NewInt(0) var TIPXDCXTestnet = big.NewInt(0)
var IsTestnet bool = false var IsTestnet bool = false

View file

@ -49,6 +49,7 @@ var TIPXDCXDISABLE = big.NewInt(99999999900)
var BerlinBlock = big.NewInt(9999999999) var BerlinBlock = big.NewInt(9999999999)
var LondonBlock = big.NewInt(9999999999) var LondonBlock = big.NewInt(9999999999)
var MergeBlock = big.NewInt(9999999999) var MergeBlock = big.NewInt(9999999999)
var ShanghaiBlock = big.NewInt(9999999999)
var TIPXDCXTestnet = big.NewInt(23779191) var TIPXDCXTestnet = big.NewInt(23779191)
var IsTestnet bool = false var IsTestnet bool = false

View file

@ -22,53 +22,37 @@ import (
"encoding/hex" "encoding/hex"
) )
// Tests disassembling the instructions for valid evm code // Tests disassembling instructions
func TestInstructionIteratorValid(t *testing.T) { func TestInstructionIterator(t *testing.T) {
cnt := 0 for i, tc := range []struct {
script, _ := hex.DecodeString("61000000") 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() { var (
cnt++ have int
} code, _ = hex.DecodeString(tc.code)
it = NewInstructionIterator(code)
if err := it.Error(); err != nil { )
t.Errorf("Expected 2, but encountered error %v instead.", err) for it.Next() {
} have++
if cnt != 2 { }
t.Errorf("Expected 2, but got %v instead.", cnt) var haveErr = ""
} if it.Error() != nil {
} haveErr = it.Error().Error()
}
// Tests disassembling the instructions for invalid evm code if haveErr != tc.wantErr {
func TestInstructionIteratorInvalid(t *testing.T) { t.Errorf("test %d: encountered error: %q want %q", i, haveErr, tc.wantErr)
cnt := 0 continue
script, _ := hex.DecodeString("6100") }
if have != tc.want {
it := NewInstructionIterator(script) t.Errorf("wrong instruction count, have %d want %d", have, tc.want)
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)
} }
} }

View file

@ -29,7 +29,9 @@ import (
// defined jump tables are not polluted. // defined jump tables are not polluted.
func EnableEIP(eipNum int, jt *JumpTable) error { func EnableEIP(eipNum int, jt *JumpTable) error {
switch eipNum { switch eipNum {
case 3898: case 3855:
enable3855(jt)
case 3198:
enable3198(jt) enable3198(jt)
case 2200: case 2200:
enable2200(jt) enable2200(jt)
@ -112,3 +114,20 @@ func opBaseFee(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([
callContext.stack.push(baseFee) callContext.stack.push(baseFee)
return nil, nil 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 jump table was not initialised we set the default one.
if cfg.JumpTable == nil { if cfg.JumpTable == nil {
switch { switch {
case evm.chainRules.IsShanghai:
cfg.JumpTable = &shanghaiInstructionSet
case evm.chainRules.IsMerge: case evm.chainRules.IsMerge:
cfg.JumpTable = &mergeInstructionSet cfg.JumpTable = &mergeInstructionSet
case evm.chainRules.IsLondon: case evm.chainRules.IsLondon:

View file

@ -53,11 +53,18 @@ var (
berlinInstructionSet = newBerlinInstructionSet() berlinInstructionSet = newBerlinInstructionSet()
londonInstructionSet = newLondonInstructionSet() londonInstructionSet = newLondonInstructionSet()
mergeInstructionSet = newMergeInstructionSet() mergeInstructionSet = newMergeInstructionSet()
shanghaiInstructionSet = newShanghaiInstructionSet()
) )
// JumpTable contains the EVM opcodes supported at a given fork. // JumpTable contains the EVM opcodes supported at a given fork.
type JumpTable [256]*operation type JumpTable [256]*operation
func newShanghaiInstructionSet() JumpTable {
instructionSet := newMergeInstructionSet()
enable3855(&instructionSet) // PUSH0 instruction
return instructionSet
}
func newMergeInstructionSet() JumpTable { func newMergeInstructionSet() JumpTable {
instructionSet := newLondonInstructionSet() instructionSet := newLondonInstructionSet()
instructionSet[PREVRANDAO] = &operation{ instructionSet[PREVRANDAO] = &operation{

View file

@ -25,11 +25,7 @@ type OpCode byte
// IsPush specifies if an opcode is a PUSH opcode. // IsPush specifies if an opcode is a PUSH opcode.
func (op OpCode) IsPush() bool { func (op OpCode) IsPush() bool {
switch op { return PUSH0 <= op && op <= PUSH32
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
} }
// 0x0 range - arithmetic ops. // 0x0 range - arithmetic ops.
@ -108,18 +104,19 @@ const (
// 0x50 range - 'storage' and execution. // 0x50 range - 'storage' and execution.
const ( const (
POP OpCode = 0x50 + iota POP OpCode = 0x50
MLOAD MLOAD OpCode = 0x51
MSTORE MSTORE OpCode = 0x52
MSTORE8 MSTORE8 OpCode = 0x53
SLOAD SLOAD OpCode = 0x54
SSTORE SSTORE OpCode = 0x55
JUMP JUMP OpCode = 0x56
JUMPI JUMPI OpCode = 0x57
PC PC OpCode = 0x58
MSIZE MSIZE OpCode = 0x59
GAS GAS OpCode = 0x5a
JUMPDEST JUMPDEST OpCode = 0x5b
PUSH0 OpCode = 0x5f
) )
// 0x60 range - pushes. // 0x60 range - pushes.
@ -300,6 +297,7 @@ var opCodeToString = [256]string{
MSIZE: "MSIZE", MSIZE: "MSIZE",
GAS: "GAS", GAS: "GAS",
JUMPDEST: "JUMPDEST", JUMPDEST: "JUMPDEST",
PUSH0: "PUSH0",
// 0x60 range - push. // 0x60 range - push.
PUSH1: "PUSH1", PUSH1: "PUSH1",
@ -462,6 +460,7 @@ var stringToOp = map[string]OpCode{
"MSIZE": MSIZE, "MSIZE": MSIZE,
"GAS": GAS, "GAS": GAS,
"JUMPDEST": JUMPDEST, "JUMPDEST": JUMPDEST,
"PUSH0": PUSH0,
"PUSH1": PUSH1, "PUSH1": PUSH1,
"PUSH2": PUSH2, "PUSH2": PUSH2,
"PUSH3": PUSH3, "PUSH3": PUSH3,

View file

@ -498,7 +498,7 @@ func (c *ChainConfig) String() string {
default: default:
engine = "unknown" 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.ChainId,
c.HomesteadBlock, c.HomesteadBlock,
c.DAOForkBlock, c.DAOForkBlock,
@ -512,6 +512,7 @@ func (c *ChainConfig) String() string {
common.BerlinBlock, common.BerlinBlock,
common.LondonBlock, common.LondonBlock,
common.MergeBlock, common.MergeBlock,
common.ShanghaiBlock,
engine, engine,
) )
} }
@ -574,6 +575,11 @@ func (c *ChainConfig) IsMerge(num *big.Int) bool {
return isForked(common.MergeBlock, num) 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 { func (c *ChainConfig) IsTIP2019(num *big.Int) bool {
return isForked(common.TIP2019Block, num) return isForked(common.TIP2019Block, num)
} }
@ -742,7 +748,7 @@ type Rules struct {
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
IsBerlin, IsLondon bool IsBerlin, IsLondon bool
IsMerge bool IsMerge, IsShanghai bool
} }
func (c *ChainConfig) Rules(num *big.Int) Rules { func (c *ChainConfig) Rules(num *big.Int) Rules {
@ -763,5 +769,6 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
IsBerlin: c.IsBerlin(num), IsBerlin: c.IsBerlin(num),
IsLondon: c.IsLondon(num), IsLondon: c.IsLondon(num),
IsMerge: c.IsMerge(num), IsMerge: c.IsMerge(num),
IsShanghai: c.IsShanghai(num),
} }
} }