github.com/calmw/ethereum@v0.1.1/beacon/engine/types.go (about)

     1  // Copyright 2022 The go-ethereum Authors
     2  // This file is part of the go-ethereum library.
     3  //
     4  // The go-ethereum library is free software: you can redistribute it and/or modify
     5  // it under the terms of the GNU Lesser General Public License as published by
     6  // the Free Software Foundation, either version 3 of the License, or
     7  // (at your option) any later version.
     8  //
     9  // The go-ethereum library is distributed in the hope that it will be useful,
    10  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    11  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    12  // GNU Lesser General Public License for more details.
    13  //
    14  // You should have received a copy of the GNU Lesser General Public License
    15  // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
    16  
    17  package engine
    18  
    19  import (
    20  	"fmt"
    21  	"math/big"
    22  
    23  	"github.com/calmw/ethereum/common"
    24  	"github.com/calmw/ethereum/common/hexutil"
    25  	"github.com/calmw/ethereum/core/types"
    26  	"github.com/calmw/ethereum/trie"
    27  )
    28  
    29  //go:generate go run github.com/fjl/gencodec -type PayloadAttributes -field-override payloadAttributesMarshaling -out gen_blockparams.go
    30  
    31  // PayloadAttributes describes the environment context in which a block should
    32  // be built.
    33  type PayloadAttributes struct {
    34  	Timestamp             uint64              `json:"timestamp"             gencodec:"required"`
    35  	Random                common.Hash         `json:"prevRandao"            gencodec:"required"`
    36  	SuggestedFeeRecipient common.Address      `json:"suggestedFeeRecipient" gencodec:"required"`
    37  	Withdrawals           []*types.Withdrawal `json:"withdrawals"`
    38  }
    39  
    40  // JSON type overrides for PayloadAttributes.
    41  type payloadAttributesMarshaling struct {
    42  	Timestamp hexutil.Uint64
    43  }
    44  
    45  //go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
    46  
    47  // ExecutableData is the data necessary to execute an EL payload.
    48  type ExecutableData struct {
    49  	ParentHash    common.Hash         `json:"parentHash"    gencodec:"required"`
    50  	FeeRecipient  common.Address      `json:"feeRecipient"  gencodec:"required"`
    51  	StateRoot     common.Hash         `json:"stateRoot"     gencodec:"required"`
    52  	ReceiptsRoot  common.Hash         `json:"receiptsRoot"  gencodec:"required"`
    53  	LogsBloom     []byte              `json:"logsBloom"     gencodec:"required"`
    54  	Random        common.Hash         `json:"prevRandao"    gencodec:"required"`
    55  	Number        uint64              `json:"blockNumber"   gencodec:"required"`
    56  	GasLimit      uint64              `json:"gasLimit"      gencodec:"required"`
    57  	GasUsed       uint64              `json:"gasUsed"       gencodec:"required"`
    58  	Timestamp     uint64              `json:"timestamp"     gencodec:"required"`
    59  	ExtraData     []byte              `json:"extraData"     gencodec:"required"`
    60  	BaseFeePerGas *big.Int            `json:"baseFeePerGas" gencodec:"required"`
    61  	BlockHash     common.Hash         `json:"blockHash"     gencodec:"required"`
    62  	Transactions  [][]byte            `json:"transactions"  gencodec:"required"`
    63  	Withdrawals   []*types.Withdrawal `json:"withdrawals"`
    64  }
    65  
    66  // JSON type overrides for executableData.
    67  type executableDataMarshaling struct {
    68  	Number        hexutil.Uint64
    69  	GasLimit      hexutil.Uint64
    70  	GasUsed       hexutil.Uint64
    71  	Timestamp     hexutil.Uint64
    72  	BaseFeePerGas *hexutil.Big
    73  	ExtraData     hexutil.Bytes
    74  	LogsBloom     hexutil.Bytes
    75  	Transactions  []hexutil.Bytes
    76  }
    77  
    78  //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
    79  
    80  type ExecutionPayloadEnvelope struct {
    81  	ExecutionPayload *ExecutableData `json:"executionPayload"  gencodec:"required"`
    82  	BlockValue       *big.Int        `json:"blockValue"  gencodec:"required"`
    83  }
    84  
    85  // JSON type overrides for ExecutionPayloadEnvelope.
    86  type executionPayloadEnvelopeMarshaling struct {
    87  	BlockValue *hexutil.Big
    88  }
    89  
    90  type PayloadStatusV1 struct {
    91  	Status          string       `json:"status"`
    92  	LatestValidHash *common.Hash `json:"latestValidHash"`
    93  	ValidationError *string      `json:"validationError"`
    94  }
    95  
    96  type TransitionConfigurationV1 struct {
    97  	TerminalTotalDifficulty *hexutil.Big   `json:"terminalTotalDifficulty"`
    98  	TerminalBlockHash       common.Hash    `json:"terminalBlockHash"`
    99  	TerminalBlockNumber     hexutil.Uint64 `json:"terminalBlockNumber"`
   100  }
   101  
   102  // PayloadID is an identifier of the payload build process
   103  type PayloadID [8]byte
   104  
   105  func (b PayloadID) String() string {
   106  	return hexutil.Encode(b[:])
   107  }
   108  
   109  func (b PayloadID) MarshalText() ([]byte, error) {
   110  	return hexutil.Bytes(b[:]).MarshalText()
   111  }
   112  
   113  func (b *PayloadID) UnmarshalText(input []byte) error {
   114  	err := hexutil.UnmarshalFixedText("PayloadID", input, b[:])
   115  	if err != nil {
   116  		return fmt.Errorf("invalid payload id %q: %w", input, err)
   117  	}
   118  	return nil
   119  }
   120  
   121  type ForkChoiceResponse struct {
   122  	PayloadStatus PayloadStatusV1 `json:"payloadStatus"`
   123  	PayloadID     *PayloadID      `json:"payloadId"`
   124  }
   125  
   126  type ForkchoiceStateV1 struct {
   127  	HeadBlockHash      common.Hash `json:"headBlockHash"`
   128  	SafeBlockHash      common.Hash `json:"safeBlockHash"`
   129  	FinalizedBlockHash common.Hash `json:"finalizedBlockHash"`
   130  }
   131  
   132  func encodeTransactions(txs []*types.Transaction) [][]byte {
   133  	var enc = make([][]byte, len(txs))
   134  	for i, tx := range txs {
   135  		enc[i], _ = tx.MarshalBinary()
   136  	}
   137  	return enc
   138  }
   139  
   140  func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
   141  	var txs = make([]*types.Transaction, len(enc))
   142  	for i, encTx := range enc {
   143  		var tx types.Transaction
   144  		if err := tx.UnmarshalBinary(encTx); err != nil {
   145  			return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
   146  		}
   147  		txs[i] = &tx
   148  	}
   149  	return txs, nil
   150  }
   151  
   152  // ExecutableDataToBlock constructs a block from executable data.
   153  // It verifies that the following fields:
   154  //
   155  //	len(extraData) <= 32
   156  //	uncleHash = emptyUncleHash
   157  //	difficulty = 0
   158  //
   159  // and that the blockhash of the constructed block matches the parameters. Nil
   160  // Withdrawals value will propagate through the returned block. Empty
   161  // Withdrawals value must be passed via non-nil, length 0 value in params.
   162  func ExecutableDataToBlock(params ExecutableData) (*types.Block, error) {
   163  	txs, err := decodeTransactions(params.Transactions)
   164  	if err != nil {
   165  		return nil, err
   166  	}
   167  	if len(params.ExtraData) > 32 {
   168  		return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData))
   169  	}
   170  	if len(params.LogsBloom) != 256 {
   171  		return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom))
   172  	}
   173  	// Check that baseFeePerGas is not negative or too big
   174  	if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
   175  		return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
   176  	}
   177  	// Only set withdrawalsRoot if it is non-nil. This allows CLs to use
   178  	// ExecutableData before withdrawals are enabled by marshaling
   179  	// Withdrawals as the json null value.
   180  	var withdrawalsRoot *common.Hash
   181  	if params.Withdrawals != nil {
   182  		h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil))
   183  		withdrawalsRoot = &h
   184  	}
   185  	header := &types.Header{
   186  		ParentHash:      params.ParentHash,
   187  		UncleHash:       types.EmptyUncleHash,
   188  		Coinbase:        params.FeeRecipient,
   189  		Root:            params.StateRoot,
   190  		TxHash:          types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
   191  		ReceiptHash:     params.ReceiptsRoot,
   192  		Bloom:           types.BytesToBloom(params.LogsBloom),
   193  		Difficulty:      common.Big0,
   194  		Number:          new(big.Int).SetUint64(params.Number),
   195  		GasLimit:        params.GasLimit,
   196  		GasUsed:         params.GasUsed,
   197  		Time:            params.Timestamp,
   198  		BaseFee:         params.BaseFeePerGas,
   199  		Extra:           params.ExtraData,
   200  		MixDigest:       params.Random,
   201  		WithdrawalsHash: withdrawalsRoot,
   202  	}
   203  	block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
   204  	if block.Hash() != params.BlockHash {
   205  		return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
   206  	}
   207  	return block, nil
   208  }
   209  
   210  // BlockToExecutableData constructs the ExecutableData structure by filling the
   211  // fields from the given block. It assumes the given block is post-merge block.
   212  func BlockToExecutableData(block *types.Block, fees *big.Int) *ExecutionPayloadEnvelope {
   213  	data := &ExecutableData{
   214  		BlockHash:     block.Hash(),
   215  		ParentHash:    block.ParentHash(),
   216  		FeeRecipient:  block.Coinbase(),
   217  		StateRoot:     block.Root(),
   218  		Number:        block.NumberU64(),
   219  		GasLimit:      block.GasLimit(),
   220  		GasUsed:       block.GasUsed(),
   221  		BaseFeePerGas: block.BaseFee(),
   222  		Timestamp:     block.Time(),
   223  		ReceiptsRoot:  block.ReceiptHash(),
   224  		LogsBloom:     block.Bloom().Bytes(),
   225  		Transactions:  encodeTransactions(block.Transactions()),
   226  		Random:        block.MixDigest(),
   227  		ExtraData:     block.Extra(),
   228  		Withdrawals:   block.Withdrawals(),
   229  	}
   230  	return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees}
   231  }
   232  
   233  // ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
   234  type ExecutionPayloadBodyV1 struct {
   235  	TransactionData []hexutil.Bytes     `json:"transactions"`
   236  	Withdrawals     []*types.Withdrawal `json:"withdrawals"`
   237  }