@ -17,6 +17,7 @@
package types
import (
"bytes"
"fmt"
"io"
"math/big"
@ -28,9 +29,9 @@ import (
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
const (
receiptStatusSuccessful = byte ( 0x01 )
receiptStatusFailed = byte ( 0x00 )
var (
receiptStatusFailed = [ ] byte { }
receiptStatusSuccessful = [ ] byte { 0x01 }
)
// Receipt represents the results of a transaction.
@ -54,22 +55,22 @@ type receiptMarshaling struct {
GasUsed * hexutil . Big
}
// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used
// during RLP serialization.
type homesteadReceiptRLP struct {
PostState [ ] byte
// receiptRLP is the consensus encoding of a receipt.
type receiptRLP struct {
PostStateOrStatus [ ] byte
CumulativeGasUsed * big . Int
Bloom Bloom
Logs [ ] * Log
}
// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used
// during RLP serialization.
type metropolisReceiptRLP struct {
Status byte
type receiptStorageRLP struct {
PostStateOrStatus [ ] byte
CumulativeGasUsed * big . Int
Bloom Bloom
Logs [ ] * Log
TxHash common . Hash
ContractAddress common . Address
Logs [ ] * LogForStorage
GasUsed * big . Int
}
// NewReceipt creates a barebone transaction receipt, copying the init fields.
@ -80,69 +81,46 @@ func NewReceipt(root []byte, failed bool, cumulativeGasUsed *big.Int) *Receipt {
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
// into an RLP stream. If no post state is present, metropolis fork is assumed.
func ( r * Receipt ) EncodeRLP ( w io . Writer ) error {
if r . PostState == nil {
status := receiptStatusSuccessful
if r . Failed {
status = receiptStatusFailed
}
return rlp . Encode ( w , & metropolisReceiptRLP { status , r . CumulativeGasUsed , r . Bloom , r . Logs } )
}
return rlp . Encode ( w , & homesteadReceiptRLP { r . PostState , r . CumulativeGasUsed , r . Bloom , r . Logs } )
return rlp . Encode ( w , & receiptRLP { r . statusEncoding ( ) , 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 {
// Load the raw bytes since we have multiple possible formats
raw , err := s . Raw ( )
if err != nil {
var dec receiptRLP
if err := s . Decode ( & dec ) ; err != nil {
return err
}
content , _ , err := rlp . SplitList ( raw )
if err != nil {
if err := r . setStatus ( dec . PostStateOrStatus ) ; err != nil {
return err
}
kind , cnt , _ , err := rlp . Split ( content )
if err != nil {
return err
}
// Deserialize based on the first component type.
switch {
case kind == rlp . Byte || ( kind == rlp . String && len ( cnt ) == 0 ) :
// The first component of metropolis receipts is Byte (0x01), or the empty
// string (0x80, decoded as a byte with 0x00 value).
var metro metropolisReceiptRLP
if err := rlp . DecodeBytes ( raw , & metro ) ; err != nil {
return err
}
switch metro . Status {
case receiptStatusSuccessful :
r . Failed = false
case receiptStatusFailed :
r . Failed = true
default :
return fmt . Errorf ( "invalid status byte: 0x%x" , metro . Status )
}
r . CumulativeGasUsed = metro . CumulativeGasUsed
r . Bloom = metro . Bloom
r . Logs = metro . Logs
return nil
case kind == rlp . String :
// The first component of homestead receipts is non-empty String.
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
r . CumulativeGasUsed , r . Bloom , r . Logs = dec . CumulativeGasUsed , dec . Bloom , dec . Logs
return nil
}
func ( r * Receipt ) setStatus ( postStateOrStatus [ ] byte ) error {
switch {
case bytes . Equal ( postStateOrStatus , receiptStatusSuccessful ) :
r . Failed = false
case bytes . Equal ( postStateOrStatus , receiptStatusFailed ) :
r . Failed = true
case len ( postStateOrStatus ) == len ( common . Hash { } ) :
r . PostState = postStateOrStatus
default :
return fmt . Errorf ( "invalid first receipt component: %v" , kind )
return fmt . Errorf ( "invalid receipt status %x" , postStateOrStatus )
}
return nil
}
func ( r * Receipt ) statusEncoding ( ) [ ] byte {
if len ( r . PostState ) == 0 {
if r . Failed {
return receiptStatusFailed
} else {
return receiptStatusSuccessful
}
}
return r . PostState
}
// String implements the Stringer interface.
@ -160,38 +138,39 @@ type ReceiptForStorage Receipt
// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
// into an RLP stream.
func ( r * ReceiptForStorage ) EncodeRLP ( w io . Writer ) error {
logs := make ( [ ] * LogForStorage , len ( r . Logs ) )
enc := & receiptStorageRLP {
PostStateOrStatus : ( * Receipt ) ( r ) . statusEncoding ( ) ,
CumulativeGasUsed : r . CumulativeGasUsed ,
Bloom : r . Bloom ,
TxHash : r . TxHash ,
ContractAddress : r . ContractAddress ,
Logs : make ( [ ] * LogForStorage , len ( r . Logs ) ) ,
GasUsed : r . GasUsed ,
}
for i , log := range r . Logs {
logs [ i ] = ( * LogForStorage ) ( log )
enc . L ogs[ i ] = ( * LogForStorage ) ( log )
}
return rlp . Encode ( w , [ ] interface { } { r . PostState , r . Failed , r . CumulativeGasUsed , r . Bloom , r . TxHash , r . ContractAddress , logs , r . GasUsed } )
return rlp . Encode ( w , enc )
}
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
func ( r * ReceiptForStorage ) DecodeRLP ( s * rlp . Stream ) error {
var receipt struct {
PostState [ ] byte
Failed bool
CumulativeGasUsed * big . Int
Bloom Bloom
TxHash common . Hash
ContractAddress common . Address
Logs [ ] * LogForStorage
GasUsed * big . Int
var dec receiptStorageRLP
if err := s . Decode ( & dec ) ; err != nil {
return err
}
if err := s . Decode ( & receipt ) ; err != nil {
if err := ( * Receipt ) ( r ) . setStatus ( dec . PostStateOrStatus ) ; err != nil {
return err
}
// Assign the consensus fields
r . PostState , r . Failed , r . CumulativeGasUsed , r . Bloom = receipt . PostState , receipt . Faile d, r eceipt . CumulativeGasUsed , receipt . Bloom
r . Logs = make ( [ ] * Log , len ( receipt . Logs ) )
for i , log := range receipt . Logs {
r . CumulativeGasUsed , r . Bloom = dec . CumulativeGasUsed , dec . Bloom
r . Logs = make ( [ ] * Log , len ( dec . Logs ) )
for i , log := range dec . Logs {
r . Logs [ i ] = ( * Log ) ( log )
}
// Assign the implementation fields
r . TxHash , r . ContractAddress , r . GasUsed = receipt . TxHash , receipt . ContractAddress , receipt . GasUsed
r . TxHash , r . ContractAddress , r . GasUsed = dec . TxHash , dec . ContractAddress , dec . GasUsed
return nil
}