prysm-pulse/slasher/rpc/detect_update_min_max_span.go
shayzluf 4330839bc1
Add surround check to endpoint (#4065)
* first version of the watchtower api

* service files

* Begin work on grpc server

* More changes to server

* REnames and mock setup

* working test

* merge

* double propose detection test

* nishant review

* todo change

* gaz

* fix service

* gaz

* remove unused import

* gaz

* resolve circular dependency

* resolve circular dependency 2nd try

* remove package

* fix package

* fix test

* added tests

* gaz

* remove status check

* gaz

* remove context

* remove context

* change var name

* moved to rpc dir

* gaz

* remove server code

* gaz

* slasher server

* visibility change

* pb

* service update

* gaz

* slasher grpc server

* making it work

* setup db and start

* gaz

* service flags fixes

* grpc service running

* go imports

* remove new initializer

* gaz

* remove feature flags

* change back SetupSlasherDB

* fix SetupSlasherDB calls

* define err

* fix bad merge

* fix test

* fix imports

* fix imports

* fix imports

* add cancel

* comment stop

* fix cancel issue

* remove unneeded code

* bring back bad merge that removed TODO

* remove use of epoch as am input

* fixed slasher to be runable again

* wait for channel close

* gaz

* small test

* flags fix

* fix flag order

* double vote detection

* remove source epoch from indexed attestation indices

* change server method to receive indexed attestation

* start implementation

* double vote detection

* proto

* pb

* fir comment

* add surround detection and retrieval to endpoint

* nishant review

* import fix

* fix miss order

* fix detection 0 case
added tests

* terence review
2019-11-21 12:41:23 +05:30

143 lines
4.9 KiB
Go

package rpc
import (
"context"
"fmt"
"github.com/pkg/errors"
ethpb "github.com/prysmaticlabs/prysm/proto/eth/v1alpha1"
"github.com/prysmaticlabs/prysm/shared/params"
)
// Detector is a function type used to implement the slashable surrounding/surrounded
// vote detection methods.
type detectFn = func(attestationEpochSpan uint64, recorderEpochSpan *ethpb.MinMaxEpochSpan, sourceEpoch uint64) uint64
// detectMax is a function for maxDetector used to detect surrounding attestations.
func detectMax(
attestationEpochSpan uint64,
recorderEpochSpan *ethpb.MinMaxEpochSpan,
attestationSourceEpoch uint64) uint64 {
maxSpan := uint64(recorderEpochSpan.MaxEpochSpan)
if maxSpan > attestationEpochSpan {
return maxSpan + attestationSourceEpoch
}
return 0
}
// detectMin is a function for minDetecter used to detect surrounded attestations.
func detectMin(attestationEpochSpan uint64,
recorderEpochSpan *ethpb.MinMaxEpochSpan,
attestationSourceEpoch uint64) uint64 {
minSpan := uint64(recorderEpochSpan.MinEpochSpan)
if minSpan > 0 && minSpan < attestationEpochSpan {
return minSpan + attestationSourceEpoch
}
return 0
}
// DetectAndUpdateMaxEpochSpan is used to detect and update the max span of an incoming attestation.
// This is used for detecting surrounding votes.
// The max span is the span between the current attestation's source epoch and the furthest attestation's
// target epoch that has a lower (earlier) source epoch.
// Logic for this detection method was designed by https://github.com/protolambda
// Detailed here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
func (ss *Server) DetectAndUpdateMaxEpochSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) (uint64, error) {
if target < source {
return 0, fmt.Errorf(
"target: %d < source: %d ",
target,
source,
)
}
targetEpoch, span, spanMap, err := ss.detectSlashingByEpochSpan(source, target, validatorIdx, detectMax)
if err != nil {
return 0, err
}
if targetEpoch > 0 {
return targetEpoch, nil
}
for i := uint64(1); i < target-source; i++ {
val := uint32(span - i)
if _, ok := spanMap.EpochSpanMap[source+i]; !ok {
spanMap.EpochSpanMap[source+i] = &ethpb.MinMaxEpochSpan{}
}
if spanMap.EpochSpanMap[source+i].MaxEpochSpan < val {
spanMap.EpochSpanMap[source+i].MaxEpochSpan = val
} else {
break
}
}
if err := ss.SlasherDB.SaveValidatorSpansMap(validatorIdx, spanMap); err != nil {
return 0, err
}
return 0, nil
}
// DetectAndUpdateMinEpochSpan is used to detect surrounded votes and update the min epoch span
// of an incoming attestation.
// The min span is the span between the current attestations target epoch and the
// closest attestation's target distance.
//
// Logic is following the detection method designed by https://github.com/protolambda
// Detailed here: https://github.com/protolambda/eth2-surround/blob/master/README.md#min-max-surround
func (ss *Server) DetectAndUpdateMinEpochSpan(ctx context.Context, source uint64, target uint64, validatorIdx uint64) (uint64, error) {
if target < source {
return 0, fmt.Errorf(
"target: %d < source: %d ",
target,
source,
)
}
targetEpoch, _, spanMap, err := ss.detectSlashingByEpochSpan(source, target, validatorIdx, detectMin)
if err != nil {
return 0, err
}
if targetEpoch > 0 {
return targetEpoch, nil
}
if source == 0 {
return 0, nil
}
for i := source - 1; i > 0; i-- {
val := uint32(target - (i))
if _, ok := spanMap.EpochSpanMap[i]; !ok {
spanMap.EpochSpanMap[i] = &ethpb.MinMaxEpochSpan{}
}
if spanMap.EpochSpanMap[i].MinEpochSpan == 0 || spanMap.EpochSpanMap[i].MinEpochSpan > val {
spanMap.EpochSpanMap[i].MinEpochSpan = val
} else {
break
}
}
if err := ss.SlasherDB.SaveValidatorSpansMap(validatorIdx, spanMap); err != nil {
return 0, errors.Wrap(err, "could not save validator spans")
}
return 0, nil
}
// detectSlashingByEpochSpan is used to detect if a slashable event is present
// in the db by checking either the closest attestation target or the furthest
// attestation target. This method receives a detector function in order to be used
// for both surrounding and surrounded vote cases.
func (ss *Server) detectSlashingByEpochSpan(source, target, validatorIdx uint64, detector detectFn) (uint64, uint64, *ethpb.EpochSpanMap, error) {
span := target - source
if span > params.BeaconConfig().WeakSubjectivityPeriod {
return 0, span, nil, fmt.Errorf("target: %d - source: %d > weakSubjectivityPeriod",
params.BeaconConfig().WeakSubjectivityPeriod,
span,
)
}
spanMap, err := ss.SlasherDB.ValidatorSpansMap(validatorIdx)
if err != nil {
return 0, span, nil, errors.Wrapf(err, "could not retrieve span map for validator index: %d", validatorIdx)
}
if _, ok := spanMap.EpochSpanMap[source]; ok {
return detector(span, spanMap.EpochSpanMap[source], source), span, spanMap, nil
}
return 0, span, spanMap, nil
}