receipt.go 6.4 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 21
	"encoding/json"
	"errors"
O
obscuren 已提交
22
	"fmt"
O
obscuren 已提交
23
	"io"
O
obscuren 已提交
24 25
	"math/big"

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

32 33 34 35 36
var (
	errMissingReceiptPostState = errors.New("missing post state root in JSON receipt")
	errMissingReceiptFields    = errors.New("missing required JSON receipt fields")
)

37
// Receipt represents the results of a transaction.
O
obscuren 已提交
38
type Receipt struct {
39
	// Consensus fields
O
obscuren 已提交
40 41
	PostState         []byte
	CumulativeGasUsed *big.Int
O
obscuren 已提交
42
	Bloom             Bloom
43 44
	Logs              vm.Logs

45
	// Implementation fields (don't reorder!)
46 47 48
	TxHash          common.Hash
	ContractAddress common.Address
	GasUsed         *big.Int
O
obscuren 已提交
49 50
}

51 52
type jsonReceipt struct {
	PostState         *common.Hash    `json:"root"`
53
	CumulativeGasUsed *hexutil.Big    `json:"cumulativeGasUsed"`
54 55 56 57
	Bloom             *Bloom          `json:"logsBloom"`
	Logs              *vm.Logs        `json:"logs"`
	TxHash            *common.Hash    `json:"transactionHash"`
	ContractAddress   *common.Address `json:"contractAddress"`
58
	GasUsed           *hexutil.Big    `json:"gasUsed"`
59 60
}

61
// NewReceipt creates a barebone transaction receipt, copying the init fields.
62 63
func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt {
	return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)}
64 65
}

66 67 68 69
// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
// into an RLP stream.
func (r *Receipt) EncodeRLP(w io.Writer) error {
	return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs})
O
obscuren 已提交
70 71
}

72 73 74 75
// DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt
// from an RLP stream.
func (r *Receipt) DecodeRLP(s *rlp.Stream) error {
	var receipt struct {
76 77 78
		PostState         []byte
		CumulativeGasUsed *big.Int
		Bloom             Bloom
79
		Logs              vm.Logs
80
	}
81
	if err := s.Decode(&receipt); err != nil {
82 83
		return err
	}
84
	r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs
85 86 87
	return nil
}

88 89 90 91 92 93
// MarshalJSON encodes receipts into the web3 RPC response block format.
func (r *Receipt) MarshalJSON() ([]byte, error) {
	root := common.BytesToHash(r.PostState)

	return json.Marshal(&jsonReceipt{
		PostState:         &root,
94
		CumulativeGasUsed: (*hexutil.Big)(r.CumulativeGasUsed),
95 96 97 98
		Bloom:             &r.Bloom,
		Logs:              &r.Logs,
		TxHash:            &r.TxHash,
		ContractAddress:   &r.ContractAddress,
99
		GasUsed:           (*hexutil.Big)(r.GasUsed),
100 101 102
	})
}

103 104 105 106 107
// UnmarshalJSON decodes the web3 RPC receipt format.
func (r *Receipt) UnmarshalJSON(input []byte) error {
	var dec jsonReceipt
	if err := json.Unmarshal(input, &dec); err != nil {
		return err
O
obscuren 已提交
108
	}
109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
	// Ensure that all fields are set. PostState is checked separately because it is a
	// recent addition to the RPC spec (as of August 2016) and older implementations might
	// not provide it. Note that ContractAddress is not checked because it can be null.
	if dec.PostState == nil {
		return errMissingReceiptPostState
	}
	if dec.CumulativeGasUsed == nil || dec.Bloom == nil ||
		dec.Logs == nil || dec.TxHash == nil || dec.GasUsed == nil {
		return errMissingReceiptFields
	}
	*r = Receipt{
		PostState:         (*dec.PostState)[:],
		CumulativeGasUsed: (*big.Int)(dec.CumulativeGasUsed),
		Bloom:             *dec.Bloom,
		Logs:              *dec.Logs,
		TxHash:            *dec.TxHash,
		GasUsed:           (*big.Int)(dec.GasUsed),
	}
	if dec.ContractAddress != nil {
		r.ContractAddress = *dec.ContractAddress
	}
	return nil
O
obscuren 已提交
131 132
}

133 134 135 136
// String implements the Stringer interface.
func (r *Receipt) String() string {
	return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
}
O
obscuren 已提交
137

138
// ReceiptForStorage is a wrapper around a Receipt that flattens and parses the
139
// entire content of a receipt, as opposed to only the consensus fields originally.
140 141 142 143 144 145 146 147 148 149
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 {
	logs := make([]*vm.LogForStorage, len(r.Logs))
	for i, log := range r.Logs {
		logs[i] = (*vm.LogForStorage)(log)
	}
	return rlp.Encode(w, []interface{}{r.PostState, r.CumulativeGasUsed, r.Bloom, r.TxHash, r.ContractAddress, logs, r.GasUsed})
O
obscuren 已提交
150 151
}

152 153
// DecodeRLP implements rlp.Decoder, and loads both consensus and implementation
// fields of a receipt from an RLP stream.
154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error {
	var receipt struct {
		PostState         []byte
		CumulativeGasUsed *big.Int
		Bloom             Bloom
		TxHash            common.Hash
		ContractAddress   common.Address
		Logs              []*vm.LogForStorage
		GasUsed           *big.Int
	}
	if err := s.Decode(&receipt); err != nil {
		return err
	}
	// Assign the consensus fields
	r.PostState, r.CumulativeGasUsed, r.Bloom = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom
	r.Logs = make(vm.Logs, len(receipt.Logs))
	for i, log := range receipt.Logs {
		r.Logs[i] = (*vm.Log)(log)
	}
	// Assign the implementation fields
	r.TxHash, r.ContractAddress, r.GasUsed = receipt.TxHash, receipt.ContractAddress, receipt.GasUsed

	return nil
O
obscuren 已提交
177 178
}

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

182 183 184 185 186 187
// 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 已提交
188
	if err != nil {
189
		panic(err)
O
obscuren 已提交
190 191
	}
	return bytes
192
}