core: implement EIP-2935 (#29465)
https://eips.ethereum.org/EIPS/eip-2935 --------- Co-authored-by: Guillaume Ballet <gballet@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com> Co-authored-by: Martin HS <martin@swende.se>
This commit is contained in:
parent
4e17f28740
commit
a223efcf39
|
@ -196,7 +196,14 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
|
||||||
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
|
||||||
}
|
}
|
||||||
|
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) {
|
||||||
|
var (
|
||||||
|
prevNumber = pre.Env.Number - 1
|
||||||
|
prevHash = pre.Env.BlockHashes[math.HexOrDecimal64(prevNumber)]
|
||||||
|
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
|
||||||
|
)
|
||||||
|
core.ProcessParentBlockHash(prevHash, evm, statedb)
|
||||||
|
}
|
||||||
for i := 0; txIt.Next(); i++ {
|
for i := 0; txIt.Next(); i++ {
|
||||||
tx, err := txIt.Tx()
|
tx, err := txIt.Tx()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -583,6 +583,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
||||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||||
// Pre-deploy EIP-4788 system contract
|
// Pre-deploy EIP-4788 system contract
|
||||||
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
params.BeaconRootsAddress: {Nonce: 1, Code: params.BeaconRootsCode, Balance: common.Big0},
|
||||||
|
// Pre-deploy EIP-2935 history contract.
|
||||||
|
params.HistoryStorageAddress: {Nonce: 1, Code: params.HistoryStorageCode},
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
if faucet != nil {
|
if faucet != nil {
|
||||||
|
|
|
@ -77,6 +77,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
|
||||||
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
|
||||||
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
if p.config.IsPrague(block.Number(), block.Time()) {
|
||||||
|
ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
// Iterate over and process the individual transactions
|
// Iterate over and process the individual transactions
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
|
||||||
|
@ -178,11 +181,13 @@ func ApplyTransaction(config *params.ChainConfig, bc ChainContext, author *commo
|
||||||
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
// ProcessBeaconBlockRoot applies the EIP-4788 system call to the beacon block root
|
||||||
// contract. This method is exported to be used in tests.
|
// contract. This method is exported to be used in tests.
|
||||||
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
func ProcessBeaconBlockRoot(beaconRoot common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
||||||
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallStart != nil {
|
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||||
vmenv.Config.Tracer.OnSystemCallStart()
|
if tracer.OnSystemCallStart != nil {
|
||||||
}
|
tracer.OnSystemCallStart()
|
||||||
if vmenv.Config.Tracer != nil && vmenv.Config.Tracer.OnSystemCallEnd != nil {
|
}
|
||||||
defer vmenv.Config.Tracer.OnSystemCallEnd()
|
if tracer.OnSystemCallEnd != nil {
|
||||||
|
defer tracer.OnSystemCallEnd()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If EIP-4788 is enabled, we need to invoke the beaconroot storage contract with
|
// 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
|
||||||
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
statedb.Finalise(true)
|
statedb.Finalise(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ProcessParentBlockHash stores the parent block hash in the history storage contract
|
||||||
|
// as per EIP-2935.
|
||||||
|
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM, statedb *state.StateDB) {
|
||||||
|
if tracer := vmenv.Config.Tracer; tracer != nil {
|
||||||
|
if tracer.OnSystemCallStart != nil {
|
||||||
|
tracer.OnSystemCallStart()
|
||||||
|
}
|
||||||
|
if tracer.OnSystemCallEnd != nil {
|
||||||
|
defer tracer.OnSystemCallEnd()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
msg := &Message{
|
||||||
|
From: params.SystemAddress,
|
||||||
|
GasLimit: 30_000_000,
|
||||||
|
GasPrice: common.Big0,
|
||||||
|
GasFeeCap: common.Big0,
|
||||||
|
GasTipCap: common.Big0,
|
||||||
|
To: ¶ms.HistoryStorageAddress,
|
||||||
|
Data: prevHash.Bytes(),
|
||||||
|
}
|
||||||
|
vmenv.Reset(NewEVMTxContext(msg), statedb)
|
||||||
|
statedb.AddAddressToAccessList(params.HistoryStorageAddress)
|
||||||
|
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
|
statedb.Finalise(true)
|
||||||
|
}
|
||||||
|
|
|
@ -18,6 +18,7 @@ package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"encoding/binary"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
@ -29,11 +30,14 @@ import (
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
|
||||||
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
|
||||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||||
|
"github.com/ethereum/go-ethereum/core/state"
|
||||||
"github.com/ethereum/go-ethereum/core/types"
|
"github.com/ethereum/go-ethereum/core/types"
|
||||||
"github.com/ethereum/go-ethereum/core/vm"
|
"github.com/ethereum/go-ethereum/core/vm"
|
||||||
"github.com/ethereum/go-ethereum/crypto"
|
"github.com/ethereum/go-ethereum/crypto"
|
||||||
|
"github.com/ethereum/go-ethereum/ethdb/memorydb"
|
||||||
"github.com/ethereum/go-ethereum/params"
|
"github.com/ethereum/go-ethereum/params"
|
||||||
"github.com/ethereum/go-ethereum/trie"
|
"github.com/ethereum/go-ethereum/trie"
|
||||||
|
"github.com/ethereum/go-ethereum/triedb"
|
||||||
"github.com/holiman/uint256"
|
"github.com/holiman/uint256"
|
||||||
"golang.org/x/crypto/sha3"
|
"golang.org/x/crypto/sha3"
|
||||||
)
|
)
|
||||||
|
@ -528,3 +532,54 @@ func TestProcessVerkle(t *testing.T) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestProcessParentBlockHash(t *testing.T) {
|
||||||
|
var (
|
||||||
|
chainConfig = params.MergedTestChainConfig
|
||||||
|
hashA = common.Hash{0x01}
|
||||||
|
hashB = common.Hash{0x02}
|
||||||
|
header = &types.Header{ParentHash: hashA, Number: big.NewInt(2), Difficulty: big.NewInt(0)}
|
||||||
|
parent = &types.Header{ParentHash: hashB, Number: big.NewInt(1), Difficulty: big.NewInt(0)}
|
||||||
|
coinbase = common.Address{}
|
||||||
|
)
|
||||||
|
test := func(statedb *state.StateDB) {
|
||||||
|
statedb.SetNonce(params.HistoryStorageAddress, 1)
|
||||||
|
statedb.SetCode(params.HistoryStorageAddress, params.HistoryStorageCode)
|
||||||
|
statedb.IntermediateRoot(true)
|
||||||
|
|
||||||
|
vmContext := NewEVMBlockContext(header, nil, &coinbase)
|
||||||
|
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(header.ParentHash, evm, statedb)
|
||||||
|
|
||||||
|
vmContext = NewEVMBlockContext(parent, nil, &coinbase)
|
||||||
|
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
|
ProcessParentBlockHash(parent.ParentHash, evm, statedb)
|
||||||
|
|
||||||
|
// make sure that the state is correct
|
||||||
|
if have := getParentBlockHash(statedb, 1); have != hashA {
|
||||||
|
t.Errorf("want parent hash %v, have %v", hashA, have)
|
||||||
|
}
|
||||||
|
if have := getParentBlockHash(statedb, 0); have != hashB {
|
||||||
|
t.Errorf("want parent hash %v, have %v", hashB, have)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t.Run("MPT", func(t *testing.T) {
|
||||||
|
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
|
||||||
|
test(statedb)
|
||||||
|
})
|
||||||
|
t.Run("Verkle", func(t *testing.T) {
|
||||||
|
db := rawdb.NewMemoryDatabase()
|
||||||
|
cacheConfig := DefaultCacheConfigWithScheme(rawdb.PathScheme)
|
||||||
|
cacheConfig.SnapshotLimit = 0
|
||||||
|
triedb := triedb.NewDatabase(db, cacheConfig.triedbConfig(true))
|
||||||
|
statedb, _ := state.New(types.EmptyVerkleHash, state.NewDatabaseWithNodeDB(db, triedb), nil)
|
||||||
|
test(statedb)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func getParentBlockHash(statedb *state.StateDB, number uint64) common.Hash {
|
||||||
|
ringIndex := number % params.HistoryServeWindow
|
||||||
|
var key common.Hash
|
||||||
|
binary.BigEndian.PutUint64(key[24:], ringIndex)
|
||||||
|
return statedb.GetState(params.HistoryStorageAddress, key)
|
||||||
|
}
|
||||||
|
|
|
@ -239,6 +239,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
|
||||||
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
// If prague hardfork, insert parent block hash in the state as per EIP-2935.
|
||||||
|
if eth.blockchain.Config().IsPrague(block.Number(), block.Time()) {
|
||||||
|
context := core.NewEVMBlockContext(block.Header(), eth.blockchain, nil)
|
||||||
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, eth.blockchain.Config(), vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
if txIndex == 0 && len(block.Transactions()) == 0 {
|
if txIndex == 0 && len(block.Transactions()) == 0 {
|
||||||
return nil, vm.BlockContext{}, statedb, release, nil
|
return nil, vm.BlockContext{}, statedb, release, nil
|
||||||
}
|
}
|
||||||
|
|
|
@ -382,6 +382,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
|
||||||
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
// Insert parent hash in history contract.
|
||||||
|
if api.backend.ChainConfig().IsPrague(next.Number(), next.Time()) {
|
||||||
|
context := core.NewEVMBlockContext(next.Header(), api.chainContext(ctx), nil)
|
||||||
|
vmenv := vm.NewEVM(context, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(next.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
// Clean out any pending release functions of trace state. Note this
|
// Clean out any pending release functions of trace state. Note this
|
||||||
// step must be done after constructing tracing state, because the
|
// step must be done after constructing tracing state, because the
|
||||||
// tracing state of block next depends on the parent state and construction
|
// 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
|
||||||
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{}), statedb)
|
||||||
|
}
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
if err := ctx.Err(); err != nil {
|
if err := ctx.Err(); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
@ -613,6 +622,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
|
||||||
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
|
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
if api.backend.ChainConfig().IsPrague(block.Number(), block.Time()) {
|
||||||
|
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
for i, tx := range txs {
|
for i, tx := range txs {
|
||||||
// Generate the next state snapshot fast without tracing
|
// Generate the next state snapshot fast without tracing
|
||||||
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
msg, _ := core.TransactionToMessage(tx, signer, block.BaseFee())
|
||||||
|
@ -771,6 +784,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
|
||||||
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
core.ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
|
||||||
}
|
}
|
||||||
|
if chainConfig.IsPrague(block.Number(), block.Time()) {
|
||||||
|
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(block.ParentHash(), vmenv, statedb)
|
||||||
|
}
|
||||||
for i, tx := range block.Transactions() {
|
for i, tx := range block.Transactions() {
|
||||||
// Prepare the transaction for un-traced execution
|
// Prepare the transaction for un-traced execution
|
||||||
var (
|
var (
|
||||||
|
|
|
@ -200,6 +200,11 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error)
|
||||||
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{})
|
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{})
|
||||||
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state)
|
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state)
|
||||||
}
|
}
|
||||||
|
if miner.chainConfig.IsPrague(header.Number, header.Time) {
|
||||||
|
context := core.NewEVMBlockContext(header, miner.chain, nil)
|
||||||
|
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{})
|
||||||
|
core.ProcessParentBlockHash(header.ParentHash, vmenv, env.state)
|
||||||
|
}
|
||||||
return env, nil
|
return env, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -174,6 +174,8 @@ const (
|
||||||
|
|
||||||
BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing)
|
BlobTxTargetBlobGasPerBlock = 3 * BlobTxBlobGasPerBlob // Target consumable blob gas for data blobs per block (for 1559-like pricing)
|
||||||
MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block
|
MaxBlobGasPerBlock = 6 * BlobTxBlobGasPerBlob // Maximum consumable blob gas for data blobs per block
|
||||||
|
|
||||||
|
HistoryServeWindow = 8192 // Number of blocks to serve historical block hashes for, EIP-2935.
|
||||||
)
|
)
|
||||||
|
|
||||||
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
||||||
|
@ -193,4 +195,8 @@ var (
|
||||||
|
|
||||||
// SystemAddress is where the system-transaction is sent from as per EIP-4788
|
// SystemAddress is where the system-transaction is sent from as per EIP-4788
|
||||||
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
|
||||||
|
// HistoryStorageAddress is where the historical block hashes are stored.
|
||||||
|
HistoryStorageAddress = common.HexToAddress("0x0aae40965e6800cd9b1f4b05ff21581047e3f91e")
|
||||||
|
// HistoryStorageCode is the code with getters for historical block hashes.
|
||||||
|
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe1460575767ffffffffffffffff5f3511605357600143035f3511604b575f35612000014311604b57611fff5f3516545f5260205ff35b5f5f5260205ff35b5f5ffd5b5f35611fff60014303165500")
|
||||||
)
|
)
|
||||||
|
|
Loading…
Reference in New Issue