From ca967ad1bb56fba1dd2ad01fcabb6e0e86be56a7 Mon Sep 17 00:00:00 2001 From: Sina Mahmoodi Date: Fri, 6 Feb 2026 13:09:46 +0100 Subject: [PATCH] introduce slimReceipt type --- core/types/receipt.go | 30 +++++++++++++++++++++++++ core/types/receipt_test.go | 39 +++++++++++++++++++++++++++++++++ internal/era/execdb/builder.go | 4 ++-- internal/era/execdb/era_test.go | 6 ++--- internal/era/execdb/iterator.go | 5 +---- 5 files changed, 75 insertions(+), 9 deletions(-) diff --git a/core/types/receipt.go b/core/types/receipt.go index 5b6669f274..ba7d9900f0 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -424,3 +424,33 @@ func EncodeBlockReceiptLists(receipts []Receipts) []rlp.RawValue { } return result } + +// SlimReceipt is a wrapper around a Receipt with RLP serialization that omits +// the Bloom field and includes the tx type. Used for era files. +type SlimReceipt Receipt + +type slimReceiptRLP struct { + Type uint8 + StatusEncoding []byte + CumulativeGasUsed uint64 + Logs []*Log +} + +// EncodeRLP implements rlp.Encoder, encoding the receipt as +// [tx-type, post-state-or-status, cumulative-gas, logs]. +func (r *SlimReceipt) EncodeRLP(w io.Writer) error { + data := &slimReceiptRLP{r.Type, (*Receipt)(r).statusEncoding(), r.CumulativeGasUsed, r.Logs} + return rlp.Encode(w, data) +} + +// DecodeRLP implements rlp.Decoder. +func (r *SlimReceipt) DecodeRLP(s *rlp.Stream) error { + var data slimReceiptRLP + if err := s.Decode(&data); err != nil { + return err + } + r.Type = data.Type + r.CumulativeGasUsed = data.CumulativeGasUsed + r.Logs = data.Logs + return (*Receipt)(r).setStatus(data.StatusEncoding) +} diff --git a/core/types/receipt_test.go b/core/types/receipt_test.go index 8f805ff096..676d9c3d30 100644 --- a/core/types/receipt_test.go +++ b/core/types/receipt_test.go @@ -512,6 +512,45 @@ func TestReceiptUnmarshalBinary(t *testing.T) { } } +func TestSlimReceiptEncodingDecoding(t *testing.T) { + tests := []*Receipt{ + legacyReceipt, + accessListReceipt, + eip1559Receipt, + { + Type: BlobTxType, + Status: ReceiptStatusSuccessful, + CumulativeGasUsed: 100, + Logs: []*Log{}, + }, + } + for i, want := range tests { + enc, err := rlp.EncodeToBytes((*SlimReceipt)(want)) + if err != nil { + t.Fatalf("test %d: encode error: %v", i, err) + } + got := new(SlimReceipt) + if err := rlp.DecodeBytes(enc, got); err != nil { + t.Fatalf("test %d: decode error: %v", i, err) + } + if got.Type != want.Type { + t.Errorf("test %d: Type mismatch: got %d, want %d", i, got.Type, want.Type) + } + if got.Status != want.Status { + t.Errorf("test %d: Status mismatch: got %d, want %d", i, got.Status, want.Status) + } + if !bytes.Equal(got.PostState, want.PostState) { + t.Errorf("test %d: PostState mismatch: got %x, want %x", i, got.PostState, want.PostState) + } + if got.CumulativeGasUsed != want.CumulativeGasUsed { + t.Errorf("test %d: CumulativeGasUsed mismatch: got %d, want %d", i, got.CumulativeGasUsed, want.CumulativeGasUsed) + } + if len(got.Logs) != len(want.Logs) { + t.Errorf("test %d: Logs length mismatch: got %d, want %d", i, len(got.Logs), len(want.Logs)) + } + } +} + func clearComputedFieldsOnReceipts(receipts []*Receipt) []*Receipt { r := make([]*Receipt, len(receipts)) for i, receipt := range receipts { diff --git a/internal/era/execdb/builder.go b/internal/era/execdb/builder.go index 4a3609ebf7..da7f6a08c3 100644 --- a/internal/era/execdb/builder.go +++ b/internal/era/execdb/builder.go @@ -107,9 +107,9 @@ func (b *Builder) Add(block *types.Block, receipts types.Receipts, td *big.Int) return fmt.Errorf("encode body: %w", err) } - rs := make([]*types.ReceiptForStorage, len(receipts)) + rs := make([]*types.SlimReceipt, len(receipts)) for i, receipt := range receipts { - rs[i] = (*types.ReceiptForStorage)(receipt) + rs[i] = (*types.SlimReceipt)(receipt) } er, err := rlp.EncodeToBytes(rs) if err != nil { diff --git a/internal/era/execdb/era_test.go b/internal/era/execdb/era_test.go index a8c1ac18ba..f66931b9ed 100644 --- a/internal/era/execdb/era_test.go +++ b/internal/era/execdb/era_test.go @@ -100,7 +100,7 @@ func TestEraE(t *testing.T) { blk := blockData{ header: mustEncode(&types.Header{Number: big.NewInt(int64(num)), Difficulty: big.NewInt(1)}), body: mustEncode(&types.Body{Transactions: []*types.Transaction{types.NewTransaction(0, common.Address{byte(i)}, nil, 0, nil, nil)}}), - receipts: mustEncode([]types.ReceiptForStorage{{CumulativeGasUsed: uint64(i)}}), + receipts: mustEncode([]types.SlimReceipt{{CumulativeGasUsed: uint64(i)}}), hash: common.Hash{byte(i)}, td: big.NewInt(int64(i + 1)), difficulty: big.NewInt(1), @@ -118,7 +118,7 @@ func TestEraE(t *testing.T) { blk := blockData{ header: mustEncode(&types.Header{Number: big.NewInt(int64(num)), Difficulty: big.NewInt(0)}), body: mustEncode(&types.Body{}), - receipts: mustEncode([]types.ReceiptForStorage{}), + receipts: mustEncode([]types.SlimReceipt{}), hash: common.Hash{byte(idx)}, difficulty: big.NewInt(0), } @@ -306,7 +306,7 @@ func TestInitialTD(t *testing.T) { // First block: difficulty=5, TD=10, so initial TD = 10-5 = 5. header := mustEncode(&types.Header{Number: big.NewInt(0), Difficulty: big.NewInt(5)}) body := mustEncode(&types.Body{}) - receipts := mustEncode([]types.ReceiptForStorage{}) + receipts := mustEncode([]types.SlimReceipt{}) if err := builder.AddRLP(header, body, receipts, 0, common.Hash{0}, big.NewInt(10), big.NewInt(5)); err != nil { t.Fatalf("error adding block: %v", err) diff --git a/internal/era/execdb/iterator.go b/internal/era/execdb/iterator.go index 655edb0e01..8d17ac00a9 100644 --- a/internal/era/execdb/iterator.go +++ b/internal/era/execdb/iterator.go @@ -88,19 +88,16 @@ func (it *Iterator) Receipts() (types.Receipts, error) { if it.inner.Receipts == nil { return nil, errors.New("receipts must be non‑nil") } - var rs []*types.ReceiptForStorage + var rs []*types.SlimReceipt if err := rlp.Decode(it.inner.Receipts, &rs); err != nil { return nil, err } - if len(rs) != len(block.Transactions()) { return nil, errors.New("number of txs does not match receipts") } - receipts := make([]*types.Receipt, len(rs)) for i, receipt := range rs { receipts[i] = (*types.Receipt)(receipt) - receipts[i].Type = block.Transactions()[i].Type() receipts[i].Bloom = types.CreateBloom(receipts[i]) } return receipts, nil