mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2025-01-14 14:08:19 +00:00
d17996f8b0
* Update V3 from V4 * Fix build v3 -> v4 * Update ssz * Update beacon_chain.pb.go * Fix formatter import * Update update-mockgen.sh comment to v4 * Fix conflicts. Pass build and tests * Fix test
860 lines
28 KiB
Go
860 lines
28 KiB
Go
package beacon_api
|
|
|
|
import (
|
|
"bytes"
|
|
"context"
|
|
"encoding/json"
|
|
"testing"
|
|
|
|
"github.com/ethereum/go-ethereum/common/hexutil"
|
|
"github.com/golang/mock/gomock"
|
|
"github.com/pkg/errors"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/apimiddleware"
|
|
"github.com/prysmaticlabs/prysm/v4/beacon-chain/rpc/eth/helpers"
|
|
ethpb "github.com/prysmaticlabs/prysm/v4/proto/prysm/v1alpha1"
|
|
"github.com/prysmaticlabs/prysm/v4/testing/assert"
|
|
"github.com/prysmaticlabs/prysm/v4/testing/require"
|
|
"github.com/prysmaticlabs/prysm/v4/validator/client/beacon-api/mock"
|
|
)
|
|
|
|
func TestCheckDoppelGanger_Nominal(t *testing.T) {
|
|
const stringPubKey1 = "0x80000e851c0f53c3246ff726d7ff7766661ca5e12a07c45c114d208d54f0f8233d4380b2e9aff759d69795d1df905526"
|
|
const stringPubKey2 = "0x80002662ecb857da7a37ed468291cb248979eca5131db56c20843262f7909220c296e18f59af1726ef86ec15c08b8317"
|
|
const stringPubKey3 = "0x80003a1c67216514e4ab257738e59ef38063edf43bc4a2ef9d38633bdde117384401684c6cf81aa04cf18890e75ab52c"
|
|
const stringPubKey4 = "0x80007e05ba643a3e5be65d1595154023dc2cf009626f32ab1054c5225a6beb28b8be3d52a463ab45f698df884614c87d"
|
|
const stringPubKey5 = "0x80006ab8cd402459b445b2f5f955c9bae550bc269717837a8cd68176ce42a21fd372b844d508711d6e0bb0efe65abfe5"
|
|
const stringPubKey6 = "0x800077c436fc0c57bec2b91509519deadeed235f35f6377e7865e17ee86271120381a49c643829be12d232a4ba8360d2"
|
|
|
|
pubKey1, err := hexutil.Decode(stringPubKey1)
|
|
require.NoError(t, err)
|
|
|
|
pubKey2, err := hexutil.Decode(stringPubKey2)
|
|
require.NoError(t, err)
|
|
|
|
pubKey3, err := hexutil.Decode(stringPubKey3)
|
|
require.NoError(t, err)
|
|
|
|
pubKey4, err := hexutil.Decode(stringPubKey4)
|
|
require.NoError(t, err)
|
|
|
|
pubKey5, err := hexutil.Decode(stringPubKey5)
|
|
require.NoError(t, err)
|
|
|
|
pubKey6, err := hexutil.Decode(stringPubKey6)
|
|
require.NoError(t, err)
|
|
|
|
testCases := []struct {
|
|
name string
|
|
doppelGangerInput *ethpb.DoppelGangerRequest
|
|
doppelGangerExpectedOutput *ethpb.DoppelGangerResponse
|
|
getSyncingOutput *apimiddleware.SyncingResponseJson
|
|
getForkOutput *apimiddleware.StateForkResponseJson
|
|
getHeadersOutput *apimiddleware.BlockHeadersResponseJson
|
|
getStateValidatorsInterface *struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
}
|
|
getLivelinessInterfaces []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
}
|
|
}{
|
|
{
|
|
name: "nil input",
|
|
doppelGangerInput: nil,
|
|
doppelGangerExpectedOutput: ðpb.DoppelGangerResponse{
|
|
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
|
|
},
|
|
},
|
|
{
|
|
name: "nil validator requests",
|
|
doppelGangerInput: ðpb.DoppelGangerRequest{
|
|
ValidatorRequests: nil,
|
|
},
|
|
doppelGangerExpectedOutput: ðpb.DoppelGangerResponse{
|
|
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
|
|
},
|
|
},
|
|
{
|
|
name: "empty validator requests",
|
|
doppelGangerInput: ðpb.DoppelGangerRequest{
|
|
ValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{},
|
|
},
|
|
doppelGangerExpectedOutput: ðpb.DoppelGangerResponse{
|
|
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{},
|
|
},
|
|
},
|
|
{
|
|
name: "phase0",
|
|
doppelGangerInput: ðpb.DoppelGangerRequest{
|
|
ValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{
|
|
{PublicKey: pubKey1},
|
|
{PublicKey: pubKey2},
|
|
{PublicKey: pubKey3},
|
|
{PublicKey: pubKey4},
|
|
{PublicKey: pubKey5},
|
|
{PublicKey: pubKey6},
|
|
},
|
|
},
|
|
doppelGangerExpectedOutput: ðpb.DoppelGangerResponse{
|
|
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{
|
|
{PublicKey: pubKey1, DuplicateExists: false},
|
|
{PublicKey: pubKey2, DuplicateExists: false},
|
|
{PublicKey: pubKey3, DuplicateExists: false},
|
|
{PublicKey: pubKey4, DuplicateExists: false},
|
|
{PublicKey: pubKey5, DuplicateExists: false},
|
|
{PublicKey: pubKey6, DuplicateExists: false},
|
|
},
|
|
},
|
|
getSyncingOutput: &apimiddleware.SyncingResponseJson{
|
|
Data: &helpers.SyncDetailsJson{
|
|
IsSyncing: false,
|
|
},
|
|
},
|
|
getForkOutput: &apimiddleware.StateForkResponseJson{
|
|
Data: &apimiddleware.ForkJson{
|
|
PreviousVersion: "0x00000000",
|
|
CurrentVersion: "0x00000000",
|
|
Epoch: "42",
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "all validators are recent",
|
|
doppelGangerInput: ðpb.DoppelGangerRequest{
|
|
ValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{
|
|
{PublicKey: pubKey1, Epoch: 2},
|
|
{PublicKey: pubKey2, Epoch: 2},
|
|
{PublicKey: pubKey3, Epoch: 2},
|
|
{PublicKey: pubKey4, Epoch: 2},
|
|
{PublicKey: pubKey5, Epoch: 2},
|
|
{PublicKey: pubKey6, Epoch: 2},
|
|
},
|
|
},
|
|
doppelGangerExpectedOutput: ðpb.DoppelGangerResponse{
|
|
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{
|
|
{PublicKey: pubKey1, DuplicateExists: false},
|
|
{PublicKey: pubKey2, DuplicateExists: false},
|
|
{PublicKey: pubKey3, DuplicateExists: false},
|
|
{PublicKey: pubKey4, DuplicateExists: false},
|
|
{PublicKey: pubKey5, DuplicateExists: false},
|
|
{PublicKey: pubKey6, DuplicateExists: false},
|
|
},
|
|
},
|
|
getSyncingOutput: &apimiddleware.SyncingResponseJson{
|
|
Data: &helpers.SyncDetailsJson{
|
|
IsSyncing: false,
|
|
},
|
|
},
|
|
getForkOutput: &apimiddleware.StateForkResponseJson{
|
|
Data: &apimiddleware.ForkJson{
|
|
PreviousVersion: "0x01000000",
|
|
CurrentVersion: "0x02000000",
|
|
Epoch: "2",
|
|
},
|
|
},
|
|
getHeadersOutput: &apimiddleware.BlockHeadersResponseJson{
|
|
Data: []*apimiddleware.BlockHeaderContainerJson{
|
|
{
|
|
Header: &apimiddleware.BeaconBlockHeaderContainerJson{
|
|
Message: &apimiddleware.BeaconBlockHeaderJson{
|
|
Slot: "99",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "some validators are recent, some not, some duplicates",
|
|
doppelGangerInput: ðpb.DoppelGangerRequest{
|
|
ValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{
|
|
{PublicKey: pubKey1, Epoch: 99}, // recent
|
|
{PublicKey: pubKey2, Epoch: 80}, // not recent - duplicate on previous epoch
|
|
{PublicKey: pubKey3, Epoch: 80}, // not recent - duplicate on current epoch
|
|
{PublicKey: pubKey4, Epoch: 80}, // not recent - duplicate on both previous and current epoch
|
|
{PublicKey: pubKey5, Epoch: 80}, // non existing validator
|
|
{PublicKey: pubKey6, Epoch: 80}, // not recent - not duplicate
|
|
},
|
|
},
|
|
doppelGangerExpectedOutput: ðpb.DoppelGangerResponse{
|
|
Responses: []*ethpb.DoppelGangerResponse_ValidatorResponse{
|
|
{PublicKey: pubKey1, DuplicateExists: false}, // recent
|
|
{PublicKey: pubKey2, DuplicateExists: true}, // not recent - duplicate on previous epoch
|
|
{PublicKey: pubKey3, DuplicateExists: true}, // not recent - duplicate on current epoch
|
|
{PublicKey: pubKey4, DuplicateExists: true}, // not recent - duplicate on both previous and current epoch
|
|
{PublicKey: pubKey5, DuplicateExists: false}, // non existing validator
|
|
{PublicKey: pubKey6, DuplicateExists: false}, // not recent - not duplicate
|
|
},
|
|
},
|
|
getSyncingOutput: &apimiddleware.SyncingResponseJson{
|
|
Data: &helpers.SyncDetailsJson{
|
|
IsSyncing: false,
|
|
},
|
|
},
|
|
getForkOutput: &apimiddleware.StateForkResponseJson{
|
|
Data: &apimiddleware.ForkJson{
|
|
PreviousVersion: "0x01000000",
|
|
CurrentVersion: "0x02000000",
|
|
Epoch: "2",
|
|
},
|
|
},
|
|
getHeadersOutput: &apimiddleware.BlockHeadersResponseJson{
|
|
Data: []*apimiddleware.BlockHeaderContainerJson{
|
|
{
|
|
Header: &apimiddleware.BeaconBlockHeaderContainerJson{
|
|
Message: &apimiddleware.BeaconBlockHeaderJson{
|
|
Slot: "3201",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
getStateValidatorsInterface: &struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
}{
|
|
input: []string{
|
|
// no stringPubKey1 since recent
|
|
stringPubKey2, // not recent - duplicate on previous epoch
|
|
stringPubKey3, // not recent - duplicate on current epoch
|
|
stringPubKey4, // not recent - duplicate on both previous and current epoch
|
|
stringPubKey5, // non existing validator
|
|
stringPubKey6, // not recent - not duplicate
|
|
},
|
|
output: &apimiddleware.StateValidatorsResponseJson{
|
|
Data: []*apimiddleware.ValidatorContainerJson{
|
|
// No "11111" since corresponding validator is recent
|
|
{Index: "22222", Validator: &apimiddleware.ValidatorJson{PublicKey: stringPubKey2}}, // not recent - duplicate on previous epoch
|
|
{Index: "33333", Validator: &apimiddleware.ValidatorJson{PublicKey: stringPubKey3}}, // not recent - duplicate on current epoch
|
|
{Index: "44444", Validator: &apimiddleware.ValidatorJson{PublicKey: stringPubKey4}}, // not recent - duplicate on both previous and current epoch
|
|
// No "55555" sicee corresponding validator does not exist
|
|
{Index: "66666", Validator: &apimiddleware.ValidatorJson{PublicKey: stringPubKey6}}, // not recent - not duplicate
|
|
},
|
|
},
|
|
},
|
|
getLivelinessInterfaces: []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
}{
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/99", // previous epoch
|
|
inputStringIndexes: []string{
|
|
// No "11111" since corresponding validator is recent
|
|
"22222", // not recent - duplicate on previous epoch
|
|
"33333", // not recent - duplicate on current epoch
|
|
"44444", // not recent - duplicate on both previous and current epoch
|
|
// No "55555" since corresponding validator it does not exist
|
|
"66666", // not recent - not duplicate
|
|
},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{
|
|
// No "11111" since corresponding validator is recent
|
|
{Index: "22222", IsLive: true}, // not recent - duplicate on previous epoch
|
|
{Index: "33333", IsLive: false}, // not recent - duplicate on current epoch
|
|
{Index: "44444", IsLive: true}, // not recent - duplicate on both previous and current epoch
|
|
// No "55555" since corresponding validator it does not exist
|
|
{Index: "66666", IsLive: false}, // not recent - not duplicate
|
|
},
|
|
},
|
|
},
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/100", // current epoch
|
|
inputStringIndexes: []string{
|
|
// No "11111" since corresponding validator is recent
|
|
"22222", // not recent - duplicate on previous epoch
|
|
"33333", // not recent - duplicate on current epoch
|
|
"44444", // not recent - duplicate on both previous and current epoch
|
|
// No "55555" since corresponding validator it does not exist
|
|
"66666", // not recent - not duplicate
|
|
},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{
|
|
// No "11111" since corresponding validator is recent
|
|
{Index: "22222", IsLive: false}, // not recent - duplicate on previous epoch
|
|
{Index: "33333", IsLive: true}, // not recent - duplicate on current epoch
|
|
{Index: "44444", IsLive: true}, // not recent - duplicate on both previous and current epoch
|
|
// No "55555" since corresponding validator it does not exist
|
|
{Index: "66666", IsLive: false}, // not recent - not duplicate
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
defer ctrl.Finish()
|
|
|
|
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
|
|
|
ctx := context.Background()
|
|
|
|
if testCase.getSyncingOutput != nil {
|
|
syncingResponseJson := apimiddleware.SyncingResponseJson{}
|
|
|
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
|
ctx,
|
|
syncingEnpoint,
|
|
&syncingResponseJson,
|
|
).Return(
|
|
nil,
|
|
nil,
|
|
).SetArg(
|
|
2,
|
|
*testCase.getSyncingOutput,
|
|
).Times(1)
|
|
}
|
|
|
|
if testCase.getForkOutput != nil {
|
|
stateForkResponseJson := apimiddleware.StateForkResponseJson{}
|
|
|
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
|
ctx,
|
|
forkEndpoint,
|
|
&stateForkResponseJson,
|
|
).Return(
|
|
nil,
|
|
nil,
|
|
).SetArg(
|
|
2,
|
|
*testCase.getForkOutput,
|
|
).Times(1)
|
|
}
|
|
|
|
if testCase.getHeadersOutput != nil {
|
|
blockHeadersResponseJson := apimiddleware.BlockHeadersResponseJson{}
|
|
|
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
|
ctx,
|
|
headersEndpoint,
|
|
&blockHeadersResponseJson,
|
|
).Return(
|
|
nil,
|
|
nil,
|
|
).SetArg(
|
|
2,
|
|
*testCase.getHeadersOutput,
|
|
).Times(1)
|
|
}
|
|
|
|
if testCase.getLivelinessInterfaces != nil {
|
|
for _, iface := range testCase.getLivelinessInterfaces {
|
|
livenessResponseJson := apimiddleware.LivenessResponseJson{}
|
|
|
|
marshalledIndexes, err := json.Marshal(iface.inputStringIndexes)
|
|
require.NoError(t, err)
|
|
|
|
jsonRestHandler.EXPECT().PostRestJson(
|
|
ctx,
|
|
iface.inputUrl,
|
|
nil,
|
|
bytes.NewBuffer(marshalledIndexes),
|
|
&livenessResponseJson,
|
|
).SetArg(
|
|
4,
|
|
*iface.output,
|
|
).Return(
|
|
nil,
|
|
nil,
|
|
).Times(1)
|
|
}
|
|
}
|
|
|
|
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
|
|
|
if testCase.getStateValidatorsInterface != nil {
|
|
stateValidatorsProvider.EXPECT().GetStateValidators(
|
|
ctx,
|
|
testCase.getStateValidatorsInterface.input,
|
|
nil,
|
|
nil,
|
|
).Return(
|
|
testCase.getStateValidatorsInterface.output,
|
|
nil,
|
|
).Times(1)
|
|
}
|
|
|
|
validatorClient := beaconApiValidatorClient{
|
|
jsonRestHandler: jsonRestHandler,
|
|
stateValidatorsProvider: stateValidatorsProvider,
|
|
}
|
|
|
|
doppelGangerActualOutput, err := validatorClient.CheckDoppelGanger(
|
|
context.Background(),
|
|
testCase.doppelGangerInput,
|
|
)
|
|
|
|
require.DeepEqual(t, testCase.doppelGangerExpectedOutput, doppelGangerActualOutput)
|
|
assert.NoError(t, err)
|
|
})
|
|
}
|
|
}
|
|
|
|
func TestCheckDoppelGanger_Errors(t *testing.T) {
|
|
const stringPubKey = "0x80000e851c0f53c3246ff726d7ff7766661ca5e12a07c45c114d208d54f0f8233d4380b2e9aff759d69795d1df905526"
|
|
pubKey, err := hexutil.Decode(stringPubKey)
|
|
require.NoError(t, err)
|
|
|
|
standardInputValidatorRequests := []*ethpb.DoppelGangerRequest_ValidatorRequest{
|
|
{
|
|
PublicKey: pubKey,
|
|
Epoch: 1,
|
|
},
|
|
}
|
|
|
|
standardGetSyncingOutput := &apimiddleware.SyncingResponseJson{
|
|
Data: &helpers.SyncDetailsJson{
|
|
IsSyncing: false,
|
|
},
|
|
}
|
|
|
|
standardGetForkOutput := &apimiddleware.StateForkResponseJson{
|
|
Data: &apimiddleware.ForkJson{
|
|
CurrentVersion: "0x02000000",
|
|
},
|
|
}
|
|
|
|
standardGetHeadersOutput := &apimiddleware.BlockHeadersResponseJson{
|
|
Data: []*apimiddleware.BlockHeaderContainerJson{
|
|
{
|
|
Header: &apimiddleware.BeaconBlockHeaderContainerJson{
|
|
Message: &apimiddleware.BeaconBlockHeaderJson{
|
|
Slot: "1000",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
standardGetStateValidatorsInterface := &struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
err error
|
|
}{
|
|
input: []string{stringPubKey},
|
|
output: &apimiddleware.StateValidatorsResponseJson{
|
|
Data: []*apimiddleware.ValidatorContainerJson{
|
|
{
|
|
Index: "42",
|
|
Validator: &apimiddleware.ValidatorJson{
|
|
PublicKey: stringPubKey,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
testCases := []struct {
|
|
name string
|
|
expectedErrorMessage string
|
|
inputValidatorRequests []*ethpb.DoppelGangerRequest_ValidatorRequest
|
|
getSyncingOutput *apimiddleware.SyncingResponseJson
|
|
getSyncingError error
|
|
getForkOutput *apimiddleware.StateForkResponseJson
|
|
getForkError error
|
|
getHeadersOutput *apimiddleware.BlockHeadersResponseJson
|
|
getHeadersError error
|
|
getStateValidatorsInterface *struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
err error
|
|
}
|
|
getLivenessInterfaces []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
err error
|
|
}
|
|
}{
|
|
{
|
|
name: "nil validatorRequest",
|
|
expectedErrorMessage: "validator request is nil",
|
|
inputValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{nil},
|
|
},
|
|
{
|
|
name: "isSyncing on error",
|
|
expectedErrorMessage: "failed to get beacon node sync status",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getSyncingError: errors.New("custom error"),
|
|
},
|
|
{
|
|
name: "beacon node not synced",
|
|
expectedErrorMessage: "beacon node not synced",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: &apimiddleware.SyncingResponseJson{
|
|
Data: &helpers.SyncDetailsJson{
|
|
IsSyncing: true,
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "getFork on error",
|
|
expectedErrorMessage: "failed to get fork",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: &apimiddleware.StateForkResponseJson{},
|
|
getForkError: errors.New("custom error"),
|
|
},
|
|
{
|
|
name: "cannot decode fork version",
|
|
expectedErrorMessage: "failed to decode fork version",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: &apimiddleware.StateForkResponseJson{Data: &apimiddleware.ForkJson{CurrentVersion: "not a version"}},
|
|
},
|
|
{
|
|
name: "get headers on error",
|
|
expectedErrorMessage: "failed to get headers",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: &apimiddleware.BlockHeadersResponseJson{},
|
|
getHeadersError: errors.New("custom error"),
|
|
},
|
|
{
|
|
name: "cannot parse head slot",
|
|
expectedErrorMessage: "failed to parse head slot",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: &apimiddleware.BlockHeadersResponseJson{
|
|
Data: []*apimiddleware.BlockHeaderContainerJson{
|
|
{
|
|
Header: &apimiddleware.BeaconBlockHeaderContainerJson{
|
|
Message: &apimiddleware.BeaconBlockHeaderJson{
|
|
Slot: "not a slot",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "state validators error",
|
|
expectedErrorMessage: "failed to get state validators",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: &struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
err error
|
|
}{
|
|
input: []string{stringPubKey},
|
|
err: errors.New("custom error"),
|
|
},
|
|
},
|
|
{
|
|
name: "validator container is nil",
|
|
expectedErrorMessage: "validator container is nil",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: &struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
err error
|
|
}{
|
|
input: []string{stringPubKey},
|
|
output: &apimiddleware.StateValidatorsResponseJson{Data: []*apimiddleware.ValidatorContainerJson{nil}},
|
|
},
|
|
},
|
|
{
|
|
name: "validator is nil",
|
|
expectedErrorMessage: "validator is nil",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: &struct {
|
|
input []string
|
|
output *apimiddleware.StateValidatorsResponseJson
|
|
err error
|
|
}{
|
|
input: []string{stringPubKey},
|
|
output: &apimiddleware.StateValidatorsResponseJson{Data: []*apimiddleware.ValidatorContainerJson{{Validator: nil}}},
|
|
},
|
|
},
|
|
{
|
|
name: "previous epoch liveness error",
|
|
expectedErrorMessage: "failed to get map from validator index to liveness for previous epoch 30",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: standardGetStateValidatorsInterface,
|
|
getLivenessInterfaces: []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
err error
|
|
}{
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/30",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{},
|
|
err: errors.New("custom error"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "liveness is nil",
|
|
expectedErrorMessage: "liveness is nil",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: standardGetStateValidatorsInterface,
|
|
getLivenessInterfaces: []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
err error
|
|
}{
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/30",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{nil},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "current epoch liveness error",
|
|
expectedErrorMessage: "failed to get map from validator index to liveness for current epoch 31",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: standardGetStateValidatorsInterface,
|
|
getLivenessInterfaces: []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
err error
|
|
}{
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/30",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{},
|
|
},
|
|
},
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/31",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{},
|
|
err: errors.New("custom error"),
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "wrong validator index for previous epoch",
|
|
expectedErrorMessage: "failed to retrieve liveness for previous epoch `30` for validator index `42`",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: standardGetStateValidatorsInterface,
|
|
getLivenessInterfaces: []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
err error
|
|
}{
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/30",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{},
|
|
},
|
|
},
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/31",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
name: "wrong validator index for current epoch",
|
|
expectedErrorMessage: "failed to retrieve liveness for current epoch `31` for validator index `42`",
|
|
inputValidatorRequests: standardInputValidatorRequests,
|
|
getSyncingOutput: standardGetSyncingOutput,
|
|
getForkOutput: standardGetForkOutput,
|
|
getHeadersOutput: standardGetHeadersOutput,
|
|
getStateValidatorsInterface: standardGetStateValidatorsInterface,
|
|
getLivenessInterfaces: []struct {
|
|
inputUrl string
|
|
inputStringIndexes []string
|
|
output *apimiddleware.LivenessResponseJson
|
|
err error
|
|
}{
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/30",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{
|
|
{
|
|
Index: "42",
|
|
},
|
|
},
|
|
},
|
|
},
|
|
{
|
|
inputUrl: "/eth/v1/validator/liveness/31",
|
|
inputStringIndexes: []string{"42"},
|
|
output: &apimiddleware.LivenessResponseJson{
|
|
Data: []*struct {
|
|
Index string `json:"index"`
|
|
IsLive bool `json:"is_live"`
|
|
}{},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
|
|
for _, testCase := range testCases {
|
|
t.Run(testCase.name, func(t *testing.T) {
|
|
ctrl := gomock.NewController(t)
|
|
defer ctrl.Finish()
|
|
|
|
jsonRestHandler := mock.NewMockjsonRestHandler(ctrl)
|
|
|
|
ctx := context.Background()
|
|
|
|
if testCase.getSyncingOutput != nil {
|
|
syncingResponseJson := apimiddleware.SyncingResponseJson{}
|
|
|
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
|
ctx,
|
|
syncingEnpoint,
|
|
&syncingResponseJson,
|
|
).Return(
|
|
nil,
|
|
testCase.getSyncingError,
|
|
).SetArg(
|
|
2,
|
|
*testCase.getSyncingOutput,
|
|
).Times(1)
|
|
}
|
|
|
|
if testCase.getForkOutput != nil {
|
|
stateForkResponseJson := apimiddleware.StateForkResponseJson{}
|
|
|
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
|
ctx,
|
|
forkEndpoint,
|
|
&stateForkResponseJson,
|
|
).Return(
|
|
nil,
|
|
testCase.getForkError,
|
|
).SetArg(
|
|
2,
|
|
*testCase.getForkOutput,
|
|
).Times(1)
|
|
}
|
|
|
|
if testCase.getHeadersOutput != nil {
|
|
blockHeadersResponseJson := apimiddleware.BlockHeadersResponseJson{}
|
|
|
|
jsonRestHandler.EXPECT().GetRestJsonResponse(
|
|
ctx,
|
|
headersEndpoint,
|
|
&blockHeadersResponseJson,
|
|
).Return(
|
|
nil,
|
|
testCase.getHeadersError,
|
|
).SetArg(
|
|
2,
|
|
*testCase.getHeadersOutput,
|
|
).Times(1)
|
|
}
|
|
|
|
stateValidatorsProvider := mock.NewMockstateValidatorsProvider(ctrl)
|
|
|
|
if testCase.getStateValidatorsInterface != nil {
|
|
stateValidatorsProvider.EXPECT().GetStateValidators(
|
|
ctx,
|
|
testCase.getStateValidatorsInterface.input,
|
|
nil,
|
|
nil,
|
|
).Return(
|
|
testCase.getStateValidatorsInterface.output,
|
|
testCase.getStateValidatorsInterface.err,
|
|
).Times(1)
|
|
}
|
|
|
|
if testCase.getLivenessInterfaces != nil {
|
|
for _, iface := range testCase.getLivenessInterfaces {
|
|
livenessResponseJson := apimiddleware.LivenessResponseJson{}
|
|
|
|
marshalledIndexes, err := json.Marshal(iface.inputStringIndexes)
|
|
require.NoError(t, err)
|
|
|
|
jsonRestHandler.EXPECT().PostRestJson(
|
|
ctx,
|
|
iface.inputUrl,
|
|
nil,
|
|
bytes.NewBuffer(marshalledIndexes),
|
|
&livenessResponseJson,
|
|
).SetArg(
|
|
4,
|
|
*iface.output,
|
|
).Return(
|
|
nil,
|
|
iface.err,
|
|
).Times(1)
|
|
}
|
|
}
|
|
|
|
validatorClient := beaconApiValidatorClient{
|
|
jsonRestHandler: jsonRestHandler,
|
|
stateValidatorsProvider: stateValidatorsProvider,
|
|
}
|
|
|
|
_, err := validatorClient.CheckDoppelGanger(
|
|
context.Background(),
|
|
ðpb.DoppelGangerRequest{
|
|
ValidatorRequests: testCase.inputValidatorRequests,
|
|
},
|
|
)
|
|
|
|
require.ErrorContains(t, testCase.expectedErrorMessage, err)
|
|
})
|
|
}
|
|
}
|