avoid attestation pool copy in check (#1755)

This commit is contained in:
Jacek Sieka 2020-09-25 19:51:44 +02:00 committed by GitHub
parent 94120ad011
commit c472d5368b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 34 additions and 14 deletions

View File

@ -8,7 +8,8 @@
{.push raises: [Defect].}
import
options, chronos, chronicles,
std/[options, sequtils, sets],
chronos, chronicles,
./spec/[
beaconstate, datatypes, crypto, digest, helpers, network, validator,
signatures],
@ -192,19 +193,6 @@ proc validateAttestation*(
# validation.
? check_attestation_beacon_block(pool, attestation) # [IGNORE/REJECT]
# The attestation is the first valid attestation received for the
# participating validator for the slot, attestation.data.slot.
let maybeAttestationsSeen = getAttestationsForSlot(pool, attestation.data.slot)
if maybeAttestationsSeen.isSome:
for attestationEntry in maybeAttestationsSeen.get.attestations:
if attestation.data != attestationEntry.data:
continue
# Attestations might be aggregated eagerly or lazily; allow for both.
for validation in attestationEntry.validations:
if attestation.aggregation_bits.isSubsetOf(validation.aggregation_bits):
const err_str: cstring = "Attestation already exists at slot"
return err((EVRESULT_IGNORE, err_str))
let tgtBlck = pool.chainDag.getRef(attestation.data.target.root)
if tgtBlck.isNil:
pool.quarantine.addMissing(attestation.data.target.root)
@ -238,6 +226,21 @@ proc validateAttestation*(
attesting_indices = get_attesting_indices(
epochRef, attestation.data, attestation.aggregation_bits)
doAssert attesting_indices.len == 1, "Per bits check above"
let validator_index = toSeq(attesting_indices)[0]
# There has been no other valid attestation seen on an attestation subnet
# that has an identical `attestation.data.target.epoch` and participating
# validator index.
# Slightly modified to allow only newer attestations than were previously
# seen (no point in propagating older votes)
if (pool.lastVotedEpoch.len > validator_index.int) and
pool.lastVotedEpoch[validator_index.int].isSome() and
(pool.lastVotedEpoch[validator_index.int].get() >=
attestation.data.target.epoch):
const err_str: cstring = "Validator has already voted in epoch"
return err((EVRESULT_IGNORE, err_str))
# The signature of attestation is valid.
block:
let v = is_valid_indexed_attestation(
@ -246,6 +249,11 @@ proc validateAttestation*(
if v.isErr():
return err((EVRESULT_REJECT, v.error))
# Only valid attestations go in the list
if pool.lastVotedEpoch.len <= validator_index.int:
pool.lastVotedEpoch.setLen(validator_index.int + 1)
pool.lastVotedEpoch[validator_index] = some(attestation.data.target.epoch)
ok(attesting_indices)
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof

View File

@ -69,6 +69,8 @@ type
forkChoice*: ForkChoice
lastVotedEpoch*: seq[Option[Epoch]] # Sequence based on validator indices
ExitPool* = object
## The exit pool tracks attester slashings, proposer slashings, and
## voluntary exits that could be added to a proposed block.

View File

@ -441,13 +441,23 @@ suiteReport "Attestation validation " & preset():
check:
validateAttestation(pool[], attestation, beaconTime, subnet).isOk
# Same validator again
validateAttestation(pool[], attestation, beaconTime, subnet).error()[0] ==
EVRESULT_IGNORE
pool[].lastVotedEpoch.setLen(0) # reset for test
check:
# Wrong subnet
validateAttestation(pool[], attestation, beaconTime, subnet + 1).isErr
pool[].lastVotedEpoch.setLen(0) # reset for test
check:
# Too far in the future
validateAttestation(
pool[], attestation, beaconTime - 1.seconds, subnet + 1).isErr
pool[].lastVotedEpoch.setLen(0) # reset for test
check:
# Too far in the past
validateAttestation(
pool[], attestation,