diff --git a/cmd/evm/internal/t8ntool/execution.go b/cmd/evm/internal/t8ntool/execution.go index 0c8340348a0..21356a28341 100644 --- a/cmd/evm/internal/t8ntool/execution.go +++ b/cmd/evm/internal/t8ntool/execution.go @@ -62,6 +62,7 @@ type stEnv struct { Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` WithdrawalsHash *libcommon.Hash `json:"withdrawalsRoot,omitempty"` Requests []*types.Request `json:"requests,omitempty"` + RequestsRoot *libcommon.Hash `json:"requestsRoot,omitempty"` } type stEnvMarshaling struct { diff --git a/cmd/evm/internal/t8ntool/gen_stenv.go b/cmd/evm/internal/t8ntool/gen_stenv.go index 4a854e2ee59..c97bf5a7def 100644 --- a/cmd/evm/internal/t8ntool/gen_stenv.go +++ b/cmd/evm/internal/t8ntool/gen_stenv.go @@ -35,6 +35,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` WithdrawalsHash *common.Hash `json:"withdrawalsRoot,omitempty"` Requests []*types.Request `json:"requests,omitempty"` + RequestsRoot *common.Hash `json:"requestsRoot,omitempty"` } var enc stEnv enc.Coinbase = common0.UnprefixedAddress(s.Coinbase) @@ -54,6 +55,7 @@ func (s stEnv) MarshalJSON() ([]byte, error) { enc.Withdrawals = s.Withdrawals enc.WithdrawalsHash = s.WithdrawalsHash enc.Requests = s.Requests + enc.RequestsRoot = s.RequestsRoot return json.Marshal(&enc) } @@ -77,6 +79,7 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { Withdrawals []*types.Withdrawal `json:"withdrawals,omitempty"` WithdrawalsHash *common.Hash `json:"withdrawalsRoot,omitempty"` Requests []*types.Request `json:"requests,omitempty"` + RequestsRoot *common.Hash `json:"requestsRoot,omitempty"` } var dec stEnv if err := json.Unmarshal(input, &dec); err != nil { @@ -137,5 +140,8 @@ func (s *stEnv) UnmarshalJSON(input []byte) error { if dec.Requests != nil { s.Requests = dec.Requests } + if dec.RequestsRoot != nil { + s.RequestsRoot = dec.RequestsRoot + } return nil } diff --git a/cmd/evm/internal/t8ntool/transition.go b/cmd/evm/internal/t8ntool/transition.go index 231e162bd27..89d7b1d3e3d 100644 --- a/cmd/evm/internal/t8ntool/transition.go +++ b/cmd/evm/internal/t8ntool/transition.go @@ -238,7 +238,11 @@ func Main(ctx *cli.Context) error { } if chainConfig.IsShanghai(prestate.Env.Timestamp) && prestate.Env.Withdrawals == nil { - return NewError(ErrorVMConfig, errors.New("Shanghai config but missing 'withdrawals' in env section")) + return NewError(ErrorVMConfig, errors.New("shanghai config but missing 'withdrawals' in env section")) + } + + if chainConfig.IsPrague(prestate.Env.Timestamp) && prestate.Env.Requests == nil { + return NewError(ErrorVMConfig, errors.New("prague config but missing 'requests' in env section")) } isMerged := chainConfig.TerminalTotalDifficulty != nil && chainConfig.TerminalTotalDifficulty.BitLen() == 0 @@ -599,6 +603,7 @@ func NewHeader(env stEnv) *types.Header { header.UncleHash = env.UncleHash header.WithdrawalsHash = env.WithdrawalsHash + header.RequestsRoot = env.RequestsRoot return &header } diff --git a/consensus/clique/verifier.go b/consensus/clique/verifier.go index 69269566448..8b9c22be82f 100644 --- a/consensus/clique/verifier.go +++ b/consensus/clique/verifier.go @@ -81,6 +81,10 @@ func (c *Clique) verifyHeader(chain consensus.ChainHeaderReader, header *types.H return consensus.ErrUnexpectedWithdrawals } + if header.RequestsRoot != nil { + return consensus.ErrUnexpectedRequests + } + // All basic checks passed, verify cascading fields return c.verifyCascadingFields(chain, header, parents) } diff --git a/consensus/errors.go b/consensus/errors.go index 0659812b7e7..2b6c7077616 100644 --- a/consensus/errors.go +++ b/consensus/errors.go @@ -46,4 +46,7 @@ var ( // ErrUnexpectedWithdrawals is returned if a pre-Shanghai block has withdrawals. ErrUnexpectedWithdrawals = errors.New("unexpected withdrawals") + + // ErrUnexpectedRequests is returned if a pre-Prague block has EIP-7685 requests. + ErrUnexpectedRequests = errors.New("unexpected requests") ) diff --git a/consensus/ethash/consensus.go b/consensus/ethash/consensus.go index aa1a998f942..e2b4e088c35 100644 --- a/consensus/ethash/consensus.go +++ b/consensus/ethash/consensus.go @@ -249,6 +249,10 @@ func VerifyHeaderBasics(chain consensus.ChainHeaderReader, header, parent *types return consensus.ErrUnexpectedWithdrawals } + if header.RequestsRoot != nil { + return consensus.ErrUnexpectedRequests + } + // If all checks passed, validate any special fields for hard forks if err := misc.VerifyDAOHeaderExtraData(chain.Config(), header); err != nil { return err diff --git a/consensus/merge/merge.go b/consensus/merge/merge.go index 8852b3184eb..4ec315c9df3 100644 --- a/consensus/merge/merge.go +++ b/consensus/merge/merge.go @@ -244,7 +244,6 @@ func (s *Merge) verifyHeader(chain consensus.ChainHeaderReader, header, parent * if !chain.Config().IsCancun(header.Time) { return misc.VerifyAbsenceOfCancunHeaderFields(header) } - if err := misc.VerifyPresenceOfCancunHeaderFields(header); err != nil { return err } @@ -252,6 +251,16 @@ func (s *Merge) verifyHeader(chain consensus.ChainHeaderReader, header, parent * if *header.ExcessBlobGas != expectedExcessBlobGas { return fmt.Errorf("invalid excessBlobGas: have %d, want %d", *header.ExcessBlobGas, expectedExcessBlobGas) } + + // Verify existence / non-existence of requestsRoot + prague := chain.Config().IsPrague(header.Time) + if prague && header.RequestsRoot == nil { + return fmt.Errorf("missing requestsRoot") + } + if !prague && header.RequestsRoot != nil { + return consensus.ErrUnexpectedRequests + } + return nil } diff --git a/core/types/block.go b/core/types/block.go index fb0282e67d2..f1b37ae245d 100644 --- a/core/types/block.go +++ b/core/types/block.go @@ -658,6 +658,7 @@ func (r RawBlock) AsBlock() (*Block, error) { b := &Block{header: r.Header} b.uncles = r.Body.Uncles b.withdrawals = r.Body.Withdrawals + b.requests = r.Body.Requests txs := make([]Transaction, len(r.Body.Transactions)) for i, tx := range r.Body.Transactions { @@ -1049,7 +1050,7 @@ func NewBlock(header *Header, txs []Transaction, uncles []*Header, receipts []*R if requests == nil { b.header.RequestsRoot = nil } else if len(requests) == 0 { - b.header.RequestsRoot = &EmptyRootHash // TODO(racytech): is this correct? + b.header.RequestsRoot = &EmptyRootHash b.requests = make(Requests, len(requests)) } else { h := DeriveSha(Requests(requests)) @@ -1305,7 +1306,7 @@ func (b *Block) SendersToTxs(senders []libcommon.Address) { // RawBody creates a RawBody based on the block. It is not very efficient, so // will probably be removed in favour of RawBlock. Also it panics func (b *Block) RawBody() *RawBody { - br := &RawBody{Transactions: make([][]byte, len(b.transactions)), Uncles: b.uncles, Withdrawals: b.withdrawals} + br := &RawBody{Transactions: make([][]byte, len(b.transactions)), Uncles: b.uncles, Withdrawals: b.withdrawals, Requests: b.requests} for i, tx := range b.transactions { var err error br.Transactions[i], err = rlp.EncodeToBytes(tx) @@ -1318,7 +1319,7 @@ func (b *Block) RawBody() *RawBody { // RawBody creates a RawBody based on the body. func (b *Body) RawBody() *RawBody { - br := &RawBody{Transactions: make([][]byte, len(b.Transactions)), Uncles: b.Uncles, Withdrawals: b.Withdrawals} + br := &RawBody{Transactions: make([][]byte, len(b.Transactions)), Uncles: b.Uncles, Withdrawals: b.Withdrawals, Requests: b.Requests} for i, tx := range b.Transactions { var err error br.Transactions[i], err = rlp.EncodeToBytes(tx) @@ -1347,7 +1348,7 @@ func (b *Block) SanityCheck() error { return b.header.SanityCheck() } -// HashCheck checks that transactions, receipts, uncles and withdrawals hashes are correct. +// HashCheck checks that transactions, receipts, uncles, withdrawals, and requests hashes are correct. func (b *Block) HashCheck() error { if hash := DeriveSha(b.Transactions()); hash != b.TxHash() { return fmt.Errorf("block has invalid transaction hash: have %x, exp: %x", hash, b.TxHash()) @@ -1377,6 +1378,20 @@ func (b *Block) HashCheck() error { if hash := DeriveSha(b.Withdrawals()); hash != *b.WithdrawalsHash() { return fmt.Errorf("block has invalid withdrawals hash: have %x, exp: %x", hash, b.WithdrawalsHash()) } + + if b.RequestsRoot() == nil { + if b.Requests() != nil { + return errors.New("header missing RequestsRoot") + } + return nil + } + if b.Requests() == nil { + return errors.New("body missing Requests") + } + if hash := DeriveSha(b.Requests()); hash != *b.RequestsRoot() { + return fmt.Errorf("block has invalid requests root: have %x, exp: %x", hash, b.RequestsRoot()) + } + return nil } @@ -1433,6 +1448,15 @@ func (b *Block) Copy() *Block { } } + var requests []*Request + if b.requests != nil { + requests = make([]*Request, 0, len(b.requests)) + for _, request := range b.requests { + rCopy := *request + requests = append(requests, &rCopy) + } + } + var hashValue atomic.Value if value := b.hash.Load(); value != nil { hash := value.(libcommon.Hash) @@ -1450,6 +1474,7 @@ func (b *Block) Copy() *Block { uncles: uncles, transactions: CopyTxs(b.transactions), withdrawals: withdrawals, + requests: requests, hash: hashValue, size: sizeValue, } @@ -1465,6 +1490,7 @@ func (b *Block) WithSeal(header *Header) *Block { transactions: b.transactions, uncles: b.uncles, withdrawals: b.withdrawals, + requests: b.requests, } } diff --git a/core/types/gen_header_json.go b/core/types/gen_header_json.go index d9d3547e67c..4b85e184c19 100644 --- a/core/types/gen_header_json.go +++ b/core/types/gen_header_json.go @@ -40,6 +40,7 @@ func (h Header) MarshalJSON() ([]byte, error) { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + RequestsRoot *common.Hash `json:"requestsRoot"` Verkle bool VerkleProof []byte VerkleKeyVals []verkle.KeyValuePair @@ -68,6 +69,7 @@ func (h Header) MarshalJSON() ([]byte, error) { enc.BlobGasUsed = (*hexutil.Uint64)(h.BlobGasUsed) enc.ExcessBlobGas = (*hexutil.Uint64)(h.ExcessBlobGas) enc.ParentBeaconBlockRoot = h.ParentBeaconBlockRoot + enc.RequestsRoot = h.RequestsRoot enc.Verkle = h.Verkle enc.VerkleProof = h.VerkleProof enc.VerkleKeyVals = h.VerkleKeyVals @@ -100,6 +102,7 @@ func (h *Header) UnmarshalJSON(input []byte) error { BlobGasUsed *hexutil.Uint64 `json:"blobGasUsed"` ExcessBlobGas *hexutil.Uint64 `json:"excessBlobGas"` ParentBeaconBlockRoot *common.Hash `json:"parentBeaconBlockRoot"` + RequestsRoot *common.Hash `json:"requestsRoot"` Verkle *bool VerkleProof []byte VerkleKeyVals []verkle.KeyValuePair @@ -186,6 +189,9 @@ func (h *Header) UnmarshalJSON(input []byte) error { if dec.ParentBeaconBlockRoot != nil { h.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot } + if dec.RequestsRoot != nil { + h.RequestsRoot = dec.RequestsRoot + } if dec.Verkle != nil { h.Verkle = *dec.Verkle } diff --git a/eth/protocols/eth/protocol.go b/eth/protocols/eth/protocol.go index 1818bf25879..7ee9cafaf76 100644 --- a/eth/protocols/eth/protocol.go +++ b/eth/protocols/eth/protocol.go @@ -356,18 +356,19 @@ type BlockBodiesRLPPacket66 struct { BlockBodiesRLPPacket } -// Unpack retrieves the transactions, uncles, and withdrawals from the range packet and returns +// Unpack retrieves the transactions, uncles, withdrawals, and requests from the range packet and returns // them in a split flat format that's more consistent with the internal data structures. -func (p *BlockRawBodiesPacket) Unpack() ([][][]byte, [][]*types.Header, []types.Withdrawals) { +func (p *BlockRawBodiesPacket) Unpack() ([][][]byte, [][]*types.Header, []types.Withdrawals, []types.Requests) { var ( txSet = make([][][]byte, len(*p)) uncleSet = make([][]*types.Header, len(*p)) withdrawalSet = make([]types.Withdrawals, len(*p)) + requestSet = make([]types.Requests, 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], requestSet[i] = body.Transactions, body.Uncles, body.Withdrawals, body.Requests } - return txSet, uncleSet, withdrawalSet + return txSet, uncleSet, withdrawalSet, requestSet } // GetReceiptsPacket represents a block receipts query. diff --git a/eth/stagedsync/exec3.go b/eth/stagedsync/exec3.go index eee5c9581ae..23a0c32cab6 100644 --- a/eth/stagedsync/exec3.go +++ b/eth/stagedsync/exec3.go @@ -593,6 +593,7 @@ Loop: GetHashFn: getHashFn, EvmBlockContext: blockContext, Withdrawals: b.Withdrawals(), + Requests: b.Requests(), } if txIndex >= 0 && txIndex < len(txs) { txTask.Tx = txs[txIndex] @@ -1080,6 +1081,7 @@ func reconstituteStep(last bool, GetHashFn: getHashFn, EvmBlockContext: blockContext, Withdrawals: b.Withdrawals(), + Requests: b.Requests(), } if txIndex >= 0 && txIndex < len(txs) { txTask.Tx = txs[txIndex] diff --git a/p2p/sentry/sentry_multi_client/sentry_multi_client.go b/p2p/sentry/sentry_multi_client/sentry_multi_client.go index 0f32615b949..dad9a57eeab 100644 --- a/p2p/sentry/sentry_multi_client/sentry_multi_client.go +++ b/p2p/sentry/sentry_multi_client/sentry_multi_client.go @@ -585,12 +585,12 @@ func (cs *MultiClient) blockBodies66(ctx context.Context, inreq *proto_sentry.In if err := rlp.DecodeBytes(inreq.Data, &request); err != nil { return fmt.Errorf("decode BlockBodiesPacket66: %w", err) } - txs, uncles, withdrawals := request.BlockRawBodiesPacket.Unpack() - if len(txs) == 0 && len(uncles) == 0 && len(withdrawals) == 0 { + txs, uncles, withdrawals, requests := request.BlockRawBodiesPacket.Unpack() + if len(txs) == 0 && len(uncles) == 0 && len(withdrawals) == 0 && len(requests) == 0 { // No point processing empty response return nil } - cs.Bd.DeliverBodies(txs, uncles, withdrawals, uint64(len(inreq.Data)), sentry.ConvertH512ToPeerID(inreq.PeerId)) + cs.Bd.DeliverBodies(txs, uncles, withdrawals, requests, uint64(len(inreq.Data)), sentry.ConvertH512ToPeerID(inreq.PeerId)) return nil } diff --git a/polygon/bor/bor.go b/polygon/bor/bor.go index ba8883d1388..b2e9407e43a 100644 --- a/polygon/bor/bor.go +++ b/polygon/bor/bor.go @@ -551,6 +551,10 @@ func ValidateHeaderUnusedFields(header *types.Header) error { return consensus.ErrUnexpectedWithdrawals } + if header.RequestsRoot != nil { + return consensus.ErrUnexpectedRequests + } + return misc.VerifyAbsenceOfCancunHeaderFields(header) } @@ -984,6 +988,10 @@ func (c *Bor) Finalize(config *chain.Config, header *types.Header, state *state. return nil, nil, consensus.ErrUnexpectedWithdrawals } + if requests != nil || header.RequestsRoot != nil { + return nil, nil, consensus.ErrUnexpectedRequests + } + if isSprintStart(headerNumber, c.config.CalculateSprintLength(headerNumber)) { cx := statefull.ChainContext{Chain: chain, Bor: c} @@ -1050,6 +1058,10 @@ func (c *Bor) FinalizeAndAssemble(chainConfig *chain.Config, header *types.Heade return nil, nil, nil, consensus.ErrUnexpectedWithdrawals } + if requests != nil || header.RequestsRoot != nil { + return nil, nil, nil, consensus.ErrUnexpectedRequests + } + if isSprintStart(headerNumber, c.config.CalculateSprintLength(headerNumber)) { cx := statefull.ChainContext{Chain: chain, Bor: c} diff --git a/tests/block_test_util.go b/tests/block_test_util.go index 22a1b2b30ff..17119dc6540 100644 --- a/tests/block_test_util.go +++ b/tests/block_test_util.go @@ -101,6 +101,7 @@ type btHeader struct { BlobGasUsed *uint64 ExcessBlobGas *uint64 ParentBeaconBlockRoot *libcommon.Hash + RequestsRoot *libcommon.Hash } type btHeaderMarshaling struct { @@ -303,6 +304,9 @@ func validateHeader(h *btHeader, h2 *types.Header) error { if !reflect.DeepEqual(h.ParentBeaconBlockRoot, h2.ParentBeaconBlockRoot) { return fmt.Errorf("parentBeaconBlockRoot: want: %v have: %v", h.ParentBeaconBlockRoot, h2.ParentBeaconBlockRoot) } + if !reflect.DeepEqual(h.RequestsRoot, h2.RequestsRoot) { + return fmt.Errorf("requestsRoot: want: %v have: %v", h.RequestsRoot, h2.RequestsRoot) + } return nil } diff --git a/tests/gen_btheader.go b/tests/gen_btheader.go index 521f77eb667..268428f334e 100644 --- a/tests/gen_btheader.go +++ b/tests/gen_btheader.go @@ -39,6 +39,7 @@ func (b btHeader) MarshalJSON() ([]byte, error) { BlobGasUsed *math.HexOrDecimal64 ExcessBlobGas *math.HexOrDecimal64 ParentBeaconBlockRoot *libcommon.Hash + RequestsRoot *libcommon.Hash } var enc btHeader enc.Bloom = b.Bloom @@ -62,6 +63,7 @@ func (b btHeader) MarshalJSON() ([]byte, error) { enc.BlobGasUsed = (*math.HexOrDecimal64)(b.BlobGasUsed) enc.ExcessBlobGas = (*math.HexOrDecimal64)(b.ExcessBlobGas) enc.ParentBeaconBlockRoot = b.ParentBeaconBlockRoot + enc.RequestsRoot = b.RequestsRoot return json.Marshal(&enc) } @@ -89,6 +91,7 @@ func (b *btHeader) UnmarshalJSON(input []byte) error { BlobGasUsed *math.HexOrDecimal64 ExcessBlobGas *math.HexOrDecimal64 ParentBeaconBlockRoot *libcommon.Hash + RequestsRoot *libcommon.Hash } var dec btHeader if err := json.Unmarshal(input, &dec); err != nil { @@ -157,5 +160,8 @@ func (b *btHeader) UnmarshalJSON(input []byte) error { if dec.ParentBeaconBlockRoot != nil { b.ParentBeaconBlockRoot = dec.ParentBeaconBlockRoot } + if dec.RequestsRoot != nil { + b.RequestsRoot = dec.RequestsRoot + } return nil } diff --git a/turbo/adapter/ethapi/api.go b/turbo/adapter/ethapi/api.go index 92767e1ce9e..e17c7c9d80d 100644 --- a/turbo/adapter/ethapi/api.go +++ b/turbo/adapter/ethapi/api.go @@ -304,6 +304,9 @@ func RPCMarshalHeader(head *types.Header) map[string]interface{} { if head.ParentBeaconBlockRoot != nil { result["parentBeaconBlockRoot"] = head.ParentBeaconBlockRoot } + if head.RequestsRoot != nil { + result["requestsRoot"] = head.RequestsRoot + } return result } @@ -361,6 +364,10 @@ func RPCMarshalBlockExDeprecated(block *types.Block, inclTx bool, fullTx bool, b fields["withdrawals"] = block.Withdrawals() } + if block.Requests() != nil { + fields["requests"] = block.Requests() + } + return fields, nil } diff --git a/turbo/execution/eth1/eth1_utils/grpc.go b/turbo/execution/eth1/eth1_utils/grpc.go index 6c8dda7c782..b33ea871e99 100644 --- a/turbo/execution/eth1/eth1_utils/grpc.go +++ b/turbo/execution/eth1/eth1_utils/grpc.go @@ -205,6 +205,7 @@ func ConvertRawBlockBodyToRpc(in *types.RawBody, blockNumber uint64, blockHash l Transactions: in.Transactions, Uncles: HeadersToHeadersRPC(in.Uncles), Withdrawals: ConvertWithdrawalsToRpc(in.Withdrawals), + //TODO(racytech): Requests } } @@ -229,6 +230,7 @@ func ConvertRawBlockBodyFromRpc(in *execution.BlockBody) (*types.RawBody, error) Transactions: in.Transactions, Uncles: uncles, Withdrawals: ConvertWithdrawalsFromRpc(in.Withdrawals), + //TODO(racytech): Requests }, nil } diff --git a/turbo/execution/eth1/getters.go b/turbo/execution/eth1/getters.go index 877a1c53a32..bce732ddef6 100644 --- a/turbo/execution/eth1/getters.go +++ b/turbo/execution/eth1/getters.go @@ -147,6 +147,7 @@ func (e *EthereumExecutionModule) GetBodiesByHashes(ctx context.Context, req *ex bodies = append(bodies, &execution.BlockBody{ Transactions: txs, Withdrawals: eth1_utils.ConvertWithdrawalsToRpc(body.Withdrawals), + //TODO(racytech): Requests }) } @@ -189,6 +190,7 @@ func (e *EthereumExecutionModule) GetBodiesByRange(ctx context.Context, req *exe bodies = append(bodies, &execution.BlockBody{ Transactions: txs, Withdrawals: eth1_utils.ConvertWithdrawalsToRpc(body.Withdrawals), + //TODO(racytech): Requests }) } // Remove trailing nil values as per spec diff --git a/turbo/stages/bodydownload/body_algos.go b/turbo/stages/bodydownload/body_algos.go index e390a461d0f..8e587a6d742 100644 --- a/turbo/stages/bodydownload/body_algos.go +++ b/turbo/stages/bodydownload/body_algos.go @@ -36,7 +36,7 @@ func (bd *BodyDownload) UpdateFromDb(db kv.Tx) (headHeight, headTime uint64, hea bd.maxProgress = headerProgress + 1 // Resetting for requesting a new range of blocks bd.requestedLow = bodyProgress + 1 - bd.requestedMap = make(map[TripleHash]uint64) + bd.requestedMap = make(map[BodyHashes]uint64) bd.delivered.Clear() bd.deliveredCount = 0 bd.wastedCount = 0 @@ -142,13 +142,18 @@ func (bd *BodyDownload) RequestMoreBodies(tx kv.RwTx, blockReader services.FullB } if request { if header.UncleHash == types.EmptyUncleHash && header.TxHash == types.EmptyRootHash && - (header.WithdrawalsHash == nil || *header.WithdrawalsHash == types.EmptyRootHash) { + (header.WithdrawalsHash == nil || *header.WithdrawalsHash == types.EmptyRootHash) && + (header.RequestsRoot == nil || *header.RequestsRoot == types.EmptyRootHash) { // Empty block body body := &types.RawBody{} if header.WithdrawalsHash != nil { // implies *header.WithdrawalsHash == types.EmptyRootHash body.Withdrawals = make([]*types.Withdrawal, 0) } + if header.RequestsRoot != nil { + // implies *header.RequestsRoot == types.EmptyRootHash + body.Requests = make([]*types.Request, 0) + } bd.addBodyToCache(blockNum, body) dataflow.BlockBodyDownloadStates.AddChange(blockNum, dataflow.BlockBodyEmpty) request = false @@ -163,19 +168,24 @@ func (bd *BodyDownload) RequestMoreBodies(tx kv.RwTx, blockReader services.FullB } } if request { - var tripleHash TripleHash - copy(tripleHash[:], header.UncleHash.Bytes()) - copy(tripleHash[length.Hash:], header.TxHash.Bytes()) + var bodyHashes BodyHashes + copy(bodyHashes[:], header.UncleHash.Bytes()) + copy(bodyHashes[length.Hash:], header.TxHash.Bytes()) if header.WithdrawalsHash != nil { - copy(tripleHash[2*length.Hash:], header.WithdrawalsHash.Bytes()) + copy(bodyHashes[2*length.Hash:], header.WithdrawalsHash.Bytes()) + } else { + copy(bodyHashes[2*length.Hash:], types.EmptyRootHash.Bytes()) + } + if header.RequestsRoot != nil { + copy(bodyHashes[3*length.Hash:], header.RequestsRoot.Bytes()) } else { - copy(tripleHash[2*length.Hash:], types.EmptyRootHash.Bytes()) + copy(bodyHashes[3*length.Hash:], types.EmptyRootHash.Bytes()) } - bd.requestedMap[tripleHash] = blockNum + bd.requestedMap[bodyHashes] = blockNum blockNums = append(blockNums, blockNum) hashes = append(hashes, hash) } else { - // uncleHash, txHash, and withdrawalsHash are all empty (or block is prefetched), no need to request + // uncleHash, txHash, withdrawalsHash, and requestsRoot are all empty (or block is prefetched), no need to request bd.delivered.Add(blockNum) } } @@ -228,8 +238,10 @@ func (bd *BodyDownload) RequestSent(bodyReq *BodyRequest, timeWithTimeout uint64 } // DeliverBodies takes the block body received from a peer and adds it to the various data structures -func (bd *BodyDownload) DeliverBodies(txs [][][]byte, uncles [][]*types.Header, withdrawals []types.Withdrawals, lenOfP2PMsg uint64, peerID [64]byte) { - bd.deliveryCh <- Delivery{txs: txs, uncles: uncles, withdrawals: withdrawals, lenOfP2PMessage: lenOfP2PMsg, peerID: peerID} +func (bd *BodyDownload) DeliverBodies(txs [][][]byte, uncles [][]*types.Header, withdrawals []types.Withdrawals, + requests []types.Requests, lenOfP2PMsg uint64, peerID [64]byte, +) { + bd.deliveryCh <- Delivery{txs: txs, uncles: uncles, withdrawals: withdrawals, requests: requests, lenOfP2PMessage: lenOfP2PMsg, peerID: peerID} select { case bd.DeliveryNotify <- struct{}{}: @@ -288,27 +300,32 @@ Loop: if delivery.withdrawals == nil { bd.logger.Warn("nil withdrawals delivered", "peer_id", delivery.peerID, "p2p_msg_len", delivery.lenOfP2PMessage) } - if delivery.txs == nil || delivery.uncles == nil || delivery.withdrawals == nil { + if delivery.requests == nil { + bd.logger.Warn("nil requests delivered", "peer_id", delivery.peerID, "p2p_msg_len", delivery.lenOfP2PMessage) + } + if delivery.txs == nil || delivery.uncles == nil || delivery.withdrawals == nil || delivery.requests == nil { bd.logger.Debug("delivery body processing has been skipped due to nil tx|data") continue } //var deliveredNums []uint64 toClean := map[uint64]struct{}{} - txs, uncles, withdrawals, lenOfP2PMessage := delivery.txs, delivery.uncles, delivery.withdrawals, delivery.lenOfP2PMessage + txs, uncles, withdrawals, requests, lenOfP2PMessage := delivery.txs, delivery.uncles, delivery.withdrawals, delivery.requests, delivery.lenOfP2PMessage for i := range txs { uncleHash := types.CalcUncleHash(uncles[i]) txHash := types.DeriveSha(RawTransactions(txs[i])) withdrawalsHash := types.DeriveSha(withdrawals[i]) - var tripleHash TripleHash - copy(tripleHash[:], uncleHash.Bytes()) - copy(tripleHash[length.Hash:], txHash.Bytes()) - copy(tripleHash[2*length.Hash:], withdrawalsHash.Bytes()) + requestsRoot := types.DeriveSha(requests[i]) + var bodyHashes BodyHashes + copy(bodyHashes[:], uncleHash.Bytes()) + copy(bodyHashes[length.Hash:], txHash.Bytes()) + copy(bodyHashes[2*length.Hash:], withdrawalsHash.Bytes()) + copy(bodyHashes[3*length.Hash:], requestsRoot.Bytes()) // Block numbers are added to the bd.delivered bitmap here, only for blocks for which the body has been received, and their double hashes are present in the bd.requestedMap // Also, block numbers can be added to bd.delivered for empty blocks, above - blockNum, ok := bd.requestedMap[tripleHash] + blockNum, ok := bd.requestedMap[bodyHashes] if !ok { undelivered++ continue @@ -319,9 +336,9 @@ Loop: toClean[blockNum] = struct{}{} } } - delete(bd.requestedMap, tripleHash) // Delivered, cleaning up + delete(bd.requestedMap, bodyHashes) // Delivered, cleaning up - bd.addBodyToCache(blockNum, &types.RawBody{Transactions: txs[i], Uncles: uncles[i], Withdrawals: withdrawals[i]}) + bd.addBodyToCache(blockNum, &types.RawBody{Transactions: txs[i], Uncles: uncles[i], Withdrawals: withdrawals[i], Requests: requests[i]}) bd.delivered.Add(blockNum) delivered++ dataflow.BlockBodyDownloadStates.AddChange(blockNum, dataflow.BlockBodyReceived) diff --git a/turbo/stages/bodydownload/body_data_struct.go b/turbo/stages/bodydownload/body_data_struct.go index 9f6f7c1741f..ce77e8671cd 100644 --- a/turbo/stages/bodydownload/body_data_struct.go +++ b/turbo/stages/bodydownload/body_data_struct.go @@ -12,8 +12,8 @@ import ( "github.com/ledgerwatch/erigon/core/types" ) -// TripleHash is type to be used for the mapping between TxHash, UncleHash, and WithdrawalsHash to the block header -type TripleHash [3 * length.Hash]byte +// BodyHashes is to be used for the mapping between TxHash, UncleHash, WithdrawalsHash, and RequestRoot to the block header +type BodyHashes [4 * length.Hash]byte const MaxBodiesInRequest = 1024 @@ -22,6 +22,7 @@ type Delivery struct { txs [][][]byte uncles [][]*types.Header withdrawals []types.Withdrawals + requests []types.Requests lenOfP2PMessage uint64 } @@ -35,7 +36,7 @@ type BodyTreeItem struct { // BodyDownload represents the state of body downloading process type BodyDownload struct { peerMap map[[64]byte]int - requestedMap map[TripleHash]uint64 + requestedMap map[BodyHashes]uint64 DeliveryNotify chan struct{} deliveryCh chan Delivery Engine consensus.Engine @@ -66,7 +67,7 @@ type BodyRequest struct { // NewBodyDownload create a new body download state object func NewBodyDownload(engine consensus.Engine, blockBufferSize, bodyCacheLimit int, br services.FullBlockReader, logger log.Logger) *BodyDownload { bd := &BodyDownload{ - requestedMap: make(map[TripleHash]uint64), + requestedMap: make(map[BodyHashes]uint64), bodyCacheLimit: bodyCacheLimit, delivered: roaring64.New(), deliveriesH: make(map[uint64]*types.Header),