From 7221cb1434eebce879a0bd1bf3867cd8a24bcc99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?P=C3=A9ter=20Szil=C3=A1gyi?= Date: Mon, 15 Apr 2019 12:36:27 +0300 Subject: core, eth, les, light: scope receipt functionality a bit cleaner --- core/types/receipt.go | 72 +++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 56 insertions(+), 16 deletions(-) (limited to 'core/types/receipt.go') diff --git a/core/types/receipt.go b/core/types/receipt.go index dc8177079..578daba3f 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -18,6 +18,7 @@ package types import ( "bytes" + "errors" "fmt" "io" "math/big" @@ -25,6 +26,8 @@ import ( "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/crypto" + "github.com/ethereum/go-ethereum/params" "github.com/ethereum/go-ethereum/rlp" ) @@ -99,8 +102,8 @@ type v4StoredReceiptRLP struct { GasUsed uint64 } -// legacyStoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields. -type legacyStoredReceiptRLP struct { +// v3StoredReceiptRLP is the original storage encoding of a receipt including some unnecessary fields. +type v3StoredReceiptRLP struct { PostStateOrStatus []byte CumulativeGasUsed uint64 Bloom Bloom @@ -198,20 +201,21 @@ func (r *ReceiptForStorage) EncodeRLP(w io.Writer) error { // DecodeRLP implements rlp.Decoder, and loads both consensus and implementation // fields of a receipt from an RLP stream. func (r *ReceiptForStorage) DecodeRLP(s *rlp.Stream) error { + // Retrieve the entire receipt blob as we need to try multiple decoders blob, err := s.Raw() if err != nil { return err } - + // Try decoding from the newest format for future proofness, then the older one + // for old nodes that just upgraded. V4 was an intermediate unreleased format so + // we do need to decode it, but it's not common (try last). if err := decodeStoredReceiptRLP(r, blob); err == nil { return nil } - - if err := decodeV4StoredReceiptRLP(r, blob); err == nil { + if err := decodeV3StoredReceiptRLP(r, blob); err == nil { return nil } - - return decodeLegacyStoredReceiptRLP(r, blob) + return decodeV4StoredReceiptRLP(r, blob) } func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { @@ -219,11 +223,9 @@ func decodeStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { if err := rlp.DecodeBytes(blob, &stored); err != nil { return err } - if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { return err } - r.CumulativeGasUsed = stored.CumulativeGasUsed r.Logs = make([]*Log, len(stored.Logs)) for i, log := range stored.Logs { @@ -239,11 +241,9 @@ func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { if err := rlp.DecodeBytes(blob, &stored); err != nil { return err } - if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { return err } - r.CumulativeGasUsed = stored.CumulativeGasUsed r.TxHash = stored.TxHash r.ContractAddress = stored.ContractAddress @@ -257,16 +257,14 @@ func decodeV4StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { return nil } -func decodeLegacyStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { - var stored legacyStoredReceiptRLP +func decodeV3StoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { + var stored v3StoredReceiptRLP if err := rlp.DecodeBytes(blob, &stored); err != nil { return err } - if err := (*Receipt)(r).setStatus(stored.PostStateOrStatus); err != nil { return err } - r.CumulativeGasUsed = stored.GasUsed r.Bloom = stored.Bloom r.TxHash = stored.TxHash @@ -276,7 +274,6 @@ func decodeLegacyStoredReceiptRLP(r *ReceiptForStorage, blob []byte) error { for i, log := range stored.Logs { r.Logs[i] = (*Log)(log) } - return nil } @@ -294,3 +291,46 @@ func (r Receipts) GetRlp(i int) []byte { } return bytes } + +// DeriveFields fills the receipts with their computed fields based on consensus +// data and contextual infos like containing block and transactions. +func (r Receipts) DeriveFields(config *params.ChainConfig, hash common.Hash, number uint64, txs Transactions) error { + signer := MakeSigner(config, new(big.Int).SetUint64(number)) + + logIndex := uint(0) + if len(txs) != len(r) { + return errors.New("transaction and receipt count mismatch") + } + for i := 0; i < len(r); i++ { + // The transaction hash can be retrieved from the transaction itself + r[i].TxHash = txs[i].Hash() + + // block location fields + r[i].BlockHash = hash + r[i].BlockNumber = new(big.Int).SetUint64(number) + r[i].TransactionIndex = uint(i) + + // The contract address can be derived from the transaction itself + if txs[i].To() == nil { + // Deriving the signer is expensive, only do if it's actually needed + from, _ := Sender(signer, txs[i]) + r[i].ContractAddress = crypto.CreateAddress(from, txs[i].Nonce()) + } + // The used gas can be calculated based on previous r + if i == 0 { + r[i].GasUsed = r[i].CumulativeGasUsed + } else { + r[i].GasUsed = r[i].CumulativeGasUsed - r[i-1].CumulativeGasUsed + } + // The derived log fields can simply be set from the block and transaction + for j := 0; j < len(r[i].Logs); j++ { + r[i].Logs[j].BlockNumber = number + r[i].Logs[j].BlockHash = hash + r[i].Logs[j].TxHash = r[i].TxHash + r[i].Logs[j].TxIndex = uint(i) + r[i].Logs[j].Index = logIndex + logIndex++ + } + } + return nil +} -- cgit v1.2.3