/
compute-score.ts
98 lines (83 loc) · 3.21 KB
/
compute-score.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import type { PeerStats } from './peer-stats.js'
import type { PeerScoreParams } from './peer-score-params.js'
export function computeScore(
peer: string,
pstats: PeerStats,
params: PeerScoreParams,
peerIPs: Map<string, Set<string>>
): number {
let score = 0
// topic stores
Object.entries(pstats.topics).forEach(([topic, tstats]) => {
// the topic parameters
const topicParams = params.topics[topic]
if (topicParams === undefined) {
// we are not scoring this topic
return
}
let topicScore = 0
// P1: time in Mesh
if (tstats.inMesh) {
let p1 = tstats.meshTime / topicParams.timeInMeshQuantum
if (p1 > topicParams.timeInMeshCap) {
p1 = topicParams.timeInMeshCap
}
topicScore += p1 * topicParams.timeInMeshWeight
}
// P2: first message deliveries
let p2 = tstats.firstMessageDeliveries
if (p2 > topicParams.firstMessageDeliveriesCap) {
p2 = topicParams.firstMessageDeliveriesCap
}
topicScore += p2 * topicParams.firstMessageDeliveriesWeight
// P3: mesh message deliveries
if (
tstats.meshMessageDeliveriesActive &&
tstats.meshMessageDeliveries < topicParams.meshMessageDeliveriesThreshold
) {
const deficit = topicParams.meshMessageDeliveriesThreshold - tstats.meshMessageDeliveries
const p3 = deficit * deficit
topicScore += p3 * topicParams.meshMessageDeliveriesWeight
}
// P3b:
// NOTE: the weight of P3b is negative (validated in validateTopicScoreParams) so this detracts
const p3b = tstats.meshFailurePenalty
topicScore += p3b * topicParams.meshFailurePenaltyWeight
// P4: invalid messages
// NOTE: the weight of P4 is negative (validated in validateTopicScoreParams) so this detracts
const p4 = tstats.invalidMessageDeliveries * tstats.invalidMessageDeliveries
topicScore += p4 * topicParams.invalidMessageDeliveriesWeight
// update score, mixing with topic weight
score += topicScore * topicParams.topicWeight
})
// apply the topic score cap, if any
if (params.topicScoreCap > 0 && score > params.topicScoreCap) {
score = params.topicScoreCap
}
// P5: application-specific score
const p5 = params.appSpecificScore(peer)
score += p5 * params.appSpecificWeight
// P6: IP colocation factor
pstats.knownIPs.forEach((ip) => {
if (params.IPColocationFactorWhitelist.has(ip)) {
return
}
// P6 has a cliff (IPColocationFactorThreshold)
// It's only applied if at least that many peers are connected to us from that source IP addr.
// It is quadratic, and the weight is negative (validated in validatePeerScoreParams)
const peersInIP = peerIPs.get(ip)
const numPeersInIP = peersInIP ? peersInIP.size : 0
if (numPeersInIP > params.IPColocationFactorThreshold) {
const surplus = numPeersInIP - params.IPColocationFactorThreshold
const p6 = surplus * surplus
score += p6 * params.IPColocationFactorWeight
}
})
// P7: behavioural pattern penalty
if (pstats.behaviourPenalty > params.behaviourPenaltyThreshold) {
const excess = pstats.behaviourPenalty - params.behaviourPenaltyThreshold
const p7 = excess * excess
score += p7 * params.behaviourPenaltyWeight
}
return score
}