Skip to content

Commit

Permalink
Merge pull request #459 from XinFinOrg/eip4399
Browse files Browse the repository at this point in the history
implement EIP-4399, PREVRANDAO opcode
  • Loading branch information
liam-lai authored Mar 4, 2024
2 parents 46ef5e1 + 72e5ee0 commit 38a192e
Show file tree
Hide file tree
Showing 11 changed files with 150 additions and 77 deletions.
1 change: 1 addition & 0 deletions common/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions common/constants/constants.go.devnet
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions common/constants/constants.go.testnet
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
9 changes: 8 additions & 1 deletion core/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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,
}
}

Expand Down
1 change: 1 addition & 0 deletions core/vm/evm.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
11 changes: 11 additions & 0 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
34 changes: 34 additions & 0 deletions core/vm/instructions_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"fmt"
"log"
"math/big"
"os"
"testing"

Expand Down Expand Up @@ -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)
}
}
}
4 changes: 3 additions & 1 deletion core/vm/interpreter.go
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down Expand Up @@ -262,7 +264,7 @@ func (in *EVMInterpreter) Run(contract *Contract, input []byte, readOnly bool) (
}
pc++
}

if err == errStopToken {
err = nil // clear stop token error
}
Expand Down
12 changes: 12 additions & 0 deletions core/vm/jump_table.go
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
4 changes: 3 additions & 1 deletion core/vm/opcodes.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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",
Expand Down
Loading

0 comments on commit 38a192e

Please sign in to comment.