mirror of
https://github.com/status-im/nimbus-eth2.git
synced 2025-02-26 13:15:16 +00:00
update attestation extended validation to v1.0.0-rc.0 (#1889)
* update attestation extended validation to v1.0.0-rc.0 * attestation block and target must be within same epoch * remove duplicate attestation epoch/target epoch check * in spec now
This commit is contained in:
parent
58dcca3364
commit
5b13a5ba10
@ -163,21 +163,24 @@ func check_attestation_subnet(
|
|||||||
|
|
||||||
ok()
|
ok()
|
||||||
|
|
||||||
# https://github.com/ethereum/eth2.0-specs/blob/v0.12.2/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id
|
# https://github.com/ethereum/eth2.0-specs/blob/v1.0.0-rc.0/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id
|
||||||
proc validateAttestation*(
|
proc validateAttestation*(
|
||||||
pool: var AttestationPool,
|
pool: var AttestationPool,
|
||||||
attestation: Attestation, wallTime: BeaconTime,
|
attestation: Attestation, wallTime: BeaconTime,
|
||||||
topicCommitteeIndex: uint64):
|
topicCommitteeIndex: uint64):
|
||||||
Result[HashSet[ValidatorIndex], (ValidationResult, cstring)] =
|
Result[HashSet[ValidatorIndex], (ValidationResult, cstring)] =
|
||||||
|
# [REJECT] The attestation's epoch matches its target -- i.e.
|
||||||
|
# attestation.data.target.epoch ==
|
||||||
|
# compute_epoch_at_slot(attestation.data.slot)
|
||||||
block:
|
block:
|
||||||
let v = check_attestation_slot_target(attestation.data) # Not in spec
|
let v = check_attestation_slot_target(attestation.data)
|
||||||
if v.isErr():
|
if v.isErr():
|
||||||
return err((EVRESULT_IGNORE, v.error))
|
return err((EVRESULT_REJECT, v.error))
|
||||||
|
|
||||||
# attestation.data.slot is within the last ATTESTATION_PROPAGATION_SLOT_RANGE
|
# attestation.data.slot is within the last ATTESTATION_PROPAGATION_SLOT_RANGE
|
||||||
# slots (within a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e.
|
# slots (within a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e.
|
||||||
# attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot
|
# attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot
|
||||||
# >= attestation.data.slot (a client MAY queue future attestations for\
|
# >= attestation.data.slot (a client MAY queue future attestations for
|
||||||
# processing at the appropriate slot).
|
# processing at the appropriate slot).
|
||||||
? check_propagation_slot_range(attestation.data, wallTime) # [IGNORE]
|
? check_propagation_slot_range(attestation.data, wallTime) # [IGNORE]
|
||||||
|
|
||||||
@ -186,13 +189,6 @@ proc validateAttestation*(
|
|||||||
# if bit == 0b1]) == 1).
|
# if bit == 0b1]) == 1).
|
||||||
? check_aggregation_count(attestation, singular = true) # [REJECT]
|
? check_aggregation_count(attestation, singular = true) # [REJECT]
|
||||||
|
|
||||||
# The block being voted for (attestation.data.beacon_block_root) has been seen
|
|
||||||
# (via both gossip and non-gossip sources) (a client MAY queue aggregates for
|
|
||||||
# processing once block is retrieved).
|
|
||||||
# The block being voted for (attestation.data.beacon_block_root) passes
|
|
||||||
# validation.
|
|
||||||
? check_attestation_beacon_block(pool, attestation) # [IGNORE/REJECT]
|
|
||||||
|
|
||||||
let tgtBlck = pool.chainDag.getRef(attestation.data.target.root)
|
let tgtBlck = pool.chainDag.getRef(attestation.data.target.root)
|
||||||
if tgtBlck.isNil:
|
if tgtBlck.isNil:
|
||||||
pool.quarantine.addMissing(attestation.data.target.root)
|
pool.quarantine.addMissing(attestation.data.target.root)
|
||||||
@ -211,6 +207,13 @@ proc validateAttestation*(
|
|||||||
let epochRef = pool.chainDag.getEpochRef(
|
let epochRef = pool.chainDag.getEpochRef(
|
||||||
tgtBlck, attestation.data.target.epoch)
|
tgtBlck, attestation.data.target.epoch)
|
||||||
|
|
||||||
|
# [REJECT] The committee index is within the expected range -- i.e.
|
||||||
|
# data.index < get_committee_count_per_slot(state, data.target.epoch).
|
||||||
|
if not (attestation.data.index < get_committee_count_per_slot(epochRef)):
|
||||||
|
const err_str: cstring =
|
||||||
|
"validateAttestation: committee index not within expected range"
|
||||||
|
return err((EVRESULT_REJECT, err_str))
|
||||||
|
|
||||||
# [REJECT] The attestation is for the correct subnet -- i.e.
|
# [REJECT] The attestation is for the correct subnet -- i.e.
|
||||||
# compute_subnet_for_attestation(committees_per_slot,
|
# compute_subnet_for_attestation(committees_per_slot,
|
||||||
# attestation.data.slot, attestation.data.index) == subnet_id, where
|
# attestation.data.slot, attestation.data.index) == subnet_id, where
|
||||||
@ -219,6 +222,26 @@ proc validateAttestation*(
|
|||||||
# committee information for the signature check.
|
# committee information for the signature check.
|
||||||
? check_attestation_subnet(epochRef, attestation, topicCommitteeIndex)
|
? check_attestation_subnet(epochRef, attestation, topicCommitteeIndex)
|
||||||
|
|
||||||
|
# [REJECT] The number of aggregation bits matches the committee size -- i.e.
|
||||||
|
# len(attestation.aggregation_bits) == len(get_beacon_committee(state,
|
||||||
|
# data.slot, data.index)).
|
||||||
|
#
|
||||||
|
# This uses the same epochRef as data.target.epoch, because the attestation's
|
||||||
|
# epoch matches its target and attestation.data.target.root is an ancestor of
|
||||||
|
# attestation.data.beacon_block_root.
|
||||||
|
if not (attestation.aggregation_bits.lenu64 == get_beacon_committee_len(
|
||||||
|
epochRef, attestation.data.slot, attestation.data.index.CommitteeIndex)):
|
||||||
|
const err_str: cstring =
|
||||||
|
"validateAttestation: number of aggregation bits and committee size mismatch"
|
||||||
|
return err((EVRESULT_REJECT, err_str))
|
||||||
|
|
||||||
|
# The block being voted for (attestation.data.beacon_block_root) has been seen
|
||||||
|
# (via both gossip and non-gossip sources) (a client MAY queue aggregates for
|
||||||
|
# processing once block is retrieved).
|
||||||
|
# The block being voted for (attestation.data.beacon_block_root) passes
|
||||||
|
# validation.
|
||||||
|
? check_attestation_beacon_block(pool, attestation) # [IGNORE/REJECT]
|
||||||
|
|
||||||
let
|
let
|
||||||
fork = pool.chainDag.headState.data.data.fork
|
fork = pool.chainDag.headState.data.data.fork
|
||||||
genesis_validators_root =
|
genesis_validators_root =
|
||||||
@ -226,11 +249,8 @@ proc validateAttestation*(
|
|||||||
attesting_indices = get_attesting_indices(
|
attesting_indices = get_attesting_indices(
|
||||||
epochRef, attestation.data, attestation.aggregation_bits)
|
epochRef, attestation.data, attestation.aggregation_bits)
|
||||||
|
|
||||||
if attesting_indices.len == 0:
|
# The number of aggregation bits matches the committee size, which ensures
|
||||||
# an extension of the check_aggregation_count() check
|
# this condition holds.
|
||||||
const err_str: cstring =
|
|
||||||
"validateAttestation: inconsistent aggregation and committee length"
|
|
||||||
return err((EVRESULT_REJECT, err_str))
|
|
||||||
doAssert attesting_indices.len == 1, "Per bits check above"
|
doAssert attesting_indices.len == 1, "Per bits check above"
|
||||||
let validator_index = toSeq(attesting_indices)[0]
|
let validator_index = toSeq(attesting_indices)[0]
|
||||||
|
|
||||||
@ -254,6 +274,24 @@ proc validateAttestation*(
|
|||||||
if v.isErr():
|
if v.isErr():
|
||||||
return err((EVRESULT_REJECT, v.error))
|
return err((EVRESULT_REJECT, v.error))
|
||||||
|
|
||||||
|
# [REJECT] The attestation's target block is an ancestor of the block named
|
||||||
|
# in the LMD vote -- i.e. get_ancestor(store,
|
||||||
|
# attestation.data.beacon_block_root,
|
||||||
|
# compute_start_slot_at_epoch(attestation.data.target.epoch)) ==
|
||||||
|
# attestation.data.target.root
|
||||||
|
let attestationBlck = pool.chainDag.getRef(attestation.data.beacon_block_root)
|
||||||
|
|
||||||
|
# already checked in check_attestation_beacon_block()
|
||||||
|
doAssert not attestationBlck.isNil
|
||||||
|
|
||||||
|
if not (get_ancestor(attestationBlck,
|
||||||
|
compute_start_slot_at_epoch(attestation.data.target.epoch),
|
||||||
|
SLOTS_PER_EPOCH.int).root ==
|
||||||
|
attestation.data.target.root):
|
||||||
|
const err_str: cstring =
|
||||||
|
"validateAttestation: attestation's target block not an ancestor of LMD vote block"
|
||||||
|
return err((EVRESULT_REJECT, err_str))
|
||||||
|
|
||||||
# Only valid attestations go in the list
|
# Only valid attestations go in the list
|
||||||
if pool.lastVotedEpoch.len <= validator_index.int:
|
if pool.lastVotedEpoch.len <= validator_index.int:
|
||||||
pool.lastVotedEpoch.setLen(validator_index.int + 1)
|
pool.lastVotedEpoch.setLen(validator_index.int + 1)
|
||||||
|
@ -184,8 +184,10 @@ func isAncestorOf*(a, b: BlockRef): bool =
|
|||||||
doAssert b.slot > b.parent.slot
|
doAssert b.slot > b.parent.slot
|
||||||
b = b.parent
|
b = b.parent
|
||||||
|
|
||||||
func get_ancestor*(blck: BlockRef, slot: Slot): BlockRef =
|
func get_ancestor*(blck: BlockRef, slot: Slot,
|
||||||
## https://github.com/ethereum/eth2.0-specs/blob/v0.12.3/specs/phase0/fork-choice.md#get_ancestor
|
maxDepth = 100'i64 * 365 * 24 * 60 * 60 div SECONDS_PER_SLOT.int):
|
||||||
|
BlockRef =
|
||||||
|
## https://github.com/ethereum/eth2.0-specs/blob/v1.0.0-rc.0/specs/phase0/fork-choice.md#get_ancestor
|
||||||
## Return the most recent block as of the time at `slot` that not more recent
|
## Return the most recent block as of the time at `slot` that not more recent
|
||||||
## than `blck` itself
|
## than `blck` itself
|
||||||
doAssert not blck.isNil
|
doAssert not blck.isNil
|
||||||
@ -193,7 +195,6 @@ func get_ancestor*(blck: BlockRef, slot: Slot): BlockRef =
|
|||||||
var blck = blck
|
var blck = blck
|
||||||
|
|
||||||
var depth = 0
|
var depth = 0
|
||||||
const maxDepth = (100'i64 * 365 * 24 * 60 * 60 div SECONDS_PER_SLOT.int)
|
|
||||||
|
|
||||||
while true:
|
while true:
|
||||||
if blck.slot <= slot:
|
if blck.slot <= slot:
|
||||||
|
Loading…
x
Reference in New Issue
Block a user