From 26eead0d1cb03f476802bea9dbe8e860236eceee Mon Sep 17 00:00:00 2001 From: Ivan Martinez Date: Fri, 8 May 2020 22:07:37 -0400 Subject: [PATCH] Gate disable lookback behind featureflag (#5782) * Gate disable lookback behind featureflag * Merge branch 'master' into slasher-lookback-flag * Update shared/featureconfig/config.go * Merge branch 'master' into slasher-lookback-flag * Add context timeout error handling * Merge branch 'slasher-lookback-flag' of github.com:prysmaticlabs/prysm into slasher-lookback-flag * gaz * Merge branch 'master' into slasher-lookback-flag * Merge branch 'master' into slasher-lookback-flag * Merge refs/heads/master into slasher-lookback-flag * Merge refs/heads/master into slasher-lookback-flag * Merge refs/heads/master into slasher-lookback-flag * Merge refs/heads/master into slasher-lookback-flag --- shared/featureconfig/config.go | 7 +- shared/featureconfig/flags.go | 5 + slasher/detection/attestations/BUILD.bazel | 2 + slasher/detection/attestations/spanner.go | 131 ++++++++++++++------- 4 files changed, 103 insertions(+), 42 deletions(-) diff --git a/shared/featureconfig/config.go b/shared/featureconfig/config.go index dcedb43b82..0cc5752b62 100644 --- a/shared/featureconfig/config.go +++ b/shared/featureconfig/config.go @@ -60,7 +60,8 @@ type Flags struct { // BroadcastSlashings enables p2p broadcasting of proposer or attester slashing. BroadcastSlashings bool - DisableHistoricalDetection bool + DisableHistoricalDetection bool // DisableHistoricalDetection disables historical attestation detection and performs detection on the chain head immediately. + DisableLookback bool // DisableLookback updates slasher to not use the lookback and update validator histories until epoch 0. // Cache toggles. EnableSSZCache bool // EnableSSZCache see https://github.com/prysmaticlabs/prysm/pull/4558. @@ -219,6 +220,10 @@ func ConfigureSlasher(ctx *cli.Context) { log.Warn("Disabling historical attestation detection") cfg.DisableHistoricalDetection = true } + if ctx.Bool(disableLookbackFlag.Name) { + log.Warn("Disabling slasher lookback") + cfg.DisableLookback = true + } Init(cfg) } diff --git a/shared/featureconfig/flags.go b/shared/featureconfig/flags.go index acef2722be..3725c4b52e 100644 --- a/shared/featureconfig/flags.go +++ b/shared/featureconfig/flags.go @@ -144,6 +144,10 @@ var ( Name: "disable-historical-detection", Usage: "Disables historical attestation detection for the slasher", } + disableLookbackFlag = &cli.BoolFlag{ + Name: "disable-lookback", + Usage: "Disables use of the lookback feature and updates attestation history for validators from head to epoch 0", + } ) // devModeFlags holds list of flags that are set when development mode is on. @@ -379,6 +383,7 @@ var ValidatorFlags = append(deprecatedFlags, []cli.Flag{ // SlasherFlags contains a list of all the feature flags that apply to the slasher client. var SlasherFlags = append(deprecatedFlags, []cli.Flag{ disableHistoricalDetectionFlag, + disableLookbackFlag, }...) // E2EValidatorFlags contains a list of the validator feature flags to be tested in E2E. diff --git a/slasher/detection/attestations/BUILD.bazel b/slasher/detection/attestations/BUILD.bazel index 7e3a60d3c6..23fa4153f1 100644 --- a/slasher/detection/attestations/BUILD.bazel +++ b/slasher/detection/attestations/BUILD.bazel @@ -10,10 +10,12 @@ go_library( importpath = "github.com/prysmaticlabs/prysm/slasher/detection/attestations", visibility = ["//slasher:__subpackages__"], deps = [ + "//shared/featureconfig:go_default_library", "//shared/params:go_default_library", "//slasher/db:go_default_library", "//slasher/detection/attestations/iface:go_default_library", "//slasher/detection/attestations/types:go_default_library", + "@com_github_pkg_errors//:go_default_library", "@com_github_prometheus_client_golang//prometheus:go_default_library", "@com_github_prometheus_client_golang//prometheus/promauto:go_default_library", "@com_github_prysmaticlabs_ethereumapis//eth/v1alpha1:go_default_library", diff --git a/slasher/detection/attestations/spanner.go b/slasher/detection/attestations/spanner.go index 2d0223f2d6..df07e8aaab 100644 --- a/slasher/detection/attestations/spanner.go +++ b/slasher/detection/attestations/spanner.go @@ -6,9 +6,11 @@ import ( "context" "fmt" + "github.com/pkg/errors" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promauto" ethpb "github.com/prysmaticlabs/ethereumapis/eth/v1alpha1" + "github.com/prysmaticlabs/prysm/shared/featureconfig" "github.com/prysmaticlabs/prysm/shared/params" db "github.com/prysmaticlabs/prysm/slasher/db" "github.com/prysmaticlabs/prysm/slasher/detection/attestations/iface" @@ -81,6 +83,9 @@ func (s *SpanDetector) DetectSlashingsForAttestation( var detections []*types.DetectionResult distance := uint16(targetEpoch - sourceEpoch) for _, idx := range att.AttestingIndices { + if ctx.Err() != nil { + return nil, errors.Wrap(ctx.Err(), "could not detect slashings") + } span := spanMap[idx] minSpan := span.MinSpan if minSpan > 0 && minSpan < distance { @@ -161,6 +166,9 @@ func (s *SpanDetector) saveSigBytes(ctx context.Context, att *ethpb.IndexedAttes // We loop through the indices, instead of constantly locking/unlocking the cache for equivalent accesses. for _, idx := range att.AttestingIndices { + if ctx.Err() != nil { + return errors.Wrap(ctx.Err(), "could not save signature bytes") + } span := spanMap[idx] // If the validator has already attested for this target epoch, // then we do not need to update the values of the span sig bytes. @@ -203,58 +211,96 @@ func (s *SpanDetector) updateMinSpan(ctx context.Context, att *ethpb.IndexedAtte spanMap := make(map[uint64]types.Span) epochsSpansMap := make(map[uint64]map[uint64]types.Span) epoch := source - 1 + untilEpoch := epoch - epochLookback + if int(untilEpoch) < 0 || featureconfig.Get().DisableLookback { + untilEpoch = 0 + } useCache := true useDb := false var err error - for ; epoch >= 0; epoch-- { - if useCache { - spanMap, useCache, err = s.slasherDB.EpochSpansMap(ctx, epoch) + for ; epoch >= untilEpoch; epoch-- { + if ctx.Err() != nil { + return errors.Wrap(ctx.Err(), "could not update min spans") } - // Should happen once when cache is exhausted. - if !useCache && !useDb { - epochsSpansMap, err = s.slasherDB.EpochsSpanByValidatorsIndices(ctx, valIndices, epoch) - useDb = true - } - if err != nil { - return err - } - if useDb { - spanMap = epochsSpansMap[epoch] - if spanMap == nil { - spanMap = make(map[uint64]types.Span) - epochsSpansMap[epoch] = spanMap + if featureconfig.Get().DisableLookback { + if useCache { + spanMap, useCache, err = s.slasherDB.EpochSpansMap(ctx, epoch) } - } - - indices := valIndices[:0] - for _, idx := range valIndices { - span := spanMap[idx] - newMinSpan := uint16(target - epoch) - if span.MinSpan == 0 || span.MinSpan > newMinSpan { - span = types.Span{ - MinSpan: newMinSpan, - MaxSpan: span.MaxSpan, - SigBytes: span.SigBytes, - HasAttested: span.HasAttested, - } - spanMap[idx] = span - indices = append(indices, idx) + // Should happen once when cache is exhausted. + if !useCache && !useDb && featureconfig.Get().DisableLookback { + epochsSpansMap, err = s.slasherDB.EpochsSpanByValidatorsIndices(ctx, valIndices, epoch) + useDb = true } - } - copy(valIndices, indices) - if useCache { - if err := s.slasherDB.SaveEpochSpansMap(ctx, epoch, spanMap); err != nil { + if err != nil { return err } - } - if len(indices) == 0 || epoch == 0 { - if useDb { - // should happen once when finishing update to all epochs and all indices. - if err := s.slasherDB.SaveEpochsSpanByValidatorsIndices(ctx, epochsSpansMap); err != nil { + if useDb && featureconfig.Get().DisableLookback { + spanMap = epochsSpansMap[epoch] + if spanMap == nil { + spanMap = make(map[uint64]types.Span) + epochsSpansMap[epoch] = spanMap + } + } + + indices := valIndices[:0] + for _, idx := range valIndices { + span := spanMap[idx] + newMinSpan := uint16(target - epoch) + if span.MinSpan == 0 || span.MinSpan > newMinSpan { + span = types.Span{ + MinSpan: newMinSpan, + MaxSpan: span.MaxSpan, + SigBytes: span.SigBytes, + HasAttested: span.HasAttested, + } + spanMap[idx] = span + indices = append(indices, idx) + } + } + copy(valIndices, indices) + if useCache { + if err := s.slasherDB.SaveEpochSpansMap(ctx, epoch, spanMap); err != nil { return err } } - break + if len(indices) == 0 || epoch == 0 { + if useDb { + // should happen once when finishing update to all epochs and all indices. + if err := s.slasherDB.SaveEpochsSpanByValidatorsIndices(ctx, epochsSpansMap); err != nil { + return err + } + } + break + } + } else { + spanMap, _, err := s.slasherDB.EpochSpansMap(ctx, epoch) + if err != nil { + return err + } + indices := valIndices[:0] + for _, idx := range valIndices { + span := spanMap[idx] + newMinSpan := uint16(target - epoch) + if span.MinSpan == 0 || span.MinSpan > newMinSpan { + span = types.Span{ + MinSpan: newMinSpan, + MaxSpan: span.MaxSpan, + SigBytes: span.SigBytes, + HasAttested: span.HasAttested, + } + spanMap[idx] = span + indices = append(indices, idx) + } + } + if err := s.slasherDB.SaveEpochSpansMap(ctx, epoch, spanMap); err != nil { + return err + } + if len(indices) == 0 { + break + } + if epoch == 0 { + break + } } } return nil @@ -271,6 +317,9 @@ func (s *SpanDetector) updateMaxSpan(ctx context.Context, att *ethpb.IndexedAtte valIndices := make([]uint64, len(att.AttestingIndices)) copy(valIndices, att.AttestingIndices) for epoch := source + 1; epoch < target; epoch++ { + if ctx.Err() != nil { + return errors.Wrap(ctx.Err(), "could not update max spans") + } spanMap, _, err := s.slasherDB.EpochSpansMap(ctx, epoch) if err != nil { return err