|
41 | 41 | // This error is returned when a typed receipt is decoded, but the string is empty. |
42 | 42 | var errEmptyTypedReceipt = errors.New("empty typed receipt bytes") |
43 | 43 |
|
| 44 | +// This error is returned when a typed receipt has an unsupported type |
| 45 | +var errRctTypeNotSupported = errors.New("receipt type not supported") |
| 46 | + |
44 | 47 | const ( |
45 | 48 | // ReceiptStatusFailed is the status code of a transaction if execution failed. |
46 | 49 | ReceiptStatusFailed = uint64(0) |
@@ -130,6 +133,24 @@ func (r *Receipt) EncodeRLP(w io.Writer) error { |
130 | 133 | return rlp.Encode(w, buf.Bytes()) |
131 | 134 | } |
132 | 135 |
|
| 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 | + |
133 | 154 | // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt |
134 | 155 | // from an RLP stream. |
135 | 156 | func (r *Receipt) DecodeRLP(s *rlp.Stream) error { |
@@ -168,6 +189,42 @@ func (r *Receipt) DecodeRLP(s *rlp.Stream) error { |
168 | 189 | } |
169 | 190 | } |
170 | 191 |
|
| 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 | + |
171 | 228 | func (r *Receipt) setFromRLP(data receiptRLP) error { |
172 | 229 | r.CumulativeGasUsed, r.Bloom, r.Logs = data.CumulativeGasUsed, data.Bloom, data.Logs |
173 | 230 | return r.setStatus(data.PostStateOrStatus) |
@@ -271,42 +328,42 @@ func (rs Receipts) EncodeIndex(i int, w *bytes.Buffer) { |
271 | 328 |
|
272 | 329 | // DeriveFields fills the receipts with their computed fields based on consensus |
273 | 330 | // 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 { |
275 | 332 | signer := MakeSigner(config, new(big.Int).SetUint64(number)) |
276 | 333 |
|
277 | 334 | logIndex := uint(0) |
278 | | - if len(txs) != len(r) { |
| 335 | + if len(txs) != len(rs) { |
279 | 336 | return errors.New("transaction and receipt count mismatch") |
280 | 337 | } |
281 | | - for i := 0; i < len(r); i++ { |
| 338 | + for i := 0; i < len(rs); i++ { |
282 | 339 | // 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() |
285 | 342 |
|
286 | 343 | // 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) |
290 | 347 |
|
291 | 348 | // The contract address can be derived from the transaction itself |
292 | 349 | if txs[i].To() == nil { |
293 | 350 | // Deriving the signer is expensive, only do if it's actually needed |
294 | 351 | 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()) |
296 | 353 | } |
297 | 354 | // The used gas can be calculated based on previous r |
298 | 355 | if i == 0 { |
299 | | - r[i].GasUsed = r[i].CumulativeGasUsed |
| 356 | + rs[i].GasUsed = rs[i].CumulativeGasUsed |
300 | 357 | } else { |
301 | | - r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed |
| 358 | + rs[i].GasUsed = rs[i].CumulativeGasUsed - rs[i-1].CumulativeGasUsed |
302 | 359 | } |
303 | 360 | // 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 |
310 | 367 | logIndex++ |
311 | 368 | } |
312 | 369 | } |
|
0 commit comments