Skip to content

Commit df799eb

Browse files
committed
receipt MarshalBinary and UnmarshalBinary methods
1 parent 5228b2a commit df799eb

File tree

1 file changed

+74
-17
lines changed

1 file changed

+74
-17
lines changed

core/types/receipt.go

Lines changed: 74 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,9 @@ var (
4141
// This error is returned when a typed receipt is decoded, but the string is empty.
4242
var errEmptyTypedReceipt = errors.New("empty typed receipt bytes")
4343

44+
// This error is returned when a typed receipt has an unsupported type
45+
var errRctTypeNotSupported = errors.New("receipt type not supported")
46+
4447
const (
4548
// ReceiptStatusFailed is the status code of a transaction if execution failed.
4649
ReceiptStatusFailed = uint64(0)
@@ -130,6 +133,24 @@ func (r *Receipt) EncodeRLP(w io.Writer) error {
130133
return rlp.Encode(w, buf.Bytes())
131134
}
132135

136+
// MarshalBinary returns the canonical encoding of the receipt.
137+
// For legacy receipts, it returns the RLP encoding. For EIP-2718 typed
138+
// receipts, it returns the `type || RLP encoding`.
139+
func (r *Receipt) MarshalBinary() ([]byte, error) {
140+
if r.Type == LegacyTxType {
141+
return rlp.EncodeToBytes(r)
142+
}
143+
data := &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs}
144+
buf := encodeBufferPool.Get().(*bytes.Buffer)
145+
defer encodeBufferPool.Put(buf)
146+
buf.Reset()
147+
buf.WriteByte(r.Type)
148+
if err := rlp.Encode(buf, data); err != nil {
149+
return nil, err
150+
}
151+
return buf.Bytes(), nil
152+
}
153+
133154
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
134155
// from an RLP stream.
135156
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
@@ -168,6 +189,42 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
168189
}
169190
}
170191

192+
// UnmarshalBinary decodes the canonical 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 AccessListTxType:
216+
var data receiptRLP
217+
err := rlp.DecodeBytes(b[1:], &data)
218+
if err != nil {
219+
return err
220+
}
221+
r.Type = AccessListTxType
222+
return r.setFromRLP(data)
223+
default:
224+
return ErrTxTypeNotSupported
225+
}
226+
}
227+
171228
func (r *Receipt) setFromRLP(data receiptRLP) error {
172229
r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs
173230
return r.setStatus(data.PostStateOrStatus)
@@ -271,42 +328,42 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) {
271328

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

277334
logIndex := uint(0)
278-
if len(txs) != len(r) {
335+
if len(txs) != len(rs) {
279336
return errors.New("transaction and receipt count mismatch")
280337
}
281-
for i := 0; i < len(r); i++ {
338+
for i := 0; i < len(rs); i++ {
282339
// The transaction type and hash can be retrieved from the transaction itself
283-
r[i].Type = txs[i].Type()
284-
r[i].TxHash = txs[i].Hash()
340+
rs[i].Type = txs[i].Type()
341+
rs[i].TxHash = txs[i].Hash()
285342

286343
// block location fields
287-
r[i].BlockHash = hash
288-
r[i].BlockNumber = new(big.Int).SetUint64(number)
289-
r[i].TransactionIndex = uint(i)
344+
rs[i].BlockHash = hash
345+
rs[i].BlockNumber = new(big.Int).SetUint64(number)
346+
rs[i].TransactionIndex = uint(i)
290347

291348
// The contract address can be derived from the transaction itself
292349
if txs[i].To() == nil {
293350
// Deriving the signer is expensive, only do if it's actually needed
294351
from, _ := Sender(signer, txs[i])
295-
r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
352+
rs[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
296353
}
297354
// The used gas can be calculated based on previous r
298355
if i == 0 {
299-
r[i].GasUsed = r[i].CumulativeGasUsed
356+
rs[i].GasUsed = rs[i].CumulativeGasUsed
300357
} else {
301-
r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed
358+
rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed
302359
}
303360
// The derived log fields can simply be set from the block and transaction
304-
for j := 0; j < len(r[i].Logs); j++ {
305-
r[i].Logs[j].BlockNumber = number
306-
r[i].Logs[j].BlockHash = hash
307-
r[i].Logs[j].TxHash = r[i].TxHash
308-
r[i].Logs[j].TxIndex = uint(i)
309-
r[i].Logs[j].Index = logIndex
361+
for j := 0; j < len(rs[i].Logs); j++ {
362+
rs[i].Logs[j].BlockNumber = number
363+
rs[i].Logs[j].BlockHash = hash
364+
rs[i].Logs[j].TxHash = rs[i].TxHash
365+
rs[i].Logs[j].TxIndex = uint(i)
366+
rs[i].Logs[j].Index = logIndex
310367
logIndex++
311368
}
312369
}

0 commit comments

Comments
 (0)