fix subnet calculation in RPC and insert broadcast attestations into node's pool (#2207)
* fix subnet calculation in RPC and insert broadcast attestations into node's pool * unify codepaths to ensure only mostly-checked-to-be-valid attestations enter the pool, even from node's own broadcasts * update attestation pool tests for new validateAttestation param
This commit is contained in:
parent
afbaa36ef7
commit
97c4f7c5c0
|
@ -162,7 +162,7 @@ func check_attestation_subnet(
|
||||||
proc validateAttestation*(
|
proc validateAttestation*(
|
||||||
pool: var AttestationPool,
|
pool: var AttestationPool,
|
||||||
attestation: Attestation, wallTime: BeaconTime,
|
attestation: Attestation, wallTime: BeaconTime,
|
||||||
topicCommitteeIndex: uint64):
|
topicCommitteeIndex: uint64, checksExpensive: bool):
|
||||||
Result[HashSet[ValidatorIndex], (ValidationResult, cstring)] =
|
Result[HashSet[ValidatorIndex], (ValidationResult, cstring)] =
|
||||||
# [REJECT] The attestation's epoch matches its target -- i.e.
|
# [REJECT] The attestation's epoch matches its target -- i.e.
|
||||||
# attestation.data.target.epoch ==
|
# attestation.data.target.epoch ==
|
||||||
|
@ -258,6 +258,9 @@ proc validateAttestation*(
|
||||||
return err((ValidationResult.Ignore, cstring(
|
return err((ValidationResult.Ignore, cstring(
|
||||||
"Validator has already voted in epoch")))
|
"Validator has already voted in epoch")))
|
||||||
|
|
||||||
|
if not checksExpensive:
|
||||||
|
return ok(attesting_indices)
|
||||||
|
|
||||||
# The signature of attestation is valid.
|
# The signature of attestation is valid.
|
||||||
block:
|
block:
|
||||||
let v = is_valid_indexed_attestation(
|
let v = is_valid_indexed_attestation(
|
||||||
|
|
|
@ -288,7 +288,8 @@ proc blockValidator*(
|
||||||
proc attestationValidator*(
|
proc attestationValidator*(
|
||||||
self: var Eth2Processor,
|
self: var Eth2Processor,
|
||||||
attestation: Attestation,
|
attestation: Attestation,
|
||||||
committeeIndex: uint64): ValidationResult =
|
committeeIndex: uint64,
|
||||||
|
checksExpensive: bool = true): ValidationResult =
|
||||||
logScope:
|
logScope:
|
||||||
attestation = shortLog(attestation)
|
attestation = shortLog(attestation)
|
||||||
committeeIndex
|
committeeIndex
|
||||||
|
@ -307,7 +308,7 @@ proc attestationValidator*(
|
||||||
let delay = wallTime - attestation.data.slot.toBeaconTime
|
let delay = wallTime - attestation.data.slot.toBeaconTime
|
||||||
debug "Attestation received", delay
|
debug "Attestation received", delay
|
||||||
let v = self.attestationPool[].validateAttestation(
|
let v = self.attestationPool[].validateAttestation(
|
||||||
attestation, wallTime, committeeIndex)
|
attestation, wallTime, committeeIndex, checksExpensive)
|
||||||
if v.isErr():
|
if v.isErr():
|
||||||
debug "Dropping attestation", err = v.error()
|
debug "Dropping attestation", err = v.error()
|
||||||
return v.error[0]
|
return v.error[0]
|
||||||
|
|
|
@ -181,8 +181,6 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
|
||||||
vc.attestationsForEpoch[epoch].contains slot:
|
vc.attestationsForEpoch[epoch].contains slot:
|
||||||
var validatorToAttestationDataRoot: Table[ValidatorPubKey, Eth2Digest]
|
var validatorToAttestationDataRoot: Table[ValidatorPubKey, Eth2Digest]
|
||||||
for a in vc.attestationsForEpoch[epoch][slot]:
|
for a in vc.attestationsForEpoch[epoch][slot]:
|
||||||
notice "Attesting", slot = slot, public_key = a.public_key
|
|
||||||
|
|
||||||
let validator = vc.attachedValidators.validators[a.public_key]
|
let validator = vc.attachedValidators.validators[a.public_key]
|
||||||
let ad = await vc.client.get_v1_validator_attestation_data(slot, a.committee_index)
|
let ad = await vc.client.get_v1_validator_attestation_data(slot, a.committee_index)
|
||||||
|
|
||||||
|
@ -206,6 +204,8 @@ proc onSlotStart(vc: ValidatorClient, lastSlot, scheduledSlot: Slot) {.gcsafe, a
|
||||||
ad, a.committee_length.int, a.validator_committee_index,
|
ad, a.committee_length.int, a.validator_committee_index,
|
||||||
vc.fork, vc.beaconGenesis.genesis_validators_root)
|
vc.fork, vc.beaconGenesis.genesis_validators_root)
|
||||||
|
|
||||||
|
notice "Attesting",
|
||||||
|
slot, public_key = a.public_key, attestation = shortLog(attestation)
|
||||||
discard await vc.client.post_v1_beacon_pool_attestations(attestation)
|
discard await vc.client.post_v1_beacon_pool_attestations(attestation)
|
||||||
|
|
||||||
validatorToAttestationDataRoot[a.public_key] = attestation.data.hash_tree_root
|
validatorToAttestationDataRoot[a.public_key] = attestation.data.hash_tree_root
|
||||||
|
|
|
@ -142,7 +142,11 @@ proc installValidatorApiHandlers*(rpcServer: RpcServer, node: BeaconNode) =
|
||||||
raise newException(CatchableError,
|
raise newException(CatchableError,
|
||||||
"Invalid slot signature")
|
"Invalid slot signature")
|
||||||
|
|
||||||
let subnet = committee_index.uint8
|
let
|
||||||
|
head = node.doChecksAndGetCurrentHead(epoch)
|
||||||
|
epochRef = node.chainDag.getEpochRef(head, epoch)
|
||||||
|
let subnet = compute_subnet_for_attestation(
|
||||||
|
get_committee_count_per_slot(epochRef), slot, committee_index).uint8
|
||||||
if subnet notin node.attestationSubnets.subscribedSubnets[0] and
|
if subnet notin node.attestationSubnets.subscribedSubnets[0] and
|
||||||
subnet notin node.attestationSubnets.subscribedSubnets[1]:
|
subnet notin node.attestationSubnets.subscribedSubnets[1]:
|
||||||
await node.network.subscribe(getAttestationTopic(
|
await node.network.subscribe(getAttestationTopic(
|
||||||
|
|
|
@ -89,15 +89,6 @@ func getAttestationTopic*(forkDigest: ForkDigest, subnetIndex: uint64):
|
||||||
except ValueError as e:
|
except ValueError as e:
|
||||||
raiseAssert e.msg
|
raiseAssert e.msg
|
||||||
|
|
||||||
func getAttestationTopic*(forkDigest: ForkDigest,
|
|
||||||
attestation: Attestation,
|
|
||||||
num_active_validators: uint64): string =
|
|
||||||
getAttestationTopic(
|
|
||||||
forkDigest,
|
|
||||||
compute_subnet_for_attestation(
|
|
||||||
get_committee_count_per_slot(num_active_validators),
|
|
||||||
attestation.data.slot, attestation.data.index.CommitteeIndex))
|
|
||||||
|
|
||||||
func get_committee_assignments(
|
func get_committee_assignments(
|
||||||
state: BeaconState, epoch: Epoch,
|
state: BeaconState, epoch: Epoch,
|
||||||
validator_indices: HashSet[ValidatorIndex]):
|
validator_indices: HashSet[ValidatorIndex]):
|
||||||
|
|
|
@ -19,7 +19,8 @@ import
|
||||||
|
|
||||||
# Local modules
|
# Local modules
|
||||||
./spec/[
|
./spec/[
|
||||||
datatypes, digest, crypto, helpers, network, signatures, state_transition],
|
datatypes, digest, crypto, helpers, network, signatures, state_transition,
|
||||||
|
validator],
|
||||||
./conf, ./time, ./validator_pool,
|
./conf, ./time, ./validator_pool,
|
||||||
./attestation_pool, ./exit_pool,
|
./attestation_pool, ./exit_pool,
|
||||||
./block_pools/[spec_cache, chain_dag, clearance],
|
./block_pools/[spec_cache, chain_dag, clearance],
|
||||||
|
@ -152,9 +153,16 @@ proc isSynced*(node: BeaconNode, head: BlockRef): bool =
|
||||||
|
|
||||||
proc sendAttestation*(
|
proc sendAttestation*(
|
||||||
node: BeaconNode, attestation: Attestation, num_active_validators: uint64) =
|
node: BeaconNode, attestation: Attestation, num_active_validators: uint64) =
|
||||||
|
let subnet_index =
|
||||||
|
compute_subnet_for_attestation(
|
||||||
|
get_committee_count_per_slot(num_active_validators), attestation.data.slot,
|
||||||
|
attestation.data.index.CommitteeIndex)
|
||||||
node.network.broadcast(
|
node.network.broadcast(
|
||||||
getAttestationTopic(node.forkDigest, attestation, num_active_validators),
|
getAttestationTopic(node.forkDigest, subnet_index), attestation)
|
||||||
attestation)
|
|
||||||
|
# Ensure node's own broadcast attestations end up in its attestation pool
|
||||||
|
discard node.processor[].attestationValidator(
|
||||||
|
attestation, subnet_index, false)
|
||||||
|
|
||||||
beacon_attestations_sent.inc()
|
beacon_attestations_sent.inc()
|
||||||
|
|
||||||
|
|
|
@ -438,22 +438,22 @@ suiteReport "Attestation validation " & preset():
|
||||||
beaconTime = attestation.data.slot.toBeaconTime()
|
beaconTime = attestation.data.slot.toBeaconTime()
|
||||||
|
|
||||||
check:
|
check:
|
||||||
validateAttestation(pool[], attestation, beaconTime, subnet).isOk
|
validateAttestation(pool[], attestation, beaconTime, subnet, true).isOk
|
||||||
|
|
||||||
# Same validator again
|
# Same validator again
|
||||||
validateAttestation(pool[], attestation, beaconTime, subnet).error()[0] ==
|
validateAttestation(pool[], attestation, beaconTime, subnet, true).error()[0] ==
|
||||||
ValidationResult.Ignore
|
ValidationResult.Ignore
|
||||||
|
|
||||||
pool[].nextAttestationEpoch.setLen(0) # reset for test
|
pool[].nextAttestationEpoch.setLen(0) # reset for test
|
||||||
check:
|
check:
|
||||||
# Wrong subnet
|
# Wrong subnet
|
||||||
validateAttestation(pool[], attestation, beaconTime, subnet + 1).isErr
|
validateAttestation(pool[], attestation, beaconTime, subnet + 1, true).isErr
|
||||||
|
|
||||||
pool[].nextAttestationEpoch.setLen(0) # reset for test
|
pool[].nextAttestationEpoch.setLen(0) # reset for test
|
||||||
check:
|
check:
|
||||||
# Too far in the future
|
# Too far in the future
|
||||||
validateAttestation(
|
validateAttestation(
|
||||||
pool[], attestation, beaconTime - 1.seconds, subnet + 1).isErr
|
pool[], attestation, beaconTime - 1.seconds, subnet + 1, true).isErr
|
||||||
|
|
||||||
pool[].nextAttestationEpoch.setLen(0) # reset for test
|
pool[].nextAttestationEpoch.setLen(0) # reset for test
|
||||||
check:
|
check:
|
||||||
|
@ -461,4 +461,4 @@ suiteReport "Attestation validation " & preset():
|
||||||
validateAttestation(
|
validateAttestation(
|
||||||
pool[], attestation,
|
pool[], attestation,
|
||||||
beaconTime - (SECONDS_PER_SLOT * SLOTS_PER_EPOCH - 1).int.seconds,
|
beaconTime - (SECONDS_PER_SLOT * SLOTS_PER_EPOCH - 1).int.seconds,
|
||||||
subnet + 1).isErr
|
subnet + 1, true).isErr
|
||||||
|
|
Loading…
Reference in New Issue