Add Capella support for Validator's REST API ProposeBeaconBlock and GetBeaconBlock endpoints (#11848)

* Add Capella support for Validator's REST API ProposeBeaconBlock and GetBeaconBlock endpoints

* Fix

* Fix

* Add context to capella tests

* Update validator/client/beacon-api/beacon_block_proto_helpers.go

* Update validator/client/beacon-api/beacon_block_proto_helpers.go

* Update validator/client/beacon-api/beacon_block_proto_helpers_test.go

* Update validator/client/beacon-api/beacon_block_proto_helpers_test.go

Co-authored-by: james-prysm <90280386+james-prysm@users.noreply.github.com>
Co-authored-by: Radosław Kapka <radek@prysmaticlabs.com>
Co-authored-by: Radosław Kapka <rkapka@wp.pl>
This commit is contained in:
Patrice Vignola
2023-01-11 08:55:09 -08:00
committed by GitHub
parent 505ff6ea3d
commit 81b9eceb50
12 changed files with 1314 additions and 2 deletions

View File

@@ -60,6 +60,7 @@ go_test(
"genesis_test.go",
"get_beacon_block_altair_test.go",
"get_beacon_block_bellatrix_test.go",
"get_beacon_block_capella_test.go",
"get_beacon_block_phase0_test.go",
"get_beacon_block_test.go",
"index_test.go",
@@ -70,6 +71,7 @@ go_test(
"propose_beacon_block_bellatrix_test.go",
"propose_beacon_block_blinded_bellatrix_test.go",
"propose_beacon_block_blinded_capella_test.go",
"propose_beacon_block_capella_test.go",
"propose_beacon_block_phase0_test.go",
"propose_beacon_block_test.go",
"propose_exit_test.go",

View File

@@ -1,8 +1,11 @@
package beacon_api
import (
"strconv"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
@@ -170,3 +173,16 @@ func jsonifySignedAggregateAndProof(signedAggregateAndProof *ethpb.SignedAggrega
Signature: hexutil.Encode(signedAggregateAndProof.Signature),
}
}
func jsonifyWithdrawals(withdrawals []*enginev1.Withdrawal) []*apimiddleware.WithdrawalJson {
jsonWithdrawals := make([]*apimiddleware.WithdrawalJson, len(withdrawals))
for index, withdrawal := range withdrawals {
jsonWithdrawals[index] = &apimiddleware.WithdrawalJson{
WithdrawalIndex: strconv.FormatUint(withdrawal.Index, 10),
ValidatorIndex: strconv.FormatUint(uint64(withdrawal.ValidatorIndex), 10),
ExecutionAddress: hexutil.Encode(withdrawal.Address),
Amount: strconv.FormatUint(withdrawal.Amount, 10),
}
}
return jsonWithdrawals
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
)
@@ -611,3 +612,38 @@ func TestBeaconBlockJsonHelpers_JsonifyAttestationData(t *testing.T) {
result := jsonifyAttestationData(input)
assert.DeepEqual(t, expectedResult, result)
}
func TestBeaconBlockJsonHelpers_JsonifyWithdrawals(t *testing.T) {
input := []*enginev1.Withdrawal{
{
Index: 1,
ValidatorIndex: 2,
Address: []byte{3},
Amount: 4,
},
{
Index: 5,
ValidatorIndex: 6,
Address: []byte{7},
Amount: 8,
},
}
expectedResult := []*apimiddleware.WithdrawalJson{
{
WithdrawalIndex: "1",
ValidatorIndex: "2",
ExecutionAddress: hexutil.Encode([]byte{3}),
Amount: "4",
},
{
WithdrawalIndex: "5",
ValidatorIndex: "6",
ExecutionAddress: hexutil.Encode([]byte{7}),
Amount: "8",
},
}
result := jsonifyWithdrawals(input)
assert.DeepEqual(t, expectedResult, result)
}

View File

@@ -7,6 +7,7 @@ import (
"github.com/pkg/errors"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
@@ -350,3 +351,87 @@ func convertTransactionsToProto(jsonTransactions []string) ([][]byte, error) {
return transactions, nil
}
func convertWithdrawalsToProto(jsonWithdrawals []*apimiddleware.WithdrawalJson) ([]*enginev1.Withdrawal, error) {
withdrawals := make([]*enginev1.Withdrawal, len(jsonWithdrawals))
for index, jsonWithdrawal := range jsonWithdrawals {
if jsonWithdrawal == nil {
return nil, errors.Errorf("withdrawal at index `%d` is nil", index)
}
withdrawalIndex, err := strconv.ParseUint(jsonWithdrawal.WithdrawalIndex, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse withdrawal index `%s`", jsonWithdrawal.WithdrawalIndex)
}
validatorIndex, err := strconv.ParseUint(jsonWithdrawal.ValidatorIndex, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse validator index `%s`", jsonWithdrawal.ValidatorIndex)
}
executionAddress, err := hexutil.Decode(jsonWithdrawal.ExecutionAddress)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode execution address `%s`", jsonWithdrawal.ExecutionAddress)
}
amount, err := strconv.ParseUint(jsonWithdrawal.Amount, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "failed to parse withdrawal amount `%s`", jsonWithdrawal.Amount)
}
withdrawals[index] = &enginev1.Withdrawal{
Index: withdrawalIndex,
ValidatorIndex: types.ValidatorIndex(validatorIndex),
Address: executionAddress,
Amount: amount,
}
}
return withdrawals, nil
}
func convertBlsToExecutionChangesToProto(jsonSignedBlsToExecutionChanges []*apimiddleware.SignedBLSToExecutionChangeJson) ([]*ethpb.SignedBLSToExecutionChange, error) {
signedBlsToExecutionChanges := make([]*ethpb.SignedBLSToExecutionChange, len(jsonSignedBlsToExecutionChanges))
for index, jsonBlsToExecutionChange := range jsonSignedBlsToExecutionChanges {
if jsonBlsToExecutionChange == nil {
return nil, errors.Errorf("bls to execution change at index `%d` is nil", index)
}
if jsonBlsToExecutionChange.Message == nil {
return nil, errors.Errorf("bls to execution change message at index `%d` is nil", index)
}
validatorIndex, err := strconv.ParseUint(jsonBlsToExecutionChange.Message.ValidatorIndex, 10, 64)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode validator index `%s`", jsonBlsToExecutionChange.Message.ValidatorIndex)
}
fromBlsPubkey, err := hexutil.Decode(jsonBlsToExecutionChange.Message.FromBLSPubkey)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode bls pubkey `%s`", jsonBlsToExecutionChange.Message.FromBLSPubkey)
}
toExecutionAddress, err := hexutil.Decode(jsonBlsToExecutionChange.Message.ToExecutionAddress)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode execution address `%s`", jsonBlsToExecutionChange.Message.ToExecutionAddress)
}
signature, err := hexutil.Decode(jsonBlsToExecutionChange.Signature)
if err != nil {
return nil, errors.Wrapf(err, "failed to decode signature `%s`", jsonBlsToExecutionChange.Signature)
}
signedBlsToExecutionChanges[index] = &ethpb.SignedBLSToExecutionChange{
Message: &ethpb.BLSToExecutionChange{
ValidatorIndex: types.ValidatorIndex(validatorIndex),
FromBlsPubkey: fromBlsPubkey,
ToExecutionAddress: toExecutionAddress,
},
Signature: signature,
}
}
return signedBlsToExecutionChanges, nil
}

View File

@@ -5,6 +5,7 @@ import (
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
@@ -917,6 +918,169 @@ func TestBeaconBlockProtoHelpers_ConvertTransactionsToProto(t *testing.T) {
}
}
func TestBeaconBlockProtoHelpers_ConvertWithdrawalsToProto(t *testing.T) {
testCases := []struct {
name string
generateInput func() []*apimiddleware.WithdrawalJson
expectedResult []*enginev1.Withdrawal
expectedErrorMessage string
}{
{
name: "nil withdrawal",
expectedErrorMessage: "withdrawal at index `0` is nil",
generateInput: func() []*apimiddleware.WithdrawalJson {
input := generateWithdrawals()
input[0] = nil
return input
},
},
{
name: "bad withdrawal index",
expectedErrorMessage: "failed to parse withdrawal index `foo`",
generateInput: func() []*apimiddleware.WithdrawalJson {
input := generateWithdrawals()
input[0].WithdrawalIndex = "foo"
return input
},
},
{
name: "bad validator index",
expectedErrorMessage: "failed to parse validator index `bar`",
generateInput: func() []*apimiddleware.WithdrawalJson {
input := generateWithdrawals()
input[0].ValidatorIndex = "bar"
return input
},
},
{
name: "bad execution address",
expectedErrorMessage: "failed to decode execution address `foo`",
generateInput: func() []*apimiddleware.WithdrawalJson {
input := generateWithdrawals()
input[0].ExecutionAddress = "foo"
return input
},
},
{
name: "bad amount",
expectedErrorMessage: "failed to parse withdrawal amount `bar`",
generateInput: func() []*apimiddleware.WithdrawalJson {
input := generateWithdrawals()
input[0].Amount = "bar"
return input
},
},
{
name: "valid",
generateInput: generateWithdrawals,
expectedResult: []*enginev1.Withdrawal{
{
Index: 1,
ValidatorIndex: 2,
Address: []byte{3},
Amount: 4,
},
{
Index: 5,
ValidatorIndex: 6,
Address: []byte{7},
Amount: 8,
},
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
result, err := convertWithdrawalsToProto(testCase.generateInput())
if testCase.expectedResult != nil {
require.NoError(t, err)
assert.DeepEqual(t, testCase.expectedResult, result)
} else if testCase.expectedErrorMessage != "" {
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
}
})
}
}
func TestBeaconBlockProtoHelpers_ConvertBlsToExecutionChangesToProto(t *testing.T) {
testCases := []struct {
name string
generateInput func() []*apimiddleware.SignedBLSToExecutionChangeJson
expectedResult []*ethpb.SignedBLSToExecutionChange
expectedErrorMessage string
}{
{
name: "nil bls to execution change",
expectedErrorMessage: "bls to execution change at index `0` is nil",
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
input := generateBlsToExecutionChanges()
input[0] = nil
return input
},
},
{
name: "nil bls to execution change message",
expectedErrorMessage: "bls to execution change message at index `0` is nil",
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
input := generateBlsToExecutionChanges()
input[0].Message = nil
return input
},
},
{
name: "bad validator index",
expectedErrorMessage: "failed to decode validator index `foo`",
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
input := generateBlsToExecutionChanges()
input[0].Message.ValidatorIndex = "foo"
return input
},
},
{
name: "bad from bls pubkey",
expectedErrorMessage: "failed to decode bls pubkey `bar`",
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
input := generateBlsToExecutionChanges()
input[0].Message.FromBLSPubkey = "bar"
return input
},
},
{
name: "bad to execution address",
expectedErrorMessage: "failed to decode execution address `foo`",
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
input := generateBlsToExecutionChanges()
input[0].Message.ToExecutionAddress = "foo"
return input
},
},
{
name: "bad signature",
expectedErrorMessage: "failed to decode signature `bar`",
generateInput: func() []*apimiddleware.SignedBLSToExecutionChangeJson {
input := generateBlsToExecutionChanges()
input[0].Signature = "bar"
return input
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
result, err := convertBlsToExecutionChangesToProto(testCase.generateInput())
if testCase.expectedResult != nil {
require.NoError(t, err)
assert.DeepEqual(t, testCase.expectedResult, result)
} else if testCase.expectedErrorMessage != "" {
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
}
})
}
}
func generateProposerSlashings() []*apimiddleware.ProposerSlashingJson {
return []*apimiddleware.ProposerSlashingJson{
{
@@ -1185,3 +1349,41 @@ func generateSignedVoluntaryExits() []*apimiddleware.SignedVoluntaryExitJson {
},
}
}
func generateWithdrawals() []*apimiddleware.WithdrawalJson {
return []*apimiddleware.WithdrawalJson{
{
WithdrawalIndex: "1",
ValidatorIndex: "2",
ExecutionAddress: hexutil.Encode([]byte{3}),
Amount: "4",
},
{
WithdrawalIndex: "5",
ValidatorIndex: "6",
ExecutionAddress: hexutil.Encode([]byte{7}),
Amount: "8",
},
}
}
func generateBlsToExecutionChanges() []*apimiddleware.SignedBLSToExecutionChangeJson {
return []*apimiddleware.SignedBLSToExecutionChangeJson{
{
Message: &apimiddleware.BLSToExecutionChangeJson{
ValidatorIndex: "1",
FromBLSPubkey: hexutil.Encode([]byte{2}),
ToExecutionAddress: hexutil.Encode([]byte{3}),
},
Signature: hexutil.Encode([]byte{4}),
},
{
Message: &apimiddleware.BLSToExecutionChangeJson{
ValidatorIndex: "5",
FromBLSPubkey: hexutil.Encode([]byte{6}),
ToExecutionAddress: hexutil.Encode([]byte{7}),
},
Signature: hexutil.Encode([]byte{8}),
},
}
}

View File

@@ -83,6 +83,18 @@ func (c beaconApiValidatorClient) getBeaconBlock(ctx context.Context, slot types
}
response.Block = bellatrixBlock
case "capella":
jsonCapellaBlock := apimiddleware.BeaconBlockCapellaJson{}
if err := decoder.Decode(&jsonCapellaBlock); err != nil {
return nil, errors.Wrap(err, "failed to decode capella block response json")
}
capellaBlock, err := convertRESTCapellaBlockToProto(&jsonCapellaBlock)
if err != nil {
return nil, errors.Wrap(err, "failed to get capella block")
}
response.Block = capellaBlock
default:
return nil, errors.Errorf("unsupported consensus version `%s`", produceBlockResponseJson.Version)
}
@@ -395,3 +407,100 @@ func convertRESTBellatrixBlockToProto(block *apimiddleware.BeaconBlockBellatrixJ
},
}, nil
}
func convertRESTCapellaBlockToProto(block *apimiddleware.BeaconBlockCapellaJson) (*ethpb.GenericBeaconBlock_Capella, error) {
if block.Body == nil {
return nil, errors.New("block body is nil")
}
if block.Body.ExecutionPayload == nil {
return nil, errors.New("execution payload is nil")
}
// Call convertRESTBellatrixBlockToProto to set the bellatrix fields because all the error handling and the heavy
// lifting has already been done
bellatrixBlock, err := convertRESTBellatrixBlockToProto(&apimiddleware.BeaconBlockBellatrixJson{
Slot: block.Slot,
ProposerIndex: block.ProposerIndex,
ParentRoot: block.ParentRoot,
StateRoot: block.StateRoot,
Body: &apimiddleware.BeaconBlockBodyBellatrixJson{
RandaoReveal: block.Body.RandaoReveal,
Eth1Data: block.Body.Eth1Data,
Graffiti: block.Body.Graffiti,
ProposerSlashings: block.Body.ProposerSlashings,
AttesterSlashings: block.Body.AttesterSlashings,
Attestations: block.Body.Attestations,
Deposits: block.Body.Deposits,
VoluntaryExits: block.Body.VoluntaryExits,
SyncAggregate: block.Body.SyncAggregate,
ExecutionPayload: &apimiddleware.ExecutionPayloadJson{
ParentHash: block.Body.ExecutionPayload.ParentHash,
FeeRecipient: block.Body.ExecutionPayload.FeeRecipient,
StateRoot: block.Body.ExecutionPayload.StateRoot,
ReceiptsRoot: block.Body.ExecutionPayload.ReceiptsRoot,
LogsBloom: block.Body.ExecutionPayload.LogsBloom,
PrevRandao: block.Body.ExecutionPayload.PrevRandao,
BlockNumber: block.Body.ExecutionPayload.BlockNumber,
GasLimit: block.Body.ExecutionPayload.GasLimit,
GasUsed: block.Body.ExecutionPayload.GasUsed,
TimeStamp: block.Body.ExecutionPayload.TimeStamp,
ExtraData: block.Body.ExecutionPayload.ExtraData,
BaseFeePerGas: block.Body.ExecutionPayload.BaseFeePerGas,
BlockHash: block.Body.ExecutionPayload.BlockHash,
Transactions: block.Body.ExecutionPayload.Transactions,
},
},
})
if err != nil {
return nil, errors.Wrap(err, "failed to get the bellatrix fields of the capella block")
}
withdrawals, err := convertWithdrawalsToProto(block.Body.ExecutionPayload.Withdrawals)
if err != nil {
return nil, errors.Wrap(err, "failed to get withdrawals")
}
blsToExecutionChanges, err := convertBlsToExecutionChangesToProto(block.Body.BLSToExecutionChanges)
if err != nil {
return nil, errors.Wrap(err, "failed to get bls to execution changes")
}
return &ethpb.GenericBeaconBlock_Capella{
Capella: &ethpb.BeaconBlockCapella{
Slot: bellatrixBlock.Bellatrix.Slot,
ProposerIndex: bellatrixBlock.Bellatrix.ProposerIndex,
ParentRoot: bellatrixBlock.Bellatrix.ParentRoot,
StateRoot: bellatrixBlock.Bellatrix.StateRoot,
Body: &ethpb.BeaconBlockBodyCapella{
RandaoReveal: bellatrixBlock.Bellatrix.Body.RandaoReveal,
Eth1Data: bellatrixBlock.Bellatrix.Body.Eth1Data,
Graffiti: bellatrixBlock.Bellatrix.Body.Graffiti,
ProposerSlashings: bellatrixBlock.Bellatrix.Body.ProposerSlashings,
AttesterSlashings: bellatrixBlock.Bellatrix.Body.AttesterSlashings,
Attestations: bellatrixBlock.Bellatrix.Body.Attestations,
Deposits: bellatrixBlock.Bellatrix.Body.Deposits,
VoluntaryExits: bellatrixBlock.Bellatrix.Body.VoluntaryExits,
SyncAggregate: bellatrixBlock.Bellatrix.Body.SyncAggregate,
ExecutionPayload: &enginev1.ExecutionPayloadCapella{
ParentHash: bellatrixBlock.Bellatrix.Body.ExecutionPayload.ParentHash,
FeeRecipient: bellatrixBlock.Bellatrix.Body.ExecutionPayload.FeeRecipient,
StateRoot: bellatrixBlock.Bellatrix.Body.ExecutionPayload.StateRoot,
ReceiptsRoot: bellatrixBlock.Bellatrix.Body.ExecutionPayload.ReceiptsRoot,
LogsBloom: bellatrixBlock.Bellatrix.Body.ExecutionPayload.LogsBloom,
PrevRandao: bellatrixBlock.Bellatrix.Body.ExecutionPayload.PrevRandao,
BlockNumber: bellatrixBlock.Bellatrix.Body.ExecutionPayload.BlockNumber,
GasLimit: bellatrixBlock.Bellatrix.Body.ExecutionPayload.GasLimit,
GasUsed: bellatrixBlock.Bellatrix.Body.ExecutionPayload.GasUsed,
Timestamp: bellatrixBlock.Bellatrix.Body.ExecutionPayload.Timestamp,
ExtraData: bellatrixBlock.Bellatrix.Body.ExecutionPayload.ExtraData,
BaseFeePerGas: bellatrixBlock.Bellatrix.Body.ExecutionPayload.BaseFeePerGas,
BlockHash: bellatrixBlock.Bellatrix.Body.ExecutionPayload.BlockHash,
Transactions: bellatrixBlock.Bellatrix.Body.ExecutionPayload.Transactions,
Withdrawals: withdrawals,
},
BlsToExecutionChanges: blsToExecutionChanges,
},
},
}, nil
}

View File

@@ -0,0 +1,149 @@
package beacon_api
import (
"context"
"encoding/json"
"fmt"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/mock/gomock"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock"
test_helpers "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/test-helpers"
)
func TestGetBeaconBlock_CapellaValid(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
capellaProtoBeaconBlock := test_helpers.GenerateProtoCapellaBeaconBlock()
capellaBeaconBlockBytes, err := json.Marshal(test_helpers.GenerateJsonCapellaBeaconBlock())
require.NoError(t, err)
const slot = types.Slot(1)
randaoReveal := []byte{2}
graffiti := []byte{3}
ctx := context.Background()
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
jsonRestHandler.EXPECT().GetRestJsonResponse(
ctx,
fmt.Sprintf("/eth/v2/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)),
&abstractProduceBlockResponseJson{},
).SetArg(
2,
abstractProduceBlockResponseJson{
Version: "capella",
Data: capellaBeaconBlockBytes,
},
).Return(
nil,
nil,
).Times(1)
expectedBeaconBlock := generateProtoCapellaBlock(capellaProtoBeaconBlock)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
beaconBlock, err := validatorClient.getBeaconBlock(ctx, slot, randaoReveal, graffiti)
require.NoError(t, err)
assert.DeepEqual(t, expectedBeaconBlock, beaconBlock)
}
func TestGetBeaconBlock_CapellaError(t *testing.T) {
testCases := []struct {
name string
expectedErrorMessage string
generateData func() *apimiddleware.BeaconBlockCapellaJson
}{
{
name: "nil body",
expectedErrorMessage: "block body is nil",
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
beaconBlock.Body = nil
return beaconBlock
},
},
{
name: "nil execution payload",
expectedErrorMessage: "execution payload is nil",
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
beaconBlock.Body.ExecutionPayload = nil
return beaconBlock
},
},
{
name: "bad bellatrix fields",
expectedErrorMessage: "failed to get the bellatrix fields of the capella block",
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
beaconBlock.Body.Eth1Data = nil
return beaconBlock
},
},
{
name: "bad withdrawals",
expectedErrorMessage: "failed to get withdrawals",
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
beaconBlock.Body.ExecutionPayload.Withdrawals[0] = nil
return beaconBlock
},
},
{
name: "bad bls execution changes",
expectedErrorMessage: "failed to get bls to execution changes",
generateData: func() *apimiddleware.BeaconBlockCapellaJson {
beaconBlock := test_helpers.GenerateJsonCapellaBeaconBlock()
beaconBlock.Body.BLSToExecutionChanges[0] = nil
return beaconBlock
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
dataBytes, err := json.Marshal(testCase.generateData())
require.NoError(t, err)
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
jsonRestHandler.EXPECT().GetRestJsonResponse(
context.Background(),
gomock.Any(),
&abstractProduceBlockResponseJson{},
).SetArg(
2,
abstractProduceBlockResponseJson{
Version: "capella",
Data: dataBytes,
},
).Return(
nil,
nil,
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
_, err = validatorClient.getBeaconBlock(context.Background(), 1, []byte{1}, []byte{2})
assert.ErrorContains(t, "failed to get capella block", err)
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
})
}
}
func generateProtoCapellaBlock(capellaProtoBeaconBlock *ethpb.BeaconBlockCapella) *ethpb.GenericBeaconBlock {
return &ethpb.GenericBeaconBlock{
Block: &ethpb.GenericBeaconBlock_Capella{
Capella: capellaProtoBeaconBlock,
},
}
}

View File

@@ -42,6 +42,8 @@ func TestGetBeaconBlock_Error(t *testing.T) {
require.NoError(t, err)
bellatrixBeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockBellatrixJson{})
require.NoError(t, err)
capellaBeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockCapellaJson{})
require.NoError(t, err)
testCases := []struct {
name string
@@ -87,6 +89,19 @@ func TestGetBeaconBlock_Error(t *testing.T) {
consensusVersion: "bellatrix",
data: bellatrixBeaconBlockBytes,
},
{
name: "capella block decoding failed",
expectedErrorMessage: "failed to decode capella block response json",
beaconBlock: "foo",
consensusVersion: "capella",
data: []byte{},
},
{
name: "capella block conversion failed",
expectedErrorMessage: "failed to get capella block",
consensusVersion: "capella",
data: capellaBeaconBlockBytes,
},
{
name: "unsupported consensus version",
expectedErrorMessage: "unsupported consensus version `foo`",

View File

@@ -67,6 +67,17 @@ func (c beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *et
if err != nil {
return nil, errors.Wrap(err, "failed to marshall blinded bellatrix beacon block")
}
case *ethpb.GenericSignedBeaconBlock_Capella:
consensusVersion = "capella"
beaconBlockRoot, err = blockType.Capella.Block.HashTreeRoot()
if err != nil {
return nil, errors.Wrap(err, "failed to compute block root for capella beacon block")
}
marshalledSignedBeaconBlockJson, err = marshallBeaconBlockCapella(blockType.Capella)
if err != nil {
return nil, errors.Wrap(err, "failed to marshall capella beacon block")
}
case *ethpb.GenericSignedBeaconBlock_BlindedCapella:
blinded = true
consensusVersion = "capella"
@@ -79,8 +90,6 @@ func (c beaconApiValidatorClient) proposeBeaconBlock(ctx context.Context, in *et
if err != nil {
return nil, errors.Wrap(err, "failed to marshall blinded capella beacon block")
}
case *ethpb.GenericSignedBeaconBlock_Capella:
return nil, errors.Errorf("Capella blocks are not supported yet")
default:
return nil, errors.Errorf("unsupported block type %T", in.Block)
}
@@ -246,6 +255,52 @@ func marshallBeaconBlockBlindedBellatrix(block *ethpb.SignedBlindedBeaconBlockBe
return json.Marshal(signedBeaconBlockBellatrixJson)
}
func marshallBeaconBlockCapella(block *ethpb.SignedBeaconBlockCapella) ([]byte, error) {
signedBeaconBlockCapellaJson := &apimiddleware.SignedBeaconBlockCapellaContainerJson{
Signature: hexutil.Encode(block.Signature),
Message: &apimiddleware.BeaconBlockCapellaJson{
ParentRoot: hexutil.Encode(block.Block.ParentRoot),
ProposerIndex: uint64ToString(block.Block.ProposerIndex),
Slot: uint64ToString(block.Block.Slot),
StateRoot: hexutil.Encode(block.Block.StateRoot),
Body: &apimiddleware.BeaconBlockBodyCapellaJson{
Attestations: jsonifyAttestations(block.Block.Body.Attestations),
AttesterSlashings: jsonifyAttesterSlashings(block.Block.Body.AttesterSlashings),
Deposits: jsonifyDeposits(block.Block.Body.Deposits),
Eth1Data: jsonifyEth1Data(block.Block.Body.Eth1Data),
Graffiti: hexutil.Encode(block.Block.Body.Graffiti),
ProposerSlashings: jsonifyProposerSlashings(block.Block.Body.ProposerSlashings),
RandaoReveal: hexutil.Encode(block.Block.Body.RandaoReveal),
VoluntaryExits: jsonifySignedVoluntaryExits(block.Block.Body.VoluntaryExits),
SyncAggregate: &apimiddleware.SyncAggregateJson{
SyncCommitteeBits: hexutil.Encode(block.Block.Body.SyncAggregate.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(block.Block.Body.SyncAggregate.SyncCommitteeSignature),
},
ExecutionPayload: &apimiddleware.ExecutionPayloadCapellaJson{
BaseFeePerGas: bytesutil.LittleEndianBytesToBigInt(block.Block.Body.ExecutionPayload.BaseFeePerGas).String(),
BlockHash: hexutil.Encode(block.Block.Body.ExecutionPayload.BlockHash),
BlockNumber: uint64ToString(block.Block.Body.ExecutionPayload.BlockNumber),
ExtraData: hexutil.Encode(block.Block.Body.ExecutionPayload.ExtraData),
FeeRecipient: hexutil.Encode(block.Block.Body.ExecutionPayload.FeeRecipient),
GasLimit: uint64ToString(block.Block.Body.ExecutionPayload.GasLimit),
GasUsed: uint64ToString(block.Block.Body.ExecutionPayload.GasUsed),
LogsBloom: hexutil.Encode(block.Block.Body.ExecutionPayload.LogsBloom),
ParentHash: hexutil.Encode(block.Block.Body.ExecutionPayload.ParentHash),
PrevRandao: hexutil.Encode(block.Block.Body.ExecutionPayload.PrevRandao),
ReceiptsRoot: hexutil.Encode(block.Block.Body.ExecutionPayload.ReceiptsRoot),
StateRoot: hexutil.Encode(block.Block.Body.ExecutionPayload.StateRoot),
TimeStamp: uint64ToString(block.Block.Body.ExecutionPayload.Timestamp),
Transactions: jsonifyTransactions(block.Block.Body.ExecutionPayload.Transactions),
Withdrawals: jsonifyWithdrawals(block.Block.Body.ExecutionPayload.Withdrawals),
},
BLSToExecutionChanges: jsonifyBlsToExecutionChanges(block.Block.Body.BlsToExecutionChanges),
},
},
}
return json.Marshal(signedBeaconBlockCapellaJson)
}
func marshallBeaconBlockBlindedCapella(block *ethpb.SignedBlindedBeaconBlockCapella) ([]byte, error) {
signedBeaconBlockCapellaJson := &apimiddleware.SignedBlindedBeaconBlockCapellaContainerJson{
Signature: hexutil.Encode(block.Signature),

View File

@@ -0,0 +1,104 @@
package beacon_api
import (
"bytes"
"context"
"encoding/json"
"testing"
"github.com/ethereum/go-ethereum/common/hexutil"
"github.com/golang/mock/gomock"
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
"github.com/prysmaticlabs/prysm/v3/testing/assert"
"github.com/prysmaticlabs/prysm/v3/testing/require"
"github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock"
test_helpers "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/test-helpers"
)
func TestProposeBeaconBlock_Capella(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
capellaBlock := generateSignedCapellaBlock()
genericSignedBlock := &ethpb.GenericSignedBeaconBlock{}
genericSignedBlock.Block = capellaBlock
jsonCapellaBlock := &apimiddleware.SignedBeaconBlockCapellaContainerJson{
Signature: hexutil.Encode(capellaBlock.Capella.Signature),
Message: &apimiddleware.BeaconBlockCapellaJson{
ParentRoot: hexutil.Encode(capellaBlock.Capella.Block.ParentRoot),
ProposerIndex: uint64ToString(capellaBlock.Capella.Block.ProposerIndex),
Slot: uint64ToString(capellaBlock.Capella.Block.Slot),
StateRoot: hexutil.Encode(capellaBlock.Capella.Block.StateRoot),
Body: &apimiddleware.BeaconBlockBodyCapellaJson{
Attestations: jsonifyAttestations(capellaBlock.Capella.Block.Body.Attestations),
AttesterSlashings: jsonifyAttesterSlashings(capellaBlock.Capella.Block.Body.AttesterSlashings),
Deposits: jsonifyDeposits(capellaBlock.Capella.Block.Body.Deposits),
Eth1Data: jsonifyEth1Data(capellaBlock.Capella.Block.Body.Eth1Data),
Graffiti: hexutil.Encode(capellaBlock.Capella.Block.Body.Graffiti),
ProposerSlashings: jsonifyProposerSlashings(capellaBlock.Capella.Block.Body.ProposerSlashings),
RandaoReveal: hexutil.Encode(capellaBlock.Capella.Block.Body.RandaoReveal),
VoluntaryExits: jsonifySignedVoluntaryExits(capellaBlock.Capella.Block.Body.VoluntaryExits),
SyncAggregate: &apimiddleware.SyncAggregateJson{
SyncCommitteeBits: hexutil.Encode(capellaBlock.Capella.Block.Body.SyncAggregate.SyncCommitteeBits),
SyncCommitteeSignature: hexutil.Encode(capellaBlock.Capella.Block.Body.SyncAggregate.SyncCommitteeSignature),
},
ExecutionPayload: &apimiddleware.ExecutionPayloadCapellaJson{
BaseFeePerGas: bytesutil.LittleEndianBytesToBigInt(capellaBlock.Capella.Block.Body.ExecutionPayload.BaseFeePerGas).String(),
BlockHash: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.BlockHash),
BlockNumber: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.BlockNumber),
ExtraData: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.ExtraData),
FeeRecipient: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.FeeRecipient),
GasLimit: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.GasLimit),
GasUsed: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.GasUsed),
LogsBloom: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.LogsBloom),
ParentHash: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.ParentHash),
PrevRandao: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.PrevRandao),
ReceiptsRoot: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.ReceiptsRoot),
StateRoot: hexutil.Encode(capellaBlock.Capella.Block.Body.ExecutionPayload.StateRoot),
TimeStamp: uint64ToString(capellaBlock.Capella.Block.Body.ExecutionPayload.Timestamp),
Transactions: jsonifyTransactions(capellaBlock.Capella.Block.Body.ExecutionPayload.Transactions),
Withdrawals: jsonifyWithdrawals(capellaBlock.Capella.Block.Body.ExecutionPayload.Withdrawals),
},
BLSToExecutionChanges: jsonifyBlsToExecutionChanges(capellaBlock.Capella.Block.Body.BlsToExecutionChanges),
},
},
}
marshalledBlock, err := json.Marshal(jsonCapellaBlock)
require.NoError(t, err)
// Make sure that what we send in the POST body is the marshalled version of the protobuf block
headers := map[string]string{"Eth-Consensus-Version": "capella"}
jsonRestHandler.EXPECT().PostRestJson(
context.Background(),
"/eth/v1/beacon/blocks",
headers,
bytes.NewBuffer(marshalledBlock),
nil,
)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
proposeResponse, err := validatorClient.proposeBeaconBlock(context.Background(), genericSignedBlock)
assert.NoError(t, err)
require.NotNil(t, proposeResponse)
expectedBlockRoot, err := capellaBlock.Capella.Block.HashTreeRoot()
require.NoError(t, err)
// Make sure that the block root is set
assert.DeepEqual(t, expectedBlockRoot[:], proposeResponse.BlockRoot)
}
func generateSignedCapellaBlock() *ethpb.GenericSignedBeaconBlock_Capella {
return &ethpb.GenericSignedBeaconBlock_Capella{
Capella: &ethpb.SignedBeaconBlockCapella{
Block: test_helpers.GenerateProtoCapellaBeaconBlock(),
Signature: test_helpers.FillByteSlice(96, 127),
},
}
}

View File

@@ -6,6 +6,7 @@ go_library(
srcs = [
"altair_beacon_block_test_helpers.go",
"bellatrix_beacon_block_test_helpers.go",
"capella_beacon_block_test_helpers.go",
"phase0_beacon_block_test_helpers.go",
"test_helpers.go",
],

View File

@@ -0,0 +1,538 @@
package test_helpers
import (
"github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware"
"github.com/prysmaticlabs/prysm/v3/encoding/bytesutil"
enginev1 "github.com/prysmaticlabs/prysm/v3/proto/engine/v1"
ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1"
)
func GenerateProtoCapellaBeaconBlock() *ethpb.BeaconBlockCapella {
return &ethpb.BeaconBlockCapella{
Slot: 1,
ProposerIndex: 2,
ParentRoot: FillByteSlice(32, 3),
StateRoot: FillByteSlice(32, 4),
Body: &ethpb.BeaconBlockBodyCapella{
RandaoReveal: FillByteSlice(96, 5),
Eth1Data: &ethpb.Eth1Data{
DepositRoot: FillByteSlice(32, 6),
DepositCount: 7,
BlockHash: FillByteSlice(32, 8),
},
Graffiti: FillByteSlice(32, 9),
ProposerSlashings: []*ethpb.ProposerSlashing{
{
Header_1: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 10,
ProposerIndex: 11,
ParentRoot: FillByteSlice(32, 12),
StateRoot: FillByteSlice(32, 13),
BodyRoot: FillByteSlice(32, 14),
},
Signature: FillByteSlice(96, 15),
},
Header_2: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 16,
ProposerIndex: 17,
ParentRoot: FillByteSlice(32, 18),
StateRoot: FillByteSlice(32, 19),
BodyRoot: FillByteSlice(32, 20),
},
Signature: FillByteSlice(96, 21),
},
},
{
Header_1: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 22,
ProposerIndex: 23,
ParentRoot: FillByteSlice(32, 24),
StateRoot: FillByteSlice(32, 25),
BodyRoot: FillByteSlice(32, 26),
},
Signature: FillByteSlice(96, 27),
},
Header_2: &ethpb.SignedBeaconBlockHeader{
Header: &ethpb.BeaconBlockHeader{
Slot: 28,
ProposerIndex: 29,
ParentRoot: FillByteSlice(32, 30),
StateRoot: FillByteSlice(32, 31),
BodyRoot: FillByteSlice(32, 32),
},
Signature: FillByteSlice(96, 33),
},
},
},
AttesterSlashings: []*ethpb.AttesterSlashing{
{
Attestation_1: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{34, 35},
Data: &ethpb.AttestationData{
Slot: 36,
CommitteeIndex: 37,
BeaconBlockRoot: FillByteSlice(32, 38),
Source: &ethpb.Checkpoint{
Epoch: 39,
Root: FillByteSlice(32, 40),
},
Target: &ethpb.Checkpoint{
Epoch: 41,
Root: FillByteSlice(32, 42),
},
},
Signature: FillByteSlice(96, 43),
},
Attestation_2: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{44, 45},
Data: &ethpb.AttestationData{
Slot: 46,
CommitteeIndex: 47,
BeaconBlockRoot: FillByteSlice(32, 38),
Source: &ethpb.Checkpoint{
Epoch: 49,
Root: FillByteSlice(32, 50),
},
Target: &ethpb.Checkpoint{
Epoch: 51,
Root: FillByteSlice(32, 52),
},
},
Signature: FillByteSlice(96, 53),
},
},
{
Attestation_1: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{54, 55},
Data: &ethpb.AttestationData{
Slot: 56,
CommitteeIndex: 57,
BeaconBlockRoot: FillByteSlice(32, 38),
Source: &ethpb.Checkpoint{
Epoch: 59,
Root: FillByteSlice(32, 60),
},
Target: &ethpb.Checkpoint{
Epoch: 61,
Root: FillByteSlice(32, 62),
},
},
Signature: FillByteSlice(96, 63),
},
Attestation_2: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{64, 65},
Data: &ethpb.AttestationData{
Slot: 66,
CommitteeIndex: 67,
BeaconBlockRoot: FillByteSlice(32, 38),
Source: &ethpb.Checkpoint{
Epoch: 69,
Root: FillByteSlice(32, 70),
},
Target: &ethpb.Checkpoint{
Epoch: 71,
Root: FillByteSlice(32, 72),
},
},
Signature: FillByteSlice(96, 73),
},
},
},
Attestations: []*ethpb.Attestation{
{
AggregationBits: FillByteSlice(4, 74),
Data: &ethpb.AttestationData{
Slot: 75,
CommitteeIndex: 76,
BeaconBlockRoot: FillByteSlice(32, 38),
Source: &ethpb.Checkpoint{
Epoch: 78,
Root: FillByteSlice(32, 79),
},
Target: &ethpb.Checkpoint{
Epoch: 80,
Root: FillByteSlice(32, 81),
},
},
Signature: FillByteSlice(96, 82),
},
{
AggregationBits: FillByteSlice(4, 83),
Data: &ethpb.AttestationData{
Slot: 84,
CommitteeIndex: 85,
BeaconBlockRoot: FillByteSlice(32, 38),
Source: &ethpb.Checkpoint{
Epoch: 87,
Root: FillByteSlice(32, 88),
},
Target: &ethpb.Checkpoint{
Epoch: 89,
Root: FillByteSlice(32, 90),
},
},
Signature: FillByteSlice(96, 91),
},
},
Deposits: []*ethpb.Deposit{
{
Proof: FillByteArraySlice(33, FillByteSlice(32, 92)),
Data: &ethpb.Deposit_Data{
PublicKey: FillByteSlice(48, 94),
WithdrawalCredentials: FillByteSlice(32, 95),
Amount: 96,
Signature: FillByteSlice(96, 97),
},
},
{
Proof: FillByteArraySlice(33, FillByteSlice(32, 98)),
Data: &ethpb.Deposit_Data{
PublicKey: FillByteSlice(48, 100),
WithdrawalCredentials: FillByteSlice(32, 101),
Amount: 102,
Signature: FillByteSlice(96, 103),
},
},
},
VoluntaryExits: []*ethpb.SignedVoluntaryExit{
{
Exit: &ethpb.VoluntaryExit{
Epoch: 104,
ValidatorIndex: 105,
},
Signature: FillByteSlice(96, 106),
},
{
Exit: &ethpb.VoluntaryExit{
Epoch: 107,
ValidatorIndex: 108,
},
Signature: FillByteSlice(96, 109),
},
},
SyncAggregate: &ethpb.SyncAggregate{
SyncCommitteeBits: FillByteSlice(64, 110),
SyncCommitteeSignature: FillByteSlice(96, 111),
},
ExecutionPayload: &enginev1.ExecutionPayloadCapella{
ParentHash: FillByteSlice(32, 112),
FeeRecipient: FillByteSlice(20, 113),
StateRoot: FillByteSlice(32, 114),
ReceiptsRoot: FillByteSlice(32, 115),
LogsBloom: FillByteSlice(256, 116),
PrevRandao: FillByteSlice(32, 117),
BlockNumber: 118,
GasLimit: 119,
GasUsed: 120,
Timestamp: 121,
ExtraData: FillByteSlice(32, 122),
BaseFeePerGas: FillByteSlice(32, 123),
BlockHash: FillByteSlice(32, 124),
Transactions: [][]byte{
FillByteSlice(32, 125),
FillByteSlice(32, 126),
},
Withdrawals: []*enginev1.Withdrawal{
{
Index: 127,
ValidatorIndex: 128,
Address: FillByteSlice(20, 129),
Amount: 130,
},
{
Index: 131,
ValidatorIndex: 132,
Address: FillByteSlice(20, 133),
Amount: 134,
},
},
},
BlsToExecutionChanges: []*ethpb.SignedBLSToExecutionChange{
{
Message: &ethpb.BLSToExecutionChange{
ValidatorIndex: 135,
FromBlsPubkey: FillByteSlice(48, 136),
ToExecutionAddress: FillByteSlice(20, 137),
},
Signature: FillByteSlice(96, 138),
},
{
Message: &ethpb.BLSToExecutionChange{
ValidatorIndex: 139,
FromBlsPubkey: FillByteSlice(48, 140),
ToExecutionAddress: FillByteSlice(20, 141),
},
Signature: FillByteSlice(96, 142),
},
},
},
}
}
func GenerateJsonCapellaBeaconBlock() *apimiddleware.BeaconBlockCapellaJson {
return &apimiddleware.BeaconBlockCapellaJson{
Slot: "1",
ProposerIndex: "2",
ParentRoot: FillEncodedByteSlice(32, 3),
StateRoot: FillEncodedByteSlice(32, 4),
Body: &apimiddleware.BeaconBlockBodyCapellaJson{
RandaoReveal: FillEncodedByteSlice(96, 5),
Eth1Data: &apimiddleware.Eth1DataJson{
DepositRoot: FillEncodedByteSlice(32, 6),
DepositCount: "7",
BlockHash: FillEncodedByteSlice(32, 8),
},
Graffiti: FillEncodedByteSlice(32, 9),
ProposerSlashings: []*apimiddleware.ProposerSlashingJson{
{
Header_1: &apimiddleware.SignedBeaconBlockHeaderJson{
Header: &apimiddleware.BeaconBlockHeaderJson{
Slot: "10",
ProposerIndex: "11",
ParentRoot: FillEncodedByteSlice(32, 12),
StateRoot: FillEncodedByteSlice(32, 13),
BodyRoot: FillEncodedByteSlice(32, 14),
},
Signature: FillEncodedByteSlice(96, 15),
},
Header_2: &apimiddleware.SignedBeaconBlockHeaderJson{
Header: &apimiddleware.BeaconBlockHeaderJson{
Slot: "16",
ProposerIndex: "17",
ParentRoot: FillEncodedByteSlice(32, 18),
StateRoot: FillEncodedByteSlice(32, 19),
BodyRoot: FillEncodedByteSlice(32, 20),
},
Signature: FillEncodedByteSlice(96, 21),
},
},
{
Header_1: &apimiddleware.SignedBeaconBlockHeaderJson{
Header: &apimiddleware.BeaconBlockHeaderJson{
Slot: "22",
ProposerIndex: "23",
ParentRoot: FillEncodedByteSlice(32, 24),
StateRoot: FillEncodedByteSlice(32, 25),
BodyRoot: FillEncodedByteSlice(32, 26),
},
Signature: FillEncodedByteSlice(96, 27),
},
Header_2: &apimiddleware.SignedBeaconBlockHeaderJson{
Header: &apimiddleware.BeaconBlockHeaderJson{
Slot: "28",
ProposerIndex: "29",
ParentRoot: FillEncodedByteSlice(32, 30),
StateRoot: FillEncodedByteSlice(32, 31),
BodyRoot: FillEncodedByteSlice(32, 32),
},
Signature: FillEncodedByteSlice(96, 33),
},
},
},
AttesterSlashings: []*apimiddleware.AttesterSlashingJson{
{
Attestation_1: &apimiddleware.IndexedAttestationJson{
AttestingIndices: []string{"34", "35"},
Data: &apimiddleware.AttestationDataJson{
Slot: "36",
CommitteeIndex: "37",
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
Source: &apimiddleware.CheckpointJson{
Epoch: "39",
Root: FillEncodedByteSlice(32, 40),
},
Target: &apimiddleware.CheckpointJson{
Epoch: "41",
Root: FillEncodedByteSlice(32, 42),
},
},
Signature: FillEncodedByteSlice(96, 43),
},
Attestation_2: &apimiddleware.IndexedAttestationJson{
AttestingIndices: []string{"44", "45"},
Data: &apimiddleware.AttestationDataJson{
Slot: "46",
CommitteeIndex: "47",
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
Source: &apimiddleware.CheckpointJson{
Epoch: "49",
Root: FillEncodedByteSlice(32, 50),
},
Target: &apimiddleware.CheckpointJson{
Epoch: "51",
Root: FillEncodedByteSlice(32, 52),
},
},
Signature: FillEncodedByteSlice(96, 53),
},
},
{
Attestation_1: &apimiddleware.IndexedAttestationJson{
AttestingIndices: []string{"54", "55"},
Data: &apimiddleware.AttestationDataJson{
Slot: "56",
CommitteeIndex: "57",
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
Source: &apimiddleware.CheckpointJson{
Epoch: "59",
Root: FillEncodedByteSlice(32, 60),
},
Target: &apimiddleware.CheckpointJson{
Epoch: "61",
Root: FillEncodedByteSlice(32, 62),
},
},
Signature: FillEncodedByteSlice(96, 63),
},
Attestation_2: &apimiddleware.IndexedAttestationJson{
AttestingIndices: []string{"64", "65"},
Data: &apimiddleware.AttestationDataJson{
Slot: "66",
CommitteeIndex: "67",
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
Source: &apimiddleware.CheckpointJson{
Epoch: "69",
Root: FillEncodedByteSlice(32, 70),
},
Target: &apimiddleware.CheckpointJson{
Epoch: "71",
Root: FillEncodedByteSlice(32, 72),
},
},
Signature: FillEncodedByteSlice(96, 73),
},
},
},
Attestations: []*apimiddleware.AttestationJson{
{
AggregationBits: FillEncodedByteSlice(4, 74),
Data: &apimiddleware.AttestationDataJson{
Slot: "75",
CommitteeIndex: "76",
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
Source: &apimiddleware.CheckpointJson{
Epoch: "78",
Root: FillEncodedByteSlice(32, 79),
},
Target: &apimiddleware.CheckpointJson{
Epoch: "80",
Root: FillEncodedByteSlice(32, 81),
},
},
Signature: FillEncodedByteSlice(96, 82),
},
{
AggregationBits: FillEncodedByteSlice(4, 83),
Data: &apimiddleware.AttestationDataJson{
Slot: "84",
CommitteeIndex: "85",
BeaconBlockRoot: FillEncodedByteSlice(32, 38),
Source: &apimiddleware.CheckpointJson{
Epoch: "87",
Root: FillEncodedByteSlice(32, 88),
},
Target: &apimiddleware.CheckpointJson{
Epoch: "89",
Root: FillEncodedByteSlice(32, 90),
},
},
Signature: FillEncodedByteSlice(96, 91),
},
},
Deposits: []*apimiddleware.DepositJson{
{
Proof: FillEncodedByteArraySlice(33, FillEncodedByteSlice(32, 92)),
Data: &apimiddleware.Deposit_DataJson{
PublicKey: FillEncodedByteSlice(48, 94),
WithdrawalCredentials: FillEncodedByteSlice(32, 95),
Amount: "96",
Signature: FillEncodedByteSlice(96, 97),
},
},
{
Proof: FillEncodedByteArraySlice(33, FillEncodedByteSlice(32, 98)),
Data: &apimiddleware.Deposit_DataJson{
PublicKey: FillEncodedByteSlice(48, 100),
WithdrawalCredentials: FillEncodedByteSlice(32, 101),
Amount: "102",
Signature: FillEncodedByteSlice(96, 103),
},
},
},
VoluntaryExits: []*apimiddleware.SignedVoluntaryExitJson{
{
Exit: &apimiddleware.VoluntaryExitJson{
Epoch: "104",
ValidatorIndex: "105",
},
Signature: FillEncodedByteSlice(96, 106),
},
{
Exit: &apimiddleware.VoluntaryExitJson{
Epoch: "107",
ValidatorIndex: "108",
},
Signature: FillEncodedByteSlice(96, 109),
},
},
SyncAggregate: &apimiddleware.SyncAggregateJson{
SyncCommitteeBits: FillEncodedByteSlice(64, 110),
SyncCommitteeSignature: FillEncodedByteSlice(96, 111),
},
ExecutionPayload: &apimiddleware.ExecutionPayloadCapellaJson{
ParentHash: FillEncodedByteSlice(32, 112),
FeeRecipient: FillEncodedByteSlice(20, 113),
StateRoot: FillEncodedByteSlice(32, 114),
ReceiptsRoot: FillEncodedByteSlice(32, 115),
LogsBloom: FillEncodedByteSlice(256, 116),
PrevRandao: FillEncodedByteSlice(32, 117),
BlockNumber: "118",
GasLimit: "119",
GasUsed: "120",
TimeStamp: "121",
ExtraData: FillEncodedByteSlice(32, 122),
BaseFeePerGas: bytesutil.LittleEndianBytesToBigInt(FillByteSlice(32, 123)).String(),
BlockHash: FillEncodedByteSlice(32, 124),
Transactions: []string{
FillEncodedByteSlice(32, 125),
FillEncodedByteSlice(32, 126),
},
Withdrawals: []*apimiddleware.WithdrawalJson{
{
WithdrawalIndex: "127",
ValidatorIndex: "128",
ExecutionAddress: FillEncodedByteSlice(20, 129),
Amount: "130",
},
{
WithdrawalIndex: "131",
ValidatorIndex: "132",
ExecutionAddress: FillEncodedByteSlice(20, 133),
Amount: "134",
},
},
},
BLSToExecutionChanges: []*apimiddleware.SignedBLSToExecutionChangeJson{
{
Message: &apimiddleware.BLSToExecutionChangeJson{
ValidatorIndex: "135",
FromBLSPubkey: FillEncodedByteSlice(48, 136),
ToExecutionAddress: FillEncodedByteSlice(20, 137),
},
Signature: FillEncodedByteSlice(96, 138),
},
{
Message: &apimiddleware.BLSToExecutionChangeJson{
ValidatorIndex: "139",
FromBLSPubkey: FillEncodedByteSlice(48, 140),
ToExecutionAddress: FillEncodedByteSlice(20, 141),
},
Signature: FillEncodedByteSlice(96, 142),
},
},
},
}
}