Skip to content

Commit

Permalink
core, ethclient: implement Metropolis EIP 98 (#14750)
Browse files Browse the repository at this point in the history
Implements ethereum/EIPs#98
  • Loading branch information
karalabe authored and fjl committed Jul 17, 2017
1 parent 4735930 commit a56f3dc
Show file tree
Hide file tree
Showing 4 changed files with 76 additions and 20 deletions.
10 changes: 8 additions & 2 deletions core/state_processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -104,11 +104,17 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common
}

// Update the state with pending changes
var root []byte
if config.IsMetropolis(header.Number) {
statedb.Finalise()
} else {
root = statedb.IntermediateRoot(config.IsEIP158(header.Number)).Bytes()
}
usedGas.Add(usedGas, gas)

// 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.
Expand Down
9 changes: 4 additions & 5 deletions core/types/gen_receipt_json.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

75 changes: 64 additions & 11 deletions core/types/receipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"`
Expand All @@ -48,35 +48,88 @@ type receiptMarshaling struct {
GasUsed *hexutil.Big
}

// homesteadReceiptRLP contains the receipt's Homestead consensus fields, used
// during RLP serialization.
type homesteadReceiptRLP struct {
PostState []byte
CumulativeGasUsed *big.Int
Bloom Bloom
Logs []*Log
}

// metropolisReceiptRLP contains the receipt's Metropolis consensus fields, used
// during RLP serialization.
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)}
}

// EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt
// into an RLP stream.
// into an RLP stream. If no post state is present, metropolis fork is assumed.
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})
}
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
// Load the raw bytes since we have multiple possible formats
raw, err := s.Raw()
if err != nil {
return err
}
if err := s.Decode(&receipt); err != nil {
list, _, err := rlp.SplitList(raw)
if err != nil {
return err
}
r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs
return nil
items, err := rlp.CountValues(list)
if err != nil {
return err
}
// Deserialize based on the number of content items
switch items {
case 3:
// Metropolis receipts have 3 components
var metro metropolisReceiptRLP
if err := rlp.DecodeBytes(raw, &metro); err != nil {
return err
}
r.CumulativeGasUsed = metro.CumulativeGasUsed
r.Bloom = metro.Bloom
r.Logs = metro.Logs
return nil

case 4:
// Homestead receipts have 4 components
var home homesteadReceiptRLP
if err := rlp.DecodeBytes(raw, &home); err != nil {
return err
}
r.PostState = home.PostState[:]
r.CumulativeGasUsed = home.CumulativeGasUsed
r.Bloom = home.Bloom
r.Logs = home.Logs
return nil

default:
return fmt.Errorf("invalid receipt components: %v", items)
}
}

// String implements the Stringer interface.
func (r *Receipt) String() string {
if r.PostState == nil {
return fmt.Sprintf("receipt{cgas=%v bloom=%x logs=%v}", r.CumulativeGasUsed, r.Bloom, r.Logs)
}
return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs)
}

Expand Down
2 changes: 0 additions & 2 deletions ethclient/ethclient.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit a56f3dc

Please sign in to comment.