Files
prysm/validator/client/beacon-api/attestation_data_test.go
Preston Van Loon 62fec4d1f3 Replace context.Background with testing.TB.Context where possible (#15416)
* Replace context.Background with testing.TB.Context where possible

* Fix failing tests
2025-06-16 22:09:18 +00:00

243 lines
7.8 KiB
Go

package beacon_api
import (
"errors"
"fmt"
"strconv"
"testing"
"github.com/OffchainLabs/prysm/v6/api/server/structs"
"github.com/OffchainLabs/prysm/v6/consensus-types/primitives"
"github.com/OffchainLabs/prysm/v6/testing/assert"
"github.com/OffchainLabs/prysm/v6/testing/require"
"github.com/OffchainLabs/prysm/v6/validator/client/beacon-api/mock"
"github.com/ethereum/go-ethereum/common/hexutil"
"go.uber.org/mock/gomock"
)
func TestGetAttestationData_ValidAttestation(t *testing.T) {
ctx := t.Context()
expectedSlot := uint64(5)
expectedCommitteeIndex := uint64(6)
expectedBeaconBlockRoot := "0x0636045df9bdda3ab96592cf5389032c8ec3977f911e2b53509b348dfe164d4d"
expectedSourceEpoch := uint64(7)
expectedSourceRoot := "0xd4bcbdefc8156e85247681086e8050e5d2d5d1bf076a25f6decd99250f3a378d"
expectedTargetEpoch := uint64(8)
expectedTargetRoot := "0x246590e8e4c2a9bd13cc776ecc7025bc432219f076e80b27267b8fa0456dc821"
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
produceAttestationDataResponseJson := structs.GetAttestationDataResponse{}
jsonRestHandler.EXPECT().Get(
gomock.Any(),
fmt.Sprintf("/eth/v1/validator/attestation_data?committee_index=%d&slot=%d", expectedCommitteeIndex, expectedSlot),
&produceAttestationDataResponseJson,
).Return(
nil,
).SetArg(
2,
structs.GetAttestationDataResponse{
Data: &structs.AttestationData{
Slot: strconv.FormatUint(expectedSlot, 10),
CommitteeIndex: strconv.FormatUint(expectedCommitteeIndex, 10),
BeaconBlockRoot: expectedBeaconBlockRoot,
Source: &structs.Checkpoint{
Epoch: strconv.FormatUint(expectedSourceEpoch, 10),
Root: expectedSourceRoot,
},
Target: &structs.Checkpoint{
Epoch: strconv.FormatUint(expectedTargetEpoch, 10),
Root: expectedTargetRoot,
},
},
},
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
resp, err := validatorClient.attestationData(ctx, primitives.Slot(expectedSlot), primitives.CommitteeIndex(expectedCommitteeIndex))
assert.NoError(t, err)
require.NotNil(t, resp)
assert.Equal(t, expectedBeaconBlockRoot, hexutil.Encode(resp.BeaconBlockRoot))
assert.Equal(t, expectedCommitteeIndex, uint64(resp.CommitteeIndex))
assert.Equal(t, expectedSlot, uint64(resp.Slot))
require.NotNil(t, resp.Source)
assert.Equal(t, expectedSourceEpoch, uint64(resp.Source.Epoch))
assert.Equal(t, expectedSourceRoot, hexutil.Encode(resp.Source.Root))
require.NotNil(t, resp.Target)
assert.Equal(t, expectedTargetEpoch, uint64(resp.Target.Epoch))
assert.Equal(t, expectedTargetRoot, hexutil.Encode(resp.Target.Root))
}
func TestGetAttestationData_InvalidData(t *testing.T) {
ctx := t.Context()
testCases := []struct {
name string
generateData func() structs.GetAttestationDataResponse
expectedErrorMessage string
}{
{
name: "nil attestation data",
generateData: func() structs.GetAttestationDataResponse {
return structs.GetAttestationDataResponse{
Data: nil,
}
},
expectedErrorMessage: "attestation data is nil",
},
{
name: "invalid committee index",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.CommitteeIndex = "foo"
return attestation
},
expectedErrorMessage: "failed to parse attestation committee index: foo",
},
{
name: "invalid block root",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.BeaconBlockRoot = "foo"
return attestation
},
expectedErrorMessage: "failed to decode beacon block root: foo",
},
{
name: "invalid slot",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Slot = "foo"
return attestation
},
expectedErrorMessage: "failed to parse attestation slot: foo",
},
{
name: "nil source",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Source = nil
return attestation
},
expectedErrorMessage: "attestation source is nil",
},
{
name: "invalid source epoch",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Source.Epoch = "foo"
return attestation
},
expectedErrorMessage: "failed to parse attestation source epoch: foo",
},
{
name: "invalid source root",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Source.Root = "foo"
return attestation
},
expectedErrorMessage: "failed to decode attestation source root: foo",
},
{
name: "nil target",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Target = nil
return attestation
},
expectedErrorMessage: "attestation target is nil",
},
{
name: "invalid target epoch",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Target.Epoch = "foo"
return attestation
},
expectedErrorMessage: "failed to parse attestation target epoch: foo",
},
{
name: "invalid target root",
generateData: func() structs.GetAttestationDataResponse {
attestation := generateValidAttestation(1, 2)
attestation.Data.Target.Root = "foo"
return attestation
},
expectedErrorMessage: "failed to decode attestation target root: foo",
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
ctrl := gomock.NewController(t)
defer ctrl.Finish()
produceAttestationDataResponseJson := structs.GetAttestationDataResponse{}
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
jsonRestHandler.EXPECT().Get(
gomock.Any(),
"/eth/v1/validator/attestation_data?committee_index=2&slot=1",
&produceAttestationDataResponseJson,
).Return(
nil,
).SetArg(
2,
testCase.generateData(),
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
_, err := validatorClient.attestationData(ctx, 1, 2)
assert.ErrorContains(t, testCase.expectedErrorMessage, err)
})
}
}
func TestGetAttestationData_JsonResponseError(t *testing.T) {
const slot = primitives.Slot(1)
const committeeIndex = primitives.CommitteeIndex(2)
ctx := t.Context()
ctrl := gomock.NewController(t)
defer ctrl.Finish()
jsonRestHandler := mock.NewMockJsonRestHandler(ctrl)
produceAttestationDataResponseJson := structs.GetAttestationDataResponse{}
jsonRestHandler.EXPECT().Get(
gomock.Any(),
fmt.Sprintf("/eth/v1/validator/attestation_data?committee_index=%d&slot=%d", committeeIndex, slot),
&produceAttestationDataResponseJson,
).Return(
errors.New("some specific json response error"),
).Times(1)
validatorClient := &beaconApiValidatorClient{jsonRestHandler: jsonRestHandler}
_, err := validatorClient.attestationData(ctx, slot, committeeIndex)
assert.ErrorContains(t, "some specific json response error", err)
}
func generateValidAttestation(slot, committeeIndex uint64) structs.GetAttestationDataResponse {
return structs.GetAttestationDataResponse{
Data: &structs.AttestationData{
Slot: strconv.FormatUint(slot, 10),
CommitteeIndex: strconv.FormatUint(committeeIndex, 10),
BeaconBlockRoot: "0x5ecf3bff35e39d5f75476d42950d549f81fa93038c46b6652ae89ae1f7ad834f",
Source: &structs.Checkpoint{
Epoch: "3",
Root: "0x9023c9e64f23c1d451d5073c641f5f69597c2ad7d82f6f16e67d703e0ce5db8b",
},
Target: &structs.Checkpoint{
Epoch: "4",
Root: "0xb154d46803b15b458ca822466547b054bc124338c6ee1d9c433dcde8c4457cca",
},
},
}
}