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 }