update gossip validation for v1.4.0-beta.0 (#5133)

Co-authored-by: Etan Kissling <etan@status.im>
This commit is contained in:
tersec 2023-06-29 08:34:21 +00:00 committed by GitHub
parent 7b0e3b1c04
commit dc5687093f
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
1 changed files with 72 additions and 33 deletions

View File

@ -82,25 +82,55 @@ func check_attestation_block(
ok()
func check_propagation_slot_range(
msgSlot: Slot, wallTime: BeaconTime): Result[Slot, ValidationError] =
let
futureSlot = (wallTime + MAXIMUM_GOSSIP_CLOCK_DISPARITY).toSlot()
consensusFork: ConsensusFork, msgSlot: Slot, wallTime: BeaconTime):
Result[Slot, ValidationError] =
let futureSlot = (wallTime + MAXIMUM_GOSSIP_CLOCK_DISPARITY).toSlot()
if not futureSlot.afterGenesis or msgSlot > futureSlot.slot:
return errIgnore("Attestation slot in the future")
let
pastSlot = (wallTime - MAXIMUM_GOSSIP_CLOCK_DISPARITY).toSlot()
let pastSlot = (wallTime - MAXIMUM_GOSSIP_CLOCK_DISPARITY).toSlot()
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-alpha.1/specs/phase0/p2p-interface.md#configuration
if not pastSlot.afterGenesis:
return ok(msgSlot)
if consensusFork < ConsensusFork.Deneb:
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/phase0/p2p-interface.md#configuration
# The spec value of ATTESTATION_PROPAGATION_SLOT_RANGE is 32, but it can
# retransmit attestations on the cusp of being out of spec, and which by
# the time they reach their destination might be out of spec.
const ATTESTATION_PROPAGATION_SLOT_RANGE = 28
if pastSlot.afterGenesis and
msgSlot + ATTESTATION_PROPAGATION_SLOT_RANGE < pastSlot.slot:
if msgSlot + ATTESTATION_PROPAGATION_SLOT_RANGE < pastSlot.slot:
return errIgnore("Attestation slot in the past")
else:
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/p2p-interface.md#beacon_attestation_subnet_id
# "[IGNORE] the epoch of attestation.data.slot is either the current or
# previous epoch (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e.
# compute_epoch_at_slot(attestation.data.slot) in
# (get_previous_epoch(state), get_current_epoch(state))"
#
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/p2p-interface.md#beacon_aggregate_and_proof
# "[IGNORE] the epoch of aggregate.data.slot is either the current or
# previous epoch (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e.
# compute_epoch_at_slot(aggregate.data.slot) in
# (get_previous_epoch(state), get_current_epoch(state))"
if msgSlot.epoch < pastSlot.slot.epoch.get_previous_epoch:
return errIgnore("Attestation slot in the past")
ok(msgSlot)
func check_slot_exact(msgSlot: Slot, wallTime: BeaconTime):
Result[Slot, ValidationError] =
let futureSlot = (wallTime + MAXIMUM_GOSSIP_CLOCK_DISPARITY).toSlot()
if not futureSlot.afterGenesis or msgSlot > futureSlot.slot:
return errIgnore("Sync committee slot in the future")
let pastSlot = (wallTime - MAXIMUM_GOSSIP_CLOCK_DISPARITY).toSlot()
if pastSlot.afterGenesis and msgSlot < pastSlot.slot:
return errIgnore("Sync committee slot in the past")
ok(msgSlot)
@ -120,10 +150,9 @@ func check_beacon_and_target_block(
? check_attestation_block(pool, data.slot, blck)
# [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
# in the LMD vote -- i.e.
# get_checkpoint_block(store, attestation.data.beacon_block_root,
# attestation.data.target.epoch) == attestation.data.target.root
# the sanity of target.epoch has been checked by check_attestation_slot_target
let target = blck.atCheckpoint(data.target).valueOr:
return errReject("Attestation target is not ancestor of LMD vote block")
@ -527,7 +556,8 @@ proc validateBeaconBlock*(
ok()
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/phase0/p2p-interface.md#beacon_attestation_subnet_id
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/p2p-interface.md#beacon_aggregate_and_proof
proc validateAttestation*(
pool: ref AttestationPool,
batchCrypto: ref BatchCrypto,
@ -556,8 +586,13 @@ proc validateAttestation*(
# attestation.data.slot + ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot
# >= attestation.data.slot (a client MAY queue future attestations for
# processing at the appropriate slot).
#
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/p2p-interface.md#beacon_attestation_subnet_id
# modifies this for Deneb and newer forks.
block:
let v = check_propagation_slot_range(slot, wallTime)
let v = check_propagation_slot_range(
pool.dag.cfg.consensusForkAtEpoch(wallTime.slotOrZero.epoch), slot,
wallTime)
if v.isErr(): # [IGNORE]
return err(v.error())
@ -584,11 +619,10 @@ proc validateAttestation*(
# The following rule follows implicitly from that we clear out any
# unviable blocks from the chain dag:
#
# The current finalized_checkpoint is an ancestor of the block defined by
# attestation.data.beacon_block_root -- i.e. get_ancestor(store,
# attestation.data.beacon_block_root,
# compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) ==
# store.finalized_checkpoint.root
# [IGNORE] The current finalized_checkpoint is an ancestor of the block
# defined by attestation.data.beacon_block_root -- i.e.
# get_checkpoint_block(store, attestation.data.beacon_block_root,
# store.finalized_checkpoint.epoch) == store.finalized_checkpoint.root
let
shufflingRef =
pool.dag.getShufflingRef(target.blck, target.slot.epoch, false).valueOr:
@ -693,7 +727,8 @@ proc validateAttestation*(
return ok((validator_index, sig))
# https://github.com/ethereum/consensus-specs/blob/v1.3.0/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/phase0/p2p-interface.md#beacon_aggregate_and_proof
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/p2p-interface.md#beacon_aggregate_and_proof
proc validateAggregate*(
pool: ref AttestationPool,
batchCrypto: ref BatchCrypto,
@ -723,8 +758,13 @@ proc validateAggregate*(
# ATTESTATION_PROPAGATION_SLOT_RANGE slots (with a
# MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance) -- i.e. aggregate.data.slot +
# ATTESTATION_PROPAGATION_SLOT_RANGE >= current_slot >= aggregate.data.slot
#
# https://github.com/ethereum/consensus-specs/blob/v1.4.0-beta.0/specs/deneb/p2p-interface.md#beacon_aggregate_and_proof
# modifies this for Deneb and newer forks.
block:
let v = check_propagation_slot_range(slot, wallTime)
let v = check_propagation_slot_range(
pool.dag.cfg.consensusForkAtEpoch(wallTime.slotOrZero.epoch), slot,
wallTime)
if v.isErr(): # [IGNORE]
return err(v.error())
@ -883,11 +923,10 @@ proc validateAggregate*(
# The following rule follows implicitly from that we clear out any
# unviable blocks from the chain dag:
#
# The current finalized_checkpoint is an ancestor of the block defined by
# aggregate.data.beacon_block_root -- i.e. get_ancestor(store,
# aggregate.data.beacon_block_root,
# compute_start_slot_at_epoch(store.finalized_checkpoint.epoch)) ==
# store.finalized_checkpoint.root
# [IGNORE] The current finalized_checkpoint is an ancestor of the block
# defined by aggregate.data.beacon_block_root -- i.e.
# get_checkpoint_block(store, aggregate.data.beacon_block_root,
# finalized_checkpoint.epoch) == store.finalized_checkpoint.root
# Only valid aggregates go in the list
if pool.nextAttestationEpoch.lenu64 <= aggregate_and_proof.aggregator_index:
@ -1040,7 +1079,7 @@ proc validateSyncCommitteeMessage*(
# [IGNORE] The message's slot is for the current slot (with a
# `MAXIMUM_GOSSIP_CLOCK_DISPARITY` allowance), i.e.
# `sync_committee_message.slot == current_slot`.
let v = check_propagation_slot_range(msg.slot, wallTime)
let v = check_slot_exact(msg.slot, wallTime)
if v.isErr():
return err(v.error())
@ -1135,7 +1174,7 @@ proc validateContribution*(
# (with a MAXIMUM_GOSSIP_CLOCK_DISPARITY allowance)
# i.e. contribution.slot == current_slot.
block:
let v = check_propagation_slot_range(syncCommitteeSlot, wallTime)
let v = check_slot_exact(syncCommitteeSlot, wallTime)
if v.isErr(): # [IGNORE]
return err(v.error())