core/types: reduce allocation when decoding typed transactions and receipts

This commit is contained in:
Felix Lange 2023-08-22 18:41:31 +02:00
parent e4a28340c4
commit 353c1d3ee0
3 changed files with 34 additions and 4 deletions

View file

@ -18,6 +18,8 @@ package types
import (
"bytes"
"fmt"
"math"
"sync"
"github.com/ethereum/go-ethereum/common"
@ -36,6 +38,21 @@ var encodeBufferPool = sync.Pool{
New: func() interface{} { return new(bytes.Buffer) },
}
// getPooledBuffer retrieves a buffer from the pool and creates a byte slice
// of the requested size from it.
//
// The caller should return the Buffer object back into encodeBufferPool after use!
func getPooledBuffer(size uint64) ([]byte, *bytes.Buffer, error) {
if size > math.MaxInt {
return nil, nil, fmt.Errorf("can't get buffer of size %d", size)
}
buf := encodeBufferPool.Get().(*bytes.Buffer)
buf.Reset()
buf.Grow(int(size))
b := buf.Bytes()[:int(size)]
return b, buf, nil
}
// rlpHash encodes x and hashes the encoded bytes.
func rlpHash(x interface{}) (h common.Hash) {
sha := hasherPool.Get().(crypto.KeccakState)

View file

@ -153,7 +153,7 @@ func (r *Receipt) MarshalBinary() ([]byte, error) {
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
kind, _, err := s.Kind()
kind, size, err := s.Kind()
switch {
case err != nil:
return err
@ -167,7 +167,14 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
return r.setFromRLP(dec)
default:
// It's an EIP-2718 typed tx receipt.
b, err := s.Bytes()
b, buf, err := getPooledBuffer(size)
if err != nil {
return err
}
defer encodeBufferPool.Put(buf)
if err := s.ReadBytes(b); err != nil {
return err
}
if err != nil {
return err
}

View file

@ -147,10 +147,16 @@ func (tx *Transaction) DecodeRLP(s *rlp.Stream) error {
return err
default:
// It's an EIP-2718 typed TX envelope.
var b []byte
if b, err = s.Bytes(); err != nil {
// First read the tx payload bytes into a temporary buffer.
b, buf, err := getPooledBuffer(size)
if err != nil {
return err
}
defer encodeBufferPool.Put(buf)
if err := s.ReadBytes(b); err != nil {
return err
}
// Now decode the inner transaction.
inner, err := tx.decodeTyped(b)
if err == nil {
tx.setDecoded(inner, uint64(len(b)))