Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft implementation of EIP-4399 #23985

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions cmd/evm/internal/t8ntool/execution.go
Expand Up @@ -67,6 +67,7 @@ type ommer struct {
type stEnv struct {
Coinbase common.Address `json:"currentCoinbase" gencodec:"required"`
Difficulty *big.Int `json:"currentDifficulty"`
Random *big.Int `json:"currentRandom"`
ParentDifficulty *big.Int `json:"parentDifficulty"`
GasLimit uint64 `json:"currentGasLimit" gencodec:"required"`
Number uint64 `json:"currentNumber" gencodec:"required"`
Expand All @@ -81,6 +82,7 @@ type stEnv struct {
type stEnvMarshaling struct {
Coinbase common.UnprefixedAddress
Difficulty *math.HexOrDecimal256
Random *math.HexOrDecimal256
ParentDifficulty *math.HexOrDecimal256
GasLimit math.HexOrDecimal64
Number math.HexOrDecimal64
Expand Down
6 changes: 6 additions & 0 deletions cmd/evm/internal/t8ntool/gen_stenv.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion cmd/geth/config.go
Expand Up @@ -159,7 +159,7 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
cfg.Eth.OverrideArrowGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideArrowGlacierFlag.Name))
}
if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) {
cfg.Eth.Genesis.Config.TerminalTotalDifficulty = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideTerminalTotalDifficulty.Name))
cfg.Eth.OverrideTerminalTotalDifficulty = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideTerminalTotalDifficulty.Name))
}
backend, _ := utils.RegisterEthService(stack, &cfg.Eth, ctx.GlobalBool(utils.CatalystFlag.Name))

Expand Down
5 changes: 1 addition & 4 deletions consensus/beacon/consensus.go
Expand Up @@ -181,10 +181,7 @@ func (beacon *Beacon) verifyHeader(chain consensus.ChainHeaderReader, header, pa
if len(header.Extra) > 32 {
return fmt.Errorf("extra-data longer than 32 bytes (%d)", len(header.Extra))
}
// Verify the seal parts. Ensure the mixhash, nonce and uncle hash are the expected value.
if header.MixDigest != (common.Hash{}) {
return errInvalidMixDigest
}
// Verify the seal parts. Ensure the nonce and uncle hash are the expected value.
if header.Nonce != beaconNonce {
return errInvalidNonce
}
Expand Down
6 changes: 6 additions & 0 deletions core/blockchain_reader.go
Expand Up @@ -343,6 +343,12 @@ func (bc *BlockChain) GetVMConfig() *vm.Config {
return &bc.vmConfig
}

// SetVMConfig sets the vm config.
// Warning: might not be threadsafe with other components
func (bc *BlockChain) SetVMConfig(config vm.Config) {
bc.vmConfig = config
}

// SetTxLookupLimit is responsible for updating the txlookup limit to the
// original one stored in db if the new mismatches with the old one.
func (bc *BlockChain) SetTxLookupLimit(limit uint64) {
Expand Down
1 change: 1 addition & 0 deletions core/evm.go
Expand Up @@ -61,6 +61,7 @@ func NewEVMBlockContext(header *types.Header, chain ChainContext, author *common
Difficulty: new(big.Int).Set(header.Difficulty),
BaseFee: baseFee,
GasLimit: header.GasLimit,
Random: header.MixDigest,
}
}

Expand Down
3 changes: 2 additions & 1 deletion core/genesis.go
Expand Up @@ -294,7 +294,8 @@ func (g *Genesis) ToBlock(db ethdb.Database) *types.Block {
if g.GasLimit == 0 {
head.GasLimit = params.GenesisGasLimit
}
if g.Difficulty == nil {
emptyHash := common.Hash{}
if g.Difficulty == nil && bytes.Equal(g.Mixhash[:], emptyHash[:]) {
head.Difficulty = params.GenesisDifficulty
}
if g.Config != nil && g.Config.IsLondon(common.Big0) {
Expand Down
2 changes: 1 addition & 1 deletion core/state_transition.go
Expand Up @@ -310,7 +310,7 @@ func (st *StateTransition) TransitionDb() (*ExecutionResult, error) {
}

// Set up the initial access list.
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber); rules.IsBerlin {
if rules := st.evm.ChainConfig().Rules(st.evm.Context.BlockNumber, st.evm.Config.RandomOpcode); rules.IsBerlin {
st.state.PrepareAccessList(msg.From(), msg.To(), vm.ActivePrecompiles(rules), msg.AccessList())
}
var (
Expand Down
3 changes: 2 additions & 1 deletion core/vm/evm.go
Expand Up @@ -75,6 +75,7 @@ type BlockContext struct {
Time *big.Int // Provides information for TIME
Difficulty *big.Int // Provides information for DIFFICULTY
BaseFee *big.Int // Provides information for BASEFEE
Random common.Hash // Provides information for RANDOM
}

// TxContext provides the EVM with information about a transaction.
Expand Down Expand Up @@ -131,7 +132,7 @@ func NewEVM(blockCtx BlockContext, txCtx TxContext, statedb StateDB, chainConfig
StateDB: statedb,
Config: config,
chainConfig: chainConfig,
chainRules: chainConfig.Rules(blockCtx.BlockNumber),
chainRules: chainConfig.Rules(blockCtx.BlockNumber, config.RandomOpcode),
}
evm.interpreter = NewEVMInterpreter(evm, config)
return evm
Expand Down
6 changes: 6 additions & 0 deletions core/vm/instructions.go
Expand Up @@ -475,6 +475,12 @@ func opDifficulty(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext)
return nil, nil
}

func opRandom(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
v := new(uint256.Int).SetBytes((interpreter.evm.Context.Random.Bytes()))
scope.Stack.push(v)
return nil, nil
}

func opGasLimit(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) ([]byte, error) {
scope.Stack.push(new(uint256.Int).SetUint64(interpreter.evm.Context.GasLimit))
return nil, nil
Expand Down
34 changes: 34 additions & 0 deletions core/vm/instructions_test.go
Expand Up @@ -21,6 +21,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"math/big"
"testing"

"github.com/ethereum/go-ethereum/common"
Expand Down Expand Up @@ -650,3 +651,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(BlockContext{Random: tt.random}, TxContext{}, nil, params.TestChainConfig, Config{RandomOpcode: true})
stack = newstack()
pc = uint64(0)
evmInterpreter = env.interpreter
)
opRandom(&pc, evmInterpreter, &ScopeContext{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)
}
}
}
3 changes: 3 additions & 0 deletions core/vm/interpreter.go
Expand Up @@ -31,6 +31,7 @@ type Config struct {
Tracer EVMLogger // Opcode logger
NoRecursion bool // Disables call, callcode, delegate call and create
NoBaseFee bool // Forces the EIP-1559 baseFee to 0 (needed for 0 price calls)
RandomOpcode bool // Enables the random opcode
EnablePreimageRecording bool // Enables recording of SHA3/keccak preimages

JumpTable JumpTable // EVM instruction table, automatically populated if unset
Expand Down Expand Up @@ -74,6 +75,8 @@ func NewEVMInterpreter(evm *EVM, cfg Config) *EVMInterpreter {
if cfg.JumpTable[STOP] == nil {
var jt JumpTable
switch {
case evm.chainRules.IsMerge:
jt = newMergeInstructionSet()
case evm.chainRules.IsLondon:
jt = londonInstructionSet
case evm.chainRules.IsBerlin:
Expand Down
12 changes: 12 additions & 0 deletions core/vm/jump_table.go
Expand Up @@ -58,11 +58,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[RANDOM] = &operation{
execute: opRandom,
constantGas: GasQuickStep,
minStack: minStack(0, 1),
maxStack: maxStack(0, 1),
}
return instructionSet
}

// newLondonInstructionSet returns the frontier, homestead, byzantium,
// contantinople, istanbul, petersburg, berlin and london instructions.
func newLondonInstructionSet() JumpTable {
Expand Down
3 changes: 2 additions & 1 deletion core/vm/opcodes.go
Expand Up @@ -104,6 +104,7 @@ const (
CHAINID OpCode = 0x46
SELFBALANCE OpCode = 0x47
BASEFEE OpCode = 0x48
RANDOM OpCode = 0x44 // Same as DIFFICULTY
)

// 0x50 range - 'storage' and execution.
Expand Down Expand Up @@ -279,7 +280,7 @@ var opCodeToString = map[OpCode]string{
COINBASE: "COINBASE",
TIMESTAMP: "TIMESTAMP",
NUMBER: "NUMBER",
DIFFICULTY: "DIFFICULTY",
DIFFICULTY: "DIFFICULTY", // TODO (MariusVanDerWijden) rename to RANDOM post merge
GASLIMIT: "GASLIMIT",
CHAINID: "CHAINID",
SELFBALANCE: "SELFBALANCE",
Expand Down
6 changes: 3 additions & 3 deletions core/vm/runtime/runtime.go
Expand Up @@ -118,7 +118,7 @@ func Execute(code, input []byte, cfg *Config) ([]byte, *state.StateDB, error) {
vmenv = NewEnv(cfg)
sender = vm.AccountRef(cfg.Origin)
)
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, false); rules.IsBerlin {
cfg.State.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
}
cfg.State.CreateAccount(address)
Expand Down Expand Up @@ -150,7 +150,7 @@ func Create(input []byte, cfg *Config) ([]byte, common.Address, uint64, error) {
vmenv = NewEnv(cfg)
sender = vm.AccountRef(cfg.Origin)
)
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, false); rules.IsBerlin {
cfg.State.PrepareAccessList(cfg.Origin, nil, vm.ActivePrecompiles(rules), nil)
}
// Call the code with the given configuration.
Expand All @@ -176,7 +176,7 @@ func Call(address common.Address, input []byte, cfg *Config) ([]byte, uint64, er
sender := cfg.State.GetOrNewStateObject(cfg.Origin)
statedb := cfg.State

if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber); rules.IsBerlin {
if rules := cfg.ChainConfig.Rules(vmenv.Context.BlockNumber, false); rules.IsBerlin {
statedb.PrepareAccessList(cfg.Origin, &address, vm.ActivePrecompiles(rules), nil)
}
// Call the code with the given configuration.
Expand Down