From 78bc05cc8943d99456acef57894b533809884cb5 Mon Sep 17 00:00:00 2001 From: Kasey Kirkham Date: Mon, 13 May 2024 18:09:38 -0500 Subject: [PATCH 1/2] Combined v1/v2 payload body handling --- beacon-chain/execution/BUILD.bazel | 3 + beacon-chain/execution/engine_client.go | 272 ++----- beacon-chain/execution/engine_client_test.go | 687 ++++-------------- beacon-chain/execution/mock_test.go | 221 ++++++ beacon-chain/execution/payload_body.go | 250 +++++++ beacon-chain/execution/payload_body_test.go | 408 +++++++++++ proto/engine/v1/execution_engine.pb.go | 329 ++++----- proto/engine/v1/execution_engine.proto | 5 - proto/engine/v1/generated.ssz.go | 2 +- proto/engine/v1/json_marshal_unmarshal.go | 133 ++-- .../engine/v1/json_marshal_unmarshal_test.go | 12 +- proto/eth/v1/generated.ssz.go | 2 +- proto/eth/v2/generated.ssz.go | 2 +- proto/prysm/v1alpha1/generated.ssz.go | 2 +- testing/util/deneb.go | 89 ++- testing/util/electra.go | 175 +++++ 16 files changed, 1533 insertions(+), 1059 deletions(-) create mode 100644 beacon-chain/execution/mock_test.go create mode 100644 beacon-chain/execution/payload_body.go create mode 100644 beacon-chain/execution/payload_body_test.go diff --git a/beacon-chain/execution/BUILD.bazel b/beacon-chain/execution/BUILD.bazel index 2ff3ec037916..2d0edffd8744 100644 --- a/beacon-chain/execution/BUILD.bazel +++ b/beacon-chain/execution/BUILD.bazel @@ -12,6 +12,7 @@ go_library( "log_processing.go", "metrics.go", "options.go", + "payload_body.go", "prometheus.go", "rpc_connection.go", "service.go", @@ -86,6 +87,8 @@ go_test( "execution_chain_test.go", "init_test.go", "log_processing_test.go", + "mock_test.go", + "payload_body_test.go", "prometheus_test.go", "service_test.go", ], diff --git a/beacon-chain/execution/engine_client.go b/beacon-chain/execution/engine_client.go index c72b3ea33b30..8ed049bce9fc 100644 --- a/beacon-chain/execution/engine_client.go +++ b/beacon-chain/execution/engine_client.go @@ -1,7 +1,6 @@ package execution import ( - "bytes" "context" "fmt" "math/big" @@ -34,12 +33,19 @@ var ( supportedEngineEndpoints = []string{ NewPayloadMethod, NewPayloadMethodV2, + NewPayloadMethodV3, + NewPayloadMethodV4, ForkchoiceUpdatedMethod, ForkchoiceUpdatedMethodV2, + ForkchoiceUpdatedMethodV3, GetPayloadMethod, GetPayloadMethodV2, + GetPayloadMethodV3, + GetPayloadMethodV4, GetPayloadBodiesByHashV1, GetPayloadBodiesByRangeV1, + GetPayloadBodiesByHashV2, + GetPayloadBodiesByRangeV2, } ) @@ -69,16 +75,22 @@ const ( BlockByHashMethod = "eth_getBlockByHash" // BlockByNumberMethod request string for JSON-RPC. BlockByNumberMethod = "eth_getBlockByNumber" - // GetPayloadBodiesByHashV1 v1 request string for JSON-RPC. + // GetPayloadBodiesByHashV1 is the engine_getPayloadBodiesByHashX JSON-RPC method for pre-Electra payloads. GetPayloadBodiesByHashV1 = "engine_getPayloadBodiesByHashV1" - // GetPayloadBodiesByRangeV1 v1 request string for JSON-RPC. + // GetPayloadBodiesByHashV2 is the engine_getPayloadBodiesByHashX JSON-RPC method introduced by Electra. + GetPayloadBodiesByHashV2 = "engine_getPayloadBodiesByHashV2" + // GetPayloadBodiesByRangeV1 is the engine_getPayloadBodiesByRangeX JSON-RPC method for pre-Electra payloads. GetPayloadBodiesByRangeV1 = "engine_getPayloadBodiesByRangeV1" + // GetPayloadBodiesByRangeV2 is the engine_getPayloadBodiesByRangeX JSON-RPC method introduced by Electra. + GetPayloadBodiesByRangeV2 = "engine_getPayloadBodiesByRangeV2" // ExchangeCapabilities request string for JSON-RPC. ExchangeCapabilities = "engine_exchangeCapabilities" // Defines the seconds before timing out engine endpoints with non-block execution semantics. defaultEngineTimeout = time.Second ) +var errInvalidPayloadBodyResponse = errors.New("engine api payload body response is invalid") + // ForkchoiceUpdatedResponse is the response kind received by the // engine_forkchoiceUpdatedV1 endpoint. type ForkchoiceUpdatedResponse struct { @@ -509,93 +521,19 @@ func (s *Service) HeaderByNumber(ctx context.Context, number *big.Int) (*types.H return hdr, err } -// GetPayloadBodiesByHash returns the relevant payload bodies for the provided block hash. -func (s *Service) GetPayloadBodiesByHash(ctx context.Context, executionBlockHashes []common.Hash) ([]*pb.ExecutionPayloadBodyV1, error) { - ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayloadBodiesByHashV1") - defer span.End() - - result := make([]*pb.ExecutionPayloadBodyV1, 0) - // Exit early if there are no execution hashes. - if len(executionBlockHashes) == 0 { - return result, nil - } - err := s.rpcClient.CallContext(ctx, &result, GetPayloadBodiesByHashV1, executionBlockHashes) - if err != nil { - return nil, handleRPCError(err) - } - if len(result) != len(executionBlockHashes) { - return nil, fmt.Errorf("mismatch of payloads retrieved from the execution client: %d vs %d", len(result), len(executionBlockHashes)) - } - for i, item := range result { - if item == nil { - result[i] = &pb.ExecutionPayloadBodyV1{ - Transactions: make([][]byte, 0), - Withdrawals: make([]*pb.Withdrawal, 0), - } - } - } - return result, nil -} - -// GetPayloadBodiesByRange returns the relevant payload bodies for the provided range. -func (s *Service) GetPayloadBodiesByRange(ctx context.Context, start, count uint64) ([]*pb.ExecutionPayloadBodyV1, error) { - ctx, span := trace.StartSpan(ctx, "powchain.engine-api-client.GetPayloadBodiesByRangeV1") - defer span.End() - - result := make([]*pb.ExecutionPayloadBodyV1, 0) - err := s.rpcClient.CallContext(ctx, &result, GetPayloadBodiesByRangeV1, start, count) - - for i, item := range result { - if item == nil { - result[i] = &pb.ExecutionPayloadBodyV1{ - Transactions: make([][]byte, 0), - Withdrawals: make([]*pb.Withdrawal, 0), - } - } - } - return result, handleRPCError(err) -} - // ReconstructFullBlock takes in a blinded beacon block and reconstructs // a beacon block with a full execution payload via the engine API. func (s *Service) ReconstructFullBlock( ctx context.Context, blindedBlock interfaces.ReadOnlySignedBeaconBlock, ) (interfaces.SignedBeaconBlock, error) { - if err := blocks.BeaconBlockIsNil(blindedBlock); err != nil { - return nil, errors.Wrap(err, "cannot reconstruct bellatrix block from nil data") - } - if !blindedBlock.Block().IsBlinded() { - return nil, errors.New("can only reconstruct block from blinded block format") - } - header, err := blindedBlock.Block().Body().Execution() + reconstructed, err := s.ReconstructFullBellatrixBlockBatch(ctx, []interfaces.ReadOnlySignedBeaconBlock{blindedBlock}) if err != nil { return nil, err } - if header.IsNil() { - return nil, errors.New("execution payload header in blinded block was nil") + if len(reconstructed) != 1 { + return nil, errors.Errorf("could not retrieve the correct number of payload bodies: wanted 1 but got %d", len(reconstructed)) } - - // If the payload header has a block hash of 0x0, it means we are pre-merge and should - // simply return the block with an empty execution payload. - if bytes.Equal(header.BlockHash(), params.BeaconConfig().ZeroHash[:]) { - payload, err := buildEmptyExecutionPayload(blindedBlock.Version()) - if err != nil { - return nil, err - } - return blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload) - } - - executionBlockHash := common.BytesToHash(header.BlockHash()) - payload, err := s.retrievePayloadFromExecutionHash(ctx, executionBlockHash, header, blindedBlock.Version()) - if err != nil { - return nil, err - } - fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlock, payload.Proto()) - if err != nil { - return nil, err - } - reconstructedExecutionPayloadCount.Add(1) - return fullBlock, nil + return reconstructed[0], nil } // ReconstructFullBellatrixBlockBatch takes in a batch of blinded beacon blocks and reconstructs @@ -603,114 +541,16 @@ func (s *Service) ReconstructFullBlock( func (s *Service) ReconstructFullBellatrixBlockBatch( ctx context.Context, blindedBlocks []interfaces.ReadOnlySignedBeaconBlock, ) ([]interfaces.SignedBeaconBlock, error) { - if len(blindedBlocks) == 0 { - return []interfaces.SignedBeaconBlock{}, nil - } - var executionHashes []common.Hash - var validExecPayloads []int - var zeroExecPayloads []int - for i, b := range blindedBlocks { - if err := blocks.BeaconBlockIsNil(b); err != nil { - return nil, errors.Wrap(err, "cannot reconstruct bellatrix block from nil data") - } - if !b.Block().IsBlinded() { - return nil, errors.New("can only reconstruct block from blinded block format") - } - header, err := b.Block().Body().Execution() - if err != nil { - return nil, err - } - if header.IsNil() { - return nil, errors.New("execution payload header in blinded block was nil") - } - // Determine if the block is pre-merge or post-merge. Depending on the result, - // we will ask the execution engine for the full payload. - if bytes.Equal(header.BlockHash(), params.BeaconConfig().ZeroHash[:]) { - zeroExecPayloads = append(zeroExecPayloads, i) - } else { - executionBlockHash := common.BytesToHash(header.BlockHash()) - validExecPayloads = append(validExecPayloads, i) - executionHashes = append(executionHashes, executionBlockHash) - } - } - fullBlocks, err := s.retrievePayloadsFromExecutionHashes(ctx, executionHashes, validExecPayloads, blindedBlocks) + unb, err := reconstructBlindedBlockBatch(ctx, s.rpcClient, blindedBlocks) if err != nil { return nil, err } - // For blocks that are pre-merge we simply reconstruct them via an empty - // execution payload. - for _, realIdx := range zeroExecPayloads { - bblock := blindedBlocks[realIdx] - payload, err := buildEmptyExecutionPayload(bblock.Version()) - if err != nil { - return nil, err - } - fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blindedBlocks[realIdx], payload) - if err != nil { - return nil, err - } - fullBlocks[realIdx] = fullBlock - } - reconstructedExecutionPayloadCount.Add(float64(len(blindedBlocks))) - return fullBlocks, nil -} - -func (s *Service) retrievePayloadFromExecutionHash(ctx context.Context, executionBlockHash common.Hash, header interfaces.ExecutionData, version int) (interfaces.ExecutionData, error) { - pBodies, err := s.GetPayloadBodiesByHash(ctx, []common.Hash{executionBlockHash}) - if err != nil { - return nil, fmt.Errorf("could not get payload body by hash %#x: %v", executionBlockHash, err) - } - if len(pBodies) != 1 { - return nil, errors.Errorf("could not retrieve the correct number of payload bodies: wanted 1 but got %d", len(pBodies)) - } - bdy := pBodies[0] - return fullPayloadFromPayloadBody(header, bdy, version) -} - -// This method assumes that the provided execution hashes are all valid and part of the -// canonical chain. -func (s *Service) retrievePayloadsFromExecutionHashes( - ctx context.Context, - executionHashes []common.Hash, - validExecPayloads []int, - blindedBlocks []interfaces.ReadOnlySignedBeaconBlock) ([]interfaces.SignedBeaconBlock, error) { - fullBlocks := make([]interfaces.SignedBeaconBlock, len(blindedBlocks)) - var payloadBodies []*pb.ExecutionPayloadBodyV1 - var err error - - payloadBodies, err = s.GetPayloadBodiesByHash(ctx, executionHashes) - if err != nil { - return nil, fmt.Errorf("could not fetch payload bodies by hash %#x: %v", executionHashes, err) - } - - // For each valid payload, we reconstruct the full block from it with the - // blinded block. - for sliceIdx, realIdx := range validExecPayloads { - var payload interfaces.ExecutionData - bblock := blindedBlocks[realIdx] - b := payloadBodies[sliceIdx] - if b == nil { - return nil, fmt.Errorf("received nil payload body for request by hash %#x", executionHashes[sliceIdx]) - } - header, err := bblock.Block().Body().Execution() - if err != nil { - return nil, err - } - payload, err = fullPayloadFromPayloadBody(header, b, bblock.Version()) - if err != nil { - return nil, err - } - fullBlock, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(bblock, payload.Proto()) - if err != nil { - return nil, err - } - fullBlocks[realIdx] = fullBlock - } - return fullBlocks, nil + reconstructedExecutionPayloadCount.Add(float64(len(unb))) + return unb, nil } func fullPayloadFromPayloadBody( - header interfaces.ExecutionData, body *pb.ExecutionPayloadBodyV1, bVersion int, + header interfaces.ExecutionData, body *pb.ExecutionPayloadBody, bVersion int, ) (interfaces.ExecutionData, error) { if header.IsNil() || body == nil { return nil, errors.New("execution block and header cannot be nil") @@ -732,7 +572,7 @@ func fullPayloadFromPayloadBody( ExtraData: header.ExtraData(), BaseFeePerGas: header.BaseFeePerGas(), BlockHash: header.BlockHash(), - Transactions: body.Transactions, + Transactions: pb.RecastHexutilByteSlice(body.Transactions), }) case version.Capella: return blocks.WrappedExecutionPayloadCapella(&pb.ExecutionPayloadCapella{ @@ -749,7 +589,7 @@ func fullPayloadFromPayloadBody( ExtraData: header.ExtraData(), BaseFeePerGas: header.BaseFeePerGas(), BlockHash: header.BlockHash(), - Transactions: body.Transactions, + Transactions: pb.RecastHexutilByteSlice(body.Transactions), Withdrawals: body.Withdrawals, }, big.NewInt(0)) // We can't get the block value and don't care about the block value for this instance case version.Deneb: @@ -776,7 +616,7 @@ func fullPayloadFromPayloadBody( ExtraData: header.ExtraData(), BaseFeePerGas: header.BaseFeePerGas(), BlockHash: header.BlockHash(), - Transactions: body.Transactions, + Transactions: pb.RecastHexutilByteSlice(body.Transactions), Withdrawals: body.Withdrawals, ExcessBlobGas: ebg, BlobGasUsed: bgu, @@ -790,25 +630,35 @@ func fullPayloadFromPayloadBody( if err != nil { return nil, errors.Wrap(err, "unable to extract BlobGasUsed attribute from execution payload header") } + wr, err := pb.JsonWithdrawalRequestsToProto(body.WithdrawalRequests) + if err != nil { + return nil, err + } + dr, err := pb.JsonDepositRequestsToProto(body.DepositRequests) + if err != nil { + return nil, err + } return blocks.WrappedExecutionPayloadElectra( &pb.ExecutionPayloadElectra{ - ParentHash: header.ParentHash(), - FeeRecipient: header.FeeRecipient(), - StateRoot: header.StateRoot(), - ReceiptsRoot: header.ReceiptsRoot(), - LogsBloom: header.LogsBloom(), - PrevRandao: header.PrevRandao(), - BlockNumber: header.BlockNumber(), - GasLimit: header.GasLimit(), - GasUsed: header.GasUsed(), - Timestamp: header.Timestamp(), - ExtraData: header.ExtraData(), - BaseFeePerGas: header.BaseFeePerGas(), - BlockHash: header.BlockHash(), - Transactions: body.Transactions, - Withdrawals: body.Withdrawals, - ExcessBlobGas: ebg, - BlobGasUsed: bgu, + ParentHash: header.ParentHash(), + FeeRecipient: header.FeeRecipient(), + StateRoot: header.StateRoot(), + ReceiptsRoot: header.ReceiptsRoot(), + LogsBloom: header.LogsBloom(), + PrevRandao: header.PrevRandao(), + BlockNumber: header.BlockNumber(), + GasLimit: header.GasLimit(), + GasUsed: header.GasUsed(), + Timestamp: header.Timestamp(), + ExtraData: header.ExtraData(), + BaseFeePerGas: header.BaseFeePerGas(), + BlockHash: header.BlockHash(), + Transactions: pb.RecastHexutilByteSlice(body.Transactions), + Withdrawals: body.Withdrawals, + ExcessBlobGas: ebg, + BlobGasUsed: bgu, + DepositReceipts: dr, + WithdrawalRequests: wr, }, big.NewInt(0)) // We can't get the block value and don't care about the block value for this instance default: return nil, fmt.Errorf("unknown execution block version for payload %d", bVersion) @@ -943,6 +793,22 @@ func buildEmptyExecutionPayload(v int) (proto.Message, error) { Transactions: make([][]byte, 0), Withdrawals: make([]*pb.Withdrawal, 0), }, nil + case version.Electra: + return &pb.ExecutionPayloadElectra{ + ParentHash: make([]byte, fieldparams.RootLength), + FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), + StateRoot: make([]byte, fieldparams.RootLength), + ReceiptsRoot: make([]byte, fieldparams.RootLength), + LogsBloom: make([]byte, fieldparams.LogsBloomLength), + PrevRandao: make([]byte, fieldparams.RootLength), + ExtraData: make([]byte, 0), + BaseFeePerGas: make([]byte, fieldparams.RootLength), + BlockHash: make([]byte, fieldparams.RootLength), + Transactions: make([][]byte, 0), + Withdrawals: make([]*pb.Withdrawal, 0), + WithdrawalRequests: make([]*pb.ExecutionLayerWithdrawalRequest, 0), + DepositReceipts: make([]*pb.DepositReceipt, 0), + }, nil default: return nil, errors.Wrapf(ErrUnsupportedVersion, "version=%s", version.String(v)) } diff --git a/beacon-chain/execution/engine_client_test.go b/beacon-chain/execution/engine_client_test.go index e42165d16651..2ac1f8d3c896 100644 --- a/beacon-chain/execution/engine_client_test.go +++ b/beacon-chain/execution/engine_client_test.go @@ -31,6 +31,7 @@ import ( "github.com/prysmaticlabs/prysm/v5/testing/assert" "github.com/prysmaticlabs/prysm/v5/testing/require" "github.com/prysmaticlabs/prysm/v5/testing/util" + "github.com/prysmaticlabs/prysm/v5/time/slots" logTest "github.com/sirupsen/logrus/hooks/test" ) @@ -993,7 +994,7 @@ func TestReconstructFullBellatrixBlockBatch(t *testing.T) { respJSON := map[string]interface{}{ "jsonrpc": "2.0", "id": 1, - "result": []map[string]interface{}{jsonPayload, jsonPayload}, + "result": []map[string]interface{}{jsonPayload}, } require.NoError(t, json.NewEncoder(w).Encode(respJSON)) @@ -1011,10 +1012,8 @@ func TestReconstructFullBellatrixBlockBatch(t *testing.T) { blindedBlock.Block.Body.ExecutionPayloadHeader = header wrapped, err := blocks.NewSignedBeaconBlock(blindedBlock) require.NoError(t, err) - copiedWrapped, err := wrapped.Copy() - require.NoError(t, err) - reconstructed, err := service.ReconstructFullBellatrixBlockBatch(ctx, []interfaces.ReadOnlySignedBeaconBlock{wrappedEmpty, wrapped, copiedWrapped}) + reconstructed, err := service.ReconstructFullBellatrixBlockBatch(ctx, []interfaces.ReadOnlySignedBeaconBlock{wrappedEmpty, wrapped}) require.NoError(t, err) // Make sure empty blocks are handled correctly @@ -1024,10 +1023,6 @@ func TestReconstructFullBellatrixBlockBatch(t *testing.T) { got, err := reconstructed[1].Block().Body().Execution() require.NoError(t, err) require.DeepEqual(t, payload, got.Proto()) - - got, err = reconstructed[2].Block().Body().Execution() - require.NoError(t, err) - require.DeepEqual(t, payload, got.Proto()) }) t.Run("handles invalid response from EL", func(t *testing.T) { fix := fixtures() @@ -1094,7 +1089,7 @@ func TestReconstructFullBellatrixBlockBatch(t *testing.T) { require.NoError(t, err) _, err = service.ReconstructFullBellatrixBlockBatch(ctx, []interfaces.ReadOnlySignedBeaconBlock{wrappedEmpty, wrapped, copiedWrapped}) - require.ErrorContains(t, "mismatch of payloads retrieved from the execution client", err) + require.ErrorIs(t, err, errInvalidPayloadBodyResponse) }) } @@ -1405,6 +1400,31 @@ func newTestIPCServer(t *testing.T) *rpc.Server { } func fixtures() map[string]interface{} { + s := fixturesStruct() + return map[string]interface{}{ + "ExecutionBlock": s.ExecutionBlock, + "ExecutionPayloadBody": s.ExecutionPayloadBody, + "ExecutionPayload": s.ExecutionPayload, + "ExecutionPayloadCapella": s.ExecutionPayloadCapella, + "ExecutionPayloadDeneb": s.ExecutionPayloadDeneb, + "ExecutionPayloadElectra": s.ExecutionPayloadElectra, + "ExecutionPayloadCapellaWithValue": s.ExecutionPayloadWithValueCapella, + "ExecutionPayloadDenebWithValue": s.ExecutionPayloadWithValueDeneb, + "ExecutionPayloadElectraWithValue": s.ExecutionPayloadWithValueElectra, + "ValidPayloadStatus": s.ValidPayloadStatus, + "InvalidBlockHashStatus": s.InvalidBlockHashStatus, + "AcceptedStatus": s.AcceptedStatus, + "SyncingStatus": s.SyncingStatus, + "InvalidStatus": s.InvalidStatus, + "UnknownStatus": s.UnknownStatus, + "ForkchoiceUpdatedResponse": s.ForkchoiceUpdatedResponse, + "ForkchoiceUpdatedSyncingResponse": s.ForkchoiceUpdatedSyncingResponse, + "ForkchoiceUpdatedAcceptedResponse": s.ForkchoiceUpdatedAcceptedResponse, + "ForkchoiceUpdatedInvalidResponse": s.ForkchoiceUpdatedInvalidResponse, + } +} + +func fixturesStruct() *payloadFixtures { foo := bytesutil.ToBytes32([]byte("foo")) bar := bytesutil.PadTo([]byte("bar"), 20) baz := bytesutil.PadTo([]byte("baz"), 256) @@ -1425,8 +1445,8 @@ func fixtures() map[string]interface{} { BlockHash: foo[:], Transactions: [][]byte{foo[:]}, } - executionPayloadBodyFixture := &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{foo[:]}, + executionPayloadBodyFixture := &pb.ExecutionPayloadBody{ + Transactions: []hexutil.Bytes{foo[:]}, Withdrawals: []*pb.Withdrawal{}, } executionPayloadFixtureCapella := &pb.ExecutionPayloadCapella{ @@ -1446,7 +1466,7 @@ func fixtures() map[string]interface{} { Transactions: [][]byte{foo[:]}, Withdrawals: []*pb.Withdrawal{}, } - executionPayloadFixtureDeneb := &pb.ExecutionPayloadDeneb{ + emptyExecutionPayloadDeneb := &pb.ExecutionPayloadDeneb{ ParentHash: foo[:], FeeRecipient: bar, StateRoot: foo[:], @@ -1460,11 +1480,29 @@ func fixtures() map[string]interface{} { ExtraData: foo[:], BaseFeePerGas: bytesutil.PadTo(baseFeePerGas.Bytes(), fieldparams.RootLength), BlockHash: foo[:], - Transactions: [][]byte{foo[:]}, - Withdrawals: []*pb.Withdrawal{}, BlobGasUsed: 2, ExcessBlobGas: 3, } + executionPayloadFixtureDeneb := &pb.ExecutionPayloadDeneb{ + ParentHash: emptyExecutionPayloadDeneb.ParentHash, + FeeRecipient: emptyExecutionPayloadDeneb.FeeRecipient, + StateRoot: emptyExecutionPayloadDeneb.StateRoot, + ReceiptsRoot: emptyExecutionPayloadDeneb.ReceiptsRoot, + LogsBloom: emptyExecutionPayloadDeneb.LogsBloom, + PrevRandao: emptyExecutionPayloadDeneb.PrevRandao, + BlockNumber: emptyExecutionPayloadDeneb.BlockNumber, + GasLimit: emptyExecutionPayloadDeneb.GasLimit, + GasUsed: emptyExecutionPayloadDeneb.GasUsed, + Timestamp: emptyExecutionPayloadDeneb.Timestamp, + ExtraData: emptyExecutionPayloadDeneb.ExtraData, + BaseFeePerGas: emptyExecutionPayloadDeneb.BaseFeePerGas, + BlockHash: emptyExecutionPayloadDeneb.BlockHash, + BlobGasUsed: emptyExecutionPayloadDeneb.BlobGasUsed, + ExcessBlobGas: emptyExecutionPayloadDeneb.ExcessBlobGas, + // added on top of the empty payload + Transactions: [][]byte{foo[:]}, + Withdrawals: []*pb.Withdrawal{}, + } withdrawalRequests := make([]pb.WithdrawalRequestV1, 3) for i := range withdrawalRequests { amount := hexutil.Uint64(i) @@ -1496,9 +1534,13 @@ func fixtures() map[string]interface{} { Index: &idx, } } - outer := &pb.ExecutionPayloadElectraJSON{ - WithdrawalRequests: withdrawalRequests, - DepositRequests: depositRequests, + dr, err := pb.JsonDepositRequestsToProto(depositRequests) + if err != nil { + panic(err) + } + wr, err := pb.JsonWithdrawalRequestsToProto(withdrawalRequests) + if err != nil { + panic(err) } executionPayloadFixtureElectra := &pb.ExecutionPayloadElectra{ ParentHash: foo[:], @@ -1518,8 +1560,8 @@ func fixtures() map[string]interface{} { Withdrawals: []*pb.Withdrawal{}, BlobGasUsed: 2, ExcessBlobGas: 3, - DepositReceipts: outer.ElectraDepositReceipts(), - WithdrawalRequests: outer.ElectraExecutionLayerWithdrawalRequests(), + DepositReceipts: dr, + WithdrawalRequests: wr, } hexUint := hexutil.Uint64(1) executionPayloadWithValueFixtureCapella := &pb.GetPayloadV2ResponseJson{ @@ -1573,22 +1615,24 @@ func fixtures() map[string]interface{} { executionPayloadWithValueFixtureElectra := &pb.GetPayloadV4ResponseJson{ ShouldOverrideBuilder: true, ExecutionPayload: &pb.ExecutionPayloadElectraJSON{ - ParentHash: &common.Hash{'a'}, - FeeRecipient: &common.Address{'b'}, - StateRoot: &common.Hash{'c'}, - ReceiptsRoot: &common.Hash{'d'}, - LogsBloom: &hexutil.Bytes{'e'}, - PrevRandao: &common.Hash{'f'}, - BaseFeePerGas: "0x123", - BlockHash: &common.Hash{'g'}, - Transactions: []hexutil.Bytes{{'h'}}, - Withdrawals: []*pb.Withdrawal{}, - BlockNumber: &hexUint, - GasLimit: &hexUint, - GasUsed: &hexUint, - Timestamp: &hexUint, - BlobGasUsed: &bgu, - ExcessBlobGas: &ebg, + ParentHash: &common.Hash{'a'}, + FeeRecipient: &common.Address{'b'}, + StateRoot: &common.Hash{'c'}, + ReceiptsRoot: &common.Hash{'d'}, + LogsBloom: &hexutil.Bytes{'e'}, + PrevRandao: &common.Hash{'f'}, + BaseFeePerGas: "0x123", + BlockHash: &common.Hash{'g'}, + Transactions: []hexutil.Bytes{{'h'}}, + Withdrawals: []*pb.Withdrawal{}, + BlockNumber: &hexUint, + GasLimit: &hexUint, + GasUsed: &hexUint, + Timestamp: &hexUint, + BlobGasUsed: &bgu, + ExcessBlobGas: &ebg, + DepositRequests: depositRequests, + WithdrawalRequests: withdrawalRequests, }, BlockValue: "0x11fffffffff", BlobsBundle: &pb.BlobBundleJSON{ @@ -1681,27 +1725,52 @@ func fixtures() map[string]interface{} { Status: pb.PayloadStatus_UNKNOWN, LatestValidHash: foo[:], } - return map[string]interface{}{ - "ExecutionBlock": executionBlock, - "ExecutionPayloadBody": executionPayloadBodyFixture, - "ExecutionPayload": executionPayloadFixture, - "ExecutionPayloadCapella": executionPayloadFixtureCapella, - "ExecutionPayloadDeneb": executionPayloadFixtureDeneb, - "ExecutionPayloadElectra": executionPayloadFixtureElectra, - "ExecutionPayloadCapellaWithValue": executionPayloadWithValueFixtureCapella, - "ExecutionPayloadDenebWithValue": executionPayloadWithValueFixtureDeneb, - "ExecutionPayloadElectraWithValue": executionPayloadWithValueFixtureElectra, - "ValidPayloadStatus": validStatus, - "InvalidBlockHashStatus": inValidBlockHashStatus, - "AcceptedStatus": acceptedStatus, - "SyncingStatus": syncingStatus, - "InvalidStatus": invalidStatus, - "UnknownStatus": unknownStatus, - "ForkchoiceUpdatedResponse": forkChoiceResp, - "ForkchoiceUpdatedSyncingResponse": forkChoiceSyncingResp, - "ForkchoiceUpdatedAcceptedResponse": forkChoiceAcceptedResp, - "ForkchoiceUpdatedInvalidResponse": forkChoiceInvalidResp, + return &payloadFixtures{ + ExecutionBlock: executionBlock, + ExecutionPayloadBody: executionPayloadBodyFixture, + ExecutionPayload: executionPayloadFixture, + ExecutionPayloadCapella: executionPayloadFixtureCapella, + ExecutionPayloadDeneb: executionPayloadFixtureDeneb, + EmptyExecutionPayloadDeneb: emptyExecutionPayloadDeneb, + ExecutionPayloadElectra: executionPayloadFixtureElectra, + ExecutionPayloadWithValueCapella: executionPayloadWithValueFixtureCapella, + ExecutionPayloadWithValueDeneb: executionPayloadWithValueFixtureDeneb, + ExecutionPayloadWithValueElectra: executionPayloadWithValueFixtureElectra, + ValidPayloadStatus: validStatus, + InvalidBlockHashStatus: inValidBlockHashStatus, + AcceptedStatus: acceptedStatus, + SyncingStatus: syncingStatus, + InvalidStatus: invalidStatus, + UnknownStatus: unknownStatus, + ForkchoiceUpdatedResponse: forkChoiceResp, + ForkchoiceUpdatedSyncingResponse: forkChoiceSyncingResp, + ForkchoiceUpdatedAcceptedResponse: forkChoiceAcceptedResp, + ForkchoiceUpdatedInvalidResponse: forkChoiceInvalidResp, } + +} + +type payloadFixtures struct { + ExecutionBlock *pb.ExecutionBlock + ExecutionPayloadBody *pb.ExecutionPayloadBody + ExecutionPayload *pb.ExecutionPayload + ExecutionPayloadCapella *pb.ExecutionPayloadCapella + EmptyExecutionPayloadDeneb *pb.ExecutionPayloadDeneb + ExecutionPayloadDeneb *pb.ExecutionPayloadDeneb + ExecutionPayloadElectra *pb.ExecutionPayloadElectra + ExecutionPayloadWithValueCapella *pb.GetPayloadV2ResponseJson + ExecutionPayloadWithValueDeneb *pb.GetPayloadV3ResponseJson + ExecutionPayloadWithValueElectra *pb.GetPayloadV4ResponseJson + ValidPayloadStatus *pb.PayloadStatus + InvalidBlockHashStatus *pb.PayloadStatus + AcceptedStatus *pb.PayloadStatus + SyncingStatus *pb.PayloadStatus + InvalidStatus *pb.PayloadStatus + UnknownStatus *pb.PayloadStatus + ForkchoiceUpdatedResponse *ForkchoiceUpdatedResponse + ForkchoiceUpdatedSyncingResponse *ForkchoiceUpdatedResponse + ForkchoiceUpdatedAcceptedResponse *ForkchoiceUpdatedResponse + ForkchoiceUpdatedInvalidResponse *ForkchoiceUpdatedResponse } func TestHeaderByHash_NotFound(t *testing.T) { @@ -2084,507 +2153,35 @@ func newPayloadV4Setup(t *testing.T, status *pb.PayloadStatus, payload *pb.Execu return service } -func TestCapella_PayloadBodiesByHash(t *testing.T) { +func TestReconstructBlindedBlockBatch(t *testing.T) { t.Run("empty response works", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 0) - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{}) - require.NoError(t, err) - require.Equal(t, 0, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("single element response null works", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) - executionPayloadBodies[0] = nil - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - bRoot := [32]byte{} - copy(bRoot[:], "hash") - results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{bRoot}) - require.NoError(t, err) - require.Equal(t, 1, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("empty, null, full works", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{}, - Withdrawals: []*pb.Withdrawal{}, - } - executionPayloadBodies[1] = nil - executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 1, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - bRoot := [32]byte{} - copy(bRoot[:], "hash") - results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{bRoot, bRoot, bRoot}) - require.NoError(t, err) - require.Equal(t, 3, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("full works, single item", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 1, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - bRoot := [32]byte{} - copy(bRoot[:], "hash") - results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{bRoot}) - require.NoError(t, err) - require.Equal(t, 1, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("full works, multiple items", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 2) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 1, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - executionPayloadBodies[1] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 2, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) ctx := context.Background() + cli, srv := newMockEngine(t) + srv.registerDefault(func(*jsonrpcMessage, http.ResponseWriter, *http.Request) { - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - bRoot := [32]byte{} - copy(bRoot[:], "hash") - results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{bRoot, bRoot}) - require.NoError(t, err) - require.Equal(t, 2, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("returning empty, null, empty should work properly", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - // [A, B, C] but no B in the server means - // we get [Abody, null, Cbody]. - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{}, - Withdrawals: []*pb.Withdrawal{}, - } - executionPayloadBodies[1] = nil - executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{}, - Withdrawals: []*pb.Withdrawal{}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - bRoot := [32]byte{} - copy(bRoot[:], "hash") - results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{bRoot, bRoot, bRoot}) - require.NoError(t, err) - require.Equal(t, 3, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) -} - -func TestCapella_PayloadBodiesByRange(t *testing.T) { - t.Run("empty response works", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 0) - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + t.Fatal("http request should not be made") + }) + results, err := reconstructBlindedBlockBatch(ctx, cli, []interfaces.ReadOnlySignedBeaconBlock{}) require.NoError(t, err) require.Equal(t, 0, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } }) - t.Run("single element response null works", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) - executionPayloadBodies[0] = nil - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) + t.Run("expected error for nil response", func(t *testing.T) { ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) + slot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch) require.NoError(t, err) - require.Equal(t, 1, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("empty, null, full works", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{}, - Withdrawals: []*pb.Withdrawal{}, - } - executionPayloadBodies[1] = nil - executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 1, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) - require.NoError(t, err) - require.Equal(t, 3, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("full works, single item", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 1) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 1, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) - require.NoError(t, err) - require.Equal(t, 1, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("full works, multiple items", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 2) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 1, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - executionPayloadBodies[1] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{hexutil.MustDecode("0x02f878831469668303f51d843b9ac9f9843b9aca0082520894c93269b73096998db66be0441e836d873535cb9c8894a19041886f000080c001a031cc29234036afbf9a1fb9476b463367cb1f957ac0b919b69bbc798436e604aaa018c4e9c3914eb27aadd0b91e10b18655739fcf8c1fc398763a9f1beecb8ddc86")}, - Withdrawals: []*pb.Withdrawal{{ - Index: 2, - ValidatorIndex: 1, - Address: hexutil.MustDecode("0xcf8e0d4e9587369b2301d0790347320302cc0943"), - Amount: 1, - }}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() - - rpcClient, err := rpc.DialHTTP(srv.URL) - require.NoError(t, err) - - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) - require.NoError(t, err) - require.Equal(t, 2, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } - }) - t.Run("returning empty, null, empty should work properly", func(t *testing.T) { - srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.Header().Set("Content-Type", "application/json") - defer func() { - require.NoError(t, r.Body.Close()) - }() - // [A, B, C] but no B in the server means - // we get [Abody, null, Cbody]. - executionPayloadBodies := make([]*pb.ExecutionPayloadBodyV1, 3) - executionPayloadBodies[0] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{}, - Withdrawals: []*pb.Withdrawal{}, - } - executionPayloadBodies[1] = nil - executionPayloadBodies[2] = &pb.ExecutionPayloadBodyV1{ - Transactions: [][]byte{}, - Withdrawals: []*pb.Withdrawal{}, - } - - resp := map[string]interface{}{ - "jsonrpc": "2.0", - "id": 1, - "result": executionPayloadBodies, - } - err := json.NewEncoder(w).Encode(resp) - require.NoError(t, err) - })) - ctx := context.Background() + blk, _ := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, slot, 0) + cli, srv := newMockEngine(t) + srv.registerDefault(func(msg *jsonrpcMessage, w http.ResponseWriter, req *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{nil} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) - rpcClient, err := rpc.DialHTTP(srv.URL) + blinded, err := blk.ToBlinded() require.NoError(t, err) - service := &Service{} - service.rpcClient = rpcClient - - results, err := service.GetPayloadBodiesByRange(ctx, uint64(1), uint64(2)) - require.NoError(t, err) - require.Equal(t, 3, len(results)) - - for _, item := range results { - require.NotNil(t, item) - } + service.rpcClient = cli + _, err = service.ReconstructFullBlock(ctx, blinded) + require.ErrorIs(t, err, errNilPayloadBody) }) } diff --git a/beacon-chain/execution/mock_test.go b/beacon-chain/execution/mock_test.go new file mode 100644 index 000000000000..a77c83ecc446 --- /dev/null +++ b/beacon-chain/execution/mock_test.go @@ -0,0 +1,221 @@ +package execution + +import ( + "context" + "encoding/json" + "math" + "net/http" + "net/http/httptest" + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/ethereum/go-ethereum/rpc" + pb "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + "github.com/prysmaticlabs/prysm/v5/testing/require" +) + +var mockHandlerDefaultName = "__default__" + +type jsonError struct { + Code int `json:"code"` + Message string `json:"message"` + Data interface{} `json:"data,omitempty"` +} + +type jsonrpcMessage struct { + Version string `json:"jsonrpc,omitempty"` + ID json.RawMessage `json:"id,omitempty"` + Method string `json:"method,omitempty"` + Params json.RawMessage `json:"params,omitempty"` + Error *jsonError `json:"error,omitempty"` + Result json.RawMessage `json:"result,omitempty"` +} + +type mockHandler func(*jsonrpcMessage, http.ResponseWriter, *http.Request) + +type mockEngine struct { + t *testing.T + handlers map[string]mockHandler + calls map[string][]*jsonrpcMessage +} + +func newMockEngine(t *testing.T) (*rpc.Client, *mockEngine) { + s := &mockEngine{t: t, handlers: make(map[string]mockHandler), calls: make(map[string][]*jsonrpcMessage)} + srv := httptest.NewServer(s) + c, err := rpc.DialHTTP(srv.URL) + require.NoError(t, err) + return c, s +} + +func (s *mockEngine) ServeHTTP(w http.ResponseWriter, r *http.Request) { + msg := &jsonrpcMessage{} + defer func() { + s.calls[msg.Method] = append(s.calls[msg.Method], msg) + }() + if err := json.NewDecoder(r.Body).Decode(msg); err != nil { + http.Error(w, "failed to decode request: "+err.Error(), http.StatusBadRequest) + return + } + w.Header().Set("Content-Type", "application/json") + defer func() { + require.NoError(s.t, r.Body.Close()) + }() + handler, ok := s.handlers[msg.Method] + if !ok { + // Fallback to default handler if it is registered. + handler, ok = s.handlers[mockHandlerDefaultName] + if !ok { + s.t.Fatalf("mockEngine called with unexpected method %s", msg.Method) + } + } + handler(msg, w, r) +} + +func (s *mockEngine) register(method string, handler mockHandler) { + s.handlers[method] = handler +} + +func (s *mockEngine) registerDefault(handler mockHandler) { + s.handlers[mockHandlerDefaultName] = handler +} + +func (s *mockEngine) callCount(method string) int { + return len(s.calls[method]) +} + +func mockParseUintList(t *testing.T, data json.RawMessage) []uint64 { + var list []uint64 + if err := json.Unmarshal(data, &list); err != nil { + t.Fatalf("failed to parse uint list: %v", err) + } + return list +} + +func mockParseHexByteList(t *testing.T, data json.RawMessage) []hexutil.Bytes { + var list [][]hexutil.Bytes + if err := json.Unmarshal(data, &list); err != nil { + t.Fatalf("failed to parse hex byte list: %v", err) + } + require.Equal(t, 1, len(list)) + return list[0] +} + +func strToHexBytes(t *testing.T, s string) hexutil.Bytes { + b := hexutil.Bytes{} + require.NoError(t, b.UnmarshalText([]byte(s))) + return b +} + +func mockWriteResult(t *testing.T, w http.ResponseWriter, req *jsonrpcMessage, result any) { + marshaled, err := json.Marshal(result) + require.NoError(t, err) + req.Result = marshaled + require.NoError(t, json.NewEncoder(w).Encode(req)) +} + +func TestParseRequest(t *testing.T) { + ctx := context.Background() + cases := []struct { + method string + uintArgs []uint64 + byteArgs []hexutil.Bytes + }{ + { + method: GetPayloadBodiesByHashV1, + byteArgs: []hexutil.Bytes{ + strToHexBytes(t, "0x656d707479000000000000000000000000000000000000000000000000000000"), + strToHexBytes(t, "0x66756c6c00000000000000000000000000000000000000000000000000000000"), + }, + }, + { + method: GetPayloadBodiesByHashV2, + byteArgs: []hexutil.Bytes{ + strToHexBytes(t, "0x656d707479000000000000000000000000000000000000000000000000000000"), + strToHexBytes(t, "0x66756c6c00000000000000000000000000000000000000000000000000000000"), + }, + }, + { + method: GetPayloadBodiesByRangeV1, + uintArgs: []uint64{0, 1}, + }, + { + method: GetPayloadBodiesByRangeV2, + uintArgs: []uint64{math.MaxUint64, 1}, + }, + } + for _, c := range cases { + t.Run(c.method, func(t *testing.T) { + cli, srv := newMockEngine(t) + srv.register(c.method, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + require.Equal(t, c.method, msg.Method) + nr := uint64(len(c.byteArgs)) + if len(c.byteArgs) > 0 { + require.DeepEqual(t, c.byteArgs, mockParseHexByteList(t, msg.Params)) + } + if len(c.uintArgs) > 0 { + rang := mockParseUintList(t, msg.Params) + require.DeepEqual(t, c.uintArgs, rang) + nr = rang[1] + } + mockWriteResult(t, w, msg, make([]*pb.ExecutionPayloadBody, nr)) + }) + + result := make([]*pb.ExecutionPayloadBody, 0) + var args []interface{} + if len(c.byteArgs) > 0 { + args = []interface{}{c.byteArgs} + } + if len(c.uintArgs) > 0 { + args = make([]interface{}, len(c.uintArgs)) + for i := range c.uintArgs { + args[i] = c.uintArgs[i] + } + } + require.NoError(t, cli.CallContext(ctx, &result, c.method, args...)) + if len(c.byteArgs) > 0 { + require.Equal(t, len(c.byteArgs), len(result)) + } + if len(c.uintArgs) > 0 { + require.Equal(t, int(c.uintArgs[1]), len(result)) + } + }) + } +} + +func TestCallCount(t *testing.T) { + methods := []string{ + GetPayloadBodiesByHashV1, + GetPayloadBodiesByHashV2, + GetPayloadBodiesByRangeV1, + GetPayloadBodiesByRangeV2, + } + cases := []struct { + method string + count int + }{ + {method: GetPayloadBodiesByHashV1, count: 1}, + {method: GetPayloadBodiesByHashV1, count: 2}, + {method: GetPayloadBodiesByHashV2, count: 1}, + {method: GetPayloadBodiesByRangeV1, count: 1}, + {method: GetPayloadBodiesByRangeV1, count: 2}, + {method: GetPayloadBodiesByRangeV2, count: 1}, + } + for _, c := range cases { + t.Run(c.method, func(t *testing.T) { + cli, srv := newMockEngine(t) + srv.register(c.method, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + mockWriteResult(t, w, msg, nil) + }) + for i := 0; i < c.count; i++ { + require.NoError(t, cli.CallContext(context.Background(), nil, c.method)) + } + for _, m := range methods { + if m == c.method { + require.Equal(t, c.count, srv.callCount(m)) + } else { + require.Equal(t, 0, srv.callCount(m)) + } + } + }) + } +} diff --git a/beacon-chain/execution/payload_body.go b/beacon-chain/execution/payload_body.go new file mode 100644 index 000000000000..71e8f7473978 --- /dev/null +++ b/beacon-chain/execution/payload_body.go @@ -0,0 +1,250 @@ +package execution + +import ( + "context" + "sort" + + "github.com/ethereum/go-ethereum/common" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + pb "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" + "google.golang.org/protobuf/proto" +) + +var errNilPayloadBody = errors.New("nil payload body for block") + +type blockWithHeader struct { + block interfaces.ReadOnlySignedBeaconBlock + header interfaces.ExecutionData +} + +// reconstructionBatch is a map of block hashes to block numbers. +type reconstructionBatch map[[32]byte]uint64 + +type blindedBlockReconstructor struct { + orderedBlocks []*blockWithHeader + bodies map[[32]byte]*pb.ExecutionPayloadBody + batches map[string]reconstructionBatch +} + +func reconstructBlindedBlockBatch(ctx context.Context, client RPCClient, sbb []interfaces.ReadOnlySignedBeaconBlock) ([]interfaces.SignedBeaconBlock, error) { + r, err := newBlindedBlockReconstructor(sbb) + if err != nil { + return nil, err + } + if err := r.requestBodies(ctx, client); err != nil { + return nil, err + } + return r.unblinded() +} + +func newBlindedBlockReconstructor(sbb []interfaces.ReadOnlySignedBeaconBlock) (*blindedBlockReconstructor, error) { + r := &blindedBlockReconstructor{ + orderedBlocks: make([]*blockWithHeader, 0, len(sbb)), + bodies: make(map[[32]byte]*pb.ExecutionPayloadBody), + } + for i := range sbb { + if err := r.addToBatch(sbb[i]); err != nil { + return nil, err + } + } + return r, nil +} + +func (r *blindedBlockReconstructor) addToBatch(b interfaces.ReadOnlySignedBeaconBlock) error { + if err := blocks.BeaconBlockIsNil(b); err != nil { + return errors.Wrap(err, "cannot reconstruct bellatrix block from nil data") + } + if !b.Block().IsBlinded() { + return errors.New("can only reconstruct block from blinded block format") + } + header, err := b.Block().Body().Execution() + if err != nil { + return err + } + if header.IsNil() { + return errors.New("execution payload header in blinded block was nil") + } + r.orderedBlocks = append(r.orderedBlocks, &blockWithHeader{block: b, header: header}) + blockHash := bytesutil.ToBytes32(header.BlockHash()) + if blockHash == params.BeaconConfig().ZeroHash { + return nil + } + + method := payloadBodyMethodForBlock(b) + if r.batches == nil { + r.batches = make(map[string]reconstructionBatch) + } + if _, ok := r.batches[method]; !ok { + r.batches[method] = make(reconstructionBatch) + } + r.batches[method][bytesutil.ToBytes32(header.BlockHash())] = header.BlockNumber() + return nil +} + +func payloadBodyMethodForBlock(b interface{ Version() int }) string { + if b.Version() > version.Deneb { + return GetPayloadBodiesByHashV2 + } + return GetPayloadBodiesByHashV1 +} + +func (r *blindedBlockReconstructor) requestBodies(ctx context.Context, client RPCClient) error { + for method := range r.batches { + nilResults, err := r.requestBodiesByHash(ctx, client, method) + if err != nil { + return err + } + if err := r.handleNilResults(ctx, client, method, nilResults); err != nil { + return err + } + } + return nil +} + +type hashBlockNumber struct { + h [32]byte + n uint64 +} + +func (r *blindedBlockReconstructor) handleNilResults(ctx context.Context, client RPCClient, method string, nilResults [][32]byte) error { + if len(nilResults) == 0 { + return nil + } + hbns := make([]hashBlockNumber, len(nilResults)) + for i := range nilResults { + h := nilResults[i] + hbns[i] = hashBlockNumber{h: h, n: r.batches[method][h]} + } + reqs := computeRanges(hbns) + for i := range reqs { + if err := r.requestBodiesByRange(ctx, client, rangeMethodForHashMethod(method), reqs[i]); err != nil { + return err + } + } + return nil +} + +type byRangeReq struct { + start uint64 + count uint64 + hbns []hashBlockNumber +} + +func computeRanges(hbns []hashBlockNumber) []byRangeReq { + if len(hbns) == 0 { + return nil + } + sort.Slice(hbns, func(i, j int) bool { + return hbns[i].n < hbns[j].n + }) + ranges := make([]byRangeReq, 0) + start := hbns[0].n + count := uint64(0) + for i := 0; i < len(hbns); i++ { + if hbns[i].n == start+count { + count++ + continue + } + ranges = append(ranges, byRangeReq{start: start, count: count, hbns: hbns[uint64(i)-count : i]}) + start = hbns[i].n + count = 1 + } + ranges = append(ranges, byRangeReq{start: start, count: count, hbns: hbns[uint64(len(hbns))-count:]}) + return ranges +} + +func (r *blindedBlockReconstructor) requestBodiesByRange(ctx context.Context, client RPCClient, method string, req byRangeReq) error { + result := make([]*pb.ExecutionPayloadBody, 0) + if err := client.CallContext(ctx, &result, method, req.start, req.count); err != nil { + return err + } + if uint64(len(result)) != req.count { + return errors.Wrapf(errInvalidPayloadBodyResponse, "received %d payload bodies from %s with count=%d (start=%d)", len(result), method, req.count, req.start) + } + for i := range result { + if result[i] == nil { + return errors.Wrapf(errNilPayloadBody, "from %s, hash=%#x", method, req.hbns[i].h) + } + r.bodies[req.hbns[i].h] = result[i] + } + return nil +} + +func (r *blindedBlockReconstructor) requestBodiesByHash(ctx context.Context, client RPCClient, method string) ([][32]byte, error) { + batch := r.batches[method] + if len(batch) == 0 { + return nil, nil + } + hashes := make([]common.Hash, 0, len(batch)) + for h := range batch { + if h == params.BeaconConfig().ZeroHash { + continue + } + hashes = append(hashes, h) + } + result := make([]*pb.ExecutionPayloadBody, 0) + if err := client.CallContext(ctx, &result, method, hashes); err != nil { + return nil, err + } + if len(hashes) != len(result) { + return nil, errors.Wrapf(errInvalidPayloadBodyResponse, "received %d payload bodies for %d requested hashes", len(result), len(hashes)) + } + nilBodies := make([][32]byte, 0) + for i := range result { + if result[i] == nil { + nilBodies = append(nilBodies, hashes[i]) + continue + } + r.bodies[hashes[i]] = result[i] + } + return nilBodies, nil +} + +func (r *blindedBlockReconstructor) payloadForHeader(header interfaces.ExecutionData, v int) (proto.Message, error) { + bodyKey := bytesutil.ToBytes32(header.BlockHash()) + if bodyKey == params.BeaconConfig().ZeroHash { + payload, err := buildEmptyExecutionPayload(v) + if err != nil { + return nil, errors.Wrapf(err, "failed to reconstruct payload for body hash %#x", bodyKey) + } + return payload, nil + } + body, ok := r.bodies[bodyKey] + if !ok { + return nil, errors.Wrapf(errNilPayloadBody, "hash %#x", bodyKey) + } + ed, err := fullPayloadFromPayloadBody(header, body, v) + if err != nil { + return nil, errors.Wrapf(err, "failed to reconstruct payload for body hash %#x", bodyKey) + } + return ed.Proto(), nil +} + +func (r *blindedBlockReconstructor) unblinded() ([]interfaces.SignedBeaconBlock, error) { + unblinded := make([]interfaces.SignedBeaconBlock, len(r.orderedBlocks)) + for i := range r.orderedBlocks { + blk, header := r.orderedBlocks[i].block, r.orderedBlocks[i].header + payload, err := r.payloadForHeader(header, blk.Version()) + if err != nil { + return nil, err + } + full, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(blk, payload) + if err != nil { + return nil, errors.Wrapf(err, "failed to build full block from execution payload for block hash %#x", header.BlockHash()) + } + unblinded[i] = full + } + return unblinded, nil +} + +func rangeMethodForHashMethod(method string) string { + if method == GetPayloadBodiesByHashV2 { + return GetPayloadBodiesByRangeV2 + } + return GetPayloadBodiesByRangeV1 +} diff --git a/beacon-chain/execution/payload_body_test.go b/beacon-chain/execution/payload_body_test.go new file mode 100644 index 000000000000..8b95141b30c9 --- /dev/null +++ b/beacon-chain/execution/payload_body_test.go @@ -0,0 +1,408 @@ +package execution + +import ( + "context" + "net/http" + "testing" + + "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v5/consensus-types/interfaces" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + pb "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" + "github.com/prysmaticlabs/prysm/v5/runtime/version" + "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/testing/util" + "github.com/prysmaticlabs/prysm/v5/time/slots" +) + +type versioner struct { + version int +} + +func (v versioner) Version() int { + return v.version +} + +func TestPayloadBodyMethodForBlock(t *testing.T) { + cases := []struct { + versions []int + want string + }{ + { + versions: []int{version.Phase0, version.Altair, version.Bellatrix, version.Capella, version.Deneb}, + want: GetPayloadBodiesByHashV1, + }, + { + versions: []int{version.Electra}, + want: GetPayloadBodiesByHashV2, + }, + } + for _, c := range cases { + for _, v := range c.versions { + t.Run(version.String(v), func(t *testing.T) { + v := versioner{version: v} + require.Equal(t, c.want, payloadBodyMethodForBlock(v)) + }) + } + } + t.Run("post-electra", func(t *testing.T) { + require.Equal(t, GetPayloadBodiesByHashV2, payloadBodyMethodForBlock(versioner{version: version.Electra + 1})) + }) +} + +func payloadToBody(t *testing.T, ed interfaces.ExecutionData) *pb.ExecutionPayloadBody { + body := &pb.ExecutionPayloadBody{} + txs, err := ed.Transactions() + require.NoError(t, err) + wd, err := ed.Withdrawals() + // Bellatrix does not have withdrawals and will return an error. + if err == nil { + body.Withdrawals = wd + } + for i := range txs { + body.Transactions = append(body.Transactions, txs[i]) + } + eed, isElectra := ed.(interfaces.ExecutionDataElectra) + if isElectra { + body.DepositRequests = pb.ProtoDepositRequestsToJson(eed.DepositReceipts()) + body.WithdrawalRequests = pb.ProtoWithdrawalRequestsToJson(eed.WithdrawalRequests()) + } + return body +} + +type blindedBlockFixtures struct { + denebBlock *fullAndBlinded + emptyDenebBlock *fullAndBlinded + afterSkipDeneb *fullAndBlinded + electra *fullAndBlinded +} + +type fullAndBlinded struct { + full interfaces.ReadOnlySignedBeaconBlock + blinded *blockWithHeader +} + +func blindedBlockWithHeader(t *testing.T, b interfaces.ReadOnlySignedBeaconBlock) *fullAndBlinded { + header, err := b.Block().Body().Execution() + require.NoError(t, err) + blinded, err := b.ToBlinded() + require.NoError(t, err) + return &fullAndBlinded{ + full: b, + blinded: &blockWithHeader{ + block: blinded, + header: header, + }} +} + +func denebSlot(t *testing.T) primitives.Slot { + s, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch) + require.NoError(t, err) + return s +} + +func electraSlot(t *testing.T) primitives.Slot { + s, err := slots.EpochStart(params.BeaconConfig().ElectraForkEpoch) + require.NoError(t, err) + return s +} + +func testBlindedBlockFixtures(t *testing.T) *blindedBlockFixtures { + pfx := fixturesStruct() + fx := &blindedBlockFixtures{} + full := pfx.ExecutionPayloadDeneb + // this func overrides fixture blockhashes to ensure they are unique + full.BlockHash = bytesutil.PadTo([]byte("full"), 32) + denebBlock, _ := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, denebSlot(t), 0, util.WithPayloadSetter(full)) + fx.denebBlock = blindedBlockWithHeader(t, denebBlock) + + empty := pfx.EmptyExecutionPayloadDeneb + empty.BlockHash = bytesutil.PadTo([]byte("empty"), 32) + empty.BlockNumber = 2 + emptyDenebBlock, _ := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, denebSlot(t)+1, 0, util.WithPayloadSetter(empty)) + fx.emptyDenebBlock = blindedBlockWithHeader(t, emptyDenebBlock) + + afterSkip := fixturesStruct().ExecutionPayloadDeneb + // this func overrides fixture blockhashes to ensure they are unique + afterSkip.BlockHash = bytesutil.PadTo([]byte("afterSkip"), 32) + afterSkip.BlockNumber = 4 + afterSkipBlock, _ := util.GenerateTestDenebBlockWithSidecar(t, [32]byte{}, denebSlot(t)+3, 0, util.WithPayloadSetter(afterSkip)) + fx.afterSkipDeneb = blindedBlockWithHeader(t, afterSkipBlock) + + electra := fixturesStruct().ExecutionPayloadElectra + electra.BlockHash = bytesutil.PadTo([]byte("electra"), 32) + electra.BlockNumber = 5 + electraBlock, _ := util.GenerateTestElectraBlockWithSidecar(t, [32]byte{}, electraSlot(t), 0, util.WithElectraPayload(electra)) + fx.electra = blindedBlockWithHeader(t, electraBlock) + return fx +} + +func TestPayloadBodiesViaUnblinder(t *testing.T) { + fx := testBlindedBlockFixtures(t) + t.Run("mix of non-empty and empty", func(t *testing.T) { + cli, srv := newMockEngine(t) + srv.register(GetPayloadBodiesByHashV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{ + payloadToBody(t, fx.denebBlock.blinded.header), + payloadToBody(t, fx.emptyDenebBlock.blinded.header), + } + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + ctx := context.Background() + + toUnblind := []interfaces.ReadOnlySignedBeaconBlock{ + fx.denebBlock.blinded.block, + fx.emptyDenebBlock.blinded.block, + } + bbr, err := newBlindedBlockReconstructor(toUnblind) + require.NoError(t, err) + require.NoError(t, bbr.requestBodies(ctx, cli)) + + payload, err := bbr.payloadForHeader(fx.denebBlock.blinded.header, fx.denebBlock.blinded.block.Version()) + require.NoError(t, err) + unblindFull, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(fx.denebBlock.blinded.block, payload) + require.NoError(t, err) + testAssertReconstructedEquivalent(t, fx.denebBlock.full, unblindFull) + + emptyPayload, err := bbr.payloadForHeader(fx.emptyDenebBlock.blinded.header, fx.emptyDenebBlock.blinded.block.Version()) + require.NoError(t, err) + unblindEmpty, err := blocks.BuildSignedBeaconBlockFromExecutionPayload(fx.emptyDenebBlock.blinded.block, emptyPayload) + require.NoError(t, err) + testAssertReconstructedEquivalent(t, fx.emptyDenebBlock.full, unblindEmpty) + }) +} + +func TestFixtureEquivalence(t *testing.T) { + fx := testBlindedBlockFixtures(t) + t.Run("full and blinded block equivalence", func(t *testing.T) { + testAssertReconstructedEquivalent(t, fx.denebBlock.blinded.block, fx.denebBlock.full) + testAssertReconstructedEquivalent(t, fx.emptyDenebBlock.blinded.block, fx.emptyDenebBlock.full) + }) +} + +func testAssertReconstructedEquivalent(t *testing.T, b, ogb interfaces.ReadOnlySignedBeaconBlock) { + bHtr, err := b.Block().HashTreeRoot() + require.NoError(t, err) + ogbHtr, err := ogb.Block().HashTreeRoot() + require.NoError(t, err) + require.Equal(t, bHtr, ogbHtr) +} + +func TestComputeRanges(t *testing.T) { + cases := []struct { + name string + hbns []hashBlockNumber + want []byRangeReq + }{ + { + name: "3 contiguous, 1 not", + hbns: []hashBlockNumber{ + {h: [32]byte{5}, n: 5}, + {h: [32]byte{3}, n: 3}, + {h: [32]byte{2}, n: 2}, + {h: [32]byte{1}, n: 1}, + }, + want: []byRangeReq{ + {start: 1, count: 3, hbns: []hashBlockNumber{{h: [32]byte{1}, n: 1}, {h: [32]byte{2}, n: 2}, {h: [32]byte{3}, n: 3}}}, + {start: 5, count: 1, hbns: []hashBlockNumber{{h: [32]byte{5}, n: 5}}}, + }, + }, + { + name: "1 element", + hbns: []hashBlockNumber{ + {h: [32]byte{1}, n: 1}, + }, + want: []byRangeReq{ + {start: 1, count: 1, hbns: []hashBlockNumber{{h: [32]byte{1}, n: 1}}}, + }, + }, + { + name: "2 contiguous", + hbns: []hashBlockNumber{ + {h: [32]byte{2}, n: 2}, + {h: [32]byte{1}, n: 1}, + }, + want: []byRangeReq{ + {start: 1, count: 2, hbns: []hashBlockNumber{{h: [32]byte{1}, n: 1}, {h: [32]byte{2}, n: 2}}}, + }, + }, + { + name: "2 non-contiguous", + hbns: []hashBlockNumber{ + {h: [32]byte{3}, n: 3}, + {h: [32]byte{1}, n: 1}, + }, + want: []byRangeReq{ + {start: 1, count: 1, hbns: []hashBlockNumber{{h: [32]byte{1}, n: 1}}}, + {start: 3, count: 1, hbns: []hashBlockNumber{{h: [32]byte{3}, n: 3}}}, + }, + }, + { + name: "3 contiguous", + hbns: []hashBlockNumber{ + {h: [32]byte{2}, n: 2}, + {h: [32]byte{1}, n: 1}, + {h: [32]byte{3}, n: 3}, + }, + want: []byRangeReq{ + {start: 1, count: 3, hbns: []hashBlockNumber{{h: [32]byte{1}, n: 1}, {h: [32]byte{2}, n: 2}, {h: [32]byte{3}, n: 3}}}, + }, + }, + { + name: "3 non-contiguous", + hbns: []hashBlockNumber{ + {h: [32]byte{5}, n: 5}, + {h: [32]byte{3}, n: 3}, + {h: [32]byte{1}, n: 1}, + }, + want: []byRangeReq{ + {start: 1, count: 1, hbns: []hashBlockNumber{{h: [32]byte{1}, n: 1}}}, + {start: 3, count: 1, hbns: []hashBlockNumber{{h: [32]byte{3}, n: 3}}}, + {start: 5, count: 1, hbns: []hashBlockNumber{{h: [32]byte{5}, n: 5}}}, + }, + }, + } + for _, c := range cases { + t.Run(c.name, func(t *testing.T) { + got := computeRanges(c.hbns) + for i := range got { + require.Equal(t, c.want[i].start, got[i].start) + require.Equal(t, c.want[i].count, got[i].count) + require.DeepEqual(t, c.want[i].hbns, got[i].hbns) + } + }) + } +} + +func TestReconstructBlindedBlockBatchFallbackToRange(t *testing.T) { + undo := util.HackElectraMaxuint(t) + defer undo() + ctx := context.Background() + t.Run("fallback fails", func(t *testing.T) { + cli, srv := newMockEngine(t) + fx := testBlindedBlockFixtures(t) + srv.register(GetPayloadBodiesByHashV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{nil, nil} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + srv.register(GetPayloadBodiesByRangeV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{nil, nil} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + toUnblind := []interfaces.ReadOnlySignedBeaconBlock{ + fx.denebBlock.blinded.block, + fx.emptyDenebBlock.blinded.block, + } + _, err := reconstructBlindedBlockBatch(ctx, cli, toUnblind) + require.ErrorIs(t, err, errNilPayloadBody) + require.Equal(t, 1, srv.callCount(GetPayloadBodiesByHashV1)) + require.Equal(t, 1, srv.callCount(GetPayloadBodiesByRangeV1)) + }) + t.Run("fallback succeeds", func(t *testing.T) { + cli, srv := newMockEngine(t) + fx := testBlindedBlockFixtures(t) + srv.register(GetPayloadBodiesByHashV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{nil, nil} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + srv.register(GetPayloadBodiesByRangeV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{ + payloadToBody(t, fx.denebBlock.blinded.header), + payloadToBody(t, fx.emptyDenebBlock.blinded.header), + } + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + unblind := []interfaces.ReadOnlySignedBeaconBlock{ + fx.denebBlock.blinded.block, + fx.emptyDenebBlock.blinded.block, + } + _, err := reconstructBlindedBlockBatch(ctx, cli, unblind) + require.NoError(t, err) + }) + t.Run("separated by block number gap", func(t *testing.T) { + cli, srv := newMockEngine(t) + fx := testBlindedBlockFixtures(t) + srv.register(GetPayloadBodiesByHashV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{nil, nil, nil} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + srv.register(GetPayloadBodiesByRangeV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + p := mockParseUintList(t, msg.Params) + require.Equal(t, 2, len(p)) + start, count := p[0], p[1] + // Return first 2 blocks by number, which are contiguous. + if start == fx.denebBlock.blinded.header.BlockNumber() { + require.Equal(t, uint64(2), count) + executionPayloadBodies := []*pb.ExecutionPayloadBody{ + payloadToBody(t, fx.denebBlock.blinded.header), + payloadToBody(t, fx.emptyDenebBlock.blinded.header), + } + mockWriteResult(t, w, msg, executionPayloadBodies) + return + } + // Assume it's the second request + require.Equal(t, fx.afterSkipDeneb.blinded.header.BlockNumber(), start) + require.Equal(t, uint64(1), count) + executionPayloadBodies := []*pb.ExecutionPayloadBody{ + payloadToBody(t, fx.afterSkipDeneb.blinded.header), + } + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + // separate methods for the electra block + srv.register(GetPayloadBodiesByHashV2, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{nil} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + srv.register(GetPayloadBodiesByRangeV2, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + p := mockParseUintList(t, msg.Params) + require.Equal(t, 2, len(p)) + start, count := p[0], p[1] + require.Equal(t, fx.electra.blinded.header.BlockNumber(), start) + require.Equal(t, uint64(1), count) + executionPayloadBodies := []*pb.ExecutionPayloadBody{ + payloadToBody(t, fx.electra.blinded.header), + } + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + blind := []interfaces.ReadOnlySignedBeaconBlock{ + fx.denebBlock.blinded.block, + fx.emptyDenebBlock.blinded.block, + fx.afterSkipDeneb.blinded.block, + } + unblind, err := reconstructBlindedBlockBatch(ctx, cli, blind) + require.NoError(t, err) + for i := range unblind { + testAssertReconstructedEquivalent(t, blind[i], unblind[i]) + } + }) +} + +func TestReconstructBlindedBlockBatchDenebAndElectra(t *testing.T) { + undo := util.HackElectraMaxuint(t) + defer undo() + t.Run("deneb and electra", func(t *testing.T) { + cli, srv := newMockEngine(t) + fx := testBlindedBlockFixtures(t) + // The reconstructed should make separate calls for the deneb (v1) and electra (v2) blocks. + srv.register(GetPayloadBodiesByHashV1, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{payloadToBody(t, fx.denebBlock.blinded.header)} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + srv.register(GetPayloadBodiesByHashV2, func(msg *jsonrpcMessage, w http.ResponseWriter, r *http.Request) { + executionPayloadBodies := []*pb.ExecutionPayloadBody{payloadToBody(t, fx.electra.blinded.header)} + mockWriteResult(t, w, msg, executionPayloadBodies) + }) + blinded := []interfaces.ReadOnlySignedBeaconBlock{ + fx.denebBlock.blinded.block, + fx.electra.blinded.block, + } + unblinded, err := reconstructBlindedBlockBatch(context.Background(), cli, blinded) + require.NoError(t, err) + require.Equal(t, len(blinded), len(unblinded)) + for i := range unblinded { + testAssertReconstructedEquivalent(t, blinded[i], unblinded[i]) + } + }) +} diff --git a/proto/engine/v1/execution_engine.pb.go b/proto/engine/v1/execution_engine.pb.go index 2464d30de932..3bf7788d62e5 100755 --- a/proto/engine/v1/execution_engine.pb.go +++ b/proto/engine/v1/execution_engine.pb.go @@ -78,7 +78,7 @@ func (x PayloadStatus_Status) Number() protoreflect.EnumNumber { // Deprecated: Use PayloadStatus_Status.Descriptor instead. func (PayloadStatus_Status) EnumDescriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{15, 0} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{14, 0} } type ExecutionPayload struct { @@ -232,61 +232,6 @@ func (x *ExecutionPayload) GetTransactions() [][]byte { return nil } -type ExecutionPayloadBodyV1 struct { - state protoimpl.MessageState - sizeCache protoimpl.SizeCache - unknownFields protoimpl.UnknownFields - - Transactions [][]byte `protobuf:"bytes,1,rep,name=transactions,proto3" json:"transactions,omitempty"` - Withdrawals []*Withdrawal `protobuf:"bytes,2,rep,name=withdrawals,proto3" json:"withdrawals,omitempty"` -} - -func (x *ExecutionPayloadBodyV1) Reset() { - *x = ExecutionPayloadBodyV1{} - if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - ms.StoreMessageInfo(mi) - } -} - -func (x *ExecutionPayloadBodyV1) String() string { - return protoimpl.X.MessageStringOf(x) -} - -func (*ExecutionPayloadBodyV1) ProtoMessage() {} - -func (x *ExecutionPayloadBodyV1) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] - if protoimpl.UnsafeEnabled && x != nil { - ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) - if ms.LoadMessageInfo() == nil { - ms.StoreMessageInfo(mi) - } - return ms - } - return mi.MessageOf(x) -} - -// Deprecated: Use ExecutionPayloadBodyV1.ProtoReflect.Descriptor instead. -func (*ExecutionPayloadBodyV1) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{1} -} - -func (x *ExecutionPayloadBodyV1) GetTransactions() [][]byte { - if x != nil { - return x.Transactions - } - return nil -} - -func (x *ExecutionPayloadBodyV1) GetWithdrawals() []*Withdrawal { - if x != nil { - return x.Withdrawals - } - return nil -} - type ExecutionPayloadCapella struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -312,7 +257,7 @@ type ExecutionPayloadCapella struct { func (x *ExecutionPayloadCapella) Reset() { *x = ExecutionPayloadCapella{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -325,7 +270,7 @@ func (x *ExecutionPayloadCapella) String() string { func (*ExecutionPayloadCapella) ProtoMessage() {} func (x *ExecutionPayloadCapella) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[1] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -338,7 +283,7 @@ func (x *ExecutionPayloadCapella) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadCapella.ProtoReflect.Descriptor instead. func (*ExecutionPayloadCapella) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{2} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{1} } func (x *ExecutionPayloadCapella) GetParentHash() []byte { @@ -473,7 +418,7 @@ type ExecutionPayloadDeneb struct { func (x *ExecutionPayloadDeneb) Reset() { *x = ExecutionPayloadDeneb{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -486,7 +431,7 @@ func (x *ExecutionPayloadDeneb) String() string { func (*ExecutionPayloadDeneb) ProtoMessage() {} func (x *ExecutionPayloadDeneb) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[2] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -499,7 +444,7 @@ func (x *ExecutionPayloadDeneb) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadDeneb.ProtoReflect.Descriptor instead. func (*ExecutionPayloadDeneb) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{3} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{2} } func (x *ExecutionPayloadDeneb) GetParentHash() []byte { @@ -650,7 +595,7 @@ type ExecutionPayloadElectra struct { func (x *ExecutionPayloadElectra) Reset() { *x = ExecutionPayloadElectra{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -663,7 +608,7 @@ func (x *ExecutionPayloadElectra) String() string { func (*ExecutionPayloadElectra) ProtoMessage() {} func (x *ExecutionPayloadElectra) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[3] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -676,7 +621,7 @@ func (x *ExecutionPayloadElectra) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadElectra.ProtoReflect.Descriptor instead. func (*ExecutionPayloadElectra) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{4} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{3} } func (x *ExecutionPayloadElectra) GetParentHash() []byte { @@ -826,7 +771,7 @@ type ExecutionPayloadElectraWithValueAndBlobsBundle struct { func (x *ExecutionPayloadElectraWithValueAndBlobsBundle) Reset() { *x = ExecutionPayloadElectraWithValueAndBlobsBundle{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -839,7 +784,7 @@ func (x *ExecutionPayloadElectraWithValueAndBlobsBundle) String() string { func (*ExecutionPayloadElectraWithValueAndBlobsBundle) ProtoMessage() {} func (x *ExecutionPayloadElectraWithValueAndBlobsBundle) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[4] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -852,7 +797,7 @@ func (x *ExecutionPayloadElectraWithValueAndBlobsBundle) ProtoReflect() protoref // Deprecated: Use ExecutionPayloadElectraWithValueAndBlobsBundle.ProtoReflect.Descriptor instead. func (*ExecutionPayloadElectraWithValueAndBlobsBundle) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{5} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{4} } func (x *ExecutionPayloadElectraWithValueAndBlobsBundle) GetPayload() *ExecutionPayloadElectra { @@ -895,7 +840,7 @@ type ExecutionPayloadCapellaWithValue struct { func (x *ExecutionPayloadCapellaWithValue) Reset() { *x = ExecutionPayloadCapellaWithValue{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -908,7 +853,7 @@ func (x *ExecutionPayloadCapellaWithValue) String() string { func (*ExecutionPayloadCapellaWithValue) ProtoMessage() {} func (x *ExecutionPayloadCapellaWithValue) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[5] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -921,7 +866,7 @@ func (x *ExecutionPayloadCapellaWithValue) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadCapellaWithValue.ProtoReflect.Descriptor instead. func (*ExecutionPayloadCapellaWithValue) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{6} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{5} } func (x *ExecutionPayloadCapellaWithValue) GetPayload() *ExecutionPayloadCapella { @@ -952,7 +897,7 @@ type ExecutionPayloadDenebWithValueAndBlobsBundle struct { func (x *ExecutionPayloadDenebWithValueAndBlobsBundle) Reset() { *x = ExecutionPayloadDenebWithValueAndBlobsBundle{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -965,7 +910,7 @@ func (x *ExecutionPayloadDenebWithValueAndBlobsBundle) String() string { func (*ExecutionPayloadDenebWithValueAndBlobsBundle) ProtoMessage() {} func (x *ExecutionPayloadDenebWithValueAndBlobsBundle) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[6] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -978,7 +923,7 @@ func (x *ExecutionPayloadDenebWithValueAndBlobsBundle) ProtoReflect() protorefle // Deprecated: Use ExecutionPayloadDenebWithValueAndBlobsBundle.ProtoReflect.Descriptor instead. func (*ExecutionPayloadDenebWithValueAndBlobsBundle) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{7} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{6} } func (x *ExecutionPayloadDenebWithValueAndBlobsBundle) GetPayload() *ExecutionPayloadDeneb { @@ -1033,7 +978,7 @@ type ExecutionPayloadHeader struct { func (x *ExecutionPayloadHeader) Reset() { *x = ExecutionPayloadHeader{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1046,7 +991,7 @@ func (x *ExecutionPayloadHeader) String() string { func (*ExecutionPayloadHeader) ProtoMessage() {} func (x *ExecutionPayloadHeader) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[7] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1059,7 +1004,7 @@ func (x *ExecutionPayloadHeader) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadHeader.ProtoReflect.Descriptor instead. func (*ExecutionPayloadHeader) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{8} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{7} } func (x *ExecutionPayloadHeader) GetParentHash() []byte { @@ -1185,7 +1130,7 @@ type ExecutionPayloadHeaderCapella struct { func (x *ExecutionPayloadHeaderCapella) Reset() { *x = ExecutionPayloadHeaderCapella{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1198,7 +1143,7 @@ func (x *ExecutionPayloadHeaderCapella) String() string { func (*ExecutionPayloadHeaderCapella) ProtoMessage() {} func (x *ExecutionPayloadHeaderCapella) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[8] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1211,7 +1156,7 @@ func (x *ExecutionPayloadHeaderCapella) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadHeaderCapella.ProtoReflect.Descriptor instead. func (*ExecutionPayloadHeaderCapella) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{9} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{8} } func (x *ExecutionPayloadHeaderCapella) GetParentHash() []byte { @@ -1346,7 +1291,7 @@ type ExecutionPayloadHeaderDeneb struct { func (x *ExecutionPayloadHeaderDeneb) Reset() { *x = ExecutionPayloadHeaderDeneb{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1359,7 +1304,7 @@ func (x *ExecutionPayloadHeaderDeneb) String() string { func (*ExecutionPayloadHeaderDeneb) ProtoMessage() {} func (x *ExecutionPayloadHeaderDeneb) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[9] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1372,7 +1317,7 @@ func (x *ExecutionPayloadHeaderDeneb) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadHeaderDeneb.ProtoReflect.Descriptor instead. func (*ExecutionPayloadHeaderDeneb) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{10} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{9} } func (x *ExecutionPayloadHeaderDeneb) GetParentHash() []byte { @@ -1523,7 +1468,7 @@ type ExecutionPayloadHeaderElectra struct { func (x *ExecutionPayloadHeaderElectra) Reset() { *x = ExecutionPayloadHeaderElectra{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1536,7 +1481,7 @@ func (x *ExecutionPayloadHeaderElectra) String() string { func (*ExecutionPayloadHeaderElectra) ProtoMessage() {} func (x *ExecutionPayloadHeaderElectra) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[10] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1549,7 +1494,7 @@ func (x *ExecutionPayloadHeaderElectra) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionPayloadHeaderElectra.ProtoReflect.Descriptor instead. func (*ExecutionPayloadHeaderElectra) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{11} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{10} } func (x *ExecutionPayloadHeaderElectra) GetParentHash() []byte { @@ -1698,7 +1643,7 @@ type PayloadAttributes struct { func (x *PayloadAttributes) Reset() { *x = PayloadAttributes{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1711,7 +1656,7 @@ func (x *PayloadAttributes) String() string { func (*PayloadAttributes) ProtoMessage() {} func (x *PayloadAttributes) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[11] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1724,7 +1669,7 @@ func (x *PayloadAttributes) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadAttributes.ProtoReflect.Descriptor instead. func (*PayloadAttributes) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{12} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{11} } func (x *PayloadAttributes) GetTimestamp() uint64 { @@ -1762,7 +1707,7 @@ type PayloadAttributesV2 struct { func (x *PayloadAttributesV2) Reset() { *x = PayloadAttributesV2{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[13] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1775,7 +1720,7 @@ func (x *PayloadAttributesV2) String() string { func (*PayloadAttributesV2) ProtoMessage() {} func (x *PayloadAttributesV2) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[13] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[12] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1788,7 +1733,7 @@ func (x *PayloadAttributesV2) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadAttributesV2.ProtoReflect.Descriptor instead. func (*PayloadAttributesV2) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{13} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{12} } func (x *PayloadAttributesV2) GetTimestamp() uint64 { @@ -1834,7 +1779,7 @@ type PayloadAttributesV3 struct { func (x *PayloadAttributesV3) Reset() { *x = PayloadAttributesV3{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[14] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[13] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1847,7 +1792,7 @@ func (x *PayloadAttributesV3) String() string { func (*PayloadAttributesV3) ProtoMessage() {} func (x *PayloadAttributesV3) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[14] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[13] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1860,7 +1805,7 @@ func (x *PayloadAttributesV3) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadAttributesV3.ProtoReflect.Descriptor instead. func (*PayloadAttributesV3) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{14} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{13} } func (x *PayloadAttributesV3) GetTimestamp() uint64 { @@ -1911,7 +1856,7 @@ type PayloadStatus struct { func (x *PayloadStatus) Reset() { *x = PayloadStatus{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[15] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[14] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1924,7 +1869,7 @@ func (x *PayloadStatus) String() string { func (*PayloadStatus) ProtoMessage() {} func (x *PayloadStatus) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[15] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[14] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -1937,7 +1882,7 @@ func (x *PayloadStatus) ProtoReflect() protoreflect.Message { // Deprecated: Use PayloadStatus.ProtoReflect.Descriptor instead. func (*PayloadStatus) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{15} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{14} } func (x *PayloadStatus) GetStatus() PayloadStatus_Status { @@ -1974,7 +1919,7 @@ type ForkchoiceState struct { func (x *ForkchoiceState) Reset() { *x = ForkchoiceState{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[16] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[15] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -1987,7 +1932,7 @@ func (x *ForkchoiceState) String() string { func (*ForkchoiceState) ProtoMessage() {} func (x *ForkchoiceState) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[16] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[15] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2000,7 +1945,7 @@ func (x *ForkchoiceState) ProtoReflect() protoreflect.Message { // Deprecated: Use ForkchoiceState.ProtoReflect.Descriptor instead. func (*ForkchoiceState) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{16} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{15} } func (x *ForkchoiceState) GetHeadBlockHash() []byte { @@ -2038,7 +1983,7 @@ type Withdrawal struct { func (x *Withdrawal) Reset() { *x = Withdrawal{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[17] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[16] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2051,7 +1996,7 @@ func (x *Withdrawal) String() string { func (*Withdrawal) ProtoMessage() {} func (x *Withdrawal) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[17] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[16] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2064,7 +2009,7 @@ func (x *Withdrawal) ProtoReflect() protoreflect.Message { // Deprecated: Use Withdrawal.ProtoReflect.Descriptor instead. func (*Withdrawal) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{17} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{16} } func (x *Withdrawal) GetIndex() uint64 { @@ -2108,7 +2053,7 @@ type BlobsBundle struct { func (x *BlobsBundle) Reset() { *x = BlobsBundle{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[18] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[17] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2121,7 +2066,7 @@ func (x *BlobsBundle) String() string { func (*BlobsBundle) ProtoMessage() {} func (x *BlobsBundle) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[18] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[17] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2134,7 +2079,7 @@ func (x *BlobsBundle) ProtoReflect() protoreflect.Message { // Deprecated: Use BlobsBundle.ProtoReflect.Descriptor instead. func (*BlobsBundle) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{18} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{17} } func (x *BlobsBundle) GetKzgCommitments() [][]byte { @@ -2169,7 +2114,7 @@ type Blob struct { func (x *Blob) Reset() { *x = Blob{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[19] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[18] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2182,7 +2127,7 @@ func (x *Blob) String() string { func (*Blob) ProtoMessage() {} func (x *Blob) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[19] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[18] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2195,7 +2140,7 @@ func (x *Blob) ProtoReflect() protoreflect.Message { // Deprecated: Use Blob.ProtoReflect.Descriptor instead. func (*Blob) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{19} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{18} } func (x *Blob) GetData() []byte { @@ -2216,7 +2161,7 @@ type ExchangeCapabilities struct { func (x *ExchangeCapabilities) Reset() { *x = ExchangeCapabilities{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[20] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[19] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2229,7 +2174,7 @@ func (x *ExchangeCapabilities) String() string { func (*ExchangeCapabilities) ProtoMessage() {} func (x *ExchangeCapabilities) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[20] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[19] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2242,7 +2187,7 @@ func (x *ExchangeCapabilities) ProtoReflect() protoreflect.Message { // Deprecated: Use ExchangeCapabilities.ProtoReflect.Descriptor instead. func (*ExchangeCapabilities) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{20} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{19} } func (x *ExchangeCapabilities) GetSupportedMethods() []string { @@ -2265,7 +2210,7 @@ type ExecutionLayerWithdrawalRequest struct { func (x *ExecutionLayerWithdrawalRequest) Reset() { *x = ExecutionLayerWithdrawalRequest{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[21] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[20] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2278,7 +2223,7 @@ func (x *ExecutionLayerWithdrawalRequest) String() string { func (*ExecutionLayerWithdrawalRequest) ProtoMessage() {} func (x *ExecutionLayerWithdrawalRequest) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[21] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[20] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2291,7 +2236,7 @@ func (x *ExecutionLayerWithdrawalRequest) ProtoReflect() protoreflect.Message { // Deprecated: Use ExecutionLayerWithdrawalRequest.ProtoReflect.Descriptor instead. func (*ExecutionLayerWithdrawalRequest) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{21} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{20} } func (x *ExecutionLayerWithdrawalRequest) GetSourceAddress() []byte { @@ -2330,7 +2275,7 @@ type DepositReceipt struct { func (x *DepositReceipt) Reset() { *x = DepositReceipt{} if protoimpl.UnsafeEnabled { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[22] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[21] ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) ms.StoreMessageInfo(mi) } @@ -2343,7 +2288,7 @@ func (x *DepositReceipt) String() string { func (*DepositReceipt) ProtoMessage() {} func (x *DepositReceipt) ProtoReflect() protoreflect.Message { - mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[22] + mi := &file_proto_engine_v1_execution_engine_proto_msgTypes[21] if protoimpl.UnsafeEnabled && x != nil { ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) if ms.LoadMessageInfo() == nil { @@ -2356,7 +2301,7 @@ func (x *DepositReceipt) ProtoReflect() protoreflect.Message { // Deprecated: Use DepositReceipt.ProtoReflect.Descriptor instead. func (*DepositReceipt) Descriptor() ([]byte, []int) { - return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{22} + return file_proto_engine_v1_execution_engine_proto_rawDescGZIP(), []int{21} } func (x *DepositReceipt) GetPubkey() []byte { @@ -2439,15 +2384,7 @@ var file_proto_engine_v1_execution_engine_proto_rawDesc = []byte{ 0x73, 0x18, 0x0e, 0x20, 0x03, 0x28, 0x0c, 0x42, 0x1d, 0x8a, 0xb5, 0x18, 0x03, 0x3f, 0x2c, 0x3f, 0x92, 0xb5, 0x18, 0x12, 0x31, 0x30, 0x34, 0x38, 0x35, 0x37, 0x36, 0x2c, 0x31, 0x30, 0x37, 0x33, 0x37, 0x34, 0x31, 0x38, 0x32, 0x34, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, - 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x7e, 0x0a, 0x16, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, - 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x42, 0x6f, 0x64, 0x79, 0x56, 0x31, 0x12, 0x22, - 0x0a, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x18, 0x01, - 0x20, 0x03, 0x28, 0x0c, 0x52, 0x0c, 0x74, 0x72, 0x61, 0x6e, 0x73, 0x61, 0x63, 0x74, 0x69, 0x6f, - 0x6e, 0x73, 0x12, 0x40, 0x0a, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, - 0x73, 0x18, 0x02, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x1e, 0x2e, 0x65, 0x74, 0x68, 0x65, 0x72, 0x65, - 0x75, 0x6d, 0x2e, 0x65, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x2e, 0x76, 0x31, 0x2e, 0x57, 0x69, 0x74, - 0x68, 0x64, 0x72, 0x61, 0x77, 0x61, 0x6c, 0x52, 0x0b, 0x77, 0x69, 0x74, 0x68, 0x64, 0x72, 0x61, - 0x77, 0x61, 0x6c, 0x73, 0x22, 0x99, 0x05, 0x0a, 0x17, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, + 0x69, 0x6f, 0x6e, 0x73, 0x22, 0x99, 0x05, 0x0a, 0x17, 0x45, 0x78, 0x65, 0x63, 0x75, 0x74, 0x69, 0x6f, 0x6e, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x43, 0x61, 0x70, 0x65, 0x6c, 0x6c, 0x61, 0x12, 0x27, 0x0a, 0x0b, 0x70, 0x61, 0x72, 0x65, 0x6e, 0x74, 0x5f, 0x68, 0x61, 0x73, 0x68, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0c, 0x42, 0x06, 0x8a, 0xb5, 0x18, 0x02, 0x33, 0x32, 0x52, 0x0a, 0x70, @@ -2958,53 +2895,51 @@ func file_proto_engine_v1_execution_engine_proto_rawDescGZIP() []byte { } var file_proto_engine_v1_execution_engine_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_proto_engine_v1_execution_engine_proto_msgTypes = make([]protoimpl.MessageInfo, 23) +var file_proto_engine_v1_execution_engine_proto_msgTypes = make([]protoimpl.MessageInfo, 22) var file_proto_engine_v1_execution_engine_proto_goTypes = []interface{}{ (PayloadStatus_Status)(0), // 0: ethereum.engine.v1.PayloadStatus.Status (*ExecutionPayload)(nil), // 1: ethereum.engine.v1.ExecutionPayload - (*ExecutionPayloadBodyV1)(nil), // 2: ethereum.engine.v1.ExecutionPayloadBodyV1 - (*ExecutionPayloadCapella)(nil), // 3: ethereum.engine.v1.ExecutionPayloadCapella - (*ExecutionPayloadDeneb)(nil), // 4: ethereum.engine.v1.ExecutionPayloadDeneb - (*ExecutionPayloadElectra)(nil), // 5: ethereum.engine.v1.ExecutionPayloadElectra - (*ExecutionPayloadElectraWithValueAndBlobsBundle)(nil), // 6: ethereum.engine.v1.ExecutionPayloadElectraWithValueAndBlobsBundle - (*ExecutionPayloadCapellaWithValue)(nil), // 7: ethereum.engine.v1.ExecutionPayloadCapellaWithValue - (*ExecutionPayloadDenebWithValueAndBlobsBundle)(nil), // 8: ethereum.engine.v1.ExecutionPayloadDenebWithValueAndBlobsBundle - (*ExecutionPayloadHeader)(nil), // 9: ethereum.engine.v1.ExecutionPayloadHeader - (*ExecutionPayloadHeaderCapella)(nil), // 10: ethereum.engine.v1.ExecutionPayloadHeaderCapella - (*ExecutionPayloadHeaderDeneb)(nil), // 11: ethereum.engine.v1.ExecutionPayloadHeaderDeneb - (*ExecutionPayloadHeaderElectra)(nil), // 12: ethereum.engine.v1.ExecutionPayloadHeaderElectra - (*PayloadAttributes)(nil), // 13: ethereum.engine.v1.PayloadAttributes - (*PayloadAttributesV2)(nil), // 14: ethereum.engine.v1.PayloadAttributesV2 - (*PayloadAttributesV3)(nil), // 15: ethereum.engine.v1.PayloadAttributesV3 - (*PayloadStatus)(nil), // 16: ethereum.engine.v1.PayloadStatus - (*ForkchoiceState)(nil), // 17: ethereum.engine.v1.ForkchoiceState - (*Withdrawal)(nil), // 18: ethereum.engine.v1.Withdrawal - (*BlobsBundle)(nil), // 19: ethereum.engine.v1.BlobsBundle - (*Blob)(nil), // 20: ethereum.engine.v1.Blob - (*ExchangeCapabilities)(nil), // 21: ethereum.engine.v1.ExchangeCapabilities - (*ExecutionLayerWithdrawalRequest)(nil), // 22: ethereum.engine.v1.ExecutionLayerWithdrawalRequest - (*DepositReceipt)(nil), // 23: ethereum.engine.v1.DepositReceipt + (*ExecutionPayloadCapella)(nil), // 2: ethereum.engine.v1.ExecutionPayloadCapella + (*ExecutionPayloadDeneb)(nil), // 3: ethereum.engine.v1.ExecutionPayloadDeneb + (*ExecutionPayloadElectra)(nil), // 4: ethereum.engine.v1.ExecutionPayloadElectra + (*ExecutionPayloadElectraWithValueAndBlobsBundle)(nil), // 5: ethereum.engine.v1.ExecutionPayloadElectraWithValueAndBlobsBundle + (*ExecutionPayloadCapellaWithValue)(nil), // 6: ethereum.engine.v1.ExecutionPayloadCapellaWithValue + (*ExecutionPayloadDenebWithValueAndBlobsBundle)(nil), // 7: ethereum.engine.v1.ExecutionPayloadDenebWithValueAndBlobsBundle + (*ExecutionPayloadHeader)(nil), // 8: ethereum.engine.v1.ExecutionPayloadHeader + (*ExecutionPayloadHeaderCapella)(nil), // 9: ethereum.engine.v1.ExecutionPayloadHeaderCapella + (*ExecutionPayloadHeaderDeneb)(nil), // 10: ethereum.engine.v1.ExecutionPayloadHeaderDeneb + (*ExecutionPayloadHeaderElectra)(nil), // 11: ethereum.engine.v1.ExecutionPayloadHeaderElectra + (*PayloadAttributes)(nil), // 12: ethereum.engine.v1.PayloadAttributes + (*PayloadAttributesV2)(nil), // 13: ethereum.engine.v1.PayloadAttributesV2 + (*PayloadAttributesV3)(nil), // 14: ethereum.engine.v1.PayloadAttributesV3 + (*PayloadStatus)(nil), // 15: ethereum.engine.v1.PayloadStatus + (*ForkchoiceState)(nil), // 16: ethereum.engine.v1.ForkchoiceState + (*Withdrawal)(nil), // 17: ethereum.engine.v1.Withdrawal + (*BlobsBundle)(nil), // 18: ethereum.engine.v1.BlobsBundle + (*Blob)(nil), // 19: ethereum.engine.v1.Blob + (*ExchangeCapabilities)(nil), // 20: ethereum.engine.v1.ExchangeCapabilities + (*ExecutionLayerWithdrawalRequest)(nil), // 21: ethereum.engine.v1.ExecutionLayerWithdrawalRequest + (*DepositReceipt)(nil), // 22: ethereum.engine.v1.DepositReceipt } var file_proto_engine_v1_execution_engine_proto_depIdxs = []int32{ - 18, // 0: ethereum.engine.v1.ExecutionPayloadBodyV1.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 18, // 1: ethereum.engine.v1.ExecutionPayloadCapella.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 18, // 2: ethereum.engine.v1.ExecutionPayloadDeneb.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 18, // 3: ethereum.engine.v1.ExecutionPayloadElectra.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 23, // 4: ethereum.engine.v1.ExecutionPayloadElectra.deposit_receipts:type_name -> ethereum.engine.v1.DepositReceipt - 22, // 5: ethereum.engine.v1.ExecutionPayloadElectra.withdrawal_requests:type_name -> ethereum.engine.v1.ExecutionLayerWithdrawalRequest - 5, // 6: ethereum.engine.v1.ExecutionPayloadElectraWithValueAndBlobsBundle.payload:type_name -> ethereum.engine.v1.ExecutionPayloadElectra - 19, // 7: ethereum.engine.v1.ExecutionPayloadElectraWithValueAndBlobsBundle.blobs_bundle:type_name -> ethereum.engine.v1.BlobsBundle - 3, // 8: ethereum.engine.v1.ExecutionPayloadCapellaWithValue.payload:type_name -> ethereum.engine.v1.ExecutionPayloadCapella - 4, // 9: ethereum.engine.v1.ExecutionPayloadDenebWithValueAndBlobsBundle.payload:type_name -> ethereum.engine.v1.ExecutionPayloadDeneb - 19, // 10: ethereum.engine.v1.ExecutionPayloadDenebWithValueAndBlobsBundle.blobs_bundle:type_name -> ethereum.engine.v1.BlobsBundle - 18, // 11: ethereum.engine.v1.PayloadAttributesV2.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 18, // 12: ethereum.engine.v1.PayloadAttributesV3.withdrawals:type_name -> ethereum.engine.v1.Withdrawal - 0, // 13: ethereum.engine.v1.PayloadStatus.status:type_name -> ethereum.engine.v1.PayloadStatus.Status - 14, // [14:14] is the sub-list for method output_type - 14, // [14:14] is the sub-list for method input_type - 14, // [14:14] is the sub-list for extension type_name - 14, // [14:14] is the sub-list for extension extendee - 0, // [0:14] is the sub-list for field type_name + 17, // 0: ethereum.engine.v1.ExecutionPayloadCapella.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 17, // 1: ethereum.engine.v1.ExecutionPayloadDeneb.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 17, // 2: ethereum.engine.v1.ExecutionPayloadElectra.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 22, // 3: ethereum.engine.v1.ExecutionPayloadElectra.deposit_receipts:type_name -> ethereum.engine.v1.DepositReceipt + 21, // 4: ethereum.engine.v1.ExecutionPayloadElectra.withdrawal_requests:type_name -> ethereum.engine.v1.ExecutionLayerWithdrawalRequest + 4, // 5: ethereum.engine.v1.ExecutionPayloadElectraWithValueAndBlobsBundle.payload:type_name -> ethereum.engine.v1.ExecutionPayloadElectra + 18, // 6: ethereum.engine.v1.ExecutionPayloadElectraWithValueAndBlobsBundle.blobs_bundle:type_name -> ethereum.engine.v1.BlobsBundle + 2, // 7: ethereum.engine.v1.ExecutionPayloadCapellaWithValue.payload:type_name -> ethereum.engine.v1.ExecutionPayloadCapella + 3, // 8: ethereum.engine.v1.ExecutionPayloadDenebWithValueAndBlobsBundle.payload:type_name -> ethereum.engine.v1.ExecutionPayloadDeneb + 18, // 9: ethereum.engine.v1.ExecutionPayloadDenebWithValueAndBlobsBundle.blobs_bundle:type_name -> ethereum.engine.v1.BlobsBundle + 17, // 10: ethereum.engine.v1.PayloadAttributesV2.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 17, // 11: ethereum.engine.v1.PayloadAttributesV3.withdrawals:type_name -> ethereum.engine.v1.Withdrawal + 0, // 12: ethereum.engine.v1.PayloadStatus.status:type_name -> ethereum.engine.v1.PayloadStatus.Status + 13, // [13:13] is the sub-list for method output_type + 13, // [13:13] is the sub-list for method input_type + 13, // [13:13] is the sub-list for extension type_name + 13, // [13:13] is the sub-list for extension extendee + 0, // [0:13] is the sub-list for field type_name } func init() { file_proto_engine_v1_execution_engine_proto_init() } @@ -3026,18 +2961,6 @@ func file_proto_engine_v1_execution_engine_proto_init() { } } file_proto_engine_v1_execution_engine_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { - switch v := v.(*ExecutionPayloadBodyV1); i { - case 0: - return &v.state - case 1: - return &v.sizeCache - case 2: - return &v.unknownFields - default: - return nil - } - } - file_proto_engine_v1_execution_engine_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadCapella); i { case 0: return &v.state @@ -3049,7 +2972,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadDeneb); i { case 0: return &v.state @@ -3061,7 +2984,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadElectra); i { case 0: return &v.state @@ -3073,7 +2996,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadElectraWithValueAndBlobsBundle); i { case 0: return &v.state @@ -3085,7 +3008,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[5].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadCapellaWithValue); i { case 0: return &v.state @@ -3097,7 +3020,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[6].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadDenebWithValueAndBlobsBundle); i { case 0: return &v.state @@ -3109,7 +3032,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[7].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadHeader); i { case 0: return &v.state @@ -3121,7 +3044,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[8].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadHeaderCapella); i { case 0: return &v.state @@ -3133,7 +3056,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[9].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadHeaderDeneb); i { case 0: return &v.state @@ -3145,7 +3068,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[10].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionPayloadHeaderElectra); i { case 0: return &v.state @@ -3157,7 +3080,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[11].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PayloadAttributes); i { case 0: return &v.state @@ -3169,7 +3092,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[12].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PayloadAttributesV2); i { case 0: return &v.state @@ -3181,7 +3104,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[13].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PayloadAttributesV3); i { case 0: return &v.state @@ -3193,7 +3116,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[14].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*PayloadStatus); i { case 0: return &v.state @@ -3205,7 +3128,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[15].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ForkchoiceState); i { case 0: return &v.state @@ -3217,7 +3140,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[16].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Withdrawal); i { case 0: return &v.state @@ -3229,7 +3152,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[17].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*BlobsBundle); i { case 0: return &v.state @@ -3241,7 +3164,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[18].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*Blob); i { case 0: return &v.state @@ -3253,7 +3176,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[19].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExchangeCapabilities); i { case 0: return &v.state @@ -3265,7 +3188,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[20].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*ExecutionLayerWithdrawalRequest); i { case 0: return &v.state @@ -3277,7 +3200,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { return nil } } - file_proto_engine_v1_execution_engine_proto_msgTypes[22].Exporter = func(v interface{}, i int) interface{} { + file_proto_engine_v1_execution_engine_proto_msgTypes[21].Exporter = func(v interface{}, i int) interface{} { switch v := v.(*DepositReceipt); i { case 0: return &v.state @@ -3296,7 +3219,7 @@ func file_proto_engine_v1_execution_engine_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_proto_engine_v1_execution_engine_proto_rawDesc, NumEnums: 1, - NumMessages: 23, + NumMessages: 22, NumExtensions: 0, NumServices: 0, }, diff --git a/proto/engine/v1/execution_engine.proto b/proto/engine/v1/execution_engine.proto index 6085c05c9b44..a6686a326495 100644 --- a/proto/engine/v1/execution_engine.proto +++ b/proto/engine/v1/execution_engine.proto @@ -41,11 +41,6 @@ message ExecutionPayload { repeated bytes transactions = 14 [(ethereum.eth.ext.ssz_size) = "?,?", (ethereum.eth.ext.ssz_max) = "1048576,1073741824"]; } -message ExecutionPayloadBodyV1 { - repeated bytes transactions = 1; - repeated Withdrawal withdrawals = 2; -} - message ExecutionPayloadCapella { bytes parent_hash = 1 [(ethereum.eth.ext.ssz_size) = "32"]; bytes fee_recipient = 2 [(ethereum.eth.ext.ssz_size) = "20"]; diff --git a/proto/engine/v1/generated.ssz.go b/proto/engine/v1/generated.ssz.go index 9022df00bdf5..05d41cc36251 100644 --- a/proto/engine/v1/generated.ssz.go +++ b/proto/engine/v1/generated.ssz.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: 88fdbdfda4571603e11174a57e65c25e06780ff2cbd795c8ae2a4709da24d9a9 +// Hash: 5e73dfd1d7df4fb984d773b9aa92658a1bc4db66b0e050f9b869a470e61416d3 package enginev1 import ( diff --git a/proto/engine/v1/json_marshal_unmarshal.go b/proto/engine/v1/json_marshal_unmarshal.go index f6c7d78d013b..cbaac71f2be6 100644 --- a/proto/engine/v1/json_marshal_unmarshal.go +++ b/proto/engine/v1/json_marshal_unmarshal.go @@ -21,6 +21,8 @@ const ( BlsSignLen = 96 ) +var errJsonNilField = errors.New("nil field in JSON value") + // BlsPubkey represents a 48 byte BLS public key. type BlsPubkey [BlsPubKeyLen]byte @@ -325,6 +327,14 @@ type ExecutionPayloadElectraJSON struct { DepositRequests []DepositRequestV1 `json:"depositRequests"` } +// ExecutionPayloadBody represents the engine API ExecutionPayloadV1 or ExecutionPayloadV2 type. +type ExecutionPayloadBody struct { + Transactions []hexutil.Bytes `json:"transactions"` + Withdrawals []*Withdrawal `json:"withdrawals"` + WithdrawalRequests []WithdrawalRequestV1 `json:"withdrawalRequests"` + DepositRequests []DepositRequestV1 `json:"depositRequests"` +} + // Validate returns an error if key fields in GetPayloadV4ResponseJson are nil or invalid. func (j *GetPayloadV4ResponseJson) Validate() error { if j.ExecutionPayload == nil { @@ -411,6 +421,19 @@ type WithdrawalRequestV1 struct { Amount *hexutil.Uint64 `json:"amount"` } +func (r WithdrawalRequestV1) Validate() error { + if r.SourceAddress == nil { + return errors.Wrap(errJsonNilField, "missing required field 'sourceAddress' for WithdrawalRequestV1") + } + if r.ValidatorPubkey == nil { + return errors.Wrap(errJsonNilField, "missing required field 'validatorPublicKey' for WithdrawalRequestV1") + } + if r.Amount == nil { + return errors.Wrap(errJsonNilField, "missing required field 'amount' for WithdrawalRequestV1") + } + return nil +} + // DepositRequestV1 represents an execution engine DepositRequestV1 value // https://github.com/ethereum/execution-apis/blob/main/src/engine/prague.md#depositrequestv1 type DepositRequestV1 struct { @@ -426,6 +449,25 @@ type DepositRequestV1 struct { Index *hexutil.Uint64 `json:"index"` } +func (r DepositRequestV1) Validate() error { + if r.PubKey == nil { + return errors.Wrap(errJsonNilField, "missing required field 'pubkey' for DepositRequestV1") + } + if r.WithdrawalCredentials == nil { + return errors.Wrap(errJsonNilField, "missing required field 'withdrawalCredentials' for DepositRequestV1") + } + if r.Amount == nil { + return errors.Wrap(errJsonNilField, "missing required field 'amount' for DepositRequestV1") + } + if r.Signature == nil { + return errors.Wrap(errJsonNilField, "missing required field 'signature' for DepositRequestV1") + } + if r.Index == nil { + return errors.Wrap(errJsonNilField, "missing required field 'index' for DepositRequestV1") + } + return nil +} + // MarshalJSON -- func (e *ExecutionPayload) MarshalJSON() ([]byte, error) { transactions := make([]hexutil.Bytes, len(e.Transactions)) @@ -941,17 +983,20 @@ func (e *ExecutionPayloadElectra) MarshalJSON() ([]byte, error) { Withdrawals: withdrawals, BlobGasUsed: &blobGasUsed, ExcessBlobGas: &excessBlobGas, - WithdrawalRequests: WithdrawalRequestProtoToJson(e.WithdrawalRequests), - DepositRequests: DepositRequestProtoToJson(e.DepositReceipts), + WithdrawalRequests: ProtoWithdrawalRequestsToJson(e.WithdrawalRequests), + DepositRequests: ProtoDepositRequestsToJson(e.DepositReceipts), }) } -func (j *ExecutionPayloadElectraJSON) ElectraDepositReceipts() []*DepositReceipt { - rcpt := make([]*DepositReceipt, len(j.DepositRequests)) +func JsonDepositRequestsToProto(j []DepositRequestV1) ([]*DepositReceipt, error) { + reqs := make([]*DepositReceipt, len(j)) - for i := range j.DepositRequests { - req := j.DepositRequests[i] - rcpt[i] = &DepositReceipt{ + for i := range j { + req := j[i] + if err := req.Validate(); err != nil { + return nil, err + } + reqs[i] = &DepositReceipt{ Pubkey: req.PubKey.Bytes(), WithdrawalCredentials: req.WithdrawalCredentials.Bytes(), Amount: uint64(*req.Amount), @@ -960,10 +1005,10 @@ func (j *ExecutionPayloadElectraJSON) ElectraDepositReceipts() []*DepositReceipt } } - return rcpt + return reqs, nil } -func DepositRequestProtoToJson(reqs []*DepositReceipt) []DepositRequestV1 { +func ProtoDepositRequestsToJson(reqs []*DepositReceipt) []DepositRequestV1 { j := make([]DepositRequestV1, len(reqs)) for i := range reqs { r := reqs[i] @@ -985,11 +1030,14 @@ func DepositRequestProtoToJson(reqs []*DepositReceipt) []DepositRequestV1 { return j } -func (j *ExecutionPayloadElectraJSON) ElectraExecutionLayerWithdrawalRequests() []*ExecutionLayerWithdrawalRequest { - reqs := make([]*ExecutionLayerWithdrawalRequest, len(j.WithdrawalRequests)) +func JsonWithdrawalRequestsToProto(j []WithdrawalRequestV1) ([]*ExecutionLayerWithdrawalRequest, error) { + reqs := make([]*ExecutionLayerWithdrawalRequest, len(j)) - for i := range j.WithdrawalRequests { - req := j.WithdrawalRequests[i] + for i := range j { + req := j[i] + if err := req.Validate(); err != nil { + return nil, err + } reqs[i] = &ExecutionLayerWithdrawalRequest{ SourceAddress: req.SourceAddress.Bytes(), ValidatorPubkey: req.ValidatorPubkey.Bytes(), @@ -997,10 +1045,10 @@ func (j *ExecutionPayloadElectraJSON) ElectraExecutionLayerWithdrawalRequests() } } - return reqs + return reqs, nil } -func WithdrawalRequestProtoToJson(reqs []*ExecutionLayerWithdrawalRequest) []WithdrawalRequestV1 { +func ProtoWithdrawalRequestsToJson(reqs []*ExecutionLayerWithdrawalRequest) []WithdrawalRequestV1 { j := make([]WithdrawalRequestV1, len(reqs)) for i := range reqs { r := reqs[i] @@ -1031,6 +1079,14 @@ func (j *ExecutionPayloadElectraJSON) ElectraPayload() (*ExecutionPayloadElectra if j.Withdrawals == nil { j.Withdrawals = make([]*Withdrawal, 0) } + dr, err := JsonDepositRequestsToProto(j.DepositRequests) + if err != nil { + return nil, err + } + wr, err := JsonWithdrawalRequestsToProto(j.WithdrawalRequests) + if err != nil { + return nil, err + } return &ExecutionPayloadElectra{ ParentHash: j.ParentHash.Bytes(), FeeRecipient: j.FeeRecipient.Bytes(), @@ -1049,8 +1105,8 @@ func (j *ExecutionPayloadElectraJSON) ElectraPayload() (*ExecutionPayloadElectra Withdrawals: j.Withdrawals, BlobGasUsed: uint64(*j.BlobGasUsed), ExcessBlobGas: uint64(*j.ExcessBlobGas), - DepositReceipts: j.ElectraDepositReceipts(), - WithdrawalRequests: j.ElectraExecutionLayerWithdrawalRequests(), + DepositReceipts: dr, + WithdrawalRequests: wr, }, nil } @@ -1232,42 +1288,11 @@ func (e *ExecutionPayloadDenebWithValueAndBlobsBundle) UnmarshalJSON(enc []byte) return nil } -type executionPayloadBodyV1JSON struct { - Transactions []hexutil.Bytes `json:"transactions"` - Withdrawals []*Withdrawal `json:"withdrawals"` -} - -func (b *ExecutionPayloadBodyV1) MarshalJSON() ([]byte, error) { - transactions := make([]hexutil.Bytes, len(b.Transactions)) - for i, tx := range b.Transactions { - transactions[i] = tx - } - if len(b.Withdrawals) == 0 { - b.Withdrawals = make([]*Withdrawal, 0) - } - return json.Marshal(executionPayloadBodyV1JSON{ - Transactions: transactions, - Withdrawals: b.Withdrawals, - }) -} - -func (b *ExecutionPayloadBodyV1) UnmarshalJSON(enc []byte) error { - var decoded *executionPayloadBodyV1JSON - err := json.Unmarshal(enc, &decoded) - if err != nil { - return err +// RecastHexutilByteSlice converts a []hexutil.Bytes to a [][]byte +func RecastHexutilByteSlice(h []hexutil.Bytes) [][]byte { + r := make([][]byte, len(h)) + for i := range h { + r[i] = h[i] } - if len(decoded.Transactions) == 0 { - b.Transactions = make([][]byte, 0) - } - if len(decoded.Withdrawals) == 0 { - b.Withdrawals = make([]*Withdrawal, 0) - } - transactions := make([][]byte, len(decoded.Transactions)) - for i, tx := range decoded.Transactions { - transactions[i] = tx - } - b.Transactions = transactions - b.Withdrawals = decoded.Withdrawals - return nil + return r } diff --git a/proto/engine/v1/json_marshal_unmarshal_test.go b/proto/engine/v1/json_marshal_unmarshal_test.go index b2dfbddc6a66..7aed00f1b7a9 100644 --- a/proto/engine/v1/json_marshal_unmarshal_test.go +++ b/proto/engine/v1/json_marshal_unmarshal_test.go @@ -360,8 +360,8 @@ func TestJsonMarshalUnmarshal(t *testing.T) { }}, BlobGasUsed: &bgu, ExcessBlobGas: &ebg, - WithdrawalRequests: enginev1.WithdrawalRequestProtoToJson(withdrawalReq), - DepositRequests: enginev1.DepositRequestProtoToJson(depositReq), + WithdrawalRequests: enginev1.ProtoWithdrawalRequestsToJson(withdrawalReq), + DepositRequests: enginev1.ProtoDepositRequestsToJson(depositReq), }, } enc, err := json.Marshal(resp) @@ -763,8 +763,8 @@ func TestPayloadIDBytes_MarshalUnmarshalJSON(t *testing.T) { } func TestExecutionPayloadBody_MarshalUnmarshalJSON(t *testing.T) { - pBody := &enginev1.ExecutionPayloadBodyV1{ - Transactions: [][]byte{[]byte("random1"), []byte("random2"), []byte("random3")}, + pBody := &enginev1.ExecutionPayloadBody{ + Transactions: []hexutil.Bytes{[]byte("random1"), []byte("random2"), []byte("random3")}, Withdrawals: []*enginev1.Withdrawal{ { Index: 200, @@ -782,8 +782,8 @@ func TestExecutionPayloadBody_MarshalUnmarshalJSON(t *testing.T) { } enc, err := json.Marshal(pBody) require.NoError(t, err) - res := &enginev1.ExecutionPayloadBodyV1{} - err = res.UnmarshalJSON(enc) + res := &enginev1.ExecutionPayloadBody{} + err = json.Unmarshal(enc, res) require.NoError(t, err) require.DeepEqual(t, pBody, res) } diff --git a/proto/eth/v1/generated.ssz.go b/proto/eth/v1/generated.ssz.go index d6f69e0a83a6..9e8cfc3999b7 100644 --- a/proto/eth/v1/generated.ssz.go +++ b/proto/eth/v1/generated.ssz.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: 6fed60156f1e57926b40b972ee25b48a82b18726a9c64fb0e974e4f638784049 +// Hash: a13be0354388a9ab681c78ee577580c9aebbd6d3d17024084c06c839c5db58ee package v1 import ( diff --git a/proto/eth/v2/generated.ssz.go b/proto/eth/v2/generated.ssz.go index 2674eea802fb..b91d3b7aa5d5 100644 --- a/proto/eth/v2/generated.ssz.go +++ b/proto/eth/v2/generated.ssz.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: 36d05ceafa355d5aa87123eb218143987a79f5095e2cafbad7760712ad0934a3 +// Hash: e1b3713d854395a4c86aa7a0bf0249d9f2764183a636fcc53badddeaf38990f2 package eth import ( diff --git a/proto/prysm/v1alpha1/generated.ssz.go b/proto/prysm/v1alpha1/generated.ssz.go index d95f6eb989f2..9d201ba3218e 100644 --- a/proto/prysm/v1alpha1/generated.ssz.go +++ b/proto/prysm/v1alpha1/generated.ssz.go @@ -1,5 +1,5 @@ // Code generated by fastssz. DO NOT EDIT. -// Hash: 4e7c07afe12b97ee034415333c33967cab8cf624f3fd43f37562cd6307760ec3 +// Hash: 5d2c5eb257aa9cd0f12fd74f707963c8e7f779fbef26d0031f6ae18e9b1ee124 package eth import ( diff --git a/testing/util/deneb.go b/testing/util/deneb.go index a847fa502322..12a888bf9d11 100644 --- a/testing/util/deneb.go +++ b/testing/util/deneb.go @@ -31,6 +31,7 @@ type denebBlockGenerator struct { sk bls.SecretKey proposer primitives.ValidatorIndex valRoot []byte + payload *enginev1.ExecutionPayloadDeneb } func WithProposerSigning(idx primitives.ValidatorIndex, sk bls.SecretKey, valRoot []byte) DenebBlockGeneratorOption { @@ -42,6 +43,12 @@ func WithProposerSigning(idx primitives.ValidatorIndex, sk bls.SecretKey, valRoo } } +func WithPayloadSetter(p *enginev1.ExecutionPayloadDeneb) DenebBlockGeneratorOption { + return func(g *denebBlockGenerator) { + g.payload = p + } +} + func GenerateTestDenebBlockWithSidecar(t *testing.T, parent [32]byte, slot primitives.Slot, nblobs int, opts ...DenebBlockGeneratorOption) (blocks.ROBlock, []blocks.ROBlob) { g := &denebBlockGenerator{ parent: parent, @@ -51,47 +58,51 @@ func GenerateTestDenebBlockWithSidecar(t *testing.T, parent [32]byte, slot primi for _, o := range opts { o(g) } - stateRoot := bytesutil.PadTo([]byte("stateRoot"), fieldparams.RootLength) - receiptsRoot := bytesutil.PadTo([]byte("receiptsRoot"), fieldparams.RootLength) - logsBloom := bytesutil.PadTo([]byte("logs"), fieldparams.LogsBloomLength) - parentHash := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength) - ads := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") - tx := gethTypes.NewTx(&gethTypes.LegacyTx{ - Nonce: 0, - To: &ads, - Value: big.NewInt(0), - Gas: 0, - GasPrice: big.NewInt(0), - Data: nil, - }) - - txs := []*gethTypes.Transaction{tx} - encodedBinaryTxs := make([][]byte, 1) - var err error - encodedBinaryTxs[0], err = txs[0].MarshalBinary() - require.NoError(t, err) - blockHash := bytesutil.ToBytes32([]byte("foo")) - payload := &enginev1.ExecutionPayloadDeneb{ - ParentHash: parentHash, - FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), - StateRoot: stateRoot, - ReceiptsRoot: receiptsRoot, - LogsBloom: logsBloom, - PrevRandao: blockHash[:], - BlockNumber: 0, - GasLimit: 0, - GasUsed: 0, - Timestamp: 0, - ExtraData: make([]byte, 0), - BaseFeePerGas: bytesutil.PadTo([]byte("baseFeePerGas"), fieldparams.RootLength), - BlockHash: blockHash[:], - Transactions: encodedBinaryTxs, - Withdrawals: make([]*enginev1.Withdrawal, 0), - BlobGasUsed: 0, - ExcessBlobGas: 0, + + if g.payload == nil { + stateRoot := bytesutil.PadTo([]byte("stateRoot"), fieldparams.RootLength) + ads := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") + tx := gethTypes.NewTx(&gethTypes.LegacyTx{ + Nonce: 0, + To: &ads, + Value: big.NewInt(0), + Gas: 0, + GasPrice: big.NewInt(0), + Data: nil, + }) + + txs := []*gethTypes.Transaction{tx} + encodedBinaryTxs := make([][]byte, 1) + var err error + encodedBinaryTxs[0], err = txs[0].MarshalBinary() + require.NoError(t, err) + blockHash := bytesutil.ToBytes32([]byte("foo")) + logsBloom := bytesutil.PadTo([]byte("logs"), fieldparams.LogsBloomLength) + receiptsRoot := bytesutil.PadTo([]byte("receiptsRoot"), fieldparams.RootLength) + parentHash := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength) + g.payload = &enginev1.ExecutionPayloadDeneb{ + ParentHash: parentHash, + FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), + StateRoot: stateRoot, + ReceiptsRoot: receiptsRoot, + LogsBloom: logsBloom, + PrevRandao: blockHash[:], + BlockNumber: 0, + GasLimit: 0, + GasUsed: 0, + Timestamp: 0, + ExtraData: make([]byte, 0), + BaseFeePerGas: bytesutil.PadTo([]byte("baseFeePerGas"), fieldparams.RootLength), + BlockHash: blockHash[:], + Transactions: encodedBinaryTxs, + Withdrawals: make([]*enginev1.Withdrawal, 0), + BlobGasUsed: 0, + ExcessBlobGas: 0, + } } + block := NewBeaconBlockDeneb() - block.Block.Body.ExecutionPayload = payload + block.Block.Body.ExecutionPayload = g.payload block.Block.Slot = g.slot block.Block.ParentRoot = g.parent[:] block.Block.ProposerIndex = g.proposer diff --git a/testing/util/electra.go b/testing/util/electra.go index 81a127923760..09bcc8b7c70f 100644 --- a/testing/util/electra.go +++ b/testing/util/electra.go @@ -1,11 +1,24 @@ package util import ( + "encoding/binary" "math" + "math/big" "testing" + "github.com/ethereum/go-ethereum/common" + gethTypes "github.com/ethereum/go-ethereum/core/types" + "github.com/prysmaticlabs/prysm/v5/beacon-chain/core/signing" + fieldparams "github.com/prysmaticlabs/prysm/v5/config/fieldparams" "github.com/prysmaticlabs/prysm/v5/config/params" + "github.com/prysmaticlabs/prysm/v5/consensus-types/blocks" + "github.com/prysmaticlabs/prysm/v5/consensus-types/primitives" + "github.com/prysmaticlabs/prysm/v5/crypto/bls" + "github.com/prysmaticlabs/prysm/v5/encoding/bytesutil" + "github.com/prysmaticlabs/prysm/v5/network/forks" + enginev1 "github.com/prysmaticlabs/prysm/v5/proto/engine/v1" "github.com/prysmaticlabs/prysm/v5/testing/require" + "github.com/prysmaticlabs/prysm/v5/time/slots" ) // HackElectraMaxuint is helpful for tests that need to set up cases where the electra fork has passed. @@ -23,3 +36,165 @@ func HackElectraMaxuint(t *testing.T) func() { require.NoError(t, undo()) } } + +type ElectraBlockGeneratorOption func(*electraBlockGenerator) + +type electraBlockGenerator struct { + parent [32]byte + slot primitives.Slot + nblobs int + sign bool + sk bls.SecretKey + proposer primitives.ValidatorIndex + valRoot []byte + payload *enginev1.ExecutionPayloadElectra +} + +func WithElectraProposerSigning(idx primitives.ValidatorIndex, sk bls.SecretKey, valRoot []byte) ElectraBlockGeneratorOption { + return func(g *electraBlockGenerator) { + g.sign = true + g.proposer = idx + g.sk = sk + g.valRoot = valRoot + } +} + +func WithElectraPayload(p *enginev1.ExecutionPayloadElectra) ElectraBlockGeneratorOption { + return func(g *electraBlockGenerator) { + g.payload = p + } +} + +func GenerateTestElectraBlockWithSidecar(t *testing.T, parent [32]byte, slot primitives.Slot, nblobs int, opts ...ElectraBlockGeneratorOption) (blocks.ROBlock, []blocks.ROBlob) { + g := &electraBlockGenerator{ + parent: parent, + slot: slot, + nblobs: nblobs, + } + for _, o := range opts { + o(g) + } + + if g.payload == nil { + stateRoot := bytesutil.PadTo([]byte("stateRoot"), fieldparams.RootLength) + ads := common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87") + tx := gethTypes.NewTx(&gethTypes.LegacyTx{ + Nonce: 0, + To: &ads, + Value: big.NewInt(0), + Gas: 0, + GasPrice: big.NewInt(0), + Data: nil, + }) + + txs := []*gethTypes.Transaction{tx} + encodedBinaryTxs := make([][]byte, 1) + var err error + encodedBinaryTxs[0], err = txs[0].MarshalBinary() + require.NoError(t, err) + blockHash := bytesutil.ToBytes32([]byte("foo")) + logsBloom := bytesutil.PadTo([]byte("logs"), fieldparams.LogsBloomLength) + receiptsRoot := bytesutil.PadTo([]byte("receiptsRoot"), fieldparams.RootLength) + parentHash := bytesutil.PadTo([]byte("parentHash"), fieldparams.RootLength) + g.payload = &enginev1.ExecutionPayloadElectra{ + ParentHash: parentHash, + FeeRecipient: make([]byte, fieldparams.FeeRecipientLength), + StateRoot: stateRoot, + ReceiptsRoot: receiptsRoot, + LogsBloom: logsBloom, + PrevRandao: blockHash[:], + BlockNumber: 0, + GasLimit: 0, + GasUsed: 0, + Timestamp: 0, + ExtraData: make([]byte, 0), + BaseFeePerGas: bytesutil.PadTo([]byte("baseFeePerGas"), fieldparams.RootLength), + BlockHash: blockHash[:], + Transactions: encodedBinaryTxs, + Withdrawals: make([]*enginev1.Withdrawal, 0), + BlobGasUsed: 0, + ExcessBlobGas: 0, + DepositReceipts: generateTestDepositRequests(uint64(g.slot), 4), + WithdrawalRequests: generateTestWithdrawalRequests(uint64(g.slot), 4), + } + } + + block := NewBeaconBlockElectra() + block.Block.Body.ExecutionPayload = g.payload + block.Block.Slot = g.slot + block.Block.ParentRoot = g.parent[:] + block.Block.ProposerIndex = g.proposer + commitments := make([][48]byte, g.nblobs) + block.Block.Body.BlobKzgCommitments = make([][]byte, g.nblobs) + for i := range commitments { + binary.LittleEndian.PutUint16(commitments[i][0:16], uint16(i)) + binary.LittleEndian.PutUint16(commitments[i][16:32], uint16(g.slot)) + block.Block.Body.BlobKzgCommitments[i] = commitments[i][:] + } + + body, err := blocks.NewBeaconBlockBody(block.Block.Body) + require.NoError(t, err) + inclusion := make([][][]byte, len(commitments)) + for i := range commitments { + proof, err := blocks.MerkleProofKZGCommitment(body, i) + require.NoError(t, err) + inclusion[i] = proof + } + if g.sign { + epoch := slots.ToEpoch(block.Block.Slot) + schedule := forks.NewOrderedSchedule(params.BeaconConfig()) + version, err := schedule.VersionForEpoch(epoch) + require.NoError(t, err) + fork, err := schedule.ForkFromVersion(version) + require.NoError(t, err) + domain := params.BeaconConfig().DomainBeaconProposer + sig, err := signing.ComputeDomainAndSignWithoutState(fork, epoch, domain, g.valRoot, block.Block, g.sk) + require.NoError(t, err) + block.Signature = sig + } + + root, err := block.Block.HashTreeRoot() + require.NoError(t, err) + + sidecars := make([]blocks.ROBlob, len(commitments)) + sbb, err := blocks.NewSignedBeaconBlock(block) + require.NoError(t, err) + + sh, err := sbb.Header() + require.NoError(t, err) + for i, c := range block.Block.Body.BlobKzgCommitments { + sidecars[i] = GenerateTestDenebBlobSidecar(t, root, sh, i, c, inclusion[i]) + } + + rob, err := blocks.NewROBlock(sbb) + require.NoError(t, err) + return rob, sidecars +} + +func generateTestDepositRequests(offset, n uint64) []*enginev1.DepositReceipt { + r := make([]*enginev1.DepositReceipt, n) + var i uint64 + for i = 0; i < n; i++ { + r[i] = &enginev1.DepositReceipt{ + Pubkey: make([]byte, 48), + WithdrawalCredentials: make([]byte, 32), + Amount: offset + i, + Signature: make([]byte, 96), + Index: offset + i + 100, + } + } + return r +} + +func generateTestWithdrawalRequests(offset, n uint64) []*enginev1.ExecutionLayerWithdrawalRequest { + r := make([]*enginev1.ExecutionLayerWithdrawalRequest, n) + var i uint64 + for i = 0; i < n; i++ { + r[i] = &enginev1.ExecutionLayerWithdrawalRequest{ + SourceAddress: make([]byte, 20), + ValidatorPubkey: make([]byte, 48), + Amount: offset + i, + } + } + return r +} From a79cec36eca7dc58a8e33a2a5a8c64fcbac13086 Mon Sep 17 00:00:00 2001 From: Kasey Kirkham Date: Fri, 17 May 2024 09:21:05 -0500 Subject: [PATCH 2/2] prevent overflows when dealing with electra fixture --- beacon-chain/execution/payload_body_test.go | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/beacon-chain/execution/payload_body_test.go b/beacon-chain/execution/payload_body_test.go index 8b95141b30c9..b95edead67d8 100644 --- a/beacon-chain/execution/payload_body_test.go +++ b/beacon-chain/execution/payload_body_test.go @@ -140,6 +140,7 @@ func testBlindedBlockFixtures(t *testing.T) *blindedBlockFixtures { } func TestPayloadBodiesViaUnblinder(t *testing.T) { + defer util.HackElectraMaxuint(t)() fx := testBlindedBlockFixtures(t) t.Run("mix of non-empty and empty", func(t *testing.T) { cli, srv := newMockEngine(t) @@ -175,6 +176,7 @@ func TestPayloadBodiesViaUnblinder(t *testing.T) { } func TestFixtureEquivalence(t *testing.T) { + defer util.HackElectraMaxuint(t)() fx := testBlindedBlockFixtures(t) t.Run("full and blinded block equivalence", func(t *testing.T) { testAssertReconstructedEquivalent(t, fx.denebBlock.blinded.block, fx.denebBlock.full) @@ -277,8 +279,7 @@ func TestComputeRanges(t *testing.T) { } func TestReconstructBlindedBlockBatchFallbackToRange(t *testing.T) { - undo := util.HackElectraMaxuint(t) - defer undo() + defer util.HackElectraMaxuint(t)() ctx := context.Background() t.Run("fallback fails", func(t *testing.T) { cli, srv := newMockEngine(t) @@ -380,8 +381,7 @@ func TestReconstructBlindedBlockBatchFallbackToRange(t *testing.T) { } func TestReconstructBlindedBlockBatchDenebAndElectra(t *testing.T) { - undo := util.HackElectraMaxuint(t) - defer undo() + defer util.HackElectraMaxuint(t)() t.Run("deneb and electra", func(t *testing.T) { cli, srv := newMockEngine(t) fx := testBlindedBlockFixtures(t)