Skip to content

Commit

Permalink
Add attestation slashing protection support
Browse files Browse the repository at this point in the history
  • Loading branch information
mratsim committed Sep 15, 2020
1 parent 3d194d5 commit e4ed246
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 31 deletions.
17 changes: 8 additions & 9 deletions beacon_chain/beacon_node.nim
Original file line number Diff line number Diff line change
Expand Up @@ -269,16 +269,15 @@ proc init*(T: type BeaconNode,
topicAggregateAndProofs: topicAggregateAndProofs,
)


res.attachedValidators = ValidatorPool.init(
SlashingProtectionDB.init(
chainDag.headState.data.data.genesis_validators_root,
when UseSlashingProtection:
kvStore SqStoreRef.init(conf.validatorsDir(), "slashing_protection").tryGet()
else:
KvStoreRef()
)
res.attachedValidators = ValidatorPool.init(
SlashingProtectionDB.init(
chainDag.headState.data.data.genesis_validators_root,
when UseSlashingProtection:
kvStore SqStoreRef.init(conf.validatorsDir(), "slashing_protection").tryGet()
else:
KvStoreRef()
)
)

proc getWallTime(): BeaconTime = res.beaconClock.now()

Expand Down
35 changes: 27 additions & 8 deletions beacon_chain/validator_client.nim
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,7 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
)
newBlock.root = hash_tree_root(newBlock.message)

# TODO: recomputed in block proposal
# TODO: signing_root is recomputed in signBlockProposal just after
let signing_root = compute_block_root(vc.fork, vc.beaconGenesis.genesis_validators_root, slot, newBlock.root)
vc.attachedValidators
.slashingProtection
Expand All @@ -159,7 +159,7 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a

discard await vc.client.post_v1_validator_block(newBlock)
else:
warn "Slashing protection activated",
warn "Slashing protection activated for block proposal",
validator = public_key,
slot = slot,
existingProposal = notSlashable.error
Expand All @@ -182,12 +182,31 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
let validator = vc.attachedValidators.validators[a.public_key]
let ad = await vc.client.get_v1_validator_attestation(slot, a.committee_index)

# TODO I don't like these (u)int64-to-int conversions...
let attestation = await validator.produceAndSignAttestation(
ad, a.committee_length.int, a.validator_committee_index.int,
vc.fork, vc.beaconGenesis.genesis_validators_root)

discard await vc.client.post_v1_beacon_pool_attestations(attestation)
let notSlashable = vc.attachedValidators
.slashingProtection
.notSlashableAttestation(
a.public_key,
ad.source.epoch,
ad.target.epoch)
if notSlashable.isOk():
# TODO signing_root is recomputed in produceAndSignAttestation/signAttestation just after
let signing_root = compute_attestation_root(
vc.fork, vc.beaconGenesis.genesis_validators_root, ad)
vc.attachedValidators
.slashingProtection
.registerAttestation(
a.public_key, ad.source.epoch, ad.target.epoch, signing_root)

# TODO I don't like these (u)int64-to-int conversions...
let attestation = await validator.produceAndSignAttestation(
ad, a.committee_length.int, a.validator_committee_index.int,
vc.fork, vc.beaconGenesis.genesis_validators_root)

discard await vc.client.post_v1_beacon_pool_attestations(attestation)
else:
warn "Slashing protection activated for attestation",
validator = a.public_key,
badVoteDetails = $notSlashable.error

except CatchableError as err:
warn "Caught an unexpected error", err = err.msg, slot = shortLog(slot)
Expand Down
20 changes: 16 additions & 4 deletions beacon_chain/validator_duties.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@

import
# Standard library
std/[os, tables, strutils, sequtils, osproc, streams],
std/[os, tables, sequtils, osproc, streams],

# Nimble packages
stew/[objects], stew/shims/macros,
Expand Down Expand Up @@ -398,9 +398,21 @@ proc handleAttestations(node: BeaconNode, head: BlockRef, slot: Slot) =
attestations.add((ad, committee.len, index_in_committee, validator))

for a in attestations:
traceAsyncErrors createAndSendAttestation(
node, fork, genesis_validators_root, a.validator, a.data,
a.committeeLen, a.indexInCommittee, num_active_validators)
let notSlashable = node.attachedValidators
.slashingProtection
.notSlashableAttestation(
a.validator.pubkey,
a.data.source.epoch,
a.data.target.epoch)

if notSlashable.isOk():
traceAsyncErrors createAndSendAttestation(
node, fork, genesis_validators_root, a.validator, a.data,
a.committeeLen, a.indexInCommittee, num_active_validators)
else:
warn "Slashing protection activated for attestation",
validator = a.validator.pubkey,
badVoteDetails = $notSlashable.error

proc handleProposal(node: BeaconNode, head: BlockRef, slot: Slot):
Future[BlockRef] {.async.} =
Expand Down
25 changes: 15 additions & 10 deletions beacon_chain/validator_slashing_protection.nim
Original file line number Diff line number Diff line change
Expand Up @@ -160,10 +160,11 @@ type
BadVote* = object
case kind*: BadVoteKind
of DoubleVote:
existingAttRoot*: Eth2Digest
existingAttestation*: Eth2Digest
of SurroundedVote, SurroundingVote:
exampleAttRoot*: Eth2Digest # Many roots might be in conflict
source*, target*: Epoch
existingAttestationRoot*: Eth2Digest # Many roots might be in conflict
sourceExisting*, targetExisting*: Epoch
sourceSlashable*, targetSlashable*: Epoch
of TargetPrecedesSource:
discard

Expand Down Expand Up @@ -421,7 +422,7 @@ proc notSlashableAttestationImpl(
# Logged by caller
return err(BadVote(
kind: DoubleVote,
existingAttRoot: foundAttestation.unsafeGet().attestation_root
existingAttestation: foundAttestation.unsafeGet().attestation_root
))

# TODO: we hack KV-store range queries
Expand Down Expand Up @@ -494,9 +495,11 @@ proc notSlashableAttestationImpl(
# Logged by caller
return err(BadVote(
kind: SurroundingVote,
exampleAttRoot: ar1,
source: s1,
target: t2
existingAttestationRoot: ar1,
sourceExisting: s1,
targetExisting: t1,
sourceSlashable: s2,
targetSlashable: t2
))

# Next iteration
Expand All @@ -523,9 +526,11 @@ proc notSlashableAttestationImpl(
# Logged by caller
return err(BadVote(
kind: SurroundedVote,
exampleAttRoot: ar1,
source: s1,
target: t2
existingAttestationRoot: ar1,
sourceExisting: s1,
targetExisting: t1,
sourceSlashable: s2,
targetSlashable: t2
))

# Next iteration
Expand Down

0 comments on commit e4ed246

Please sign in to comment.