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 }