github.com/iotexproject/iotex-core@v1.14.1-rc1/action/receipt.go (about)

     1  // Copyright (c) 2020 IoTeX Foundation
     2  // This source code is provided 'as is' and no warranties are given as to title or non-infringement, merchantability
     3  // or fitness for purpose and, to the extent permitted by law, all liability for your use of the code is disclaimed.
     4  // This source code is governed by Apache License 2.0 that can be found in the LICENSE file.
     5  
     6  package action
     7  
     8  import (
     9  	"math/big"
    10  
    11  	"google.golang.org/protobuf/proto"
    12  
    13  	"github.com/iotexproject/go-pkgs/hash"
    14  	"github.com/iotexproject/iotex-proto/golang/iotextypes"
    15  
    16  	"github.com/iotexproject/iotex-core/pkg/log"
    17  )
    18  
    19  type (
    20  	// Topics are data items of a transaction, such as send/recipient address
    21  	Topics []hash.Hash256
    22  
    23  	// Receipt represents the result of a contract
    24  	Receipt struct {
    25  		Status             uint64
    26  		BlockHeight        uint64
    27  		ActionHash         hash.Hash256
    28  		GasConsumed        uint64
    29  		ContractAddress    string
    30  		TxIndex            uint32
    31  		logs               []*Log
    32  		transactionLogs    []*TransactionLog
    33  		executionRevertMsg string
    34  	}
    35  
    36  	// Log stores an evm contract event
    37  	Log struct {
    38  		Address            string
    39  		Topics             Topics
    40  		Data               []byte
    41  		BlockHeight        uint64
    42  		ActionHash         hash.Hash256
    43  		Index, TxIndex     uint32
    44  		NotFixTopicCopyBug bool
    45  	}
    46  
    47  	// TransactionLog stores a transaction event
    48  	TransactionLog struct {
    49  		Type      iotextypes.TransactionLogType
    50  		Amount    *big.Int
    51  		Sender    string
    52  		Recipient string
    53  	}
    54  )
    55  
    56  // ConvertToReceiptPb converts a Receipt to protobuf's Receipt
    57  func (receipt *Receipt) ConvertToReceiptPb() *iotextypes.Receipt {
    58  	r := &iotextypes.Receipt{}
    59  	r.Status = receipt.Status
    60  	r.BlkHeight = receipt.BlockHeight
    61  	r.ActHash = receipt.ActionHash[:]
    62  	r.GasConsumed = receipt.GasConsumed
    63  	r.ContractAddress = receipt.ContractAddress
    64  	r.TxIndex = receipt.TxIndex
    65  	r.Logs = []*iotextypes.Log{}
    66  	for _, l := range receipt.logs {
    67  		r.Logs = append(r.Logs, l.ConvertToLogPb())
    68  	}
    69  	if receipt.executionRevertMsg != "" {
    70  		r.ExecutionRevertMsg = receipt.executionRevertMsg
    71  	}
    72  	return r
    73  }
    74  
    75  // ConvertFromReceiptPb converts a protobuf's Receipt to Receipt
    76  func (receipt *Receipt) ConvertFromReceiptPb(pbReceipt *iotextypes.Receipt) {
    77  	receipt.Status = pbReceipt.GetStatus()
    78  	receipt.BlockHeight = pbReceipt.GetBlkHeight()
    79  	copy(receipt.ActionHash[:], pbReceipt.GetActHash())
    80  	receipt.GasConsumed = pbReceipt.GetGasConsumed()
    81  	receipt.ContractAddress = pbReceipt.GetContractAddress()
    82  	receipt.TxIndex = pbReceipt.GetTxIndex()
    83  	logs := pbReceipt.GetLogs()
    84  	receipt.logs = make([]*Log, len(logs))
    85  	for i, log := range logs {
    86  		receipt.logs[i] = &Log{}
    87  		receipt.logs[i].ConvertFromLogPb(log)
    88  	}
    89  	receipt.executionRevertMsg = pbReceipt.GetExecutionRevertMsg()
    90  }
    91  
    92  // Serialize returns a serialized byte stream for the Receipt
    93  func (receipt *Receipt) Serialize() ([]byte, error) {
    94  	return proto.Marshal(receipt.ConvertToReceiptPb())
    95  }
    96  
    97  // Deserialize parse the byte stream into Receipt
    98  func (receipt *Receipt) Deserialize(buf []byte) error {
    99  	pbReceipt := &iotextypes.Receipt{}
   100  	if err := proto.Unmarshal(buf, pbReceipt); err != nil {
   101  		return err
   102  	}
   103  	receipt.ConvertFromReceiptPb(pbReceipt)
   104  	return nil
   105  }
   106  
   107  // Hash returns the hash of receipt
   108  func (receipt *Receipt) Hash() hash.Hash256 {
   109  	data, err := receipt.Serialize()
   110  	if err != nil {
   111  		log.L().Panic("Error when serializing a receipt")
   112  	}
   113  	return hash.Hash256b(data)
   114  }
   115  
   116  // Logs returns the list of logs stored in receipt
   117  func (receipt *Receipt) Logs() []*Log {
   118  	return receipt.logs
   119  }
   120  
   121  // AddLogs add log to receipt and filter out nil log.
   122  func (receipt *Receipt) AddLogs(logs ...*Log) *Receipt {
   123  	for _, l := range logs {
   124  		if l != nil {
   125  			receipt.logs = append(receipt.logs, l)
   126  		}
   127  	}
   128  	return receipt
   129  }
   130  
   131  // TransactionLogs returns the list of transaction logs stored in receipt
   132  func (receipt *Receipt) TransactionLogs() []*TransactionLog {
   133  	return receipt.transactionLogs
   134  }
   135  
   136  // AddTransactionLogs add transaction logs to receipt and filter out nil log.
   137  func (receipt *Receipt) AddTransactionLogs(logs ...*TransactionLog) *Receipt {
   138  	for _, l := range logs {
   139  		if l != nil {
   140  			receipt.transactionLogs = append(receipt.transactionLogs, l)
   141  		}
   142  	}
   143  	return receipt
   144  }
   145  
   146  // ExecutionRevertMsg returns the list of execution revert error logs stored in receipt.
   147  func (receipt *Receipt) ExecutionRevertMsg() string {
   148  	return receipt.executionRevertMsg
   149  }
   150  
   151  // SetExecutionRevertMsg sets executionerrorlogs to receipt.
   152  func (receipt *Receipt) SetExecutionRevertMsg(revertReason string) *Receipt {
   153  	if receipt.executionRevertMsg == "" && revertReason != "" {
   154  		receipt.executionRevertMsg = revertReason
   155  	}
   156  	return receipt
   157  }
   158  
   159  // UpdateIndex updates the index of receipt and logs, and returns the next log index
   160  func (receipt *Receipt) UpdateIndex(txIndex, logIndex uint32) uint32 {
   161  	receipt.TxIndex = txIndex
   162  	for _, l := range receipt.logs {
   163  		l.TxIndex = txIndex
   164  		l.Index = logIndex
   165  		logIndex++
   166  	}
   167  	return logIndex
   168  }
   169  
   170  // ConvertToLogPb converts a Log to protobuf's Log
   171  func (log *Log) ConvertToLogPb() *iotextypes.Log {
   172  	l := &iotextypes.Log{}
   173  	l.ContractAddress = log.Address
   174  	l.Topics = [][]byte{}
   175  	for _, topic := range log.Topics {
   176  		if log.NotFixTopicCopyBug {
   177  			l.Topics = append(l.Topics, topic[:])
   178  		} else {
   179  			data := make([]byte, len(topic))
   180  			copy(data, topic[:])
   181  			l.Topics = append(l.Topics, data)
   182  		}
   183  	}
   184  	l.Data = log.Data
   185  	l.BlkHeight = log.BlockHeight
   186  	l.ActHash = log.ActionHash[:]
   187  	l.Index = log.Index
   188  	l.TxIndex = log.TxIndex
   189  	return l
   190  }
   191  
   192  // ConvertFromLogPb converts a protobuf's LogPb to Log
   193  func (log *Log) ConvertFromLogPb(pbLog *iotextypes.Log) {
   194  	log.Address = pbLog.GetContractAddress()
   195  	pbLogs := pbLog.GetTopics()
   196  	log.Topics = make([]hash.Hash256, len(pbLogs))
   197  	for i, topic := range pbLogs {
   198  		copy(log.Topics[i][:], topic)
   199  	}
   200  	log.Data = pbLog.GetData()
   201  	log.BlockHeight = pbLog.GetBlkHeight()
   202  	copy(log.ActionHash[:], pbLog.GetActHash())
   203  	log.Index = pbLog.GetIndex()
   204  	log.TxIndex = pbLog.GetTxIndex()
   205  }
   206  
   207  // Serialize returns a serialized byte stream for the Log
   208  func (log *Log) Serialize() ([]byte, error) {
   209  	return proto.Marshal(log.ConvertToLogPb())
   210  }
   211  
   212  // Deserialize parse the byte stream into Log
   213  func (log *Log) Deserialize(buf []byte) error {
   214  	pbLog := &iotextypes.Log{}
   215  	if err := proto.Unmarshal(buf, pbLog); err != nil {
   216  		return err
   217  	}
   218  	log.ConvertFromLogPb(pbLog)
   219  	return nil
   220  }