Skip to content

Commit 7e80276

Browse files
s1nagballetjsignholiman
authored andcommitted
core: implement EIP-2935 (ethereum#29465)
https://eips.ethereum.org/EIPS/eip-2935 --------- Co-authored-by: Guillaume Ballet <[email protected]> Co-authored-by: Ignacio Hagopian <[email protected]> Co-authored-by: Martin HS <[email protected]>
1 parent 61b3ebb commit 7e80276

File tree

8 files changed

+136
-6
lines changed

8 files changed

+136
-6
lines changed

cmd/evm/internal/t8ntool/execution.go

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -196,7 +196,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
196196
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
197197
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
198198
}
199-
199+
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) {
200+
var (
201+
prevNumber = pre.Env.Number - 1
202+
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
203+
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
204+
)
205+
core.ProcessParentBlockHash(prevHash, evm, statedb)
206+
}
200207
for i := 0; txIt.Next(); i++ {
201208
tx, err := txIt.Tx()
202209
if err != nil {

core/genesis.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -583,6 +583,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
583583
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
584584
// Pre-deploy EIP-4788 system contract
585585
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
586+
// Pre-deploy EIP-2935 history contract.
587+
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode},
586588
},
587589
}
588590
if faucet != nil {

core/state_processor.go

Lines changed: 37 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
7777
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
7878
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
7979
}
80+
if p.config.IsPrague(block.Number(), block.Time()) {
81+
ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
82+
}
8083
// Iterate over and process the individual transactions
8184
for i, tx := range block.Transactions() {
8285
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
@@ -178,11 +181,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
178181
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
179182
// contract. This method is exported to be used in tests.
180183
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
181-
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil {
182-
vmenv.Config.Tracer.OnSystemCallStart()
183-
}
184-
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil {
185-
defer vmenv.Config.Tracer.OnSystemCallEnd()
184+
if tracer := vmenv.Config.Tracer; tracer != nil {
185+
if tracer.OnSystemCallStart != nil {
186+
tracer.OnSystemCallStart()
187+
}
188+
if tracer.OnSystemCallEnd != nil {
189+
defer tracer.OnSystemCallEnd()
190+
}
186191
}
187192

188193
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
@@ -201,3 +206,30 @@ func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *stat
201206
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
202207
statedb.Finalise(true)
203208
}
209+
210+
// ProcessParentBlockHash stores the parent block hash in the history storage contract
211+
// as per EIP-2935.
212+
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
213+
if tracer := vmenv.Config.Tracer; tracer != nil {
214+
if tracer.OnSystemCallStart != nil {
215+
tracer.OnSystemCallStart()
216+
}
217+
if tracer.OnSystemCallEnd != nil {
218+
defer tracer.OnSystemCallEnd()
219+
}
220+
}
221+
222+
msg := &Message{
223+
From: params.SystemAddress,
224+
GasLimit: 30_000_000,
225+
GasPrice: common.Big0,
226+
GasFeeCap: common.Big0,
227+
GasTipCap: common.Big0,
228+
To: &params.HistoryStorageAddress,
229+
Data: prevHash.Bytes(),
230+
}
231+
vmenv.Reset(NewEVMTxContext(msg), statedb)
232+
statedb.AddAddressToAccessList(params.HistoryStorageAddress)
233+
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
234+
statedb.Finalise(true)
235+
}

core/state_processor_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ package core
1818

1919
import (
2020
"crypto/ecdsa"
21+
"encoding/binary"
2122
"math/big"
2223
"testing"
2324

@@ -29,11 +30,14 @@ import (
2930
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
3031
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
3132
"github.com/ethereum/go-ethereum/core/rawdb"
33+
"github.com/ethereum/go-ethereum/core/state"
3234
"github.com/ethereum/go-ethereum/core/types"
3335
"github.com/ethereum/go-ethereum/core/vm"
3436
"github.com/ethereum/go-ethereum/crypto"
37+
"github.com/ethereum/go-ethereum/ethdb/memorydb"
3538
"github.com/ethereum/go-ethereum/params"
3639
"github.com/ethereum/go-ethereum/trie"
40+
"github.com/ethereum/go-ethereum/triedb"
3741
"github.com/holiman/uint256"
3842
"golang.org/x/crypto/sha3"
3943
)
@@ -528,3 +532,54 @@ func TestProcessVerkle(t *testing.T) {
528532
}
529533
}
530534
}
535+
536+
func TestProcessParentBlockHash(t *testing.T) {
537+
var (
538+
chainConfig = params.MergedTestChainConfig
539+
hashA = common.Hash{0x01}
540+
hashB = common.Hash{0x02}
541+
header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)}
542+
parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)}
543+
coinbase = common.Address{}
544+
)
545+
test := func(statedb *state.StateDB) {
546+
statedb.SetNonce(params.HistoryStorageAddress, 1)
547+
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
548+
statedb.IntermediateRoot(true)
549+
550+
vmContext := NewEVMBlockContext(header, nil, &coinbase)
551+
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
552+
ProcessParentBlockHash(header.ParentHash, evm, statedb)
553+
554+
vmContext = NewEVMBlockContext(parent, nil, &coinbase)
555+
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
556+
ProcessParentBlockHash(parent.ParentHash, evm, statedb)
557+
558+
// make sure that the state is correct
559+
if have := getParentBlockHash(statedb, 1); have != hashA {
560+
t.Errorf("want parent hash %v, have %v", hashA, have)
561+
}
562+
if have := getParentBlockHash(statedb, 0); have != hashB {
563+
t.Errorf("want parent hash %v, have %v", hashB, have)
564+
}
565+
}
566+
t.Run("MPT", func(t *testing.T) {
567+
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
568+
test(statedb)
569+
})
570+
t.Run("Verkle", func(t *testing.T) {
571+
db := rawdb.NewMemoryDatabase()
572+
cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme)
573+
cacheConfig.SnapshotLimit = 0
574+
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))
575+
statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
576+
test(statedb)
577+
})
578+
}
579+
580+
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {
581+
ringIndex := number % params.HistoryServeWindow
582+
var key common.Hash
583+
binary.BigEndian.PutUint64(key[24:], ringIndex)
584+
return statedb.GetState(params.HistoryStorageAddress, key)
585+
}

eth/state_accessor.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
239239
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
240240
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
241241
}
242+
// If prague hardfork, insert parent block hash in the state as per EIP-2935.
243+
if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) {
244+
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
245+
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
246+
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
247+
}
242248
if txIndex == 0 && len(block.Transactions()) == 0 {
243249
return nil, vm.BlockContext{}, statedb, release, nil
244250
}

eth/tracers/api.go

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -382,6 +382,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
382382
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
383383
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
384384
}
385+
// Insert parent hash in history contract.
386+
if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) {
387+
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
388+
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
389+
core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb)
390+
}
385391
// Clean out any pending release functions of trace state. Note this
386392
// step must be done after constructing tracing state, because the
387393
// tracing state of block next depends on the parent state and construction
@@ -534,6 +540,9 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
534540
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
535541
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
536542
}
543+
if chainConfig.IsPrague(block.Number(), block.Time()) {
544+
core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), statedb)
545+
}
537546
for i, tx := range block.Transactions() {
538547
if err := ctx.Err(); err != nil {
539548
return nil, err
@@ -613,6 +622,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
613622
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
614623
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
615624
}
625+
if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) {
626+
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
627+
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
628+
}
616629
for i, tx := range txs {
617630
// Generate the next state snapshot fast without tracing
618631
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
@@ -771,6 +784,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
771784
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
772785
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
773786
}
787+
if chainConfig.IsPrague(block.Number(), block.Time()) {
788+
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
789+
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
790+
}
774791
for i, tx := range block.Transactions() {
775792
// Prepare the transaction for un-traced execution
776793
var (

miner/worker.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,11 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error)
200200
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{})
201201
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state)
202202
}
203+
if miner.chainConfig.IsPrague(header.Number, header.Time) {
204+
context := core.NewEVMBlockContext(header, miner.chain, nil)
205+
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{})
206+
core.ProcessParentBlockHash(header.ParentHash, vmenv, env.state)
207+
}
203208
return env, nil
204209
}
205210

params/protocol_params.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ const (
174174

175175
BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing)
176176
MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block
177+
178+
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
177179
)
178180

179181
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
@@ -193,4 +195,8 @@ var (
193195

194196
// SystemAddress is where the system-transaction is sent from as per EIP-4788
195197
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
198+
// HistoryStorageAddress is where the historical block hashes are stored.
199+
HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e")
200+
// HistoryStorageCode is the code with getters for historical block hashes.
201+
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500")
196202
)

0 commit comments

Comments
 (0)