Skip to content

Commit

Permalink
CommitteeRunner: allow signatures of unknown validators (#442)
Browse files Browse the repository at this point in the history
* Do validator index validation, in psig messages, for validator duties only

* Drop expected error (unknown validator index) for committee runners

* Add quorum of invalid validator index test to trigger "could not find validators for root"

* Allow unsyced validators set: use "continue" if a validator is not found for a root in CommitteeRunner

* Test quorum for unknown validator index and a known one (tests the continue command)

* Generate JSON tests

* Apply suggestion

* Remove unknown validator edge case error

* Remove deprecated error in tests. Make explicit the ValidatorIndex associated with the submitted beacon root.
  • Loading branch information
MatheusFranco99 authored Jul 3, 2024
1 parent 981a403 commit b843e38
Show file tree
Hide file tree
Showing 23 changed files with 4,311 additions and 32 deletions.
17 changes: 7 additions & 10 deletions ssv/committee_runner.go
Original file line number Diff line number Diff line change
Expand Up @@ -196,13 +196,10 @@ func (cr CommitteeRunner) ProcessPostConsensus(signedMsg *types.PartialSignature
role, validators, found := findValidators(root, attestationMap, committeeMap)

if !found {
// Check if duty has terminated (runner has submitted for all duties)
if cr.HasSubmittedAllValidatorDuties(attestationMap, committeeMap) {
cr.BaseRunner.State.Finished = true
}
// All roots have quorum, so if we can't find validators for a root, it means we have a bug
// We assume it is safe to stop due to honest majority assumption
return errors.New("could not find validators for root")
// Edge case: since operators may have divergent sets of validators,
// it's possible that an operator doesn't have the validator associated to a root.
// In this case, we simply continue.
continue
}

for _, validator := range validators {
Expand Down Expand Up @@ -236,12 +233,12 @@ func (cr CommitteeRunner) ProcessPostConsensus(signedMsg *types.PartialSignature

// Get the beacon object related to root
validatorObjs, exists := beaconObjects[validator]
if !exists {
if !exists {
anyErr = errors.Wrap(err, "could not find beacon object for validator")
continue
}
sszObject, rexists := validatorObjs[root]
if !rexists {
sszObject, exists := validatorObjs[root]
if !exists {
anyErr = errors.Wrap(err, "could not find beacon object for validator")
continue
}
Expand Down
51 changes: 35 additions & 16 deletions ssv/runner_signatures.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,30 +43,49 @@ func (b *BaseRunner) validatePartialSigMsgForSlot(
return errors.New("invalid partial sig slot")
}

for _, msg := range psigMsgs.Messages {
// Get signer
msgSigner := psigMsgs.Messages[0].Signer // signer is the same in all psigMsgs.Messages and len(psigMsgs.Messages) > 0 (guaranteed by psigMsgs.Validate())

// Check if knows it has the validator index share
validatorShare, ok := b.Share[msg.ValidatorIndex]
if !ok {
return errors.New("unknown validator index")
}
// Get committee (unique for runner)
var shareSample *types.Share
for _, share := range b.Share {
shareSample = share
break
}
if shareSample == nil {
return errors.New("can not get committee because there is no share in runner")
}
committee := shareSample.Committee

// Check if signer is in committee
signerInCommittee := false
for _, operator := range validatorShare.Committee {
if operator.Signer == msg.Signer {
signerInCommittee = true
break
}
}
if !signerInCommittee {
return errors.New("unknown signer")
// Check if signer is in committee
signerInCommittee := false
for _, operator := range committee {
if operator.Signer == msgSigner {
signerInCommittee = true
break
}
}
if !signerInCommittee {
return errors.New("unknown signer")
}

return nil
}

// Validate if runner has a share for each ValidatorIndex in the PartialSignatureMessages.Messages
func (b *BaseRunner) validateValidatorIndexInPartialSigMsg(
psigMsgs *types.PartialSignatureMessages,
) error {
for _, msg := range psigMsgs.Messages {
// Check if it has the validator index share
_, ok := b.Share[msg.ValidatorIndex]
if !ok {
return errors.New("unknown validator index")
}
}
return nil
}

func (b *BaseRunner) verifyBeaconPartialSignature(signer types.OperatorID, signature types.Signature, root [32]byte,
committee []*types.ShareMember) error {
for _, n := range committee {
Expand Down
9 changes: 9 additions & 0 deletions ssv/runner_validations.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,10 @@ func (b *BaseRunner) ValidatePreConsensusMsg(runner Runner, psigMsgs *types.Part
return err
}

if err := b.validateValidatorIndexInPartialSigMsg(psigMsgs); err != nil {
return err
}

roots, domain, err := runner.expectedPreConsensusRootsAndDomain()
if err != nil {
return err
Expand Down Expand Up @@ -76,6 +80,11 @@ func (b *BaseRunner) ValidatePostConsensusMsg(runner Runner, psigMsgs *types.Par
if err := b.validatePartialSigMsgForSlot(psigMsgs, decidedValue.Duty.Slot); err != nil {
return err
}

if err := b.validateValidatorIndexInPartialSigMsg(psigMsgs); err != nil {
return err
}

roots, domain, err := runner.expectedPostConsensusRootsAndDomain()
if err != nil {
return err
Expand Down
2 changes: 2 additions & 0 deletions ssv/spectest/all_tests.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@ var AllTests = []tests.TestF{
postconsensus.InconsistentOperatorSigner,
postconsensus.NilSSVMessage,
postconsensus.InvalidValidatorIndex,
postconsensus.InvalidValidatorIndexQuorum,
postconsensus.InvalidAndValidValidatorIndexesQuorum,
postconsensus.PartialInvalidRootQuorumThenValidQuorum,
postconsensus.PartialInvalidSigQuorumThenValidQuorum,
postconsensus.MixedCommittees,
Expand Down
Loading

0 comments on commit b843e38

Please sign in to comment.