core, ethclient: implement Metropolis EIP 98 (#14750)
Implements ethereum/EIPs#98
This commit is contained in:
		
				
					committed by
					
						
						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)
 | 
				
			||||||
 | 
						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
 | 
							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