From 303ab1d512ba37c9cdd03be758af5d13646fa5bb Mon Sep 17 00:00:00 2001 From: Pavel Karpy Date: Mon, 17 Jul 2023 19:44:29 +0300 Subject: [PATCH] ir: Do not vote for the same validators list twice Closes #2365. Signed-off-by: Pavel Karpy --- CHANGELOG.md | 1 + pkg/innerring/state.go | 35 ++++++++++++++++++++++++++++++++++- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 0b060a9daa0..a5449083f9f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -11,6 +11,7 @@ Changelog for NeoFS Node ### Fixed - `neo-go` RPC connection loss handling (#1337) - Concurrent morph cache misses (#1248) +- Double voting for validators on IR startup (#2365) ### Removed - Deprecated `morph.rpc_endpoint` SN and `morph.endpoint.client` IR config sections (#2400) diff --git a/pkg/innerring/state.go b/pkg/innerring/state.go index 153a620a7eb..a6df68fe5d6 100644 --- a/pkg/innerring/state.go +++ b/pkg/innerring/state.go @@ -4,6 +4,7 @@ import ( "fmt" "sort" + "github.com/nspcc-dev/neo-go/pkg/crypto/keys" "github.com/nspcc-dev/neo-go/pkg/util" "github.com/nspcc-dev/neofs-node/pkg/innerring/processors/governance" auditClient "github.com/nspcc-dev/neofs-node/pkg/morph/client/audit" @@ -108,13 +109,21 @@ func (s *Server) voteForSidechainValidator(prm governance.VoteValidatorPrm) erro return nil } + voted, err := s.alreadyVoted(validators) + if err != nil { + return fmt.Errorf("could not check validators state: %w", err) + } + + if voted { + return nil + } + epoch := s.EpochCounter() var ( nonce uint32 = 1 vub uint32 vubP *uint32 - err error ) if prm.Hash != nil { @@ -138,6 +147,30 @@ func (s *Server) voteForSidechainValidator(prm governance.VoteValidatorPrm) erro return nil } +func (s *Server) alreadyVoted(validatorsToVote keys.PublicKeys) (bool, error) { + currentValidators := make(map[keys.PublicKey]struct{}, len(s.contracts.alphabet)) + for letter, contract := range s.contracts.alphabet { + validator, err := s.morphClient.AccountVote(contract) + if err != nil { + return false, fmt.Errorf("receiving %s's vote: %w", letter, err) + } + + if validator == nil { + continue + } + + currentValidators[*validator] = struct{}{} + } + + for _, v := range validatorsToVote { + if _, voted := currentValidators[*v]; !voted { + return false, nil + } + } + + return true, nil +} + // VoteForSidechainValidator calls vote method on alphabet contracts with // the provided list of keys. func (s *Server) VoteForSidechainValidator(prm governance.VoteValidatorPrm) error {