eth/protocols/eth: remove trimReceiptsRLP and simplify handler

This commit is contained in:
Felix Lange 2026-03-19 18:25:21 +01:00
parent 130470832f
commit 682ed6c64e
3 changed files with 61 additions and 81 deletions

View file

@ -269,33 +269,28 @@ func handleGetReceipts70(backend Backend, msg Decoder, peer *Peer) error {
// It does not send the bloom filters for the receipts. It is exposed // It does not send the bloom filters for the receipts. It is exposed
// to allow external packages to test protocol behavior. // to allow external packages to test protocol behavior.
func ServiceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest) rlp.RawList[*ReceiptList] { func ServiceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest) rlp.RawList[*ReceiptList] {
// Gather state data until the fetch or network limits is reached
var ( var (
bytes int bytes int
receipts rlp.RawList[*ReceiptList] receipts rlp.RawList[*ReceiptList]
) )
for lookups, hash := range query { for lookups, hash := range query {
if bytes >= softResponseLimit || receipts.Len() >= maxReceiptsServe || if bytes >= softResponseLimit || receipts.Len() >= maxReceiptsServe || lookups >= 2*maxReceiptsServe {
lookups >= 2*maxReceiptsServe {
break break
} }
// Retrieve the requested block's receipts // Retrieve the requested block's receipts
results := chain.GetReceiptsRLP(hash) results := chain.GetReceiptsRLP(hash)
if results == nil { if results == nil {
if header := chain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { continue // Can't retrieve the receipts, so we just skip this block.
continue }
} body := chain.GetBodyRLP(hash)
} else { if body == nil {
body := chain.GetBodyRLP(hash) continue // The block body is missing, we also have to skip.
if body == nil { }
continue results, _, err := blockReceiptsToNetwork(results, body, receiptQueryParams{})
} if err != nil {
var err error log.Error("Error in block receipts conversion", "hash", hash, "err", err)
results, err = blockReceiptsToNetwork(results, body) continue
if err != nil {
log.Error("Error in block receipts conversion", "hash", hash, "err", err)
continue
}
} }
receipts.AppendRaw(results) receipts.AppendRaw(results)
bytes += len(results) bytes += len(results)
@ -309,9 +304,8 @@ func ServiceGetReceiptsQuery69(chain *core.BlockChain, query GetReceiptsRequest)
// are omitted from the first block receipt list. // are omitted from the first block receipt list.
func serviceGetReceiptsQuery70(chain *core.BlockChain, query GetReceiptsRequest, firstBlockReceiptIndex uint64) (rlp.RawList[*ReceiptList], bool) { func serviceGetReceiptsQuery70(chain *core.BlockChain, query GetReceiptsRequest, firstBlockReceiptIndex uint64) (rlp.RawList[*ReceiptList], bool) {
var ( var (
bytes int bytes int
receipts rlp.RawList[*ReceiptList] receipts rlp.RawList[*ReceiptList]
lastBlockIncomplete bool
) )
for i, hash := range query { for i, hash := range query {
if bytes >= softResponseLimit || receipts.Len() >= maxReceiptsServe { if bytes >= softResponseLimit || receipts.Len() >= maxReceiptsServe {
@ -319,65 +313,28 @@ func serviceGetReceiptsQuery70(chain *core.BlockChain, query GetReceiptsRequest,
} }
results := chain.GetReceiptsRLP(hash) results := chain.GetReceiptsRLP(hash)
if results == nil { if results == nil {
if header := chain.GetHeaderByHash(hash); header == nil || header.ReceiptHash != types.EmptyRootHash { continue // Can't retrieve the receipts, so we just skip this block.
continue
}
} else {
body := chain.GetBodyRLP(hash)
if body == nil {
continue
}
var err error
results, err = blockReceiptsToNetwork(results, body)
if err != nil {
log.Error("Error in block receipts conversion", "hash", hash, "err", err)
continue
}
} }
body := chain.GetBodyRLP(hash)
if firstBlockReceiptIndex > 0 && i == 0 { if body == nil {
results, lastBlockIncomplete = trimReceiptsRLP(results, int(firstBlockReceiptIndex), maxPacketSize) continue // The block body is missing, we also have to skip.
} else if bytes+len(results) > maxPacketSize {
results, lastBlockIncomplete = trimReceiptsRLP(results, 0, maxPacketSize-bytes)
} }
q := receiptQueryParams{sizeLimit: uint64(maxPacketSize - bytes)}
receipts.AppendRaw(results) if i == 0 {
bytes += len(results) q.firstIndex = firstBlockReceiptIndex
} }
results, incomplete, err := blockReceiptsToNetwork(results, body, q)
return receipts, lastBlockIncomplete if err != nil {
} log.Error("Error in block receipts conversion", "hash", hash, "err", err)
// trimReceiptsRLP trims raw value from `from` index until it exceeds limit
func trimReceiptsRLP(receiptsRLP rlp.RawValue, from int, limit int) (rlp.RawValue, bool) {
var (
out bytes.Buffer
buffer = rlp.NewEncoderBuffer(&out)
iter, _ = rlp.NewListIterator(receiptsRLP)
index int
bytes int
overflow bool
)
list := buffer.List()
for iter.Next() {
if index < from {
index++
continue continue
} }
receipt := iter.Value() receipts.AppendRaw(results)
if bytes+len(receipt) > limit { bytes += len(results)
overflow = true if incomplete {
break return receipts, true
} }
buffer.Write(receipt)
bytes += len(receipt)
index++
} }
buffer.ListEnd(list) return receipts, false
buffer.Flush()
return out.Bytes(), overflow
} }
func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error { func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error {

View file

@ -240,12 +240,17 @@ func (rl *ReceiptList) LogsSize() (uint64, error) {
return size, nil return size, nil
} }
// blockReceiptsToNetwork takes a slice of rlp-encoded receipts, and transactions, type receiptQueryParams struct {
// and re-encodes them for the network protocol. firstIndex uint64
func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, error) { sizeLimit uint64
}
// blockReceiptsToNetwork takes a slice of rlp-encoded receipts (in the 'storage' encoding),
// and an encoded block body, and re-encodes the receipts for the network protocol.
func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue, q receiptQueryParams) (output []byte, incomplete bool, err error) {
txTypesIter, err := txTypesInBody(blockBody) txTypesIter, err := txTypesInBody(blockBody)
if err != nil { if err != nil {
return nil, fmt.Errorf("invalid block body: %v", err) return nil, false, fmt.Errorf("invalid block body: %v", err)
} }
nextTxType, stopTxTypes := iter.Pull(txTypesIter) nextTxType, stopTxTypes := iter.Pull(txTypesIter)
defer stopTxTypes() defer stopTxTypes()
@ -256,9 +261,24 @@ func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, erro
it, _ = rlp.NewListIterator(blockReceipts) it, _ = rlp.NewListIterator(blockReceipts)
) )
outer := enc.List() outer := enc.List()
for i := 0; it.Next(); i++ { for i := 0; it.Next() && !incomplete; i++ {
txType, _ := nextTxType() txType, end := nextTxType()
if end {
return nil, false, fmt.Errorf("block has less txs than receipts (%d)", i)
}
// Skip receipts before the requested index.
if uint64(i) < q.firstIndex {
continue
}
content, _, _ := rlp.SplitList(it.Value()) content, _, _ := rlp.SplitList(it.Value())
// Stop appending receipts when they would go over the size limit.
// Note we rely on the assumption that the txType is encoded as a single byte,
// which is always true because EIP-2718 does not allow tx types > 0x7f.
size := rlp.ListSize(1 + uint64(len(content)))
if q.sizeLimit > 0 && (uint64(enc.Size())+size) > q.sizeLimit {
break
}
receiptList := enc.List() receiptList := enc.List()
enc.WriteUint64(uint64(txType)) enc.WriteUint64(uint64(txType))
enc.Write(content) enc.Write(content)
@ -266,7 +286,7 @@ func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, erro
} }
enc.ListEnd(outer) enc.ListEnd(outer)
enc.Flush() enc.Flush()
return out.Bytes(), nil return out.Bytes(), incomplete, nil
} }
// txTypesInBody parses the transactions list of an encoded block body, returning just the types. // txTypesInBody parses the transactions list of an encoded block body, returning just the types.

View file

@ -105,10 +105,13 @@ func TestReceiptList(t *testing.T) {
canonBody, _ := rlp.EncodeToBytes(blockBody) canonBody, _ := rlp.EncodeToBytes(blockBody)
// convert from storage encoding to network encoding // convert from storage encoding to network encoding
network, err := blockReceiptsToNetwork(canonDB, canonBody) network, incomplete, err := blockReceiptsToNetwork(canonDB, canonBody, receiptQueryParams{})
if err != nil { if err != nil {
t.Fatalf("test[%d]: blockReceiptsToNetwork error: %v", i, err) t.Fatalf("test[%d]: blockReceiptsToNetwork error: %v", i, err)
} }
if incomplete {
t.Fatalf("test[%d]: blockReceiptsToNetwork returned incomplete == true", i)
}
// parse as Receipts response list from network encoding // parse as Receipts response list from network encoding
var rl ReceiptList var rl ReceiptList