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)
|
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) {
|
||||||
|
// 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++ {
|
for i := 0; txIt.Next(); i++ {
|
||||||
tx, err := txIt.Tx()
|
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{7}): {Balance: big.NewInt(1)}, // ECScalarMul
|
||||||
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
common.BytesToAddress([]byte{8}): {Balance: big.NewInt(1)}, // ECPairing
|
||||||
common.BytesToAddress([]byte{9}): {Balance: big.NewInt(1)}, // BLAKE2b
|
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 {
|
if faucet != nil {
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@
|
||||||
package core
|
package core
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math/big"
|
"math/big"
|
||||||
|
|
@ -80,6 +81,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()) {
|
||||||
|
ProcessBlockHashHistory(statedb, block.Header(), p.config, p.bc)
|
||||||
|
}
|
||||||
// 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)
|
||||||
|
|
@ -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)
|
_, _, _ = vmenv.Call(vm.AccountRef(msg.From), *msg.To, msg.Data, 30_000_000, common.U2560)
|
||||||
statedb.Finalise(true)
|
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 (
|
import (
|
||||||
"crypto/ecdsa"
|
"crypto/ecdsa"
|
||||||
|
"encoding/binary"
|
||||||
"math/big"
|
"math/big"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
|
|
@ -29,9 +30,11 @@ 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/holiman/uint256"
|
"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
|
package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"encoding/binary"
|
||||||
"math"
|
"math"
|
||||||
|
|
||||||
"github.com/ethereum/go-ethereum/common"
|
"github.com/ethereum/go-ethereum/common"
|
||||||
|
|
@ -434,16 +435,27 @@ func opBlockhash(pc *uint64, interpreter *EVMInterpreter, scope *ScopeContext) (
|
||||||
num.Clear()
|
num.Clear()
|
||||||
return nil, nil
|
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
|
var upper, lower uint64
|
||||||
upper = interpreter.evm.Context.BlockNumber.Uint64()
|
upper = interpreter.evm.Context.BlockNumber.Uint64()
|
||||||
if upper < 257 {
|
if upper < historySize+1 {
|
||||||
lower = 0
|
lower = 0
|
||||||
} else {
|
} else {
|
||||||
lower = upper - 256
|
lower = upper - historySize
|
||||||
}
|
}
|
||||||
if num64 >= lower && num64 < upper {
|
if num64 >= lower && num64 < upper {
|
||||||
|
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())
|
num.SetBytes(interpreter.evm.Context.GetHash(num64).Bytes())
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
num.Clear()
|
num.Clear()
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -87,6 +87,11 @@ func newVerkleInstructionSet() JumpTable {
|
||||||
return validate(instructionSet)
|
return validate(instructionSet)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func newPraugeInstructionSet() JumpTable {
|
||||||
|
instructionSet := newCancunInstructionSet()
|
||||||
|
return validate(instructionSet)
|
||||||
|
}
|
||||||
|
|
||||||
func newCancunInstructionSet() JumpTable {
|
func newCancunInstructionSet() JumpTable {
|
||||||
instructionSet := newShanghaiInstructionSet()
|
instructionSet := newShanghaiInstructionSet()
|
||||||
enable4844(&instructionSet) // EIP-4844 (BLOBHASH opcode)
|
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{})
|
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) {
|
||||||
|
core.ProcessBlockHashHistory(env.state, header, miner.chainConfig, miner.chain)
|
||||||
|
}
|
||||||
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
|
||||||
|
|
@ -189,4 +191,11 @@ var (
|
||||||
BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02")
|
BeaconRootsAddress = common.HexToAddress("0x000F3df6D732807Ef1319fB7B8bB8522d0Beac02")
|
||||||
// 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("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