diff options
Diffstat (limited to 'core/types/receipt.go')
-rw-r--r-- | core/types/receipt.go | 75 |
1 files changed, 64 insertions, 11 deletions
diff --git a/core/types/receipt.go b/core/types/receipt.go index ef6f6a2bb..c9906b015 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -31,7 +31,7 @@ import ( // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields - PostState []byte `json:"root" gencodec:"required"` + PostState []byte `json:"root"` CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -48,35 +48,88 @@ type receiptMarshaling struct { GasUsed *hexutil.Big } +// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used +// during RLP serialization. +type homesteadReceiptRLP struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + +// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used +// during RLP serialization. +type metropolisReceiptRLP struct { + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + // NewReceipt creates a barebone transaction receipt, copying the init fields. func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} } // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt -// into an RLP stream. +// into an RLP stream. If no post state is present, metropolis fork is assumed. func (r *Receipt) EncodeRLP(w io.Writer) error { - return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) + if r.PostState == nil { + return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs}) + } + return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) } // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt // from an RLP stream. func (r *Receipt) DecodeRLP(s *rlp.Stream) error { - var receipt struct { - PostState []byte - CumulativeGasUsed *big.Int - Bloom Bloom - Logs []*Log + // Load the raw bytes since we have multiple possible formats + raw, err := s.Raw() + if err != nil { + return err } - if err := s.Decode(&receipt); err != nil { + list, _, err := rlp.SplitList(raw) + if err != nil { return err } - r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs - return nil + items, err := rlp.CountValues(list) + if err != nil { + return err + } + // Deserialize based on the number of content items + switch items { + case 3: + // Metropolis receipts have 3 components + var metro metropolisReceiptRLP + if err := rlp.DecodeBytes(raw, &metro); err != nil { + return err + } + r.CumulativeGasUsed = metro.CumulativeGasUsed + r.Bloom = metro.Bloom + r.Logs = metro.Logs + return nil + + case 4: + // Homestead receipts have 4 components + var home homesteadReceiptRLP + if err := rlp.DecodeBytes(raw, &home); err != nil { + return err + } + r.PostState = home.PostState[:] + r.CumulativeGasUsed = home.CumulativeGasUsed + r.Bloom = home.Bloom + r.Logs = home.Logs + return nil + + default: + return fmt.Errorf("invalid receipt components: %v", items) + } } // String implements the Stringer interface. func (r *Receipt) String() string { + if r.PostState == nil { + return fmt.Sprintf("receipt{cgas=%v bloom=%x logs=%v}", r.CumulativeGasUsed, r.Bloom, r.Logs) + } return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs) } |