github.com/Inphi/go-ethereum@v1.9.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  	"errors"
    22  	"fmt"
    23  	"io"
    24  	"math/big"
    25  	"unsafe"
    26  
    27  	"github.com/ethereum/go-ethereum/common"
    28  	"github.com/ethereum/go-ethereum/common/hexutil"
    29  	"github.com/ethereum/go-ethereum/crypto"
    30  	"github.com/ethereum/go-ethereum/params"
    31  	"github.com/ethereum/go-ethereum/rlp"
    32  )
    33  
    34  //go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
    35  
    36  var (
    37  	receiptStatusFailedRLP     = []byte{}
    38  	receiptStatusSuccessfulRLP = []byte{0x01}
    39  )
    40  
    41  const (
    42  	// ReceiptStatusFailed is the status code of a transaction if execution failed.
    43  	ReceiptStatusFailed = uint64(0)
    44  
    45  	// ReceiptStatusSuccessful is the status code of a transaction if execution succeeded.
    46  	ReceiptStatusSuccessful = uint64(1)
    47  )
    48  
    49  // Receipt represents the results of a transaction.
    50  type Receipt struct {
    51  	// Consensus fields: These fields are defined by the Yellow Paper
    52  	PostState         []byte `json:"root"`
    53  	Status            uint64 `json:"status"`
    54  	CumulativeGasUsed uint64 `json:"cumulativeGasUsed" gencodec:"required"`
    55  	Bloom             Bloom  `json:"logsBloom"         gencodec:"required"`
    56  	Logs              []*Log `json:"logs"              gencodec:"required"`
    57  
    58  	// Implementation fields: These fields are added by geth when processing a transaction.
    59  	// They are stored in the chain database.
    60  	TxHash          common.Hash    `json:"transactionHash" gencodec:"required"`
    61  	ContractAddress common.Address `json:"contractAddress"`
    62  	GasUsed         uint64         `json:"gasUsed" gencodec:"required"`
    63  
    64  	// Inclusion information: These fields provide information about the inclusion of the
    65  	// transaction corresponding to this receipt.
    66  	BlockHash        common.Hash `json:"blockHash,omitempty"`
    67  	BlockNumber      *big.Int    `json:"blockNumber,omitempty"`
    68  	TransactionIndex uint        `json:"transactionIndex"`
    69  }
    70  
    71  type receiptMarshaling struct {
    72  	PostState         hexutil.Bytes
    73  	Status            hexutil.Uint64
    74  	CumulativeGasUsed hexutil.Uint64
    75  	GasUsed           hexutil.Uint64
    76  	BlockNumber       *hexutil.Big
    77  	TransactionIndex  hexutil.Uint
    78  }
    79  
    80  // receiptRLP is the consensus encoding of a receipt.
    81  type receiptRLP struct {
    82  	PostStateOrStatus []byte
    83  	CumulativeGasUsed uint64
    84  	Bloom             Bloom
    85  	Logs              []*Log
    86  }
    87  
    88  // storedReceiptRLP is the storage encoding of a receipt.
    89  type storedReceiptRLP struct {
    90  	PostStateOrStatus []byte
    91  	CumulativeGasUsed uint64
    92  	Logs              []*LogForStorage
    93  }
    94  
    95  // v4StoredReceiptRLP is the storage encoding of a receipt used in database version 4.
    96  type v4StoredReceiptRLP struct {
    97  	PostStateOrStatus []byte
    98  	CumulativeGasUsed uint64
    99  	TxHash            common.Hash
   100  	ContractAddress   common.Address
   101  	Logs              []*LogForStorage
   102  	GasUsed           uint64
   103  }
   104  
   105  // v3StoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields.
   106  type v3StoredReceiptRLP struct {
   107  	PostStateOrStatus []byte
   108  	CumulativeGasUsed uint64
   109  	Bloom             Bloom
   110  	TxHash            common.Hash
   111  	ContractAddress   common.Address
   112  	Logs              []*LogForStorage
   113  	GasUsed           uint64
   114  }
   115  
   116  // NewReceipt creates a barebone transaction receipt, copying the init fields.
   117  func NewReceipt(root []byte, failed bool, cumulativeGasUsed uint64) *Receipt {
   118  	r := &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: cumulativeGasUsed}
   119  	if failed {
   120  		r.Status = ReceiptStatusFailed
   121  	} else {
   122  		r.Status = ReceiptStatusSuccessful
   123  	}
   124  	return r
   125  }
   126  
   127  // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
   128  // into an RLP stream. If no post state is present, byzantium fork is assumed.
   129  func (r *Receipt) EncodeRLP(w io.Writer) error {
   130  	return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
   131  }
   132  
   133  // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
   134  // from an RLP stream.
   135  func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
   136  	var dec receiptRLP
   137  	if err := s.Decode(&dec); err != nil {
   138  		return err
   139  	}
   140  	if err := r.setStatus(dec.PostStateOrStatus); err != nil {
   141  		return err
   142  	}
   143  	r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
   144  	return nil
   145  }
   146  
   147  func (r *Receipt) setStatus(postStateOrStatus []byte) error {
   148  	switch {
   149  	case bytes.Equal(postStateOrStatus, receiptStatusSuccessfulRLP):
   150  		r.Status = ReceiptStatusSuccessful
   151  	case bytes.Equal(postStateOrStatus, receiptStatusFailedRLP):
   152  		r.Status = ReceiptStatusFailed
   153  	case len(postStateOrStatus) == len(common.Hash{}):
   154  		r.PostState = postStateOrStatus
   155  	default:
   156  		return fmt.Errorf("invalid receipt status %x", postStateOrStatus)
   157  	}
   158  	return nil
   159  }
   160  
   161  func (r *Receipt) statusEncoding() []byte {
   162  	if len(r.PostState) == 0 {
   163  		if r.Status == ReceiptStatusFailed {
   164  			return receiptStatusFailedRLP
   165  		}
   166  		return receiptStatusSuccessfulRLP
   167  	}
   168  	return r.PostState
   169  }
   170  
   171  // Size returns the approximate memory used by all internal contents. It is used
   172  // to approximate and limit the memory consumption of various caches.
   173  func (r *Receipt) Size() common.StorageSize {
   174  	size := common.StorageSize(unsafe.Sizeof(*r)) + common.StorageSize(len(r.PostState))
   175  
   176  	size += common.StorageSize(len(r.Logs)) * common.StorageSize(unsafe.Sizeof(Log{}))
   177  	for _, log := range r.Logs {
   178  		size += common.StorageSize(len(log.Topics)*common.HashLength + len(log.Data))
   179  	}
   180  	return size
   181  }
   182  
   183  // ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
   184  // entire content of a receipt, as opposed to only the consensus fields originally.
   185  type ReceiptForStorage Receipt
   186  
   187  // EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
   188  // into an RLP stream.
   189  func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
   190  	enc := &storedReceiptRLP{
   191  		PostStateOrStatus: (*Receipt)(r).statusEncoding(),
   192  		CumulativeGasUsed: r.CumulativeGasUsed,
   193  		Logs:              make([]*LogForStorage, len(r.Logs)),
   194  	}
   195  	for i, log := range r.Logs {
   196  		enc.Logs[i] = (*LogForStorage)(log)
   197  	}
   198  	return rlp.Encode(w, enc)
   199  }
   200  
   201  // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
   202  // fields of a receipt from an RLP stream.
   203  func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
   204  	// Retrieve the entire receipt blob as we need to try multiple decoders
   205  	blob, err := s.Raw()
   206  	if err != nil {
   207  		return err
   208  	}
   209  	// Try decoding from the newest format for future proofness, then the older one
   210  	// for old nodes that just upgraded. V4 was an intermediate unreleased format so
   211  	// we do need to decode it, but it's not common (try last).
   212  	if err := decodeStoredReceiptRLP(r, blob); err == nil {
   213  		return nil
   214  	}
   215  	if err := decodeV3StoredReceiptRLP(r, blob); err == nil {
   216  		return nil
   217  	}
   218  	return decodeV4StoredReceiptRLP(r, blob)
   219  }
   220  
   221  func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
   222  	var stored storedReceiptRLP
   223  	if err := rlp.DecodeBytes(blob, &stored); err != nil {
   224  		return err
   225  	}
   226  	if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
   227  		return err
   228  	}
   229  	r.CumulativeGasUsed = stored.CumulativeGasUsed
   230  	r.Logs = make([]*Log, len(stored.Logs))
   231  	for i, log := range stored.Logs {
   232  		r.Logs[i] = (*Log)(log)
   233  	}
   234  	r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
   235  
   236  	return nil
   237  }
   238  
   239  func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
   240  	var stored v4StoredReceiptRLP
   241  	if err := rlp.DecodeBytes(blob, &stored); err != nil {
   242  		return err
   243  	}
   244  	if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
   245  		return err
   246  	}
   247  	r.CumulativeGasUsed = stored.CumulativeGasUsed
   248  	r.TxHash = stored.TxHash
   249  	r.ContractAddress = stored.ContractAddress
   250  	r.GasUsed = stored.GasUsed
   251  	r.Logs = make([]*Log, len(stored.Logs))
   252  	for i, log := range stored.Logs {
   253  		r.Logs[i] = (*Log)(log)
   254  	}
   255  	r.Bloom = CreateBloom(Receipts{(*Receipt)(r)})
   256  
   257  	return nil
   258  }
   259  
   260  func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error {
   261  	var stored v3StoredReceiptRLP
   262  	if err := rlp.DecodeBytes(blob, &stored); err != nil {
   263  		return err
   264  	}
   265  	if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil {
   266  		return err
   267  	}
   268  	r.CumulativeGasUsed = stored.CumulativeGasUsed
   269  	r.Bloom = stored.Bloom
   270  	r.TxHash = stored.TxHash
   271  	r.ContractAddress = stored.ContractAddress
   272  	r.GasUsed = stored.GasUsed
   273  	r.Logs = make([]*Log, len(stored.Logs))
   274  	for i, log := range stored.Logs {
   275  		r.Logs[i] = (*Log)(log)
   276  	}
   277  	return nil
   278  }
   279  
   280  // Receipts is a wrapper around a Receipt array to implement DerivableList.
   281  type Receipts []*Receipt
   282  
   283  // Len returns the number of receipts in this list.
   284  func (r Receipts) Len() int { return len(r) }
   285  
   286  // GetRlp returns the RLP encoding of one receipt from the list.
   287  func (r Receipts) GetRlp(i int) []byte {
   288  	bytes, err := rlp.EncodeToBytes(r[i])
   289  	if err != nil {
   290  		panic(err)
   291  	}
   292  	return bytes
   293  }
   294  
   295  // DeriveFields fills the receipts with their computed fields based on consensus
   296  // data and contextual infos like containing block and transactions.
   297  func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error {
   298  	signer := MakeSigner(config, new(big.Int).SetUint64(number))
   299  
   300  	logIndex := uint(0)
   301  	if len(txs) != len(r) {
   302  		return errors.New("transaction and receipt count mismatch")
   303  	}
   304  	for i := 0; i < len(r); i++ {
   305  		// The transaction hash can be retrieved from the transaction itself
   306  		r[i].TxHash = txs[i].Hash()
   307  
   308  		// block location fields
   309  		r[i].BlockHash = hash
   310  		r[i].BlockNumber = new(big.Int).SetUint64(number)
   311  		r[i].TransactionIndex = uint(i)
   312  
   313  		// The contract address can be derived from the transaction itself
   314  		if txs[i].To() == nil {
   315  			// Deriving the signer is expensive, only do if it's actually needed
   316  			from, _ := Sender(signer, txs[i])
   317  			r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce())
   318  		}
   319  		// The used gas can be calculated based on previous r
   320  		if i == 0 {
   321  			r[i].GasUsed = r[i].CumulativeGasUsed
   322  		} else {
   323  			r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed
   324  		}
   325  		// The derived log fields can simply be set from the block and transaction
   326  		for j := 0; j < len(r[i].Logs); j++ {
   327  			r[i].Logs[j].BlockNumber = number
   328  			r[i].Logs[j].BlockHash = hash
   329  			r[i].Logs[j].TxHash = r[i].TxHash
   330  			r[i].Logs[j].TxIndex = uint(i)
   331  			r[i].Logs[j].Index = logIndex
   332  			logIndex++
   333  		}
   334  	}
   335  	return nil
   336  }