From 17ecac6a16015ede952e40eb14b82cd0ea86e4e8 Mon Sep 17 00:00:00 2001 From: Sahil Sojitra Date: Fri, 22 May 2026 17:11:42 +0530 Subject: [PATCH] rlp, eth: batch-allocate headers and reuse stream in decode path --- eth/protocols/eth/handlers.go | 23 ++++++++++++++++++++--- rlp/decode.go | 8 ++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/eth/protocols/eth/handlers.go b/eth/protocols/eth/handlers.go index 742cdd9ec3..984b944901 100644 --- a/eth/protocols/eth/handlers.go +++ b/eth/protocols/eth/handlers.go @@ -21,6 +21,7 @@ import ( "encoding/json" "fmt" "math" + "math/big" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/core" @@ -374,15 +375,31 @@ func handleBlockHeaders(backend Backend, msg Decoder, peer *Peer) error { }, metadata) } +type headerAlloc struct { + header types.Header + difficulty big.Int + number big.Int +} + func decodeBlockHeaders(list *rlp.RawList[*types.Header]) ([]*types.Header, error) { headers := make([]*types.Header, 0, list.Len()) + stream := rlp.NewBytesStream(nil) + defer rlp.PutStream(stream) + it := list.ContentIterator() for it.Next() { - header := new(types.Header) - if err := types.DecodeHeader(it.Value(), header); err != nil { + a := new(headerAlloc) + a.header.Difficulty = &a.difficulty + a.header.Number = &a.number + + stream.ResetBytes(it.Value()) + if err := a.header.DecodeRLP(stream); err != nil { return headers, err } - headers = append(headers, header) + if stream.Remaining() != 0 { + return headers, rlp.ErrMoreThanOneValue + } + headers = append(headers, &a.header) } return headers, nil } diff --git a/rlp/decode.go b/rlp/decode.go index 93a8250155..c467d59a47 100644 --- a/rlp/decode.go +++ b/rlp/decode.go @@ -642,6 +642,14 @@ func PutStream(stream *Stream) { streamPool.Put(stream) } +// ResetBytes resets the stream to decode from b, reusing the inline slice +// reader. This allows decoding a batch of values with one pooled stream +// instead of doing a pool round-trip per value. +func (s *Stream) ResetBytes(b []byte) { + s.sliceRdr = b + s.Reset(&s.sliceRdr, uint64(len(b))) +} + // NewListStream creates a new stream that pretends to be positioned // at an encoded list of the given length. func NewListStream(r io.Reader, len uint64) *Stream {