Add Doppelganger E2E (#9239)

* add current fixes

* fix prev release

* Update endtoend/endtoend_test.go

Co-authored-by: Radosław Kapka <rkapka@wp.pl>

* Update endtoend/endtoend_test.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* Update endtoend/endtoend_test.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>

* review comments for radek and raul

Co-authored-by: Radosław Kapka <rkapka@wp.pl>
Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
This commit is contained in:
Nishant Das
2021-07-22 12:00:12 +08:00
committed by GitHub
parent 6dadb80cc4
commit 33f7582d25
2 changed files with 54 additions and 5 deletions

View File

@@ -35,6 +35,9 @@ const (
// allNodesStartTimeout defines period after which nodes are considered
// stalled (safety measure for nodes stuck at startup, shouldn't normally happen).
allNodesStartTimeout = 5 * time.Minute
// errGeneralCode is used to represent the string value for all general process errors.
errGeneralCode = "exit status 1"
)
func init() {
@@ -181,7 +184,10 @@ func (r *testRunner) run() {
if !config.TestSync {
return nil
}
return r.testBeaconChainSync(ctx, g, conns, tickingStartTime, bootNode.ENR())
if err := r.testBeaconChainSync(ctx, g, conns, tickingStartTime, bootNode.ENR()); err != nil {
return err
}
return r.testDoppelGangerProtection(ctx)
})
if err := g.Wait(); err != nil && !errors.Is(err, context.Canceled) {
@@ -296,3 +302,43 @@ func (r *testRunner) testBeaconChainSync(ctx context.Context, g *errgroup.Group,
return nil
}
func (r *testRunner) testDoppelGangerProtection(ctx context.Context) error {
// Exit if we are running from the previous release.
if r.config.UsePrysmShValidator {
return nil
}
g, ctx := errgroup.WithContext(ctx)
// Follow same parameters as older validators.
validatorNum := int(params.BeaconConfig().MinGenesisActiveValidatorCount)
beaconNodeNum := e2e.TestParams.BeaconNodeCount
if validatorNum%beaconNodeNum != 0 {
return errors.New("validator count is not easily divisible by beacon node count")
}
validatorsPerNode := validatorNum / beaconNodeNum
valIndex := beaconNodeNum + 1
// Replicate starting up validator client 0 to test doppleganger protection.
valNode := components.NewValidatorNode(r.config, validatorsPerNode, valIndex, validatorsPerNode*0)
g.Go(func() error {
return valNode.Start(ctx)
})
if err := helpers.ComponentsStarted(ctx, []e2etypes.ComponentRunner{valNode}); err != nil {
return fmt.Errorf("validator not ready: %w", err)
}
logFile, err := os.Create(path.Join(e2e.TestParams.LogPath, fmt.Sprintf(e2e.ValidatorLogFileName, valIndex)))
if err != nil {
return fmt.Errorf("unable to open log file: %v", err)
}
r.t.Run("doppelganger found", func(t *testing.T) {
assert.NoError(t, helpers.WaitForTextInFile(logFile, "Duplicate instances exists in the network for validator keys"), "Failed to carry out doppelganger check correctly")
})
if r.t.Failed() {
return errors.New("doppelganger was unable to be found")
}
// Expect an abrupt exit for the validator client.
if err := g.Wait(); err == nil || !strings.Contains(err.Error(), errGeneralCode) {
return fmt.Errorf("wanted an error of %s but received %v", errGeneralCode, err)
}
return nil
}

View File

@@ -387,7 +387,8 @@ func (v *validator) CheckDoppelGanger(ctx context.Context) error {
}
req := &ethpb.DoppelGangerRequest{ValidatorRequests: []*ethpb.DoppelGangerRequest_ValidatorRequest{}}
for _, pkey := range pubkeys {
attRec, err := v.db.AttestationHistoryForPubKey(ctx, pkey)
copiedKey := pkey
attRec, err := v.db.AttestationHistoryForPubKey(ctx, copiedKey)
if err != nil {
return err
}
@@ -396,14 +397,14 @@ func (v *validator) CheckDoppelGanger(ctx context.Context) error {
// value for the request epoch and root.
req.ValidatorRequests = append(req.ValidatorRequests,
&ethpb.DoppelGangerRequest_ValidatorRequest{
PublicKey: pkey[:],
PublicKey: copiedKey[:],
Epoch: 0,
SignedRoot: make([]byte, 32),
})
continue
}
r := retrieveLatestRecord(attRec)
if pkey != r.PubKey {
if copiedKey != r.PubKey {
return errors.New("attestation record mismatched public key")
}
req.ValidatorRequests = append(req.ValidatorRequests,
@@ -429,7 +430,9 @@ func buildDuplicateError(respones []*ethpb.DoppelGangerResponse_ValidatorRespons
duplicates := make([][]byte, 0)
for _, valRes := range respones {
if valRes.DuplicateExists {
duplicates = append(duplicates, valRes.PublicKey)
copiedKey := [48]byte{}
copy(copiedKey[:], valRes.PublicKey)
duplicates = append(duplicates, copiedKey[:])
}
}
if len(duplicates) == 0 {