diff --git a/beacon-chain/rpc/apimiddleware/custom_hooks.go b/beacon-chain/rpc/apimiddleware/custom_hooks.go index 5ccf6405f6..c451c2d15f 100644 --- a/beacon-chain/rpc/apimiddleware/custom_hooks.go +++ b/beacon-chain/rpc/apimiddleware/custom_hooks.go @@ -422,31 +422,31 @@ func prepareValidatorAggregates(body []byte, responseContainer interface{}) (api } type phase0BlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *SignedBeaconBlockContainerJson `json:"data"` ExecutionOptimistic bool `json:"execution_optimistic"` } type altairBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *SignedBeaconBlockAltairContainerJson `json:"data"` ExecutionOptimistic bool `json:"execution_optimistic"` } type bellatrixBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *SignedBeaconBlockBellatrixContainerJson `json:"data"` ExecutionOptimistic bool `json:"execution_optimistic"` } type bellatrixBlindedBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *SignedBlindedBeaconBlockBellatrixContainerJson `json:"data"` ExecutionOptimistic bool `json:"execution_optimistic"` } type capellaBlindedBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *SignedBlindedBeaconBlockCapellaContainerJson `json:"data"` ExecutionOptimistic bool `json:"execution_optimistic"` } @@ -553,22 +553,22 @@ func serializeBlindedBlock(response interface{}) (apimiddleware.RunDefault, []by } type phase0StateResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconStateJson `json:"data"` } type altairStateResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconStateAltairJson `json:"data"` } type bellatrixStateResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconStateBellatrixJson `json:"data"` } type capellaStateResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconStateCapellaJson `json:"data"` } @@ -612,22 +612,22 @@ func serializeV2State(response interface{}) (apimiddleware.RunDefault, []byte, a } type phase0ProduceBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconBlockJson `json:"data"` } type altairProduceBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconBlockAltairJson `json:"data"` } type bellatrixProduceBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconBlockBellatrixJson `json:"data"` } type bellatrixProduceBlindedBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BlindedBeaconBlockBellatrixJson `json:"data"` } diff --git a/beacon-chain/rpc/apimiddleware/structs.go b/beacon-chain/rpc/apimiddleware/structs.go index 3072b676da..3f554a44d5 100644 --- a/beacon-chain/rpc/apimiddleware/structs.go +++ b/beacon-chain/rpc/apimiddleware/structs.go @@ -239,12 +239,12 @@ type ProduceBlockResponseJson struct { } type ProduceBlockResponseV2Json struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BeaconBlockContainerV2Json `json:"data"` } type ProduceBlindedBlockResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Data *BlindedBeaconBlockContainerJson `json:"data"` } @@ -685,7 +685,7 @@ type PeerJson struct { } type VersionJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` } type BeaconStateJson struct { @@ -1000,7 +1000,7 @@ func (*SszResponseJson) SSZOptimistic() bool { } type VersionedSSZResponseJson struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` ExecutionOptimistic bool `json:"execution_optimistic"` Data string `json:"data"` } diff --git a/encoding/bytesutil/bytes.go b/encoding/bytesutil/bytes.go index 8ee328dff8..21f7c6f554 100644 --- a/encoding/bytesutil/bytes.go +++ b/encoding/bytesutil/bytes.go @@ -454,3 +454,9 @@ func LittleEndianBytesToBigInt(bytes []byte) *big.Int { // Integers are stored as little-endian, but big.Int expects big-endian. So we need to reverse the byte order before decoding. return new(big.Int).SetBytes(ReverseByteOrder(bytes)) } + +// BigIntToLittleEndianBytes takes a big integer and returns its bytes stored as little-endian +func BigIntToLittleEndianBytes(bigInt *big.Int) []byte { + // big.Int.Bytes() returns bytes in big-endian order, so we need to reverse the byte order + return ReverseByteOrder(bigInt.Bytes()) +} diff --git a/encoding/bytesutil/bytes_test.go b/encoding/bytesutil/bytes_test.go index 61a57cc574..58244b3942 100644 --- a/encoding/bytesutil/bytes_test.go +++ b/encoding/bytesutil/bytes_test.go @@ -662,3 +662,11 @@ func TestLittleEndianBytesToBigInt(t *testing.T) { expected := new(big.Int).SetInt64(1234567890) assert.DeepEqual(t, expected, converted) } + +func TestBigIntToLittleEndianBytes(t *testing.T) { + expected := make([]byte, 4) + binary.LittleEndian.PutUint32(expected, 1234567890) + bigInt := new(big.Int).SetUint64(1234567890) + converted := bytesutil.BigIntToLittleEndianBytes(bigInt) + assert.DeepEqual(t, expected, converted) +} diff --git a/validator/client/beacon-api/BUILD.bazel b/validator/client/beacon-api/BUILD.bazel index 1c5f6a20f0..5eb4bb2c5b 100644 --- a/validator/client/beacon-api/BUILD.bazel +++ b/validator/client/beacon-api/BUILD.bazel @@ -8,8 +8,10 @@ go_library( "beacon_api_helpers.go", "beacon_api_validator_client.go", "beacon_block_json_helpers.go", + "beacon_block_proto_helpers.go", "domain_data.go", "genesis.go", + "get_beacon_block.go", "index.go", "json_rest_handler.go", "propose_beacon_block.go", @@ -26,6 +28,7 @@ go_library( "//consensus-types/primitives:go_default_library", "//encoding/bytesutil:go_default_library", "//network/forks:go_default_library", + "//proto/engine/v1:go_default_library", "//proto/prysm/v1alpha1:go_default_library", "//validator/client/iface:go_default_library", "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", @@ -44,8 +47,13 @@ go_test( "beacon_api_helpers_test.go", "beacon_api_validator_client_test.go", "beacon_block_json_helpers_test.go", + "beacon_block_proto_helpers_test.go", "domain_data_test.go", "genesis_test.go", + "get_beacon_block_altair_test.go", + "get_beacon_block_bellatrix_test.go", + "get_beacon_block_phase0_test.go", + "get_beacon_block_test.go", "index_test.go", "json_rest_handler_test.go", "propose_beacon_block_altair_test.go", diff --git a/validator/client/beacon-api/beacon_api_validator_client.go b/validator/client/beacon-api/beacon_api_validator_client.go index 1066efc91a..d4a7edf5e2 100644 --- a/validator/client/beacon-api/beacon_api_validator_client.go +++ b/validator/client/beacon-api/beacon_api_validator_client.go @@ -71,13 +71,8 @@ func (c *beaconApiValidatorClient) GetAttestationData(_ context.Context, in *eth return c.getAttestationData(in.Slot, in.CommitteeIndex) } -func (c *beaconApiValidatorClient) GetBeaconBlock(ctx context.Context, in *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) { - if c.fallbackClient != nil { - return c.fallbackClient.GetBeaconBlock(ctx, in) - } - - // TODO: Implement me - panic("beaconApiValidatorClient.GetBeaconBlock is not implemented. To use a fallback client, create this validator with NewBeaconApiValidatorClientWithFallback instead.") +func (c *beaconApiValidatorClient) GetBeaconBlock(_ context.Context, in *ethpb.BlockRequest) (*ethpb.GenericBeaconBlock, error) { + return c.getBeaconBlock(in.Slot, in.RandaoReveal, in.Graffiti) } func (c *beaconApiValidatorClient) GetFeeRecipientByPubKey(ctx context.Context, in *ethpb.FeeRecipientByPubKeyRequest) (*ethpb.FeeRecipientByPubKeyResponse, error) { diff --git a/validator/client/beacon-api/beacon_block_proto_helpers.go b/validator/client/beacon-api/beacon_block_proto_helpers.go new file mode 100644 index 0000000000..e9414dc860 --- /dev/null +++ b/validator/client/beacon-api/beacon_block_proto_helpers.go @@ -0,0 +1,352 @@ +package beacon_api + +import ( + "strconv" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" + "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" +) + +func convertProposerSlashingsToProto(jsonProposerSlashings []*apimiddleware.ProposerSlashingJson) ([]*ethpb.ProposerSlashing, error) { + proposerSlashings := make([]*ethpb.ProposerSlashing, len(jsonProposerSlashings)) + + for index, jsonProposerSlashing := range jsonProposerSlashings { + if jsonProposerSlashing == nil { + return nil, errors.Errorf("proposer slashing at index `%d` is nil", index) + } + + header1, err := convertProposerSlashingSignedHeaderToProto(jsonProposerSlashing.Header_1) + if err != nil { + return nil, errors.Wrap(err, "failed to get proposer header 1") + } + + header2, err := convertProposerSlashingSignedHeaderToProto(jsonProposerSlashing.Header_2) + if err != nil { + return nil, errors.Wrap(err, "failed to get proposer header 2") + } + + proposerSlashings[index] = ðpb.ProposerSlashing{ + Header_1: header1, + Header_2: header2, + } + } + + return proposerSlashings, nil +} + +func convertProposerSlashingSignedHeaderToProto(signedHeader *apimiddleware.SignedBeaconBlockHeaderJson) (*ethpb.SignedBeaconBlockHeader, error) { + if signedHeader == nil { + return nil, errors.New("signed header is nil") + } + + if signedHeader.Header == nil { + return nil, errors.New("header is nil") + } + + slot, err := strconv.ParseUint(signedHeader.Header.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse header slot `%s`", signedHeader.Header.Slot) + } + + proposerIndex, err := strconv.ParseUint(signedHeader.Header.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse header proposer index `%s`", signedHeader.Header.ProposerIndex) + } + + parentRoot, err := hexutil.Decode(signedHeader.Header.ParentRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode header parent root `%s`", signedHeader.Header.ParentRoot) + } + + stateRoot, err := hexutil.Decode(signedHeader.Header.StateRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode header state root `%s`", signedHeader.Header.StateRoot) + } + + bodyRoot, err := hexutil.Decode(signedHeader.Header.BodyRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode header body root `%s`", signedHeader.Header.BodyRoot) + } + + signature, err := hexutil.Decode(signedHeader.Signature) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode signature `%s`", signedHeader.Signature) + } + + return ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: types.Slot(slot), + ProposerIndex: types.ValidatorIndex(proposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + BodyRoot: bodyRoot, + }, + Signature: signature, + }, nil +} + +func convertAttesterSlashingsToProto(jsonAttesterSlashings []*apimiddleware.AttesterSlashingJson) ([]*ethpb.AttesterSlashing, error) { + attesterSlashings := make([]*ethpb.AttesterSlashing, len(jsonAttesterSlashings)) + + for index, jsonAttesterSlashing := range jsonAttesterSlashings { + if jsonAttesterSlashing == nil { + return nil, errors.Errorf("attester slashing at index `%d` is nil", index) + } + + attestation1, err := convertAttestationToProto(jsonAttesterSlashing.Attestation_1) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestation 1") + } + + attestation2, err := convertAttestationToProto(jsonAttesterSlashing.Attestation_2) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestation 2") + } + + attesterSlashings[index] = ðpb.AttesterSlashing{ + Attestation_1: attestation1, + Attestation_2: attestation2, + } + } + + return attesterSlashings, nil +} + +func convertAttestationToProto(jsonAttestation *apimiddleware.IndexedAttestationJson) (*ethpb.IndexedAttestation, error) { + if jsonAttestation == nil { + return nil, errors.New("indexed attestation is nil") + } + + attestingIndices := make([]uint64, len(jsonAttestation.AttestingIndices)) + + for index, jsonAttestingIndex := range jsonAttestation.AttestingIndices { + attestingIndex, err := strconv.ParseUint(jsonAttestingIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse attesting index `%s`", jsonAttestingIndex) + } + + attestingIndices[index] = attestingIndex + } + + signature, err := hexutil.Decode(jsonAttestation.Signature) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode attestation signature `%s`", jsonAttestation.Signature) + } + + attestationData, err := convertAttestationDataToProto(jsonAttestation.Data) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestation data") + } + + return ðpb.IndexedAttestation{ + AttestingIndices: attestingIndices, + Data: attestationData, + Signature: signature, + }, nil +} + +func convertCheckpointToProto(jsonCheckpoint *apimiddleware.CheckpointJson) (*ethpb.Checkpoint, error) { + if jsonCheckpoint == nil { + return nil, errors.New("checkpoint is nil") + } + + epoch, err := strconv.ParseUint(jsonCheckpoint.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse checkpoint epoch `%s`", jsonCheckpoint.Epoch) + } + + root, err := hexutil.Decode(jsonCheckpoint.Root) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode checkpoint root `%s`", jsonCheckpoint.Root) + } + + return ðpb.Checkpoint{ + Epoch: types.Epoch(epoch), + Root: root, + }, nil +} + +func convertAttestationsToProto(jsonAttestations []*apimiddleware.AttestationJson) ([]*ethpb.Attestation, error) { + attestations := make([]*ethpb.Attestation, len(jsonAttestations)) + + for index, jsonAttestation := range jsonAttestations { + if jsonAttestation == nil { + return nil, errors.Errorf("attestation at index `%d` is nil", index) + } + + aggregationBits, err := hexutil.Decode(jsonAttestation.AggregationBits) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode aggregation bits `%s`", jsonAttestation.AggregationBits) + } + + attestationData, err := convertAttestationDataToProto(jsonAttestation.Data) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestation data") + } + + signature, err := hexutil.Decode(jsonAttestation.Signature) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode attestation signature `%s`", jsonAttestation.Signature) + } + + attestations[index] = ðpb.Attestation{ + AggregationBits: aggregationBits, + Data: attestationData, + Signature: signature, + } + } + + return attestations, nil +} + +func convertAttestationDataToProto(jsonAttestationData *apimiddleware.AttestationDataJson) (*ethpb.AttestationData, error) { + if jsonAttestationData == nil { + return nil, errors.New("attestation data is nil") + } + + slot, err := strconv.ParseUint(jsonAttestationData.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse attestation slot `%s`", jsonAttestationData.Slot) + } + + committeeIndex, err := strconv.ParseUint(jsonAttestationData.CommitteeIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse attestation committee index `%s`", jsonAttestationData.CommitteeIndex) + } + + beaconBlockRoot, err := hexutil.Decode(jsonAttestationData.BeaconBlockRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode attestation beacon block root `%s`", jsonAttestationData.BeaconBlockRoot) + } + + sourceCheckpoint, err := convertCheckpointToProto(jsonAttestationData.Source) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestation source checkpoint") + } + + targetCheckpoint, err := convertCheckpointToProto(jsonAttestationData.Target) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestation target checkpoint") + } + + return ðpb.AttestationData{ + Slot: types.Slot(slot), + CommitteeIndex: types.CommitteeIndex(committeeIndex), + BeaconBlockRoot: beaconBlockRoot, + Source: sourceCheckpoint, + Target: targetCheckpoint, + }, nil +} + +func convertDepositsToProto(jsonDeposits []*apimiddleware.DepositJson) ([]*ethpb.Deposit, error) { + deposits := make([]*ethpb.Deposit, len(jsonDeposits)) + + for depositIndex, jsonDeposit := range jsonDeposits { + if jsonDeposit == nil { + return nil, errors.Errorf("deposit at index `%d` is nil", depositIndex) + } + + proofs := make([][]byte, len(jsonDeposit.Proof)) + for proofIndex, jsonProof := range jsonDeposit.Proof { + proof, err := hexutil.Decode(jsonProof) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode deposit proof `%s`", jsonProof) + } + + proofs[proofIndex] = proof + } + + if jsonDeposit.Data == nil { + return nil, errors.Errorf("deposit data at index `%d` is nil", depositIndex) + } + + pubkey, err := hexutil.Decode(jsonDeposit.Data.PublicKey) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode deposit public key `%s`", jsonDeposit.Data.PublicKey) + } + + withdrawalCredentials, err := hexutil.Decode(jsonDeposit.Data.WithdrawalCredentials) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode deposit withdrawal credentials `%s`", jsonDeposit.Data.WithdrawalCredentials) + } + + amount, err := strconv.ParseUint(jsonDeposit.Data.Amount, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse deposit amount `%s`", jsonDeposit.Data.Amount) + } + + signature, err := hexutil.Decode(jsonDeposit.Data.Signature) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode signature `%s`", jsonDeposit.Data.Signature) + } + + deposits[depositIndex] = ðpb.Deposit{ + Proof: proofs, + Data: ðpb.Deposit_Data{ + PublicKey: pubkey, + WithdrawalCredentials: withdrawalCredentials, + Amount: amount, + Signature: signature, + }, + } + } + + return deposits, nil +} + +func convertVoluntaryExitsToProto(jsonVoluntaryExits []*apimiddleware.SignedVoluntaryExitJson) ([]*ethpb.SignedVoluntaryExit, error) { + attestingIndices := make([]*ethpb.SignedVoluntaryExit, len(jsonVoluntaryExits)) + + for index, jsonVoluntaryExit := range jsonVoluntaryExits { + if jsonVoluntaryExit == nil { + return nil, errors.Errorf("signed voluntary exit at index `%d` is nil", index) + } + + if jsonVoluntaryExit.Exit == nil { + return nil, errors.Errorf("voluntary exit at index `%d` is nil", index) + } + + epoch, err := strconv.ParseUint(jsonVoluntaryExit.Exit.Epoch, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse voluntary exit epoch `%s`", jsonVoluntaryExit.Exit.Epoch) + } + + validatorIndex, err := strconv.ParseUint(jsonVoluntaryExit.Exit.ValidatorIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse voluntary exit validator index `%s`", jsonVoluntaryExit.Exit.ValidatorIndex) + } + + signature, err := hexutil.Decode(jsonVoluntaryExit.Signature) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode signature `%s`", jsonVoluntaryExit.Signature) + } + + attestingIndices[index] = ðpb.SignedVoluntaryExit{ + Exit: ðpb.VoluntaryExit{ + Epoch: types.Epoch(epoch), + ValidatorIndex: types.ValidatorIndex(validatorIndex), + }, + Signature: signature, + } + } + + return attestingIndices, nil +} + +func convertTransactionsToProto(jsonTransactions []string) ([][]byte, error) { + transactions := make([][]byte, len(jsonTransactions)) + + for index, jsonTransaction := range jsonTransactions { + transaction, err := hexutil.Decode(jsonTransaction) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode transaction `%s`", jsonTransaction) + } + + transactions[index] = transaction + } + + return transactions, nil +} diff --git a/validator/client/beacon-api/beacon_block_proto_helpers_test.go b/validator/client/beacon-api/beacon_block_proto_helpers_test.go new file mode 100644 index 0000000000..3fb44d665d --- /dev/null +++ b/validator/client/beacon-api/beacon_block_proto_helpers_test.go @@ -0,0 +1,1187 @@ +package beacon_api + +import ( + "testing" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" + "github.com/prysmaticlabs/prysm/v3/testing/assert" + "github.com/prysmaticlabs/prysm/v3/testing/require" +) + +func TestBeaconBlockProtoHelpers_ConvertProposerSlashingsToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() []*apimiddleware.ProposerSlashingJson + expectedResult []*ethpb.ProposerSlashing + expectedErrorMessage string + }{ + { + name: "nil proposer slashing", + expectedErrorMessage: "proposer slashing at index `0` is nil", + generateInput: func() []*apimiddleware.ProposerSlashingJson { + return []*apimiddleware.ProposerSlashingJson{ + nil, + } + }, + }, + { + name: "bad header 1", + expectedErrorMessage: "failed to get proposer header 1", + generateInput: func() []*apimiddleware.ProposerSlashingJson { + return []*apimiddleware.ProposerSlashingJson{ + { + Header_1: nil, + Header_2: nil, + }, + } + }, + }, + { + name: "bad header 2", + expectedErrorMessage: "failed to get proposer header 2", + generateInput: func() []*apimiddleware.ProposerSlashingJson { + input := generateProposerSlashings() + input[0].Header_2 = nil + return input + }, + }, + { + name: "valid", + generateInput: generateProposerSlashings, + expectedResult: []*ethpb.ProposerSlashing{ + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 2, + ParentRoot: []byte{3}, + StateRoot: []byte{4}, + BodyRoot: []byte{5}, + }, + Signature: []byte{6}, + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 7, + ProposerIndex: 8, + ParentRoot: []byte{9}, + StateRoot: []byte{10}, + BodyRoot: []byte{11}, + }, + Signature: []byte{12}, + }, + }, + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 13, + ProposerIndex: 14, + ParentRoot: []byte{15}, + StateRoot: []byte{16}, + BodyRoot: []byte{17}, + }, + Signature: []byte{18}, + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 19, + ProposerIndex: 20, + ParentRoot: []byte{21}, + StateRoot: []byte{22}, + BodyRoot: []byte{23}, + }, + Signature: []byte{24}, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertProposerSlashingsToProto(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_ConvertProposerSlashingSignedHeaderToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() *apimiddleware.SignedBeaconBlockHeaderJson + expectedResult *ethpb.SignedBeaconBlockHeader + expectedErrorMessage string + }{ + { + name: "nil signed header", + expectedErrorMessage: "signed header is nil", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { return nil }, + }, + { + name: "nil header", + expectedErrorMessage: "header is nil", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Header = nil + return input + }, + }, + { + name: "bad slot", + expectedErrorMessage: "failed to parse header slot `foo`", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Header.Slot = "foo" + return input + }, + }, + { + name: "bad proposer index", + expectedErrorMessage: "failed to parse header proposer index `bar`", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Header.ProposerIndex = "bar" + return input + }, + }, + { + name: "bad parent root", + expectedErrorMessage: "failed to decode header parent root `foo`", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Header.ParentRoot = "foo" + return input + }, + }, + { + name: "bad state root", + expectedErrorMessage: "failed to decode header state root `bar`", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Header.StateRoot = "bar" + return input + }, + }, + { + name: "bad body root", + expectedErrorMessage: "failed to decode header body root `foo`", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Header.BodyRoot = "foo" + return input + }, + }, + { + name: "bad parent root", + expectedErrorMessage: "failed to decode signature `bar`", + generateInput: func() *apimiddleware.SignedBeaconBlockHeaderJson { + input := generateSignedBeaconBlockHeader() + input.Signature = "bar" + return input + }, + }, + { + name: "valid", + generateInput: generateSignedBeaconBlockHeader, + expectedResult: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 1, + ProposerIndex: 2, + ParentRoot: []byte{3}, + StateRoot: []byte{4}, + BodyRoot: []byte{5}, + }, + Signature: []byte{6}, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertProposerSlashingSignedHeaderToProto(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_ConvertAttesterSlashingsToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() []*apimiddleware.AttesterSlashingJson + expectedResult []*ethpb.AttesterSlashing + expectedErrorMessage string + }{ + { + name: "nil attester slashing", + expectedErrorMessage: "attester slashing at index `0` is nil", + generateInput: func() []*apimiddleware.AttesterSlashingJson { + return []*apimiddleware.AttesterSlashingJson{ + nil, + } + }, + }, + { + name: "bad attestation 1", + expectedErrorMessage: "failed to get attestation 1", + generateInput: func() []*apimiddleware.AttesterSlashingJson { + return []*apimiddleware.AttesterSlashingJson{ + { + Attestation_1: nil, + Attestation_2: nil, + }, + } + }, + }, + { + name: "bad attestation 2", + expectedErrorMessage: "failed to get attestation 2", + generateInput: func() []*apimiddleware.AttesterSlashingJson { + input := generateAttesterSlashings() + input[0].Attestation_2 = nil + return input + }, + }, + { + name: "valid", + generateInput: generateAttesterSlashings, + expectedResult: []*ethpb.AttesterSlashing{ + { + Attestation_1: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{1, 2}, + Data: ðpb.AttestationData{ + Slot: 3, + CommitteeIndex: 4, + BeaconBlockRoot: []byte{5}, + Source: ðpb.Checkpoint{ + Epoch: 6, + Root: []byte{7}, + }, + Target: ðpb.Checkpoint{ + Epoch: 8, + Root: []byte{9}, + }, + }, + Signature: []byte{10}, + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{11, 12}, + Data: ðpb.AttestationData{ + Slot: 13, + CommitteeIndex: 14, + BeaconBlockRoot: []byte{15}, + Source: ðpb.Checkpoint{ + Epoch: 16, + Root: []byte{17}, + }, + Target: ðpb.Checkpoint{ + Epoch: 18, + Root: []byte{19}, + }, + }, + Signature: []byte{20}, + }, + }, + { + Attestation_1: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{21, 22}, + Data: ðpb.AttestationData{ + Slot: 23, + CommitteeIndex: 24, + BeaconBlockRoot: []byte{25}, + Source: ðpb.Checkpoint{ + Epoch: 26, + Root: []byte{27}, + }, + Target: ðpb.Checkpoint{ + Epoch: 28, + Root: []byte{29}, + }, + }, + Signature: []byte{30}, + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{31, 32}, + Data: ðpb.AttestationData{ + Slot: 33, + CommitteeIndex: 34, + BeaconBlockRoot: []byte{35}, + Source: ðpb.Checkpoint{ + Epoch: 36, + Root: []byte{37}, + }, + Target: ðpb.Checkpoint{ + Epoch: 38, + Root: []byte{39}, + }, + }, + Signature: []byte{40}, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertAttesterSlashingsToProto(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_ConvertAttestationToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() *apimiddleware.IndexedAttestationJson + expectedResult *ethpb.IndexedAttestation + expectedErrorMessage string + }{ + { + name: "nil indexed attestation", + expectedErrorMessage: "indexed attestation is nil", + generateInput: func() *apimiddleware.IndexedAttestationJson { return nil }, + }, + { + name: "bad attesting index", + expectedErrorMessage: "failed to parse attesting index `foo`", + generateInput: func() *apimiddleware.IndexedAttestationJson { + input := generateIndexedAttestation() + input.AttestingIndices[0] = "foo" + return input + }, + }, + { + name: "bad signature", + expectedErrorMessage: "failed to decode attestation signature `bar`", + generateInput: func() *apimiddleware.IndexedAttestationJson { + input := generateIndexedAttestation() + input.Signature = "bar" + return input + }, + }, + { + name: "bad data", + expectedErrorMessage: "failed to get attestation data", + generateInput: func() *apimiddleware.IndexedAttestationJson { + input := generateIndexedAttestation() + input.Data = nil + return input + }, + }, + { + name: "valid", + generateInput: generateIndexedAttestation, + expectedResult: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{1, 2}, + Data: ðpb.AttestationData{ + Slot: 3, + CommitteeIndex: 4, + BeaconBlockRoot: []byte{5}, + Source: ðpb.Checkpoint{ + Epoch: 6, + Root: []byte{7}, + }, + Target: ðpb.Checkpoint{ + Epoch: 8, + Root: []byte{9}, + }, + }, + Signature: []byte{10}, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertAttestationToProto(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_ConvertCheckpointToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() *apimiddleware.CheckpointJson + expectedResult *ethpb.Checkpoint + expectedErrorMessage string + }{ + { + name: "nil checkpoint", + expectedErrorMessage: "checkpoint is nil", + generateInput: func() *apimiddleware.CheckpointJson { return nil }, + }, + { + name: "bad epoch", + expectedErrorMessage: "failed to parse checkpoint epoch `foo`", + generateInput: func() *apimiddleware.CheckpointJson { + input := generateCheckpoint() + input.Epoch = "foo" + return input + }, + }, + { + name: "bad root", + expectedErrorMessage: "failed to decode checkpoint root `bar`", + generateInput: func() *apimiddleware.CheckpointJson { + input := generateCheckpoint() + input.Root = "bar" + return input + }, + }, + { + name: "valid", + generateInput: generateCheckpoint, + expectedResult: ðpb.Checkpoint{ + Epoch: 1, + Root: []byte{2}, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertCheckpointToProto(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_ConvertAttestationsToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() []*apimiddleware.AttestationJson + expectedResult []*ethpb.Attestation + expectedErrorMessage string + }{ + { + name: "nil attestation", + expectedErrorMessage: "attestation at index `0` is nil", + generateInput: func() []*apimiddleware.AttestationJson { + return []*apimiddleware.AttestationJson{ + nil, + } + }, + }, + { + name: "bad aggregation bits", + expectedErrorMessage: "failed to decode aggregation bits `foo`", + generateInput: func() []*apimiddleware.AttestationJson { + input := generateAttestations() + input[0].AggregationBits = "foo" + return input + }, + }, + { + name: "bad data", + expectedErrorMessage: "failed to get attestation data", + generateInput: func() []*apimiddleware.AttestationJson { + input := generateAttestations() + input[0].Data = nil + return input + }, + }, + { + name: "bad signature", + expectedErrorMessage: "failed to decode attestation signature `bar`", + generateInput: func() []*apimiddleware.AttestationJson { + input := generateAttestations() + input[0].Signature = "bar" + return input + }, + }, + { + name: "valid", + generateInput: generateAttestations, + expectedResult: []*ethpb.Attestation{ + { + AggregationBits: []byte{1}, + Data: ðpb.AttestationData{ + Slot: 2, + CommitteeIndex: 3, + BeaconBlockRoot: []byte{4}, + Source: ðpb.Checkpoint{ + Epoch: 5, + Root: []byte{6}, + }, + Target: ðpb.Checkpoint{ + Epoch: 7, + Root: []byte{8}, + }, + }, + Signature: []byte{9}, + }, + { + AggregationBits: []byte{10}, + Data: ðpb.AttestationData{ + Slot: 11, + CommitteeIndex: 12, + BeaconBlockRoot: []byte{13}, + Source: ðpb.Checkpoint{ + Epoch: 14, + Root: []byte{15}, + }, + Target: ðpb.Checkpoint{ + Epoch: 16, + Root: []byte{17}, + }, + }, + Signature: []byte{18}, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertAttestationsToProto(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_ConvertAttestationDataToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() *apimiddleware.AttestationDataJson + expectedResult *ethpb.AttestationData + expectedErrorMessage string + }{ + { + name: "nil attestation data", + expectedErrorMessage: "attestation data is nil", + generateInput: func() *apimiddleware.AttestationDataJson { return nil }, + }, + { + name: "bad slot", + expectedErrorMessage: "failed to parse attestation slot `foo`", + generateInput: func() *apimiddleware.AttestationDataJson { + input := generateAttestationData() + input.Slot = "foo" + return input + }, + }, + { + name: "bad committee index", + expectedErrorMessage: "failed to parse attestation committee index `bar`", + generateInput: func() *apimiddleware.AttestationDataJson { + input := generateAttestationData() + input.CommitteeIndex = "bar" + return input + }, + }, + { + name: "bad beacon block root", + expectedErrorMessage: "failed to decode attestation beacon block root `foo`", + generateInput: func() *apimiddleware.AttestationDataJson { + input := generateAttestationData() + input.BeaconBlockRoot = "foo" + return input + }, + }, + { + name: "bad source checkpoint", + expectedErrorMessage: "failed to get attestation source checkpoint", + generateInput: func() *apimiddleware.AttestationDataJson { + input := generateAttestationData() + input.Source = nil + return input + }, + }, + { + name: "bad target checkpoint", + expectedErrorMessage: "failed to get attestation target checkpoint", + generateInput: func() *apimiddleware.AttestationDataJson { + input := generateAttestationData() + input.Target = nil + return input + }, + }, + { + name: "valid", + generateInput: generateAttestationData, + expectedResult: ðpb.AttestationData{ + Slot: 1, + CommitteeIndex: 2, + BeaconBlockRoot: []byte{3}, + Source: ðpb.Checkpoint{ + Epoch: 4, + Root: []byte{5}, + }, + Target: ðpb.Checkpoint{ + Epoch: 6, + Root: []byte{7}, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertAttestationDataToProto(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_ConvertDepositsToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() []*apimiddleware.DepositJson + expectedResult []*ethpb.Deposit + expectedErrorMessage string + }{ + { + name: "nil deposit", + expectedErrorMessage: "deposit at index `0` is nil", + generateInput: func() []*apimiddleware.DepositJson { + return []*apimiddleware.DepositJson{ + nil, + } + }, + }, + { + name: "bad proof", + expectedErrorMessage: "failed to decode deposit proof `foo`", + generateInput: func() []*apimiddleware.DepositJson { + input := generateDeposits() + input[0].Proof[0] = "foo" + return input + }, + }, + { + name: "nil data", + expectedErrorMessage: "deposit data at index `0` is nil", + generateInput: func() []*apimiddleware.DepositJson { + input := generateDeposits() + input[0].Data = nil + return input + }, + }, + { + name: "bad public key", + expectedErrorMessage: "failed to decode deposit public key `bar`", + generateInput: func() []*apimiddleware.DepositJson { + input := generateDeposits() + input[0].Data.PublicKey = "bar" + return input + }, + }, + { + name: "bad withdrawal credentials", + expectedErrorMessage: "failed to decode deposit withdrawal credentials `foo`", + generateInput: func() []*apimiddleware.DepositJson { + input := generateDeposits() + input[0].Data.WithdrawalCredentials = "foo" + return input + }, + }, + { + name: "bad amount", + expectedErrorMessage: "failed to parse deposit amount `bar`", + generateInput: func() []*apimiddleware.DepositJson { + input := generateDeposits() + input[0].Data.Amount = "bar" + return input + }, + }, + { + name: "bad signature", + expectedErrorMessage: "failed to decode signature `foo`", + generateInput: func() []*apimiddleware.DepositJson { + input := generateDeposits() + input[0].Data.Signature = "foo" + return input + }, + }, + { + name: "valid", + generateInput: generateDeposits, + expectedResult: []*ethpb.Deposit{ + { + Proof: [][]byte{ + {1}, + {2}, + }, + Data: ðpb.Deposit_Data{ + PublicKey: []byte{3}, + WithdrawalCredentials: []byte{4}, + Amount: 5, + Signature: []byte{6}, + }, + }, + { + Proof: [][]byte{ + {7}, + {8}, + }, + Data: ðpb.Deposit_Data{ + PublicKey: []byte{9}, + WithdrawalCredentials: []byte{10}, + Amount: 11, + Signature: []byte{12}, + }, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertDepositsToProto(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_ConvertVoluntaryExitsToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() []*apimiddleware.SignedVoluntaryExitJson + expectedResult []*ethpb.SignedVoluntaryExit + expectedErrorMessage string + }{ + { + name: "nil voluntary exit", + expectedErrorMessage: "signed voluntary exit at index `0` is nil", + generateInput: func() []*apimiddleware.SignedVoluntaryExitJson { + return []*apimiddleware.SignedVoluntaryExitJson{ + nil, + } + }, + }, + { + name: "nil data", + expectedErrorMessage: "voluntary exit at index `0` is nil", + generateInput: func() []*apimiddleware.SignedVoluntaryExitJson { + input := generateSignedVoluntaryExits() + input[0].Exit = nil + return input + }, + }, + { + name: "bad epoch", + expectedErrorMessage: "failed to parse voluntary exit epoch `foo`", + generateInput: func() []*apimiddleware.SignedVoluntaryExitJson { + input := generateSignedVoluntaryExits() + input[0].Exit.Epoch = "foo" + return input + }, + }, + { + name: "bad validator index", + expectedErrorMessage: "failed to parse voluntary exit validator index `bar`", + generateInput: func() []*apimiddleware.SignedVoluntaryExitJson { + input := generateSignedVoluntaryExits() + input[0].Exit.ValidatorIndex = "bar" + return input + }, + }, + { + name: "bad signature", + expectedErrorMessage: "failed to decode signature `foo`", + generateInput: func() []*apimiddleware.SignedVoluntaryExitJson { + input := generateSignedVoluntaryExits() + input[0].Signature = "foo" + return input + }, + }, + { + name: "valid", + generateInput: generateSignedVoluntaryExits, + expectedResult: []*ethpb.SignedVoluntaryExit{ + { + Exit: ðpb.VoluntaryExit{ + Epoch: 1, + ValidatorIndex: 2, + }, + Signature: []byte{3}, + }, + { + Exit: ðpb.VoluntaryExit{ + Epoch: 4, + ValidatorIndex: 5, + }, + Signature: []byte{6}, + }, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertVoluntaryExitsToProto(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_ConvertTransactionsToProto(t *testing.T) { + testCases := []struct { + name string + generateInput func() []string + expectedResult [][]byte + expectedErrorMessage string + }{ + { + name: "bad transaction", + expectedErrorMessage: "failed to decode transaction `foo`", + generateInput: func() []string { + return []string{ + "foo", + } + }, + }, + { + name: "valid", + generateInput: func() []string { + return []string{ + hexutil.Encode([]byte{1}), + hexutil.Encode([]byte{2}), + } + }, + expectedResult: [][]byte{ + {1}, + {2}, + }, + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + result, err := convertTransactionsToProto(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{ + { + Header_1: &apimiddleware.SignedBeaconBlockHeaderJson{ + Header: &apimiddleware.BeaconBlockHeaderJson{ + Slot: "1", + ProposerIndex: "2", + ParentRoot: hexutil.Encode([]byte{3}), + StateRoot: hexutil.Encode([]byte{4}), + BodyRoot: hexutil.Encode([]byte{5}), + }, + Signature: hexutil.Encode([]byte{6}), + }, + Header_2: &apimiddleware.SignedBeaconBlockHeaderJson{ + Header: &apimiddleware.BeaconBlockHeaderJson{ + Slot: "7", + ProposerIndex: "8", + ParentRoot: hexutil.Encode([]byte{9}), + StateRoot: hexutil.Encode([]byte{10}), + BodyRoot: hexutil.Encode([]byte{11}), + }, + Signature: hexutil.Encode([]byte{12}), + }, + }, + { + Header_1: &apimiddleware.SignedBeaconBlockHeaderJson{ + Header: &apimiddleware.BeaconBlockHeaderJson{ + Slot: "13", + ProposerIndex: "14", + ParentRoot: hexutil.Encode([]byte{15}), + StateRoot: hexutil.Encode([]byte{16}), + BodyRoot: hexutil.Encode([]byte{17}), + }, + Signature: hexutil.Encode([]byte{18}), + }, + Header_2: &apimiddleware.SignedBeaconBlockHeaderJson{ + Header: &apimiddleware.BeaconBlockHeaderJson{ + Slot: "19", + ProposerIndex: "20", + ParentRoot: hexutil.Encode([]byte{21}), + StateRoot: hexutil.Encode([]byte{22}), + BodyRoot: hexutil.Encode([]byte{23}), + }, + Signature: hexutil.Encode([]byte{24}), + }, + }, + } +} + +func generateSignedBeaconBlockHeader() *apimiddleware.SignedBeaconBlockHeaderJson { + return &apimiddleware.SignedBeaconBlockHeaderJson{ + Header: &apimiddleware.BeaconBlockHeaderJson{ + Slot: "1", + ProposerIndex: "2", + ParentRoot: hexutil.Encode([]byte{3}), + StateRoot: hexutil.Encode([]byte{4}), + BodyRoot: hexutil.Encode([]byte{5}), + }, + Signature: hexutil.Encode([]byte{6}), + } +} + +func generateAttesterSlashings() []*apimiddleware.AttesterSlashingJson { + return []*apimiddleware.AttesterSlashingJson{ + { + Attestation_1: &apimiddleware.IndexedAttestationJson{ + AttestingIndices: []string{"1", "2"}, + Data: &apimiddleware.AttestationDataJson{ + Slot: "3", + CommitteeIndex: "4", + BeaconBlockRoot: hexutil.Encode([]byte{5}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "6", + Root: hexutil.Encode([]byte{7}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "8", + Root: hexutil.Encode([]byte{9}), + }, + }, + Signature: hexutil.Encode([]byte{10}), + }, + Attestation_2: &apimiddleware.IndexedAttestationJson{ + AttestingIndices: []string{"11", "12"}, + Data: &apimiddleware.AttestationDataJson{ + Slot: "13", + CommitteeIndex: "14", + BeaconBlockRoot: hexutil.Encode([]byte{15}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "16", + Root: hexutil.Encode([]byte{17}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "18", + Root: hexutil.Encode([]byte{19}), + }, + }, + Signature: hexutil.Encode([]byte{20}), + }, + }, + { + Attestation_1: &apimiddleware.IndexedAttestationJson{ + AttestingIndices: []string{"21", "22"}, + Data: &apimiddleware.AttestationDataJson{ + Slot: "23", + CommitteeIndex: "24", + BeaconBlockRoot: hexutil.Encode([]byte{25}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "26", + Root: hexutil.Encode([]byte{27}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "28", + Root: hexutil.Encode([]byte{29}), + }, + }, + Signature: hexutil.Encode([]byte{30}), + }, + Attestation_2: &apimiddleware.IndexedAttestationJson{ + AttestingIndices: []string{"31", "32"}, + Data: &apimiddleware.AttestationDataJson{ + Slot: "33", + CommitteeIndex: "34", + BeaconBlockRoot: hexutil.Encode([]byte{35}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "36", + Root: hexutil.Encode([]byte{37}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "38", + Root: hexutil.Encode([]byte{39}), + }, + }, + Signature: hexutil.Encode([]byte{40}), + }, + }, + } +} + +func generateIndexedAttestation() *apimiddleware.IndexedAttestationJson { + return &apimiddleware.IndexedAttestationJson{ + AttestingIndices: []string{"1", "2"}, + Data: &apimiddleware.AttestationDataJson{ + Slot: "3", + CommitteeIndex: "4", + BeaconBlockRoot: hexutil.Encode([]byte{5}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "6", + Root: hexutil.Encode([]byte{7}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "8", + Root: hexutil.Encode([]byte{9}), + }, + }, + Signature: hexutil.Encode([]byte{10}), + } +} + +func generateCheckpoint() *apimiddleware.CheckpointJson { + return &apimiddleware.CheckpointJson{ + Epoch: "1", + Root: hexutil.Encode([]byte{2}), + } +} + +func generateAttestations() []*apimiddleware.AttestationJson { + return []*apimiddleware.AttestationJson{ + { + AggregationBits: hexutil.Encode([]byte{1}), + Data: &apimiddleware.AttestationDataJson{ + Slot: "2", + CommitteeIndex: "3", + BeaconBlockRoot: hexutil.Encode([]byte{4}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "5", + Root: hexutil.Encode([]byte{6}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "7", + Root: hexutil.Encode([]byte{8}), + }, + }, + Signature: hexutil.Encode([]byte{9}), + }, + { + AggregationBits: hexutil.Encode([]byte{10}), + Data: &apimiddleware.AttestationDataJson{ + Slot: "11", + CommitteeIndex: "12", + BeaconBlockRoot: hexutil.Encode([]byte{13}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "14", + Root: hexutil.Encode([]byte{15}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "16", + Root: hexutil.Encode([]byte{17}), + }, + }, + Signature: hexutil.Encode([]byte{18}), + }, + } +} + +func generateAttestationData() *apimiddleware.AttestationDataJson { + return &apimiddleware.AttestationDataJson{ + Slot: "1", + CommitteeIndex: "2", + BeaconBlockRoot: hexutil.Encode([]byte{3}), + Source: &apimiddleware.CheckpointJson{ + Epoch: "4", + Root: hexutil.Encode([]byte{5}), + }, + Target: &apimiddleware.CheckpointJson{ + Epoch: "6", + Root: hexutil.Encode([]byte{7}), + }, + } +} + +func generateDeposits() []*apimiddleware.DepositJson { + return []*apimiddleware.DepositJson{ + { + Proof: []string{ + hexutil.Encode([]byte{1}), + hexutil.Encode([]byte{2}), + }, + Data: &apimiddleware.Deposit_DataJson{ + PublicKey: hexutil.Encode([]byte{3}), + WithdrawalCredentials: hexutil.Encode([]byte{4}), + Amount: "5", + Signature: hexutil.Encode([]byte{6}), + }, + }, + { + Proof: []string{ + hexutil.Encode([]byte{7}), + hexutil.Encode([]byte{8}), + }, + Data: &apimiddleware.Deposit_DataJson{ + PublicKey: hexutil.Encode([]byte{9}), + WithdrawalCredentials: hexutil.Encode([]byte{10}), + Amount: "11", + Signature: hexutil.Encode([]byte{12}), + }, + }, + } +} + +func generateSignedVoluntaryExits() []*apimiddleware.SignedVoluntaryExitJson { + return []*apimiddleware.SignedVoluntaryExitJson{ + { + Exit: &apimiddleware.VoluntaryExitJson{ + Epoch: "1", + ValidatorIndex: "2", + }, + Signature: hexutil.Encode([]byte{3}), + }, + { + Exit: &apimiddleware.VoluntaryExitJson{ + Epoch: "4", + ValidatorIndex: "5", + }, + Signature: hexutil.Encode([]byte{6}), + }, + } +} diff --git a/validator/client/beacon-api/get_beacon_block.go b/validator/client/beacon-api/get_beacon_block.go new file mode 100644 index 0000000000..ef9aebb13d --- /dev/null +++ b/validator/client/beacon-api/get_beacon_block.go @@ -0,0 +1,396 @@ +package beacon_api + +import ( + "bytes" + "encoding/json" + "fmt" + "math/big" + neturl "net/url" + "strconv" + + "github.com/ethereum/go-ethereum/common/hexutil" + "github.com/pkg/errors" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware" + types "github.com/prysmaticlabs/prysm/v3/consensus-types/primitives" + "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" +) + +type abstractProduceBlockResponseJson struct { + Version string `json:"version" enum:"true"` + Data json.RawMessage `json:"data"` +} + +func (c beaconApiValidatorClient) getBeaconBlock(slot types.Slot, randaoReveal []byte, graffiti []byte) (*ethpb.GenericBeaconBlock, error) { + queryParams := neturl.Values{} + queryParams.Add("randao_reveal", hexutil.Encode(randaoReveal)) + + if len(graffiti) > 0 { + queryParams.Add("graffiti", hexutil.Encode(graffiti)) + } + + queryUrl := buildURL(fmt.Sprintf("/eth/v2/validator/blocks/%d", slot), queryParams) + + // Since we don't know yet what the json looks like, we unmarshal into an abstract structure that has only a version + // and a blob of data + produceBlockResponseJson := abstractProduceBlockResponseJson{} + if _, err := c.jsonRestHandler.GetRestJsonResponse(queryUrl, &produceBlockResponseJson); err != nil { + return nil, errors.Wrap(err, "failed to query GET REST endpoint") + } + + // Once we know what the consensus version is, we can go ahead and unmarshal into the specific structs unique to each version + decoder := json.NewDecoder(bytes.NewReader(produceBlockResponseJson.Data)) + decoder.DisallowUnknownFields() + + response := ðpb.GenericBeaconBlock{} + + switch produceBlockResponseJson.Version { + case "phase0": + jsonPhase0Block := apimiddleware.BeaconBlockJson{} + if err := decoder.Decode(&jsonPhase0Block); err != nil { + return nil, errors.Wrap(err, "failed to decode phase0 block response json") + } + + phase0Block, err := convertRESTPhase0BlockToProto(&jsonPhase0Block) + if err != nil { + return nil, errors.Wrap(err, "failed to get phase0 block") + } + response.Block = phase0Block + + case "altair": + jsonAltairBlock := apimiddleware.BeaconBlockAltairJson{} + if err := decoder.Decode(&jsonAltairBlock); err != nil { + return nil, errors.Wrap(err, "failed to decode altair block response json") + } + + altairBlock, err := convertRESTAltairBlockToProto(&jsonAltairBlock) + if err != nil { + return nil, errors.Wrap(err, "failed to get altair block") + } + response.Block = altairBlock + + case "bellatrix": + jsonBellatrixBlock := apimiddleware.BeaconBlockBellatrixJson{} + if err := decoder.Decode(&jsonBellatrixBlock); err != nil { + return nil, errors.Wrap(err, "failed to decode bellatrix block response json") + } + + bellatrixBlock, err := convertRESTBellatrixBlockToProto(&jsonBellatrixBlock) + if err != nil { + return nil, errors.Wrap(err, "failed to get bellatrix block") + } + response.Block = bellatrixBlock + + default: + return nil, errors.Errorf("unsupported consensus version `%s`", produceBlockResponseJson.Version) + } + return response, nil +} + +func convertRESTPhase0BlockToProto(block *apimiddleware.BeaconBlockJson) (*ethpb.GenericBeaconBlock_Phase0, error) { + blockSlot, err := strconv.ParseUint(block.Slot, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse slot `%s`", block.Slot) + } + + blockProposerIndex, err := strconv.ParseUint(block.ProposerIndex, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse proposer index `%s`", block.ProposerIndex) + } + + parentRoot, err := hexutil.Decode(block.ParentRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode parent root `%s`", block.ParentRoot) + } + + stateRoot, err := hexutil.Decode(block.StateRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode state root `%s`", block.StateRoot) + } + + if block.Body == nil { + return nil, errors.New("block body is nil") + } + + randaoReveal, err := hexutil.Decode(block.Body.RandaoReveal) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode randao reveal `%s`", block.Body.RandaoReveal) + } + + if block.Body.Eth1Data == nil { + return nil, errors.New("eth1 data is nil") + } + + depositRoot, err := hexutil.Decode(block.Body.Eth1Data.DepositRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode deposit root `%s`", block.Body.Eth1Data.DepositRoot) + } + + depositCount, err := strconv.ParseUint(block.Body.Eth1Data.DepositCount, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse deposit count `%s`", block.Body.Eth1Data.DepositCount) + } + + blockHash, err := hexutil.Decode(block.Body.Eth1Data.BlockHash) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode block hash `%s`", block.Body.Eth1Data.BlockHash) + } + + graffiti, err := hexutil.Decode(block.Body.Graffiti) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode graffiti `%s`", block.Body.Graffiti) + } + + proposerSlashings, err := convertProposerSlashingsToProto(block.Body.ProposerSlashings) + if err != nil { + return nil, errors.Wrap(err, "failed to get proposer slashings") + } + + attesterSlashings, err := convertAttesterSlashingsToProto(block.Body.AttesterSlashings) + if err != nil { + return nil, errors.Wrap(err, "failed to get attester slashings") + } + + attestations, err := convertAttestationsToProto(block.Body.Attestations) + if err != nil { + return nil, errors.Wrap(err, "failed to get attestations") + } + + deposits, err := convertDepositsToProto(block.Body.Deposits) + if err != nil { + return nil, errors.Wrap(err, "failed to get deposits") + } + + voluntaryExits, err := convertVoluntaryExitsToProto(block.Body.VoluntaryExits) + if err != nil { + return nil, errors.Wrap(err, "failed to get voluntary exits") + } + + return ðpb.GenericBeaconBlock_Phase0{ + Phase0: ðpb.BeaconBlock{ + Slot: types.Slot(blockSlot), + ProposerIndex: types.ValidatorIndex(blockProposerIndex), + ParentRoot: parentRoot, + StateRoot: stateRoot, + Body: ðpb.BeaconBlockBody{ + RandaoReveal: randaoReveal, + Eth1Data: ðpb.Eth1Data{ + DepositRoot: depositRoot, + DepositCount: depositCount, + BlockHash: blockHash, + }, + Graffiti: graffiti, + ProposerSlashings: proposerSlashings, + AttesterSlashings: attesterSlashings, + Attestations: attestations, + Deposits: deposits, + VoluntaryExits: voluntaryExits, + }, + }, + }, nil +} + +func convertRESTAltairBlockToProto(block *apimiddleware.BeaconBlockAltairJson) (*ethpb.GenericBeaconBlock_Altair, error) { + if block.Body == nil { + return nil, errors.New("block body is nil") + } + + // Call convertRESTPhase0BlockToProto to set the phase0 fields because all the error handling and the heavy lifting + // has already been done + phase0Block, err := convertRESTPhase0BlockToProto(&apimiddleware.BeaconBlockJson{ + Slot: block.Slot, + ProposerIndex: block.ProposerIndex, + ParentRoot: block.ParentRoot, + StateRoot: block.StateRoot, + Body: &apimiddleware.BeaconBlockBodyJson{ + 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, + }, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to get the phase0 fields of the altair block") + } + + if block.Body.SyncAggregate == nil { + return nil, errors.New("sync aggregate is nil") + } + + syncCommitteeBits, err := hexutil.Decode(block.Body.SyncAggregate.SyncCommitteeBits) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode sync committee bits `%s`", block.Body.SyncAggregate.SyncCommitteeBits) + } + + syncCommitteeSignature, err := hexutil.Decode(block.Body.SyncAggregate.SyncCommitteeSignature) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode sync committee signature `%s`", block.Body.SyncAggregate.SyncCommitteeSignature) + } + + return ðpb.GenericBeaconBlock_Altair{ + Altair: ðpb.BeaconBlockAltair{ + Slot: phase0Block.Phase0.Slot, + ProposerIndex: phase0Block.Phase0.ProposerIndex, + ParentRoot: phase0Block.Phase0.ParentRoot, + StateRoot: phase0Block.Phase0.StateRoot, + Body: ðpb.BeaconBlockBodyAltair{ + RandaoReveal: phase0Block.Phase0.Body.RandaoReveal, + Eth1Data: phase0Block.Phase0.Body.Eth1Data, + Graffiti: phase0Block.Phase0.Body.Graffiti, + ProposerSlashings: phase0Block.Phase0.Body.ProposerSlashings, + AttesterSlashings: phase0Block.Phase0.Body.AttesterSlashings, + Attestations: phase0Block.Phase0.Body.Attestations, + Deposits: phase0Block.Phase0.Body.Deposits, + VoluntaryExits: phase0Block.Phase0.Body.VoluntaryExits, + SyncAggregate: ðpb.SyncAggregate{ + SyncCommitteeBits: syncCommitteeBits, + SyncCommitteeSignature: syncCommitteeSignature, + }, + }, + }, + }, nil +} + +func convertRESTBellatrixBlockToProto(block *apimiddleware.BeaconBlockBellatrixJson) (*ethpb.GenericBeaconBlock_Bellatrix, error) { + if block.Body == nil { + return nil, errors.New("block body is nil") + } + + // Call convertRESTAltairBlockToProto to set the altair fields because all the error handling and the heavy lifting + // has already been done + altairBlock, err := convertRESTAltairBlockToProto(&apimiddleware.BeaconBlockAltairJson{ + Slot: block.Slot, + ProposerIndex: block.ProposerIndex, + ParentRoot: block.ParentRoot, + StateRoot: block.StateRoot, + Body: &apimiddleware.BeaconBlockBodyAltairJson{ + 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, + }, + }) + if err != nil { + return nil, errors.Wrap(err, "failed to get the altair fields of the bellatrix block") + } + + if block.Body.ExecutionPayload == nil { + return nil, errors.New("execution payload is nil") + } + + parentHash, err := hexutil.Decode(block.Body.ExecutionPayload.ParentHash) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload parent hash `%s`", block.Body.ExecutionPayload.ParentHash) + } + + feeRecipient, err := hexutil.Decode(block.Body.ExecutionPayload.FeeRecipient) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload fee recipient `%s`", block.Body.ExecutionPayload.FeeRecipient) + } + + stateRoot, err := hexutil.Decode(block.Body.ExecutionPayload.StateRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload state root `%s`", block.Body.ExecutionPayload.StateRoot) + } + + receiptsRoot, err := hexutil.Decode(block.Body.ExecutionPayload.ReceiptsRoot) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload receipts root `%s`", block.Body.ExecutionPayload.ReceiptsRoot) + } + + logsBloom, err := hexutil.Decode(block.Body.ExecutionPayload.LogsBloom) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload logs bloom `%s`", block.Body.ExecutionPayload.LogsBloom) + } + + prevRandao, err := hexutil.Decode(block.Body.ExecutionPayload.PrevRandao) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload prev randao `%s`", block.Body.ExecutionPayload.PrevRandao) + } + + blockNumber, err := strconv.ParseUint(block.Body.ExecutionPayload.BlockNumber, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse execution payload block number `%s`", block.Body.ExecutionPayload.BlockNumber) + } + + gasLimit, err := strconv.ParseUint(block.Body.ExecutionPayload.GasLimit, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse execution payload gas limit `%s`", block.Body.ExecutionPayload.GasLimit) + } + + gasUsed, err := strconv.ParseUint(block.Body.ExecutionPayload.GasUsed, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse execution payload gas used `%s`", block.Body.ExecutionPayload.GasUsed) + } + + timestamp, err := strconv.ParseUint(block.Body.ExecutionPayload.TimeStamp, 10, 64) + if err != nil { + return nil, errors.Wrapf(err, "failed to parse execution payload timestamp `%s`", block.Body.ExecutionPayload.TimeStamp) + } + + extraData, err := hexutil.Decode(block.Body.ExecutionPayload.ExtraData) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload extra data `%s`", block.Body.ExecutionPayload.ExtraData) + } + + baseFeePerGas := new(big.Int) + if _, ok := baseFeePerGas.SetString(block.Body.ExecutionPayload.BaseFeePerGas, 10); !ok { + return nil, errors.Errorf("failed to parse execution payload base fee per gas `%s`", block.Body.ExecutionPayload.BaseFeePerGas) + } + + blockHash, err := hexutil.Decode(block.Body.ExecutionPayload.BlockHash) + if err != nil { + return nil, errors.Wrapf(err, "failed to decode execution payload block hash `%s`", block.Body.ExecutionPayload.BlockHash) + } + + transactions, err := convertTransactionsToProto(block.Body.ExecutionPayload.Transactions) + if err != nil { + return nil, errors.Wrap(err, "failed to get execution payload transactions") + } + + return ðpb.GenericBeaconBlock_Bellatrix{ + Bellatrix: ðpb.BeaconBlockBellatrix{ + Slot: altairBlock.Altair.Slot, + ProposerIndex: altairBlock.Altair.ProposerIndex, + ParentRoot: altairBlock.Altair.ParentRoot, + StateRoot: altairBlock.Altair.StateRoot, + Body: ðpb.BeaconBlockBodyBellatrix{ + RandaoReveal: altairBlock.Altair.Body.RandaoReveal, + Eth1Data: altairBlock.Altair.Body.Eth1Data, + Graffiti: altairBlock.Altair.Body.Graffiti, + ProposerSlashings: altairBlock.Altair.Body.ProposerSlashings, + AttesterSlashings: altairBlock.Altair.Body.AttesterSlashings, + Attestations: altairBlock.Altair.Body.Attestations, + Deposits: altairBlock.Altair.Body.Deposits, + VoluntaryExits: altairBlock.Altair.Body.VoluntaryExits, + SyncAggregate: altairBlock.Altair.Body.SyncAggregate, + ExecutionPayload: &enginev1.ExecutionPayload{ + ParentHash: parentHash, + FeeRecipient: feeRecipient, + StateRoot: stateRoot, + ReceiptsRoot: receiptsRoot, + LogsBloom: logsBloom, + PrevRandao: prevRandao, + BlockNumber: blockNumber, + GasLimit: gasLimit, + GasUsed: gasUsed, + Timestamp: timestamp, + ExtraData: extraData, + BaseFeePerGas: bytesutil.PadTo(bytesutil.BigIntToLittleEndianBytes(baseFeePerGas), 32), + BlockHash: blockHash, + Transactions: transactions, + }, + }, + }, + }, nil +} diff --git a/validator/client/beacon-api/get_beacon_block_altair_test.go b/validator/client/beacon-api/get_beacon_block_altair_test.go new file mode 100644 index 0000000000..d660f20093 --- /dev/null +++ b/validator/client/beacon-api/get_beacon_block_altair_test.go @@ -0,0 +1,144 @@ +package beacon_api + +import ( + "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_AltairValid(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + altairProtoBeaconBlock := test_helpers.GenerateProtoAltairBeaconBlock() + altairBeaconBlockBytes, err := json.Marshal(test_helpers.GenerateJsonAltairBeaconBlock()) + require.NoError(t, err) + + const slot = types.Slot(1) + randaoReveal := []byte{2} + graffiti := []byte{3} + + jsonRestHandler := mock.NewMockjsonRestHandler(ctrl) + jsonRestHandler.EXPECT().GetRestJsonResponse( + fmt.Sprintf("/eth/v2/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: "altair", + Data: altairBeaconBlockBytes, + }, + ).Return( + nil, + nil, + ).Times(1) + + expectedBeaconBlock := generateProtoAltairBlock(altairProtoBeaconBlock) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + beaconBlock, err := validatorClient.getBeaconBlock(slot, randaoReveal, graffiti) + require.NoError(t, err) + assert.DeepEqual(t, expectedBeaconBlock, beaconBlock) +} + +func TestGetBeaconBlock_AltairError(t *testing.T) { + testCases := []struct { + name string + expectedErrorMessage string + generateData func() *apimiddleware.BeaconBlockAltairJson + }{ + { + name: "nil body", + expectedErrorMessage: "block body is nil", + generateData: func() *apimiddleware.BeaconBlockAltairJson { + beaconBlock := test_helpers.GenerateJsonAltairBeaconBlock() + beaconBlock.Body = nil + return beaconBlock + }, + }, + { + name: "nil sync aggregate", + expectedErrorMessage: "sync aggregate is nil", + generateData: func() *apimiddleware.BeaconBlockAltairJson { + beaconBlock := test_helpers.GenerateJsonAltairBeaconBlock() + beaconBlock.Body.SyncAggregate = nil + return beaconBlock + }, + }, + { + name: "bad phase0 fields", + expectedErrorMessage: "failed to get the phase0 fields of the altair block", + generateData: func() *apimiddleware.BeaconBlockAltairJson { + beaconBlock := test_helpers.GenerateJsonAltairBeaconBlock() + beaconBlock.Body.Eth1Data = nil + return beaconBlock + }, + }, + { + name: "bad sync committee bits", + expectedErrorMessage: "failed to decode sync committee bits `foo`", + generateData: func() *apimiddleware.BeaconBlockAltairJson { + beaconBlock := test_helpers.GenerateJsonAltairBeaconBlock() + beaconBlock.Body.SyncAggregate.SyncCommitteeBits = "foo" + return beaconBlock + }, + }, + { + name: "bad sync committee signature", + expectedErrorMessage: "failed to decode sync committee signature `bar`", + generateData: func() *apimiddleware.BeaconBlockAltairJson { + beaconBlock := test_helpers.GenerateJsonAltairBeaconBlock() + beaconBlock.Body.SyncAggregate.SyncCommitteeSignature = "bar" + 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( + gomock.Any(), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: "altair", + Data: dataBytes, + }, + ).Return( + nil, + nil, + ).Times(1) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + _, err = validatorClient.getBeaconBlock(1, []byte{1}, []byte{2}) + assert.ErrorContains(t, "failed to get altair block", err) + assert.ErrorContains(t, testCase.expectedErrorMessage, err) + }) + } +} + +func generateProtoAltairBlock(altairProtoBeaconBlock *ethpb.BeaconBlockAltair) *ethpb.GenericBeaconBlock { + return ðpb.GenericBeaconBlock{ + Block: ðpb.GenericBeaconBlock_Altair{ + Altair: altairProtoBeaconBlock, + }, + } +} diff --git a/validator/client/beacon-api/get_beacon_block_bellatrix_test.go b/validator/client/beacon-api/get_beacon_block_bellatrix_test.go new file mode 100644 index 0000000000..d71b75ccb0 --- /dev/null +++ b/validator/client/beacon-api/get_beacon_block_bellatrix_test.go @@ -0,0 +1,252 @@ +package beacon_api + +import ( + "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_BellatrixValid(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + bellatrixProtoBeaconBlock := test_helpers.GenerateProtoBellatrixBeaconBlock() + bellatrixBeaconBlockBytes, err := json.Marshal(test_helpers.GenerateJsonBellatrixBeaconBlock()) + require.NoError(t, err) + + const slot = types.Slot(1) + randaoReveal := []byte{2} + graffiti := []byte{3} + + jsonRestHandler := mock.NewMockjsonRestHandler(ctrl) + jsonRestHandler.EXPECT().GetRestJsonResponse( + fmt.Sprintf("/eth/v2/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: "bellatrix", + Data: bellatrixBeaconBlockBytes, + }, + ).Return( + nil, + nil, + ).Times(1) + + expectedBeaconBlock := generateProtoBellatrixBlock(bellatrixProtoBeaconBlock) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + beaconBlock, err := validatorClient.getBeaconBlock(slot, randaoReveal, graffiti) + require.NoError(t, err) + assert.DeepEqual(t, expectedBeaconBlock, beaconBlock) +} + +func TestGetBeaconBlock_BellatrixError(t *testing.T) { + testCases := []struct { + name string + expectedErrorMessage string + generateData func() *apimiddleware.BeaconBlockBellatrixJson + }{ + { + name: "nil body", + expectedErrorMessage: "block body is nil", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body = nil + return beaconBlock + }, + }, + { + name: "nil execution payload", + expectedErrorMessage: "execution payload is nil", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload = nil + return beaconBlock + }, + }, + { + name: "bad altair fields", + expectedErrorMessage: "failed to get the altair fields of the bellatrix block", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.Eth1Data = nil + return beaconBlock + }, + }, + { + name: "bad parent hash", + expectedErrorMessage: "failed to decode execution payload parent hash `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.ParentHash = "foo" + return beaconBlock + }, + }, + { + name: "bad fee recipient", + expectedErrorMessage: "failed to decode execution payload fee recipient `bar`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.FeeRecipient = "bar" + return beaconBlock + }, + }, + { + name: "bad state root", + expectedErrorMessage: "failed to decode execution payload state root `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.StateRoot = "foo" + return beaconBlock + }, + }, + { + name: "bad receipts root", + expectedErrorMessage: "failed to decode execution payload receipts root `bar`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.ReceiptsRoot = "bar" + return beaconBlock + }, + }, + { + name: "bad logs bloom", + expectedErrorMessage: "failed to decode execution payload logs bloom `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.LogsBloom = "foo" + return beaconBlock + }, + }, + { + name: "bad prev randao", + expectedErrorMessage: "failed to decode execution payload prev randao `bar`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.PrevRandao = "bar" + return beaconBlock + }, + }, + { + name: "bad block number", + expectedErrorMessage: "failed to parse execution payload block number `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.BlockNumber = "foo" + return beaconBlock + }, + }, + { + name: "bad gas limit", + expectedErrorMessage: "failed to parse execution payload gas limit `bar`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.GasLimit = "bar" + return beaconBlock + }, + }, + { + name: "bad gas used", + expectedErrorMessage: "failed to parse execution payload gas used `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.GasUsed = "foo" + return beaconBlock + }, + }, + { + name: "bad timestamp", + expectedErrorMessage: "failed to parse execution payload timestamp `bar`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.TimeStamp = "bar" + return beaconBlock + }, + }, + { + name: "bad extra data", + expectedErrorMessage: "failed to decode execution payload extra data `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.ExtraData = "foo" + return beaconBlock + }, + }, + { + name: "bad base fee per gas", + expectedErrorMessage: "failed to parse execution payload base fee per gas `bar`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.BaseFeePerGas = "bar" + return beaconBlock + }, + }, + { + name: "bad block hash", + expectedErrorMessage: "failed to decode execution payload block hash `foo`", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.BlockHash = "foo" + return beaconBlock + }, + }, + { + name: "bad transactions", + expectedErrorMessage: "failed to get execution payload transactions", + generateData: func() *apimiddleware.BeaconBlockBellatrixJson { + beaconBlock := test_helpers.GenerateJsonBellatrixBeaconBlock() + beaconBlock.Body.ExecutionPayload.Transactions[0] = "bar" + 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( + gomock.Any(), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: "bellatrix", + Data: dataBytes, + }, + ).Return( + nil, + nil, + ).Times(1) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + _, err = validatorClient.getBeaconBlock(1, []byte{1}, []byte{2}) + assert.ErrorContains(t, "failed to get bellatrix block", err) + assert.ErrorContains(t, testCase.expectedErrorMessage, err) + }) + } +} + +func generateProtoBellatrixBlock(bellatrixProtoBeaconBlock *ethpb.BeaconBlockBellatrix) *ethpb.GenericBeaconBlock { + return ðpb.GenericBeaconBlock{ + Block: ðpb.GenericBeaconBlock_Bellatrix{ + Bellatrix: bellatrixProtoBeaconBlock, + }, + } +} diff --git a/validator/client/beacon-api/get_beacon_block_phase0_test.go b/validator/client/beacon-api/get_beacon_block_phase0_test.go new file mode 100644 index 0000000000..8b34f59104 --- /dev/null +++ b/validator/client/beacon-api/get_beacon_block_phase0_test.go @@ -0,0 +1,243 @@ +package beacon_api + +import ( + "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_Phase0Valid(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + phase0ProtoBeaconBlock := test_helpers.GenerateProtoPhase0BeaconBlock() + phase0BeaconBlockBytes, err := json.Marshal(test_helpers.GenerateJsonPhase0BeaconBlock()) + require.NoError(t, err) + + const slot = types.Slot(1) + randaoReveal := []byte{2} + graffiti := []byte{3} + + jsonRestHandler := mock.NewMockjsonRestHandler(ctrl) + jsonRestHandler.EXPECT().GetRestJsonResponse( + fmt.Sprintf("/eth/v2/validator/blocks/%d?graffiti=%s&randao_reveal=%s", slot, hexutil.Encode(graffiti), hexutil.Encode(randaoReveal)), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: "phase0", + Data: phase0BeaconBlockBytes, + }, + ).Return( + nil, + nil, + ).Times(1) + + expectedBeaconBlock := generateProtoPhase0Block(phase0ProtoBeaconBlock) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + beaconBlock, err := validatorClient.getBeaconBlock(slot, randaoReveal, graffiti) + require.NoError(t, err) + assert.DeepEqual(t, expectedBeaconBlock, beaconBlock) +} + +func TestGetBeaconBlock_Phase0Error(t *testing.T) { + testCases := []struct { + name string + expectedErrorMessage string + generateData func() *apimiddleware.BeaconBlockJson + }{ + { + name: "nil body", + expectedErrorMessage: "block body is nil", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body = nil + return beaconBlock + }, + }, + { + name: "nil eth1 data", + expectedErrorMessage: "eth1 data is nil", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Eth1Data = nil + return beaconBlock + }, + }, + { + name: "bad slot", + expectedErrorMessage: "failed to parse slot `foo`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Slot = "foo" + return beaconBlock + }, + }, + { + name: "bad proposer index", + expectedErrorMessage: "failed to parse proposer index `bar`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.ProposerIndex = "bar" + return beaconBlock + }, + }, + { + name: "bad parent root", + expectedErrorMessage: "failed to decode parent root `foo`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.ParentRoot = "foo" + return beaconBlock + }, + }, + { + name: "bad state root", + expectedErrorMessage: "failed to decode state root `bar`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.StateRoot = "bar" + return beaconBlock + }, + }, + { + name: "bad randao reveal", + expectedErrorMessage: "failed to decode randao reveal `foo`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.RandaoReveal = "foo" + return beaconBlock + }, + }, + { + name: "bad deposit root", + expectedErrorMessage: "failed to decode deposit root `bar`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Eth1Data.DepositRoot = "bar" + return beaconBlock + }, + }, + { + name: "bad deposit count", + expectedErrorMessage: "failed to parse deposit count `foo`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Eth1Data.DepositCount = "foo" + return beaconBlock + }, + }, + { + name: "bad block hash", + expectedErrorMessage: "failed to decode block hash `bar`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Eth1Data.BlockHash = "bar" + return beaconBlock + }, + }, + { + name: "bad graffiti", + expectedErrorMessage: "failed to decode graffiti `foo`", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Graffiti = "foo" + return beaconBlock + }, + }, + { + name: "bad proposer slashings", + expectedErrorMessage: "failed to get proposer slashings", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.ProposerSlashings[0] = nil + return beaconBlock + }, + }, + { + name: "bad attester slashings", + expectedErrorMessage: "failed to get attester slashings", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.AttesterSlashings[0] = nil + return beaconBlock + }, + }, + { + name: "bad attestations", + expectedErrorMessage: "failed to get attestations", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Attestations[0] = nil + return beaconBlock + }, + }, + { + name: "bad deposits", + expectedErrorMessage: "failed to get deposits", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.Deposits[0] = nil + return beaconBlock + }, + }, + { + name: "bad voluntary exits", + expectedErrorMessage: "failed to get voluntary exits", + generateData: func() *apimiddleware.BeaconBlockJson { + beaconBlock := test_helpers.GenerateJsonPhase0BeaconBlock() + beaconBlock.Body.VoluntaryExits[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( + gomock.Any(), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: "phase0", + Data: dataBytes, + }, + ).Return( + nil, + nil, + ).Times(1) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + _, err = validatorClient.getBeaconBlock(1, []byte{1}, []byte{2}) + assert.ErrorContains(t, "failed to get phase0 block", err) + assert.ErrorContains(t, testCase.expectedErrorMessage, err) + }) + } +} + +func generateProtoPhase0Block(phase0ProtoBeaconBlock *ethpb.BeaconBlock) *ethpb.GenericBeaconBlock { + return ðpb.GenericBeaconBlock{ + Block: ðpb.GenericBeaconBlock_Phase0{ + Phase0: phase0ProtoBeaconBlock, + }, + } +} diff --git a/validator/client/beacon-api/get_beacon_block_test.go b/validator/client/beacon-api/get_beacon_block_test.go new file mode 100644 index 0000000000..42ff7928e1 --- /dev/null +++ b/validator/client/beacon-api/get_beacon_block_test.go @@ -0,0 +1,118 @@ +package beacon_api + +import ( + "encoding/json" + "errors" + "testing" + + "github.com/golang/mock/gomock" + "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware" + "github.com/prysmaticlabs/prysm/v3/testing/assert" + "github.com/prysmaticlabs/prysm/v3/testing/require" + "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/mock" +) + +func TestGetBeaconBlock_RequestFailed(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + jsonRestHandler := mock.NewMockjsonRestHandler(ctrl) + jsonRestHandler.EXPECT().GetRestJsonResponse( + gomock.Any(), + gomock.Any(), + ).Return( + nil, + errors.New("foo error"), + ).Times(1) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + _, err := validatorClient.getBeaconBlock(1, []byte{1}, []byte{2}) + assert.ErrorContains(t, "failed to query GET REST endpoint", err) + assert.ErrorContains(t, "foo error", err) +} + +func TestGetBeaconBlock_Error(t *testing.T) { + phase0BeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockJson{}) + require.NoError(t, err) + altairBeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockAltairJson{}) + require.NoError(t, err) + bellatrixBeaconBlockBytes, err := json.Marshal(apimiddleware.BeaconBlockBellatrixJson{}) + require.NoError(t, err) + + testCases := []struct { + name string + beaconBlock interface{} + expectedErrorMessage string + consensusVersion string + data json.RawMessage + }{ + { + name: "phase0 block decoding failed", + expectedErrorMessage: "failed to decode phase0 block response json", + consensusVersion: "phase0", + data: []byte{}, + }, + { + name: "phase0 block conversion failed", + expectedErrorMessage: "failed to get phase0 block", + consensusVersion: "phase0", + data: phase0BeaconBlockBytes, + }, + { + name: "altair block decoding failed", + expectedErrorMessage: "failed to decode altair block response json", + consensusVersion: "altair", + data: []byte{}, + }, + { + name: "altair block conversion failed", + expectedErrorMessage: "failed to get altair block", + consensusVersion: "altair", + data: altairBeaconBlockBytes, + }, + { + name: "bellatrix block decoding failed", + expectedErrorMessage: "failed to decode bellatrix block response json", + beaconBlock: "foo", + consensusVersion: "bellatrix", + data: []byte{}, + }, + { + name: "bellatrix block conversion failed", + expectedErrorMessage: "failed to get bellatrix block", + consensusVersion: "bellatrix", + data: bellatrixBeaconBlockBytes, + }, + { + name: "unsupported consensus version", + expectedErrorMessage: "unsupported consensus version `foo`", + consensusVersion: "foo", + }, + } + + for _, testCase := range testCases { + t.Run(testCase.name, func(t *testing.T) { + ctrl := gomock.NewController(t) + defer ctrl.Finish() + + jsonRestHandler := mock.NewMockjsonRestHandler(ctrl) + jsonRestHandler.EXPECT().GetRestJsonResponse( + gomock.Any(), + &abstractProduceBlockResponseJson{}, + ).SetArg( + 1, + abstractProduceBlockResponseJson{ + Version: testCase.consensusVersion, + Data: testCase.data, + }, + ).Return( + nil, + nil, + ).Times(1) + + validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler} + _, err := validatorClient.getBeaconBlock(1, []byte{1}, []byte{2}) + assert.ErrorContains(t, testCase.expectedErrorMessage, err) + }) + } +} diff --git a/validator/client/beacon-api/json_rest_handler.go b/validator/client/beacon-api/json_rest_handler.go index dfe0b5ca65..11c67b0c6a 100644 --- a/validator/client/beacon-api/json_rest_handler.go +++ b/validator/client/beacon-api/json_rest_handler.go @@ -69,9 +69,12 @@ func (c beaconApiJsonRestHandler) PostRestJson(apiEndpoint string, headers map[s } func decodeJsonResp(resp *http.Response, responseJson interface{}) (*apimiddleware.DefaultErrorJson, error) { + decoder := json.NewDecoder(resp.Body) + decoder.DisallowUnknownFields() + if resp.StatusCode != http.StatusOK { errorJson := &apimiddleware.DefaultErrorJson{} - if err := json.NewDecoder(resp.Body).Decode(errorJson); err != nil { + if err := decoder.Decode(errorJson); err != nil { return nil, errors.Wrapf(err, "failed to decode error json for %s", resp.Request.URL) } @@ -79,7 +82,7 @@ func decodeJsonResp(resp *http.Response, responseJson interface{}) (*apimiddlewa } if responseJson != nil { - if err := json.NewDecoder(resp.Body).Decode(responseJson); err != nil { + if err := decoder.Decode(responseJson); err != nil { return nil, errors.Wrapf(err, "failed to decode response json for %s", resp.Request.URL) } } diff --git a/validator/client/beacon-api/propose_beacon_block_altair_test.go b/validator/client/beacon-api/propose_beacon_block_altair_test.go index 9c0e4356fd..3131b61af2 100644 --- a/validator/client/beacon-api/propose_beacon_block_altair_test.go +++ b/validator/client/beacon-api/propose_beacon_block_altair_test.go @@ -76,217 +76,7 @@ func TestProposeBeaconBlock_Altair(t *testing.T) { func generateSignedAltairBlock() *ethpb.GenericSignedBeaconBlock_Altair { return ðpb.GenericSignedBeaconBlock_Altair{ Altair: ðpb.SignedBeaconBlockAltair{ - Block: ðpb.BeaconBlockAltair{ - Slot: 1, - ProposerIndex: 2, - ParentRoot: test_helpers.FillByteSlice(32, 3), - StateRoot: test_helpers.FillByteSlice(32, 4), - Body: ðpb.BeaconBlockBodyAltair{ - RandaoReveal: test_helpers.FillByteSlice(96, 5), - Eth1Data: ðpb.Eth1Data{ - DepositRoot: test_helpers.FillByteSlice(32, 6), - DepositCount: 7, - BlockHash: test_helpers.FillByteSlice(32, 8), - }, - Graffiti: test_helpers.FillByteSlice(32, 9), - ProposerSlashings: []*ethpb.ProposerSlashing{ - { - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 10, - ProposerIndex: 11, - ParentRoot: test_helpers.FillByteSlice(32, 12), - StateRoot: test_helpers.FillByteSlice(32, 13), - BodyRoot: test_helpers.FillByteSlice(32, 14), - }, - Signature: test_helpers.FillByteSlice(96, 15), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 16, - ProposerIndex: 17, - ParentRoot: test_helpers.FillByteSlice(32, 18), - StateRoot: test_helpers.FillByteSlice(32, 19), - BodyRoot: test_helpers.FillByteSlice(32, 20), - }, - Signature: test_helpers.FillByteSlice(96, 21), - }, - }, - { - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 22, - ProposerIndex: 23, - ParentRoot: test_helpers.FillByteSlice(32, 24), - StateRoot: test_helpers.FillByteSlice(32, 25), - BodyRoot: test_helpers.FillByteSlice(32, 26), - }, - Signature: test_helpers.FillByteSlice(96, 27), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 28, - ProposerIndex: 29, - ParentRoot: test_helpers.FillByteSlice(32, 30), - StateRoot: test_helpers.FillByteSlice(32, 31), - BodyRoot: test_helpers.FillByteSlice(32, 32), - }, - Signature: test_helpers.FillByteSlice(96, 33), - }, - }, - }, - AttesterSlashings: []*ethpb.AttesterSlashing{ - { - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{34, 35}, - Data: ðpb.AttestationData{ - Slot: 36, - CommitteeIndex: 37, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 39, - Root: test_helpers.FillByteSlice(32, 40), - }, - Target: ðpb.Checkpoint{ - Epoch: 41, - Root: test_helpers.FillByteSlice(32, 42), - }, - }, - Signature: test_helpers.FillByteSlice(96, 43), - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{44, 45}, - Data: ðpb.AttestationData{ - Slot: 46, - CommitteeIndex: 47, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 49, - Root: test_helpers.FillByteSlice(32, 50), - }, - Target: ðpb.Checkpoint{ - Epoch: 51, - Root: test_helpers.FillByteSlice(32, 52), - }, - }, - Signature: test_helpers.FillByteSlice(96, 53), - }, - }, - { - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{54, 55}, - Data: ðpb.AttestationData{ - Slot: 56, - CommitteeIndex: 57, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 59, - Root: test_helpers.FillByteSlice(32, 60), - }, - Target: ðpb.Checkpoint{ - Epoch: 61, - Root: test_helpers.FillByteSlice(32, 62), - }, - }, - Signature: test_helpers.FillByteSlice(96, 63), - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{64, 65}, - Data: ðpb.AttestationData{ - Slot: 66, - CommitteeIndex: 67, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 69, - Root: test_helpers.FillByteSlice(32, 70), - }, - Target: ðpb.Checkpoint{ - Epoch: 71, - Root: test_helpers.FillByteSlice(32, 72), - }, - }, - Signature: test_helpers.FillByteSlice(96, 73), - }, - }, - }, - Attestations: []*ethpb.Attestation{ - { - AggregationBits: test_helpers.FillByteSlice(4, 74), - Data: ðpb.AttestationData{ - Slot: 75, - CommitteeIndex: 76, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 78, - Root: test_helpers.FillByteSlice(32, 79), - }, - Target: ðpb.Checkpoint{ - Epoch: 80, - Root: test_helpers.FillByteSlice(32, 81), - }, - }, - Signature: test_helpers.FillByteSlice(96, 82), - }, - { - AggregationBits: test_helpers.FillByteSlice(4, 83), - Data: ðpb.AttestationData{ - Slot: 84, - CommitteeIndex: 85, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 87, - Root: test_helpers.FillByteSlice(32, 88), - }, - Target: ðpb.Checkpoint{ - Epoch: 89, - Root: test_helpers.FillByteSlice(32, 90), - }, - }, - Signature: test_helpers.FillByteSlice(96, 91), - }, - }, - Deposits: []*ethpb.Deposit{ - { - Proof: test_helpers.FillByteArraySlice(33, test_helpers.FillByteSlice(32, 92)), - Data: ðpb.Deposit_Data{ - PublicKey: test_helpers.FillByteSlice(48, 94), - WithdrawalCredentials: test_helpers.FillByteSlice(32, 95), - Amount: 96, - Signature: test_helpers.FillByteSlice(96, 97), - }, - }, - { - Proof: test_helpers.FillByteArraySlice(33, test_helpers.FillByteSlice(32, 98)), - Data: ðpb.Deposit_Data{ - PublicKey: test_helpers.FillByteSlice(48, 100), - WithdrawalCredentials: test_helpers.FillByteSlice(32, 101), - Amount: 102, - Signature: test_helpers.FillByteSlice(96, 103), - }, - }, - }, - VoluntaryExits: []*ethpb.SignedVoluntaryExit{ - { - Exit: ðpb.VoluntaryExit{ - Epoch: 104, - ValidatorIndex: 105, - }, - Signature: test_helpers.FillByteSlice(96, 106), - }, - { - Exit: ðpb.VoluntaryExit{ - Epoch: 107, - ValidatorIndex: 108, - }, - Signature: test_helpers.FillByteSlice(96, 109), - }, - }, - SyncAggregate: ðpb.SyncAggregate{ - SyncCommitteeBits: test_helpers.FillByteSlice(64, 110), - SyncCommitteeSignature: test_helpers.FillByteSlice(96, 111), - }, - }, - }, + Block: test_helpers.GenerateProtoAltairBeaconBlock(), Signature: test_helpers.FillByteSlice(96, 112), }, } diff --git a/validator/client/beacon-api/propose_beacon_block_bellatrix_test.go b/validator/client/beacon-api/propose_beacon_block_bellatrix_test.go index e0c1f41e44..80b484de5e 100644 --- a/validator/client/beacon-api/propose_beacon_block_bellatrix_test.go +++ b/validator/client/beacon-api/propose_beacon_block_bellatrix_test.go @@ -9,7 +9,6 @@ import ( "github.com/golang/mock/gomock" "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" "github.com/prysmaticlabs/prysm/v3/testing/assert" "github.com/prysmaticlabs/prysm/v3/testing/require" @@ -94,236 +93,7 @@ func TestProposeBeaconBlock_Bellatrix(t *testing.T) { func generateSignedBellatrixBlock() *ethpb.GenericSignedBeaconBlock_Bellatrix { return ðpb.GenericSignedBeaconBlock_Bellatrix{ Bellatrix: ðpb.SignedBeaconBlockBellatrix{ - Block: ðpb.BeaconBlockBellatrix{ - Slot: 1, - ProposerIndex: 2, - ParentRoot: test_helpers.FillByteSlice(32, 3), - StateRoot: test_helpers.FillByteSlice(32, 4), - Body: ðpb.BeaconBlockBodyBellatrix{ - RandaoReveal: test_helpers.FillByteSlice(96, 5), - Eth1Data: ðpb.Eth1Data{ - DepositRoot: test_helpers.FillByteSlice(32, 6), - DepositCount: 7, - BlockHash: test_helpers.FillByteSlice(32, 8), - }, - Graffiti: test_helpers.FillByteSlice(32, 9), - ProposerSlashings: []*ethpb.ProposerSlashing{ - { - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 10, - ProposerIndex: 11, - ParentRoot: test_helpers.FillByteSlice(32, 12), - StateRoot: test_helpers.FillByteSlice(32, 13), - BodyRoot: test_helpers.FillByteSlice(32, 14), - }, - Signature: test_helpers.FillByteSlice(96, 15), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 16, - ProposerIndex: 17, - ParentRoot: test_helpers.FillByteSlice(32, 18), - StateRoot: test_helpers.FillByteSlice(32, 19), - BodyRoot: test_helpers.FillByteSlice(32, 20), - }, - Signature: test_helpers.FillByteSlice(96, 21), - }, - }, - { - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 22, - ProposerIndex: 23, - ParentRoot: test_helpers.FillByteSlice(32, 24), - StateRoot: test_helpers.FillByteSlice(32, 25), - BodyRoot: test_helpers.FillByteSlice(32, 26), - }, - Signature: test_helpers.FillByteSlice(96, 27), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 28, - ProposerIndex: 29, - ParentRoot: test_helpers.FillByteSlice(32, 30), - StateRoot: test_helpers.FillByteSlice(32, 31), - BodyRoot: test_helpers.FillByteSlice(32, 32), - }, - Signature: test_helpers.FillByteSlice(96, 33), - }, - }, - }, - AttesterSlashings: []*ethpb.AttesterSlashing{ - { - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{34, 35}, - Data: ðpb.AttestationData{ - Slot: 36, - CommitteeIndex: 37, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 39, - Root: test_helpers.FillByteSlice(32, 40), - }, - Target: ðpb.Checkpoint{ - Epoch: 41, - Root: test_helpers.FillByteSlice(32, 42), - }, - }, - Signature: test_helpers.FillByteSlice(96, 43), - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{44, 45}, - Data: ðpb.AttestationData{ - Slot: 46, - CommitteeIndex: 47, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 49, - Root: test_helpers.FillByteSlice(32, 50), - }, - Target: ðpb.Checkpoint{ - Epoch: 51, - Root: test_helpers.FillByteSlice(32, 52), - }, - }, - Signature: test_helpers.FillByteSlice(96, 53), - }, - }, - { - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{54, 55}, - Data: ðpb.AttestationData{ - Slot: 56, - CommitteeIndex: 57, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 59, - Root: test_helpers.FillByteSlice(32, 60), - }, - Target: ðpb.Checkpoint{ - Epoch: 61, - Root: test_helpers.FillByteSlice(32, 62), - }, - }, - Signature: test_helpers.FillByteSlice(96, 63), - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{64, 65}, - Data: ðpb.AttestationData{ - Slot: 66, - CommitteeIndex: 67, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 69, - Root: test_helpers.FillByteSlice(32, 70), - }, - Target: ðpb.Checkpoint{ - Epoch: 71, - Root: test_helpers.FillByteSlice(32, 72), - }, - }, - Signature: test_helpers.FillByteSlice(96, 73), - }, - }, - }, - Attestations: []*ethpb.Attestation{ - { - AggregationBits: test_helpers.FillByteSlice(4, 74), - Data: ðpb.AttestationData{ - Slot: 75, - CommitteeIndex: 76, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 78, - Root: test_helpers.FillByteSlice(32, 79), - }, - Target: ðpb.Checkpoint{ - Epoch: 80, - Root: test_helpers.FillByteSlice(32, 81), - }, - }, - Signature: test_helpers.FillByteSlice(96, 82), - }, - { - AggregationBits: test_helpers.FillByteSlice(4, 83), - Data: ðpb.AttestationData{ - Slot: 84, - CommitteeIndex: 85, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 87, - Root: test_helpers.FillByteSlice(32, 88), - }, - Target: ðpb.Checkpoint{ - Epoch: 89, - Root: test_helpers.FillByteSlice(32, 90), - }, - }, - Signature: test_helpers.FillByteSlice(96, 91), - }, - }, - Deposits: []*ethpb.Deposit{ - { - Proof: test_helpers.FillByteArraySlice(33, test_helpers.FillByteSlice(32, 92)), - Data: ðpb.Deposit_Data{ - PublicKey: test_helpers.FillByteSlice(48, 94), - WithdrawalCredentials: test_helpers.FillByteSlice(32, 95), - Amount: 96, - Signature: test_helpers.FillByteSlice(96, 97), - }, - }, - { - Proof: test_helpers.FillByteArraySlice(33, test_helpers.FillByteSlice(32, 98)), - Data: ðpb.Deposit_Data{ - PublicKey: test_helpers.FillByteSlice(48, 100), - WithdrawalCredentials: test_helpers.FillByteSlice(32, 101), - Amount: 102, - Signature: test_helpers.FillByteSlice(96, 103), - }, - }, - }, - VoluntaryExits: []*ethpb.SignedVoluntaryExit{ - { - Exit: ðpb.VoluntaryExit{ - Epoch: 104, - ValidatorIndex: 105, - }, - Signature: test_helpers.FillByteSlice(96, 106), - }, - { - Exit: ðpb.VoluntaryExit{ - Epoch: 107, - ValidatorIndex: 108, - }, - Signature: test_helpers.FillByteSlice(96, 109), - }, - }, - SyncAggregate: ðpb.SyncAggregate{ - SyncCommitteeBits: test_helpers.FillByteSlice(64, 110), - SyncCommitteeSignature: test_helpers.FillByteSlice(96, 111), - }, - ExecutionPayload: &enginev1.ExecutionPayload{ - ParentHash: test_helpers.FillByteSlice(32, 112), - FeeRecipient: test_helpers.FillByteSlice(20, 113), - StateRoot: test_helpers.FillByteSlice(32, 114), - ReceiptsRoot: test_helpers.FillByteSlice(32, 115), - LogsBloom: test_helpers.FillByteSlice(256, 116), - PrevRandao: test_helpers.FillByteSlice(32, 117), - BlockNumber: 118, - GasLimit: 119, - GasUsed: 120, - Timestamp: 121, - ExtraData: test_helpers.FillByteSlice(32, 122), - BaseFeePerGas: test_helpers.FillByteSlice(32, 123), - BlockHash: test_helpers.FillByteSlice(32, 124), - Transactions: [][]byte{ - {125}, - {126}, - }, - }, - }, - }, + Block: test_helpers.GenerateProtoBellatrixBeaconBlock(), Signature: test_helpers.FillByteSlice(96, 127), }, } diff --git a/validator/client/beacon-api/propose_beacon_block_phase0_test.go b/validator/client/beacon-api/propose_beacon_block_phase0_test.go index e723660433..286975eeb5 100644 --- a/validator/client/beacon-api/propose_beacon_block_phase0_test.go +++ b/validator/client/beacon-api/propose_beacon_block_phase0_test.go @@ -72,213 +72,7 @@ func TestProposeBeaconBlock_Phase0(t *testing.T) { func generateSignedPhase0Block() *ethpb.GenericSignedBeaconBlock_Phase0 { return ðpb.GenericSignedBeaconBlock_Phase0{ Phase0: ðpb.SignedBeaconBlock{ - Block: ðpb.BeaconBlock{ - Slot: 1, - ProposerIndex: 2, - ParentRoot: test_helpers.FillByteSlice(32, 3), - StateRoot: test_helpers.FillByteSlice(32, 4), - Body: ðpb.BeaconBlockBody{ - RandaoReveal: test_helpers.FillByteSlice(96, 5), - Eth1Data: ðpb.Eth1Data{ - DepositRoot: test_helpers.FillByteSlice(32, 6), - DepositCount: 7, - BlockHash: test_helpers.FillByteSlice(32, 8), - }, - Graffiti: test_helpers.FillByteSlice(32, 9), - ProposerSlashings: []*ethpb.ProposerSlashing{ - { - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 10, - ProposerIndex: 11, - ParentRoot: test_helpers.FillByteSlice(32, 12), - StateRoot: test_helpers.FillByteSlice(32, 13), - BodyRoot: test_helpers.FillByteSlice(32, 14), - }, - Signature: test_helpers.FillByteSlice(96, 15), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 16, - ProposerIndex: 17, - ParentRoot: test_helpers.FillByteSlice(32, 18), - StateRoot: test_helpers.FillByteSlice(32, 19), - BodyRoot: test_helpers.FillByteSlice(32, 20), - }, - Signature: test_helpers.FillByteSlice(96, 21), - }, - }, - { - Header_1: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 22, - ProposerIndex: 23, - ParentRoot: test_helpers.FillByteSlice(32, 24), - StateRoot: test_helpers.FillByteSlice(32, 25), - BodyRoot: test_helpers.FillByteSlice(32, 26), - }, - Signature: test_helpers.FillByteSlice(96, 27), - }, - Header_2: ðpb.SignedBeaconBlockHeader{ - Header: ðpb.BeaconBlockHeader{ - Slot: 28, - ProposerIndex: 29, - ParentRoot: test_helpers.FillByteSlice(32, 30), - StateRoot: test_helpers.FillByteSlice(32, 31), - BodyRoot: test_helpers.FillByteSlice(32, 32), - }, - Signature: test_helpers.FillByteSlice(96, 33), - }, - }, - }, - AttesterSlashings: []*ethpb.AttesterSlashing{ - { - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{34, 35}, - Data: ðpb.AttestationData{ - Slot: 36, - CommitteeIndex: 37, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 39, - Root: test_helpers.FillByteSlice(32, 40), - }, - Target: ðpb.Checkpoint{ - Epoch: 41, - Root: test_helpers.FillByteSlice(32, 42), - }, - }, - Signature: test_helpers.FillByteSlice(96, 43), - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{44, 45}, - Data: ðpb.AttestationData{ - Slot: 46, - CommitteeIndex: 47, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 48), - Source: ðpb.Checkpoint{ - Epoch: 49, - Root: test_helpers.FillByteSlice(32, 50), - }, - Target: ðpb.Checkpoint{ - Epoch: 51, - Root: test_helpers.FillByteSlice(32, 52), - }, - }, - Signature: test_helpers.FillByteSlice(96, 53), - }, - }, - { - Attestation_1: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{54, 55}, - Data: ðpb.AttestationData{ - Slot: 56, - CommitteeIndex: 57, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 58), - Source: ðpb.Checkpoint{ - Epoch: 59, - Root: test_helpers.FillByteSlice(32, 60), - }, - Target: ðpb.Checkpoint{ - Epoch: 61, - Root: test_helpers.FillByteSlice(32, 62), - }, - }, - Signature: test_helpers.FillByteSlice(96, 63), - }, - Attestation_2: ðpb.IndexedAttestation{ - AttestingIndices: []uint64{64, 65}, - Data: ðpb.AttestationData{ - Slot: 66, - CommitteeIndex: 67, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 68), - Source: ðpb.Checkpoint{ - Epoch: 69, - Root: test_helpers.FillByteSlice(32, 70), - }, - Target: ðpb.Checkpoint{ - Epoch: 71, - Root: test_helpers.FillByteSlice(32, 72), - }, - }, - Signature: test_helpers.FillByteSlice(96, 73), - }, - }, - }, - Attestations: []*ethpb.Attestation{ - { - AggregationBits: test_helpers.FillByteSlice(32, 74), - Data: ðpb.AttestationData{ - Slot: 75, - CommitteeIndex: 76, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 77), - Source: ðpb.Checkpoint{ - Epoch: 78, - Root: test_helpers.FillByteSlice(32, 79), - }, - Target: ðpb.Checkpoint{ - Epoch: 80, - Root: test_helpers.FillByteSlice(32, 81), - }, - }, - Signature: test_helpers.FillByteSlice(96, 82), - }, - { - AggregationBits: test_helpers.FillByteSlice(4, 83), - Data: ðpb.AttestationData{ - Slot: 84, - CommitteeIndex: 85, - BeaconBlockRoot: test_helpers.FillByteSlice(32, 38), - Source: ðpb.Checkpoint{ - Epoch: 87, - Root: test_helpers.FillByteSlice(32, 88), - }, - Target: ðpb.Checkpoint{ - Epoch: 89, - Root: test_helpers.FillByteSlice(32, 90), - }, - }, - Signature: test_helpers.FillByteSlice(96, 91), - }, - }, - Deposits: []*ethpb.Deposit{ - { - Proof: test_helpers.FillByteArraySlice(33, test_helpers.FillByteSlice(32, 92)), - Data: ðpb.Deposit_Data{ - PublicKey: test_helpers.FillByteSlice(48, 94), - WithdrawalCredentials: test_helpers.FillByteSlice(32, 95), - Amount: 96, - Signature: test_helpers.FillByteSlice(96, 97), - }, - }, - { - Proof: test_helpers.FillByteArraySlice(33, test_helpers.FillByteSlice(32, 98)), - Data: ðpb.Deposit_Data{ - PublicKey: test_helpers.FillByteSlice(48, 100), - WithdrawalCredentials: test_helpers.FillByteSlice(32, 101), - Amount: 102, - Signature: test_helpers.FillByteSlice(96, 103), - }, - }, - }, - VoluntaryExits: []*ethpb.SignedVoluntaryExit{ - { - Exit: ðpb.VoluntaryExit{ - Epoch: 104, - ValidatorIndex: 105, - }, - Signature: test_helpers.FillByteSlice(96, 106), - }, - { - Exit: ðpb.VoluntaryExit{ - Epoch: 107, - ValidatorIndex: 108, - }, - Signature: test_helpers.FillByteSlice(96, 109), - }, - }, - }, - }, + Block: test_helpers.GenerateProtoPhase0BeaconBlock(), Signature: test_helpers.FillByteSlice(96, 110), }, } diff --git a/validator/client/beacon-api/test-helpers/BUILD.bazel b/validator/client/beacon-api/test-helpers/BUILD.bazel index f1a9406b7b..529d27096b 100644 --- a/validator/client/beacon-api/test-helpers/BUILD.bazel +++ b/validator/client/beacon-api/test-helpers/BUILD.bazel @@ -3,7 +3,19 @@ load("@prysm//tools/go:def.bzl", "go_library") go_library( name = "go_default_library", testonly = True, - srcs = ["test_helpers.go"], + srcs = [ + "altair_beacon_block_test_helpers.go", + "bellatrix_beacon_block_test_helpers.go", + "phase0_beacon_block_test_helpers.go", + "test_helpers.go", + ], importpath = "github.com/prysmaticlabs/prysm/v3/validator/client/beacon-api/test-helpers", visibility = ["//validator:__subpackages__"], + deps = [ + "//beacon-chain/rpc/apimiddleware:go_default_library", + "//encoding/bytesutil:go_default_library", + "//proto/engine/v1:go_default_library", + "//proto/prysm/v1alpha1:go_default_library", + "@com_github_ethereum_go_ethereum//common/hexutil:go_default_library", + ], ) diff --git a/validator/client/beacon-api/test-helpers/altair_beacon_block_test_helpers.go b/validator/client/beacon-api/test-helpers/altair_beacon_block_test_helpers.go new file mode 100644 index 0000000000..b2bcbe8038 --- /dev/null +++ b/validator/client/beacon-api/test-helpers/altair_beacon_block_test_helpers.go @@ -0,0 +1,434 @@ +package test_helpers + +import ( + "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" +) + +func GenerateProtoAltairBeaconBlock() *ethpb.BeaconBlockAltair { + return ðpb.BeaconBlockAltair{ + Slot: 1, + ProposerIndex: 2, + ParentRoot: FillByteSlice(32, 3), + StateRoot: FillByteSlice(32, 4), + Body: ðpb.BeaconBlockBodyAltair{ + RandaoReveal: FillByteSlice(96, 5), + Eth1Data: ðpb.Eth1Data{ + DepositRoot: FillByteSlice(32, 6), + DepositCount: 7, + BlockHash: FillByteSlice(32, 8), + }, + Graffiti: FillByteSlice(32, 9), + ProposerSlashings: []*ethpb.ProposerSlashing{ + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 11, + ParentRoot: FillByteSlice(32, 12), + StateRoot: FillByteSlice(32, 13), + BodyRoot: FillByteSlice(32, 14), + }, + Signature: FillByteSlice(96, 15), + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 16, + ProposerIndex: 17, + ParentRoot: FillByteSlice(32, 18), + StateRoot: FillByteSlice(32, 19), + BodyRoot: FillByteSlice(32, 20), + }, + Signature: FillByteSlice(96, 21), + }, + }, + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 22, + ProposerIndex: 23, + ParentRoot: FillByteSlice(32, 24), + StateRoot: FillByteSlice(32, 25), + BodyRoot: FillByteSlice(32, 26), + }, + Signature: FillByteSlice(96, 27), + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.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: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{34, 35}, + Data: ðpb.AttestationData{ + Slot: 36, + CommitteeIndex: 37, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 39, + Root: FillByteSlice(32, 40), + }, + Target: ðpb.Checkpoint{ + Epoch: 41, + Root: FillByteSlice(32, 42), + }, + }, + Signature: FillByteSlice(96, 43), + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{44, 45}, + Data: ðpb.AttestationData{ + Slot: 46, + CommitteeIndex: 47, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 49, + Root: FillByteSlice(32, 50), + }, + Target: ðpb.Checkpoint{ + Epoch: 51, + Root: FillByteSlice(32, 52), + }, + }, + Signature: FillByteSlice(96, 53), + }, + }, + { + Attestation_1: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{54, 55}, + Data: ðpb.AttestationData{ + Slot: 56, + CommitteeIndex: 57, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 59, + Root: FillByteSlice(32, 60), + }, + Target: ðpb.Checkpoint{ + Epoch: 61, + Root: FillByteSlice(32, 62), + }, + }, + Signature: FillByteSlice(96, 63), + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{64, 65}, + Data: ðpb.AttestationData{ + Slot: 66, + CommitteeIndex: 67, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 69, + Root: FillByteSlice(32, 70), + }, + Target: ðpb.Checkpoint{ + Epoch: 71, + Root: FillByteSlice(32, 72), + }, + }, + Signature: FillByteSlice(96, 73), + }, + }, + }, + Attestations: []*ethpb.Attestation{ + { + AggregationBits: FillByteSlice(4, 74), + Data: ðpb.AttestationData{ + Slot: 75, + CommitteeIndex: 76, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 78, + Root: FillByteSlice(32, 79), + }, + Target: ðpb.Checkpoint{ + Epoch: 80, + Root: FillByteSlice(32, 81), + }, + }, + Signature: FillByteSlice(96, 82), + }, + { + AggregationBits: FillByteSlice(4, 83), + Data: ðpb.AttestationData{ + Slot: 84, + CommitteeIndex: 85, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 87, + Root: FillByteSlice(32, 88), + }, + Target: ðpb.Checkpoint{ + Epoch: 89, + Root: FillByteSlice(32, 90), + }, + }, + Signature: FillByteSlice(96, 91), + }, + }, + Deposits: []*ethpb.Deposit{ + { + Proof: FillByteArraySlice(33, FillByteSlice(32, 92)), + Data: ðpb.Deposit_Data{ + PublicKey: FillByteSlice(48, 94), + WithdrawalCredentials: FillByteSlice(32, 95), + Amount: 96, + Signature: FillByteSlice(96, 97), + }, + }, + { + Proof: FillByteArraySlice(33, FillByteSlice(32, 98)), + Data: ðpb.Deposit_Data{ + PublicKey: FillByteSlice(48, 100), + WithdrawalCredentials: FillByteSlice(32, 101), + Amount: 102, + Signature: FillByteSlice(96, 103), + }, + }, + }, + VoluntaryExits: []*ethpb.SignedVoluntaryExit{ + { + Exit: ðpb.VoluntaryExit{ + Epoch: 104, + ValidatorIndex: 105, + }, + Signature: FillByteSlice(96, 106), + }, + { + Exit: ðpb.VoluntaryExit{ + Epoch: 107, + ValidatorIndex: 108, + }, + Signature: FillByteSlice(96, 109), + }, + }, + SyncAggregate: ðpb.SyncAggregate{ + SyncCommitteeBits: FillByteSlice(64, 110), + SyncCommitteeSignature: FillByteSlice(96, 111), + }, + }, + } +} + +func GenerateJsonAltairBeaconBlock() *apimiddleware.BeaconBlockAltairJson { + return &apimiddleware.BeaconBlockAltairJson{ + Slot: "1", + ProposerIndex: "2", + ParentRoot: FillEncodedByteSlice(32, 3), + StateRoot: FillEncodedByteSlice(32, 4), + Body: &apimiddleware.BeaconBlockBodyAltairJson{ + 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), + }, + }, + } +} diff --git a/validator/client/beacon-api/test-helpers/bellatrix_beacon_block_test_helpers.go b/validator/client/beacon-api/test-helpers/bellatrix_beacon_block_test_helpers.go new file mode 100644 index 0000000000..2bc479c07e --- /dev/null +++ b/validator/client/beacon-api/test-helpers/bellatrix_beacon_block_test_helpers.go @@ -0,0 +1,474 @@ +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 GenerateProtoBellatrixBeaconBlock() *ethpb.BeaconBlockBellatrix { + return ðpb.BeaconBlockBellatrix{ + Slot: 1, + ProposerIndex: 2, + ParentRoot: FillByteSlice(32, 3), + StateRoot: FillByteSlice(32, 4), + Body: ðpb.BeaconBlockBodyBellatrix{ + RandaoReveal: FillByteSlice(96, 5), + Eth1Data: ðpb.Eth1Data{ + DepositRoot: FillByteSlice(32, 6), + DepositCount: 7, + BlockHash: FillByteSlice(32, 8), + }, + Graffiti: FillByteSlice(32, 9), + ProposerSlashings: []*ethpb.ProposerSlashing{ + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 11, + ParentRoot: FillByteSlice(32, 12), + StateRoot: FillByteSlice(32, 13), + BodyRoot: FillByteSlice(32, 14), + }, + Signature: FillByteSlice(96, 15), + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 16, + ProposerIndex: 17, + ParentRoot: FillByteSlice(32, 18), + StateRoot: FillByteSlice(32, 19), + BodyRoot: FillByteSlice(32, 20), + }, + Signature: FillByteSlice(96, 21), + }, + }, + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 22, + ProposerIndex: 23, + ParentRoot: FillByteSlice(32, 24), + StateRoot: FillByteSlice(32, 25), + BodyRoot: FillByteSlice(32, 26), + }, + Signature: FillByteSlice(96, 27), + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.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: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{34, 35}, + Data: ðpb.AttestationData{ + Slot: 36, + CommitteeIndex: 37, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 39, + Root: FillByteSlice(32, 40), + }, + Target: ðpb.Checkpoint{ + Epoch: 41, + Root: FillByteSlice(32, 42), + }, + }, + Signature: FillByteSlice(96, 43), + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{44, 45}, + Data: ðpb.AttestationData{ + Slot: 46, + CommitteeIndex: 47, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 49, + Root: FillByteSlice(32, 50), + }, + Target: ðpb.Checkpoint{ + Epoch: 51, + Root: FillByteSlice(32, 52), + }, + }, + Signature: FillByteSlice(96, 53), + }, + }, + { + Attestation_1: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{54, 55}, + Data: ðpb.AttestationData{ + Slot: 56, + CommitteeIndex: 57, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 59, + Root: FillByteSlice(32, 60), + }, + Target: ðpb.Checkpoint{ + Epoch: 61, + Root: FillByteSlice(32, 62), + }, + }, + Signature: FillByteSlice(96, 63), + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{64, 65}, + Data: ðpb.AttestationData{ + Slot: 66, + CommitteeIndex: 67, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 69, + Root: FillByteSlice(32, 70), + }, + Target: ðpb.Checkpoint{ + Epoch: 71, + Root: FillByteSlice(32, 72), + }, + }, + Signature: FillByteSlice(96, 73), + }, + }, + }, + Attestations: []*ethpb.Attestation{ + { + AggregationBits: FillByteSlice(4, 74), + Data: ðpb.AttestationData{ + Slot: 75, + CommitteeIndex: 76, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 78, + Root: FillByteSlice(32, 79), + }, + Target: ðpb.Checkpoint{ + Epoch: 80, + Root: FillByteSlice(32, 81), + }, + }, + Signature: FillByteSlice(96, 82), + }, + { + AggregationBits: FillByteSlice(4, 83), + Data: ðpb.AttestationData{ + Slot: 84, + CommitteeIndex: 85, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 87, + Root: FillByteSlice(32, 88), + }, + Target: ðpb.Checkpoint{ + Epoch: 89, + Root: FillByteSlice(32, 90), + }, + }, + Signature: FillByteSlice(96, 91), + }, + }, + Deposits: []*ethpb.Deposit{ + { + Proof: FillByteArraySlice(33, FillByteSlice(32, 92)), + Data: ðpb.Deposit_Data{ + PublicKey: FillByteSlice(48, 94), + WithdrawalCredentials: FillByteSlice(32, 95), + Amount: 96, + Signature: FillByteSlice(96, 97), + }, + }, + { + Proof: FillByteArraySlice(33, FillByteSlice(32, 98)), + Data: ðpb.Deposit_Data{ + PublicKey: FillByteSlice(48, 100), + WithdrawalCredentials: FillByteSlice(32, 101), + Amount: 102, + Signature: FillByteSlice(96, 103), + }, + }, + }, + VoluntaryExits: []*ethpb.SignedVoluntaryExit{ + { + Exit: ðpb.VoluntaryExit{ + Epoch: 104, + ValidatorIndex: 105, + }, + Signature: FillByteSlice(96, 106), + }, + { + Exit: ðpb.VoluntaryExit{ + Epoch: 107, + ValidatorIndex: 108, + }, + Signature: FillByteSlice(96, 109), + }, + }, + SyncAggregate: ðpb.SyncAggregate{ + SyncCommitteeBits: FillByteSlice(64, 110), + SyncCommitteeSignature: FillByteSlice(96, 111), + }, + ExecutionPayload: &enginev1.ExecutionPayload{ + 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), + }, + }, + }, + } +} + +func GenerateJsonBellatrixBeaconBlock() *apimiddleware.BeaconBlockBellatrixJson { + return &apimiddleware.BeaconBlockBellatrixJson{ + Slot: "1", + ProposerIndex: "2", + ParentRoot: FillEncodedByteSlice(32, 3), + StateRoot: FillEncodedByteSlice(32, 4), + Body: &apimiddleware.BeaconBlockBodyBellatrixJson{ + 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.ExecutionPayloadJson{ + 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), + }, + }, + }, + } +} diff --git a/validator/client/beacon-api/test-helpers/phase0_beacon_block_test_helpers.go b/validator/client/beacon-api/test-helpers/phase0_beacon_block_test_helpers.go new file mode 100644 index 0000000000..58a24bf841 --- /dev/null +++ b/validator/client/beacon-api/test-helpers/phase0_beacon_block_test_helpers.go @@ -0,0 +1,426 @@ +package test_helpers + +import ( + "github.com/prysmaticlabs/prysm/v3/beacon-chain/rpc/apimiddleware" + ethpb "github.com/prysmaticlabs/prysm/v3/proto/prysm/v1alpha1" +) + +func GenerateProtoPhase0BeaconBlock() *ethpb.BeaconBlock { + return ðpb.BeaconBlock{ + Slot: 1, + ProposerIndex: 2, + ParentRoot: FillByteSlice(32, 3), + StateRoot: FillByteSlice(32, 4), + Body: ðpb.BeaconBlockBody{ + RandaoReveal: FillByteSlice(96, 5), + Eth1Data: ðpb.Eth1Data{ + DepositRoot: FillByteSlice(32, 6), + DepositCount: 7, + BlockHash: FillByteSlice(32, 8), + }, + Graffiti: FillByteSlice(32, 9), + ProposerSlashings: []*ethpb.ProposerSlashing{ + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 10, + ProposerIndex: 11, + ParentRoot: FillByteSlice(32, 12), + StateRoot: FillByteSlice(32, 13), + BodyRoot: FillByteSlice(32, 14), + }, + Signature: FillByteSlice(96, 15), + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 16, + ProposerIndex: 17, + ParentRoot: FillByteSlice(32, 18), + StateRoot: FillByteSlice(32, 19), + BodyRoot: FillByteSlice(32, 20), + }, + Signature: FillByteSlice(96, 21), + }, + }, + { + Header_1: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.BeaconBlockHeader{ + Slot: 22, + ProposerIndex: 23, + ParentRoot: FillByteSlice(32, 24), + StateRoot: FillByteSlice(32, 25), + BodyRoot: FillByteSlice(32, 26), + }, + Signature: FillByteSlice(96, 27), + }, + Header_2: ðpb.SignedBeaconBlockHeader{ + Header: ðpb.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: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{34, 35}, + Data: ðpb.AttestationData{ + Slot: 36, + CommitteeIndex: 37, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 39, + Root: FillByteSlice(32, 40), + }, + Target: ðpb.Checkpoint{ + Epoch: 41, + Root: FillByteSlice(32, 42), + }, + }, + Signature: FillByteSlice(96, 43), + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{44, 45}, + Data: ðpb.AttestationData{ + Slot: 46, + CommitteeIndex: 47, + BeaconBlockRoot: FillByteSlice(32, 48), + Source: ðpb.Checkpoint{ + Epoch: 49, + Root: FillByteSlice(32, 50), + }, + Target: ðpb.Checkpoint{ + Epoch: 51, + Root: FillByteSlice(32, 52), + }, + }, + Signature: FillByteSlice(96, 53), + }, + }, + { + Attestation_1: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{54, 55}, + Data: ðpb.AttestationData{ + Slot: 56, + CommitteeIndex: 57, + BeaconBlockRoot: FillByteSlice(32, 58), + Source: ðpb.Checkpoint{ + Epoch: 59, + Root: FillByteSlice(32, 60), + }, + Target: ðpb.Checkpoint{ + Epoch: 61, + Root: FillByteSlice(32, 62), + }, + }, + Signature: FillByteSlice(96, 63), + }, + Attestation_2: ðpb.IndexedAttestation{ + AttestingIndices: []uint64{64, 65}, + Data: ðpb.AttestationData{ + Slot: 66, + CommitteeIndex: 67, + BeaconBlockRoot: FillByteSlice(32, 68), + Source: ðpb.Checkpoint{ + Epoch: 69, + Root: FillByteSlice(32, 70), + }, + Target: ðpb.Checkpoint{ + Epoch: 71, + Root: FillByteSlice(32, 72), + }, + }, + Signature: FillByteSlice(96, 73), + }, + }, + }, + Attestations: []*ethpb.Attestation{ + { + AggregationBits: FillByteSlice(32, 74), + Data: ðpb.AttestationData{ + Slot: 75, + CommitteeIndex: 76, + BeaconBlockRoot: FillByteSlice(32, 77), + Source: ðpb.Checkpoint{ + Epoch: 78, + Root: FillByteSlice(32, 79), + }, + Target: ðpb.Checkpoint{ + Epoch: 80, + Root: FillByteSlice(32, 81), + }, + }, + Signature: FillByteSlice(96, 82), + }, + { + AggregationBits: FillByteSlice(4, 83), + Data: ðpb.AttestationData{ + Slot: 84, + CommitteeIndex: 85, + BeaconBlockRoot: FillByteSlice(32, 38), + Source: ðpb.Checkpoint{ + Epoch: 87, + Root: FillByteSlice(32, 88), + }, + Target: ðpb.Checkpoint{ + Epoch: 89, + Root: FillByteSlice(32, 90), + }, + }, + Signature: FillByteSlice(96, 91), + }, + }, + Deposits: []*ethpb.Deposit{ + { + Proof: FillByteArraySlice(33, FillByteSlice(32, 92)), + Data: ðpb.Deposit_Data{ + PublicKey: FillByteSlice(48, 94), + WithdrawalCredentials: FillByteSlice(32, 95), + Amount: 96, + Signature: FillByteSlice(96, 97), + }, + }, + { + Proof: FillByteArraySlice(33, FillByteSlice(32, 98)), + Data: ðpb.Deposit_Data{ + PublicKey: FillByteSlice(48, 100), + WithdrawalCredentials: FillByteSlice(32, 101), + Amount: 102, + Signature: FillByteSlice(96, 103), + }, + }, + }, + VoluntaryExits: []*ethpb.SignedVoluntaryExit{ + { + Exit: ðpb.VoluntaryExit{ + Epoch: 104, + ValidatorIndex: 105, + }, + Signature: FillByteSlice(96, 106), + }, + { + Exit: ðpb.VoluntaryExit{ + Epoch: 107, + ValidatorIndex: 108, + }, + Signature: FillByteSlice(96, 109), + }, + }, + }, + } +} + +func GenerateJsonPhase0BeaconBlock() *apimiddleware.BeaconBlockJson { + return &apimiddleware.BeaconBlockJson{ + Slot: "1", + ProposerIndex: "2", + ParentRoot: FillEncodedByteSlice(32, 3), + StateRoot: FillEncodedByteSlice(32, 4), + Body: &apimiddleware.BeaconBlockBodyJson{ + 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, 48), + 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, 58), + 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, 68), + 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(32, 74), + Data: &apimiddleware.AttestationDataJson{ + Slot: "75", + CommitteeIndex: "76", + BeaconBlockRoot: FillEncodedByteSlice(32, 77), + 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), + }, + }, + }, + } +} diff --git a/validator/client/beacon-api/test-helpers/test_helpers.go b/validator/client/beacon-api/test-helpers/test_helpers.go index 9566d64fcf..c4ccbbb782 100644 --- a/validator/client/beacon-api/test-helpers/test_helpers.go +++ b/validator/client/beacon-api/test-helpers/test_helpers.go @@ -1,5 +1,9 @@ package test_helpers +import ( + "github.com/ethereum/go-ethereum/common/hexutil" +) + func FillByteSlice(sliceLength int, value byte) []byte { bytes := make([]byte, sliceLength) @@ -19,3 +23,15 @@ func FillByteArraySlice(sliceLength int, value []byte) [][]byte { return bytes } + +func FillEncodedByteSlice(sliceLength int, value byte) string { + return hexutil.Encode(FillByteSlice(sliceLength, value)) +} + +func FillEncodedByteArraySlice(sliceLength int, value string) []string { + encodedBytes := make([]string, sliceLength) + for index := range encodedBytes { + encodedBytes[index] = value + } + return encodedBytes +} diff --git a/validator/keymanager/remote-web3signer/v1/web3signer_types.go b/validator/keymanager/remote-web3signer/v1/web3signer_types.go index 41cc4271b6..4b30fc9d3a 100644 --- a/validator/keymanager/remote-web3signer/v1/web3signer_types.go +++ b/validator/keymanager/remote-web3signer/v1/web3signer_types.go @@ -249,7 +249,7 @@ type VoluntaryExit struct { // BeaconBlockAltairBlockV2 a sub property of BlockAltairSignRequest. type BeaconBlockAltairBlockV2 struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Block *BeaconBlockAltair `json:"block"` } @@ -277,7 +277,7 @@ type BeaconBlockBodyAltair struct { // BeaconBlockBellatrixBlockV2 a field of BlockBellatrixSignRequest. type BeaconBlockBellatrixBlockV2 struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` BlockHeader *BeaconBlockHeader `json:"block_header"` } @@ -289,7 +289,7 @@ type SyncAggregate struct { // BeaconBlockBlockV2 a sub property of BlockV2SignRequest. type BeaconBlockBlockV2 struct { - Version string `json:"version"` + Version string `json:"version" enum:"true"` Block *BeaconBlock `json:"beacon_block"` }