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

View file

@ -240,12 +240,17 @@ func (rl *ReceiptList) LogsSize() (uint64, error) {
return size, nil
}
// blockReceiptsToNetwork takes a slice of rlp-encoded receipts, and transactions,
// and re-encodes them for the network protocol.
func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, error) {
type receiptQueryParams struct {
firstIndex uint64
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)
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)
defer stopTxTypes()
@ -256,9 +261,24 @@ func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, erro
it, _ = rlp.NewListIterator(blockReceipts)
)
outer := enc.List()
for i := 0; it.Next(); i++ {
txType, _ := nextTxType()
for i := 0; it.Next() && !incomplete; i++ {
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())
// 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()
enc.WriteUint64(uint64(txType))
enc.Write(content)
@ -266,7 +286,7 @@ func blockReceiptsToNetwork(blockReceipts, blockBody rlp.RawValue) ([]byte, erro
}
enc.ListEnd(outer)
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.

View file

@ -105,10 +105,13 @@ func TestReceiptList(t *testing.T) {
canonBody, _ := rlp.EncodeToBytes(blockBody)
// convert from storage encoding to network encoding
network, err := blockReceiptsToNetwork(canonDB, canonBody)
network, incomplete, err := blockReceiptsToNetwork(canonDB, canonBody, receiptQueryParams{})
if err != nil {
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
var rl ReceiptList