diff --git a/common/configs/processConfigs.go b/common/configs/processConfigs.go index cdc20eaae85..6db42f27e2c 100644 --- a/common/configs/processConfigs.go +++ b/common/configs/processConfigs.go @@ -137,6 +137,9 @@ func checkRoundConfigValues(cfg config.ProcessConfigByRound) error { return fmt.Errorf("%w for MaxBlockProcessingTimeMs, received %d, min expected %d", process.ErrInvalidValue, cfg.MaxBlockProcessingTimeMs, minBlockProcessingTimeMs) } + if cfg.RoundModulusTriggerWhenSyncIsStuck == 0 { + return fmt.Errorf("%w for RoundModulusTriggerWhenSyncIsStuck", process.ErrInvalidValue) + } return nil } diff --git a/common/configs/processConfigs_test.go b/common/configs/processConfigs_test.go index e9d2b005051..96d6c6f2f54 100644 --- a/common/configs/processConfigs_test.go +++ b/common/configs/processConfigs_test.go @@ -24,6 +24,7 @@ func getConfigsByRound() []config.ProcessConfigByRound { NumFloodingRoundsOutOfSpecs: 4, MaxConsecutiveRoundsOfRatingDecrease: 600, MaxBlockProcessingTimeMs: 1000, + RoundModulusTriggerWhenSyncIsStuck: 10, }, { EnableRound: 1, @@ -35,6 +36,7 @@ func getConfigsByRound() []config.ProcessConfigByRound { NumFloodingRoundsOutOfSpecs: 40, MaxConsecutiveRoundsOfRatingDecrease: 6000, MaxBlockProcessingTimeMs: 1000, + RoundModulusTriggerWhenSyncIsStuck: 10, }, } } @@ -112,6 +114,21 @@ func TestNewProcessConfigsByEpoch(t *testing.T) { require.True(t, strings.Contains(err.Error(), "MaxRoundsToKeepUnprocessedMiniBlocks")) }) + t.Run("should return error for zero RoundModulusTriggerWhenSyncIsStuck value", func(t *testing.T) { + t.Parallel() + + confByEpoch := []config.ProcessConfigByEpoch{ + {EnableEpoch: 0, MaxMetaNoncesBehind: 15}, + } + confByRound := getConfigsByRound() + confByRound[0].RoundModulusTriggerWhenSyncIsStuck = 0 + + pce, err := configs.NewProcessConfigsHandler(confByEpoch, confByRound, &epochNotifier.RoundNotifierStub{}) + require.Nil(t, pce) + require.ErrorIs(t, err, process.ErrInvalidValue) + require.True(t, strings.Contains(err.Error(), "RoundModulusTriggerWhenSyncIsStuck")) + }) + t.Run("should return error for invalid max consecutive rounds of rating decrease value", func(t *testing.T) { t.Parallel() @@ -175,6 +192,7 @@ func TestProcessConfigsByEpoch_Getters(t *testing.T) { NumFloodingRoundsOutOfSpecs: 4, MaxConsecutiveRoundsOfRatingDecrease: 600, MaxBlockProcessingTimeMs: 1000, + RoundModulusTriggerWhenSyncIsStuck: 10, }, {EnableRound: 1, MaxRoundsWithoutNewBlockReceived: 11, @@ -187,6 +205,7 @@ func TestProcessConfigsByEpoch_Getters(t *testing.T) { NumFloodingRoundsOutOfSpecs: 40, MaxConsecutiveRoundsOfRatingDecrease: 6000, MaxBlockProcessingTimeMs: 2000, + RoundModulusTriggerWhenSyncIsStuck: 10, }, } diff --git a/consensus/spos/bls/ntpsync/roundSyncController.go b/consensus/spos/bls/ntpsync/roundSyncController.go index 64b5094f4f6..c33a14f9521 100644 --- a/consensus/spos/bls/ntpsync/roundSyncController.go +++ b/consensus/spos/bls/ntpsync/roundSyncController.go @@ -7,6 +7,7 @@ import ( "github.com/multiversx/mx-chain-go/consensus/spos" "github.com/multiversx/mx-chain-go/ntp" logger "github.com/multiversx/mx-chain-logger-go" + "golang.org/x/exp/slices" ) var log = logger.GetOrCreate("nonceSyncController") @@ -95,6 +96,8 @@ func areNoncesInAscendingOrder(nonces []uint64) bool { return false } + slices.Sort(nonces) + for i := 1; i < len(nonces); i++ { if nonces[i] != nonces[i-1]+1 { return false diff --git a/consensus/spos/bls/v2/subroundEndRound.go b/consensus/spos/bls/v2/subroundEndRound.go index bde22a3f478..b8245e19c2b 100644 --- a/consensus/spos/bls/v2/subroundEndRound.go +++ b/consensus/spos/bls/v2/subroundEndRound.go @@ -1016,6 +1016,11 @@ func (sr *subroundEndRound) receivedSignature(_ context.Context, cnsDta *consens return false } + if sr.HasProofForCompetingBlock() { + log.Debug("receivedSignature: competing block proof detected, dropping signature") + return false + } + index, err := sr.ConsensusGroupIndex(node) if err != nil { log.Debug("receivedSignature.ConsensusGroupIndex",