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 }