Skip to content

Commit a402cbf

Browse files
committed
core/types: add MarshalBinary, UnmarshalBinary for Receipt (ethereum#22806)
1 parent e5fb0b4 commit a402cbf

File tree

2 files changed

+162
-21
lines changed

2 files changed

+162
-21
lines changed

core/types/receipt.go

Lines changed: 74 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -128,12 +128,29 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
128128
defer encodeBufferPool.Put(buf)
129129
buf.Reset()
130130
buf.WriteByte(r.Type)
131-
if err := rlp.Encode(buf, data); err != nil {
131+
if err := r.encodeTyped(data, buf); err != nil {
132132
return err
133133
}
134134
return rlp.Encode(w, buf.Bytes())
135135
}
136136

137+
// encodeTyped writes the canonical encoding of a typed receipt to w.
138+
func (r *Receipt) encodeTyped(data *receiptRLP, w *bytes.Buffer) error {
139+
w.WriteByte(r.Type)
140+
return rlp.Encode(w, data)
141+
}
142+
143+
// MarshalBinary returns the consensus encoding of the receipt.
144+
func (r *Receipt) MarshalBinary() ([]byte, error) {
145+
if r.Type == LegacyTxType {
146+
return rlp.EncodeToBytes(r)
147+
}
148+
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
149+
var buf bytes.Buffer
150+
err := r.encodeTyped(data, &buf)
151+
return buf.Bytes(), err
152+
}
153+
137154
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
138155
// from an RLP stream.
139156
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
@@ -172,6 +189,42 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
172189
}
173190
}
174191

192+
// UnmarshalBinary decodes the consensus encoding of receipts.
193+
// It supports legacy RLP receipts and EIP-2718 typed receipts.
194+
func (r *Receipt) UnmarshalBinary(b []byte) error {
195+
if len(b) > 0 && b[0] > 0x7f {
196+
// It's a legacy receipt decode the RLP
197+
var data receiptRLP
198+
err := rlp.DecodeBytes(b, &data)
199+
if err != nil {
200+
return err
201+
}
202+
r.Type = LegacyTxType
203+
return r.setFromRLP(data)
204+
}
205+
// It's an EIP2718 typed transaction envelope.
206+
return r.decodeTyped(b)
207+
}
208+
209+
// decodeTyped decodes a typed receipt from the canonical format.
210+
func (r *Receipt) decodeTyped(b []byte) error {
211+
if len(b) == 0 {
212+
return errEmptyTypedReceipt
213+
}
214+
switch b[0] {
215+
case DynamicFeeTxType, AccessListTxType:
216+
var data receiptRLP
217+
err := rlp.DecodeBytes(b[1:], &data)
218+
if err != nil {
219+
return err
220+
}
221+
r.Type = b[0]
222+
return r.setFromRLP(data)
223+
default:
224+
return ErrTxTypeNotSupported
225+
}
226+
}
227+
175228
func (r *Receipt) setFromRLP(data receiptRLP) error {
176229
r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs
177230
return r.setStatus(data.PostStateOrStatus)
@@ -279,11 +332,11 @@ func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
279332
type Receipts []*Receipt
280333

281334
// Len returns the number of receipts in this list.
282-
func (r Receipts) Len() int { return len(r) }
335+
func (rs Receipts) Len() int { return len(rs) }
283336

284337
// GetRlp returns the RLP encoding of one receipt from the list.
285-
func (r Receipts) GetRlp(i int) []byte {
286-
bytes, err := rlp.EncodeToBytes(r[i])
338+
func (rs Receipts) GetRlp(i int) []byte {
339+
bytes, err := rlp.EncodeToBytes(rs[i])
287340
if err != nil {
288341
panic(err)
289342
}
@@ -292,42 +345,42 @@ func (r Receipts) GetRlp(i int) []byte {
292345

293346
// DeriveFields fills the receipts with their computed fields based on consensus
294347
// data and contextual infos like containing block and transactions.
295-
func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
348+
func (rs Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
296349
signer := MakeSigner(config, new(big.Int).SetUint64(number))
297350

298351
logIndex := uint(0)
299-
if len(txs) != len(r) {
352+
if len(txs) != len(rs) {
300353
return errors.New("transaction and receipt count mismatch")
301354
}
302-
for i := 0; i < len(r); i++ {
355+
for i := 0; i < len(rs); i++ {
303356
// The transaction type and hash can be retrieved from the transaction itself
304-
r[i].Type = txs[i].Type()
305-
r[i].TxHash = txs[i].Hash()
357+
rs[i].Type = txs[i].Type()
358+
rs[i].TxHash = txs[i].Hash()
306359

307360
// block location fields
308-
r[i].BlockHash = hash
309-
r[i].BlockNumber = new(big.Int).SetUint64(number)
310-
r[i].TransactionIndex = uint(i)
361+
rs[i].BlockHash = hash
362+
rs[i].BlockNumber = new(big.Int).SetUint64(number)
363+
rs[i].TransactionIndex = uint(i)
311364

312365
// The contract address can be derived from the transaction itself
313366
if txs[i].To() == nil {
314367
// Deriving the signer is expensive, only do if it's actually needed
315368
from, _ := Sender(signer, txs[i])
316-
r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
369+
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
317370
}
318371
// The used gas can be calculated based on previous r
319372
if i == 0 {
320-
r[i].GasUsed = r[i].CumulativeGasUsed
373+
rs[i].GasUsed = rs[i].CumulativeGasUsed
321374
} else {
322-
r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed
375+
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
323376
}
324377
// The derived log fields can simply be set from the block and transaction
325-
for j := 0; j < len(r[i].Logs); j++ {
326-
r[i].Logs[j].BlockNumber = number
327-
r[i].Logs[j].BlockHash = hash
328-
r[i].Logs[j].TxHash = r[i].TxHash
329-
r[i].Logs[j].TxIndex = uint(i)
330-
r[i].Logs[j].Index = logIndex
378+
for j := 0; j < len(rs[i].Logs); j++ {
379+
rs[i].Logs[j].BlockNumber = number
380+
rs[i].Logs[j].BlockHash = hash
381+
rs[i].Logs[j].TxHash = rs[i].TxHash
382+
rs[i].Logs[j].TxIndex = uint(i)
383+
rs[i].Logs[j].Index = logIndex
331384
logIndex++
332385
}
333386
}

core/types/receipt_test.go

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,59 @@ import (
2929
"github.com/XinFinOrg/XDPoSChain/rlp"
3030
)
3131

32+
var (
33+
legacyReceipt = &Receipt{
34+
Status: ReceiptStatusFailed,
35+
CumulativeGasUsed: 1,
36+
Logs: []*Log{
37+
{
38+
Address: common.BytesToAddress([]byte{0x11}),
39+
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
40+
Data: []byte{0x01, 0x00, 0xff},
41+
},
42+
{
43+
Address: common.BytesToAddress([]byte{0x01, 0x11}),
44+
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
45+
Data: []byte{0x01, 0x00, 0xff},
46+
},
47+
},
48+
}
49+
accessListReceipt = &Receipt{
50+
Status: ReceiptStatusFailed,
51+
CumulativeGasUsed: 1,
52+
Logs: []*Log{
53+
{
54+
Address: common.BytesToAddress([]byte{0x11}),
55+
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
56+
Data: []byte{0x01, 0x00, 0xff},
57+
},
58+
{
59+
Address: common.BytesToAddress([]byte{0x01, 0x11}),
60+
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
61+
Data: []byte{0x01, 0x00, 0xff},
62+
},
63+
},
64+
Type: AccessListTxType,
65+
}
66+
eip1559Receipt = &Receipt{
67+
Status: ReceiptStatusFailed,
68+
CumulativeGasUsed: 1,
69+
Logs: []*Log{
70+
{
71+
Address: common.BytesToAddress([]byte{0x11}),
72+
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
73+
Data: []byte{0x01, 0x00, 0xff},
74+
},
75+
{
76+
Address: common.BytesToAddress([]byte{0x01, 0x11}),
77+
Topics: []common.Hash{common.HexToHash("dead"), common.HexToHash("beef")},
78+
Data: []byte{0x01, 0x00, 0xff},
79+
},
80+
},
81+
Type: DynamicFeeTxType,
82+
}
83+
)
84+
3285
func TestDecodeEmptyTypedReceipt(t *testing.T) {
3386
input := []byte{0x80}
3487
var r Receipt
@@ -315,3 +368,38 @@ func TestTypedReceiptEncodingDecoding(t *testing.T) {
315368
check(bundle)
316369
}
317370
}
371+
372+
func TestReceiptUnmarshalBinary(t *testing.T) {
373+
// Legacy Receipt
374+
legacyBinary := common.FromHex("f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
375+
gotLegacyReceipt := new(Receipt)
376+
if err := gotLegacyReceipt.UnmarshalBinary(legacyBinary); err != nil {
377+
t.Fatalf("unmarshal binary error: %v", err)
378+
}
379+
legacyReceipt.Bloom = CreateBloom(Receipts{legacyReceipt})
380+
if !reflect.DeepEqual(gotLegacyReceipt, legacyReceipt) {
381+
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotLegacyReceipt, legacyReceipt)
382+
}
383+
384+
// 2930 Receipt
385+
accessListBinary := common.FromHex("01f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
386+
gotAccessListReceipt := new(Receipt)
387+
if err := gotAccessListReceipt.UnmarshalBinary(accessListBinary); err != nil {
388+
t.Fatalf("unmarshal binary error: %v", err)
389+
}
390+
accessListReceipt.Bloom = CreateBloom(Receipts{accessListReceipt})
391+
if !reflect.DeepEqual(gotAccessListReceipt, accessListReceipt) {
392+
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", gotAccessListReceipt, accessListReceipt)
393+
}
394+
395+
// 1559 Receipt
396+
eip1559RctBinary := common.FromHex("02f901c58001b9010000000000000010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000500000000000000000000000000000000000014000000000000000000000000000000000000000000000000000000000000000000000000000010000080000000000000000000004000000000000000000000000000040000000000000000000000000000800000000000000000000000000000000000000000000000000000400000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000f8bef85d940000000000000000000000000000000000000011f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100fff85d940000000000000000000000000000000000000111f842a0000000000000000000000000000000000000000000000000000000000000deada0000000000000000000000000000000000000000000000000000000000000beef830100ff")
397+
got1559Receipt := new(Receipt)
398+
if err := got1559Receipt.UnmarshalBinary(eip1559RctBinary); err != nil {
399+
t.Fatalf("unmarshal binary error: %v", err)
400+
}
401+
eip1559Receipt.Bloom = CreateBloom(Receipts{eip1559Receipt})
402+
if !reflect.DeepEqual(got1559Receipt, eip1559Receipt) {
403+
t.Errorf("receipt unmarshalled from binary mismatch, got %v want %v", got1559Receipt, eip1559Receipt)
404+
}
405+
}

0 commit comments

Comments
 (0)