From b870952a66c4f217b4e8402f93fd8e7e89a6190e Mon Sep 17 00:00:00 2001 From: MatheusFranco99 <48058141+MatheusFranco99@users.noreply.github.com> Date: Wed, 7 Jan 2026 11:20:13 +0000 Subject: [PATCH 1/6] update rules for agg committee --- .../ReceivedMessagesEstimation.md | 3 + p2p/MessageValidation/Rules.md | 177 +++++++++--------- 2 files changed, 91 insertions(+), 89 deletions(-) diff --git a/p2p/MessageValidation/ReceivedMessagesEstimation.md b/p2p/MessageValidation/ReceivedMessagesEstimation.md index f16349e..c709bc8 100644 --- a/p2p/MessageValidation/ReceivedMessagesEstimation.md +++ b/p2p/MessageValidation/ReceivedMessagesEstimation.md @@ -1,5 +1,8 @@ # Estimation of amount of messages received +> [!WARNING] +> This document is deprecated due to protocol changes as the Alan and Boole forks. + To play with the below formulas, follow this [google sheet link](https://docs.google.com/spreadsheets/d/1TpXnVFzF4eGiQarXuPBrOIU4tJXhzOHav9PkGve3_Qc/edit?usp=sharing). ## Probability of having a duty per slot diff --git a/p2p/MessageValidation/Rules.md b/p2p/MessageValidation/Rules.md index 4959479..ba955e2 100644 --- a/p2p/MessageValidation/Rules.md +++ b/p2p/MessageValidation/Rules.md @@ -120,7 +120,7 @@ var ( ErrPartialSigOneSigner = Error{text: "partial signature message with len(signers) != 1", reject: true} ErrTooManyPartialSignatureMessages = Error{text: "too many signatures for cluster in partial signature message"} - ErrTripleValidatorIndexInPartialSignatures = Error{text: "validator index appear 3 times in partial signature message", reject: true} + ErrTooManyEqualValidatorIndexInPartialSignatures = Error{text: "validator index appear 3 times in partial signature message", reject: true} ErrNoPartialSignatureMessages = Error{text: "no partial signature messages", reject: true} ErrInconsistentSigners = Error{text: "inconsistent signers", reject: true} ErrValidatorIndexMismatch = Error{text: "validator index mismatch"} @@ -140,14 +140,13 @@ The main structure is the `MessageValidation` structure which has a `ValidatePub ```go const ( - MaxMsgSize = 4945164 - maxConsensusMsgSize = 722412 - maxPartialSignatureMsgSize = 144020 + MaxMsgSize = 9114816 + maxConsensusMsgSize = 722480 + maxPartialSignatureMsgSize = 727000 maxSSVMessageDataSize = max(maxConsensusMsgSize, maxPartialSignatureMsgSize) PartialSignatureSize = 48 MessageSignatureSize = 256 SyncCommitteeSize = 512 - MaxSignaturesInSyncCommitteeContribution = 13 ) type MessageValidation struct { @@ -423,19 +422,19 @@ func (mv *MessageValidation) ValidatePubSubMessage(pmsg *pubsub.Message) error { ### Semantics General Rules -| Verification | Error | Classification | Explanation | -| -------------------- | ------------------------- | -------------- | --------------------------------------------------------------------- | -| Signers in committee | ErrSignerNotInCommittee | Reject | Signers must belong to validator's or CommitteeID's committee. | -| Different Domain | ErrWrongDomain | Ignore | MsgID.Domain is different than self domain. | -| Invalid Role | ErrInvalidRole | Reject | MsgID.Role is not known. | -| Validator exists | ErrUnknownValidator | Ignore | If MsgID.SenderID is a validator, it must exist. | -| Active Validator ID | ErrValidatorNotAttesting | Ignore | If MsgID.SenderID is a validator, it must be active active validator. | -| Validator Liquidated | ErrValidatorLiquidated | Ignore | If MsgID.SenderID is a validator, it must not be liquidated. | -| CommitteeID exists | ErrNonExistentCommitteeID | Ignore | If MsgID.SenderID is a committee, it must exist. | -| Wrong topic | ErrIncorrectTopic | Ignore | The message should be sent in the correct topic | -| Event Message | ErrEventMessage | Reject | MsgType can't be of event message. | -| DKG Message | ErrDKGMessage | Reject | MsgType can't be of DKG message. | -| Unknown MsgType | ErrUnknownSSVMessageType | Reject | MsgType is not known. | +| Verification | Error | Classification | Explanation | +| -------------------- | ------------------------- | -------------- |--------------------------------------------------------------------------------------------------------------------------------------------| +| Signers in committee | ErrSignerNotInCommittee | Reject | Signers must belong to validator's or CommitteeID's committee. | +| Different Domain | ErrWrongDomain | Ignore | MsgID.Domain is different than self domain. | +| Invalid Role | ErrInvalidRole | Reject | MsgID.Role is wrong (not `RoleCommittee`, `RoleProposer`, `RoleValidatorRegistration`, `RoleVoluntaryExit`, or `RoleAggregatorCommittee`). | +| Validator exists | ErrUnknownValidator | Ignore | If MsgID.SenderID is a validator, it must exist. | +| Active Validator ID | ErrValidatorNotAttesting | Ignore | If MsgID.SenderID is a validator, it must be active active validator. | +| Validator Liquidated | ErrValidatorLiquidated | Ignore | If MsgID.SenderID is a validator, it must not be liquidated. | +| CommitteeID exists | ErrNonExistentCommitteeID | Ignore | If MsgID.SenderID is a committee, it must exist. | +| Wrong topic | ErrIncorrectTopic | Ignore | The message should be sent in the correct topic | +| Event Message | ErrEventMessage | Reject | MsgType can't be of event message. | +| DKG Message | ErrDKGMessage | Reject | MsgType can't be of DKG message. | +| Unknown MsgType | ErrUnknownSSVMessageType | Reject | MsgType is not known. | ```go @@ -477,7 +476,7 @@ func (mv *MessageValidation) ValidateSemantics(peerID peer.ID, signedSSVMessage } senderID := signedSSVMessage.SSVMessage.MsgID.GetSenderID() - if role != types.RoleCommittee { + if !isCommitteeRole(role) { validatorPK := senderID // Rule: Validator does not exist @@ -521,6 +520,10 @@ func (mv *MessageValidation) ValidateSemantics(peerID peer.ID, signedSSVMessage return ErrUnknownSSVMessageType } } + +func isCommitteeRole(role) bool { + return role == types.RoleCommittee || role == types.RoleAggregatorCommittee +} ``` ### Consensus @@ -732,14 +735,14 @@ func (mv *MessageValidation) ValidateQBFTLogic(peerID peer.ID, signedSSVMessage #### Duty Logic -| Verification | Error | Classification | Explanation | -| ------------------------- | ----------------------------- | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Already advanced slot | ErrSlotAlreadyAdvanced | Ignore | (Non-committee roles) Signer already advanced to later slot. | -| Invalid role for consensus | ErrUnexpectedConsensusMessage | Reject | SSVMessage.MsgID.Role must not be ValidatorRegistration or VoluntaryExit. | -| No beacon duty | ErrNoDuty | Ignore | If Proposal or Sync committee contribution duty, check if duty exists with beacon node. | -| Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator) or +3 (else) slots. | -| Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either aggregator, voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee,
2*V (if no validator is doing sync committee).
Else accept. | -| Valid round for role | ErrRoundTooHigh | Reject | For committee and aggregation, round can go up to 12. Else, it can go up to 6. | +| Verification | Error | Classification | Explanation | +| ------------------------- | ----------------------------- | -------------- |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Already advanced slot | ErrSlotAlreadyAdvanced | Ignore | (Non-committee roles) Signer already advanced to later slot. | +| Invalid role for consensus | ErrUnexpectedConsensusMessage | Reject | SSVMessage.MsgID.Role must not be ValidatorRegistration or VoluntaryExit. | +| No beacon duty | ErrNoDuty | Ignore | If Proposal duty, check if duty exists with beacon node. | +| Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator committee) or +3 (else) slots. | +| Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee or aggregator committee,
2*V (if no validator is doing sync committee).
Else accept. | +| Valid round for role | ErrRoundTooHigh | Reject | For committee and aggregator committee, round can go up to 12. Else, it can go up to 6. | ```go @@ -757,7 +760,7 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign } type SSVMessage struct { MsgType MsgType - MsgID MessageID -> Role must have consensus, Must be assigned to duty if role is Proposal or Sync Committee Aggregator + MsgID MessageID -> Role must have consensus, Must be assigned to duty if role is Proposal Data []byte } type Message struct { @@ -777,7 +780,7 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign _ = qbftMessage.Decode(signedSSVMessage.SSVMessage.Data) // Rule: Height must not be "old". I.e., signer must not have already advanced to a later slot. - if signedSSVMessage.SSVMessage.MsgID.GetRoleType() != types.RoleCommittee { // Rule only for validator runners + if !isCommitteeRole(signedSSVMessage.SSVMessage.MsgID.GetRoleType()) { // Rule only for validator runners if !mv.MessageFromOldSlot(peerID, signedSSVMessage.SSVMessage.MsgID, qbftMessage.Height) { return ErrSlotAlreadyAdvanced } @@ -788,8 +791,8 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign return ErrUnexpectedConsensusMessage } - // Rule: For proposal and sync committee aggregation duties, we check if the validator is assigned to it - if err := mv.ValidBeaconDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), signedSSVMessage.SSVMessage.MsgID.GetRoleType(), phase0.Slot(qbftMessage.Height)); err != nil { + // Rule: For proposer duty, we check if the validator is assigned to it + if err := mv.ValidProposerDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), signedSSVMessage.SSVMessage.MsgID.GetRoleType(), phase0.Slot(qbftMessage.Height)); err != nil { return err } @@ -802,15 +805,15 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign } // Rule: valid number of duties per epoch: - // - 2 for aggregation, voluntary exit and validator registration - // - 2*V for Committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) + // - 2 for voluntary exit and validator registration + // - 2*V for Committee and Aggrgeator Committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) // - else, accept if !mv.ValidNumberOfDutiesPerEpoch(peerID, signedSSVMessage.SSVMessage.MsgID, phase0.Slot(qbftMessage.Height)) { return ErrTooManyDutiesPerEpoch } // Rule: Round cut-offs for roles: - // - 12 (committee and aggregation) + // - 12 (committee and aggregator committee) // - 6 (other types) if !mv.ValidRoundForRole(qbftMessage.Round, signedSSVMessage.SSVMessage.MsgID.GetRoleType()) { return ErrRoundTooHigh @@ -819,7 +822,7 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign return nil } -func (mv *MessageValidation) ValidBeaconDuty() error { +func (mv *MessageValidation) ValidProposerDuty() error { // Rule: For a proposal duty message, we check if the validator is assigned to it if signedSSVMessage.SSVMessage.MsgID.GetRoleType() == types.RoleProposer { @@ -828,13 +831,6 @@ func (mv *MessageValidation) ValidBeaconDuty() error { } } - // Rule: For a sync committee aggregation duty message, we check if the validator is assigned to it - if signedSSVMessage.SSVMessage.MsgID.GetRoleType() == types.RoleSyncCommitteeContribution { - if !mv.HasSyncCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), phase0.Slot(qbftMessage.Height)) { - return ErrNoDuty - } - } - return nil } @@ -844,16 +840,16 @@ func (mv *MessageValidation) ValidBeaconDuty() error { #### Semantics -| Verification | Error | Classification | Explanation | -| -------------------------- | ----------------------------------- | -------------- | ----------- | -| More than one signer | ErrPartialSigOneSigner | Reject | Must have only 1 signer. | -| Unexpected FullData | ErrFullDataNotInConsensusMessage | Reject | Must not have FullData. | -| Unknown type | ErrInvalidPartialSignatureType | Reject | Type not known. | -| Wrong type for role | ErrPartialSignatureTypeRoleMismatch | Reject | Type must match role:
PostConsensusPartialSig for Committee,
RandaoPartialSig or PostConsensusPartialSig for Proposer,
SelectionProofPartialSig or PostConsensusPartialSig for Aggregator,
SelectionProofPartialSig or PostConsensusPartialSig for Sync committee contribution,
ValidatorRegistrationPartialSig for Validator Registration,
VoluntaryExitPartialSig for Voluntary Exit | -| No PartialSignatureMessage | ErrNoPartialSignatureMessages | Reject | Message must have at least one PartialSignatureMessage. | -| Wrong BLS Signature Size | ErrWrongBLSSignatureSize | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signature must have the correct length. | -| Inconsistent signer | ErrInconsistentSigners | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signer must be the same as the
SignedSSVMessage.OperatorIDs[i]. | -| Validtor's index mismatch | ErrValidatorIndexMismatch | Ignore | $\forall i$ PartialSignatureMessages.Message[i].ValidatorIndex must belong to SSVMessage.SenderID(). | +| Verification | Error | Classification | Explanation | +| -------------------------- | ----------------------------------- | -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| More than one signer | ErrPartialSigOneSigner | Reject | Must have only 1 signer. | +| Unexpected FullData | ErrFullDataNotInConsensusMessage | Reject | Must not have FullData. | +| Unknown type | ErrInvalidPartialSignatureType | Reject | Type not known. | +| Wrong type for role | ErrPartialSignatureTypeRoleMismatch | Reject | Type must match role:
PostConsensusPartialSig for Committee,
RandaoPartialSig or PostConsensusPartialSig for Proposer,
AggregatorCommitteePartialSig or PostConsensusPartialSig for AggregatorCommittee,
ValidatorRegistrationPartialSig for Validator Registration,
VoluntaryExitPartialSig for Voluntary Exit | +| No PartialSignatureMessage | ErrNoPartialSignatureMessages | Reject | Message must have at least one PartialSignatureMessage. | +| Wrong BLS Signature Size | ErrWrongBLSSignatureSize | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signature must have the correct length. | +| Inconsistent signer | ErrInconsistentSigners | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signer must be the same as the
SignedSSVMessage.OperatorIDs[i]. | +| Validtor's index mismatch | ErrValidatorIndexMismatch | Ignore | $\forall i$ PartialSignatureMessages.Message[i].ValidatorIndex must belong to SSVMessage.SenderID(). | ```go @@ -911,8 +907,7 @@ func (mv *MessageValidation) ValidatePartialSignatureMessageSemantics(peerID pee // Rule: Partial signature type must match expected type: // - PostConsensusPartialSig, for Committee duty // - RandaoPartialSig or PostConsensusPartialSig for Proposer - // - SelectionProofPartialSig or PostConsensusPartialSig for Aggregator - // - SelectionProofPartialSig or PostConsensusPartialSig for Sync committee contribution + // - AggregatorCommitteePartialSig or PostConsensusPartialSig for AggregatorCommittee // - ValidatorRegistrationPartialSig for Validator Registration // - VoluntaryExitPartialSig for Voluntary Exit if !mv.ExpectedPartialSignatureTypeForRole(partialSignatureMessages.Type, signedSSVMessage.SSVMessage.MsgID) { @@ -945,15 +940,15 @@ func (mv *MessageValidation) ValidatePartialSignatureMessageSemantics(peerID pee #### Duty Logic -| Verification | Error | Classification | Explanation | -| ---------------------------- | ------------------------ | -------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -| Already advanced slot | ErrSlotAlreadyAdvanced | Ignore | (Non-committee roles) Signer already advanced to later slot. | -| No beacon duty | ErrNoDuty | Ignore | If Proposal or Sync committee contribution duty, check if duty exists with beacon node. | -| Invalid signature type count | ErrInvalidPartialSignatureTypeCount | Reject | It's allow only:
1 PostConsensusPartialSig, for Committee duty,
1 RandaoPartialSig and 1 PostConsensusPartialSig for Proposer,
1 SelectionProofPartialSig and 1 PostConsensusPartialSig for Aggregator,
1 SelectionProofPartialSig and 1 PostConsensusPartialSig for Sync committee contribution,
1 ValidatorRegistrationPartialSig for Validator Registration,
1 VoluntaryExitPartialSig for Voluntary Exit. | -| Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator) or +3 (else) slots. | -| Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either aggregator, voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee,
2*V (if no validator is doing sync committee).
Else accept. | -| Too many partial signatures | ErrTooManyPartialSignatureMessages | Reject | For the committee role, it's allowed $min(2*V, V + $ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validatos.
For sync committee contribution, it's allowed 13.
Else, only 1. | -| Triple validator index | ErrTripleValidatorIndexInPartialSignatures | Reject | A validator index can not be associated to more than 2 signatures. | +| Verification | Error | Classification | Explanation | +| ---------------------------- | ------------------------ | -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Already advanced slot | ErrSlotAlreadyAdvanced | Ignore | (Non-committee roles) Signer already advanced to later slot. | +| No beacon duty | ErrNoDuty | Ignore | If Proposal duty, check if duty exists with beacon node. | +| Invalid signature type count | ErrInvalidPartialSignatureTypeCount | Reject | It's allow only:
1 PostConsensusPartialSig, for Committee duty,
1 RandaoPartialSig and 1 PostConsensusPartialSig for Proposer,
1 AggregatorCommitteePartialSig and 1 PostConsensusPartialSig for AggregatorCommittee,
1 ValidatorRegistrationPartialSig for Validator Registration,
1 VoluntaryExitPartialSig for Voluntary Exit. | +| Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator committee) or +3 (else) slots. | +| Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either aggregator, voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee or aggregator committee,
2*V (if no validator is doing sync committee).
Else accept. | +| Too many partial signatures | ErrTooManyPartialSignatureMessages | Reject | For the committee role, it's allowed $min(2*V, V + $ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
For the aggregator committee role, it's allowed $min((1+4)*V, V + 4\times$ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
Else, only 1. | +| Triple validator index | ErrTooManyEqualValidatorIndexInPartialSignatures | Reject | For the committee (resp. aggregator committee) role, a validator index can not be associated to more than 2 (resp. 5) signatures. | ```go @@ -971,20 +966,20 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I } type SSVMessage struct { MsgType MsgType - MsgID MessageID -> Must be assigned to duty if role is Proposal or Sync Committee Aggregator + MsgID MessageID -> Must be assigned to duty if role is Proposal Data []byte } type PartialSignatureMessages struct { Type PartialSigMsgType -> Message count rules Slot phase0.Slot -> Must belong to allowed spread, Satisfies a maximum number of duties per epoch for role, Must not be "old" - Messages []*PartialSignatureMessage -> Valid number of signatures (3 cases: committee duty, sync committee contribution, others) + Messages []*PartialSignatureMessage -> Valid number of signatures (3 cases: committee duty, aggregator committee duty, others) } type PartialSignatureMessage struct { PartialSignature Signature SigningRoot [32]byte Signer OperatorID - ValidatorIndex phase0.ValidatorIndex -> Can't appear more than 2 times for role Committee + ValidatorIndex phase0.ValidatorIndex -> Can't appear more than 2 (resp. 5) times for role Committee (resp. AggregatorCommittee) } */ @@ -992,25 +987,25 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I var partialSignatureMessages types.PartialSignatureMessages _ = partialSignatureMessages.Decode(signedSSVMessage.SSVMessage.Data) + msgRole := signedSSVMessage.SSVMessage.MsgID.GetRoleType() // Rule: Height must not be "old". I.e., signer must not have already advanced to a later slot. - if signedSSVMessage.SSVMessage.MsgID.GetRoleType() != types.RoleCommittee { // Rule only for validator runners + if isCommitteeRole(msgRole) { // Rule only for validator runners if !mv.MessageFromOldSlot(peerID, signedSSVMessage.SSVMessage.MsgID, partialSignatureMessages.Slot) { return ErrSlotAlreadyAdvanced } } - // Rule: For proposal and sync committee aggregation duties, we check if the validator is assigned to it - if err := mv.ValidBeaconDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), signedSSVMessage.SSVMessage.MsgID.GetRoleType(), partialSignatureMessages.Slot); err != nil { + // Rule: For proposer duty, we check if the validator is assigned to it + if err := mv.ValidProposerDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), signedSSVMessage.SSVMessage.MsgID.GetRoleType(), partialSignatureMessages.Slot); err != nil { return err } // Rule: peer must send only: // - 1 PostConsensusPartialSig, for Committee duty // - 1 RandaoPartialSig and 1 PostConsensusPartialSig for Proposer - // - 1 SelectionProofPartialSig and 1 PostConsensusPartialSig for Aggregator - // - 1 SelectionProofPartialSig and 1 PostConsensusPartialSig for Sync committee contribution + // - 1 AggregatorCommitteePartialSig and 1 PostConsensusPartialSig for AggregatorCommittee // - 1 ValidatorRegistrationPartialSig for Validator Registration // - 1 VoluntaryExitPartialSig for Voluntary Exit if err := mv.ValidPartialSigMessageCount(peerID, signedSSVMessage.SSVMessage.MsgID, &partialSignatureMessages); err != nil { @@ -1018,7 +1013,7 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I } // Rule: current slot must be between duty's starting slot and: - // - duty's starting slot + 34 (committee and aggregation) + // - duty's starting slot + 34 (committee and aggregator committee) // - duty's starting slot + 3 (other duties) if err := mv.ValidDutySlot(peerID, partialSignatureMessages.Slot, signedSSVMessage.SSVMessage.MsgID.GetRoleType()); err != nil { // Err should be ErrEarlySlotMessage or ErrLateSlotMessage @@ -1026,28 +1021,32 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I } // Rule: valid number of duties per epoch: - // - 2 for aggregation, voluntary exit and validator registration - // - 2*V for Committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) + // - 2 for voluntary exit and validator registration + // - 2*V for Committee and AggregatorCommittee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) // - else, accept if !mv.ValidNumberOfDutiesPerEpoch(peerID, signedSSVMessage.SSVMessage.MsgID, partialSignatureMessages.Slot) { return ErrTooManyDutiesPerEpoch } - if signedSSVMessage.SSVMessage.MsgID.GetRoleType() == types.RoleCommittee { - - // Rule: The number of signatures must be <= min(2*V, V + SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster - if !mv.ValidNumberOfSignaturesForCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), &partialSignatureMessages) { - return ErrTooManyPartialSignatureMessages - } - - // Rule: a ValidatorIndex can't appear more than 2 times in the []*PartialSignatureMessage list - if !mv.NoTripleValidatorOccurrence(&partialSignatureMessages) { - return ErrTripleValidatorIndexInPartialSignatures - } - } else if signedSSVMessage.SSVMessage.MsgID.GetRoleType() == types.RoleSyncCommitteeContribution { - // Rule: The number of signatures must be <= MaxSignaturesInSyncCommitteeContribution for the sync comittee contribution duty - if len(partialSignatureMessages.Messages) > MaxSignaturesInSyncCommitteeContribution { - return ErrTooManyPartialSignatureMessages + if isCommitteeRole(msgRole) { + + if msgRole == types.RoleCommmittee { + // Rule: The number of signatures must be <= min(2*V, V + SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster + if !mv.ValidNumberOfSignaturesForCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), &partialSignatureMessages) { + return ErrTooManyPartialSignatureMessages + } + } + + if msgRole == types.RoleAggregatorCommittee { + // Rule: The number of signatures must be <= min(5*V, V + 4*SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster + if !mv.ValidNumberOfSignaturesForAggregatorCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), &partialSignatureMessages) { + return ErrTooManyPartialSignatureMessages + } + } + + // Rule: a ValidatorIndex can't appear more than 2 (resp. 5) times in the []*PartialSignatureMessage list for role Committee (resp. AggregatorCommittee) + if !mv.TooManyEqualValidatorOccurrence(&partialSignatureMessages, msgRole) { + return ErrTooManyEqualValidatorIndexInPartialSignatures } } else { // Rule: The number of signatures must be 1 for the other types of duties From 8d6b65c8dbd14a5702400a9e16a359b67121619c Mon Sep 17 00:00:00 2001 From: MatheusFranco99 <48058141+MatheusFranco99@users.noreply.github.com> Date: Wed, 7 Jan 2026 11:37:38 +0000 Subject: [PATCH 2/6] apply suggestions --- p2p/MessageValidation/Rules.md | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/p2p/MessageValidation/Rules.md b/p2p/MessageValidation/Rules.md index ba955e2..b738678 100644 --- a/p2p/MessageValidation/Rules.md +++ b/p2p/MessageValidation/Rules.md @@ -521,7 +521,7 @@ func (mv *MessageValidation) ValidateSemantics(peerID peer.ID, signedSSVMessage } } -func isCommitteeRole(role) bool { +func isCommitteeRole(role types.RunnerRole) bool { return role == types.RoleCommittee || role == types.RoleAggregatorCommittee } ``` @@ -806,7 +806,7 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign // Rule: valid number of duties per epoch: // - 2 for voluntary exit and validator registration - // - 2*V for Committee and Aggrgeator Committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) + // - 2*V for Committee and Aggregator Committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) // - else, accept if !mv.ValidNumberOfDutiesPerEpoch(peerID, signedSSVMessage.SSVMessage.MsgID, phase0.Slot(qbftMessage.Height)) { return ErrTooManyDutiesPerEpoch @@ -840,16 +840,16 @@ func (mv *MessageValidation) ValidProposerDuty() error { #### Semantics -| Verification | Error | Classification | Explanation | -| -------------------------- | ----------------------------------- | -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Verification | Error | Classification | Explanation | +|----------------------------| ----------------------------------- | -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| | More than one signer | ErrPartialSigOneSigner | Reject | Must have only 1 signer. | -| Unexpected FullData | ErrFullDataNotInConsensusMessage | Reject | Must not have FullData. | +| Unexpected FullData | ErrFullDataNotInConsensusMessage | Reject | Must not have FullData. | | Unknown type | ErrInvalidPartialSignatureType | Reject | Type not known. | | Wrong type for role | ErrPartialSignatureTypeRoleMismatch | Reject | Type must match role:
PostConsensusPartialSig for Committee,
RandaoPartialSig or PostConsensusPartialSig for Proposer,
AggregatorCommitteePartialSig or PostConsensusPartialSig for AggregatorCommittee,
ValidatorRegistrationPartialSig for Validator Registration,
VoluntaryExitPartialSig for Voluntary Exit | -| No PartialSignatureMessage | ErrNoPartialSignatureMessages | Reject | Message must have at least one PartialSignatureMessage. | -| Wrong BLS Signature Size | ErrWrongBLSSignatureSize | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signature must have the correct length. | -| Inconsistent signer | ErrInconsistentSigners | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signer must be the same as the
SignedSSVMessage.OperatorIDs[i]. | -| Validtor's index mismatch | ErrValidatorIndexMismatch | Ignore | $\forall i$ PartialSignatureMessages.Message[i].ValidatorIndex must belong to SSVMessage.SenderID(). | +| No PartialSignatureMessage | ErrNoPartialSignatureMessages | Reject | Message must have at least one PartialSignatureMessage. | +| Wrong BLS Signature Size | ErrWrongBLSSignatureSize | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signature must have the correct length. | +| Inconsistent signer | ErrInconsistentSigners | Reject | $\forall i$ PartialSignatureMessages.Message[i].Signer must be the same as the
SignedSSVMessage.OperatorIDs[i]. | +| Validator's index mismatch | ErrValidatorIndexMismatch | Ignore | $\forall i$ PartialSignatureMessages.Message[i].ValidatorIndex must belong to SSVMessage.SenderID(). | ```go @@ -990,7 +990,7 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I msgRole := signedSSVMessage.SSVMessage.MsgID.GetRoleType() // Rule: Height must not be "old". I.e., signer must not have already advanced to a later slot. - if isCommitteeRole(msgRole) { // Rule only for validator runners + if !isCommitteeRole(msgRole) { // Rule only for validator runners if !mv.MessageFromOldSlot(peerID, signedSSVMessage.SSVMessage.MsgID, partialSignatureMessages.Slot) { return ErrSlotAlreadyAdvanced } @@ -1030,7 +1030,7 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I if isCommitteeRole(msgRole) { - if msgRole == types.RoleCommmittee { + if msgRole == types.RoleCommittee { // Rule: The number of signatures must be <= min(2*V, V + SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster if !mv.ValidNumberOfSignaturesForCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), &partialSignatureMessages) { return ErrTooManyPartialSignatureMessages @@ -1045,7 +1045,7 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I } // Rule: a ValidatorIndex can't appear more than 2 (resp. 5) times in the []*PartialSignatureMessage list for role Committee (resp. AggregatorCommittee) - if !mv.TooManyEqualValidatorOccurrence(&partialSignatureMessages, msgRole) { + if mv.TooManyEqualValidatorOccurrence(&partialSignatureMessages, msgRole) { return ErrTooManyEqualValidatorIndexInPartialSignatures } } else { From db2eeb4e625dc7b7f2535a54382d10a68e09cd72 Mon Sep 17 00:00:00 2001 From: MatheusFranco99 <48058141+MatheusFranco99@users.noreply.github.com> Date: Tue, 13 Jan 2026 08:53:50 +0000 Subject: [PATCH 3/6] Update p2p/MessageValidation/Rules.md Co-authored-by: Nikita Kryuchkov --- p2p/MessageValidation/Rules.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/p2p/MessageValidation/Rules.md b/p2p/MessageValidation/Rules.md index b738678..b7d757a 100644 --- a/p2p/MessageValidation/Rules.md +++ b/p2p/MessageValidation/Rules.md @@ -948,7 +948,7 @@ func (mv *MessageValidation) ValidatePartialSignatureMessageSemantics(peerID pee | Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator committee) or +3 (else) slots. | | Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either aggregator, voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee or aggregator committee,
2*V (if no validator is doing sync committee).
Else accept. | | Too many partial signatures | ErrTooManyPartialSignatureMessages | Reject | For the committee role, it's allowed $min(2*V, V + $ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
For the aggregator committee role, it's allowed $min((1+4)*V, V + 4\times$ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
Else, only 1. | -| Triple validator index | ErrTooManyEqualValidatorIndexInPartialSignatures | Reject | For the committee (resp. aggregator committee) role, a validator index can not be associated to more than 2 (resp. 5) signatures. | +| Too many equal validator indices | ErrTooManyEqualValidatorIndexInPartialSignatures | Reject | A validator index can not be associated with more than 2 signatures for the committee role and more than 5 for the aggregator committee role. | ```go From a1c68c8cf054f8a506a62f0697cfde3474ffa7fd Mon Sep 17 00:00:00 2001 From: MatheusFranco99 <48058141+MatheusFranco99@users.noreply.github.com> Date: Tue, 13 Jan 2026 09:17:28 +0000 Subject: [PATCH 4/6] apply suggestions --- .../ReceivedMessagesEstimation.md | 2 +- p2p/MessageValidation/Rules.md | 50 +++++++++---------- 2 files changed, 26 insertions(+), 26 deletions(-) diff --git a/p2p/MessageValidation/ReceivedMessagesEstimation.md b/p2p/MessageValidation/ReceivedMessagesEstimation.md index c709bc8..391eccd 100644 --- a/p2p/MessageValidation/ReceivedMessagesEstimation.md +++ b/p2p/MessageValidation/ReceivedMessagesEstimation.md @@ -1,7 +1,7 @@ # Estimation of amount of messages received > [!WARNING] -> This document is deprecated due to protocol changes as the Alan and Boole forks. +> This document is deprecated due to protocol changes as of the Alan and Boole forks. To play with the below formulas, follow this [google sheet link](https://docs.google.com/spreadsheets/d/1TpXnVFzF4eGiQarXuPBrOIU4tJXhzOHav9PkGve3_Qc/edit?usp=sharing). diff --git a/p2p/MessageValidation/Rules.md b/p2p/MessageValidation/Rules.md index b7d757a..b4bc99f 100644 --- a/p2p/MessageValidation/Rules.md +++ b/p2p/MessageValidation/Rules.md @@ -118,15 +118,15 @@ var ( ErrUnexpectedPrepareJustifications = Error{text: "message has a prepare justification but it's not a proposal", reject: true} - ErrPartialSigOneSigner = Error{text: "partial signature message with len(signers) != 1", reject: true} - ErrTooManyPartialSignatureMessages = Error{text: "too many signatures for cluster in partial signature message"} - ErrTooManyEqualValidatorIndexInPartialSignatures = Error{text: "validator index appear 3 times in partial signature message", reject: true} - ErrNoPartialSignatureMessages = Error{text: "no partial signature messages", reject: true} - ErrInconsistentSigners = Error{text: "inconsistent signers", reject: true} - ErrValidatorIndexMismatch = Error{text: "validator index mismatch"} - ErrInvalidPartialSignatureType = Error{text: "invalid partial signature type", reject: true} - ErrPartialSignatureTypeRoleMismatch = Error{text: "partial signature type and role don't match", reject: true} - ErrInvalidPartialSignatureTypeCount = Error{text: "sent more partial signature messages of a certain type than allowed", reject: true} + ErrPartialSigOneSigner = Error{text: "partial signature message with len(signers) != 1", reject: true} + ErrTooManyPartialSignatureMessages = Error{text: "too many signatures for cluster in partial signature message"} + ErrTooManyEqualValidatorIndicesInPartialSignatures = Error{text: "validator index appears too many times in partial signature message", reject: true} + ErrNoPartialSignatureMessages = Error{text: "no partial signature messages", reject: true} + ErrInconsistentSigners = Error{text: "inconsistent signers", reject: true} + ErrValidatorIndexMismatch = Error{text: "validator index mismatch"} + ErrInvalidPartialSignatureType = Error{text: "invalid partial signature type", reject: true} + ErrPartialSignatureTypeRoleMismatch = Error{text: "partial signature type and role don't match", reject: true} + ErrInvalidPartialSignatureTypeCount = Error{text: "sent more partial signature messages of a certain type than allowed", reject: true} ErrTooManyDutiesPerEpoch = Error{text: "too many duties per epoch"} ErrNoDuty = Error{text: "no duty for this epoch"} @@ -140,13 +140,13 @@ The main structure is the `MessageValidation` structure which has a `ValidatePub ```go const ( - MaxMsgSize = 9114816 - maxConsensusMsgSize = 722480 - maxPartialSignatureMsgSize = 727000 + MaxMsgSize = 9114816 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_signed_ssv_message.go#L11 + maxConsensusMsgSize = 722480 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_ssv_message.go#L9 + maxPartialSignatureMsgSize = 727000 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_ssv_message.go#L10 maxSSVMessageDataSize = max(maxConsensusMsgSize, maxPartialSignatureMsgSize) - PartialSignatureSize = 48 - MessageSignatureSize = 256 - SyncCommitteeSize = 512 + PartialSignatureSize = 96 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/partial_sig_message.go#L80 and https://eth2book.info/latest/part2/building_blocks/signatures/#signing + MessageSignatureSize = 256 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/messages.go#L128 + SyncCommitteeSize = 512 // Source: https://github.com/ethereum/consensus-specs/blob/master/specs/altair/beacon-chain.md#sync-committee ) type MessageValidation struct { @@ -940,15 +940,15 @@ func (mv *MessageValidation) ValidatePartialSignatureMessageSemantics(peerID pee #### Duty Logic -| Verification | Error | Classification | Explanation | -| ---------------------------- | ------------------------ | -------------- |-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| Already advanced slot | ErrSlotAlreadyAdvanced | Ignore | (Non-committee roles) Signer already advanced to later slot. | -| No beacon duty | ErrNoDuty | Ignore | If Proposal duty, check if duty exists with beacon node. | -| Invalid signature type count | ErrInvalidPartialSignatureTypeCount | Reject | It's allow only:
1 PostConsensusPartialSig, for Committee duty,
1 RandaoPartialSig and 1 PostConsensusPartialSig for Proposer,
1 AggregatorCommitteePartialSig and 1 PostConsensusPartialSig for AggregatorCommittee,
1 ValidatorRegistrationPartialSig for Validator Registration,
1 VoluntaryExitPartialSig for Voluntary Exit. | -| Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator committee) or +3 (else) slots. | -| Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either aggregator, voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee or aggregator committee,
2*V (if no validator is doing sync committee).
Else accept. | -| Too many partial signatures | ErrTooManyPartialSignatureMessages | Reject | For the committee role, it's allowed $min(2*V, V + $ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
For the aggregator committee role, it's allowed $min((1+4)*V, V + 4\times$ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
Else, only 1. | -| Too many equal validator indices | ErrTooManyEqualValidatorIndexInPartialSignatures | Reject | A validator index can not be associated with more than 2 signatures for the committee role and more than 5 for the aggregator committee role. | +| Verification | Error | Classification | Explanation | +|----------------------------------|----------------------------------------------------| -------------- |-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| Already advanced slot | ErrSlotAlreadyAdvanced | Ignore | (Non-committee roles) Signer already advanced to later slot. | +| No beacon duty | ErrNoDuty | Ignore | If Proposal duty, check if duty exists with beacon node. | +| Invalid signature type count | ErrInvalidPartialSignatureTypeCount | Reject | It allows only:
1 PostConsensusPartialSig, for Committee duty,
1 RandaoPartialSig and 1 PostConsensusPartialSig for Proposer,
1 AggregatorCommitteePartialSig and 1 PostConsensusPartialSig for AggregatorCommittee,
1 ValidatorRegistrationPartialSig for Validator Registration,
1 VoluntaryExitPartialSig for Voluntary Exit.| +| Slot not in time for role | ErrEarlySlotMessage or ErrLateSlotMessage | Ignore | Current time must be between duty's starting time and
+34 (committee and aggregator committee) or +3 (else) slots. | +| Too many duties per epoch | ErrTooManyDutiesPerEpoch | Ignore | If role is either aggregator, voluntary exit and validator registration,
it's allowed 2 duties per epoch. Else if committee or aggregator committee,
2*V (if no validator is doing sync committee).
Else accept. | +| Too many partial signatures | ErrTooManyPartialSignatureMessages | Reject | For the committee role, it's allowed $min(2*V, V + $ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
For the aggregator committee role, it's allowed $min((1+4)*V, V + 4 \times$ SYNC_COMMITTEE_SIZE $)$
where $V$ is the number of committee's validators.
Else, only 1. | +| Too many equal validator indices | ErrTooManyEqualValidatorIndicesInPartialSignatures | Reject | A validator index can not be associated with more than 2 signatures for the committee role and more than 5 for the aggregator committee role. | ```go @@ -1046,7 +1046,7 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I // Rule: a ValidatorIndex can't appear more than 2 (resp. 5) times in the []*PartialSignatureMessage list for role Committee (resp. AggregatorCommittee) if mv.TooManyEqualValidatorOccurrence(&partialSignatureMessages, msgRole) { - return ErrTooManyEqualValidatorIndexInPartialSignatures + return ErrTooManyEqualValidatorIndicesInPartialSignatures } } else { // Rule: The number of signatures must be 1 for the other types of duties From 41309871f8e40776692a8037d077446436a340a0 Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Sun, 25 Jan 2026 13:15:14 +0200 Subject: [PATCH 5/6] whitespaces nit --- p2p/MessageValidation/Rules.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/p2p/MessageValidation/Rules.md b/p2p/MessageValidation/Rules.md index b4bc99f..5bab75b 100644 --- a/p2p/MessageValidation/Rules.md +++ b/p2p/MessageValidation/Rules.md @@ -142,9 +142,9 @@ The main structure is the `MessageValidation` structure which has a `ValidatePub const ( MaxMsgSize = 9114816 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_signed_ssv_message.go#L11 maxConsensusMsgSize = 722480 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_ssv_message.go#L9 - maxPartialSignatureMsgSize = 727000 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_ssv_message.go#L10 + maxPartialSignatureMsgSize = 727000 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/spectest/tests/maxmsgsize/max_ssv_message.go#L10 maxSSVMessageDataSize = max(maxConsensusMsgSize, maxPartialSignatureMsgSize) - PartialSignatureSize = 96 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/partial_sig_message.go#L80 and https://eth2book.info/latest/part2/building_blocks/signatures/#signing + PartialSignatureSize = 96 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/partial_sig_message.go#L80 and https://eth2book.info/latest/part2/building_blocks/signatures/#signing MessageSignatureSize = 256 // Source: https://github.com/ssvlabs/ssv-spec/blob/a65134ed45c932588c17d421173923f0216c6c73/types/messages.go#L128 SyncCommitteeSize = 512 // Source: https://github.com/ethereum/consensus-specs/blob/master/specs/altair/beacon-chain.md#sync-committee ) @@ -1029,14 +1029,14 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I } if isCommitteeRole(msgRole) { - + if msgRole == types.RoleCommittee { // Rule: The number of signatures must be <= min(2*V, V + SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster if !mv.ValidNumberOfSignaturesForCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), &partialSignatureMessages) { return ErrTooManyPartialSignatureMessages } } - + if msgRole == types.RoleAggregatorCommittee { // Rule: The number of signatures must be <= min(5*V, V + 4*SYNC_COMMITTEE_SIZE) where V is the number of validators assigned to the cluster if !mv.ValidNumberOfSignaturesForAggregatorCommitteeDuty(signedSSVMessage.SSVMessage.MsgID.GetSenderID(), &partialSignatureMessages) { @@ -1067,4 +1067,4 @@ func (mv *MessageValidation) ValidatePartialSigMessagesByDutyLogic(peerID peer.I ### Rules suggestions for future - Priority-based message handling: priority based on type and sender. -- Message aggregation: aggregate similar messages (e.g. wait for a quorum of prepares, commits, round-changes, partial-sig) before delivering to the app. \ No newline at end of file +- Message aggregation: aggregate similar messages (e.g. wait for a quorum of prepares, commits, round-changes, partial-sig) before delivering to the app. From 49f11a9e5e98a905747a62e0ccf5f99ca2dac49b Mon Sep 17 00:00:00 2001 From: Gal Rogozinski Date: Sun, 25 Jan 2026 13:17:48 +0200 Subject: [PATCH 6/6] docs: normalize aggregator committee wording --- p2p/MessageValidation/Rules.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/p2p/MessageValidation/Rules.md b/p2p/MessageValidation/Rules.md index 5bab75b..a871265 100644 --- a/p2p/MessageValidation/Rules.md +++ b/p2p/MessageValidation/Rules.md @@ -797,7 +797,7 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign } // Rule: current slot(height) must be between duty's starting slot and: - // - duty's starting slot + 34 (committee and aggregation) + // - duty's starting slot + 34 (committee and aggregator committee) // - duty's starting slot + 3 (other types) if err != mv.ValidDutySlot(peerID, phase0.Slot(qbftMessage.Height), signedSSVMessage.SSVMessage.MsgID.GetRoleType()); err != nil { // Err should be ErrEarlySlotMessage or ErrLateSlotMessage @@ -806,7 +806,7 @@ func (mv *MessageValidation) ValidateQBFTMessageByDutyLogic(peerID peer.ID, sign // Rule: valid number of duties per epoch: // - 2 for voluntary exit and validator registration - // - 2*V for Committee and Aggregator Committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) + // - 2*V for committee and aggregator committee duty (where V is the number of validators in the cluster) (if no validator is doing sync committee in this epoch) // - else, accept if !mv.ValidNumberOfDutiesPerEpoch(peerID, signedSSVMessage.SSVMessage.MsgID, phase0.Slot(qbftMessage.Height)) { return ErrTooManyDutiesPerEpoch