github.com/waltonchain/waltonchain_gwtc_src@v1.1.4-0.20201225072101-8a298c95a819/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-wtc 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-wtc 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  	"math/big"
    24  
    25  	"github.com/wtc/go-wtc/common"
    26  	"github.com/wtc/go-wtc/common/hexutil"
    27  	"github.com/wtc/go-wtc/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 = uint(0)
    40  
    41  	// ReceiptStatusSuccessful is the status code of a transaction if execution succeeded.
    42  	ReceiptStatusSuccessful = uint(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            uint     `json:"status"`
    50  	CumulativeGasUsed *big.Int `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         *big.Int       `json:"gasUsed" gencodec:"required"`
    58  }
    59  
    60  type receiptMarshaling struct {
    61  	PostState         hexutil.Bytes
    62  	Status            hexutil.Uint
    63  	CumulativeGasUsed *hexutil.Big
    64  	GasUsed           *hexutil.Big
    65  }
    66  
    67  // receiptRLP is the consensus encoding of a receipt.
    68  type receiptRLP struct {
    69  	PostStateOrStatus []byte
    70  	CumulativeGasUsed *big.Int
    71  	Bloom             Bloom
    72  	Logs              []*Log
    73  }
    74  
    75  type receiptStorageRLP struct {
    76  	PostStateOrStatus []byte
    77  	CumulativeGasUsed *big.Int
    78  	Bloom             Bloom
    79  	TxHash            common.Hash
    80  	ContractAddress   common.Address
    81  	Logs              []*LogForStorage
    82  	GasUsed           *big.Int
    83  }
    84  
    85  // NewReceipt creates a barebone transaction receipt, copying the init fields.
    86  func NewReceipt(root []byte, failed bool, cumulativeGasUsed *big.Int) *Receipt {
    87  	r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(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  // String implements the Stringer interface.
   141  func (r *Receipt) String() string {
   142  	if len(r.PostState) == 0 {
   143  		return fmt.Sprintf("receipt{status=%d cgas=%v bloom=%x logs=%v}", r.Status, r.CumulativeGasUsed, r.Bloom, r.Logs)
   144  	}
   145  	return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
   146  }
   147  
   148  // ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
   149  // entire content of a receipt, as opposed to only the consensus fields originally.
   150  type ReceiptForStorage Receipt
   151  
   152  // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
   153  // into an RLP stream.
   154  func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
   155  	enc := &receiptStorageRLP{
   156  		PostStateOrStatus: (*Receipt)(r).statusEncoding(),
   157  		CumulativeGasUsed: r.CumulativeGasUsed,
   158  		Bloom:             r.Bloom,
   159  		TxHash:            r.TxHash,
   160  		ContractAddress:   r.ContractAddress,
   161  		Logs:              make([]*LogForStorage, len(r.Logs)),
   162  		GasUsed:           r.GasUsed,
   163  	}
   164  	for i, log := range r.Logs {
   165  		enc.Logs[i] = (*LogForStorage)(log)
   166  	}
   167  	return rlp.Encode(w, enc)
   168  }
   169  
   170  // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
   171  // fields of a receipt from an RLP stream.
   172  func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
   173  	var dec receiptStorageRLP
   174  	if err := s.Decode(&dec); err != nil {
   175  		return err
   176  	}
   177  	if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil {
   178  		return err
   179  	}
   180  	// Assign the consensus fields
   181  	r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom
   182  	r.Logs = make([]*Log, len(dec.Logs))
   183  	for i, log := range dec.Logs {
   184  		r.Logs[i] = (*Log)(log)
   185  	}
   186  	// Assign the implementation fields
   187  	r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
   188  	return nil
   189  }
   190  
   191  // Receipts is a wrapper around a Receipt array to implement DerivableList.
   192  type Receipts []*Receipt
   193  
   194  // Len returns the number of receipts in this list.
   195  func (r Receipts) Len() int { return len(r) }
   196  
   197  // GetRlp returns the RLP encoding of one receipt from the list.
   198  func (r Receipts) GetRlp(i int) []byte {
   199  	bytes, err := rlp.EncodeToBytes(r[i])
   200  	if err != nil {
   201  		panic(err)
   202  	}
   203  	return bytes
   204  }