mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-07-17 10:20:44 +00:00
implement EIP-4399, PREVRANDAO opcode.
and remove unused LondonBlock and BerlinBlock in `params/config.go` (already defined in constants.go)
This commit is contained in:
parent
928a0691ca
commit
a31489541d
11 changed files with 89 additions and 16 deletions
|
|
@ -47,6 +47,7 @@ var TIPXDCXCancellationFee = big.NewInt(38383838)
|
||||||
var TIPXDCXCancellationFeeTestnet = big.NewInt(38383838)
|
var TIPXDCXCancellationFeeTestnet = big.NewInt(38383838)
|
||||||
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 TIPXDCXTestnet = big.NewInt(38383838)
|
var TIPXDCXTestnet = big.NewInt(38383838)
|
||||||
var IsTestnet bool = false
|
var IsTestnet bool = false
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ var TIPXDCXCancellationFee = big.NewInt(225000)
|
||||||
var TIPXDCXCancellationFeeTestnet = big.NewInt(225000)
|
var TIPXDCXCancellationFeeTestnet = big.NewInt(225000)
|
||||||
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 TIPXDCXTestnet = big.NewInt(0)
|
var TIPXDCXTestnet = big.NewInt(0)
|
||||||
var IsTestnet bool = false
|
var IsTestnet bool = false
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,7 @@ var TIPXDCXCancellationFee = big.NewInt(23779191)
|
||||||
var TIPXDCXCancellationFeeTestnet = big.NewInt(23779191)
|
var TIPXDCXCancellationFeeTestnet = big.NewInt(23779191)
|
||||||
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 TIPXDCXTestnet = big.NewInt(23779191)
|
var TIPXDCXTestnet = big.NewInt(23779191)
|
||||||
var IsTestnet bool = false
|
var IsTestnet bool = false
|
||||||
|
|
|
||||||
|
|
@ -23,17 +23,23 @@ import (
|
||||||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||||
|
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewEVMContext creates a new context for use in the EVM.
|
// NewEVMContext creates a new context for use in the EVM.
|
||||||
func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainContext, author *common.Address) vm.Context {
|
func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainContext, author *common.Address) vm.Context {
|
||||||
// If we don't have an explicit author (i.e. not mining), extract from the header
|
// If we don't have an explicit author (i.e. not mining), extract from the header
|
||||||
var beneficiary common.Address
|
var (
|
||||||
|
beneficiary common.Address
|
||||||
|
random common.Hash
|
||||||
|
)
|
||||||
if author == nil {
|
if author == nil {
|
||||||
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
|
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
|
||||||
} else {
|
} else {
|
||||||
beneficiary = *author
|
beneficiary = *author
|
||||||
}
|
}
|
||||||
|
// since xdpos chain do not use difficulty and mixdigest, we use hash of the block number as random
|
||||||
|
random = crypto.Keccak256Hash(header.Number.Bytes())
|
||||||
return vm.Context{
|
return vm.Context{
|
||||||
CanTransfer: CanTransfer,
|
CanTransfer: CanTransfer,
|
||||||
Transfer: Transfer,
|
Transfer: Transfer,
|
||||||
|
|
@ -45,6 +51,7 @@ func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainConte
|
||||||
Difficulty: new(big.Int).Set(header.Difficulty),
|
Difficulty: new(big.Int).Set(header.Difficulty),
|
||||||
GasLimit: header.GasLimit,
|
GasLimit: header.GasLimit,
|
||||||
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
||||||
|
Random: &random,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -107,6 +107,7 @@ type Context struct {
|
||||||
BlockNumber *big.Int // Provides information for NUMBER
|
BlockNumber *big.Int // Provides information for NUMBER
|
||||||
Time *big.Int // Provides information for TIME
|
Time *big.Int // Provides information for TIME
|
||||||
Difficulty *big.Int // Provides information for DIFFICULTY
|
Difficulty *big.Int // Provides information for DIFFICULTY
|
||||||
|
Random *common.Hash // Provides information for PREVRANDAO
|
||||||
}
|
}
|
||||||
|
|
||||||
// EVM is the Ethereum Virtual Machine base object and provides
|
// EVM is the Ethereum Virtual Machine base object and provides
|
||||||
|
|
|
||||||
|
|
@ -477,6 +477,17 @@ func opDifficulty(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx)
|
||||||
return nil, nil
|
return nil, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func opRandom(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
|
var v *uint256.Int
|
||||||
|
if interpreter.evm.Context.Random != nil {
|
||||||
|
v = new(uint256.Int).SetBytes((interpreter.evm.Context.Random.Bytes()))
|
||||||
|
} else { // if context random is not set, use emptyCodeHash as default
|
||||||
|
v = new(uint256.Int).SetBytes(emptyCodeHash.Bytes())
|
||||||
|
}
|
||||||
|
callContext.stack.push(v)
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, callContext *callCtx) ([]byte, error) {
|
||||||
callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.GasLimit))
|
callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.GasLimit))
|
||||||
return nil, nil
|
return nil, nil
|
||||||
|
|
|
||||||
|
|
@ -21,6 +21,7 @@ import (
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"fmt"
|
"fmt"
|
||||||
"log"
|
"log"
|
||||||
|
"math/big"
|
||||||
"os"
|
"os"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -661,3 +662,36 @@ func TestCreate2Addreses(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestRandom(t *testing.T) {
|
||||||
|
type testcase struct {
|
||||||
|
name string
|
||||||
|
random common.Hash
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range []testcase{
|
||||||
|
{name: "empty hash", random: common.Hash{}},
|
||||||
|
{name: "1", random: common.Hash{0}},
|
||||||
|
{name: "emptyCodeHash", random: emptyCodeHash},
|
||||||
|
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
|
||||||
|
} {
|
||||||
|
var (
|
||||||
|
env = NewEVM(Context{Random: &tt.random}, nil, nil, params.TestChainConfig, Config{})
|
||||||
|
stack = newstack()
|
||||||
|
pc = uint64(0)
|
||||||
|
evmInterpreter = NewEVMInterpreter(env, env.vmConfig)
|
||||||
|
)
|
||||||
|
opRandom(&pc, evmInterpreter, &callCtx{nil, stack, nil})
|
||||||
|
if len(stack.data) != 1 {
|
||||||
|
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
|
||||||
|
}
|
||||||
|
actual := stack.pop()
|
||||||
|
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.random.Bytes()))
|
||||||
|
if overflow {
|
||||||
|
t.Errorf("Testcase %v: invalid overflow", tt.name)
|
||||||
|
}
|
||||||
|
if actual.Cmp(expected) != 0 {
|
||||||
|
t.Errorf("Testcase %v: expected %x, got %x", tt.name, expected, actual)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -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.IsMerge:
|
||||||
|
cfg.JumpTable = &mergeInstructionSet
|
||||||
case evm.chainRules.IsLondon:
|
case evm.chainRules.IsLondon:
|
||||||
cfg.JumpTable = &londonInstructionSet
|
cfg.JumpTable = &londonInstructionSet
|
||||||
case evm.chainRules.IsBerlin:
|
case evm.chainRules.IsBerlin:
|
||||||
|
|
@ -262,7 +264,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
||||||
}
|
}
|
||||||
pc++
|
pc++
|
||||||
}
|
}
|
||||||
|
|
||||||
if err == errStopToken {
|
if err == errStopToken {
|
||||||
err = nil // clear stop token error
|
err = nil // clear stop token error
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -52,11 +52,23 @@ var (
|
||||||
istanbulInstructionSet = newIstanbulInstructionSet()
|
istanbulInstructionSet = newIstanbulInstructionSet()
|
||||||
berlinInstructionSet = newBerlinInstructionSet()
|
berlinInstructionSet = newBerlinInstructionSet()
|
||||||
londonInstructionSet = newLondonInstructionSet()
|
londonInstructionSet = newLondonInstructionSet()
|
||||||
|
mergeInstructionSet = newMergeInstructionSet()
|
||||||
)
|
)
|
||||||
|
|
||||||
// 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 newMergeInstructionSet() JumpTable {
|
||||||
|
instructionSet := newLondonInstructionSet()
|
||||||
|
instructionSet[PREVRANDAO] = &operation{
|
||||||
|
execute: opRandom,
|
||||||
|
constantGas: GasQuickStep,
|
||||||
|
minStack: minStack(0, 1),
|
||||||
|
maxStack: maxStack(0, 1),
|
||||||
|
}
|
||||||
|
return instructionSet
|
||||||
|
}
|
||||||
|
|
||||||
// newLondonInstructionSet returns the frontier, homestead, byzantium,
|
// newLondonInstructionSet returns the frontier, homestead, byzantium,
|
||||||
// constantinople, istanbul, petersburg, berlin and london instructions.
|
// constantinople, istanbul, petersburg, berlin and london instructions.
|
||||||
func newLondonInstructionSet() JumpTable {
|
func newLondonInstructionSet() JumpTable {
|
||||||
|
|
|
||||||
|
|
@ -98,6 +98,8 @@ const (
|
||||||
TIMESTAMP OpCode = 0x42
|
TIMESTAMP OpCode = 0x42
|
||||||
NUMBER OpCode = 0x43
|
NUMBER OpCode = 0x43
|
||||||
DIFFICULTY OpCode = 0x44
|
DIFFICULTY OpCode = 0x44
|
||||||
|
RANDOM OpCode = 0x44 // Same as DIFFICULTY
|
||||||
|
PREVRANDAO OpCode = 0x44 // Same as DIFFICULTY
|
||||||
GASLIMIT OpCode = 0x45
|
GASLIMIT OpCode = 0x45
|
||||||
CHAINID OpCode = 0x46
|
CHAINID OpCode = 0x46
|
||||||
SELFBALANCE OpCode = 0x47
|
SELFBALANCE OpCode = 0x47
|
||||||
|
|
@ -277,7 +279,7 @@ var opCodeToString = [256]string{
|
||||||
COINBASE: "COINBASE",
|
COINBASE: "COINBASE",
|
||||||
TIMESTAMP: "TIMESTAMP",
|
TIMESTAMP: "TIMESTAMP",
|
||||||
NUMBER: "NUMBER",
|
NUMBER: "NUMBER",
|
||||||
DIFFICULTY: "DIFFICULTY",
|
DIFFICULTY: "DIFFICULTY", // TODO rename to PREVRANDAO post merge
|
||||||
GASLIMIT: "GASLIMIT",
|
GASLIMIT: "GASLIMIT",
|
||||||
CHAINID: "CHAINID",
|
CHAINID: "CHAINID",
|
||||||
SELFBALANCE: "SELFBALANCE",
|
SELFBALANCE: "SELFBALANCE",
|
||||||
|
|
|
||||||
|
|
@ -362,8 +362,6 @@ type ChainConfig struct {
|
||||||
|
|
||||||
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
|
ByzantiumBlock *big.Int `json:"byzantiumBlock,omitempty"` // Byzantium switch block (nil = no fork, 0 = already on byzantium)
|
||||||
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
|
ConstantinopleBlock *big.Int `json:"constantinopleBlock,omitempty"` // Constantinople switch block (nil = no fork, 0 = already activated)
|
||||||
BerlinBlock *big.Int `json:"berlinBlock,omitempty"` // Berlin switch block (nil = no fork, 0 = already on berlin)
|
|
||||||
LondonBlock *big.Int `json:"londonBlock,omitempty"` // London switch block (nil = no fork, 0 = already on london)
|
|
||||||
|
|
||||||
// Various consensus engines
|
// Various consensus engines
|
||||||
Ethash *EthashConfig `json:"ethash,omitempty"`
|
Ethash *EthashConfig `json:"ethash,omitempty"`
|
||||||
|
|
@ -500,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 BerlinBlock: %v LondonBlock: %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 Engine: %v}",
|
||||||
c.ChainId,
|
c.ChainId,
|
||||||
c.HomesteadBlock,
|
c.HomesteadBlock,
|
||||||
c.DAOForkBlock,
|
c.DAOForkBlock,
|
||||||
|
|
@ -510,8 +508,10 @@ func (c *ChainConfig) String() string {
|
||||||
c.EIP158Block,
|
c.EIP158Block,
|
||||||
c.ByzantiumBlock,
|
c.ByzantiumBlock,
|
||||||
c.ConstantinopleBlock,
|
c.ConstantinopleBlock,
|
||||||
c.BerlinBlock,
|
common.TIPXDCXCancellationFee,
|
||||||
c.LondonBlock,
|
common.BerlinBlock,
|
||||||
|
common.LondonBlock,
|
||||||
|
common.MergeBlock,
|
||||||
engine,
|
engine,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
@ -568,6 +568,12 @@ func (c *ChainConfig) IsLondon(num *big.Int) bool {
|
||||||
return isForked(common.LondonBlock, num)
|
return isForked(common.LondonBlock, num)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// IsMerge returns whether num is either equal to the Merge fork block or greater.
|
||||||
|
// Different from Geth which uses `block.difficulty != nil`
|
||||||
|
func (c *ChainConfig) IsMerge(num *big.Int) bool {
|
||||||
|
return isForked(common.MergeBlock, 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)
|
||||||
}
|
}
|
||||||
|
|
@ -669,13 +675,6 @@ func (c *ChainConfig) checkCompatible(newcfg *ChainConfig, head *big.Int) *Confi
|
||||||
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
|
if isForkIncompatible(c.ConstantinopleBlock, newcfg.ConstantinopleBlock, head) {
|
||||||
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
|
return newCompatError("Constantinople fork block", c.ConstantinopleBlock, newcfg.ConstantinopleBlock)
|
||||||
}
|
}
|
||||||
if isForkIncompatible(c.BerlinBlock, newcfg.BerlinBlock, head) {
|
|
||||||
return newCompatError("Berlin fork block", c.BerlinBlock, newcfg.BerlinBlock)
|
|
||||||
}
|
|
||||||
if isForkIncompatible(c.LondonBlock, newcfg.LondonBlock, head) {
|
|
||||||
return newCompatError("London fork block", c.LondonBlock, newcfg.LondonBlock)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -744,6 +743,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
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *ChainConfig) Rules(num *big.Int) Rules {
|
func (c *ChainConfig) Rules(num *big.Int) Rules {
|
||||||
|
|
@ -762,6 +762,7 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
|
||||||
IsPetersburg: c.IsPetersburg(num),
|
IsPetersburg: c.IsPetersburg(num),
|
||||||
IsIstanbul: c.IsIstanbul(num),
|
IsIstanbul: c.IsIstanbul(num),
|
||||||
IsBerlin: c.IsBerlin(num),
|
IsBerlin: c.IsBerlin(num),
|
||||||
IsLondon: c.IsLondon(num),
|
IsLondon: c.IsLondon(num),
|
||||||
|
IsMerge: c.IsMerge(num),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue