github.com/Ethersocial/go-esn@v0.3.7/core/types/receipt.go (about)

     1  // Copyright 2014 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package types
    18  
    19  import (
    20  	"bytes"
    21  	"fmt"
    22  	"io"
    23  	"unsafe"
    24  
    25  	"github.com/ethersocial/go-esn/common"
    26  	"github.com/ethersocial/go-esn/common/hexutil"
    27  	"github.com/ethersocial/go-esn/rlp"
    28  )
    29  
    30  //go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
    31  
    32  var (
    33  	receiptStatusFailedRLP     = []byte{}
    34  	receiptStatusSuccessfulRLP = []byte{0x01}
    35  )
    36  
    37  const (
    38  	// ReceiptStatusFailed is the status code of a transaction if execution failed.
    39  	ReceiptStatusFailed = uint64(0)
    40  
    41  	// ReceiptStatusSuccessful is the status code of a transaction if execution succeeded.
    42  	ReceiptStatusSuccessful = uint64(1)
    43  )
    44  
    45  // Receipt represents the results of a transaction.
    46  type Receipt struct {
    47  	// Consensus fields
    48  	PostState         []byte `json:"root"`
    49  	Status            uint64 `json:"status"`
    50  	CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
    51  	Bloom             Bloom  `json:"logsBloom"         gencodec:"required"`
    52  	Logs              []*Log `json:"logs"              gencodec:"required"`
    53  
    54  	// Implementation fields (don't reorder!)
    55  	TxHash          common.Hash    `json:"transactionHash" gencodec:"required"`
    56  	ContractAddress common.Address `json:"contractAddress"`
    57  	GasUsed         uint64         `json:"gasUsed" gencodec:"required"`
    58  }
    59  
    60  type receiptMarshaling struct {
    61  	PostState         hexutil.Bytes
    62  	Status            hexutil.Uint64
    63  	CumulativeGasUsed hexutil.Uint64
    64  	GasUsed           hexutil.Uint64
    65  }
    66  
    67  // receiptRLP is the consensus encoding of a receipt.
    68  type receiptRLP struct {
    69  	PostStateOrStatus []byte
    70  	CumulativeGasUsed uint64
    71  	Bloom             Bloom
    72  	Logs              []*Log
    73  }
    74  
    75  type receiptStorageRLP struct {
    76  	PostStateOrStatus []byte
    77  	CumulativeGasUsed uint64
    78  	Bloom             Bloom
    79  	TxHash            common.Hash
    80  	ContractAddress   common.Address
    81  	Logs              []*LogForStorage
    82  	GasUsed           uint64
    83  }
    84  
    85  // NewReceipt creates a barebone transaction receipt, copying the init fields.
    86  func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
    87  	r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed}
    88  	if failed {
    89  		r.Status = ReceiptStatusFailed
    90  	} else {
    91  		r.Status = ReceiptStatusSuccessful
    92  	}
    93  	return r
    94  }
    95  
    96  // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
    97  // into an RLP stream. If no post state is present, byzantium fork is assumed.
    98  func (r *Receipt) EncodeRLP(w io.Writer) error {
    99  	return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
   100  }
   101  
   102  // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
   103  // from an RLP stream.
   104  func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
   105  	var dec receiptRLP
   106  	if err := s.Decode(&dec); err != nil {
   107  		return err
   108  	}
   109  	if err := r.setStatus(dec.PostStateOrStatus); err != nil {
   110  		return err
   111  	}
   112  	r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
   113  	return nil
   114  }
   115  
   116  func (r *Receipt) setStatus(postStateOrStatus []byte) error {
   117  	switch {
   118  	case bytes.Equal(postStateOrStatus, receiptStatusSuccessfulRLP):
   119  		r.Status = ReceiptStatusSuccessful
   120  	case bytes.Equal(postStateOrStatus, receiptStatusFailedRLP):
   121  		r.Status = ReceiptStatusFailed
   122  	case len(postStateOrStatus) == len(common.Hash{}):
   123  		r.PostState = postStateOrStatus
   124  	default:
   125  		return fmt.Errorf("invalid receipt status %x", postStateOrStatus)
   126  	}
   127  	return nil
   128  }
   129  
   130  func (r *Receipt) statusEncoding() []byte {
   131  	if len(r.PostState) == 0 {
   132  		if r.Status == ReceiptStatusFailed {
   133  			return receiptStatusFailedRLP
   134  		}
   135  		return receiptStatusSuccessfulRLP
   136  	}
   137  	return r.PostState
   138  }
   139  
   140  // Size returns the approximate memory used by all internal contents. It is used
   141  // to approximate and limit the memory consumption of various caches.
   142  func (r *Receipt) Size() common.StorageSize {
   143  	size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState))
   144  
   145  	size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{}))
   146  	for _, log := range r.Logs {
   147  		size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
   148  	}
   149  	return size
   150  }
   151  
   152  // ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
   153  // entire content of a receipt, as opposed to only the consensus fields originally.
   154  type ReceiptForStorage Receipt
   155  
   156  // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
   157  // into an RLP stream.
   158  func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
   159  	enc := &receiptStorageRLP{
   160  		PostStateOrStatus: (*Receipt)(r).statusEncoding(),
   161  		CumulativeGasUsed: r.CumulativeGasUsed,
   162  		Bloom:             r.Bloom,
   163  		TxHash:            r.TxHash,
   164  		ContractAddress:   r.ContractAddress,
   165  		Logs:              make([]*LogForStorage, len(r.Logs)),
   166  		GasUsed:           r.GasUsed,
   167  	}
   168  	for i, log := range r.Logs {
   169  		enc.Logs[i] = (*LogForStorage)(log)
   170  	}
   171  	return rlp.Encode(w, enc)
   172  }
   173  
   174  // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
   175  // fields of a receipt from an RLP stream.
   176  func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
   177  	var dec receiptStorageRLP
   178  	if err := s.Decode(&dec); err != nil {
   179  		return err
   180  	}
   181  	if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil {
   182  		return err
   183  	}
   184  	// Assign the consensus fields
   185  	r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom
   186  	r.Logs = make([]*Log, len(dec.Logs))
   187  	for i, log := range dec.Logs {
   188  		r.Logs[i] = (*Log)(log)
   189  	}
   190  	// Assign the implementation fields
   191  	r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
   192  	return nil
   193  }
   194  
   195  // Receipts is a wrapper around a Receipt array to implement DerivableList.
   196  type Receipts []*Receipt
   197  
   198  // Len returns the number of receipts in this list.
   199  func (r Receipts) Len() int { return len(r) }
   200  
   201  // GetRlp returns the RLP encoding of one receipt from the list.
   202  func (r Receipts) GetRlp(i int) []byte {
   203  	bytes, err := rlp.EncodeToBytes(r[i])
   204  	if err != nil {
   205  		panic(err)
   206  	}
   207  	return bytes
   208  }