@libp2p/gossipsub 14.1.1-6059227cb
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +85 -0
- package/dist/index.min.js +19 -0
- package/dist/index.min.js.map +7 -0
- package/dist/src/config.d.ts +32 -0
- package/dist/src/config.d.ts.map +1 -0
- package/dist/src/config.js +2 -0
- package/dist/src/config.js.map +1 -0
- package/dist/src/constants.d.ts +213 -0
- package/dist/src/constants.d.ts.map +1 -0
- package/dist/src/constants.js +217 -0
- package/dist/src/constants.js.map +1 -0
- package/dist/src/errors.d.ts +9 -0
- package/dist/src/errors.d.ts.map +1 -0
- package/dist/src/errors.js +15 -0
- package/dist/src/errors.js.map +1 -0
- package/dist/src/gossipsub.d.ts +419 -0
- package/dist/src/gossipsub.d.ts.map +1 -0
- package/dist/src/gossipsub.js +2520 -0
- package/dist/src/gossipsub.js.map +1 -0
- package/dist/src/index.d.ts +344 -0
- package/dist/src/index.d.ts.map +1 -0
- package/dist/src/index.js +43 -0
- package/dist/src/index.js.map +1 -0
- package/dist/src/message/decodeRpc.d.ts +11 -0
- package/dist/src/message/decodeRpc.d.ts.map +1 -0
- package/dist/src/message/decodeRpc.js +10 -0
- package/dist/src/message/decodeRpc.js.map +1 -0
- package/dist/src/message/index.d.ts +2 -0
- package/dist/src/message/index.d.ts.map +1 -0
- package/dist/src/message/index.js +2 -0
- package/dist/src/message/index.js.map +1 -0
- package/dist/src/message/rpc.d.ts +99 -0
- package/dist/src/message/rpc.d.ts.map +1 -0
- package/dist/src/message/rpc.js +663 -0
- package/dist/src/message/rpc.js.map +1 -0
- package/dist/src/message-cache.d.ts +80 -0
- package/dist/src/message-cache.d.ts.map +1 -0
- package/dist/src/message-cache.js +144 -0
- package/dist/src/message-cache.js.map +1 -0
- package/dist/src/metrics.d.ts +467 -0
- package/dist/src/metrics.d.ts.map +1 -0
- package/dist/src/metrics.js +896 -0
- package/dist/src/metrics.js.map +1 -0
- package/dist/src/score/compute-score.d.ts +4 -0
- package/dist/src/score/compute-score.d.ts.map +1 -0
- package/dist/src/score/compute-score.js +75 -0
- package/dist/src/score/compute-score.js.map +1 -0
- package/dist/src/score/index.d.ts +4 -0
- package/dist/src/score/index.d.ts.map +1 -0
- package/dist/src/score/index.js +4 -0
- package/dist/src/score/index.js.map +1 -0
- package/dist/src/score/message-deliveries.d.ts +45 -0
- package/dist/src/score/message-deliveries.d.ts.map +1 -0
- package/dist/src/score/message-deliveries.js +75 -0
- package/dist/src/score/message-deliveries.js.map +1 -0
- package/dist/src/score/peer-score-params.d.ts +125 -0
- package/dist/src/score/peer-score-params.d.ts.map +1 -0
- package/dist/src/score/peer-score-params.js +159 -0
- package/dist/src/score/peer-score-params.js.map +1 -0
- package/dist/src/score/peer-score-thresholds.d.ts +31 -0
- package/dist/src/score/peer-score-thresholds.d.ts.map +1 -0
- package/dist/src/score/peer-score-thresholds.js +32 -0
- package/dist/src/score/peer-score-thresholds.js.map +1 -0
- package/dist/src/score/peer-score.d.ts +119 -0
- package/dist/src/score/peer-score.d.ts.map +1 -0
- package/dist/src/score/peer-score.js +459 -0
- package/dist/src/score/peer-score.js.map +1 -0
- package/dist/src/score/peer-stats.d.ts +32 -0
- package/dist/src/score/peer-stats.d.ts.map +1 -0
- package/dist/src/score/peer-stats.js +2 -0
- package/dist/src/score/peer-stats.js.map +1 -0
- package/dist/src/score/scoreMetrics.d.ts +23 -0
- package/dist/src/score/scoreMetrics.d.ts.map +1 -0
- package/dist/src/score/scoreMetrics.js +155 -0
- package/dist/src/score/scoreMetrics.js.map +1 -0
- package/dist/src/stream.d.ts +30 -0
- package/dist/src/stream.d.ts.map +1 -0
- package/dist/src/stream.js +55 -0
- package/dist/src/stream.js.map +1 -0
- package/dist/src/tracer.d.ts +53 -0
- package/dist/src/tracer.d.ts.map +1 -0
- package/dist/src/tracer.js +155 -0
- package/dist/src/tracer.js.map +1 -0
- package/dist/src/types.d.ts +148 -0
- package/dist/src/types.d.ts.map +1 -0
- package/dist/src/types.js +90 -0
- package/dist/src/types.js.map +1 -0
- package/dist/src/utils/buildRawMessage.d.ts +20 -0
- package/dist/src/utils/buildRawMessage.d.ts.map +1 -0
- package/dist/src/utils/buildRawMessage.js +151 -0
- package/dist/src/utils/buildRawMessage.js.map +1 -0
- package/dist/src/utils/create-gossip-rpc.d.ts +7 -0
- package/dist/src/utils/create-gossip-rpc.d.ts.map +1 -0
- package/dist/src/utils/create-gossip-rpc.js +31 -0
- package/dist/src/utils/create-gossip-rpc.js.map +1 -0
- package/dist/src/utils/index.d.ts +4 -0
- package/dist/src/utils/index.d.ts.map +1 -0
- package/dist/src/utils/index.js +4 -0
- package/dist/src/utils/index.js.map +1 -0
- package/dist/src/utils/messageIdToString.d.ts +5 -0
- package/dist/src/utils/messageIdToString.d.ts.map +1 -0
- package/dist/src/utils/messageIdToString.js +8 -0
- package/dist/src/utils/messageIdToString.js.map +1 -0
- package/dist/src/utils/msgIdFn.d.ts +10 -0
- package/dist/src/utils/msgIdFn.d.ts.map +1 -0
- package/dist/src/utils/msgIdFn.js +23 -0
- package/dist/src/utils/msgIdFn.js.map +1 -0
- package/dist/src/utils/multiaddr.d.ts +3 -0
- package/dist/src/utils/multiaddr.d.ts.map +1 -0
- package/dist/src/utils/multiaddr.js +15 -0
- package/dist/src/utils/multiaddr.js.map +1 -0
- package/dist/src/utils/publishConfig.d.ts +8 -0
- package/dist/src/utils/publishConfig.d.ts.map +1 -0
- package/dist/src/utils/publishConfig.js +25 -0
- package/dist/src/utils/publishConfig.js.map +1 -0
- package/dist/src/utils/set.d.ts +14 -0
- package/dist/src/utils/set.d.ts.map +1 -0
- package/dist/src/utils/set.js +41 -0
- package/dist/src/utils/set.js.map +1 -0
- package/dist/src/utils/shuffle.d.ts +7 -0
- package/dist/src/utils/shuffle.d.ts.map +1 -0
- package/dist/src/utils/shuffle.js +21 -0
- package/dist/src/utils/shuffle.js.map +1 -0
- package/dist/src/utils/time-cache.d.ts +22 -0
- package/dist/src/utils/time-cache.d.ts.map +1 -0
- package/dist/src/utils/time-cache.js +54 -0
- package/dist/src/utils/time-cache.js.map +1 -0
- package/package.json +142 -0
- package/src/config.ts +31 -0
- package/src/constants.ts +261 -0
- package/src/errors.ts +17 -0
- package/src/gossipsub.ts +3061 -0
- package/src/index.ts +404 -0
- package/src/message/decodeRpc.ts +19 -0
- package/src/message/index.ts +1 -0
- package/src/message/rpc.proto +58 -0
- package/src/message/rpc.ts +848 -0
- package/src/message-cache.ts +196 -0
- package/src/metrics.ts +1014 -0
- package/src/score/compute-score.ts +98 -0
- package/src/score/index.ts +3 -0
- package/src/score/message-deliveries.ts +95 -0
- package/src/score/peer-score-params.ts +316 -0
- package/src/score/peer-score-thresholds.ts +70 -0
- package/src/score/peer-score.ts +565 -0
- package/src/score/peer-stats.ts +33 -0
- package/src/score/scoreMetrics.ts +215 -0
- package/src/stream.ts +79 -0
- package/src/tracer.ts +177 -0
- package/src/types.ts +178 -0
- package/src/utils/buildRawMessage.ts +174 -0
- package/src/utils/create-gossip-rpc.ts +34 -0
- package/src/utils/index.ts +3 -0
- package/src/utils/messageIdToString.ts +8 -0
- package/src/utils/msgIdFn.ts +24 -0
- package/src/utils/multiaddr.ts +19 -0
- package/src/utils/publishConfig.ts +33 -0
- package/src/utils/set.ts +43 -0
- package/src/utils/shuffle.ts +21 -0
- package/src/utils/time-cache.ts +71 -0
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { InvalidPeerScoreThresholdsError } from '../errors.js';
|
|
2
|
+
export const defaultPeerScoreThresholds = {
|
|
3
|
+
gossipThreshold: -10,
|
|
4
|
+
publishThreshold: -50,
|
|
5
|
+
graylistThreshold: -80,
|
|
6
|
+
acceptPXThreshold: 10,
|
|
7
|
+
opportunisticGraftThreshold: 20
|
|
8
|
+
};
|
|
9
|
+
export function createPeerScoreThresholds(p = {}) {
|
|
10
|
+
return {
|
|
11
|
+
...defaultPeerScoreThresholds,
|
|
12
|
+
...p
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
export function validatePeerScoreThresholds(p) {
|
|
16
|
+
if (p.gossipThreshold > 0) {
|
|
17
|
+
throw new InvalidPeerScoreThresholdsError('invalid gossip threshold; it must be <= 0');
|
|
18
|
+
}
|
|
19
|
+
if (p.publishThreshold > 0 || p.publishThreshold > p.gossipThreshold) {
|
|
20
|
+
throw new InvalidPeerScoreThresholdsError('invalid publish threshold; it must be <= 0 and <= gossip threshold');
|
|
21
|
+
}
|
|
22
|
+
if (p.graylistThreshold > 0 || p.graylistThreshold > p.publishThreshold) {
|
|
23
|
+
throw new InvalidPeerScoreThresholdsError('invalid graylist threshold; it must be <= 0 and <= publish threshold');
|
|
24
|
+
}
|
|
25
|
+
if (p.acceptPXThreshold < 0) {
|
|
26
|
+
throw new InvalidPeerScoreThresholdsError('invalid accept PX threshold; it must be >= 0');
|
|
27
|
+
}
|
|
28
|
+
if (p.opportunisticGraftThreshold < 0) {
|
|
29
|
+
throw new InvalidPeerScoreThresholdsError('invalid opportunistic grafting threshold; it must be >= 0');
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
//# sourceMappingURL=peer-score-thresholds.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-score-thresholds.js","sourceRoot":"","sources":["../../../src/score/peer-score-thresholds.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,+BAA+B,EAAE,MAAM,cAAc,CAAA;AAsC9D,MAAM,CAAC,MAAM,0BAA0B,GAAwB;IAC7D,eAAe,EAAE,CAAC,EAAE;IACpB,gBAAgB,EAAE,CAAC,EAAE;IACrB,iBAAiB,EAAE,CAAC,EAAE;IACtB,iBAAiB,EAAE,EAAE;IACrB,2BAA2B,EAAE,EAAE;CAChC,CAAA;AAED,MAAM,UAAU,yBAAyB,CAAE,IAAkC,EAAE;IAC7E,OAAO;QACL,GAAG,0BAA0B;QAC7B,GAAG,CAAC;KACL,CAAA;AACH,CAAC;AAED,MAAM,UAAU,2BAA2B,CAAE,CAAsB;IACjE,IAAI,CAAC,CAAC,eAAe,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,+BAA+B,CAAC,2CAA2C,CAAC,CAAA;IACxF,CAAC;IACD,IAAI,CAAC,CAAC,gBAAgB,GAAG,CAAC,IAAI,CAAC,CAAC,gBAAgB,GAAG,CAAC,CAAC,eAAe,EAAE,CAAC;QACrE,MAAM,IAAI,+BAA+B,CAAC,oEAAoE,CAAC,CAAA;IACjH,CAAC;IACD,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAC,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAC,CAAC,gBAAgB,EAAE,CAAC;QACxE,MAAM,IAAI,+BAA+B,CAAC,sEAAsE,CAAC,CAAA;IACnH,CAAC;IACD,IAAI,CAAC,CAAC,iBAAiB,GAAG,CAAC,EAAE,CAAC;QAC5B,MAAM,IAAI,+BAA+B,CAAC,8CAA8C,CAAC,CAAA;IAC3F,CAAC;IACD,IAAI,CAAC,CAAC,2BAA2B,GAAG,CAAC,EAAE,CAAC;QACtC,MAAM,IAAI,+BAA+B,CAAC,2DAA2D,CAAC,CAAA;IACxG,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { RejectReason } from '../types.js';
|
|
2
|
+
import { MapDef } from '../utils/set.js';
|
|
3
|
+
import { computeScore } from './compute-score.js';
|
|
4
|
+
import { MessageDeliveries } from './message-deliveries.js';
|
|
5
|
+
import type { MsgIdStr, PeerIdStr, TopicStr } from '../types.js';
|
|
6
|
+
import type { PeerScoreParams } from './peer-score-params.js';
|
|
7
|
+
import type { PeerStats } from './peer-stats.js';
|
|
8
|
+
import type { Metrics, ScorePenalty } from '../metrics.js';
|
|
9
|
+
import type { ComponentLogger } from '@libp2p/interface';
|
|
10
|
+
interface PeerScoreOpts {
|
|
11
|
+
/**
|
|
12
|
+
* Miliseconds to cache computed score per peer
|
|
13
|
+
*/
|
|
14
|
+
scoreCacheValidityMs: number;
|
|
15
|
+
computeScore?: typeof computeScore;
|
|
16
|
+
}
|
|
17
|
+
interface ScoreCacheEntry {
|
|
18
|
+
/** The cached score */
|
|
19
|
+
score: number;
|
|
20
|
+
/** Unix timestamp in miliseconds, the time after which the cached score for a peer is no longer valid */
|
|
21
|
+
cacheUntil: number;
|
|
22
|
+
}
|
|
23
|
+
export type PeerScoreStatsDump = Record<PeerIdStr, PeerStats>;
|
|
24
|
+
export declare class PeerScore {
|
|
25
|
+
readonly params: PeerScoreParams;
|
|
26
|
+
private readonly metrics;
|
|
27
|
+
/**
|
|
28
|
+
* Per-peer stats for score calculation
|
|
29
|
+
*/
|
|
30
|
+
readonly peerStats: Map<string, PeerStats>;
|
|
31
|
+
/**
|
|
32
|
+
* IP colocation tracking; maps IP => set of peers.
|
|
33
|
+
*/
|
|
34
|
+
readonly peerIPs: MapDef<string, Set<string>>;
|
|
35
|
+
/**
|
|
36
|
+
* Cache score up to decayInterval if topic stats are unchanged.
|
|
37
|
+
*/
|
|
38
|
+
readonly scoreCache: Map<string, ScoreCacheEntry>;
|
|
39
|
+
/**
|
|
40
|
+
* Recent message delivery timing/participants
|
|
41
|
+
*/
|
|
42
|
+
readonly deliveryRecords: MessageDeliveries;
|
|
43
|
+
_backgroundInterval?: ReturnType<typeof setInterval>;
|
|
44
|
+
private readonly scoreCacheValidityMs;
|
|
45
|
+
private readonly computeScore;
|
|
46
|
+
private readonly log;
|
|
47
|
+
constructor(params: PeerScoreParams, metrics: Metrics | null, componentLogger: ComponentLogger, opts: PeerScoreOpts);
|
|
48
|
+
get size(): number;
|
|
49
|
+
/**
|
|
50
|
+
* Start PeerScore instance
|
|
51
|
+
*/
|
|
52
|
+
start(): void;
|
|
53
|
+
/**
|
|
54
|
+
* Stop PeerScore instance
|
|
55
|
+
*/
|
|
56
|
+
stop(): void;
|
|
57
|
+
/**
|
|
58
|
+
* Periodic maintenance
|
|
59
|
+
*/
|
|
60
|
+
background(): void;
|
|
61
|
+
dumpPeerScoreStats(): PeerScoreStatsDump;
|
|
62
|
+
messageFirstSeenTimestampMs(msgIdStr: MsgIdStr): number | null;
|
|
63
|
+
/**
|
|
64
|
+
* Decays scores, and purges score records for disconnected peers once their expiry has elapsed.
|
|
65
|
+
*/
|
|
66
|
+
refreshScores(): void;
|
|
67
|
+
/**
|
|
68
|
+
* Return the score for a peer
|
|
69
|
+
*/
|
|
70
|
+
score(id: PeerIdStr): number;
|
|
71
|
+
/**
|
|
72
|
+
* Apply a behavioural penalty to a peer
|
|
73
|
+
*/
|
|
74
|
+
addPenalty(id: PeerIdStr, penalty: number, penaltyLabel: ScorePenalty): void;
|
|
75
|
+
addPeer(id: PeerIdStr): void;
|
|
76
|
+
/** Adds a new IP to a peer, if the peer is not known the update is ignored */
|
|
77
|
+
addIP(id: PeerIdStr, ip: string): void;
|
|
78
|
+
/** Remove peer association with IP */
|
|
79
|
+
removeIP(id: PeerIdStr, ip: string): void;
|
|
80
|
+
removePeer(id: PeerIdStr): void;
|
|
81
|
+
/** Handles scoring functionality as a peer GRAFTs to a topic. */
|
|
82
|
+
graft(id: PeerIdStr, topic: TopicStr): void;
|
|
83
|
+
/** Handles scoring functionality as a peer PRUNEs from a topic. */
|
|
84
|
+
prune(id: PeerIdStr, topic: TopicStr): void;
|
|
85
|
+
validateMessage(msgIdStr: MsgIdStr): void;
|
|
86
|
+
deliverMessage(from: PeerIdStr, msgIdStr: MsgIdStr, topic: TopicStr): void;
|
|
87
|
+
/**
|
|
88
|
+
* Similar to `rejectMessage` except does not require the message id or reason for an invalid message.
|
|
89
|
+
*/
|
|
90
|
+
rejectInvalidMessage(from: PeerIdStr, topic: TopicStr): void;
|
|
91
|
+
rejectMessage(from: PeerIdStr, msgIdStr: MsgIdStr, topic: TopicStr, reason: RejectReason): void;
|
|
92
|
+
duplicateMessage(from: PeerIdStr, msgIdStr: MsgIdStr, topic: TopicStr): void;
|
|
93
|
+
/**
|
|
94
|
+
* Increments the "invalid message deliveries" counter for all scored topics the message is published in.
|
|
95
|
+
*/
|
|
96
|
+
markInvalidMessageDelivery(from: PeerIdStr, topic: TopicStr): void;
|
|
97
|
+
/**
|
|
98
|
+
* Increments the "first message deliveries" counter for all scored topics the message is published in,
|
|
99
|
+
* as well as the "mesh message deliveries" counter, if the peer is in the mesh for the topic.
|
|
100
|
+
* Messages already known (with the seenCache) are counted with markDuplicateMessageDelivery()
|
|
101
|
+
*/
|
|
102
|
+
markFirstMessageDelivery(from: PeerIdStr, topic: TopicStr): void;
|
|
103
|
+
/**
|
|
104
|
+
* Increments the "mesh message deliveries" counter for messages we've seen before,
|
|
105
|
+
* as long the message was received within the P3 window.
|
|
106
|
+
*/
|
|
107
|
+
markDuplicateMessageDelivery(from: PeerIdStr, topic: TopicStr, validatedTime?: number): void;
|
|
108
|
+
/**
|
|
109
|
+
* Removes an IP list from the tracking list for a peer.
|
|
110
|
+
*/
|
|
111
|
+
private removeIPsForPeer;
|
|
112
|
+
/**
|
|
113
|
+
* Returns topic stats if they exist, otherwise if the supplied parameters score the
|
|
114
|
+
* topic, inserts the default stats and returns a reference to those. If neither apply, returns None.
|
|
115
|
+
*/
|
|
116
|
+
private getPtopicStats;
|
|
117
|
+
}
|
|
118
|
+
export {};
|
|
119
|
+
//# sourceMappingURL=peer-score.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-score.d.ts","sourceRoot":"","sources":["../../../src/score/peer-score.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,459 @@
|
|
|
1
|
+
import { RejectReason } from '../types.js';
|
|
2
|
+
import { MapDef } from '../utils/set.js';
|
|
3
|
+
import { computeScore } from './compute-score.js';
|
|
4
|
+
import { MessageDeliveries, DeliveryRecordStatus } from './message-deliveries.js';
|
|
5
|
+
import { validatePeerScoreParams } from './peer-score-params.js';
|
|
6
|
+
export class PeerScore {
|
|
7
|
+
params;
|
|
8
|
+
metrics;
|
|
9
|
+
/**
|
|
10
|
+
* Per-peer stats for score calculation
|
|
11
|
+
*/
|
|
12
|
+
peerStats = new Map();
|
|
13
|
+
/**
|
|
14
|
+
* IP colocation tracking; maps IP => set of peers.
|
|
15
|
+
*/
|
|
16
|
+
peerIPs = new MapDef(() => new Set());
|
|
17
|
+
/**
|
|
18
|
+
* Cache score up to decayInterval if topic stats are unchanged.
|
|
19
|
+
*/
|
|
20
|
+
scoreCache = new Map();
|
|
21
|
+
/**
|
|
22
|
+
* Recent message delivery timing/participants
|
|
23
|
+
*/
|
|
24
|
+
deliveryRecords = new MessageDeliveries();
|
|
25
|
+
_backgroundInterval;
|
|
26
|
+
scoreCacheValidityMs;
|
|
27
|
+
computeScore;
|
|
28
|
+
log;
|
|
29
|
+
constructor(params, metrics, componentLogger, opts) {
|
|
30
|
+
this.params = params;
|
|
31
|
+
this.metrics = metrics;
|
|
32
|
+
validatePeerScoreParams(params);
|
|
33
|
+
this.scoreCacheValidityMs = opts.scoreCacheValidityMs;
|
|
34
|
+
this.computeScore = opts.computeScore ?? computeScore;
|
|
35
|
+
this.log = componentLogger.forComponent('libp2p:gossipsub:score');
|
|
36
|
+
}
|
|
37
|
+
get size() {
|
|
38
|
+
return this.peerStats.size;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Start PeerScore instance
|
|
42
|
+
*/
|
|
43
|
+
start() {
|
|
44
|
+
if (this._backgroundInterval != null) {
|
|
45
|
+
this.log('Peer score already running');
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this._backgroundInterval = setInterval(() => { this.background(); }, this.params.decayInterval);
|
|
49
|
+
this.log('started');
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Stop PeerScore instance
|
|
53
|
+
*/
|
|
54
|
+
stop() {
|
|
55
|
+
if (this._backgroundInterval == null) {
|
|
56
|
+
this.log('Peer score already stopped');
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
clearInterval(this._backgroundInterval);
|
|
60
|
+
delete this._backgroundInterval;
|
|
61
|
+
this.peerIPs.clear();
|
|
62
|
+
this.peerStats.clear();
|
|
63
|
+
this.deliveryRecords.clear();
|
|
64
|
+
this.log('stopped');
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Periodic maintenance
|
|
68
|
+
*/
|
|
69
|
+
background() {
|
|
70
|
+
this.refreshScores();
|
|
71
|
+
this.deliveryRecords.gc();
|
|
72
|
+
}
|
|
73
|
+
dumpPeerScoreStats() {
|
|
74
|
+
return Object.fromEntries(Array.from(this.peerStats.entries()).map(([peer, stats]) => [peer, stats]));
|
|
75
|
+
}
|
|
76
|
+
messageFirstSeenTimestampMs(msgIdStr) {
|
|
77
|
+
const drec = this.deliveryRecords.getRecord(msgIdStr);
|
|
78
|
+
return (drec != null) ? drec.firstSeenTsMs : null;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Decays scores, and purges score records for disconnected peers once their expiry has elapsed.
|
|
82
|
+
*/
|
|
83
|
+
refreshScores() {
|
|
84
|
+
const now = Date.now();
|
|
85
|
+
const decayToZero = this.params.decayToZero;
|
|
86
|
+
this.peerStats.forEach((pstats, id) => {
|
|
87
|
+
if (!pstats.connected) {
|
|
88
|
+
// has the retention period expired?
|
|
89
|
+
if (now > pstats.expire) {
|
|
90
|
+
// yes, throw it away (but clean up the IP tracking first)
|
|
91
|
+
this.removeIPsForPeer(id, pstats.knownIPs);
|
|
92
|
+
this.peerStats.delete(id);
|
|
93
|
+
this.scoreCache.delete(id);
|
|
94
|
+
}
|
|
95
|
+
// we don't decay retained scores, as the peer is not active.
|
|
96
|
+
// this way the peer cannot reset a negative score by simply disconnecting and reconnecting,
|
|
97
|
+
// unless the retention period has elapsed.
|
|
98
|
+
// similarly, a well behaved peer does not lose its score by getting disconnected.
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
Object.entries(pstats.topics).forEach(([topic, tstats]) => {
|
|
102
|
+
const tparams = this.params.topics[topic];
|
|
103
|
+
if (tparams === undefined) {
|
|
104
|
+
// we are not scoring this topic
|
|
105
|
+
// should be unreachable, we only add scored topics to pstats
|
|
106
|
+
return;
|
|
107
|
+
}
|
|
108
|
+
// decay counters
|
|
109
|
+
tstats.firstMessageDeliveries *= tparams.firstMessageDeliveriesDecay;
|
|
110
|
+
if (tstats.firstMessageDeliveries < decayToZero) {
|
|
111
|
+
tstats.firstMessageDeliveries = 0;
|
|
112
|
+
}
|
|
113
|
+
tstats.meshMessageDeliveries *= tparams.meshMessageDeliveriesDecay;
|
|
114
|
+
if (tstats.meshMessageDeliveries < decayToZero) {
|
|
115
|
+
tstats.meshMessageDeliveries = 0;
|
|
116
|
+
}
|
|
117
|
+
tstats.meshFailurePenalty *= tparams.meshFailurePenaltyDecay;
|
|
118
|
+
if (tstats.meshFailurePenalty < decayToZero) {
|
|
119
|
+
tstats.meshFailurePenalty = 0;
|
|
120
|
+
}
|
|
121
|
+
tstats.invalidMessageDeliveries *= tparams.invalidMessageDeliveriesDecay;
|
|
122
|
+
if (tstats.invalidMessageDeliveries < decayToZero) {
|
|
123
|
+
tstats.invalidMessageDeliveries = 0;
|
|
124
|
+
}
|
|
125
|
+
// update mesh time and activate mesh message delivery parameter if need be
|
|
126
|
+
if (tstats.inMesh) {
|
|
127
|
+
tstats.meshTime = now - tstats.graftTime;
|
|
128
|
+
if (tstats.meshTime > tparams.meshMessageDeliveriesActivation) {
|
|
129
|
+
tstats.meshMessageDeliveriesActive = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
});
|
|
133
|
+
// decay P7 counter
|
|
134
|
+
pstats.behaviourPenalty *= this.params.behaviourPenaltyDecay;
|
|
135
|
+
if (pstats.behaviourPenalty < decayToZero) {
|
|
136
|
+
pstats.behaviourPenalty = 0;
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Return the score for a peer
|
|
142
|
+
*/
|
|
143
|
+
score(id) {
|
|
144
|
+
this.metrics?.scoreFnCalls.inc();
|
|
145
|
+
const pstats = this.peerStats.get(id);
|
|
146
|
+
if (pstats == null) {
|
|
147
|
+
return 0;
|
|
148
|
+
}
|
|
149
|
+
const now = Date.now();
|
|
150
|
+
const cacheEntry = this.scoreCache.get(id);
|
|
151
|
+
// Found cached score within validity period
|
|
152
|
+
if ((cacheEntry != null) && cacheEntry.cacheUntil > now) {
|
|
153
|
+
return cacheEntry.score;
|
|
154
|
+
}
|
|
155
|
+
this.metrics?.scoreFnRuns.inc();
|
|
156
|
+
const score = this.computeScore(id, pstats, this.params, this.peerIPs);
|
|
157
|
+
const cacheUntil = now + this.scoreCacheValidityMs;
|
|
158
|
+
if (cacheEntry != null) {
|
|
159
|
+
this.metrics?.scoreCachedDelta.observe(Math.abs(score - cacheEntry.score));
|
|
160
|
+
cacheEntry.score = score;
|
|
161
|
+
cacheEntry.cacheUntil = cacheUntil;
|
|
162
|
+
}
|
|
163
|
+
else {
|
|
164
|
+
this.scoreCache.set(id, { score, cacheUntil });
|
|
165
|
+
}
|
|
166
|
+
return score;
|
|
167
|
+
}
|
|
168
|
+
/**
|
|
169
|
+
* Apply a behavioural penalty to a peer
|
|
170
|
+
*/
|
|
171
|
+
addPenalty(id, penalty, penaltyLabel) {
|
|
172
|
+
const pstats = this.peerStats.get(id);
|
|
173
|
+
if (pstats != null) {
|
|
174
|
+
pstats.behaviourPenalty += penalty;
|
|
175
|
+
this.metrics?.onScorePenalty(penaltyLabel);
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
addPeer(id) {
|
|
179
|
+
// create peer stats (not including topic stats for each topic to be scored)
|
|
180
|
+
// topic stats will be added as needed
|
|
181
|
+
const pstats = {
|
|
182
|
+
connected: true,
|
|
183
|
+
expire: 0,
|
|
184
|
+
topics: {},
|
|
185
|
+
knownIPs: new Set(),
|
|
186
|
+
behaviourPenalty: 0
|
|
187
|
+
};
|
|
188
|
+
this.peerStats.set(id, pstats);
|
|
189
|
+
}
|
|
190
|
+
/** Adds a new IP to a peer, if the peer is not known the update is ignored */
|
|
191
|
+
addIP(id, ip) {
|
|
192
|
+
const pstats = this.peerStats.get(id);
|
|
193
|
+
if (pstats != null) {
|
|
194
|
+
pstats.knownIPs.add(ip);
|
|
195
|
+
}
|
|
196
|
+
this.peerIPs.getOrDefault(ip).add(id);
|
|
197
|
+
}
|
|
198
|
+
/** Remove peer association with IP */
|
|
199
|
+
removeIP(id, ip) {
|
|
200
|
+
const pstats = this.peerStats.get(id);
|
|
201
|
+
if (pstats != null) {
|
|
202
|
+
pstats.knownIPs.delete(ip);
|
|
203
|
+
}
|
|
204
|
+
const peersWithIP = this.peerIPs.get(ip);
|
|
205
|
+
if (peersWithIP != null) {
|
|
206
|
+
peersWithIP.delete(id);
|
|
207
|
+
if (peersWithIP.size === 0) {
|
|
208
|
+
this.peerIPs.delete(ip);
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
removePeer(id) {
|
|
213
|
+
const pstats = this.peerStats.get(id);
|
|
214
|
+
if (pstats == null) {
|
|
215
|
+
return;
|
|
216
|
+
}
|
|
217
|
+
// decide whether to retain the score; this currently only retains non-positive scores
|
|
218
|
+
// to dissuade attacks on the score function.
|
|
219
|
+
if (this.score(id) > 0) {
|
|
220
|
+
this.removeIPsForPeer(id, pstats.knownIPs);
|
|
221
|
+
this.peerStats.delete(id);
|
|
222
|
+
return;
|
|
223
|
+
}
|
|
224
|
+
// furthermore, when we decide to retain the score, the firstMessageDelivery counters are
|
|
225
|
+
// reset to 0 and mesh delivery penalties applied.
|
|
226
|
+
Object.entries(pstats.topics).forEach(([topic, tstats]) => {
|
|
227
|
+
tstats.firstMessageDeliveries = 0;
|
|
228
|
+
const threshold = this.params.topics[topic].meshMessageDeliveriesThreshold;
|
|
229
|
+
if (tstats.inMesh && tstats.meshMessageDeliveriesActive && tstats.meshMessageDeliveries < threshold) {
|
|
230
|
+
const deficit = threshold - tstats.meshMessageDeliveries;
|
|
231
|
+
tstats.meshFailurePenalty += deficit * deficit;
|
|
232
|
+
}
|
|
233
|
+
tstats.inMesh = false;
|
|
234
|
+
tstats.meshMessageDeliveriesActive = false;
|
|
235
|
+
});
|
|
236
|
+
pstats.connected = false;
|
|
237
|
+
pstats.expire = Date.now() + this.params.retainScore;
|
|
238
|
+
}
|
|
239
|
+
/** Handles scoring functionality as a peer GRAFTs to a topic. */
|
|
240
|
+
graft(id, topic) {
|
|
241
|
+
const pstats = this.peerStats.get(id);
|
|
242
|
+
if (pstats != null) {
|
|
243
|
+
const tstats = this.getPtopicStats(pstats, topic);
|
|
244
|
+
if (tstats != null) {
|
|
245
|
+
// if we are scoring the topic, update the mesh status.
|
|
246
|
+
tstats.inMesh = true;
|
|
247
|
+
tstats.graftTime = Date.now();
|
|
248
|
+
tstats.meshTime = 0;
|
|
249
|
+
tstats.meshMessageDeliveriesActive = false;
|
|
250
|
+
}
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/** Handles scoring functionality as a peer PRUNEs from a topic. */
|
|
254
|
+
prune(id, topic) {
|
|
255
|
+
const pstats = this.peerStats.get(id);
|
|
256
|
+
if (pstats != null) {
|
|
257
|
+
const tstats = this.getPtopicStats(pstats, topic);
|
|
258
|
+
if (tstats != null) {
|
|
259
|
+
// sticky mesh delivery rate failure penalty
|
|
260
|
+
const threshold = this.params.topics[topic].meshMessageDeliveriesThreshold;
|
|
261
|
+
if (tstats.meshMessageDeliveriesActive && tstats.meshMessageDeliveries < threshold) {
|
|
262
|
+
const deficit = threshold - tstats.meshMessageDeliveries;
|
|
263
|
+
tstats.meshFailurePenalty += deficit * deficit;
|
|
264
|
+
}
|
|
265
|
+
tstats.meshMessageDeliveriesActive = false;
|
|
266
|
+
tstats.inMesh = false;
|
|
267
|
+
// TODO: Consider clearing score cache on important penalties
|
|
268
|
+
// this.scoreCache.delete(id)
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
}
|
|
272
|
+
validateMessage(msgIdStr) {
|
|
273
|
+
this.deliveryRecords.ensureRecord(msgIdStr);
|
|
274
|
+
}
|
|
275
|
+
deliverMessage(from, msgIdStr, topic) {
|
|
276
|
+
this.markFirstMessageDelivery(from, topic);
|
|
277
|
+
const drec = this.deliveryRecords.ensureRecord(msgIdStr);
|
|
278
|
+
const now = Date.now();
|
|
279
|
+
// defensive check that this is the first delivery trace -- delivery status should be unknown
|
|
280
|
+
if (drec.status !== DeliveryRecordStatus.unknown) {
|
|
281
|
+
this.log('unexpected delivery: message from %s was first seen %s ago and has delivery status %s', from, now - drec.firstSeenTsMs, DeliveryRecordStatus[drec.status]);
|
|
282
|
+
return;
|
|
283
|
+
}
|
|
284
|
+
// mark the message as valid and reward mesh peers that have already forwarded it to us
|
|
285
|
+
drec.status = DeliveryRecordStatus.valid;
|
|
286
|
+
drec.validated = now;
|
|
287
|
+
drec.peers.forEach((p) => {
|
|
288
|
+
// this check is to make sure a peer can't send us a message twice and get a double count
|
|
289
|
+
// if it is a first delivery.
|
|
290
|
+
if (p !== from.toString()) {
|
|
291
|
+
this.markDuplicateMessageDelivery(p, topic);
|
|
292
|
+
}
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
/**
|
|
296
|
+
* Similar to `rejectMessage` except does not require the message id or reason for an invalid message.
|
|
297
|
+
*/
|
|
298
|
+
rejectInvalidMessage(from, topic) {
|
|
299
|
+
this.markInvalidMessageDelivery(from, topic);
|
|
300
|
+
}
|
|
301
|
+
rejectMessage(from, msgIdStr, topic, reason) {
|
|
302
|
+
// eslint-disable-next-line default-case
|
|
303
|
+
switch (reason) {
|
|
304
|
+
// these messages are not tracked, but the peer is penalized as they are invalid
|
|
305
|
+
case RejectReason.Error:
|
|
306
|
+
this.markInvalidMessageDelivery(from, topic);
|
|
307
|
+
return;
|
|
308
|
+
// we ignore those messages, so do nothing.
|
|
309
|
+
case RejectReason.Blacklisted:
|
|
310
|
+
return;
|
|
311
|
+
// the rest are handled after record creation
|
|
312
|
+
}
|
|
313
|
+
const drec = this.deliveryRecords.ensureRecord(msgIdStr);
|
|
314
|
+
// defensive check that this is the first rejection -- delivery status should be unknown
|
|
315
|
+
if (drec.status !== DeliveryRecordStatus.unknown) {
|
|
316
|
+
this.log('unexpected rejection: message from %s was first seen %s ago and has delivery status %d', from, Date.now() - drec.firstSeenTsMs, DeliveryRecordStatus[drec.status]);
|
|
317
|
+
return;
|
|
318
|
+
}
|
|
319
|
+
if (reason === RejectReason.Ignore) {
|
|
320
|
+
// we were explicitly instructed by the validator to ignore the message but not penalize the peer
|
|
321
|
+
drec.status = DeliveryRecordStatus.ignored;
|
|
322
|
+
drec.peers.clear();
|
|
323
|
+
return;
|
|
324
|
+
}
|
|
325
|
+
// mark the message as invalid and penalize peers that have already forwarded it.
|
|
326
|
+
drec.status = DeliveryRecordStatus.invalid;
|
|
327
|
+
this.markInvalidMessageDelivery(from, topic);
|
|
328
|
+
drec.peers.forEach((p) => {
|
|
329
|
+
this.markInvalidMessageDelivery(p, topic);
|
|
330
|
+
});
|
|
331
|
+
// release the delivery time tracking map to free some memory early
|
|
332
|
+
drec.peers.clear();
|
|
333
|
+
}
|
|
334
|
+
duplicateMessage(from, msgIdStr, topic) {
|
|
335
|
+
const drec = this.deliveryRecords.ensureRecord(msgIdStr);
|
|
336
|
+
if (drec.peers.has(from)) {
|
|
337
|
+
// we have already seen this duplicate
|
|
338
|
+
return;
|
|
339
|
+
}
|
|
340
|
+
// eslint-disable-next-line default-case
|
|
341
|
+
switch (drec.status) {
|
|
342
|
+
case DeliveryRecordStatus.unknown:
|
|
343
|
+
// the message is being validated; track the peer delivery and wait for
|
|
344
|
+
// the Deliver/Reject/Ignore notification.
|
|
345
|
+
drec.peers.add(from);
|
|
346
|
+
break;
|
|
347
|
+
case DeliveryRecordStatus.valid:
|
|
348
|
+
// mark the peer delivery time to only count a duplicate delivery once.
|
|
349
|
+
drec.peers.add(from);
|
|
350
|
+
this.markDuplicateMessageDelivery(from, topic, drec.validated);
|
|
351
|
+
break;
|
|
352
|
+
case DeliveryRecordStatus.invalid:
|
|
353
|
+
// we no longer track delivery time
|
|
354
|
+
this.markInvalidMessageDelivery(from, topic);
|
|
355
|
+
break;
|
|
356
|
+
case DeliveryRecordStatus.ignored:
|
|
357
|
+
// the message was ignored; do nothing (we don't know if it was valid)
|
|
358
|
+
break;
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
/**
|
|
362
|
+
* Increments the "invalid message deliveries" counter for all scored topics the message is published in.
|
|
363
|
+
*/
|
|
364
|
+
markInvalidMessageDelivery(from, topic) {
|
|
365
|
+
const pstats = this.peerStats.get(from);
|
|
366
|
+
if (pstats != null) {
|
|
367
|
+
const tstats = this.getPtopicStats(pstats, topic);
|
|
368
|
+
if (tstats != null) {
|
|
369
|
+
tstats.invalidMessageDeliveries += 1;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
/**
|
|
374
|
+
* Increments the "first message deliveries" counter for all scored topics the message is published in,
|
|
375
|
+
* as well as the "mesh message deliveries" counter, if the peer is in the mesh for the topic.
|
|
376
|
+
* Messages already known (with the seenCache) are counted with markDuplicateMessageDelivery()
|
|
377
|
+
*/
|
|
378
|
+
markFirstMessageDelivery(from, topic) {
|
|
379
|
+
const pstats = this.peerStats.get(from);
|
|
380
|
+
if (pstats != null) {
|
|
381
|
+
const tstats = this.getPtopicStats(pstats, topic);
|
|
382
|
+
if (tstats != null) {
|
|
383
|
+
let cap = this.params.topics[topic].firstMessageDeliveriesCap;
|
|
384
|
+
tstats.firstMessageDeliveries = Math.min(cap, tstats.firstMessageDeliveries + 1);
|
|
385
|
+
if (tstats.inMesh) {
|
|
386
|
+
cap = this.params.topics[topic].meshMessageDeliveriesCap;
|
|
387
|
+
tstats.meshMessageDeliveries = Math.min(cap, tstats.meshMessageDeliveries + 1);
|
|
388
|
+
}
|
|
389
|
+
}
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
/**
|
|
393
|
+
* Increments the "mesh message deliveries" counter for messages we've seen before,
|
|
394
|
+
* as long the message was received within the P3 window.
|
|
395
|
+
*/
|
|
396
|
+
markDuplicateMessageDelivery(from, topic, validatedTime) {
|
|
397
|
+
const pstats = this.peerStats.get(from);
|
|
398
|
+
if (pstats != null) {
|
|
399
|
+
const now = validatedTime !== undefined ? Date.now() : 0;
|
|
400
|
+
const tstats = this.getPtopicStats(pstats, topic);
|
|
401
|
+
if (tstats != null && tstats.inMesh) {
|
|
402
|
+
const tparams = this.params.topics[topic];
|
|
403
|
+
// check against the mesh delivery window -- if the validated time is passed as 0, then
|
|
404
|
+
// the message was received before we finished validation and thus falls within the mesh
|
|
405
|
+
// delivery window.
|
|
406
|
+
if (validatedTime !== undefined) {
|
|
407
|
+
const deliveryDelayMs = now - validatedTime;
|
|
408
|
+
const isLateDelivery = deliveryDelayMs > tparams.meshMessageDeliveriesWindow;
|
|
409
|
+
this.metrics?.onDuplicateMsgDelivery(topic, deliveryDelayMs, isLateDelivery);
|
|
410
|
+
if (isLateDelivery) {
|
|
411
|
+
return;
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
const cap = tparams.meshMessageDeliveriesCap;
|
|
415
|
+
tstats.meshMessageDeliveries = Math.min(cap, tstats.meshMessageDeliveries + 1);
|
|
416
|
+
}
|
|
417
|
+
}
|
|
418
|
+
}
|
|
419
|
+
/**
|
|
420
|
+
* Removes an IP list from the tracking list for a peer.
|
|
421
|
+
*/
|
|
422
|
+
removeIPsForPeer(id, ipsToRemove) {
|
|
423
|
+
for (const ipToRemove of ipsToRemove) {
|
|
424
|
+
const peerSet = this.peerIPs.get(ipToRemove);
|
|
425
|
+
if (peerSet != null) {
|
|
426
|
+
peerSet.delete(id);
|
|
427
|
+
if (peerSet.size === 0) {
|
|
428
|
+
this.peerIPs.delete(ipToRemove);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
}
|
|
433
|
+
/**
|
|
434
|
+
* Returns topic stats if they exist, otherwise if the supplied parameters score the
|
|
435
|
+
* topic, inserts the default stats and returns a reference to those. If neither apply, returns None.
|
|
436
|
+
*/
|
|
437
|
+
getPtopicStats(pstats, topic) {
|
|
438
|
+
let topicStats = pstats.topics[topic];
|
|
439
|
+
if (topicStats !== undefined) {
|
|
440
|
+
return topicStats;
|
|
441
|
+
}
|
|
442
|
+
if (this.params.topics[topic] !== undefined) {
|
|
443
|
+
topicStats = {
|
|
444
|
+
inMesh: false,
|
|
445
|
+
graftTime: 0,
|
|
446
|
+
meshTime: 0,
|
|
447
|
+
firstMessageDeliveries: 0,
|
|
448
|
+
meshMessageDeliveries: 0,
|
|
449
|
+
meshMessageDeliveriesActive: false,
|
|
450
|
+
meshFailurePenalty: 0,
|
|
451
|
+
invalidMessageDeliveries: 0
|
|
452
|
+
};
|
|
453
|
+
pstats.topics[topic] = topicStats;
|
|
454
|
+
return topicStats;
|
|
455
|
+
}
|
|
456
|
+
return null;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
//# sourceMappingURL=peer-score.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"peer-score.js","sourceRoot":"","sources":["../../../src/score/peer-score.ts"],"names":[],"mappings":"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"}
|