mirror of
https://github.com/OffchainLabs/prysm.git
synced 2026-01-10 07:58:22 -05:00
Source lrg target (#7839)
* 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>
This commit is contained in:
@@ -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
|
||||
@@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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")
|
||||
@@ -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
|
||||
@@ -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))
|
||||
@@ -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)
|
||||
|
||||
@@ -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) {
|
||||
@@ -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: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{0, 1, 2, 3},
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 7,
|
||||
Root: []byte("good source"),
|
||||
},
|
||||
Target: ðpb.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: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{0, 1, 2, 3},
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 9,
|
||||
Root: []byte("good source"),
|
||||
},
|
||||
Target: ðpb.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: ðpb.IndexedAttestation{
|
||||
AttestingIndices: []uint64{0, 1, 2, 3},
|
||||
Data: ðpb.AttestationData{
|
||||
Source: ðpb.Checkpoint{
|
||||
Epoch: 2,
|
||||
Root: []byte("good source"),
|
||||
},
|
||||
Target: ðpb.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) {
|
||||
|
||||
Reference in New Issue
Block a user