diff --git a/core/state_processor.go b/core/state_processor.go index 90f5a4f60c..158a9fa2df 100644 --- a/core/state_processor.go +++ b/core/state_processor.go @@ -105,10 +105,15 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common // Update the state with pending changes usedGas.Add(usedGas, gas) + var root []byte + if config.IsMetropolis(header.Number) { + statedb.Finalise() + } else { + root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes() + } // Create a new receipt for the transaction, storing the intermediate root and gas used by the tx // based on the eip phase, we're passing wether the root touch-delete accounts. - root := statedb.IntermediateRoot(config.IsEIP158(header.Number)) - receipt := types.NewReceipt(root.Bytes(), usedGas) + receipt := types.NewReceipt(root, usedGas) receipt.TxHash = tx.Hash() receipt.GasUsed = new(big.Int).Set(gas) // if the transaction created a contract, store the creation address in the receipt. diff --git a/core/types/gen_receipt_json.go b/core/types/gen_receipt_json.go index edbd64ba4e..eb2e5d42b4 100644 --- a/core/types/gen_receipt_json.go +++ b/core/types/gen_receipt_json.go @@ -13,7 +13,7 @@ import ( func (r Receipt) MarshalJSON() ([]byte, error) { type Receipt struct { - PostState hexutil.Bytes `json:"root" gencodec:"required"` + PostState hexutil.Bytes `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -34,7 +34,7 @@ func (r Receipt) MarshalJSON() ([]byte, error) { func (r *Receipt) UnmarshalJSON(input []byte) error { type Receipt struct { - PostState hexutil.Bytes `json:"root" gencodec:"required"` + PostState hexutil.Bytes `json:"root"` CumulativeGasUsed *hexutil.Big `json:"cumulativeGasUsed" gencodec:"required"` Bloom *Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -46,10 +46,9 @@ func (r *Receipt) UnmarshalJSON(input []byte) error { if err := json.Unmarshal(input, &dec); err != nil { return err } - if dec.PostState == nil { - return errors.New("missing required field 'root' for Receipt") + if dec.PostState != nil { + r.PostState = dec.PostState } - r.PostState = dec.PostState if dec.CumulativeGasUsed == nil { return errors.New("missing required field 'cumulativeGasUsed' for Receipt") } diff --git a/core/types/receipt.go b/core/types/receipt.go index ef6f6a2bb2..46d2530bbc 100644 --- a/core/types/receipt.go +++ b/core/types/receipt.go @@ -31,7 +31,7 @@ import ( // Receipt represents the results of a transaction. type Receipt struct { // Consensus fields - PostState []byte `json:"root" gencodec:"required"` + PostState []byte `json:"root"` CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` Bloom Bloom `json:"logsBloom" gencodec:"required"` Logs []*Log `json:"logs" gencodec:"required"` @@ -48,6 +48,19 @@ type receiptMarshaling struct { GasUsed *hexutil.Big } +type homesteadReceiptRLP struct { + PostState []byte + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + +type metropolisReceiptRLP struct { + CumulativeGasUsed *big.Int + Bloom Bloom + Logs []*Log +} + // NewReceipt creates a barebone transaction receipt, copying the init fields. func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} @@ -56,23 +69,28 @@ func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { // 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}) + if r.PostState == nil { + return rlp.Encode(w, &metropolisReceiptRLP{r.CumulativeGasUsed, r.Bloom, r.Logs}) + } else { + return rlp.Encode(w, &homesteadReceiptRLP{r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs}) + } } // 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 { - PostState []byte - CumulativeGasUsed *big.Int - Bloom Bloom - Logs []*Log - } - if err := s.Decode(&receipt); err != nil { + raw, err := s.Raw() + if err != nil { return err } - r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs - return nil + var hr homesteadReceiptRLP + var mr metropolisReceiptRLP + if err = rlp.DecodeBytes(raw, &mr); err == nil { + r.CumulativeGasUsed, r.Bloom, r.Logs = mr.CumulativeGasUsed, mr.Bloom, mr.Logs + } else if err = rlp.DecodeBytes(raw, &hr); err == nil { + r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = hr.PostState[:], hr.CumulativeGasUsed, hr.Bloom, hr.Logs + } + return err } // String implements the Stringer interface. diff --git a/ethclient/ethclient.go b/ethclient/ethclient.go index 45bb873225..02df03fff4 100644 --- a/ethclient/ethclient.go +++ b/ethclient/ethclient.go @@ -203,8 +203,6 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* if err == nil { if r == nil { return nil, ethereum.NotFound - } else if len(r.PostState) == 0 { - return nil, fmt.Errorf("server returned receipt without post state") } } return r, err