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 | ||||
| 	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. | ||||
|   | ||||
| @@ -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") | ||||
| 	} | ||||
|   | ||||
| @@ -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,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 | ||||
| 	} | ||||
| 	if err := s.Decode(&receipt); err != nil { | ||||
| 	// Load the raw bytes since we have multiple possible formats | ||||
| 	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 | ||||
| 	list, _, err := rlp.SplitList(raw) | ||||
| 	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. | ||||
| 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) | ||||
| } | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
		Reference in New Issue
	
	Block a user