Skip to content

Commit 175036b

Browse files
MariusVanDerWijdenjagdeep sidhu
authored andcommitted
core/evm: RANDOM opcode (EIP-4399) (ethereum#24141)
1 parent d3f79e0 commit 175036b

File tree

21 files changed

+124
-29
lines changed

21 files changed

+124
-29
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ type ommer struct {
6767
type stEnv struct {
6868
Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
6969
Difficulty *big.Int `json:"currentDifficulty"`
70+
Random *big.Int `json:"currentRandom"`
7071
ParentDifficulty *big.Int `json:"parentDifficulty"`
7172
GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
7273
Number uint64 `json:"currentNumber" gencodec:"required"`
@@ -81,6 +82,7 @@ type stEnv struct {
8182
type stEnvMarshaling struct {
8283
Coinbase common.UnprefixedAddress
8384
Difficulty *math.HexOrDecimal256
85+
Random *math.HexOrDecimal256
8486
ParentDifficulty *math.HexOrDecimal256
8587
GasLimit math.HexOrDecimal64
8688
Number math.HexOrDecimal64
@@ -139,6 +141,11 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
139141
if pre.Env.BaseFee != nil {
140142
vmContext.BaseFee = new(big.Int).Set(pre.Env.BaseFee)
141143
}
144+
// If random is defined, add it to the vmContext.
145+
if pre.Env.Random != nil {
146+
rnd := common.BigToHash(pre.Env.Random)
147+
vmContext.Random = &rnd
148+
}
142149
// If DAO is supported/enabled, we need to handle it here. In geth 'proper', it's
143150
// done in StateProcessor.Process(block, ...), right before transactions are applied.
144151
if chainConfig.DAOForkSupport &&

cmd/evm/internal/t8ntool/gen_stenv.go

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

cmd/evm/internal/t8ntool/transition.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -252,6 +252,10 @@ func Transition(ctx *cli.Context) error {
252252
return NewError(ErrorConfig, errors.New("EIP-1559 config but missing 'currentBaseFee' in env section"))
253253
}
254254
}
255+
// Sanity check, to not `panic` in state_transition
256+
if prestate.Env.Random != nil && !chainConfig.IsLondon(big.NewInt(int64(prestate.Env.Number))) {
257+
return NewError(ErrorConfig, errors.New("can only apply RANDOM on top of London chainrules"))
258+
}
255259
if env := prestate.Env; env.Difficulty == nil {
256260
// If difficulty was not provided by caller, we need to calculate it.
257261
switch {

consensus/beacon/consensus.go

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,6 @@ var (
4343
// error types into the consensus package.
4444
var (
4545
errTooManyUncles = errors.New("too many uncles")
46-
errInvalidMixDigest = errors.New("invalid mix digest")
4746
errInvalidNonce = errors.New("invalid nonce")
4847
errInvalidUncleHash = errors.New("invalid uncle hash")
4948
)
@@ -182,10 +181,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
182181
if len(header.Extra) > 32 {
183182
return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra))
184183
}
185-
// Verify the seal parts. Ensure the mixhash, nonce and uncle hash are the expected value.
186-
if header.MixDigest != (common.Hash{}) {
187-
return errInvalidMixDigest
188-
}
184+
// Verify the seal parts. Ensure the nonce and uncle hash are the expected value.
189185
if header.Nonce != beaconNonce {
190186
return errInvalidNonce
191187
}

core/evm.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
4242
var (
4343
beneficiary common.Address
4444
baseFee *big.Int
45+
random *common.Hash
4546
)
4647
// If we don't have an explicit author (i.e. not mining), extract from the header
4748
if author == nil {
@@ -52,6 +53,9 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
5253
if header.BaseFee != nil {
5354
baseFee = new(big.Int).Set(header.BaseFee)
5455
}
56+
if header.Difficulty.Cmp(common.Big0) == 0 {
57+
random = &header.MixDigest
58+
}
5559
return vm.BlockContext{
5660
CanTransfer: CanTransfer,
5761
Transfer: Transfer,
@@ -64,6 +68,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
6468
Difficulty: new(big.Int).Set(header.Difficulty),
6569
BaseFee: baseFee,
6670
GasLimit: header.GasLimit,
71+
Random: random,
6772
}
6873
}
6974

core/genesis.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -298,7 +298,7 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
298298
if g.GasLimit == 0 {
299299
head.GasLimit = params.GenesisGasLimit
300300
}
301-
if g.Difficulty == nil {
301+
if g.Difficulty == nil && g.Mixhash == (common.Hash{}) {
302302
head.Difficulty = params.GenesisDifficulty
303303
}
304304
if g.Config != nil && g.Config.IsLondon(common.Big0) {

core/state_transition.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
310310
}
311311

312312
// Set up the initial access list.
313-
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin {
313+
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Context.Random != nil); rules.IsBerlin {
314314
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
315315
}
316316
var (

core/vm/evm.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,7 @@ type BlockContext struct {
7979
Time *big.Int // Provides information for TIME
8080
Difficulty *big.Int // Provides information for DIFFICULTY
8181
BaseFee *big.Int // Provides information for BASEFEE
82+
Random *common.Hash // Provides information for RANDOM
8283
}
8384

8485
// TxContext provides the EVM with information about a transaction.
@@ -135,7 +136,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
135136
StateDB: statedb,
136137
Config: config,
137138
chainConfig: chainConfig,
138-
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
139+
chainRules: chainConfig.Rules(blockCtx.BlockNumber, blockCtx.Random != nil),
139140
}
140141
evm.interpreter = NewEVMInterpreter(evm, config)
141142
return evm

core/vm/instructions.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -499,6 +499,12 @@ func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
499499
return nil, nil
500500
}
501501

502+
func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
503+
v := new(uint256.Int).SetBytes((interpreter.evm.Context.Random.Bytes()))
504+
scope.Stack.push(v)
505+
return nil, nil
506+
}
507+
502508
func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
503509
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
504510
return nil, nil

core/vm/instructions_test.go

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"encoding/json"
2222
"fmt"
2323
"io/ioutil"
24+
"math/big"
2425
"testing"
2526

2627
"github.com/ethereum/go-ethereum/common"
@@ -654,3 +655,36 @@ func TestCreate2Addreses(t *testing.T) {
654655
}
655656
}
656657
}
658+
659+
func TestRandom(t *testing.T) {
660+
type testcase struct {
661+
name string
662+
random common.Hash
663+
}
664+
665+
for _, tt := range []testcase{
666+
{name: "empty hash", random: common.Hash{}},
667+
{name: "1", random: common.Hash{0}},
668+
{name: "emptyCodeHash", random: emptyCodeHash},
669+
{name: "hash(0x010203)", random: crypto.Keccak256Hash([]byte{0x01, 0x02, 0x03})},
670+
} {
671+
var (
672+
env = NewEVM(BlockContext{Random: &tt.random}, TxContext{}, nil, params.TestChainConfig, Config{})
673+
stack = newstack()
674+
pc = uint64(0)
675+
evmInterpreter = env.interpreter
676+
)
677+
opRandom(&pc, evmInterpreter, &ScopeContext{nil, stack, nil})
678+
if len(stack.data) != 1 {
679+
t.Errorf("Expected one item on stack after %v, got %d: ", tt.name, len(stack.data))
680+
}
681+
actual := stack.pop()
682+
expected, overflow := uint256.FromBig(new(big.Int).SetBytes(tt.random.Bytes()))
683+
if overflow {
684+
t.Errorf("Testcase %v: invalid overflow", tt.name)
685+
}
686+
if actual.Cmp(expected) != 0 {
687+
t.Errorf("Testcase %v: expected %x, got %x", tt.name, expected, actual)
688+
}
689+
}
690+
}

0 commit comments

Comments
 (0)