diff --git a/beacon/engine/types.go b/beacon/engine/types.go index 60accc3c79..564e001333 100644 --- a/beacon/engine/types.go +++ b/beacon/engine/types.go @@ -57,23 +57,24 @@ type payloadAttributesMarshaling struct { // ExecutableData is the data necessary to execute an EL payload. type ExecutableData struct { - ParentHash common.Hash `json:"parentHash" gencodec:"required"` - FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` - StateRoot common.Hash `json:"stateRoot" gencodec:"required"` - ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` - LogsBloom []byte `json:"logsBloom" gencodec:"required"` - Random common.Hash `json:"prevRandao" gencodec:"required"` - Number uint64 `json:"blockNumber" gencodec:"required"` - GasLimit uint64 `json:"gasLimit" gencodec:"required"` - GasUsed uint64 `json:"gasUsed" gencodec:"required"` - Timestamp uint64 `json:"timestamp" gencodec:"required"` - ExtraData []byte `json:"extraData" gencodec:"required"` - BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` - BlockHash common.Hash `json:"blockHash" gencodec:"required"` - Transactions [][]byte `json:"transactions" gencodec:"required"` - Withdrawals []*types.Withdrawal `json:"withdrawals"` - BlobGasUsed *uint64 `json:"blobGasUsed"` - ExcessBlobGas *uint64 `json:"excessBlobGas"` + ParentHash common.Hash `json:"parentHash" gencodec:"required"` + FeeRecipient common.Address `json:"feeRecipient" gencodec:"required"` + StateRoot common.Hash `json:"stateRoot" gencodec:"required"` + ReceiptsRoot common.Hash `json:"receiptsRoot" gencodec:"required"` + LogsBloom []byte `json:"logsBloom" gencodec:"required"` + Random common.Hash `json:"prevRandao" gencodec:"required"` + Number uint64 `json:"blockNumber" gencodec:"required"` + GasLimit uint64 `json:"gasLimit" gencodec:"required"` + GasUsed uint64 `json:"gasUsed" gencodec:"required"` + Timestamp uint64 `json:"timestamp" gencodec:"required"` + ExtraData []byte `json:"extraData" gencodec:"required"` + BaseFeePerGas *big.Int `json:"baseFeePerGas" gencodec:"required"` + BlockHash common.Hash `json:"blockHash" gencodec:"required"` + Transactions [][]byte `json:"transactions" gencodec:"required"` + 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,28 +234,34 @@ func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil)) withdrawalsRoot = &h } - header := &types.Header{ - ParentHash: params.ParentHash, - UncleHash: types.EmptyUncleHash, - Coinbase: params.FeeRecipient, - Root: params.StateRoot, - TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), - ReceiptHash: params.ReceiptsRoot, - Bloom: types.BytesToBloom(params.LogsBloom), - Difficulty: common.Big0, - Number: new(big.Int).SetUint64(params.Number), - GasLimit: params.GasLimit, - GasUsed: params.GasUsed, - Time: params.Timestamp, - BaseFee: params.BaseFeePerGas, - Extra: params.ExtraData, - MixDigest: params.Random, - WithdrawalsHash: withdrawalsRoot, - ExcessBlobGas: params.ExcessBlobGas, - BlobGasUsed: params.BlobGasUsed, - ParentBeaconRoot: beaconRoot, + var inclusionRoot *common.Hash + if params.InclusionListSummary != nil { + h := types.DeriveSha(types.InclusionList{List: params.InclusionListSummary.Summary}, trie.NewStackTrie(nil)) + inclusionRoot = &h } - block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals) + header := &types.Header{ + ParentHash: params.ParentHash, + UncleHash: types.EmptyUncleHash, + Coinbase: params.FeeRecipient, + Root: params.StateRoot, + TxHash: types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)), + ReceiptHash: params.ReceiptsRoot, + Bloom: types.BytesToBloom(params.LogsBloom), + Difficulty: common.Big0, + Number: new(big.Int).SetUint64(params.Number), + GasLimit: params.GasLimit, + GasUsed: params.GasUsed, + Time: params.Timestamp, + BaseFee: params.BaseFeePerGas, + Extra: params.ExtraData, + MixDigest: params.Random, + WithdrawalsHash: withdrawalsRoot, + ExcessBlobGas: params.ExcessBlobGas, + BlobGasUsed: params.BlobGasUsed, + ParentBeaconRoot: beaconRoot, + InclusionListSummaryRoot: inclusionRoot, + } + 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"` +} diff --git a/cmd/geth/chaincmd.go b/cmd/geth/chaincmd.go index 17aab67876..c75c5495e9 100644 --- a/cmd/geth/chaincmd.go +++ b/cmd/geth/chaincmd.go @@ -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 diff --git a/cmd/geth/config.go b/cmd/geth/config.go index 76c6484fee..afa6665b81 100644 --- a/cmd/geth/config.go +++ b/cmd/geth/config.go @@ -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 diff --git a/cmd/geth/main.go b/cmd/geth/main.go index d79d23e226..b41f003c04 100644 --- a/cmd/geth/main.go +++ b/cmd/geth/main.go @@ -65,6 +65,7 @@ var ( utils.USBFlag, utils.SmartCardDaemonPathFlag, utils.OverrideCancun, + utils.OverridePrague, utils.OverrideVerkle, utils.EnablePersonal, utils.TxPoolLocalsFlag, diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go index b38f33b8dd..619820448e 100644 --- a/cmd/utils/flags.go +++ b/cmd/utils/flags.go @@ -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", diff --git a/consensus/misc/eip7547/eip7547.go b/consensus/misc/eip7547/eip7547.go new file mode 100644 index 0000000000..764543aba2 --- /dev/null +++ b/consensus/misc/eip7547/eip7547.go @@ -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<. + +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]) +} diff --git a/core/vm/jump_table_export.go b/core/vm/jump_table_export.go index b74109da0a..75ba881dca 100644 --- a/core/vm/jump_table_export.go +++ b/core/vm/jump_table_export.go @@ -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: diff --git a/eth/backend.go b/eth/backend.go index 81d84028a5..f81523e773 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -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 } diff --git a/eth/catalyst/api.go b/eth/catalyst/api.go index d154d794be..c6e6fccca9 100644 --- a/eth/catalyst/api.go +++ b/eth/catalyst/api.go @@ -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 +} diff --git a/eth/downloader/downloader.go b/eth/downloader/downloader.go index 6b26822e22..29ad02668c 100644 --- a/eth/downloader/downloader.go +++ b/eth/downloader/downloader.go @@ -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 diff --git a/eth/downloader/fetchers_concurrent_bodies.go b/eth/downloader/fetchers_concurrent_bodies.go index 5105fda66b..0235d79ed4 100644 --- a/eth/downloader/fetchers_concurrent_bodies.go +++ b/eth/downloader/fetchers_concurrent_bodies.go @@ -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") diff --git a/eth/downloader/queue.go b/eth/downloader/queue.go index 6ff858d755..13ce40270a 100644 --- a/eth/downloader/queue.go +++ b/eth/downloader/queue.go @@ -65,11 +65,12 @@ type fetchRequest struct { type fetchResult struct { pending atomic.Int32 // Flag telling what deliveries are outstanding - Header *types.Header - Uncles []*types.Header - Transactions types.Transactions - Receipts types.Receipts - Withdrawals types.Withdrawals + Header *types.Header + Uncles []*types.Header + 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, diff --git a/eth/downloader/queue_test.go b/eth/downloader/queue_test.go index 50b9031a27..97a067d4ca 100644 --- a/eth/downloader/queue_test.go +++ b/eth/downloader/queue_test.go @@ -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) } diff --git a/eth/ethconfig/config.go b/eth/ethconfig/config.go index 420a8b147a..3ff7ccbafd 100644 --- a/eth/ethconfig/config.go +++ b/eth/ethconfig/config.go @@ -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"` } diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 96656afb1b..345ef57607 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -310,9 +310,10 @@ func handleBlockBodies(backend Backend, msg Decoder, peer *Peer) error { } metadata := func() interface{} { var ( - txsHashes = make([]common.Hash, len(res.BlockBodiesResponse)) - uncleHashes = make([]common.Hash, len(res.BlockBodiesResponse)) - withdrawalHashes = make([]common.Hash, len(res.BlockBodiesResponse)) + 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, diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index c5cb2dd1dc..bac289f22f 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -221,24 +221,26 @@ type BlockBodiesRLPPacket struct { // BlockBody represents the data content of a single block. 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 + 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)) + 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. diff --git a/params/protocol_params.go b/params/protocol_params.go index 4e01b80970..f5aed68cda 100644 --- a/params/protocol_params.go +++ b/params/protocol_params.go @@ -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