Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -98,6 +98,11 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
isMiko := p.config.IsMiko(blockNumber)
isSystemTxsSection := false

// EIP-2935: Store the parent block hash in the history storage contract
if p.config.IsPrague(block.Number()) {
ProcessParentBlockHash(block.ParentHash(), vmenv)
}

for i, tx := range block.Transactions() {
if isPoSA {
if isSystemTx, err := posa.IsSystemTransaction(tx, block.Header()); err != nil {
Expand Down Expand Up @@ -143,6 +148,19 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
return receipts, allLogs, *blockContext.InternalTransactions, *usedGas, nil
}

// ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935.
func ProcessParentBlockHash(prevHash common.Hash, vmenv *vm.EVM) {
msg := types.NewMessage(consensus.SystemAddress, &params.HistoryStorageAddress, 0, common.Big0, 30_000_000, common.Big0, common.Big0, common.Big0, prevHash.Bytes(), nil, false, nil, nil)
vmenv.Reset(NewEVMTxContext(msg), vmenv.StateDB)
vmenv.StateDB.AddAddressToAccessList(params.HistoryStorageAddress)
_, _, err := vmenv.Call(vm.AccountRef(msg.From()), *msg.To(), msg.Data(), 30_000_000, common.Big0)
if err != nil {
log.Error("Failed to store parent block hash in history storage contract", "err", err)
Comment thread
sonhv0212 marked this conversation as resolved.
}
vmenv.StateDB.Finalise(true)
}

func applyTransaction(
msg types.Message,
config *params.ChainConfig,
Expand Down
63 changes: 63 additions & 0 deletions core/state_processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ package core

import (
"crypto/ecdsa"
"encoding/binary"
"fmt"
"math/big"
"strings"
Expand All @@ -33,6 +34,7 @@ import (
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/ethdb/memorydb"
"github.com/ethereum/go-ethereum/params"
"github.com/ethereum/go-ethereum/trie"
"github.com/holiman/uint256"
Expand Down Expand Up @@ -623,3 +625,64 @@ func TestBaseFee(t *testing.T) {
t.Fatalf("Treasury balance mismatches, expect %d got %d", fee, treasuryBalance)
}
}

func TestProcessParentBlockHash(t *testing.T) {
var (
chainConfig = &params.ChainConfig{
ChainID: big.NewInt(1),
HomesteadBlock: big.NewInt(0),
EIP150Block: big.NewInt(0),
EIP155Block: big.NewInt(0),
EIP158Block: big.NewInt(0),
ByzantiumBlock: big.NewInt(0),
ConstantinopleBlock: big.NewInt(0),
PetersburgBlock: big.NewInt(0),
IstanbulBlock: big.NewInt(0),
MuirGlacierBlock: big.NewInt(0),
BerlinBlock: big.NewInt(0),
LondonBlock: big.NewInt(0),
ShanghaiBlock: big.NewInt(0),
CancunBlock: big.NewInt(0),
VenokiBlock: big.NewInt(0),
PragueBlock: big.NewInt(0),
Ethash: new(params.EthashConfig),
}
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)

vmContext = NewEVMBlockContext(parent, nil, &coinbase)
evm = vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vm.Config{})
ProcessParentBlockHash(parent.ParentHash, evm)

// 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)
})
}

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)
}
3 changes: 3 additions & 0 deletions core/vm/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,9 @@ type StateDB interface {
ValidDeployer(common.Address) bool
ValidDeployerV2(common.Address, uint64, *common.Address) bool
Blacklisted(*common.Address, *common.Address) bool

// Finalise must be invoked at the end of a transaction
Finalise(bool)
}

// CallContext provides a basic interface for the EVM calling conventions. The EVM
Expand Down
6 changes: 6 additions & 0 deletions eth/state_accessor.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,12 @@ func (eth *Ethereum) stateAtTransaction(ctx context.Context, block *types.Block,
if err != nil {
return nil, vm.BlockContext{}, nil, nil, err
}
// If prague hardfork, insert parent block hash in the state as per EIP-2935.
if eth.blockchain.Config().IsPrague(block.Number()) {
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)
}
if txIndex == 0 && len(block.Transactions()) == 0 {
return nil, vm.BlockContext{}, statedb, release, nil
}
Expand Down
18 changes: 18 additions & 0 deletions eth/tracers/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -415,6 +415,12 @@ func (api *API) traceChain(start, end *types.Block, config *TraceConfig, closed
failed = err
break
}
// Insert parent hash in history contract.
if api.backend.ChainConfig().IsPrague(next.Number()) {
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)
}
// Clean out any pending release functions of trace state. Note this
// step must be done after constructing tracing state, because the
// tracing state of block next depends on the parent state and construction
Expand Down Expand Up @@ -574,6 +580,10 @@ func (api *API) IntermediateRoots(ctx context.Context, hash common.Hash, config
vmctx = core.NewEVMBlockContext(block.Header(), api.chainContext(ctx), nil)
deleteEmptyObjects = chainConfig.IsEIP158(block.Number())
)
if chainConfig.IsPrague(block.Number()) {
vevm := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), vevm)
}
for i, tx := range block.Transactions() {
if err := ctx.Err(); err != nil {
return nil, err
Expand Down Expand Up @@ -654,6 +664,10 @@ func (api *API) traceBlock(ctx context.Context, block *types.Block, config *Trac
signer = types.MakeSigner(api.backend.ChainConfig(), block.Number())
results = make([]*txTraceResult, len(txs))
)
if api.backend.ChainConfig().IsPrague(block.Number()) {
vmenv := vm.NewEVM(blockCtx, vm.TxContext{}, statedb, api.backend.ChainConfig(), vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), vmenv)
}
for i, tx := range txs {
// Generate the next state snapshot fast without tracing
msg, _ := tx.AsMessage(signer, block.BaseFee())
Expand Down Expand Up @@ -920,6 +934,10 @@ func (api *API) standardTraceBlockToFile(ctx context.Context, block *types.Block
// Note: This copies the config, to not screw up the main config
chainConfig, canon = overrideConfig(chainConfig, config.Overrides)
}
if chainConfig.IsPrague(block.Number()) {
vmenv := vm.NewEVM(vmctx, vm.TxContext{}, statedb, chainConfig, vm.Config{})
core.ProcessParentBlockHash(block.ParentHash(), vmenv)
}
for i, tx := range block.Transactions() {
// Prepare the transaction for un-traced execution
var (
Expand Down
9 changes: 9 additions & 0 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ import (
"github.com/ethereum/go-ethereum/core/state"
"github.com/ethereum/go-ethereum/core/txpool"
"github.com/ethereum/go-ethereum/core/types"
"github.com/ethereum/go-ethereum/core/vm"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/log"
"github.com/ethereum/go-ethereum/params"
Expand Down Expand Up @@ -1199,6 +1200,13 @@ func (w *worker) commitNewWork(interrupt *int32, noempty bool, timestamp int64)
misc.ApplyDAOHardFork(env.state)
}

// EIP-2935: Store the parent block hash in the history storage contract
if w.chainConfig.IsPrague(env.header.Number) {
vmctx := core.NewEVMBlockContext(env.header, w.chain, &w.coinbase)
vevm := vm.NewEVM(vmctx, vm.TxContext{}, env.state, w.chainConfig, vm.Config{})
core.ProcessParentBlockHash(env.header.ParentHash, vevm)
}
Comment thread
trantienduchn marked this conversation as resolved.

// Accumulate the uncles for the current block
uncles := make([]*types.Header, 0, 2)
commitUncles := func(blocks map[common.Hash]*types.Block) {
Expand Down Expand Up @@ -1300,6 +1308,7 @@ func (w *worker) commit(uncles []*types.Header, interval func(), update bool, st
if w.isRunning() {
// Deep copy receipts here to avoid interaction between different tasks.
env := w.current.copy()

// As consortium does not use uncles, we don't care about copying uncles here
block, receipts, err := w.engine.FinalizeAndAssemble(w.chain, env.header, env.state, env.txs, uncles, env.receipts)
if err != nil {
Expand Down
11 changes: 11 additions & 0 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ package params
import (
"math/big"
"time"

"github.com/ethereum/go-ethereum/common"
)

const (
Expand Down Expand Up @@ -187,6 +189,8 @@ const (
MaxBlobsPerBlock = 6 // Maximum number of data blobs per block
BlobPrunePeriod = 518400 // Number of blocks after which to prune old blob
BlobKeepPeriod = 18 * 24 * time.Hour // The approximate period of time before which the blob is pruned

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
Expand All @@ -198,3 +202,10 @@ var (
MinimumDifficulty = big.NewInt(131072) // The minimum that the difficulty may ever be.
DurationLimit = big.NewInt(13) // The decision boundary on the blocktime duration used to determine whether difficulty should go up or not.
)

var (
// HistoryStorageAddress is where the historical block hashes are stored.
HistoryStorageAddress = common.HexToAddress("0x0000F90827F1C53a10cb7A02335B175320002935")
// HistoryStorageCode is the code with getters for historical block hashes.
HistoryStorageCode = common.FromHex("3373fffffffffffffffffffffffffffffffffffffffe14604657602036036042575f35600143038111604257611fff81430311604257611fff9006545f5260205ff35b5f5ffd5b5f35611fff60014303065500")
Comment thread
trantienduchn marked this conversation as resolved.
)