mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-06-19 21:31:37 +00:00
Merge pull request #459 from XinFinOrg/eip4399
implement EIP-4399, PREVRANDAO opcode
This commit is contained in:
commit
38a192e672
11 changed files with 150 additions and 77 deletions
|
|
@ -47,6 +47,7 @@ var TIPXDCXCancellationFee = big.NewInt(38383838)
|
|||
var TIPXDCXCancellationFeeTestnet = big.NewInt(38383838)
|
||||
var BerlinBlock = big.NewInt(9999999999)
|
||||
var LondonBlock = big.NewInt(9999999999)
|
||||
var MergeBlock = big.NewInt(9999999999)
|
||||
|
||||
var TIPXDCXTestnet = big.NewInt(38383838)
|
||||
var IsTestnet bool = false
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ var TIPXDCXCancellationFee = big.NewInt(225000)
|
|||
var TIPXDCXCancellationFeeTestnet = big.NewInt(225000)
|
||||
var BerlinBlock = big.NewInt(9999999999)
|
||||
var LondonBlock = big.NewInt(9999999999)
|
||||
var MergeBlock = big.NewInt(9999999999)
|
||||
|
||||
var TIPXDCXTestnet = big.NewInt(0)
|
||||
var IsTestnet bool = false
|
||||
|
|
|
|||
|
|
@ -47,6 +47,7 @@ var TIPXDCXCancellationFee = big.NewInt(23779191)
|
|||
var TIPXDCXCancellationFeeTestnet = big.NewInt(23779191)
|
||||
var BerlinBlock = big.NewInt(9999999999)
|
||||
var LondonBlock = big.NewInt(9999999999)
|
||||
var MergeBlock = big.NewInt(9999999999)
|
||||
|
||||
var TIPXDCXTestnet = big.NewInt(23779191)
|
||||
var IsTestnet bool = false
|
||||
|
|
|
|||
|
|
@ -23,17 +23,23 @@ import (
|
|||
"github.com/XinFinOrg/XDPoSChain/consensus"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/types"
|
||||
"github.com/XinFinOrg/XDPoSChain/core/vm"
|
||||
"github.com/XinFinOrg/XDPoSChain/crypto"
|
||||
)
|
||||
|
||||
// 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 {
|
||||
// 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 {
|
||||
beneficiary, _ = chain.Engine().Author(header) // Ignore error, we're past header validation
|
||||
} else {
|
||||
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{
|
||||
CanTransfer: CanTransfer,
|
||||
Transfer: Transfer,
|
||||
|
|
@ -45,6 +51,7 @@ func NewEVMContext(msg Message, header *types.Header, chain consensus.ChainConte
|
|||
Difficulty: new(big.Int).Set(header.Difficulty),
|
||||
GasLimit: header.GasLimit,
|
||||
GasPrice: new(big.Int).Set(msg.GasPrice()),
|
||||
Random: &random,
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -107,6 +107,7 @@ type Context struct {
|
|||
BlockNumber *big.Int // Provides information for NUMBER
|
||||
Time *big.Int // Provides information for TIME
|
||||
Difficulty *big.Int // Provides information for DIFFICULTY
|
||||
Random *common.Hash // Provides information for PREVRANDAO
|
||||
}
|
||||
|
||||
// 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
|
||||
}
|
||||
|
||||
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) {
|
||||
callContext.stack.push(new(uint256.Int).SetUint64(interpreter.evm.GasLimit))
|
||||
return nil, nil
|
||||
|
|
|
|||
|
|
@ -21,6 +21,7 @@ import (
|
|||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"math/big"
|
||||
"os"
|
||||
"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 cfg.JumpTable == nil {
|
||||
switch {
|
||||
case evm.chainRules.IsMerge:
|
||||
cfg.JumpTable = &mergeInstructionSet
|
||||
case evm.chainRules.IsLondon:
|
||||
cfg.JumpTable = &londonInstructionSet
|
||||
case evm.chainRules.IsBerlin:
|
||||
|
|
@ -262,7 +264,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
|
|||
}
|
||||
pc++
|
||||
}
|
||||
|
||||
|
||||
if err == errStopToken {
|
||||
err = nil // clear stop token error
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,11 +52,23 @@ var (
|
|||
istanbulInstructionSet = newIstanbulInstructionSet()
|
||||
berlinInstructionSet = newBerlinInstructionSet()
|
||||
londonInstructionSet = newLondonInstructionSet()
|
||||
mergeInstructionSet = newMergeInstructionSet()
|
||||
)
|
||||
|
||||
// JumpTable contains the EVM opcodes supported at a given fork.
|
||||
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,
|
||||
// constantinople, istanbul, petersburg, berlin and london instructions.
|
||||
func newLondonInstructionSet() JumpTable {
|
||||
|
|
|
|||
|
|
@ -98,6 +98,8 @@ const (
|
|||
TIMESTAMP OpCode = 0x42
|
||||
NUMBER OpCode = 0x43
|
||||
DIFFICULTY OpCode = 0x44
|
||||
RANDOM OpCode = 0x44 // Same as DIFFICULTY
|
||||
PREVRANDAO OpCode = 0x44 // Same as DIFFICULTY
|
||||
GASLIMIT OpCode = 0x45
|
||||
CHAINID OpCode = 0x46
|
||||
SELFBALANCE OpCode = 0x47
|
||||
|
|
@ -277,7 +279,7 @@ var opCodeToString = [256]string{
|
|||
COINBASE: "COINBASE",
|
||||
TIMESTAMP: "TIMESTAMP",
|
||||
NUMBER: "NUMBER",
|
||||
DIFFICULTY: "DIFFICULTY",
|
||||
DIFFICULTY: "DIFFICULTY", // TODO rename to PREVRANDAO post merge
|
||||
GASLIMIT: "GASLIMIT",
|
||||
CHAINID: "CHAINID",
|
||||
SELFBALANCE: "SELFBALANCE",
|
||||
|
|
|
|||
149
params/config.go
149
params/config.go
|
|
@ -242,19 +242,19 @@ var (
|
|||
// This configuration is intentionally not using keyed fields to force anyone
|
||||
// adding flags to the config to also have to set these fields.
|
||||
AllEthashProtocolChanges = &ChainConfig{
|
||||
ChainId: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ChainId: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: nil,
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
XDPoS: nil,
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
XDPoS: nil,
|
||||
}
|
||||
|
||||
// AllXDPoSProtocolChanges contains every protocol change (EIPs) introduced
|
||||
|
|
@ -262,52 +262,52 @@ var (
|
|||
//
|
||||
// This configuration is intentionally not using keyed fields to force anyone
|
||||
// adding flags to the config to also have to set these fields.
|
||||
AllXDPoSProtocolChanges = &ChainConfig{
|
||||
ChainId: big.NewInt(89),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
AllXDPoSProtocolChanges = &ChainConfig{
|
||||
ChainId: big.NewInt(89),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: nil,
|
||||
Ethash: nil,
|
||||
Clique: nil,
|
||||
XDPoS: &XDPoSConfig{Period: 0, Epoch: 900},
|
||||
Ethash: nil,
|
||||
Clique: nil,
|
||||
XDPoS: &XDPoSConfig{Period: 0, Epoch: 900},
|
||||
}
|
||||
|
||||
AllCliqueProtocolChanges = &ChainConfig{
|
||||
ChainId: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ChainId: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: nil,
|
||||
Ethash: nil,
|
||||
Clique: &CliqueConfig{Period: 0, Epoch: 900},
|
||||
XDPoS: nil,
|
||||
Ethash: nil,
|
||||
Clique: &CliqueConfig{Period: 0, Epoch: 900},
|
||||
XDPoS: nil,
|
||||
}
|
||||
|
||||
// XDPoS config with v2 engine after block 901
|
||||
TestXDPoSMockChainConfig = &ChainConfig{
|
||||
ChainId: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ChainId: big.NewInt(1337),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: nil,
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
XDPoS: &XDPoSConfig{
|
||||
Epoch: 900,
|
||||
Gap: 450,
|
||||
|
|
@ -323,21 +323,21 @@ var (
|
|||
}
|
||||
|
||||
TestChainConfig = &ChainConfig{
|
||||
ChainId: big.NewInt(1),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ChainId: big.NewInt(1),
|
||||
HomesteadBlock: big.NewInt(0),
|
||||
DAOForkBlock: nil,
|
||||
DAOForkSupport: false,
|
||||
EIP150Block: big.NewInt(0),
|
||||
EIP150Hash: common.Hash{},
|
||||
EIP155Block: big.NewInt(0),
|
||||
EIP158Block: big.NewInt(0),
|
||||
ByzantiumBlock: big.NewInt(0),
|
||||
ConstantinopleBlock: nil,
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
XDPoS: nil,
|
||||
Ethash: new(EthashConfig),
|
||||
Clique: nil,
|
||||
XDPoS: nil,
|
||||
}
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
TestRules = TestChainConfig.Rules(new(big.Int))
|
||||
)
|
||||
|
||||
// ChainConfig is the core config which determines the blockchain settings.
|
||||
|
|
@ -362,8 +362,6 @@ type ChainConfig struct {
|
|||
|
||||
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)
|
||||
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
|
||||
Ethash *EthashConfig `json:"ethash,omitempty"`
|
||||
|
|
@ -500,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 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.HomesteadBlock,
|
||||
c.DAOForkBlock,
|
||||
|
|
@ -510,8 +508,10 @@ func (c *ChainConfig) String() string {
|
|||
c.EIP158Block,
|
||||
c.ByzantiumBlock,
|
||||
c.ConstantinopleBlock,
|
||||
c.BerlinBlock,
|
||||
c.LondonBlock,
|
||||
common.TIPXDCXCancellationFee,
|
||||
common.BerlinBlock,
|
||||
common.LondonBlock,
|
||||
common.MergeBlock,
|
||||
engine,
|
||||
)
|
||||
}
|
||||
|
|
@ -568,6 +568,12 @@ func (c *ChainConfig) IsLondon(num *big.Int) bool {
|
|||
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 {
|
||||
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) {
|
||||
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
|
||||
}
|
||||
|
||||
|
|
@ -744,6 +743,7 @@ type Rules struct {
|
|||
IsHomestead, IsEIP150, IsEIP155, IsEIP158 bool
|
||||
IsByzantium, IsConstantinople, IsPetersburg, IsIstanbul bool
|
||||
IsBerlin, IsLondon bool
|
||||
IsMerge bool
|
||||
}
|
||||
|
||||
func (c *ChainConfig) Rules(num *big.Int) Rules {
|
||||
|
|
@ -762,6 +762,7 @@ func (c *ChainConfig) Rules(num *big.Int) Rules {
|
|||
IsPetersburg: c.IsPetersburg(num),
|
||||
IsIstanbul: c.IsIstanbul(num),
|
||||
IsBerlin: c.IsBerlin(num),
|
||||
IsLondon: c.IsLondon(num),
|
||||
IsLondon: c.IsLondon(num),
|
||||
IsMerge: c.IsMerge(num),
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue