mirror of
https://github.com/ethereum/go-ethereum.git
synced 2026-08-20 10:52:25 +00:00
eip-7547: implement NewInclusionListV1
This commit is contained in:
parent
bca6c40709
commit
4cce9f9970
28 changed files with 446 additions and 159 deletions
|
|
@ -74,6 +74,7 @@ type ExecutableData struct {
|
|||
Withdrawals []*types.Withdrawal `json:"withdrawals"`
|
||||
BlobGasUsed *uint64 `json:"blobGasUsed"`
|
||||
ExcessBlobGas *uint64 `json:"excessBlobGas"`
|
||||
InclusionListSummary *types.InclusionListSummary `json:"inclusionListSummary"`
|
||||
}
|
||||
|
||||
// JSON type overrides for executableData.
|
||||
|
|
@ -175,7 +176,7 @@ func encodeTransactions(txs []*types.Transaction) [][]byte {
|
|||
return enc
|
||||
}
|
||||
|
||||
func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||
func DecodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
||||
var txs = make([]*types.Transaction, len(enc))
|
||||
for i, encTx := range enc {
|
||||
var tx types.Transaction
|
||||
|
|
@ -199,7 +200,7 @@ func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
|
|||
// Withdrawals value will propagate through the returned block. Empty
|
||||
// Withdrawals value must be passed via non-nil, length 0 value in params.
|
||||
func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
|
||||
txs, err := decodeTransactions(params.Transactions)
|
||||
txs, err := DecodeTransactions(params.Transactions)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
|
@ -233,6 +234,11 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
|||
h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil))
|
||||
withdrawalsRoot = &h
|
||||
}
|
||||
var inclusionRoot *common.Hash
|
||||
if params.InclusionListSummary != nil {
|
||||
h := types.DeriveSha(types.InclusionList{List: params.InclusionListSummary.Summary}, trie.NewStackTrie(nil))
|
||||
inclusionRoot = &h
|
||||
}
|
||||
header := &types.Header{
|
||||
ParentHash: params.ParentHash,
|
||||
UncleHash: types.EmptyUncleHash,
|
||||
|
|
@ -253,8 +259,9 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash,
|
|||
ExcessBlobGas: params.ExcessBlobGas,
|
||||
BlobGasUsed: params.BlobGasUsed,
|
||||
ParentBeaconRoot: beaconRoot,
|
||||
InclusionListSummaryRoot: inclusionRoot,
|
||||
}
|
||||
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
|
||||
block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals).WithInclusionList(params.InclusionListSummary.Summary)
|
||||
if block.Hash() != params.BlockHash {
|
||||
return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
|
||||
}
|
||||
|
|
@ -321,3 +328,9 @@ type ClientVersionV1 struct {
|
|||
func (v *ClientVersionV1) String() string {
|
||||
return fmt.Sprintf("%s-%s-%s-%s", v.Code, v.Name, v.Version, v.Commit)
|
||||
}
|
||||
|
||||
// InclusionListStatusV1 is returned by engine_newInclusionListV1
|
||||
type InclusionListStatusV1 struct {
|
||||
Status string `json:"status"`
|
||||
ValidationError *string `json:"validationError"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -216,6 +216,10 @@ func initGenesis(ctx *cli.Context) error {
|
|||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||
overrides.OverrideCancun = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverridePrague.Name) {
|
||||
v := ctx.Uint64(utils.OverridePrague.Name)
|
||||
overrides.OverridePrague = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideVerkle.Name) {
|
||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||
overrides.OverrideVerkle = &v
|
||||
|
|
|
|||
|
|
@ -175,6 +175,10 @@ func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) {
|
|||
v := ctx.Uint64(utils.OverrideCancun.Name)
|
||||
cfg.Eth.OverrideCancun = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverridePrague.Name) {
|
||||
v := ctx.Uint64(utils.OverridePrague.Name)
|
||||
cfg.Eth.OverridePrague = &v
|
||||
}
|
||||
if ctx.IsSet(utils.OverrideVerkle.Name) {
|
||||
v := ctx.Uint64(utils.OverrideVerkle.Name)
|
||||
cfg.Eth.OverrideVerkle = &v
|
||||
|
|
|
|||
|
|
@ -65,6 +65,7 @@ var (
|
|||
utils.USBFlag,
|
||||
utils.SmartCardDaemonPathFlag,
|
||||
utils.OverrideCancun,
|
||||
utils.OverridePrague,
|
||||
utils.OverrideVerkle,
|
||||
utils.EnablePersonal,
|
||||
utils.TxPoolLocalsFlag,
|
||||
|
|
|
|||
|
|
@ -248,6 +248,11 @@ var (
|
|||
Usage: "Manually specify the Cancun fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverridePrague = &cli.Uint64Flag{
|
||||
Name: "override.prague",
|
||||
Usage: "Manually specify the Prague fork timestamp, overriding the bundled setting",
|
||||
Category: flags.EthCategory,
|
||||
}
|
||||
OverrideVerkle = &cli.Uint64Flag{
|
||||
Name: "override.verkle",
|
||||
Usage: "Manually specify the Verkle fork timestamp, overriding the bundled setting",
|
||||
|
|
|
|||
57
consensus/misc/eip7547/eip7547.go
Normal file
57
consensus/misc/eip7547/eip7547.go
Normal file
|
|
@ -0,0 +1,57 @@
|
|||
package eip7547
|
||||
|
||||
import (
|
||||
"math"
|
||||
"math/big"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/core"
|
||||
"github.com/ethereum/go-ethereum/core/txpool"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/holiman/uint256"
|
||||
)
|
||||
|
||||
func VerifyInclusionList(bc *core.BlockChain, parent *types.Block, signer types.Signer, txs []*types.Transaction) error {
|
||||
statedb, err := bc.StateAt(parent.Root())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
for _, tx := range txs {
|
||||
sender, _ := signer.Sender(tx)
|
||||
nonce := statedb.GetNonce(sender)
|
||||
balance := statedb.GetBalance(sender)
|
||||
opts := &txpool.ValidationOptions{
|
||||
Config: bc.Config(),
|
||||
Accept: 0 |
|
||||
1<<types.LegacyTxType |
|
||||
1<<types.AccessListTxType |
|
||||
1<<types.DynamicFeeTxType,
|
||||
MaxSize: 128 * 1024,
|
||||
MinTip: new(big.Int),
|
||||
}
|
||||
if err := txpool.ValidateTransaction(tx, parent.Header(), signer, opts); err != nil {
|
||||
return err
|
||||
}
|
||||
stateOpts := &txpool.ValidationOptionsWithState{
|
||||
State: statedb,
|
||||
FirstNonceGap: func(addr common.Address) uint64 {
|
||||
return statedb.GetNonce(addr) // Nonce gaps are not permitted
|
||||
},
|
||||
UsedAndLeftSlots: func(addr common.Address) (int, int) {
|
||||
return 0, math.MaxInt
|
||||
},
|
||||
ExistingExpenditure: func(addr common.Address) *big.Int {
|
||||
return new(big.Int)
|
||||
},
|
||||
ExistingCost: func(addr common.Address, nonce uint64) *big.Int {
|
||||
return new(big.Int)
|
||||
},
|
||||
}
|
||||
if err := txpool.ValidateTransactionWithState(tx, signer, stateOpts); err != nil {
|
||||
return err
|
||||
}
|
||||
statedb.SetNonce(sender, nonce+1)
|
||||
statedb.SetBalance(sender, balance.Sub(balance, uint256.MustFromBig(tx.Cost())))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
@ -209,6 +209,7 @@ func (e *GenesisMismatchError) Error() string {
|
|||
// ChainOverrides contains the changes to chain config.
|
||||
type ChainOverrides struct {
|
||||
OverrideCancun *uint64
|
||||
OverridePrague *uint64
|
||||
OverrideVerkle *uint64
|
||||
}
|
||||
|
||||
|
|
@ -238,6 +239,9 @@ func SetupGenesisBlockWithOverride(db ethdb.Database, triedb *triedb.Database, g
|
|||
if overrides != nil && overrides.OverrideCancun != nil {
|
||||
config.CancunTime = overrides.OverrideCancun
|
||||
}
|
||||
if overrides != nil && overrides.OverridePrague != nil {
|
||||
config.PragueTime = overrides.OverridePrague
|
||||
}
|
||||
if overrides != nil && overrides.OverrideVerkle != nil {
|
||||
config.VerkleTime = overrides.OverrideVerkle
|
||||
}
|
||||
|
|
|
|||
|
|
@ -753,7 +753,7 @@ func ReadBlock(db ethdb.Reader, hash common.Hash, number uint64) *types.Block {
|
|||
if body == nil {
|
||||
return nil
|
||||
}
|
||||
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals)
|
||||
return types.NewBlockWithHeader(header).WithBody(body.Transactions, body.Uncles).WithWithdrawals(body.Withdrawals).WithInclusionList(body.InclusionListSummary)
|
||||
}
|
||||
|
||||
// WriteBlock serializes a block into the database, header and body separately.
|
||||
|
|
@ -843,7 +843,7 @@ func ReadBadBlock(db ethdb.Reader, hash common.Hash) *types.Block {
|
|||
}
|
||||
for _, bad := range badBlocks {
|
||||
if bad.Header.Hash() == hash {
|
||||
return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals)
|
||||
return types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals).WithInclusionList(bad.Body.InclusionListSummary)
|
||||
}
|
||||
}
|
||||
return nil
|
||||
|
|
@ -862,7 +862,7 @@ func ReadAllBadBlocks(db ethdb.Reader) []*types.Block {
|
|||
}
|
||||
var blocks []*types.Block
|
||||
for _, bad := range badBlocks {
|
||||
blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals))
|
||||
blocks = append(blocks, types.NewBlockWithHeader(bad.Header).WithBody(bad.Body.Transactions, bad.Body.Uncles).WithWithdrawals(bad.Body.Withdrawals).WithInclusionList(bad.Body.InclusionListSummary))
|
||||
}
|
||||
return blocks
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1645,6 +1645,9 @@ func (p *BlobPool) Locals() []common.Address {
|
|||
return []common.Address{}
|
||||
}
|
||||
|
||||
// There is no notion of local accounts in the blob pool.
|
||||
func (p *BlobPool) AddLocalAddr(common.Address) {}
|
||||
|
||||
// Status returns the known status (unknown/pending/queued) of a transaction
|
||||
// identified by their hashes.
|
||||
func (p *BlobPool) Status(hash common.Hash) txpool.TxStatus {
|
||||
|
|
|
|||
|
|
@ -1959,3 +1959,8 @@ func (t *lookup) RemotesBelowTip(threshold *big.Int) types.Transactions {
|
|||
func numSlots(tx *types.Transaction) int {
|
||||
return int((tx.Size() + txSlotSize - 1) / txSlotSize)
|
||||
}
|
||||
|
||||
func (p *LegacyPool) AddLocalAddr(addr common.Address) {
|
||||
p.locals.add(addr)
|
||||
// TODO go through all txs to mark as local now
|
||||
}
|
||||
|
|
|
|||
|
|
@ -159,6 +159,9 @@ type SubPool interface {
|
|||
// Locals retrieves the accounts currently considered local by the pool.
|
||||
Locals() []common.Address
|
||||
|
||||
// AddLocalAddr marks an account as local.
|
||||
AddLocalAddr(common.Address)
|
||||
|
||||
// Status returns the known status (unknown/pending/queued) of a transaction
|
||||
// identified by their hashes.
|
||||
Status(hash common.Hash) TxStatus
|
||||
|
|
|
|||
|
|
@ -464,6 +464,12 @@ func (p *TxPool) Status(hash common.Hash) TxStatus {
|
|||
return TxStatusUnknown
|
||||
}
|
||||
|
||||
func (p *TxPool) MarkLocal(addr common.Address) {
|
||||
for _, pool := range p.subpools {
|
||||
pool.AddLocalAddr(addr)
|
||||
}
|
||||
}
|
||||
|
||||
// Sync is a helper method for unit tests or simulator runs where the chain events
|
||||
// are arriving in quick succession, without any time in between them to run the
|
||||
// internal background reset operations. This method will run an explicit reset
|
||||
|
|
|
|||
|
|
@ -93,6 +93,9 @@ type Header struct {
|
|||
|
||||
// ParentBeaconRoot was added by EIP-4788 and is ignored in legacy headers.
|
||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||
|
||||
// InclusionListSummaryRoot was added by EIP-7547 and is ignored in legacy headers.
|
||||
InclusionListSummaryRoot *common.Hash `json:"inclusionListSummaryRoot" rlp:"optional"`
|
||||
}
|
||||
|
||||
// field type overrides for gencodec
|
||||
|
|
@ -171,6 +174,7 @@ type Body struct {
|
|||
Transactions []*Transaction
|
||||
Uncles []*Header
|
||||
Withdrawals []*Withdrawal `rlp:"optional"`
|
||||
InclusionListSummary []*InclusionListEntry
|
||||
}
|
||||
|
||||
// Block represents an Ethereum block.
|
||||
|
|
@ -195,6 +199,7 @@ type Block struct {
|
|||
uncles []*Header
|
||||
transactions Transactions
|
||||
withdrawals Withdrawals
|
||||
inclusionListSummary []*InclusionListEntry
|
||||
|
||||
// caches
|
||||
hash atomic.Value
|
||||
|
|
@ -212,6 +217,7 @@ type extblock struct {
|
|||
Txs []*Transaction
|
||||
Uncles []*Header
|
||||
Withdrawals []*Withdrawal `rlp:"optional"`
|
||||
InclusionListSummary []*InclusionListEntry
|
||||
}
|
||||
|
||||
// NewBlock creates a new block. The input data is copied, changes to header and to the
|
||||
|
|
@ -332,7 +338,7 @@ func (b *Block) EncodeRLP(w io.Writer) error {
|
|||
// Body returns the non-header content of the block.
|
||||
// Note the returned data is not an independent copy.
|
||||
func (b *Block) Body() *Body {
|
||||
return &Body{b.transactions, b.uncles, b.withdrawals}
|
||||
return &Body{b.transactions, b.uncles, b.withdrawals, b.inclusionListSummary}
|
||||
}
|
||||
|
||||
// Accessors for body data. These do not return a copy because the content
|
||||
|
|
@ -341,6 +347,7 @@ func (b *Block) Body() *Body {
|
|||
func (b *Block) Uncles() []*Header { return b.uncles }
|
||||
func (b *Block) Transactions() Transactions { return b.transactions }
|
||||
func (b *Block) Withdrawals() Withdrawals { return b.withdrawals }
|
||||
func (b *Block) InclusionListSummary() []*InclusionListEntry { return b.inclusionListSummary }
|
||||
|
||||
func (b *Block) Transaction(hash common.Hash) *Transaction {
|
||||
for _, transaction := range b.transactions {
|
||||
|
|
@ -482,6 +489,20 @@ func (b *Block) WithWithdrawals(withdrawals []*Withdrawal) *Block {
|
|||
return block
|
||||
}
|
||||
|
||||
// WithInclusionList returns a copy of the block containing the given inclusionList.
|
||||
func (b *Block) WithInclusionList(summary []*InclusionListEntry) *Block {
|
||||
block := &Block{
|
||||
header: b.header,
|
||||
transactions: b.transactions,
|
||||
uncles: b.uncles,
|
||||
}
|
||||
if summary != nil {
|
||||
block.inclusionListSummary = make([]*InclusionListEntry, len(summary))
|
||||
copy(block.inclusionListSummary, summary)
|
||||
}
|
||||
return block
|
||||
}
|
||||
|
||||
// Hash returns the keccak256 hash of b's header.
|
||||
// The hash is computed on the first call and cached thereafter.
|
||||
func (b *Block) Hash() common.Hash {
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
|||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||
InclusionListSummaryRoot *common.Hash `json:"inclusionListSummaryRoot" rlp:"optional"`
|
||||
Hash common.Hash `json:"hash"`
|
||||
}
|
||||
var enc Header
|
||||
|
|
@ -59,6 +60,7 @@ func (h Header) MarshalJSON() ([]byte, error) {
|
|||
enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed)
|
||||
enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas)
|
||||
enc.ParentBeaconRoot = h.ParentBeaconRoot
|
||||
enc.InclusionListSummaryRoot = h.InclusionListSummaryRoot
|
||||
enc.Hash = h.Hash()
|
||||
return json.Marshal(&enc)
|
||||
}
|
||||
|
|
@ -86,6 +88,7 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
|||
BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed" rlp:"optional"`
|
||||
ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas" rlp:"optional"`
|
||||
ParentBeaconRoot *common.Hash `json:"parentBeaconBlockRoot" rlp:"optional"`
|
||||
InclusionListSummaryRoot *common.Hash `json:"inclusionListSummaryRoot" rlp:"optional"`
|
||||
}
|
||||
var dec Header
|
||||
if err := json.Unmarshal(input, &dec); err != nil {
|
||||
|
|
@ -163,5 +166,8 @@ func (h *Header) UnmarshalJSON(input []byte) error {
|
|||
if dec.ParentBeaconRoot != nil {
|
||||
h.ParentBeaconRoot = dec.ParentBeaconRoot
|
||||
}
|
||||
if dec.InclusionListSummaryRoot != nil {
|
||||
h.InclusionListSummaryRoot = dec.InclusionListSummaryRoot
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,8 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
|||
_tmp3 := obj.BlobGasUsed != nil
|
||||
_tmp4 := obj.ExcessBlobGas != nil
|
||||
_tmp5 := obj.ParentBeaconRoot != nil
|
||||
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 {
|
||||
_tmp6 := obj.InclusionListSummaryRoot != nil
|
||||
if _tmp1 || _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 {
|
||||
if obj.BaseFee == nil {
|
||||
w.Write(rlp.EmptyString)
|
||||
} else {
|
||||
|
|
@ -52,34 +53,41 @@ func (obj *Header) EncodeRLP(_w io.Writer) error {
|
|||
w.WriteBigInt(obj.BaseFee)
|
||||
}
|
||||
}
|
||||
if _tmp2 || _tmp3 || _tmp4 || _tmp5 {
|
||||
if _tmp2 || _tmp3 || _tmp4 || _tmp5 || _tmp6 {
|
||||
if obj.WithdrawalsHash == nil {
|
||||
w.Write([]byte{0x80})
|
||||
} else {
|
||||
w.WriteBytes(obj.WithdrawalsHash[:])
|
||||
}
|
||||
}
|
||||
if _tmp3 || _tmp4 || _tmp5 {
|
||||
if _tmp3 || _tmp4 || _tmp5 || _tmp6 {
|
||||
if obj.BlobGasUsed == nil {
|
||||
w.Write([]byte{0x80})
|
||||
} else {
|
||||
w.WriteUint64((*obj.BlobGasUsed))
|
||||
}
|
||||
}
|
||||
if _tmp4 || _tmp5 {
|
||||
if _tmp4 || _tmp5 || _tmp6 {
|
||||
if obj.ExcessBlobGas == nil {
|
||||
w.Write([]byte{0x80})
|
||||
} else {
|
||||
w.WriteUint64((*obj.ExcessBlobGas))
|
||||
}
|
||||
}
|
||||
if _tmp5 {
|
||||
if _tmp5 || _tmp6 {
|
||||
if obj.ParentBeaconRoot == nil {
|
||||
w.Write([]byte{0x80})
|
||||
} else {
|
||||
w.WriteBytes(obj.ParentBeaconRoot[:])
|
||||
}
|
||||
}
|
||||
if _tmp6 {
|
||||
if obj.InclusionListSummaryRoot == nil {
|
||||
w.Write([]byte{0x80})
|
||||
} else {
|
||||
w.WriteBytes(obj.InclusionListSummaryRoot[:])
|
||||
}
|
||||
}
|
||||
w.ListEnd(_tmp0)
|
||||
return w.Flush()
|
||||
}
|
||||
|
|
|
|||
54
core/types/inclusion_list.go
Normal file
54
core/types/inclusion_list.go
Normal file
|
|
@ -0,0 +1,54 @@
|
|||
// Copyright 2024 The go-ethereum Authors
|
||||
// This file is part of the go-ethereum library.
|
||||
//
|
||||
// The go-ethereum library is free software: you can redistribute it and/or modify
|
||||
// it under the terms of the GNU Lesser General Public License as published by
|
||||
// the Free Software Foundation, either version 3 of the License, or
|
||||
// (at your option) any later version.
|
||||
//
|
||||
// The go-ethereum library is distributed in the hope that it will be useful,
|
||||
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
// GNU Lesser General Public License for more details.
|
||||
//
|
||||
// You should have received a copy of the GNU Lesser General Public License
|
||||
// along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
package types
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/rlp"
|
||||
)
|
||||
|
||||
//go:generate go run github.com/fjl/gencodec -type InclusionList gen_inclusion_rlp.go
|
||||
//go:generate go run ../../rlp/rlpgen -type InclusionList -out gen_inculsion.go
|
||||
|
||||
type InclusionListEntry struct {
|
||||
Address common.Address
|
||||
Nonce uint64
|
||||
}
|
||||
|
||||
type InclusionListSummary struct {
|
||||
Slot uint64
|
||||
ProposerIndex uint64
|
||||
ParentHash common.Hash
|
||||
Summary []*InclusionListEntry
|
||||
}
|
||||
|
||||
// InclusionList represents a validator InclusionList from the consensus layer.
|
||||
type InclusionList struct {
|
||||
List []*InclusionListEntry
|
||||
}
|
||||
|
||||
// Len returns the length of s.
|
||||
func (s InclusionList) Len() int { return len(s.List) }
|
||||
|
||||
// EncodeIndex encodes the i'th InclusionList to w. Note that this does not check for errors
|
||||
// because we assume that *InclusionList will only ever contain valid InclusionLists that were either
|
||||
// constructed by decoding or via public API in this package.
|
||||
func (s InclusionList) EncodeIndex(i int, w *bytes.Buffer) {
|
||||
rlp.Encode(w, s.List[i])
|
||||
}
|
||||
|
|
@ -29,7 +29,7 @@ func LookupInstructionSet(rules params.Rules) (JumpTable, error) {
|
|||
case rules.IsVerkle:
|
||||
return newCancunInstructionSet(), errors.New("verkle-fork not defined yet")
|
||||
case rules.IsPrague:
|
||||
return newCancunInstructionSet(), errors.New("prague-fork not defined yet")
|
||||
return newCancunInstructionSet(), nil
|
||||
case rules.IsCancun:
|
||||
return newCancunInstructionSet(), nil
|
||||
case rules.IsShanghai:
|
||||
|
|
|
|||
|
|
@ -204,6 +204,9 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) {
|
|||
if config.OverrideCancun != nil {
|
||||
overrides.OverrideCancun = config.OverrideCancun
|
||||
}
|
||||
if config.OverridePrague != nil {
|
||||
overrides.OverridePrague = config.OverridePrague
|
||||
}
|
||||
if config.OverrideVerkle != nil {
|
||||
overrides.OverrideVerkle = config.OverrideVerkle
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ import (
|
|||
"github.com/ethereum/go-ethereum/beacon/engine"
|
||||
"github.com/ethereum/go-ethereum/common"
|
||||
"github.com/ethereum/go-ethereum/common/hexutil"
|
||||
"github.com/ethereum/go-ethereum/consensus/misc/eip7547"
|
||||
"github.com/ethereum/go-ethereum/core/rawdb"
|
||||
"github.com/ethereum/go-ethereum/core/types"
|
||||
"github.com/ethereum/go-ethereum/eth"
|
||||
|
|
@ -896,3 +897,66 @@ func getBody(block *types.Block) *engine.ExecutionPayloadBodyV1 {
|
|||
Withdrawals: withdrawals,
|
||||
}
|
||||
}
|
||||
|
||||
func (api *ConsensusAPI) NewInclusionListV1(addresses []common.Address, transactions [][]byte, parentBlockHash common.Hash) (*engine.InclusionListStatusV1, error) {
|
||||
if len(addresses) != len(transactions) {
|
||||
return inclusionListError("number of transactions do not match addresses"), nil
|
||||
}
|
||||
txs, err := engine.DecodeTransactions(transactions)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("could not decode transactions: %v", err)
|
||||
}
|
||||
signer := types.LatestSignerForChainID(api.eth.BlockChain().Config().ChainID)
|
||||
var maxGas uint64
|
||||
for index, tx := range txs {
|
||||
sender, err := signer.Sender(tx)
|
||||
if err != nil {
|
||||
return inclusionListError(fmt.Sprintf("Invalid signer at index %v, error: %v", index, err)), nil
|
||||
}
|
||||
if addresses[index] != sender {
|
||||
return inclusionListError(fmt.Sprintf("Invalid sender at index %v, got %v want %v", index, sender, addresses[index])), nil
|
||||
}
|
||||
maxGas += tx.Gas()
|
||||
}
|
||||
if maxGas != params.InclusionListMaxGas {
|
||||
return inclusionListError(fmt.Sprintf("Invalid inclusion list max gas, got %v want %v", maxGas, params.InclusionListMaxGas)), nil
|
||||
}
|
||||
block := api.eth.BlockChain().GetBlockByHash(parentBlockHash)
|
||||
if block == nil {
|
||||
return inclusionListError("Parent block not found"), nil
|
||||
}
|
||||
if err := eip7547.VerifyInclusionList(api.eth.BlockChain(), block, signer, txs); err != nil {
|
||||
return inclusionListError(err.Error()), nil
|
||||
}
|
||||
return &engine.InclusionListStatusV1{Status: engine.VALID}, nil
|
||||
}
|
||||
|
||||
func (api *ConsensusAPI) GetInclusionListV1() ([]common.Address, [][]byte, error) {
|
||||
return []common.Address{}, [][]byte{}, nil
|
||||
}
|
||||
|
||||
func inclusionListError(errorMsg string) *engine.InclusionListStatusV1 {
|
||||
return &engine.InclusionListStatusV1{Status: engine.INVALID, ValidationError: &errorMsg}
|
||||
}
|
||||
|
||||
func (c *ConsensusAPI) SetLocalAccounts(locals []common.Address) error {
|
||||
for _, addr := range locals {
|
||||
c.eth.TxPool().MarkLocal(addr)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *ConsensusAPI) GetLocalTransactions() ([][]byte, error) {
|
||||
var res [][]byte
|
||||
for _, addr := range c.eth.TxPool().Locals() {
|
||||
pending, _ := c.eth.TxPool().ContentFrom(addr)
|
||||
for _, tx := range pending {
|
||||
m, err := tx.MarshalJSON()
|
||||
if err != nil {
|
||||
return [][]byte{}, nil
|
||||
}
|
||||
res = append(res, m)
|
||||
}
|
||||
}
|
||||
return res, nil
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1500,7 +1500,7 @@ func (d *Downloader) importBlockResults(results []*fetchResult) error {
|
|||
)
|
||||
blocks := make([]*types.Block, len(results))
|
||||
for i, result := range results {
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals)
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals).WithInclusionList(result.InclusionListSummary)
|
||||
}
|
||||
// Downloaded blocks are always regarded as trusted after the
|
||||
// transition. Because the downloaded chain is guided by the
|
||||
|
|
@ -1718,7 +1718,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state
|
|||
blocks := make([]*types.Block, len(results))
|
||||
receipts := make([]types.Receipts, len(results))
|
||||
for i, result := range results {
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals)
|
||||
blocks[i] = types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals).WithInclusionList(result.InclusionListSummary)
|
||||
receipts[i] = result.Receipts
|
||||
}
|
||||
if index, err := d.blockchain.InsertReceiptChain(blocks, receipts, d.ancientLimit); err != nil {
|
||||
|
|
@ -1729,7 +1729,7 @@ func (d *Downloader) commitSnapSyncData(results []*fetchResult, stateSync *state
|
|||
}
|
||||
|
||||
func (d *Downloader) commitPivotBlock(result *fetchResult) error {
|
||||
block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals)
|
||||
block := types.NewBlockWithHeader(result.Header).WithBody(result.Transactions, result.Uncles).WithWithdrawals(result.Withdrawals).WithInclusionList(result.InclusionListSummary)
|
||||
log.Debug("Committing snap sync pivot as new head", "number", block.Number(), "hash", block.Hash())
|
||||
|
||||
// Commit the pivot block as the new head, will require full sync from here on
|
||||
|
|
|
|||
|
|
@ -89,10 +89,10 @@ func (q *bodyQueue) request(peer *peerConnection, req *fetchRequest, resCh chan
|
|||
// deliver is responsible for taking a generic response packet from the concurrent
|
||||
// fetcher, unpacking the body data and delivering it to the downloader's queue.
|
||||
func (q *bodyQueue) deliver(peer *peerConnection, packet *eth.Response) (int, error) {
|
||||
txs, uncles, withdrawals := packet.Res.(*eth.BlockBodiesResponse).Unpack()
|
||||
hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal hashes}
|
||||
txs, uncles, withdrawals, ilSummaries := packet.Res.(*eth.BlockBodiesResponse).Unpack()
|
||||
hashsets := packet.Meta.([][]common.Hash) // {txs hashes, uncle hashes, withdrawal, inclusionListSummaryRoot hashes}
|
||||
|
||||
accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2])
|
||||
accepted, err := q.queue.DeliverBodies(peer.id, txs, hashsets[0], uncles, hashsets[1], withdrawals, hashsets[2], ilSummaries, hashsets[3])
|
||||
switch {
|
||||
case err == nil && len(txs) == 0:
|
||||
peer.log.Trace("Requested bodies delivered")
|
||||
|
|
|
|||
|
|
@ -70,6 +70,7 @@ type fetchResult struct {
|
|||
Transactions types.Transactions
|
||||
Receipts types.Receipts
|
||||
Withdrawals types.Withdrawals
|
||||
InclusionListSummary []*types.InclusionListEntry
|
||||
}
|
||||
|
||||
func newFetchResult(header *types.Header, fastSync bool) *fetchResult {
|
||||
|
|
@ -774,7 +775,7 @@ func (q *queue) DeliverHeaders(id string, headers []*types.Header, hashes []comm
|
|||
// also wakes any threads waiting for data delivery.
|
||||
func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListHashes []common.Hash,
|
||||
uncleLists [][]*types.Header, uncleListHashes []common.Hash,
|
||||
withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash) (int, error) {
|
||||
withdrawalLists [][]*types.Withdrawal, withdrawalListHashes []common.Hash, ilSummaries [][]*types.InclusionListEntry, ilSummaryHashes []common.Hash) (int, error) {
|
||||
q.lock.Lock()
|
||||
defer q.lock.Unlock()
|
||||
|
||||
|
|
@ -798,6 +799,19 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
|
|||
return errInvalidBody
|
||||
}
|
||||
}
|
||||
if header.InclusionListSummaryRoot == nil {
|
||||
// nil hash means that inclusionListSummaries should not be present in body
|
||||
if ilSummaries[index] != nil {
|
||||
return errInvalidBody
|
||||
}
|
||||
} else {
|
||||
if ilSummaries[index] == nil {
|
||||
return errInvalidBody
|
||||
}
|
||||
if ilSummaryHashes[index] != *header.InclusionListSummaryRoot {
|
||||
return errInvalidBody
|
||||
}
|
||||
}
|
||||
// Blocks must have a number of blobs corresponding to the header gas usage,
|
||||
// and zero before the Cancun hardfork.
|
||||
var blobs int
|
||||
|
|
@ -836,6 +850,7 @@ func (q *queue) DeliverBodies(id string, txLists [][]*types.Transaction, txListH
|
|||
result.Transactions = txLists[index]
|
||||
result.Uncles = uncleLists[index]
|
||||
result.Withdrawals = withdrawalLists[index]
|
||||
result.InclusionListSummary = ilSummaries[index]
|
||||
result.SetBodyDone()
|
||||
}
|
||||
return q.deliver(id, q.blockTaskPool, q.blockTaskQueue, q.blockPendPool,
|
||||
|
|
|
|||
|
|
@ -341,7 +341,7 @@ func XTestDelivery(t *testing.T) {
|
|||
uncleHashes[i] = types.CalcUncleHash(uncles)
|
||||
}
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil)
|
||||
_, err := q.DeliverBodies(peer.id, txset, txsHashes, uncleset, uncleHashes, nil, nil, nil, nil)
|
||||
if err != nil {
|
||||
fmt.Printf("delivered %d bodies %v\n", len(txset), err)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -157,6 +157,9 @@ type Config struct {
|
|||
// OverrideCancun (TODO: remove after the fork)
|
||||
OverrideCancun *uint64 `toml:",omitempty"`
|
||||
|
||||
// OverrideCancun (TODO: remove after the fork)
|
||||
OverridePrague *uint64 `toml:",omitempty"`
|
||||
|
||||
// OverrideVerkle (TODO: remove after the fork)
|
||||
OverrideVerkle *uint64 `toml:",omitempty"`
|
||||
}
|
||||
|
|
|
|||
|
|
@ -313,6 +313,7 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
|
|||
txsHashes = make([]common.Hash, len(res.BlockBodiesResponse))
|
||||
uncleHashes = make([]common.Hash, len(res.BlockBodiesResponse))
|
||||
withdrawalHashes = make([]common.Hash, len(res.BlockBodiesResponse))
|
||||
inclusionListSummaryRoots = make([]common.Hash, len(res.BlockBodiesResponse))
|
||||
)
|
||||
hasher := trie.NewStackTrie(nil)
|
||||
for i, body := range res.BlockBodiesResponse {
|
||||
|
|
@ -321,8 +322,11 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error {
|
|||
if body.Withdrawals != nil {
|
||||
withdrawalHashes[i] = types.DeriveSha(types.Withdrawals(body.Withdrawals), hasher)
|
||||
}
|
||||
if body.InclusionListSummary != nil {
|
||||
inclusionListSummaryRoots[i] = types.DeriveSha(types.InclusionList{List: body.InclusionListSummary}, hasher)
|
||||
}
|
||||
return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes}
|
||||
}
|
||||
return [][]common.Hash{txsHashes, uncleHashes, withdrawalHashes, inclusionListSummaryRoots}
|
||||
}
|
||||
return peer.dispatchResponse(&Response{
|
||||
id: res.RequestId,
|
||||
|
|
|
|||
|
|
@ -224,21 +224,23 @@ type BlockBody struct {
|
|||
Transactions []*types.Transaction // Transactions contained within a block
|
||||
Uncles []*types.Header // Uncles contained within a block
|
||||
Withdrawals []*types.Withdrawal `rlp:"optional"` // Withdrawals contained within a block
|
||||
InclusionListSummary []*types.InclusionListEntry `rlp:"optional"` // InclusionListSummary contained within a block
|
||||
}
|
||||
|
||||
// Unpack retrieves the transactions and uncles from the range packet and returns
|
||||
// them in a split flat format that's more consistent with the internal data structures.
|
||||
func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal) {
|
||||
func (p *BlockBodiesResponse) Unpack() ([][]*types.Transaction, [][]*types.Header, [][]*types.Withdrawal, [][]*types.InclusionListEntry) {
|
||||
// TODO(matt): add support for withdrawals to fetchers
|
||||
var (
|
||||
txset = make([][]*types.Transaction, len(*p))
|
||||
uncleset = make([][]*types.Header, len(*p))
|
||||
withdrawalset = make([][]*types.Withdrawal, len(*p))
|
||||
inclusionListSummarySet = make([][]*types.InclusionListEntry, len(*p))
|
||||
)
|
||||
for i, body := range *p {
|
||||
txset[i], uncleset[i], withdrawalset[i] = body.Transactions, body.Uncles, body.Withdrawals
|
||||
txset[i], uncleset[i], withdrawalset[i], inclusionListSummarySet[i] = body.Transactions, body.Uncles, body.Withdrawals, body.InclusionListSummary
|
||||
}
|
||||
return txset, uncleset, withdrawalset
|
||||
return txset, uncleset, withdrawalset, inclusionListSummarySet
|
||||
}
|
||||
|
||||
// GetReceiptsRequest represents a block receipts query.
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
||||
InclusionListMaxGas = 10_000_000 // Max gas for inclusion list part of the block
|
||||
)
|
||||
|
||||
// Gas discount table for BLS12-381 G1 and G2 multi exponentiation operations
|
||||
|
|
|
|||
Loading…
Reference in a new issue