|
|
@@ -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)
|
|
|
}
|
|
|
|