diff --git a/internal/p2p/peermanager.go b/internal/p2p/peermanager.go index 3293468ae..4044ad569 100644 --- a/internal/p2p/peermanager.go +++ b/internal/p2p/peermanager.go @@ -42,7 +42,8 @@ const ( type PeerScore uint8 const ( - PeerScorePersistent PeerScore = math.MaxUint8 // persistent peers + PeerScorePersistent PeerScore = math.MaxUint8 // persistent peers + MaxPeerScoreNotPersistent PeerScore = PeerScorePersistent - 1 ) // PeerUpdate is a peer update event sent via PeerUpdates. @@ -1283,6 +1284,9 @@ func (p *peerInfo) Score() PeerScore { } score := p.MutableScore + if score > int64(MaxPeerScoreNotPersistent) { + score = int64(MaxPeerScoreNotPersistent) + } for _, addr := range p.AddressInfo { // DialFailures is reset when dials succeed, so this @@ -1294,10 +1298,6 @@ func (p *peerInfo) Score() PeerScore { return 0 } - if score >= math.MaxUint8 { - return PeerScore(math.MaxUint8) - } - return PeerScore(score) } diff --git a/internal/p2p/peermanager_scoring_test.go b/internal/p2p/peermanager_scoring_test.go index 4c7bef0cc..a45df0b72 100644 --- a/internal/p2p/peermanager_scoring_test.go +++ b/internal/p2p/peermanager_scoring_test.go @@ -80,4 +80,20 @@ func TestPeerScoring(t *testing.T) { time.Millisecond, "startAt=%d score=%d", start, peerManager.Scores()[id]) }) + t.Run("TestNonPersistantPeerUpperBound", func(t *testing.T) { + start := int64(peerManager.Scores()[id] + 1) + + for i := start; i <= int64(PeerScorePersistent); i++ { + peerManager.processPeerEvent(ctx, PeerUpdate{ + NodeID: id, + Status: PeerStatusGood, + }) + + if i == int64(PeerScorePersistent) { + require.EqualValues(t, MaxPeerScoreNotPersistent, peerManager.Scores()[id]) + } else { + require.EqualValues(t, i, peerManager.Scores()[id]) + } + } + }) } diff --git a/spec/abci++/abci++_methods_002_draft.md b/spec/abci++/abci++_methods_002_draft.md index 834c161bd..4114bb9b8 100644 --- a/spec/abci++/abci++_methods_002_draft.md +++ b/spec/abci++/abci++_methods_002_draft.md @@ -422,7 +422,7 @@ Note that, if _p_ has a non-`nil` _validValue_, Tendermint will use it as propos * The parameters and types of `RequestProcessProposal` are the same as `RequestPrepareProposal` and `RequestFinalizeBlock`. * The Application may fully execute the block as though it was handling `RequestFinalizeBlock`. - However, any resulting state changes must be kept as _canditade state_, + However, any resulting state changes must be kept as _candidate state_, and the Application should be ready to backtrack/discard it in case the decided block is different. * The header exactly matches the Tendermint header of the proposed block. * In next-block execution mode, the header hashes _AppHash_, _LastResultHash_, _ValidatorHash_,