Skip to content

Commit

Permalink
Source lrg target (#7839)
Browse files Browse the repository at this point in the history
* handle source > target better

* promatheus metric for source > target

* handle source > target well in sig bytes

* Update slasher/detection/attestations/spanner_test.go

* Update slasher/detection/attestations/spanner_test.go

Co-authored-by: Raul Jordan <raul@prysmaticlabs.com>
Co-authored-by: prylabs-bulldozer[bot] <58059840+prylabs-bulldozer[bot]@users.noreply.github.com>
  • Loading branch information
3 people committed Nov 17, 2020
1 parent 7c54cfe commit 2976bf7
Show file tree
Hide file tree
Showing 2 changed files with 138 additions and 3 deletions.
37 changes: 34 additions & 3 deletions slasher/detection/attestations/spanner.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ var (
Name: "latest_max_span_distance_observed",
Help: "The latest distance between target - source observed for max spans",
})
sourceLargerThenTargetObserved = promauto.NewCounter(prometheus.CounterOpts{
Name: "attestation_source_larger_then_target",
Help: "The number of attestation data source epoch that aren larger then target epoch.",
})
)

// We look back 128 epochs when updating min/max spans
Expand Down Expand Up @@ -64,11 +68,21 @@ func (s *SpanDetector) DetectSlashingsForAttestation(
defer traceSpan.End()
sourceEpoch := att.Data.Source.Epoch
targetEpoch := att.Data.Target.Epoch
if (targetEpoch - sourceEpoch) > params.BeaconConfig().WeakSubjectivityPeriod {
dis := targetEpoch - sourceEpoch

if sourceEpoch > targetEpoch { //Prevent underflow and handle source > target slashable cases.
dis = sourceEpoch - targetEpoch
tmp := sourceEpoch
sourceEpoch = targetEpoch
targetEpoch = tmp
sourceLargerThenTargetObserved.Inc()
}

if dis > params.BeaconConfig().WeakSubjectivityPeriod {
return nil, fmt.Errorf(
"attestation span was greater than weak subjectivity period %d, received: %d",
params.BeaconConfig().WeakSubjectivityPeriod,
targetEpoch-sourceEpoch,
dis,
)
}

Expand All @@ -82,7 +96,7 @@ func (s *SpanDetector) DetectSlashingsForAttestation(
}

var detections []*types.DetectionResult
distance := uint16(targetEpoch - sourceEpoch)
distance := uint16(dis)
for _, idx := range att.AttestingIndices {
if ctx.Err() != nil {
return nil, errors.Wrap(ctx.Err(), "could not detect slashings")
Expand Down Expand Up @@ -171,6 +185,11 @@ func (s *SpanDetector) saveSigBytes(ctx context.Context, att *ethpb.IndexedAttes
ctx, traceSpan := trace.StartSpan(ctx, "spanner.saveSigBytes")
defer traceSpan.End()
target := att.Data.Target.Epoch
source := att.Data.Source.Epoch
// handle source > target well
if source > target {
target = source
}
spanMap, err := s.slasherDB.EpochSpans(ctx, target, dbTypes.UseCache)
if err != nil {
return err
Expand Down Expand Up @@ -220,6 +239,12 @@ func (s *SpanDetector) updateMinSpan(ctx context.Context, att *ethpb.IndexedAtte
if source < 1 {
return nil
}
// handle source > target well
if source > target {
tmp := source
source = target
target = tmp
}
valIndices := make([]uint64, len(att.AttestingIndices))
copy(valIndices, att.AttestingIndices)
latestMinSpanDistanceObserved.Set(float64(att.Data.Target.Epoch - att.Data.Source.Epoch))
Expand Down Expand Up @@ -292,6 +317,12 @@ func (s *SpanDetector) updateMaxSpan(ctx context.Context, att *ethpb.IndexedAtte
defer traceSpan.End()
source := att.Data.Source.Epoch
target := att.Data.Target.Epoch
// handle source > target well
if source > target {
tmp := source
source = target
target = tmp
}
latestMaxSpanDistanceObserved.Set(float64(target - source))
valIndices := make([]uint64, len(att.AttestingIndices))
copy(valIndices, att.AttestingIndices)
Expand Down
104 changes: 104 additions & 0 deletions slasher/detection/attestations/spanner_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -456,6 +456,29 @@ func TestSpanDetector_DetectSlashingsForAttestation_Surround(t *testing.T) {
17: {0, 0},
},
},
{
name: "Should slash if max span > distance && source > target",
sourceEpoch: 6,
targetEpoch: 3,
slashableEpoch: 7,
shouldSlash: true,
// Given a distance of (6 - 3) = 3, we want the validator at epoch 3 to have
// committed a slashable offense by having a max span of 4 > distance.
spansByEpochForValidator: map[uint64][3]uint16{
3: {0, 4},
},
},
{
name: "Should not slash if max span = distance && source > target",
sourceEpoch: 6,
targetEpoch: 3,
shouldSlash: false,
// Given a distance of (6 - 3) = 3, we want the validator at epoch 3 to NOT
// have committed slashable offense by having a max span of 1 < distance.
spansByEpochForValidator: map[uint64][3]uint16{
3: {0, 1},
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down Expand Up @@ -623,6 +646,87 @@ func TestSpanDetector_DetectSlashingsForAttestation_MultipleValidators(t *testin
indexedAttestation(1, 5, []uint64{3}),
},
},
{
name: "3 of 4 validators slashed, differing surrounds source > target",
incomingAtt: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{0, 1, 2, 3},
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{
Epoch: 7,
Root: []byte("good source"),
},
Target: &ethpb.Checkpoint{
Epoch: 5,
Root: []byte("good target"),
},
},
Signature: []byte{1, 2},
},
slashableEpochs: []uint64{8, 9, 10, 0},
// Detections - surround, surround, surround, none.
shouldSlash: []bool{true, true, true, false},
// Atts in map: (src, epoch) - 0: (1, 8), 1: (3, 9), 2: (2, 10), 3: (4, 6)
atts: []*ethpb.IndexedAttestation{
indexedAttestation(1, 8, []uint64{0}),
indexedAttestation(3, 9, []uint64{1}),
indexedAttestation(2, 10, []uint64{2}),
indexedAttestation(4, 6, []uint64{3}),
},
},
{
name: "3 of 4 validators slashed, differing surrounded source > target",
incomingAtt: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{0, 1, 2, 3},
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{
Epoch: 9,
Root: []byte("good source"),
},
Target: &ethpb.Checkpoint{
Epoch: 2,
Root: []byte("good target"),
},
},
Signature: []byte{1, 2},
},
slashableEpochs: []uint64{8, 8, 7, 0},
// Detections - surround, surround, surround, none.
shouldSlash: []bool{true, true, true, false},
// Atts in map: (src, epoch) - 0: (5, 8), 1: (3, 8), 2: (4, 7), 3: (1, 5)
atts: []*ethpb.IndexedAttestation{
indexedAttestation(5, 8, []uint64{0}),
indexedAttestation(3, 8, []uint64{1}),
indexedAttestation(4, 7, []uint64{2}),
indexedAttestation(1, 5, []uint64{3}),
},
},
{
name: "3 of 4 validators slashed, differing surrounded source > target in update",
incomingAtt: &ethpb.IndexedAttestation{
AttestingIndices: []uint64{0, 1, 2, 3},
Data: &ethpb.AttestationData{
Source: &ethpb.Checkpoint{
Epoch: 2,
Root: []byte("good source"),
},
Target: &ethpb.Checkpoint{
Epoch: 9,
Root: []byte("good target"),
},
},
Signature: []byte{1, 2},
},
slashableEpochs: []uint64{8, 8, 7, 0},
// Detections - surround, surround, surround, none.
shouldSlash: []bool{true, true, true, false},
// Atts in map: (src, epoch) - 0: (5, 8), 1: (3, 8), 2: (4, 7), 3: (1, 5)
atts: []*ethpb.IndexedAttestation{
indexedAttestation(8, 5, []uint64{0}),
indexedAttestation(8, 3, []uint64{1}),
indexedAttestation(7, 4, []uint64{2}),
indexedAttestation(5, 1, []uint64{3}),
},
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
Expand Down

0 comments on commit 2976bf7

Please sign in to comment.