Skip to content

Commit

Permalink
core: implement eip-2935
Browse files Browse the repository at this point in the history
Co-authored-by: Guillaume Ballet <gballet@gmail.com>
Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com>
  • Loading branch information
3 people authored and lightclient committed May 13, 2024
1 parent 6d51c1f commit 62cf853
Show file tree
Hide file tree
Showing 6 changed files with 117 additions and 2 deletions.
10 changes: 10 additions & 0 deletions cmd/evm/internal/t8ntool/execution.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,16 @@ func (pre *Prestate) Apply(vmConfig vm.Config, chainConfig *params.ChainConfig,
evm := vm.NewEVM(vmContext, vm.TxContext{}, statedb, chainConfig, vmConfig)
core.ProcessBeaconBlockRoot(*beaconRoot, evm, statedb)
}
if pre.Env.BlockHashes != nil && chainConfig.IsPrague(new(big.Int).SetUint64(pre.Env.Number), pre.Env.Timestamp) {
// insert all parent hashes in the contract
for i, h := range pre.Env.BlockHashes {
n := uint64(i)
if n >= pre.Env.Number || pre.Env.Number > (n+params.HistoryServeWindow) {
continue
}
core.ProcessParentBlockHash(statedb, n, h)
}
}

for i := 0; txIt.Next(); i++ {
tx, err := txIt.Tx()
Expand Down
38 changes: 38 additions & 0 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package core

import (
"encoding/binary"
"errors"
"fmt"
"math/big"
Expand Down Expand Up @@ -80,6 +81,9 @@ func (p *StateProcessor) Process(block *types.Block, statedb *state.StateDB, cfg
if beaconRoot := block.BeaconRoot(); beaconRoot != nil {
ProcessBeaconBlockRoot(*beaconRoot, vmenv, statedb)
}
if p.config.IsPrague(block.Number(), block.Time()) {
ProcessBlockHashHistory(statedb, block.Header(), p.config, p.bc)
}
// Iterate over and process the individual transactions
for i, tx := range block.Transactions() {
msg, err := TransactionToMessage(tx, signer, header.BaseFee)
Expand Down Expand Up @@ -209,3 +213,37 @@ 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)
statedb.Finalise(true)
}

// ProcessBlockHashHistory is called at every block to insert the parent block hash
// in the history storage contract as per EIP-2935. At the EIP-2935 fork block, it
// populates the whole buffer with block hashes.
func ProcessBlockHashHistory(statedb *state.StateDB, header *types.Header, chainConfig *params.ChainConfig, chain consensus.ChainHeaderReader) {
var (
prevHash = header.ParentHash
parent = chain.GetHeaderByHash(prevHash)
number = header.Number.Uint64()
prevNumber = parent.Number.Uint64()
)
ProcessParentBlockHash(statedb, prevNumber, prevHash)
// History already inserted.
if chainConfig.IsPrague(parent.Number, parent.Time) || prevNumber == 0 {
return
}
var low uint64
if number > params.HistoryServeWindow {
low = number - params.HistoryServeWindow
}
for i := prevNumber; i > low; i-- {
ProcessParentBlockHash(statedb, i-1, parent.ParentHash)
parent = chain.GetHeader(parent.ParentHash, i-1)
}
}

// ProcessParentBlockHash stores the parent block hash in the history storage contract
// as per EIP-2935.
func ProcessParentBlockHash(statedb *state.StateDB, prevNumber uint64, prevHash common.Hash) {
ringIndex := prevNumber % params.HistoryServeWindow
var key common.Hash
binary.BigEndian.PutUint64(key[24:], ringIndex)
statedb.SetState(params.HistoryStorageAddress, key, prevHash)
}
55 changes: 55 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"
"math/big"
"testing"

Expand All @@ -29,9 +30,11 @@ import (
"github.com/ethereum/go-ethereum/consensus/misc/eip1559"
"github.com/ethereum/go-ethereum/consensus/misc/eip4844"
"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/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 @@ -528,3 +531,55 @@ func TestProcessVerkle(t *testing.T) {
}
}
}

type MockChain struct {
chain map[common.Hash]*types.Header
}

func (m *MockChain) Config() *params.ChainConfig { return nil }

func (m *MockChain) CurrentHeader() *types.Header { return nil }

func (m *MockChain) GetHeaderByNumber(number uint64) *types.Header { return nil }

func (m *MockChain) GetTd(hash common.Hash, number uint64) *big.Int { return nil }

func (m *MockChain) GetHeaderByHash(hash common.Hash) *types.Header {
return m.chain[hash]
}

func (m *MockChain) GetHeader(hash common.Hash, number uint64) *types.Header {
return m.chain[hash]
}

func TestProcessBlockHashHistory(t *testing.T) {
hashA := common.Hash{0x01}
hashB := common.Hash{0x02}
statedb, _ := state.New(types.EmptyRootHash, state.NewDatabase(rawdb.NewDatabase(memorydb.New())), nil)
header := &types.Header{ParentHash: hashA, Number: big.NewInt(2)}
parent := &types.Header{ParentHash: hashB, Number: big.NewInt(1)}
parentParent := &types.Header{ParentHash: common.Hash{}, Number: big.NewInt(0)}
chainConfig := params.AllDevChainProtocolChanges
chainConfig.PragueTime = nil
chain := new(MockChain)
chain.chain = make(map[common.Hash]*types.Header)
chain.chain[hashA] = parent
chain.chain[hashB] = parentParent

ProcessBlockHashHistory(statedb, header, chainConfig, chain)

// make sure that the state is correct
if have := getParentBlockHash(statedb, 1); have != hashA {
t.Fail()
}
if have := getParentBlockHash(statedb, 0); have != hashB {
t.Fail()
}
}

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)
}
9 changes: 7 additions & 2 deletions core/vm/instructions.go
Original file line number Diff line number Diff line change
Expand Up @@ -434,12 +434,17 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
num.Clear()
return nil, nil
}
historySize := uint64(256)
// EIP-2935 extends the observable history window.
if interpreter.evm.ChainConfig().IsPrague(interpreter.evm.Context.BlockNumber, interpreter.evm.Context.Time) {
historySize = params.HistoryServeWindow
}
var upper, lower uint64
upper = interpreter.evm.Context.BlockNumber.Uint64()
if upper < 257 {
if upper < historySize+1 {
lower = 0
} else {
lower = upper - 256
lower = upper - historySize
}
if num64 >= lower && num64 < upper {
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
Expand Down
3 changes: 3 additions & 0 deletions miner/worker.go
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@ func (miner *Miner) prepareWork(genParams *generateParams) (*environment, error)
vmenv := vm.NewEVM(context, vm.TxContext{}, env.state, miner.chainConfig, vm.Config{})
core.ProcessBeaconBlockRoot(*header.ParentBeaconRoot, vmenv, env.state)
}
if miner.chainConfig.IsPrague(header.Number, header.Time) {
core.ProcessBlockHashHistory(env.state, header, miner.chainConfig, miner.chain)
}
return env, nil
}

Expand Down
4 changes: 4 additions & 0 deletions params/protocol_params.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,8 @@ const (

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

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 @@ -188,4 +190,6 @@ var (
BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02")
// SystemAddress is where the system-transaction is sent from as per EIP-4788
SystemAddress = common.HexToAddress("0xfffffffffffffffffffffffffffffffffffffffe")
// HistoryStorageAddress is where the historical block hashes are stored.
HistoryStorageAddress = common.HexToAddress("0x25a219378dad9b3503c8268c9ca836a52427a4fb")
)

0 comments on commit 62cf853

Please sign in to comment.