core, ethclient: implement Metropolis EIP 98 (#14750)
Implements ethereum/EIPs#98
This commit is contained in:
		
				
					committed by
					
						 Felix Lange
						Felix Lange
					
				
			
			
				
	
			
			
			
						parent
						
							47359301a2
						
					
				
				
					commit
					a56f3dc0d9
				
			| @@ -104,11 +104,17 @@ func ApplyTransaction(config *params.ChainConfig, bc *BlockChain, author *common | |||||||
| 	} | 	} | ||||||
|  |  | ||||||
| 	// Update the state with pending changes | 	// 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) | 	usedGas.Add(usedGas, gas) | ||||||
|  |  | ||||||
| 	// Create a new receipt for the transaction, storing the intermediate root and gas used by the tx | 	// 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. | 	// 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, usedGas) | ||||||
| 	receipt := types.NewReceipt(root.Bytes(), usedGas) |  | ||||||
| 	receipt.TxHash = tx.Hash() | 	receipt.TxHash = tx.Hash() | ||||||
| 	receipt.GasUsed = new(big.Int).Set(gas) | 	receipt.GasUsed = new(big.Int).Set(gas) | ||||||
| 	// if the transaction created a contract, store the creation address in the receipt. | 	// if the transaction created a contract, store the creation address in the receipt. | ||||||
|   | |||||||
| @@ -13,7 +13,7 @@ import ( | |||||||
|  |  | ||||||
| func (r Receipt) MarshalJSON() ([]byte, error) { | func (r Receipt) MarshalJSON() ([]byte, error) { | ||||||
| 	type Receipt struct { | 	type Receipt struct { | ||||||
| 		PostState         hexutil.Bytes  `json:"root"              gencodec:"required"` | 		PostState         hexutil.Bytes  `json:"root"` | ||||||
| 		CumulativeGasUsed *hexutil.Big   `json:"cumulativeGasUsed" gencodec:"required"` | 		CumulativeGasUsed *hexutil.Big   `json:"cumulativeGasUsed" gencodec:"required"` | ||||||
| 		Bloom             Bloom          `json:"logsBloom"         gencodec:"required"` | 		Bloom             Bloom          `json:"logsBloom"         gencodec:"required"` | ||||||
| 		Logs              []*Log         `json:"logs"              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 { | func (r *Receipt) UnmarshalJSON(input []byte) error { | ||||||
| 	type Receipt struct { | 	type Receipt struct { | ||||||
| 		PostState         hexutil.Bytes   `json:"root"              gencodec:"required"` | 		PostState         hexutil.Bytes   `json:"root"` | ||||||
| 		CumulativeGasUsed *hexutil.Big    `json:"cumulativeGasUsed" gencodec:"required"` | 		CumulativeGasUsed *hexutil.Big    `json:"cumulativeGasUsed" gencodec:"required"` | ||||||
| 		Bloom             *Bloom          `json:"logsBloom"         gencodec:"required"` | 		Bloom             *Bloom          `json:"logsBloom"         gencodec:"required"` | ||||||
| 		Logs              []*Log          `json:"logs"              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 { | 	if err := json.Unmarshal(input, &dec); err != nil { | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	if dec.PostState == nil { | 	if dec.PostState != nil { | ||||||
| 		return errors.New("missing required field 'root' for Receipt") | 		r.PostState = dec.PostState | ||||||
| 	} | 	} | ||||||
| 	r.PostState = dec.PostState |  | ||||||
| 	if dec.CumulativeGasUsed == nil { | 	if dec.CumulativeGasUsed == nil { | ||||||
| 		return errors.New("missing required field 'cumulativeGasUsed' for Receipt") | 		return errors.New("missing required field 'cumulativeGasUsed' for Receipt") | ||||||
| 	} | 	} | ||||||
|   | |||||||
| @@ -31,7 +31,7 @@ import ( | |||||||
| // Receipt represents the results of a transaction. | // Receipt represents the results of a transaction. | ||||||
| type Receipt struct { | type Receipt struct { | ||||||
| 	// Consensus fields | 	// Consensus fields | ||||||
| 	PostState         []byte   `json:"root"              gencodec:"required"` | 	PostState         []byte   `json:"root"` | ||||||
| 	CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` | 	CumulativeGasUsed *big.Int `json:"cumulativeGasUsed" gencodec:"required"` | ||||||
| 	Bloom             Bloom    `json:"logsBloom"         gencodec:"required"` | 	Bloom             Bloom    `json:"logsBloom"         gencodec:"required"` | ||||||
| 	Logs              []*Log   `json:"logs"              gencodec:"required"` | 	Logs              []*Log   `json:"logs"              gencodec:"required"` | ||||||
| @@ -48,35 +48,88 @@ type receiptMarshaling struct { | |||||||
| 	GasUsed           *hexutil.Big | 	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. | // NewReceipt creates a barebone transaction receipt, copying the init fields. | ||||||
| func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { | func NewReceipt(root []byte, cumulativeGasUsed *big.Int) *Receipt { | ||||||
| 	return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} | 	return &Receipt{PostState: common.CopyBytes(root), CumulativeGasUsed: new(big.Int).Set(cumulativeGasUsed)} | ||||||
| } | } | ||||||
|  |  | ||||||
| // EncodeRLP implements rlp.Encoder, and flattens the consensus fields of a receipt | // 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 { | 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 | // DecodeRLP implements rlp.Decoder, and loads the consensus fields of a receipt | ||||||
| // from an RLP stream. | // from an RLP stream. | ||||||
| func (r *Receipt) DecodeRLP(s *rlp.Stream) error { | func (r *Receipt) DecodeRLP(s *rlp.Stream) error { | ||||||
| 	var receipt struct { | 	// Load the raw bytes since we have multiple possible formats | ||||||
| 		PostState         []byte | 	raw, err := s.Raw() | ||||||
| 		CumulativeGasUsed *big.Int | 	if err != nil { | ||||||
| 		Bloom             Bloom |  | ||||||
| 		Logs              []*Log |  | ||||||
| 	} |  | ||||||
| 	if err := s.Decode(&receipt); err != nil { |  | ||||||
| 		return err | 		return err | ||||||
| 	} | 	} | ||||||
| 	r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs = receipt.PostState, receipt.CumulativeGasUsed, receipt.Bloom, receipt.Logs | 	list, _, err := rlp.SplitList(raw) | ||||||
| 	return nil | 	if err != nil { | ||||||
|  | 		return err | ||||||
|  | 	} | ||||||
|  | 	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. | // String implements the Stringer interface. | ||||||
| func (r *Receipt) String() string { | 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) | 	return fmt.Sprintf("receipt{med=%x cgas=%v bloom=%x logs=%v}", r.PostState, r.CumulativeGasUsed, r.Bloom, r.Logs) | ||||||
| } | } | ||||||
|  |  | ||||||
|   | |||||||
| @@ -203,8 +203,6 @@ func (ec *Client) TransactionReceipt(ctx context.Context, txHash common.Hash) (* | |||||||
| 	if err == nil { | 	if err == nil { | ||||||
| 		if r == nil { | 		if r == nil { | ||||||
| 			return nil, ethereum.NotFound | 			return nil, ethereum.NotFound | ||||||
| 		} else if len(r.PostState) == 0 { |  | ||||||
| 			return nil, fmt.Errorf("server returned receipt without post state") |  | ||||||
| 		} | 		} | ||||||
| 	} | 	} | ||||||
| 	return r, err | 	return r, err | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user