doppelganger detection walltime refactor (#2656)

* strawman doppelganger detection walltime refactor

* move DoppelgangerProtection to Eth2Processor

* increase comment precision

* document difference between broadcastStartEpoch and nodeLaunchSlot, and allow for one-slot overlap to avoid false positives on intra-slot restarts
This commit is contained in:
tersec 2021-06-17 11:51:04 +00:00 committed by GitHub
parent 53d05060c9
commit 87ed9e62a1
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 23 additions and 14 deletions

View File

@ -45,6 +45,18 @@ declareHistogram beacon_block_delay,
"Time(s) between slot start and beacon block reception", buckets = delayBuckets
type
DoppelgangerProtection = object
broadcastStartEpoch*: Epoch ##\
## Set anew, each time gossip is re-enabled after syncing completes, so
## might reset multiple times per instance. This allows some safe level
## of gossip interleaving between nodes so long as they don't gossip at
## the same time.
nodeLaunchSlot: Slot ##\
## Set once, at node launch. This functions as a basic protection against
## false positives from attestations persisting within the gossip network
## across quick restarts.
Eth2Processor* = object
doppelGangerDetectionEnabled*: bool
getWallTime*: GetWallTimeFn
@ -88,6 +100,8 @@ proc new*(T: type Eth2Processor,
getWallTime: GetWallTimeFn): ref Eth2Processor =
(ref Eth2Processor)(
doppelGangerDetectionEnabled: doppelGangerDetectionEnabled,
doppelgangerDetection: DoppelgangerProtection(
nodeLaunchSlot: getWallTime().slotOrZero),
getWallTime: getWallTime,
blockProcessor: blockProcessor,
dag: dag,
@ -158,15 +172,15 @@ proc blockValidator*(
proc checkForPotentialDoppelganger(
self: var Eth2Processor, attestation: Attestation,
attesterIndices: openArray[ValidatorIndex], wallSlot: Slot) =
let epoch = wallSlot.epoch
# Only check for current epoch, not potential attestations bouncing around
# from up to several minutes prior.
if attestation.data.slot.epoch < epoch:
attesterIndices: openArray[ValidatorIndex]) =
# Only check for attestations after node launch. There might be one slot of
# overlap in quick intra-slot restarts so trade off a few true negatives in
# the service of avoiding more likely false positives.
if attestation.data.slot <= self.doppelgangerDetection.nodeLaunchSlot + 1:
return
if epoch < self.doppelgangerDetection.broadcastStartEpoch:
if attestation.data.slot.epoch <
self.doppelgangerDetection.broadcastStartEpoch:
let tgtBlck = self.dag.getRef(attestation.data.target.root)
doAssert not tgtBlck.isNil # because attestation is valid above
@ -219,8 +233,7 @@ proc attestationValidator*(
let (attestation_index, sig) = v.get()
self[].checkForPotentialDoppelganger(
attestation, [attestation_index], wallSlot)
self[].checkForPotentialDoppelganger(attestation, [attestation_index])
trace "Attestation validated"
self.attestationPool[].addAttestation(
@ -267,8 +280,7 @@ proc aggregateValidator*(
let (attesting_indices, sig) = v.get()
self[].checkForPotentialDoppelganger(
signedAggregateAndProof.message.aggregate, attesting_indices,
wallSlot)
signedAggregateAndProof.message.aggregate, attesting_indices)
trace "Aggregate validated",
aggregator_index = signedAggregateAndProof.message.aggregator_index,

View File

@ -470,9 +470,6 @@ type
current_justified_checkpoint*: Checkpoint
finalized_checkpoint*: Checkpoint
DoppelgangerProtection* = object
broadcastStartEpoch*: Epoch
type
# Caches for computing justificiation, rewards and penalties - based on
# implementation in Lighthouse: