mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-19 18:32:23 +00:00
core: implement eip-2935
Co-authored-by: Guillaume Ballet <gballet@gmail.com> Co-authored-by: Ignacio Hagopian <jsign.uy@gmail.com>
This commit is contained in:
parent
44a50c9f96
commit
20f1d2ceed
8 changed files with 138 additions and 4 deletions
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -593,6 +593,8 @@ func DeveloperGenesisBlock(gasLimit uint64, faucet *common.Address) *Genesis {
|
|||
common.BytesToAddress([]byte{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
||||
// Pre-deploy EIP-2935 history contract.
|
||||
params.HistoryStorageAddress: types.Account{Nonce: 1, Code: params.HistoryStorageCode},
|
||||
},
|
||||
}
|
||||
if faucet != nil {
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package core
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"errors"
|
||||
"fmt"
|
||||
"math/big"
|
||||
|
|
@ -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)
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -18,6 +18,7 @@ package core
|
|||
|
||||
import (
|
||||
"crypto/ecdsa"
|
||||
"encoding/binary"
|
||||
"math/big"
|
||||
"testing"
|
||||
|
||||
|
|
@ -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"
|
||||
|
|
@ -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)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@
|
|||
package vm
|
||||
|
||||
import (
|
||||
"encoding/binary"
|
||||
"math"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
|
|
@ -434,16 +435,27 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
|||
num.Clear()
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
historySize := uint64(256)
|
||||
isPrague := interpreter.evm.ChainConfig().IsPrague(interpreter.evm.Context.BlockNumber, interpreter.evm.Context.Time)
|
||||
// EIP-2935 extends the observable history window.
|
||||
if isPrague {
|
||||
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())
|
||||
if isPrague {
|
||||
var key common.Hash
|
||||
binary.BigEndian.PutUint64(key[24:], num64 % params.HistoryServeWindow)
|
||||
num.SetBytes(interpreter.evm.StateDB.GetState(params.HistoryStorageAddress, key).Bytes())
|
||||
} else {
|
||||
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
||||
}
|
||||
} else {
|
||||
num.Clear()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,6 +87,11 @@ func newVerkleInstructionSet() JumpTable {
|
|||
return validate(instructionSet)
|
||||
}
|
||||
|
||||
func newPraugeInstructionSet() JumpTable {
|
||||
instructionSet := newCancunInstructionSet()
|
||||
return validate(instructionSet)
|
||||
}
|
||||
|
||||
func newCancunInstructionSet() JumpTable {
|
||||
instructionSet := newShanghaiInstructionSet()
|
||||
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -174,6 +174,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
|
||||
|
|
@ -189,4 +191,11 @@ 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")
|
||||
// HistoryStorageCode is the code with getters for historical block hashes.
|
||||
HistoryStorageCode = common.FromHex("60203611603157600143035f35116029575f356120000143116029576120005f3506545f5260205ff35b5f5f5260205ff35b5f5ffd00")
|
||||
|
||||
// Magic prefix for EIP-3074 AUTH messages.
|
||||
AuthMagic = byte(0x04)
|
||||
)
|
||||
|
|
|
|||
Loading…
Reference in a new issue