github.com/beyonderyue/gochain@v2.2.26+incompatible/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/gochain-io/gochain/common"
    26  	"github.com/gochain-io/gochain/common/hexutil"
    27  	"github.com/gochain-io/gochain/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              LogsForStorage
    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  // ReceiptsForStorage RLP encodes as []*ReceiptForStorage.
   153  type ReceiptsForStorage []*Receipt
   154  
   155  func (r ReceiptsForStorage) EncodeRLPElem(i int, w io.Writer) error {
   156  	return rlp.Encode(w, (*ReceiptForStorage)(r[i]))
   157  }
   158  
   159  func (r *ReceiptsForStorage) DecodeRLPElem(s *rlp.Stream) error {
   160  	var rec ReceiptForStorage
   161  	if err := s.Decode(&rec); err != nil {
   162  		return err
   163  	}
   164  	*r = append(*r, (*Receipt)(&rec))
   165  	return nil
   166  }
   167  
   168  // ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
   169  // entire content of a receipt, as opposed to only the consensus fields originally.
   170  type ReceiptForStorage Receipt
   171  
   172  // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
   173  // into an RLP stream.
   174  func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
   175  	enc := &receiptStorageRLP{
   176  		PostStateOrStatus: (*Receipt)(r).statusEncoding(),
   177  		CumulativeGasUsed: r.CumulativeGasUsed,
   178  		Bloom:             r.Bloom,
   179  		TxHash:            r.TxHash,
   180  		ContractAddress:   r.ContractAddress,
   181  		Logs:              LogsForStorage(r.Logs),
   182  		GasUsed:           r.GasUsed,
   183  	}
   184  	return rlp.Encode(w, enc)
   185  }
   186  
   187  // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
   188  // fields of a receipt from an RLP stream.
   189  func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
   190  	var dec receiptStorageRLP
   191  	if err := s.Decode(&dec); err != nil {
   192  		return err
   193  	}
   194  	if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil {
   195  		return err
   196  	}
   197  	// Assign the consensus fields
   198  	r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom
   199  	r.Logs = []*Log(dec.Logs)
   200  	// Assign the implementation fields
   201  	r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
   202  	return nil
   203  }
   204  
   205  // Receipts is a wrapper around a Receipt array to implement DerivableList.
   206  type Receipts []*Receipt
   207  
   208  // Len returns the number of receipts in this list.
   209  func (r Receipts) Len() int { return len(r) }
   210  
   211  // GetRlp returns the RLP encoding of one receipt from the list.
   212  func (r Receipts) GetRlp(i int) []byte {
   213  	bytes, err := rlp.EncodeToBytes(r[i])
   214  	if err != nil {
   215  		panic(err)
   216  	}
   217  	return bytes
   218  }