Electra payload body engine methods (#14000)

* Combined v1/v2 payload body handling

* prevent overflows when dealing with electra fixture

---------

Co-authored-by: Kasey Kirkham <kasey@users.noreply.github.com>
This commit is contained in:
kasey
2024-05-17 15:31:07 -05:00
committed by GitHub
parent 1272b9e186
commit 46168607e8
16 changed files with 1534 additions and 1060 deletions

View File

@@ -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",
],

View File

@@ -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))
}

View File

@@ -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()
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
results, err := service.GetPayloadBodiesByHash(ctx, []common.Hash{})
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)
slot, err := slots.EpochStart(params.BeaconConfig().DenebForkEpoch)
require.NoError(t, err)
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)
})
blinded, err := blk.ToBlinded()
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()
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))
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
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("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()
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)
}
service.rpcClient = cli
_, err = service.ReconstructFullBlock(ctx, blinded)
require.ErrorIs(t, err, errNilPayloadBody)
})
}

View File

@@ -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))
}
}
})
}
}

View File

@@ -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
}

View File

@@ -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) {
defer util.HackElectraMaxuint(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) {
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)
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) {
defer util.HackElectraMaxuint(t)()
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) {
defer util.HackElectraMaxuint(t)()
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])
}
})
}

View File

@@ -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,
},

View File

@@ -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"];

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 88fdbdfda4571603e11174a57e65c25e06780ff2cbd795c8ae2a4709da24d9a9
// Hash: 5e73dfd1d7df4fb984d773b9aa92658a1bc4db66b0e050f9b869a470e61416d3
package enginev1
import (

View File

@@ -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
}
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
// 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]
}
return r
}

View File

@@ -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)
}

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 6fed60156f1e57926b40b972ee25b48a82b18726a9c64fb0e974e4f638784049
// Hash: a13be0354388a9ab681c78ee577580c9aebbd6d3d17024084c06c839c5db58ee
package v1
import (

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 36d05ceafa355d5aa87123eb218143987a79f5095e2cafbad7760712ad0934a3
// Hash: e1b3713d854395a4c86aa7a0bf0249d9f2764183a636fcc53badddeaf38990f2
package eth
import (

View File

@@ -1,5 +1,5 @@
// Code generated by fastssz. DO NOT EDIT.
// Hash: 4e7c07afe12b97ee034415333c33967cab8cf624f3fd43f37562cd6307760ec3
// Hash: 5d2c5eb257aa9cd0f12fd74f707963c8e7f779fbef26d0031f6ae18e9b1ee124
package eth
import (

View File

@@ -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

View File

@@ -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
}