github.com/theQRL/go-zond@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/theQRL/go-zond/common"
    24  	"github.com/theQRL/go-zond/common/hexutil"
    25  	"github.com/theQRL/go-zond/core/types"
    26  	"github.com/theQRL/go-zond/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  	BeaconRoot            *common.Hash        `json:"parentBeaconBlockRoot"`
    39  }
    40  
    41  // JSON type overrides for PayloadAttributes.
    42  type payloadAttributesMarshaling struct {
    43  	Timestamp hexutil.Uint64
    44  }
    45  
    46  //go:generate go run github.com/fjl/gencodec -type ExecutableData -field-override executableDataMarshaling -out gen_ed.go
    47  
    48  // ExecutableData is the data necessary to execute an EL payload.
    49  type ExecutableData struct {
    50  	ParentHash    common.Hash         `json:"parentHash"    gencodec:"required"`
    51  	FeeRecipient  common.Address      `json:"feeRecipient"  gencodec:"required"`
    52  	StateRoot     common.Hash         `json:"stateRoot"     gencodec:"required"`
    53  	ReceiptsRoot  common.Hash         `json:"receiptsRoot"  gencodec:"required"`
    54  	LogsBloom     []byte              `json:"logsBloom"     gencodec:"required"`
    55  	Random        common.Hash         `json:"prevRandao"    gencodec:"required"`
    56  	Number        uint64              `json:"blockNumber"   gencodec:"required"`
    57  	GasLimit      uint64              `json:"gasLimit"      gencodec:"required"`
    58  	GasUsed       uint64              `json:"gasUsed"       gencodec:"required"`
    59  	Timestamp     uint64              `json:"timestamp"     gencodec:"required"`
    60  	ExtraData     []byte              `json:"extraData"     gencodec:"required"`
    61  	BaseFeePerGas *big.Int            `json:"baseFeePerGas" gencodec:"required"`
    62  	BlockHash     common.Hash         `json:"blockHash"     gencodec:"required"`
    63  	Transactions  [][]byte            `json:"transactions"  gencodec:"required"`
    64  	Withdrawals   []*types.Withdrawal `json:"withdrawals"`
    65  	BlobGasUsed   *uint64             `json:"blobGasUsed"`
    66  	ExcessBlobGas *uint64             `json:"excessBlobGas"`
    67  }
    68  
    69  // JSON type overrides for executableData.
    70  type executableDataMarshaling struct {
    71  	Number        hexutil.Uint64
    72  	GasLimit      hexutil.Uint64
    73  	GasUsed       hexutil.Uint64
    74  	Timestamp     hexutil.Uint64
    75  	BaseFeePerGas *hexutil.Big
    76  	ExtraData     hexutil.Bytes
    77  	LogsBloom     hexutil.Bytes
    78  	Transactions  []hexutil.Bytes
    79  	BlobGasUsed   *hexutil.Uint64
    80  	ExcessBlobGas *hexutil.Uint64
    81  }
    82  
    83  //go:generate go run github.com/fjl/gencodec -type ExecutionPayloadEnvelope -field-override executionPayloadEnvelopeMarshaling -out gen_epe.go
    84  
    85  type ExecutionPayloadEnvelope struct {
    86  	ExecutionPayload *ExecutableData `json:"executionPayload"  gencodec:"required"`
    87  	BlockValue       *big.Int        `json:"blockValue"  gencodec:"required"`
    88  	BlobsBundle      *BlobsBundleV1  `json:"blobsBundle"`
    89  	Override         bool            `json:"shouldOverrideBuilder"`
    90  }
    91  
    92  type BlobsBundleV1 struct {
    93  	Commitments []hexutil.Bytes `json:"commitments"`
    94  	Proofs      []hexutil.Bytes `json:"proofs"`
    95  	Blobs       []hexutil.Bytes `json:"blobs"`
    96  }
    97  
    98  // JSON type overrides for ExecutionPayloadEnvelope.
    99  type executionPayloadEnvelopeMarshaling struct {
   100  	BlockValue *hexutil.Big
   101  }
   102  
   103  type PayloadStatusV1 struct {
   104  	Status          string       `json:"status"`
   105  	LatestValidHash *common.Hash `json:"latestValidHash"`
   106  	ValidationError *string      `json:"validationError"`
   107  }
   108  
   109  type TransitionConfigurationV1 struct {
   110  	TerminalTotalDifficulty *hexutil.Big   `json:"terminalTotalDifficulty"`
   111  	TerminalBlockHash       common.Hash    `json:"terminalBlockHash"`
   112  	TerminalBlockNumber     hexutil.Uint64 `json:"terminalBlockNumber"`
   113  }
   114  
   115  // PayloadID is an identifier of the payload build process
   116  type PayloadID [8]byte
   117  
   118  func (b PayloadID) String() string {
   119  	return hexutil.Encode(b[:])
   120  }
   121  
   122  func (b PayloadID) MarshalText() ([]byte, error) {
   123  	return hexutil.Bytes(b[:]).MarshalText()
   124  }
   125  
   126  func (b *PayloadID) UnmarshalText(input []byte) error {
   127  	err := hexutil.UnmarshalFixedText("PayloadID", input, b[:])
   128  	if err != nil {
   129  		return fmt.Errorf("invalid payload id %q: %w", input, err)
   130  	}
   131  	return nil
   132  }
   133  
   134  type ForkChoiceResponse struct {
   135  	PayloadStatus PayloadStatusV1 `json:"payloadStatus"`
   136  	PayloadID     *PayloadID      `json:"payloadId"`
   137  }
   138  
   139  type ForkchoiceStateV1 struct {
   140  	HeadBlockHash      common.Hash `json:"headBlockHash"`
   141  	SafeBlockHash      common.Hash `json:"safeBlockHash"`
   142  	FinalizedBlockHash common.Hash `json:"finalizedBlockHash"`
   143  }
   144  
   145  func encodeTransactions(txs []*types.Transaction) [][]byte {
   146  	var enc = make([][]byte, len(txs))
   147  	for i, tx := range txs {
   148  		enc[i], _ = tx.MarshalBinary()
   149  	}
   150  	return enc
   151  }
   152  
   153  func decodeTransactions(enc [][]byte) ([]*types.Transaction, error) {
   154  	var txs = make([]*types.Transaction, len(enc))
   155  	for i, encTx := range enc {
   156  		var tx types.Transaction
   157  		if err := tx.UnmarshalBinary(encTx); err != nil {
   158  			return nil, fmt.Errorf("invalid transaction %d: %v", i, err)
   159  		}
   160  		txs[i] = &tx
   161  	}
   162  	return txs, nil
   163  }
   164  
   165  // ExecutableDataToBlock constructs a block from executable data.
   166  // It verifies that the following fields:
   167  //
   168  //		len(extraData) <= 32
   169  //		uncleHash = emptyUncleHash
   170  //		difficulty = 0
   171  //	 	if versionedHashes != nil, versionedHashes match to blob transactions
   172  //
   173  // and that the blockhash of the constructed block matches the parameters. Nil
   174  // Withdrawals value will propagate through the returned block. Empty
   175  // Withdrawals value must be passed via non-nil, length 0 value in params.
   176  func ExecutableDataToBlock(params ExecutableData, versionedHashes []common.Hash, beaconRoot *common.Hash) (*types.Block, error) {
   177  	txs, err := decodeTransactions(params.Transactions)
   178  	if err != nil {
   179  		return nil, err
   180  	}
   181  	if len(params.ExtraData) > 32 {
   182  		return nil, fmt.Errorf("invalid extradata length: %v", len(params.ExtraData))
   183  	}
   184  	if len(params.LogsBloom) != 256 {
   185  		return nil, fmt.Errorf("invalid logsBloom length: %v", len(params.LogsBloom))
   186  	}
   187  	// Check that baseFeePerGas is not negative or too big
   188  	if params.BaseFeePerGas != nil && (params.BaseFeePerGas.Sign() == -1 || params.BaseFeePerGas.BitLen() > 256) {
   189  		return nil, fmt.Errorf("invalid baseFeePerGas: %v", params.BaseFeePerGas)
   190  	}
   191  	var blobHashes []common.Hash
   192  	for _, tx := range txs {
   193  		blobHashes = append(blobHashes, tx.BlobHashes()...)
   194  	}
   195  	if len(blobHashes) != len(versionedHashes) {
   196  		return nil, fmt.Errorf("invalid number of versionedHashes: %v blobHashes: %v", versionedHashes, blobHashes)
   197  	}
   198  	for i := 0; i < len(blobHashes); i++ {
   199  		if blobHashes[i] != versionedHashes[i] {
   200  			return nil, fmt.Errorf("invalid versionedHash at %v: %v blobHashes: %v", i, versionedHashes, blobHashes)
   201  		}
   202  	}
   203  	// Only set withdrawalsRoot if it is non-nil. This allows CLs to use
   204  	// ExecutableData before withdrawals are enabled by marshaling
   205  	// Withdrawals as the json null value.
   206  	var withdrawalsRoot *common.Hash
   207  	if params.Withdrawals != nil {
   208  		h := types.DeriveSha(types.Withdrawals(params.Withdrawals), trie.NewStackTrie(nil))
   209  		withdrawalsRoot = &h
   210  	}
   211  	header := &types.Header{
   212  		ParentHash:       params.ParentHash,
   213  		UncleHash:        types.EmptyUncleHash,
   214  		Coinbase:         params.FeeRecipient,
   215  		Root:             params.StateRoot,
   216  		TxHash:           types.DeriveSha(types.Transactions(txs), trie.NewStackTrie(nil)),
   217  		ReceiptHash:      params.ReceiptsRoot,
   218  		Bloom:            types.BytesToBloom(params.LogsBloom),
   219  		Difficulty:       common.Big0,
   220  		Number:           new(big.Int).SetUint64(params.Number),
   221  		GasLimit:         params.GasLimit,
   222  		GasUsed:          params.GasUsed,
   223  		Time:             params.Timestamp,
   224  		BaseFee:          params.BaseFeePerGas,
   225  		Extra:            params.ExtraData,
   226  		MixDigest:        params.Random,
   227  		WithdrawalsHash:  withdrawalsRoot,
   228  		ExcessBlobGas:    params.ExcessBlobGas,
   229  		BlobGasUsed:      params.BlobGasUsed,
   230  		ParentBeaconRoot: beaconRoot,
   231  	}
   232  	block := types.NewBlockWithHeader(header).WithBody(txs, nil /* uncles */).WithWithdrawals(params.Withdrawals)
   233  	if block.Hash() != params.BlockHash {
   234  		return nil, fmt.Errorf("blockhash mismatch, want %x, got %x", params.BlockHash, block.Hash())
   235  	}
   236  	return block, nil
   237  }
   238  
   239  // BlockToExecutableData constructs the ExecutableData structure by filling the
   240  // fields from the given block. It assumes the given block is post-merge block.
   241  func BlockToExecutableData(block *types.Block, fees *big.Int, sidecars []*types.BlobTxSidecar) *ExecutionPayloadEnvelope {
   242  	data := &ExecutableData{
   243  		BlockHash:     block.Hash(),
   244  		ParentHash:    block.ParentHash(),
   245  		FeeRecipient:  block.Coinbase(),
   246  		StateRoot:     block.Root(),
   247  		Number:        block.NumberU64(),
   248  		GasLimit:      block.GasLimit(),
   249  		GasUsed:       block.GasUsed(),
   250  		BaseFeePerGas: block.BaseFee(),
   251  		Timestamp:     block.Time(),
   252  		ReceiptsRoot:  block.ReceiptHash(),
   253  		LogsBloom:     block.Bloom().Bytes(),
   254  		Transactions:  encodeTransactions(block.Transactions()),
   255  		Random:        block.MixDigest(),
   256  		ExtraData:     block.Extra(),
   257  		Withdrawals:   block.Withdrawals(),
   258  		BlobGasUsed:   block.BlobGasUsed(),
   259  		ExcessBlobGas: block.ExcessBlobGas(),
   260  	}
   261  	bundle := BlobsBundleV1{
   262  		Commitments: make([]hexutil.Bytes, 0),
   263  		Blobs:       make([]hexutil.Bytes, 0),
   264  		Proofs:      make([]hexutil.Bytes, 0),
   265  	}
   266  	for _, sidecar := range sidecars {
   267  		for j := range sidecar.Blobs {
   268  			bundle.Blobs = append(bundle.Blobs, hexutil.Bytes(sidecar.Blobs[j][:]))
   269  			bundle.Commitments = append(bundle.Commitments, hexutil.Bytes(sidecar.Commitments[j][:]))
   270  			bundle.Proofs = append(bundle.Proofs, hexutil.Bytes(sidecar.Proofs[j][:]))
   271  		}
   272  	}
   273  	return &ExecutionPayloadEnvelope{ExecutionPayload: data, BlockValue: fees, BlobsBundle: &bundle, Override: false}
   274  }
   275  
   276  // ExecutionPayloadBodyV1 is used in the response to GetPayloadBodiesByHashV1 and GetPayloadBodiesByRangeV1
   277  type ExecutionPayloadBodyV1 struct {
   278  	TransactionData []hexutil.Bytes     `json:"transactions"`
   279  	Withdrawals     []*types.Withdrawal `json:"withdrawals"`
   280  }