receipt.go 6.1 KB
Newer Older
F
Felix Lange 已提交
1
// Copyright 2014 The go-ethereum Authors
2
// This file is part of the go-ethereum library.
F
Felix Lange 已提交
3
//
4
// The go-ethereum library is free software: you can redistribute it and/or modify
F
Felix Lange 已提交
5 6 7 8
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
9
// The go-ethereum library is distributed in the hope that it will be useful,
F
Felix Lange 已提交
10
// but WITHOUT ANY WARRANTY; without even the implied warranty of
11
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
F
Felix Lange 已提交
12 13 14
// GNU Lesser General Public License for more details.
//
// 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/>.
F
Felix Lange 已提交
16

17
package types
O
obscuren 已提交
18 19

import (
20
	"bytes"
O
obscuren 已提交
21
	"fmt"
O
obscuren 已提交
22
	"io"
O
obscuren 已提交
23 24
	"math/big"

O
obscuren 已提交
25
	"github.com/ethereum/go-ethereum/common"
26
	"github.com/ethereum/go-ethereum/common/hexutil"
O
obscuren 已提交
27
	"github.com/ethereum/go-ethereum/rlp"
O
obscuren 已提交
28 29
)

30
//go:generate gencodec -type Receipt -field-override receiptMarshaling -out gen_receipt_json.go
31

32 33 34
var (
	receiptStatusFailed     = []byte{}
	receiptStatusSuccessful = []byte{0x01}
35 36
)

37
// Receipt represents the results of a transaction.
O
obscuren 已提交
38
type Receipt struct {
39
	// Consensus fields
40
	PostState         []byte   `json:"root"`
41
	Failed            bool     `json:"failed"`
42 43 44
	CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"`
	Bloom             Bloom    `json:"logsBloom"         gencodec:"required"`
	Logs              []*Log   `json:"logs"              gencodec:"required"`
45

46
	// Implementation fields (don't reorder!)
47 48 49
	TxHash          common.Hash    `json:"transactionHash" gencodec:"required"`
	ContractAddress common.Address `json:"contractAddress"`
	GasUsed         *big.Int       `json:"gasUsed" gencodec:"required"`
O
obscuren 已提交
50 51
}

52 53 54 55
type receiptMarshaling struct {
	PostState         hexutil.Bytes
	CumulativeGasUsed *hexutil.Big
	GasUsed           *hexutil.Big
56 57
}

58 59 60
// receiptRLP is the consensus encoding of a receipt.
type receiptRLP struct {
	PostStateOrStatus []byte
61 62 63 64 65
	CumulativeGasUsed *big.Int
	Bloom             Bloom
	Logs              []*Log
}

66 67
type receiptStorageRLP struct {
	PostStateOrStatus []byte
68 69
	CumulativeGasUsed *big.Int
	Bloom             Bloom
70 71 72 73
	TxHash            common.Hash
	ContractAddress   common.Address
	Logs              []*LogForStorage
	GasUsed           *big.Int
74 75
}

76
// NewReceipt creates a barebone transaction receipt, copying the init fields.
77 78
func NewReceipt(root []byte, failed bool, cumulativeGasUsed *big.Int) *Receipt {
	return &Receipt{PostState: common.CopyBytes(root), Failed: failed, CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
79 80
}

81
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
82
// into an RLP stream. If no post state is present, metropolis fork is assumed.
83
func (r *Receipt) EncodeRLP(w io.Writer) error {
84
	return rlp.Encode(w, &receiptRLP{r.statusEncoding(), r.CumulativeGasUsed, r.Bloom, r.Logs})
O
obscuren 已提交
85 86
}

87 88 89
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
90 91
	var dec receiptRLP
	if err := s.Decode(&dec); err != nil {
92 93
		return err
	}
94
	if err := r.setStatus(dec.PostStateOrStatus); err != nil {
95
		return err
96
	}
97 98 99
	r.CumulativeGasUsed, r.Bloom, r.Logs = dec.CumulativeGasUsed, dec.Bloom, dec.Logs
	return nil
}
100

101 102 103 104 105 106 107 108
func (r *Receipt) setStatus(postStateOrStatus []byte) error {
	switch {
	case bytes.Equal(postStateOrStatus, receiptStatusSuccessful):
		r.Failed = false
	case bytes.Equal(postStateOrStatus, receiptStatusFailed):
		r.Failed = true
	case len(postStateOrStatus) == len(common.Hash{}):
		r.PostState = postStateOrStatus
109
	default:
110
		return fmt.Errorf("invalid receipt status %x", postStateOrStatus)
111
	}
112 113 114 115 116 117 118 119 120 121 122 123
	return nil
}

func (r *Receipt) statusEncoding() []byte {
	if len(r.PostState) == 0 {
		if r.Failed {
			return receiptStatusFailed
		} else {
			return receiptStatusSuccessful
		}
	}
	return r.PostState
124 125
}

126 127
// String implements the Stringer interface.
func (r *Receipt) String() string {
128
	if r.PostState == nil {
129
		return fmt.Sprintf("receipt{failed=%t cgas=%v bloom=%x logs=%v}", r.Failed, r.CumulativeGasUsed, r.Bloom, r.Logs)
130
	}
131 132
	return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
}
O
obscuren 已提交
133

134
// ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
135
// entire content of a receipt, as opposed to only the consensus fields originally.
136 137 138 139 140
type ReceiptForStorage Receipt

// EncodeRLP implements rlp.Encoder, and flattens all content fields of a receipt
// into an RLP stream.
func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error {
141 142 143 144 145 146 147 148 149
	enc := &receiptStorageRLP{
		PostStateOrStatus: (*Receipt)(r).statusEncoding(),
		CumulativeGasUsed: r.CumulativeGasUsed,
		Bloom:             r.Bloom,
		TxHash:            r.TxHash,
		ContractAddress:   r.ContractAddress,
		Logs:              make([]*LogForStorage, len(r.Logs)),
		GasUsed:           r.GasUsed,
	}
150
	for i, log := range r.Logs {
151
		enc.Logs[i] = (*LogForStorage)(log)
152
	}
153
	return rlp.Encode(w, enc)
O
obscuren 已提交
154 155
}

156 157
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
158
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
159 160 161
	var dec receiptStorageRLP
	if err := s.Decode(&dec); err != nil {
		return err
162
	}
163
	if err := (*Receipt)(r).setStatus(dec.PostStateOrStatus); err != nil {
164 165 166
		return err
	}
	// Assign the consensus fields
167 168 169
	r.CumulativeGasUsed, r.Bloom = dec.CumulativeGasUsed, dec.Bloom
	r.Logs = make([]*Log, len(dec.Logs))
	for i, log := range dec.Logs {
F
Felix Lange 已提交
170
		r.Logs[i] = (*Log)(log)
171 172
	}
	// Assign the implementation fields
173
	r.TxHash, r.ContractAddress, r.GasUsed = dec.TxHash, dec.ContractAddress, dec.GasUsed
174
	return nil
O
obscuren 已提交
175 176
}

177
// Receipts is a wrapper around a Receipt array to implement DerivableList.
O
obscuren 已提交
178 179
type Receipts []*Receipt

180 181 182 183 184 185
// Len returns the number of receipts in this list.
func (r Receipts) Len() int { return len(r) }

// GetRlp returns the RLP encoding of one receipt from the list.
func (r Receipts) GetRlp(i int) []byte {
	bytes, err := rlp.EncodeToBytes(r[i])
O
obscuren 已提交
186
	if err != nil {
187
		panic(err)
O
obscuren 已提交
188 189
	}
	return bytes
190
}