Skip to content

Commit 83172e7

Browse files
committed
refactor(model): one shared predicate for provider supply
The gated membership and the advertised provider_count applied different rules: membership was gated on egress health, the count was not. Extract the health check into providerCountFilter, shared by both jobs, and add the observed-country check the count needs. UpdateClientScores keeps using passesHealth alone because its pool is not country scoped.
1 parent c15d205 commit 83172e7

2 files changed

Lines changed: 132 additions & 30 deletions

File tree

model/network_client_location_model.go

Lines changed: 79 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1772,6 +1772,79 @@ func distinctIds(ids ...*server.Id) []server.Id {
17721772
return distinct
17731773
}
17741774

1775+
// The share of destinations a provider must reach to count as healthy: 90%,
1776+
// as 9/10. Compared exactly as `10*ok >= 9*total` rather than through a float
1777+
// division, so the boundary is the same for every denominator.
1778+
//
1779+
// Package scope, not function scope: both UpdateClientScores and
1780+
// UpdateClientLocations gate on this now, and two copies could drift.
1781+
const minEgressHealthOKNumerator = 9
1782+
const minEgressHealthOKDenominator = 10
1783+
1784+
// providerCountFilter answers one question: does this provider count as real,
1785+
// reachable supply?
1786+
//
1787+
// It exists so the advertised provider_count (UpdateClientLocations) and the
1788+
// gated membership (UpdateClientScores) apply an IDENTICAL predicate. They ran
1789+
// different rules before: membership was gated on egress health while the count
1790+
// was not, so a location could survive the gate and still advertise providers
1791+
// that no probe had ever reached.
1792+
//
1793+
// Both maps are loaded once per pass. These loops run over the entire provider
1794+
// population, so a per-provider query here is one round trip per provider.
1795+
type providerCountFilter struct {
1796+
healthCounts map[server.Id]ProviderEgressHealthCounts
1797+
countryCodes map[server.Id]string
1798+
}
1799+
1800+
func newProviderCountFilter(ctx context.Context) providerCountFilter {
1801+
return providerCountFilter{
1802+
healthCounts: GetAllProviderEgressHealthCounts(ctx),
1803+
countryCodes: GetAllProviderEgressCountryCodes(ctx),
1804+
}
1805+
}
1806+
1807+
// passesHealth reports whether a probe has MEASURED this provider healthy.
1808+
// Fail closed: no record at all (never probed) does not pass, and neither does
1809+
// a record with no destinations in it, which is not a measurement of anything.
1810+
// Guarding total also keeps the ratio well defined.
1811+
//
1812+
// Compared exactly as 10*ok >= 9*total rather than through a float, so the 90%
1813+
// boundary cannot drift with rounding.
1814+
func (f providerCountFilter) passesHealth(clientId server.Id) bool {
1815+
counts, ok := f.healthCounts[clientId]
1816+
if !ok {
1817+
return false
1818+
}
1819+
if counts.Total <= 0 {
1820+
return false
1821+
}
1822+
return minEgressHealthOKDenominator*counts.OKCount >= minEgressHealthOKNumerator*counts.Total
1823+
}
1824+
1825+
// countsTowardCountry reports whether this provider counts as supply for
1826+
// countryCode. It must both be measured healthy and have been OBSERVED
1827+
// egressing from that country.
1828+
//
1829+
// The two locations are different claims. network_client_location is where the
1830+
// provider says it is, derived from its own connection. provider_egress_location
1831+
// is where a probe actually watched its traffic leave. Counting on the claim
1832+
// alone advertises providers in countries they do not egress from -- measured
1833+
// on beta at 3 of 152 healthy providers claiming `at` while egressing from `gb`
1834+
// -- which is what an adversarial provider would exploit at scale.
1835+
//
1836+
// A provider with no observed location is not counted, matching the health rule.
1837+
func (f providerCountFilter) countsTowardCountry(clientId server.Id, countryCode string) bool {
1838+
if !f.passesHealth(clientId) {
1839+
return false
1840+
}
1841+
observed, ok := f.countryCodes[clientId]
1842+
if !ok {
1843+
return false
1844+
}
1845+
return observed == strings.ToLower(countryCode)
1846+
}
1847+
17751848
func UpdateClientLocations(ctx context.Context, ttl time.Duration) (returnErr error) {
17761849
topCitiesPerRegion := 20
17771850
topCitiesPerCountry := 10
@@ -3060,20 +3133,6 @@ func UpdateClientScores(ctx context.Context, ttl time.Duration, parallel int) (r
30603133
minScoreScale := 0.1
30613134
maxScoreScale := 1.0
30623135

3063-
// the measured egress health a provider must reach to be offered to users
3064-
// at all, as a fraction of the destinations its last probe run sampled.
3065-
//
3066-
// 90% because it cleanly separates working from broken on the real
3067-
// population: the healthy fleet measures 129-131 of 131 destinations, while
3068-
// a dead proxy measures 0 of 131. Nothing observed sits near the line, so
3069-
// the exact figure is not load bearing -- it only has to be far above 0 and
3070-
// below the ~98% a genuinely working provider always clears.
3071-
//
3072-
// Compared exactly as `10*ok >= 9*total` rather than through a float
3073-
// division, so the boundary is the same for every denominator.
3074-
const minEgressHealthOKNumerator = 9
3075-
const minEgressHealthOKDenominator = 10
3076-
30773136
// health is loaded once for the whole pass rather than per client: this
30783137
// walks every provider, and the table is one row per ever-probed provider.
30793138
//
@@ -3095,21 +3154,11 @@ func UpdateClientScores(ctx context.Context, ttl time.Duration, parallel int) (r
30953154
// still handed to the prober and still graduates the moment it measures
30963155
// healthy. If that queue ever starts consulting these scores, an excluded
30973156
// provider can never be re-measured and is stuck out permanently.
3098-
egressHealthCounts := GetAllProviderEgressHealthCounts(ctx)
3099-
// passesEgressHealth reports whether a probe has MEASURED this provider
3100-
// healthy. Fail closed: no record at all (never probed) does not pass, and
3101-
// neither does a record with no destinations in it, which is also not a
3102-
// measurement of anything. Guarding total keeps the ratio well defined.
3103-
passesEgressHealth := func(clientId server.Id) bool {
3104-
counts, ok := egressHealthCounts[clientId]
3105-
if !ok {
3106-
return false
3107-
}
3108-
if counts.Total <= 0 {
3109-
return false
3110-
}
3111-
return minEgressHealthOKDenominator*counts.OKCount >= minEgressHealthOKNumerator*counts.Total
3112-
}
3157+
// Shared with UpdateClientLocations so the gated membership and the
3158+
// advertised count can never disagree about what "healthy" means.
3159+
// UpdateClientScores uses passesHealth ONLY: its candidate pool is not
3160+
// country-scoped, so the observed-country check does not apply here.
3161+
countFilter := newProviderCountFilter(ctx)
31133162

31143163
// migration: set each client score to the lowest lookback index index
31153164
migrateClientScore := func(clientScore *ClientScore) {
@@ -3136,7 +3185,7 @@ func UpdateClientScores(ctx context.Context, ttl time.Duration, parallel int) (r
31363185
// nothing else: it can only take a provider out of the pool, and the
31373186
// scaled-weight arithmetic below is untouched, so every provider that
31383187
// still qualifies keeps exactly the weight and ordering it has today.
3139-
passesHealth := passesEgressHealth(clientScore.ClientId)
3188+
passesHealth := countFilter.passesHealth(clientScore.ClientId)
31403189

31413190
for _, rankMode := range slices.Collect(maps.Keys(clientScore.Scores)) {
31423191
passesMinimum := passesHealth

model/network_client_location_model_test.go

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ import (
1010

1111
"maps"
1212

13+
"github.com/go-playground/assert/v2"
14+
1315
"github.com/urnetwork/connect"
1416

1517
"github.com/urnetwork/server"
@@ -3183,3 +3185,54 @@ func TestUpdateClientScoresRestoresAProviderWhoseHealthRecovers(t *testing.T) {
31833185
}
31843186
})
31853187
}
3188+
3189+
func TestProviderCountFilter(t *testing.T) {
3190+
healthy := server.NewId()
3191+
degraded := server.NewId()
3192+
unmeasured := server.NewId()
3193+
zeroTotal := server.NewId()
3194+
wrongCountry := server.NewId()
3195+
unobserved := server.NewId()
3196+
3197+
f := providerCountFilter{
3198+
healthCounts: map[server.Id]ProviderEgressHealthCounts{
3199+
// 118/131 is the first passing value: 10*118 >= 9*131 (1180 >= 1179)
3200+
healthy: {OKCount: 118, Total: 131},
3201+
// 117/131 is the last failing value: 1170 < 1179
3202+
degraded: {OKCount: 117, Total: 131},
3203+
zeroTotal: {OKCount: 0, Total: 0},
3204+
wrongCountry: {OKCount: 131, Total: 131},
3205+
unobserved: {OKCount: 131, Total: 131},
3206+
},
3207+
countryCodes: map[server.Id]string{
3208+
healthy: "us",
3209+
degraded: "us",
3210+
zeroTotal: "us",
3211+
wrongCountry: "gb",
3212+
// unobserved deliberately absent
3213+
},
3214+
}
3215+
3216+
// the 90% boundary, asserted on the integer comparison
3217+
assert.Equal(t, f.passesHealth(healthy), true)
3218+
assert.Equal(t, f.passesHealth(degraded), false)
3219+
3220+
// fail closed: never probed, and probed-with-no-destinations
3221+
assert.Equal(t, f.passesHealth(unmeasured), false)
3222+
assert.Equal(t, f.passesHealth(zeroTotal), false)
3223+
3224+
// counts only where health passes AND the observed country matches
3225+
assert.Equal(t, f.countsTowardCountry(healthy, "us"), true)
3226+
assert.Equal(t, f.countsTowardCountry(degraded, "us"), false)
3227+
3228+
// healthy but egressing from somewhere else: not counted in the claim
3229+
assert.Equal(t, f.countsTowardCountry(wrongCountry, "us"), false)
3230+
// ...and it does count where it actually is
3231+
assert.Equal(t, f.countsTowardCountry(wrongCountry, "gb"), true)
3232+
3233+
// healthy but never located: fail closed
3234+
assert.Equal(t, f.countsTowardCountry(unobserved, "us"), false)
3235+
3236+
// comparison is case insensitive on the caller's side
3237+
assert.Equal(t, f.countsTowardCountry(healthy, "US"), true)
3238+
}

0 commit comments

Comments
 (0)