-
Notifications
You must be signed in to change notification settings - Fork 18
Duty logic validation for consensus messages #228
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
e99fdc7
to
89f0306
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors duty logic validations by introducing new parameters and modules to support BeaconNetwork and Duties tracking while updating the Validator to use a DutiesProvider.
- Introduces the new slots_per_epoch field into validation contexts and tests.
- Refactors the Validator to take a DutiesProvider along with a BeaconNetwork.
- Adds new modules for duties tracking and beacon network functionalities.
Reviewed Changes
Copilot reviewed 14 out of 15 changed files in this pull request and generated no comments.
Show a summary per file
File | Description |
---|---|
anchor/message_validator/src/partial_signature.rs | Added slots_per_epoch field in test contexts for partial signature validation. |
anchor/message_validator/src/lib.rs | Updated Validator struct and validation functions to use BeaconNetwork and DutiesProvider. |
anchor/message_validator/src/consensus_message.rs | Updated consensus message validation to utilize the new duty logic and error variants. |
anchor/message_validator/src/duties/* | New modules that implement duties tracking and the DutiesProvider trait. |
Other files | Updates updating generics and dependencies across message sender/receiver and client to support the new duty logic features. |
Files not reviewed (1)
- .githooks/pre-commit: Language not supported
Comments suppressed due to low confidence (2)
anchor/message_validator/src/partial_signature.rs:237
- [nitpick] Consider replacing the hard-coded magic number '32' with a named constant to improve clarity and maintainability in test configurations.
+ slots_per_epoch: 32,
anchor/message_validator/src/consensus_message.rs:51
- [nitpick] Cloning the entire slot clock might incur unnecessary performance overhead if the underlying implementation is not lightweight; consider passing a reference or ensuring that the SlotClock type implements a cheap clone.
beacon_network.slot_clock().clone(),
# Conflicts: # anchor/client/src/lib.rs # anchor/message_receiver/src/manager.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR refactors the duty validation logic for SSV messages to improve clarity and correctness, while also integrating a new duties management module.
- Updated validation functions to accept a generic SlotClock and DutiesProvider.
- Introduced a new duties module and duties_tracker for handling sync committee and proposer duties.
- Modified the Validator and related methods across message validation, sending, and receiving to propagate the new duties provider.
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
anchor/message_validator/src/partial_signature.rs | Updated validation context to include a generic SlotClock; minor adjustments for new duty fields. |
anchor/message_validator/src/lib.rs | Modified ValidationContext and Validator to include DutiesProvider; updated message validation functions accordingly. |
anchor/message_validator/src/duties/mod.rs | Introduced new duties module with types and traits for duty management. |
anchor/message_validator/src/duties/duties_tracker.rs | Added duties tracker to poll sync committee and proposer duties from beacon nodes. |
anchor/message_validator/src/consensus_message.rs | Integrated duty-based validation logic within consensus messages; adjusted round and timing validations. |
Other files (message_sender, message_receiver, database, client, etc.) | Updated generics and dependencies to accommodate the new duties provider integration. |
Comments suppressed due to low confidence (1)
anchor/message_validator/src/lib.rs:302
- Verify that substituting slot_clock with duties_provider in the call to validate_consensus_message fully preserves the original timing logic and that duties_provider properly encapsulates the necessary timing behavior.
self.duties_provider.clone(),
// - duty's starting slot + 34 (committee and aggregation) | ||
// - duty's starting slot + 3 (other types) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dknopik, any idea why these numbers?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The committee duty is needed for attestation, which can be submitted on chain until the end of the next epoch. So a large window for message validity is a good idea here. Same reasoning for attestation aggregation.
let validator_index_count = validator_indices.len() as u64; | ||
let slots_per_epoch_val = validation_context.slots_per_epoch; | ||
|
||
// Skip duty search if validators * 2 exceeds slots per epoch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@Zacholme7 @dknopik, does this make sense? If the number of validators in the committee is >= slots per epoch, it doesn't mean one of them is in the sync committee. Additionally, do they use the Committee role for the sync committee? What's the difference to SyncCommittee?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The Committee Role is used for BeaconVote
data, which includes the current head. This is needed for attestations AND sync committee contributions.
The word "Committee" in the "Committee role" refers to the SSV committee, not the sync committee, as this role is executed once per SSV committee, not once per validator.
As for the check:
The limit is at most slots_per_epoch
because we decide a BeaconVote
at most once per slot.
We need to vote for a BeaconVote
if
- at least one validator is in the sync committee, or
- at least one validator attests in this slot
Furthermore, validators attest once per epoch. So, if we have 32 validators, it is possible that we have to perform the Committee role every slot - regardless of whether one of them is in the sync committee.
That being said, I am not sure why we multiply/divide by two.
slot: Slot, | ||
validator_indices: &[ValidatorIndex], | ||
duty_provider: Arc<impl DutiesProvider>, | ||
) -> Result<(u64, bool), ValidationFailure> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why do we use a (u64, bool)
instead of a Option<u64>
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
fixed
6100a28
to
ee4cc61
Compare
} | ||
} | ||
} | ||
Ok(Some(std::cmp::min( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@@nkryuchkov given the if at line 580, it seems when we get here, 2 * validator_index_count >= slots_per_epoch_val
, so we could simply return slots_per_epoch_val
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When validator_index_count < slots_per_epoch_val / 2
, the code inside the if
returns only if one of the indices satisfies the duty_provider.is_validator_in_sync_committee(period, index)
condition, so it can also go out of the if
block and reach the last line. To get rid of min
, we'd need to add an extra check:
// Skip duty search if validators * 2 exceeds slots per epoch,
// as the maximum duties per epoch is capped at the number of slots.
// This avoids unnecessary checks.
if validatorIndexCount*2 >= slotsPerEpoch {
return slotsPerEpoch, true
}
// Check if there is at least one validator in the sync committee.
// If so, the duty limit is equal to the number of slots per epoch.
period := mv.netCfg.Beacon.EstimatedSyncCommitteePeriodAtEpoch(mv.netCfg.Beacon.EstimatedEpochAtSlot(slot))
for _, i := range validatorIndices {
if mv.dutyStore.SyncCommittee.Duty(period, i) != nil {
return slotsPerEpoch, true
}
}
return 2 * validatorIndexCount, true
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good catch, I like your solution more. But do we need to skip duty_provider.is_validator_in_sync_committee(period, index)
tho? Isn't it just a map get?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@diegomrsantos I'm not sure I understand, what do you mean by skipping? Yes, it's just a map get
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
is the code below necessary?
if validatorIndexCount*2 >= slotsPerEpoch {
return slotsPerEpoch, true
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Why the *2
in the condition validator_index_count * 2 >= slots_per_epoch_val
? If we want to skip the check, shouldn't it be validator_index_count >= slots_per_epoch_val
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@diegomrsantos sorry for the delay. The *2
is because there might be 2 duties per validator. Do I understand correctly that your question is only about the *2
part?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nkryuchkov I assume you mean sync committee and attestation duty. But isn't the BeaconData
only voted on once per committee regardless?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@dknopik IIRC the main reason was reorgs. @MatheusFranco99 can you please confirm it? If one of validators participates in sync committee, the duty limit changes to slotsPerEpoch
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nkryuchkov @dknopik
Yes, the reason is reorgs. We allow up to 2 attestation duties per epoch, i.e. 2*validatorIndexCount
. For example, a committee with a single validator is allowed to send messages for up to 2 duties.
However, for the case validatorIndexCount*2 >= slotsPerEpoch
, it's meaningless to set the maximum number of committee duties to more than 32, so we cap it to 32.
The only exception is when one of the committee's validators is in the sync committee period. In this case, the committee can send msgs for up to 32 duties, i.e. all slots.
@diegomrsantos Answering your question, yes, the following code is equivalent:
period := mv.netCfg.Beacon.EstimatedSyncCommitteePeriodAtEpoch(mv.netCfg.Beacon.EstimatedEpochAtSlot(slot))
for _, i := range validatorIndices {
if mv.dutyStore.SyncCommittee.Duty(period, i) != nil {
return slotsPerEpoch, true
}
}
return min(validatorIndexCount*2, slotsPerEpoch), true
We added the IF check before mv.dutyStore.SyncCommittee.Duty
is called because:
- it's very likely that
validatorIndexCount*2 >= slotsPerEpoch
, immediately returning. - and it's very unlikely that any
mv.dutyStore.SyncCommittee.Duty
will return true, so the FOR loop complexity is expected to belen(validatorIndices)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR introduces duty validation logic for SSV messages and integrates a new duties management module into the message validation and networking components. The key changes include:
- The addition of a new duties module and a duties_tracker to manage sync committee and proposer duties.
- Updates to the Validator and related message validation functions to accept a generic DutiesProvider, along with corresponding test updates.
- Modifications in networking and message receiver code to propagate the new generic parameters and improve logging.
Reviewed Changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 1 comment.
Show a summary per file
File | Description |
---|---|
anchor/message_validator/src/partial_signature.rs | Updated function signatures and tests to use a generic SlotClock type. |
anchor/message_validator/src/lib.rs | Integrated DutiesProvider into Validator and refactored validation logic. |
anchor/message_validator/src/duties/mod.rs | Added the new duties module for sync committee and proposer duties. |
anchor/message_validator/src/duties/duties_tracker.rs | Introduced duties_tracker with polling and pruning of duties. |
anchor/message_validator/src/consensus_state.rs | Added getters for max_slot and duty counts for operators. |
anchor/message_validator/src/consensus_message.rs | Updated consensus message validation to incorporate duty-based checks. |
anchor/message_sender/src/network.rs | Updated network sender to use the new generic Validator with DutiesProvider. |
anchor/message_receiver/src/manager.rs | Updated message receiver to use generic Validator and improved logging. |
anchor/database/src/state.rs | Added a helper to collect validator indices. |
anchor/common/ssv_types/src/cluster.rs | Introduced conversion from ValidatorIndex to u64. |
anchor/client/src/lib.rs | Updated client startup to initialize and start the new DutiesTracker. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
great work, LGTM! sorry for the delay
Issue Addressed
#161
Proposed Changes
This PR adds duty validation logic for SSV messages and integrates a new duties management module.
Additional Info
This is pending #277 and will be implemented in a future PR.