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 }