mirror of
https://gitlab.com/pulsechaincom/prysm-pulse.git
synced 2024-12-22 03:30:35 +00:00
Validator Changes for Optimized Slasher (#9705)
* val changes * mock * mocks * gomock any * gaz Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
This commit is contained in:
parent
520bc9d955
commit
13cdb83591
@ -21,7 +21,7 @@ go_library(
|
||||
"//testing/fuzz:__pkg__",
|
||||
"//testing/spectest:__subpackages__",
|
||||
"//testing/util:__pkg__",
|
||||
"//validator/accounts:__pkg__",
|
||||
"//validator:__subpackages__",
|
||||
],
|
||||
deps = [
|
||||
"//beacon-chain/core:go_default_library",
|
||||
|
@ -3,12 +3,13 @@
|
||||
# Script to update mock files after proto/prysm/v1alpha1/services.proto changes.
|
||||
# Use a space to separate mock destination from its interfaces.
|
||||
|
||||
mock_path="shared/mock"
|
||||
mock_path="testing/mock"
|
||||
mocks=(
|
||||
"$mock_path/beacon_service_mock.go BeaconChainClient,BeaconChain_StreamChainHeadClient,BeaconChain_StreamAttestationsClient,BeaconChain_StreamBlocksClient,BeaconChain_StreamValidatorsInfoClient,BeaconChain_StreamIndexedAttestationsClient"
|
||||
"$mock_path/beacon_chain_service_mock.go BeaconChain_StreamChainHeadServer,BeaconChain_StreamAttestationsServer,BeaconChain_StreamBlocksServer,BeaconChain_StreamValidatorsInfoServer,BeaconChain_StreamIndexedAttestationsServer"
|
||||
"$mock_path/beacon_validator_server_mock.go BeaconNodeValidatorServer,BeaconNodeValidator_WaitForActivationServer,BeaconNodeValidator_WaitForChainStartServer,BeaconNodeValidator_StreamDutiesServer"
|
||||
"$mock_path/beacon_validator_client_mock.go BeaconNodeValidatorClient,BeaconNodeValidator_WaitForChainStartClient,BeaconNodeValidator_WaitForActivationClient,BeaconNodeValidator_StreamDutiesClient"
|
||||
"$mock_path/slasher_client_mock.go SlasherClient"
|
||||
"$mock_path/event_service_mock.go EventsClient,Events_StreamEventsClient,Events_StreamEventsServer"
|
||||
"$mock_path/node_service_mock.go NodeClient"
|
||||
"$mock_path/keymanager_mock.go RemoteSignerClient"
|
||||
@ -19,8 +20,8 @@ for ((i = 0; i < ${#mocks[@]}; i++)); do
|
||||
interfaces=${mocks[i]#* };
|
||||
echo "generating $file for interfaces: $interfaces";
|
||||
GO11MODULE=on mockgen -package=mock -destination="$file" github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1 "$interfaces"
|
||||
GO11MODULE=on mockgen -package=mock -destination="$file" github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1 "$interfaces"
|
||||
done
|
||||
|
||||
goimports -w "$mock_path/."
|
||||
gofmt -s -w "$mock_path/."
|
||||
|
||||
|
@ -16,6 +16,7 @@ go_library(
|
||||
"event_service_mock.go",
|
||||
"keymanager_mock.go",
|
||||
"node_service_mock.go",
|
||||
"slasher_client_mock.go",
|
||||
],
|
||||
importpath = "github.com/prysmaticlabs/prysm/testing/mock",
|
||||
visibility = ["//visibility:public"],
|
||||
|
97
testing/mock/slasher_client_mock.go
generated
Normal file
97
testing/mock/slasher_client_mock.go
generated
Normal file
@ -0,0 +1,97 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1 (interfaces: SlasherClient)
|
||||
|
||||
// Package mock is a generated GoMock package.
|
||||
package mock
|
||||
|
||||
import (
|
||||
context "context"
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
eth "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
grpc "google.golang.org/grpc"
|
||||
)
|
||||
|
||||
// MockSlasherClient is a mock of SlasherClient interface.
|
||||
type MockSlasherClient struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockSlasherClientMockRecorder
|
||||
}
|
||||
|
||||
// MockSlasherClientMockRecorder is the mock recorder for MockSlasherClient.
|
||||
type MockSlasherClientMockRecorder struct {
|
||||
mock *MockSlasherClient
|
||||
}
|
||||
|
||||
// NewMockSlasherClient creates a new mock instance.
|
||||
func NewMockSlasherClient(ctrl *gomock.Controller) *MockSlasherClient {
|
||||
mock := &MockSlasherClient{ctrl: ctrl}
|
||||
mock.recorder = &MockSlasherClientMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockSlasherClient) EXPECT() *MockSlasherClientMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// HighestAttestations mocks base method.
|
||||
func (m *MockSlasherClient) HighestAttestations(arg0 context.Context, arg1 *eth.HighestAttestationRequest, arg2 ...grpc.CallOption) (*eth.HighestAttestationResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "HighestAttestations", varargs...)
|
||||
ret0, _ := ret[0].(*eth.HighestAttestationResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// HighestAttestations indicates an expected call of HighestAttestations.
|
||||
func (mr *MockSlasherClientMockRecorder) HighestAttestations(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HighestAttestations", reflect.TypeOf((*MockSlasherClient)(nil).HighestAttestations), varargs...)
|
||||
}
|
||||
|
||||
// IsSlashableAttestation mocks base method.
|
||||
func (m *MockSlasherClient) IsSlashableAttestation(arg0 context.Context, arg1 *eth.IndexedAttestation, arg2 ...grpc.CallOption) (*eth.AttesterSlashingResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "IsSlashableAttestation", varargs...)
|
||||
ret0, _ := ret[0].(*eth.AttesterSlashingResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// IsSlashableAttestation indicates an expected call of IsSlashableAttestation.
|
||||
func (mr *MockSlasherClientMockRecorder) IsSlashableAttestation(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSlashableAttestation", reflect.TypeOf((*MockSlasherClient)(nil).IsSlashableAttestation), varargs...)
|
||||
}
|
||||
|
||||
// IsSlashableBlock mocks base method.
|
||||
func (m *MockSlasherClient) IsSlashableBlock(arg0 context.Context, arg1 *eth.SignedBeaconBlockHeader, arg2 ...grpc.CallOption) (*eth.ProposerSlashingResponse, error) {
|
||||
m.ctrl.T.Helper()
|
||||
varargs := []interface{}{arg0, arg1}
|
||||
for _, a := range arg2 {
|
||||
varargs = append(varargs, a)
|
||||
}
|
||||
ret := m.ctrl.Call(m, "IsSlashableBlock", varargs...)
|
||||
ret0, _ := ret[0].(*eth.ProposerSlashingResponse)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// IsSlashableBlock indicates an expected call of IsSlashableBlock.
|
||||
func (mr *MockSlasherClientMockRecorder) IsSlashableBlock(arg0, arg1 interface{}, arg2 ...interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
varargs := append([]interface{}{arg0, arg1}, arg2...)
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "IsSlashableBlock", reflect.TypeOf((*MockSlasherClient)(nil).IsSlashableBlock), varargs...)
|
||||
}
|
@ -53,7 +53,6 @@ go_library(
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/imported:go_default_library",
|
||||
"//validator/keymanager/remote:go_default_library",
|
||||
"//validator/slashing-protection/iface:go_default_library",
|
||||
"@com_github_dgraph_io_ristretto//:go_default_library",
|
||||
"@com_github_ferranbt_fastssz//:go_default_library",
|
||||
"@com_github_grpc_ecosystem_go_grpc_middleware//:go_default_library",
|
||||
@ -113,6 +112,7 @@ go_test(
|
||||
"//encoding/bytesutil:go_default_library",
|
||||
"//io/file:go_default_library",
|
||||
"//proto/prysm/v1alpha1:go_default_library",
|
||||
"//proto/prysm/v1alpha1/block:go_default_library",
|
||||
"//proto/prysm/v1alpha1/validator-client:go_default_library",
|
||||
"//proto/prysm/v1alpha1/wrapper:go_default_library",
|
||||
"//runtime:go_default_library",
|
||||
|
@ -81,8 +81,12 @@ func (v *validator) slashableAttestationCheck(
|
||||
return errors.Wrap(err, "could not save attestation history for validator public key")
|
||||
}
|
||||
|
||||
if features.Get().RemoteSlasherProtection && v.protector != nil {
|
||||
if !v.protector.CheckAttestationSafety(ctx, indexedAtt) {
|
||||
if features.Get().RemoteSlasherProtection {
|
||||
slashing, err := v.slashingProtectionClient.IsSlashableAttestation(ctx, indexedAtt)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not check if attestation is slashable")
|
||||
}
|
||||
if slashing != nil && len(slashing.AttesterSlashings) > 0 {
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorAttestFailVecSlasher.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
|
@ -10,7 +10,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
mockSlasher "github.com/prysmaticlabs/prysm/validator/testing"
|
||||
)
|
||||
|
||||
func Test_slashableAttestationCheck(t *testing.T) {
|
||||
@ -19,7 +18,7 @@ func Test_slashableAttestationCheck(t *testing.T) {
|
||||
}
|
||||
reset := features.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
@ -39,11 +38,23 @@ func Test_slashableAttestationCheck(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
mockProtector := &mockSlasher.MockProtector{AllowAttestation: false}
|
||||
validator.protector = mockProtector
|
||||
|
||||
m.slasherClient.EXPECT().IsSlashableAttestation(
|
||||
gomock.Any(), // ctx
|
||||
att,
|
||||
).Return(ðpb.AttesterSlashingResponse{AttesterSlashings: []*ethpb.AttesterSlashing{{
|
||||
Attestation_1: ðpb.IndexedAttestation{},
|
||||
Attestation_2: ðpb.IndexedAttestation{},
|
||||
}}}, nil /*err*/)
|
||||
|
||||
err := validator.slashableAttestationCheck(context.Background(), att, pubKey, [32]byte{1})
|
||||
require.ErrorContains(t, failedPostAttSignExternalErr, err)
|
||||
mockProtector.AllowAttestation = true
|
||||
|
||||
m.slasherClient.EXPECT().IsSlashableAttestation(
|
||||
gomock.Any(), // ctx
|
||||
att,
|
||||
).Return(ðpb.AttesterSlashingResponse{}, nil /*err*/)
|
||||
|
||||
err = validator.slashableAttestationCheck(context.Background(), att, pubKey, [32]byte{1})
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
}
|
||||
@ -75,18 +86,23 @@ func Test_slashableAttestationCheck_UpdatesLowestSignedEpochs(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
mockProtector := &mockSlasher.MockProtector{AllowAttestation: false}
|
||||
validator.protector = mockProtector
|
||||
|
||||
m.slasherClient.EXPECT().IsSlashableAttestation(
|
||||
gomock.Any(), // ctx
|
||||
att,
|
||||
).Return(ðpb.AttesterSlashingResponse{}, nil /*err*/)
|
||||
|
||||
m.validatorClient.EXPECT().DomainData(
|
||||
gomock.Any(), // ctx
|
||||
ðpb.DomainRequest{Epoch: 10, Domain: []byte{1, 0, 0, 0}},
|
||||
).Return(ðpb.DomainResponse{SignatureDomain: make([]byte, 32)}, nil /*err*/)
|
||||
_, sr, err := validator.getDomainAndSigningRoot(ctx, att.Data)
|
||||
require.NoError(t, err)
|
||||
mockProtector.AllowAttestation = true
|
||||
|
||||
err = validator.slashableAttestationCheck(context.Background(), att, pubKey, sr)
|
||||
require.NoError(t, err)
|
||||
differentSigningRoot := [32]byte{2}
|
||||
|
||||
err = validator.slashableAttestationCheck(context.Background(), att, pubKey, differentSigningRoot)
|
||||
require.ErrorContains(t, "could not sign attestation", err)
|
||||
|
||||
@ -102,12 +118,12 @@ func Test_slashableAttestationCheck_UpdatesLowestSignedEpochs(t *testing.T) {
|
||||
|
||||
func Test_slashableAttestationCheck_OK(t *testing.T) {
|
||||
config := &features.Flags{
|
||||
RemoteSlasherProtection: false,
|
||||
RemoteSlasherProtection: true,
|
||||
}
|
||||
reset := features.InitWithReset(config)
|
||||
defer reset()
|
||||
ctx := context.Background()
|
||||
validator, _, _, finish := setup(t)
|
||||
validator, mocks, _, finish := setup(t)
|
||||
defer finish()
|
||||
att := ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2},
|
||||
@ -127,18 +143,24 @@ func Test_slashableAttestationCheck_OK(t *testing.T) {
|
||||
}
|
||||
sr := [32]byte{1}
|
||||
fakePubkey := bytesutil.ToBytes48([]byte("test"))
|
||||
|
||||
mocks.slasherClient.EXPECT().IsSlashableAttestation(
|
||||
gomock.Any(), // ctx
|
||||
att,
|
||||
).Return(ðpb.AttesterSlashingResponse{}, nil /*err*/)
|
||||
|
||||
err := validator.slashableAttestationCheck(ctx, att, fakePubkey, sr)
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
}
|
||||
|
||||
func Test_slashableAttestationCheck_GenesisEpoch(t *testing.T) {
|
||||
config := &features.Flags{
|
||||
RemoteSlasherProtection: false,
|
||||
RemoteSlasherProtection: true,
|
||||
}
|
||||
reset := features.InitWithReset(config)
|
||||
defer reset()
|
||||
ctx := context.Background()
|
||||
validator, _, _, finish := setup(t)
|
||||
validator, mocks, _, finish := setup(t)
|
||||
defer finish()
|
||||
att := ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{1, 2},
|
||||
@ -156,6 +178,12 @@ func Test_slashableAttestationCheck_GenesisEpoch(t *testing.T) {
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
mocks.slasherClient.EXPECT().IsSlashableAttestation(
|
||||
gomock.Any(), // ctx
|
||||
att,
|
||||
).Return(ðpb.AttesterSlashingResponse{}, nil /*err*/)
|
||||
|
||||
fakePubkey := bytesutil.ToBytes48([]byte("test"))
|
||||
err := validator.slashableAttestationCheck(ctx, att, fakePubkey, [32]byte{})
|
||||
require.NoError(t, err, "Expected allowed attestation not to throw error")
|
||||
|
@ -36,7 +36,6 @@ type Validator interface {
|
||||
WaitForChainStart(ctx context.Context) error
|
||||
WaitForSync(ctx context.Context) error
|
||||
WaitForActivation(ctx context.Context, accountsChangedChan chan [][48]byte) error
|
||||
SlasherReady(ctx context.Context) error
|
||||
CanonicalHeadSlot(ctx context.Context) (types.Slot, error)
|
||||
NextSlot() <-chan types.Slot
|
||||
SlotDeadline(slot types.Slot) time.Time
|
||||
|
@ -119,20 +119,13 @@ func (v *validator) proposeBlockPhase0(ctx context.Context, slot types.Slot, pub
|
||||
return
|
||||
}
|
||||
|
||||
if err := v.preBlockSignValidations(ctx, pubKey, wrapper.WrappedPhase0BeaconBlock(b), signingRoot); err != nil {
|
||||
if err := v.slashableProposalCheck(ctx, pubKey, wrapper.WrappedPhase0SignedBeaconBlock(blk), signingRoot); err != nil {
|
||||
log.WithFields(
|
||||
blockLogFields(pubKey, wrapper.WrappedPhase0BeaconBlock(b), nil),
|
||||
).WithError(err).Error("Failed block slashing protection check")
|
||||
return
|
||||
}
|
||||
|
||||
if err := v.postBlockSignUpdate(ctx, pubKey, wrapper.WrappedPhase0SignedBeaconBlock(blk), signingRoot); err != nil {
|
||||
log.WithFields(
|
||||
blockLogFields(pubKey, wrapper.WrappedPhase0BeaconBlock(b), sig),
|
||||
).WithError(err).Error("Failed block slashing protection check")
|
||||
return
|
||||
}
|
||||
|
||||
// Propose and broadcast block via beacon node
|
||||
blkResp, err := v.validatorClient.ProposeBlock(ctx, blk)
|
||||
if err != nil {
|
||||
@ -252,16 +245,6 @@ func (v *validator) proposeBlockAltair(ctx context.Context, slot types.Slot, pub
|
||||
return
|
||||
}
|
||||
|
||||
if err := v.preBlockSignValidations(ctx, pubKey, wb, signingRoot); err != nil {
|
||||
log.WithFields(
|
||||
blockLogFields(pubKey, wb, nil),
|
||||
).WithError(err).Error("Failed block slashing protection check")
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
wsb, err := wrapper.WrappedAltairSignedBeaconBlock(blk)
|
||||
if err != nil {
|
||||
log.WithError(err).Error("Failed to wrap signed block")
|
||||
@ -270,9 +253,10 @@ func (v *validator) proposeBlockAltair(ctx context.Context, slot types.Slot, pub
|
||||
}
|
||||
return
|
||||
}
|
||||
if err := v.postBlockSignUpdate(ctx, pubKey, wsb, signingRoot); err != nil {
|
||||
|
||||
if err := v.slashableProposalCheck(ctx, pubKey, wsb, signingRoot); err != nil {
|
||||
log.WithFields(
|
||||
blockLogFields(pubKey, wb, sig),
|
||||
blockLogFields(pubKey, wb, nil),
|
||||
).WithError(err).Error("Failed block slashing protection check")
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc()
|
||||
|
@ -11,15 +11,15 @@ import (
|
||||
"github.com/sirupsen/logrus"
|
||||
)
|
||||
|
||||
var failedPreBlockSignLocalErr = "attempted to sign a double proposal, block rejected by local protection"
|
||||
var failedPreBlockSignExternalErr = "attempted a double proposal, block rejected by remote slashing protection"
|
||||
var failedPostBlockSignErr = "made a double proposal, considered slashable by remote slashing protection"
|
||||
var failedBlockSignLocalErr = "attempted to sign a double proposal, block rejected by local protection"
|
||||
var failedBlockSignExternalErr = "attempted a double proposal, block rejected by remote slashing protection"
|
||||
|
||||
func (v *validator) preBlockSignValidations(
|
||||
ctx context.Context, pubKey [48]byte, blk block.BeaconBlock, signingRoot [32]byte,
|
||||
func (v *validator) slashableProposalCheck(
|
||||
ctx context.Context, pubKey [48]byte, signedBlock block.SignedBeaconBlock, signingRoot [32]byte,
|
||||
) error {
|
||||
fmtKey := fmt.Sprintf("%#x", pubKey[:])
|
||||
|
||||
blk := signedBlock.Block()
|
||||
prevSigningRoot, proposalAtSlotExists, err := v.db.ProposalHistoryForSlot(ctx, pubKey, blk.Slot())
|
||||
if err != nil {
|
||||
if v.emitAccountMetrics {
|
||||
@ -42,7 +42,7 @@ func (v *validator) preBlockSignValidations(
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
return errors.New(failedPreBlockSignLocalErr)
|
||||
return errors.New(failedBlockSignLocalErr)
|
||||
}
|
||||
|
||||
// Based on EIP3076, validator should refuse to sign any proposal with slot less
|
||||
@ -56,29 +56,24 @@ func (v *validator) preBlockSignValidations(
|
||||
blk.Slot(),
|
||||
)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (v *validator) postBlockSignUpdate(
|
||||
ctx context.Context,
|
||||
pubKey [48]byte,
|
||||
blk block.SignedBeaconBlock,
|
||||
signingRoot [32]byte,
|
||||
) error {
|
||||
fmtKey := fmt.Sprintf("%#x", pubKey[:])
|
||||
if features.Get().RemoteSlasherProtection && v.protector != nil {
|
||||
blockHdr, err := block.SignedBeaconBlockHeaderFromBlockInterface(blk)
|
||||
if features.Get().RemoteSlasherProtection {
|
||||
blockHdr, err := block.SignedBeaconBlockHeaderFromBlockInterface(signedBlock)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "failed to get block header from block")
|
||||
}
|
||||
if !v.protector.CheckBlockSafety(ctx, blockHdr) {
|
||||
slashing, err := v.slashingProtectionClient.IsSlashableBlock(ctx, blockHdr)
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not check if block is slashable")
|
||||
}
|
||||
if slashing != nil && len(slashing.ProposerSlashings) > 0 {
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVecSlasher.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
return errors.New(failedPostBlockSignErr)
|
||||
return errors.New(failedBlockSignExternalErr)
|
||||
}
|
||||
}
|
||||
if err := v.db.SaveProposalHistoryForSlot(ctx, pubKey, blk.Block().Slot(), signingRoot[:]); err != nil {
|
||||
if err := v.db.SaveProposalHistoryForSlot(ctx, pubKey, blk.Slot(), signingRoot[:]); err != nil {
|
||||
if v.emitAccountMetrics {
|
||||
ValidatorProposeFailVec.WithLabelValues(fmtKey).Inc()
|
||||
}
|
||||
|
@ -4,16 +4,18 @@ import (
|
||||
"context"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/block"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
mockSlasher "github.com/prysmaticlabs/prysm/validator/testing"
|
||||
)
|
||||
|
||||
func TestPreBlockSignLocalValidation_PreventsLowerThanMinProposal(t *testing.T) {
|
||||
func Test_slashableProposalCheck_PreventsLowerThanMinProposal(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
@ -28,55 +30,64 @@ func TestPreBlockSignLocalValidation_PreventsLowerThanMinProposal(t *testing.T)
|
||||
|
||||
// We expect the same block with a slot lower than the lowest
|
||||
// signed slot to fail validation.
|
||||
block := ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot - 1,
|
||||
ProposerIndex: 0,
|
||||
block := ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot - 1,
|
||||
ProposerIndex: 0,
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
}
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{4})
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKeyBytes, wrapper.WrappedPhase0SignedBeaconBlock(block), [32]byte{4})
|
||||
require.ErrorContains(t, "could not sign block with slot <= lowest signed", err)
|
||||
|
||||
// We expect the same block with a slot equal to the lowest
|
||||
// signed slot to pass validation if signing roots are equal.
|
||||
block = ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot,
|
||||
ProposerIndex: 0,
|
||||
block = ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot,
|
||||
ProposerIndex: 0,
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
}
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{1})
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKeyBytes, wrapper.WrappedPhase0SignedBeaconBlock(block), [32]byte{1})
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the same block with a slot equal to the lowest
|
||||
// signed slot to fail validation if signing roots are different.
|
||||
block = ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot,
|
||||
ProposerIndex: 0,
|
||||
}
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{4})
|
||||
require.ErrorContains(t, failedPreBlockSignLocalErr, err)
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKeyBytes, wrapper.WrappedPhase0SignedBeaconBlock(block), [32]byte{4})
|
||||
require.ErrorContains(t, failedBlockSignLocalErr, err)
|
||||
|
||||
// We expect the same block with a slot > than the lowest
|
||||
// signed slot to pass validation.
|
||||
block = ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot + 1,
|
||||
ProposerIndex: 0,
|
||||
block = ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
Slot: lowestSignedSlot + 1,
|
||||
ProposerIndex: 0,
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
}
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKeyBytes, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{3})
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKeyBytes, wrapper.WrappedPhase0SignedBeaconBlock(block), [32]byte{3})
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestPreBlockSignLocalValidation(t *testing.T) {
|
||||
func Test_slashableProposalCheck(t *testing.T) {
|
||||
ctx := context.Background()
|
||||
config := &features.Flags{
|
||||
RemoteSlasherProtection: false,
|
||||
RemoteSlasherProtection: true,
|
||||
}
|
||||
reset := features.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
validator, mocks, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
|
||||
block := ðpb.BeaconBlock{
|
||||
Slot: 10,
|
||||
ProposerIndex: 0,
|
||||
}
|
||||
blk := util.HydrateSignedBeaconBlock(ðpb.SignedBeaconBlock{
|
||||
Block: ðpb.BeaconBlock{
|
||||
Slot: 10,
|
||||
ProposerIndex: 0,
|
||||
},
|
||||
Signature: params.BeaconConfig().EmptySignature[:],
|
||||
})
|
||||
|
||||
pubKeyBytes := [48]byte{}
|
||||
copy(pubKeyBytes[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
@ -90,65 +101,77 @@ func TestPreBlockSignLocalValidation(t *testing.T) {
|
||||
require.NoError(t, err)
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
sBlock := wrapper.WrappedPhase0SignedBeaconBlock(blk)
|
||||
blockHdr, err := block.SignedBeaconBlockHeaderFromBlockInterface(sBlock)
|
||||
require.NoError(t, err)
|
||||
|
||||
mocks.slasherClient.EXPECT().IsSlashableBlock(
|
||||
gomock.Any(), // ctx
|
||||
blockHdr,
|
||||
).Return(ðpb.ProposerSlashingResponse{}, nil /*err*/)
|
||||
|
||||
// We expect the same block sent out with the same root should not be slasahble.
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKey, wrapper.WrappedPhase0BeaconBlock(block), dummySigningRoot)
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKey, sBlock, dummySigningRoot)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the same block sent out with a different signing root should be slasahble.
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKey, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{2})
|
||||
require.ErrorContains(t, failedPreBlockSignLocalErr, err)
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKey, sBlock, [32]byte{2})
|
||||
require.ErrorContains(t, failedBlockSignLocalErr, err)
|
||||
|
||||
// We save a proposal at slot 11 with a nil signing root.
|
||||
block.Slot = 11
|
||||
err = validator.db.SaveProposalHistoryForSlot(ctx, pubKeyBytes, block.Slot, nil)
|
||||
blk.Block.Slot = 11
|
||||
sBlock = wrapper.WrappedPhase0SignedBeaconBlock(blk)
|
||||
err = validator.db.SaveProposalHistoryForSlot(ctx, pubKeyBytes, blk.Block.Slot, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// We expect the same block sent out should return slashable error even
|
||||
// if we had a nil signing root stored in the database.
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKey, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{2})
|
||||
require.ErrorContains(t, failedPreBlockSignLocalErr, err)
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKey, sBlock, [32]byte{2})
|
||||
require.ErrorContains(t, failedBlockSignLocalErr, err)
|
||||
|
||||
// A block with a different slot for which we do not have a proposing history
|
||||
// should not be failing validation.
|
||||
block.Slot = 9
|
||||
err = validator.preBlockSignValidations(context.Background(), pubKey, wrapper.WrappedPhase0BeaconBlock(block), [32]byte{3})
|
||||
blk.Block.Slot = 9
|
||||
sBlock = wrapper.WrappedPhase0SignedBeaconBlock(blk)
|
||||
blockHdr, err = block.SignedBeaconBlockHeaderFromBlockInterface(sBlock)
|
||||
require.NoError(t, err)
|
||||
mocks.slasherClient.EXPECT().IsSlashableBlock(
|
||||
gomock.Any(), // ctx
|
||||
blockHdr,
|
||||
).Return(ðpb.ProposerSlashingResponse{}, nil /*err*/)
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKey, sBlock, [32]byte{3})
|
||||
require.NoError(t, err, "Expected allowed block not to throw error")
|
||||
}
|
||||
|
||||
func TestPreBlockSignValidation(t *testing.T) {
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
|
||||
block := util.NewBeaconBlock()
|
||||
block.Block.Slot = 10
|
||||
mockProtector := &mockSlasher.MockProtector{AllowBlock: false}
|
||||
validator.protector = mockProtector
|
||||
mockProtector.AllowBlock = true
|
||||
err := validator.preBlockSignValidations(context.Background(), pubKey, wrapper.WrappedPhase0BeaconBlock(block.Block), [32]byte{2})
|
||||
require.NoError(t, err, "Expected allowed block not to throw error")
|
||||
}
|
||||
|
||||
func TestPostBlockSignUpdate(t *testing.T) {
|
||||
func Test_slashableProposalCheck_RemoteProtection(t *testing.T) {
|
||||
config := &features.Flags{
|
||||
RemoteSlasherProtection: true,
|
||||
}
|
||||
reset := features.InitWithReset(config)
|
||||
defer reset()
|
||||
validator, _, validatorKey, finish := setup(t)
|
||||
validator, m, validatorKey, finish := setup(t)
|
||||
defer finish()
|
||||
pubKey := [48]byte{}
|
||||
copy(pubKey[:], validatorKey.PublicKey().Marshal())
|
||||
emptyBlock := util.NewBeaconBlock()
|
||||
emptyBlock.Block.Slot = 10
|
||||
emptyBlock.Block.ProposerIndex = 0
|
||||
mockProtector := &mockSlasher.MockProtector{AllowBlock: false}
|
||||
validator.protector = mockProtector
|
||||
err := validator.postBlockSignUpdate(context.Background(), pubKey, wrapper.WrappedPhase0SignedBeaconBlock(emptyBlock), [32]byte{})
|
||||
require.ErrorContains(t, failedPostBlockSignErr, err, "Expected error when post signature update is detected as slashable")
|
||||
mockProtector.AllowBlock = true
|
||||
err = validator.postBlockSignUpdate(context.Background(), pubKey, wrapper.WrappedPhase0SignedBeaconBlock(emptyBlock), [32]byte{})
|
||||
|
||||
blk := util.NewBeaconBlock()
|
||||
blk.Block.Slot = 10
|
||||
sBlock := wrapper.WrappedPhase0SignedBeaconBlock(blk)
|
||||
blockHdr, err := block.SignedBeaconBlockHeaderFromBlockInterface(sBlock)
|
||||
require.NoError(t, err)
|
||||
m.slasherClient.EXPECT().IsSlashableBlock(
|
||||
gomock.Any(), // ctx
|
||||
blockHdr,
|
||||
).Return(ðpb.ProposerSlashingResponse{ProposerSlashings: []*ethpb.ProposerSlashing{{}}}, nil /*err*/)
|
||||
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKey, sBlock, [32]byte{2})
|
||||
require.ErrorContains(t, failedBlockSignExternalErr, err)
|
||||
|
||||
m.slasherClient.EXPECT().IsSlashableBlock(
|
||||
gomock.Any(), // ctx
|
||||
blockHdr,
|
||||
).Return(ðpb.ProposerSlashingResponse{}, nil /*err*/)
|
||||
|
||||
err = validator.slashableProposalCheck(context.Background(), pubKey, sBlock, [32]byte{2})
|
||||
require.NoError(t, err, "Expected allowed block not to throw error")
|
||||
}
|
||||
|
@ -18,7 +18,7 @@ import (
|
||||
validatorpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/validator-client"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
mock2 "github.com/prysmaticlabs/prysm/testing/mock"
|
||||
mock "github.com/prysmaticlabs/prysm/testing/mock"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/testing/util"
|
||||
testing2 "github.com/prysmaticlabs/prysm/validator/db/testing"
|
||||
@ -29,8 +29,9 @@ import (
|
||||
)
|
||||
|
||||
type mocks struct {
|
||||
validatorClient *mock2.MockBeaconNodeValidatorClient
|
||||
nodeClient *mock2.MockNodeClient
|
||||
validatorClient *mock.MockBeaconNodeValidatorClient
|
||||
nodeClient *mock.MockNodeClient
|
||||
slasherClient *mock.MockSlasherClient
|
||||
signExitFunc func(context.Context, *validatorpb.SignRequest) (bls.Signature, error)
|
||||
}
|
||||
|
||||
@ -67,8 +68,9 @@ func setupWithKey(t *testing.T, validatorKey bls.SecretKey) (*validator, *mocks,
|
||||
valDB := testing2.SetupDB(t, [][48]byte{pubKey})
|
||||
ctrl := gomock.NewController(t)
|
||||
m := &mocks{
|
||||
validatorClient: mock2.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
nodeClient: mock2.NewMockNodeClient(ctrl),
|
||||
validatorClient: mock.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
nodeClient: mock.NewMockNodeClient(ctrl),
|
||||
slasherClient: mock.NewMockSlasherClient(ctrl),
|
||||
signExitFunc: func(ctx context.Context, req *validatorpb.SignRequest) (bls.Signature, error) {
|
||||
return mockSignature{}, nil
|
||||
},
|
||||
@ -85,6 +87,7 @@ func setupWithKey(t *testing.T, validatorKey bls.SecretKey) (*validator, *mocks,
|
||||
db: valDB,
|
||||
keyManager: km,
|
||||
validatorClient: m.validatorClient,
|
||||
slashingProtectionClient: m.slasherClient,
|
||||
graffiti: []byte{},
|
||||
attLogs: make(map[[32]byte]*attSubmitted),
|
||||
aggregatedSlotCommitteeIDCache: aggregatedSlotCommitteeIDCache,
|
||||
@ -296,10 +299,10 @@ func TestProposeBlock_BlocksDoubleProposal(t *testing.T) {
|
||||
).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), slot, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
|
||||
validator.ProposeBlock(context.Background(), slot, pubKey)
|
||||
require.LogsContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsContain(t, hook, failedBlockSignLocalErr)
|
||||
}
|
||||
|
||||
func TestProposeBlockAltair_BlocksDoubleProposal(t *testing.T) {
|
||||
@ -356,10 +359,10 @@ func TestProposeBlockAltair_BlocksDoubleProposal(t *testing.T) {
|
||||
).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), slot, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
|
||||
validator.ProposeBlock(context.Background(), slot, pubKey)
|
||||
require.LogsContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsContain(t, hook, failedBlockSignLocalErr)
|
||||
}
|
||||
|
||||
func TestProposeBlock_BlocksDoubleProposal_After54KEpochs(t *testing.T) {
|
||||
@ -408,10 +411,10 @@ func TestProposeBlock_BlocksDoubleProposal_After54KEpochs(t *testing.T) {
|
||||
).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farFuture, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farFuture, pubKey)
|
||||
require.LogsContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsContain(t, hook, failedBlockSignLocalErr)
|
||||
}
|
||||
|
||||
func TestProposeBlock_AllowsPastProposals(t *testing.T) {
|
||||
@ -449,7 +452,7 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) {
|
||||
).Times(2).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farAhead, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
|
||||
past := params.BeaconConfig().SlotsPerEpoch.Mul(uint64(params.BeaconConfig().WeakSubjectivityPeriod - 400))
|
||||
blk2 := util.NewBeaconBlock()
|
||||
@ -459,7 +462,7 @@ func TestProposeBlock_AllowsPastProposals(t *testing.T) {
|
||||
gomock.Any(),
|
||||
).Return(blk2.Block, nil /*err*/)
|
||||
validator.ProposeBlock(context.Background(), past, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
}
|
||||
|
||||
func TestProposeBlock_AllowsSameEpoch(t *testing.T) {
|
||||
@ -497,7 +500,7 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) {
|
||||
).Times(2).Return(ðpb.ProposeResponse{BlockRoot: make([]byte, 32)}, nil /*error*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farAhead, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
|
||||
blk2 := util.NewBeaconBlock()
|
||||
blk2.Block.Slot = farAhead - 4
|
||||
@ -507,7 +510,7 @@ func TestProposeBlock_AllowsSameEpoch(t *testing.T) {
|
||||
).Return(blk2.Block, nil /*err*/)
|
||||
|
||||
validator.ProposeBlock(context.Background(), farAhead-4, pubKey)
|
||||
require.LogsDoNotContain(t, hook, failedPreBlockSignLocalErr)
|
||||
require.LogsDoNotContain(t, hook, failedBlockSignLocalErr)
|
||||
}
|
||||
|
||||
func TestProposeBlock_BroadcastsBlock(t *testing.T) {
|
||||
@ -875,7 +878,7 @@ func TestSignAltairBlock(t *testing.T) {
|
||||
func TestGetGraffiti_Ok(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
m := &mocks{
|
||||
validatorClient: mock2.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
validatorClient: mock.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
}
|
||||
pubKey := [48]byte{'a'}
|
||||
tests := []struct {
|
||||
@ -958,7 +961,7 @@ func TestGetGraffitiOrdered_Ok(t *testing.T) {
|
||||
valDB := testing2.SetupDB(t, [][48]byte{pubKey})
|
||||
ctrl := gomock.NewController(t)
|
||||
m := &mocks{
|
||||
validatorClient: mock2.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
validatorClient: mock.NewMockBeaconNodeValidatorClient(ctrl),
|
||||
}
|
||||
m.validatorClient.EXPECT().
|
||||
ValidatorIndex(gomock.Any(), ðpb.ValidatorIndexRequest{PublicKey: pubKey[:]}).
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"github.com/pkg/errors"
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/beacon-chain/core"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/config/params"
|
||||
"github.com/prysmaticlabs/prysm/encoding/bytesutil"
|
||||
"github.com/prysmaticlabs/prysm/validator/client/iface"
|
||||
@ -40,11 +39,6 @@ func run(ctx context.Context, v iface.Validator) {
|
||||
cleanup()
|
||||
log.Fatalf("Wallet is not ready: %v", err)
|
||||
}
|
||||
if features.Get().RemoteSlasherProtection {
|
||||
if err := v.SlasherReady(ctx); err != nil {
|
||||
log.Fatalf("Slasher is not ready: %v", err)
|
||||
}
|
||||
}
|
||||
ticker := time.NewTicker(backOffPeriod)
|
||||
defer ticker.Stop()
|
||||
|
||||
|
@ -8,7 +8,6 @@ import (
|
||||
|
||||
types "github.com/prysmaticlabs/eth2-types"
|
||||
"github.com/prysmaticlabs/prysm/async/event"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/testing/assert"
|
||||
"github.com/prysmaticlabs/prysm/testing/require"
|
||||
"github.com/prysmaticlabs/prysm/validator/client/iface"
|
||||
@ -62,17 +61,6 @@ func TestCancelledContext_WaitsForActivation(t *testing.T) {
|
||||
assert.Equal(t, 1, v.WaitForActivationCalled, "Expected WaitForActivation() to be called")
|
||||
}
|
||||
|
||||
func TestCancelledContext_ChecksSlasherReady(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
cfg := &features.Flags{
|
||||
RemoteSlasherProtection: true,
|
||||
}
|
||||
reset := features.InitWithReset(cfg)
|
||||
defer reset()
|
||||
run(cancelledContext(), v)
|
||||
assert.Equal(t, true, v.SlasherReadyCalled, "Expected SlasherReady() to be called")
|
||||
}
|
||||
|
||||
func TestUpdateDuties_NextSlot(t *testing.T) {
|
||||
v := &testutil.FakeValidator{Keymanager: &mockKeymanager{accountsChangedFeed: &event.Feed{}}}
|
||||
ctx, cancel := context.WithCancel(context.Background())
|
||||
|
@ -27,7 +27,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/validator/graffiti"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager/imported"
|
||||
slashingiface "github.com/prysmaticlabs/prysm/validator/slashing-protection/iface"
|
||||
"go.opencensus.io/plugin/ocgrpc"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials"
|
||||
@ -64,7 +63,6 @@ type ValidatorService struct {
|
||||
withCert string
|
||||
endpoint string
|
||||
validator iface.Validator
|
||||
protector slashingiface.Protector
|
||||
ctx context.Context
|
||||
keyManager keymanager.IKeymanager
|
||||
grpcHeaders []string
|
||||
@ -82,7 +80,6 @@ type Config struct {
|
||||
GrpcRetriesFlag uint
|
||||
GrpcRetryDelay time.Duration
|
||||
GrpcMaxCallRecvMsgSizeFlag int
|
||||
Protector slashingiface.Protector
|
||||
Endpoint string
|
||||
Validator iface.Validator
|
||||
ValDB db.Database
|
||||
@ -112,7 +109,6 @@ func NewValidatorService(ctx context.Context, cfg *Config) (*ValidatorService, e
|
||||
grpcRetries: cfg.GrpcRetriesFlag,
|
||||
grpcRetryDelay: cfg.GrpcRetryDelay,
|
||||
grpcHeaders: strings.Split(cfg.GrpcHeadersFlag, ","),
|
||||
protector: cfg.Protector,
|
||||
validator: cfg.Validator,
|
||||
db: cfg.ValDB,
|
||||
walletInitializedFeed: cfg.WalletInitializedFeed,
|
||||
@ -188,7 +184,6 @@ func (v *ValidatorService) Start() {
|
||||
attLogs: make(map[[32]byte]*attSubmitted),
|
||||
domainDataCache: cache,
|
||||
aggregatedSlotCommitteeIDCache: aggregatedSlotCommitteeIDCache,
|
||||
protector: v.protector,
|
||||
voteStats: voteStats{startEpoch: types.Epoch(^uint64(0))},
|
||||
useWeb: v.useWeb,
|
||||
walletInitializedFeed: v.walletInitializedFeed,
|
||||
|
@ -9,7 +9,6 @@ import (
|
||||
"testing"
|
||||
|
||||
"github.com/bazelbuild/rules_go/go/tools/bazel"
|
||||
"github.com/prysmaticlabs/prysm/config/features"
|
||||
"github.com/prysmaticlabs/prysm/io/file"
|
||||
ethpb "github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1"
|
||||
"github.com/prysmaticlabs/prysm/proto/prysm/v1alpha1/wrapper"
|
||||
@ -76,12 +75,6 @@ func setupEIP3076SpecTests(t *testing.T) []*eip3076TestCase {
|
||||
}
|
||||
|
||||
func TestEIP3076SpecTests(t *testing.T) {
|
||||
config := &features.Flags{
|
||||
RemoteSlasherProtection: true,
|
||||
}
|
||||
reset := features.InitWithReset(config)
|
||||
defer reset()
|
||||
|
||||
testCases := setupEIP3076SpecTests(t)
|
||||
for _, tt := range testCases {
|
||||
t.Run(tt.Name, func(t *testing.T) {
|
||||
@ -130,22 +123,12 @@ func TestEIP3076SpecTests(t *testing.T) {
|
||||
copy(signingRoot[:], signingRootBytes)
|
||||
}
|
||||
|
||||
err = validator.preBlockSignValidations(context.Background(), pk, wrapper.WrappedPhase0BeaconBlock(b.Block), signingRoot)
|
||||
err = validator.slashableProposalCheck(context.Background(), pk, wrapper.WrappedPhase0SignedBeaconBlock(b), signingRoot)
|
||||
if sb.ShouldSucceed {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.NotEqual(t, nil, err, "pre validation should have failed for block")
|
||||
}
|
||||
|
||||
// Only proceed post update if pre validation did not error.
|
||||
if err == nil {
|
||||
err = validator.postBlockSignUpdate(context.Background(), pk, wrapper.WrappedPhase0SignedBeaconBlock(b), signingRoot)
|
||||
if sb.ShouldSucceed {
|
||||
require.NoError(t, err)
|
||||
} else {
|
||||
require.NotEqual(t, nil, err, "post validation should have failed for block")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// This loops through a list of attestation signings to attempt after importing the interchange data above.
|
||||
|
@ -36,20 +36,17 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/validator/db/kv"
|
||||
"github.com/prysmaticlabs/prysm/validator/graffiti"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
slashingiface "github.com/prysmaticlabs/prysm/validator/slashing-protection/iface"
|
||||
"github.com/sirupsen/logrus"
|
||||
"go.opencensus.io/trace"
|
||||
"google.golang.org/protobuf/proto"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// reconnectPeriod is the frequency that we try to restart our
|
||||
// slasher connection when the slasher client connection is not ready.
|
||||
var reconnectPeriod = 5 * time.Second
|
||||
|
||||
// keyFetchPeriod is the frequency that we try to refetch validating keys
|
||||
// in case no keys were fetched previously.
|
||||
var keyRefetchPeriod = 30 * time.Second
|
||||
var (
|
||||
keyRefetchPeriod = 30 * time.Second
|
||||
)
|
||||
|
||||
var (
|
||||
msgCouldNotFetchKeys = "could not fetch validating keys"
|
||||
@ -81,7 +78,7 @@ type validator struct {
|
||||
keyManager keymanager.IKeymanager
|
||||
beaconClient ethpb.BeaconChainClient
|
||||
validatorClient ethpb.BeaconNodeValidatorClient
|
||||
protector slashingiface.Protector
|
||||
slashingProtectionClient ethpb.SlasherClient
|
||||
db vdb.Database
|
||||
graffiti []byte
|
||||
voteStats voteStats
|
||||
@ -224,37 +221,6 @@ func (v *validator) WaitForSync(ctx context.Context) error {
|
||||
}
|
||||
}
|
||||
|
||||
// SlasherReady checks if slasher that was configured as external protection
|
||||
// is reachable.
|
||||
func (v *validator) SlasherReady(ctx context.Context) error {
|
||||
ctx, span := trace.StartSpan(ctx, "validator.SlasherReady")
|
||||
defer span.End()
|
||||
if features.Get().RemoteSlasherProtection {
|
||||
err := v.protector.Status()
|
||||
if err == nil {
|
||||
return nil
|
||||
}
|
||||
ticker := time.NewTicker(reconnectPeriod)
|
||||
defer ticker.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-ticker.C:
|
||||
log.WithError(err).Info("Slasher connection wasn't ready. Trying again")
|
||||
err = v.protector.Status()
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
log.Info("Slasher connection is ready")
|
||||
return nil
|
||||
case <-ctx.Done():
|
||||
log.Debug("Context closed, exiting reconnect external protection")
|
||||
return ctx.Err()
|
||||
}
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ReceiveBlocks starts a gRPC client stream listener to obtain
|
||||
// blocks from the beacon node. Upon receiving a block, the service
|
||||
// broadcasts it to a feed for other usages to subscribe to.
|
||||
|
@ -52,8 +52,6 @@ go_library(
|
||||
"//validator/keymanager:go_default_library",
|
||||
"//validator/keymanager/imported:go_default_library",
|
||||
"//validator/rpc:go_default_library",
|
||||
"//validator/slashing-protection:go_default_library",
|
||||
"//validator/slashing-protection/iface:go_default_library",
|
||||
"//validator/web:go_default_library",
|
||||
"@com_github_grpc_ecosystem_grpc_gateway_v2//runtime:go_default_library",
|
||||
"@com_github_pkg_errors//:go_default_library",
|
||||
|
@ -40,8 +40,6 @@ import (
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager"
|
||||
"github.com/prysmaticlabs/prysm/validator/keymanager/imported"
|
||||
"github.com/prysmaticlabs/prysm/validator/rpc"
|
||||
slashingprotection "github.com/prysmaticlabs/prysm/validator/slashing-protection"
|
||||
"github.com/prysmaticlabs/prysm/validator/slashing-protection/iface"
|
||||
"github.com/prysmaticlabs/prysm/validator/web"
|
||||
"github.com/sirupsen/logrus"
|
||||
"github.com/urfave/cli/v2"
|
||||
@ -251,9 +249,6 @@ func (c *ValidatorClient) initializeFromCLI(cliCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.registerSlasherService(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.registerValidatorService(keyManager); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -338,9 +333,6 @@ func (c *ValidatorClient) initializeForWeb(cliCtx *cli.Context) error {
|
||||
return err
|
||||
}
|
||||
}
|
||||
if err := c.registerSlasherService(); err != nil {
|
||||
return err
|
||||
}
|
||||
if err := c.registerValidatorService(keyManager); err != nil {
|
||||
return err
|
||||
}
|
||||
@ -391,12 +383,6 @@ func (c *ValidatorClient) registerValidatorService(
|
||||
maxCallRecvMsgSize := c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name)
|
||||
grpcRetries := c.cliCtx.Uint(flags.GrpcRetriesFlag.Name)
|
||||
grpcRetryDelay := c.cliCtx.Duration(flags.GrpcRetryDelayFlag.Name)
|
||||
var sp *slashingprotection.Service
|
||||
var protector iface.Protector
|
||||
if err := c.services.FetchService(&sp); err == nil {
|
||||
protector = sp
|
||||
}
|
||||
|
||||
gStruct := &g.Graffiti{}
|
||||
var err error
|
||||
if c.cliCtx.IsSet(flags.GraffitiFileFlag.Name) {
|
||||
@ -419,7 +405,6 @@ func (c *ValidatorClient) registerValidatorService(
|
||||
GrpcRetriesFlag: grpcRetries,
|
||||
GrpcRetryDelay: grpcRetryDelay,
|
||||
GrpcHeadersFlag: c.cliCtx.String(flags.GrpcHeadersFlag.Name),
|
||||
Protector: protector,
|
||||
ValDB: c.db,
|
||||
UseWeb: c.cliCtx.Bool(flags.EnableWebFlag.Name),
|
||||
WalletInitializedFeed: c.walletInitialized,
|
||||
@ -432,32 +417,6 @@ func (c *ValidatorClient) registerValidatorService(
|
||||
|
||||
return c.services.RegisterService(v)
|
||||
}
|
||||
func (c *ValidatorClient) registerSlasherService() error {
|
||||
if !features.Get().RemoteSlasherProtection {
|
||||
return nil
|
||||
}
|
||||
endpoint := c.cliCtx.String(flags.SlasherRPCProviderFlag.Name)
|
||||
if endpoint == "" {
|
||||
return errors.New("external slasher feature flag is set but no slasher endpoint is configured")
|
||||
|
||||
}
|
||||
cert := c.cliCtx.String(flags.SlasherCertFlag.Name)
|
||||
maxCallRecvMsgSize := c.cliCtx.Int(cmd.GrpcMaxCallRecvMsgSizeFlag.Name)
|
||||
grpcRetries := c.cliCtx.Uint(flags.GrpcRetriesFlag.Name)
|
||||
grpcRetryDelay := c.cliCtx.Duration(flags.GrpcRetryDelayFlag.Name)
|
||||
sp, err := slashingprotection.NewService(c.cliCtx.Context, &slashingprotection.Config{
|
||||
Endpoint: endpoint,
|
||||
CertFlag: cert,
|
||||
GrpcMaxCallRecvMsgSizeFlag: maxCallRecvMsgSize,
|
||||
GrpcRetriesFlag: grpcRetries,
|
||||
GrpcRetryDelay: grpcRetryDelay,
|
||||
GrpcHeadersFlag: c.cliCtx.String(flags.GrpcHeadersFlag.Name),
|
||||
})
|
||||
if err != nil {
|
||||
return errors.Wrap(err, "could not initialize slasher service")
|
||||
}
|
||||
return c.services.RegisterService(sp)
|
||||
}
|
||||
|
||||
func (c *ValidatorClient) registerRPCService(cliCtx *cli.Context, km keymanager.IKeymanager) error {
|
||||
var vs *client.ValidatorService
|
||||
|
Loading…
Reference in New Issue
Block a user