Skip to content

Commit baf84f8

Browse files
dappliontwoeths
andauthored
Add metrics and revamp logic (#206)
* Add metrics and revamp logic Declare prometheus metrics in gossipsub Add missing metric labels Fix metrics types Add onReportValidation * Compile tests * Fix tests * Customize await policy * Run prettier on files * Relax heartbeat test condition * Re-add util package for browser testing * Remove unused dependencies * Add getMeshPeers * Fix rpc metric name * Improve metrics * More gossip promise metrics * Fix metrics typo * Clarify metrics names * Track metric of score deltas * Fix score metrics * Add buckets for gossipsub_score_cache_delta * Review PeerScore logic * Dump peer stats * Fix PeerStats constructor * Enable strict typescript checks * Fix compute-score logic * f * Fix peer stats types * Reenable go-gossipsub tests (#201) * Add checkReceivedSubscriptions * Add checkReceivedSubscriptions to 'test gossipsub multihops' * Add checkReceivedSubscriptions to 'test gossipsub tree topology' * test gossipsub star topology with signed peer records * Fix 'test gossipsub direct peers' * Fix 'test gossipsub flood publish' * Fix 'test gossipsub star topology with signed peer records' * 'direct peers' test: wait for subscriptions event again * 'direct peer': await for 2 peer:connect events * 'direct peers': add missing Promise.all * Expect topic peers to contain peer id * Fix test types * Set as connected in addPeer() * Prune publishedMessageIds * Fix markFirstMessageDelivery typo * Same logic in scoreMetrics * More metrics for p3 and p7 (#213) * Add behaviourPenalty metrics * Add duplicateMsgDelivery metric * Observe topic and peer in duplicateMsgDelivery topic * Remove peerId from duplicateMsgDelivery metric * Use min meshMessageDeliveriesWindow * Use topic label for duplicateMsgDelivery metric * Record duplicateMsgDelivery in all cases * Forward messages to floodsub peers (#214) * Forward messages to floodsub peers * Add comments Co-authored-by: Lion - dapplion <[email protected]> * Add missing msgId in validateReceivedMessage (#215) * Fix 'test gossipsub opportunistic grafting' * Fix tests in browser * Fix tests suspended issue in browsers * Fix 'test gossipsub fanout expiry' go-gossipsub test * GossipsubIWantFollowupTime as a param (#216) * Increase resolution of delay metrics (#217) * Fix minMeshMessageDeliveriesWindow (#218) * Fix minMeshMessageDeliveriesWindow * Fix gossipsubIWantFollowupTime for metric * Fix tracer prune() * Change to maxMeshMessageDeliveriesWindow * Use maxMeshMessageDeliveriesWindowSec for metric * Rename gossipsubIWantFollowupMs option, revert/correct tracer.prune() logic * Reset behaviourPenalty histogram to track current count * publish(): return number of sent peers * Add getScore() * makePrune: update PeerStat so that we don't apply p3 penalty * Remove redundant this.score.prune() in heartbeat * Track iasked cache size per heartbeat and remove TODOs * validateReceivedMessage: check duplicate message first (#223) Co-authored-by: tuyennhv <[email protected]>
1 parent 25c9aa1 commit baf84f8

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

46 files changed

+3755
-1334
lines changed

.eslintrc.js

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,9 @@ module.exports = {
2929
}
3030
],
3131
'@typescript-eslint/indent': 'off', // This is the job of StandardJS, they are competing rules so we turn off the Typescript one.
32-
'node/no-unsupported-features/es-syntax': 'off', // Allows us to use Import and Export keywords.
3332
'@typescript-eslint/no-non-null-assertion': 'off',
33+
'@typescript-eslint/member-delimiter-style': 'off',
34+
'node/no-unsupported-features/es-syntax': 'off', // Allows us to use Import and Export keywords.
3435
"@typescript-eslint/strict-boolean-expressions": [
3536
"error",
3637
{
@@ -42,6 +43,8 @@ module.exports = {
4243
'no-mixed-operators': 'off',
4344
'space-before-function-paren': 'off',
4445
'comma-dangle': 'off',
46+
// Allow to place comments before the else {} block
47+
'brace-style': 'off',
4548
indent: 'off'
4649
}
4750
}

package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,11 @@
4444
"debug": "^4.3.1",
4545
"denque": "^1.5.0",
4646
"err-code": "^3.0.1",
47+
"iso-random-stream": "^2.0.2",
4748
"it-pipe": "^1.1.0",
48-
"libp2p-interfaces": "^4.0.4",
49+
"libp2p-crypto": "^0.21.2",
50+
"libp2p-interfaces": "4.0.4",
51+
"multiformats": "^9.6.4",
4952
"peer-id": "^0.16.0",
5053
"protobufjs": "^6.11.2",
5154
"uint8arrays": "^3.0.0"
@@ -75,10 +78,10 @@
7578
"eslint-plugin-standard": "^4.0.1",
7679
"it-pair": "^1.0.0",
7780
"libp2p": "0.36.1",
78-
"libp2p-floodsub": "^0.29.0",
79-
"libp2p-interfaces-compliance-tests": "^4.0.6",
80-
"libp2p-mplex": "^0.10.3",
81-
"libp2p-websockets": "^0.16.1",
81+
"libp2p-floodsub": "^0.29.1",
82+
"libp2p-interfaces-compliance-tests": "^4.0.8",
83+
"libp2p-mplex": "^0.10.7",
84+
"libp2p-websockets": "^0.16.2",
8285
"lodash": "^4.17.15",
8386
"multiaddr": "^10.0.0",
8487
"os": "^0.1.1",

test/2-nodes.spec.ts

Lines changed: 79 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
import chai from 'chai'
22
import { fromString as uint8ArrayFromString } from 'uint8arrays/from-string'
33
import delay from 'delay'
4-
import Gossipsub, { multicodec } from '../ts'
5-
import { createGossipsubs, createConnectedGossipsubs, expectSet, stopNode, first } from './utils'
4+
import Gossipsub from '../ts'
5+
import { createGossipsubs, createPubsubs, createConnectedGossipsubs, expectSet, stopNode, first } from './utils'
66
import { RPC } from '../ts/message/rpc'
7-
import { InMessage, PeerId } from 'libp2p-interfaces/src/pubsub'
7+
import PubsubBaseProtocol, { PeerId } from 'libp2p-interfaces/src/pubsub'
8+
import { FloodsubID, GossipsubIDv11 } from '../ts/constants'
9+
import { GossipsubMessage } from '../ts/types'
810

911
chai.use(require('dirty-chai'))
1012
chai.use(require('chai-spies'))
@@ -13,6 +15,28 @@ const expect = chai.expect
1315
const shouldNotHappen = () => expect.fail()
1416

1517
describe('2 nodes', () => {
18+
describe('Pubsub dial', () => {
19+
let nodes: PubsubBaseProtocol[]
20+
21+
// Create pubsub nodes
22+
before(async () => {
23+
nodes = await createPubsubs({ number: 2 })
24+
})
25+
26+
after(() => Promise.all(nodes.map(stopNode)))
27+
28+
it('Dial from nodeA to nodeB happened with pubsub', async () => {
29+
await nodes[0]._libp2p.dialProtocol(nodes[1]._libp2p.peerId, FloodsubID)
30+
31+
while (nodes[0]['peers'].size === 0 || nodes[1]['peers'].size === 0) {
32+
await delay(10)
33+
}
34+
35+
expect(nodes[0]['peers'].size).to.be.eql(1)
36+
expect(nodes[1]['peers'].size).to.be.eql(1)
37+
})
38+
})
39+
1640
describe('basics', () => {
1741
let nodes: Gossipsub[] = []
1842

@@ -24,15 +48,14 @@ describe('2 nodes', () => {
2448
after(() => Promise.all(nodes.map(stopNode)))
2549

2650
it('Dial from nodeA to nodeB happened with pubsub', async () => {
27-
await nodes[0]._libp2p.dialProtocol(nodes[1]._libp2p.peerId, multicodec)
28-
await delay(10)
29-
await Promise.all([
30-
new Promise((resolve) => nodes[0].once('gossipsub:heartbeat', resolve)),
31-
new Promise((resolve) => nodes[1].once('gossipsub:heartbeat', resolve))
32-
])
51+
await nodes[0]._libp2p.dialProtocol(nodes[1]._libp2p.peerId, GossipsubIDv11)
3352

34-
expect(nodes[0].peers.size).to.be.eql(1)
35-
expect(nodes[1].peers.size).to.be.eql(1)
53+
while (nodes[0]['peers'].size === 0 || nodes[1]['peers'].size === 0) {
54+
await delay(10)
55+
}
56+
57+
expect(nodes[0]['peers'].size).to.be.eql(1)
58+
expect(nodes[1]['peers'].size).to.be.eql(1)
3659
})
3760
})
3861

@@ -47,7 +70,14 @@ describe('2 nodes', () => {
4770
after(() => Promise.all(nodes.map(stopNode)))
4871

4972
it('Subscribe to a topic', async () => {
50-
const topic = 'Z'
73+
const topic = 'test_topic'
74+
75+
// await subscription change, after calling subscribe
76+
const subscriptionEventPromise = Promise.all([
77+
new Promise((resolve) => nodes[0].once('pubsub:subscription-change', (...args) => resolve(args))),
78+
new Promise((resolve) => nodes[1].once('pubsub:subscription-change', (...args) => resolve(args)))
79+
])
80+
5181
nodes[0].subscribe(topic)
5282
nodes[1].subscribe(topic)
5383

@@ -61,14 +91,14 @@ describe('2 nodes', () => {
6191

6292
const [changedPeerId, changedSubs] = evt0 as [PeerId, RPC.ISubOpts[]]
6393

64-
expectSet(nodes[0].subscriptions, [topic])
65-
expectSet(nodes[1].subscriptions, [topic])
66-
expect(nodes[0].peers.size).to.equal(1)
67-
expect(nodes[1].peers.size).to.equal(1)
68-
expectSet(nodes[0].topics.get(topic), [nodes[1].peerId.toB58String()])
69-
expectSet(nodes[1].topics.get(topic), [nodes[0].peerId.toB58String()])
94+
expectSet(nodes[0]['subscriptions'], [topic])
95+
expectSet(nodes[1]['subscriptions'], [topic])
96+
expect(nodes[0]['peers'].size).to.equal(1)
97+
expect(nodes[1]['peers'].size).to.equal(1)
98+
expectSet(nodes[0]['topics'].get(topic), [nodes[1].peerId.toB58String()])
99+
expectSet(nodes[1]['topics'].get(topic), [nodes[0].peerId.toB58String()])
70100

71-
expect(changedPeerId.toB58String()).to.equal(first(nodes[0].peers).id.toB58String())
101+
expect(changedPeerId.toB58String()).to.equal(first(nodes[0]['peers']).id.toB58String())
72102
expect(changedSubs).to.have.lengthOf(1)
73103
expect(changedSubs[0].topicID).to.equal(topic)
74104
expect(changedSubs[0].subscribe).to.equal(true)
@@ -79,8 +109,8 @@ describe('2 nodes', () => {
79109
new Promise((resolve) => nodes[1].once('gossipsub:heartbeat', resolve))
80110
])
81111

82-
expect(first(nodes[0].mesh.get(topic))).to.equal(first(nodes[0].peers).id.toB58String())
83-
expect(first(nodes[1].mesh.get(topic))).to.equal(first(nodes[1].peers).id.toB58String())
112+
expect(first(nodes[0]['mesh'].get(topic))).to.equal(first(nodes[0]['peers']).id.toB58String())
113+
expect(first(nodes[1]['mesh'].get(topic))).to.equal(first(nodes[1]['peers']).id.toB58String())
84114
})
85115
})
86116

@@ -109,29 +139,29 @@ describe('2 nodes', () => {
109139
afterEach(() => Promise.all(nodes.map(stopNode)))
110140

111141
it('Publish to a topic - nodeA', async () => {
112-
const promise = new Promise<InMessage>((resolve) => nodes[1].once(topic, resolve))
142+
const promise = new Promise<GossipsubMessage>((resolve) => nodes[1].once(topic, resolve))
113143
nodes[0].once(topic, (m) => shouldNotHappen)
114144

115145
nodes[0].publish(topic, uint8ArrayFromString('hey'))
116146

117147
const msg = await promise
118148

119149
expect(msg.data.toString()).to.equal('hey')
120-
expect(msg.from).to.be.eql(nodes[0].peerId.toB58String())
150+
expect(msg.from).to.be.eql(nodes[0].peerId.toBytes())
121151

122152
nodes[0].removeListener(topic, shouldNotHappen)
123153
})
124154

125155
it('Publish to a topic - nodeB', async () => {
126-
const promise = new Promise<InMessage>((resolve) => nodes[0].once(topic, resolve))
156+
const promise = new Promise<GossipsubMessage>((resolve) => nodes[0].once(topic, resolve))
127157
nodes[1].once(topic, shouldNotHappen)
128158

129159
nodes[1].publish(topic, uint8ArrayFromString('banana'))
130160

131161
const msg = await promise
132162

133163
expect(msg.data.toString()).to.equal('banana')
134-
expect(msg.from).to.be.eql(nodes[1].peerId.toB58String())
164+
expect(msg.from).to.be.eql(nodes[1].peerId.toBytes())
135165

136166
nodes[1].removeListener(topic, shouldNotHappen)
137167
})
@@ -143,11 +173,11 @@ describe('2 nodes', () => {
143173

144174
nodes[0].on(topic, receivedMsg)
145175

146-
function receivedMsg(msg: InMessage) {
147-
expect(msg.data.toString().startsWith('banana')).to.be.true
148-
expect(msg.from).to.be.eql(nodes[1].peerId.toB58String())
176+
function receivedMsg(msg: RPC.IMessage) {
177+
expect(msg.data!.toString().startsWith('banana')).to.be.true
178+
expect(msg.from).to.be.eql(nodes[1].peerId.toBytes())
149179
expect(msg.seqno).to.be.a('Uint8Array')
150-
expect(msg.topicIDs).to.be.eql([topic])
180+
expect(msg.topic).to.be.eql(topic)
151181

152182
if (++counter === 10) {
153183
nodes[0].removeListener(topic, receivedMsg)
@@ -168,7 +198,7 @@ describe('2 nodes', () => {
168198

169199
// Create pubsub nodes
170200
beforeEach(async () => {
171-
nodes = await createConnectedGossipsubs({ number: 2 })
201+
nodes = await createConnectedGossipsubs({ number: 2, options: {allowPublishToZeroPeers: true} })
172202
})
173203

174204
// Create subscriptions
@@ -188,16 +218,16 @@ describe('2 nodes', () => {
188218

189219
it('Unsubscribe from a topic', async () => {
190220
nodes[0].unsubscribe(topic)
191-
expect(nodes[0].subscriptions.size).to.equal(0)
221+
expect(nodes[0]['subscriptions'].size).to.equal(0)
192222

193223
const [changedPeerId, changedSubs] = await new Promise<[PeerId, RPC.ISubOpts[]]>((resolve) => {
194224
nodes[1].once('pubsub:subscription-change', (...args: [PeerId, RPC.ISubOpts[]]) => resolve(args))
195225
})
196226
await new Promise((resolve) => nodes[1].once('gossipsub:heartbeat', resolve))
197227

198-
expect(nodes[1].peers.size).to.equal(1)
199-
expectSet(nodes[1].topics.get(topic), [])
200-
expect(changedPeerId.toB58String()).to.equal(first(nodes[1].peers).id.toB58String())
228+
expect(nodes[1]['peers'].size).to.equal(1)
229+
expectSet(nodes[1]['topics'].get(topic), [])
230+
expect(changedPeerId.toB58String()).to.equal(first(nodes[1]['peers']).id.toB58String())
201231
expect(changedSubs).to.have.lengthOf(1)
202232
expect(changedSubs[0].topicID).to.equal(topic)
203233
expect(changedSubs[0].subscribe).to.equal(false)
@@ -245,10 +275,10 @@ describe('2 nodes', () => {
245275
nodes[0].subscribe('Za')
246276
nodes[1].subscribe('Zb')
247277

248-
expect(nodes[0].peers.size).to.equal(0)
249-
expectSet(nodes[0].subscriptions, ['Za'])
250-
expect(nodes[1].peers.size).to.equal(0)
251-
expectSet(nodes[1].subscriptions, ['Zb'])
278+
expect(nodes[0]['peers'].size).to.equal(0)
279+
expectSet(nodes[0]['subscriptions'], ['Za'])
280+
expect(nodes[1]['peers'].size).to.equal(0)
281+
expectSet(nodes[1]['subscriptions'], ['Zb'])
252282
})
253283

254284
after(() => Promise.all(nodes.map(stopNode)))
@@ -257,20 +287,20 @@ describe('2 nodes', () => {
257287
this.timeout(5000)
258288

259289
await Promise.all([
260-
nodes[0]._libp2p.dialProtocol(nodes[1]._libp2p.peerId, multicodec),
290+
nodes[0]._libp2p.dialProtocol(nodes[1]._libp2p.peerId, GossipsubIDv11),
261291
new Promise((resolve) => nodes[0].once('pubsub:subscription-change', resolve)),
262292
new Promise((resolve) => nodes[1].once('pubsub:subscription-change', resolve))
263293
])
264-
expect(nodes[0].peers.size).to.equal(1)
265-
expect(nodes[1].peers.size).to.equal(1)
294+
expect(nodes[0]['peers'].size).to.equal(1)
295+
expect(nodes[1]['peers'].size).to.equal(1)
266296

267-
expectSet(nodes[0].subscriptions, ['Za'])
268-
expect(nodes[1].peers.size).to.equal(1)
269-
expectSet(nodes[1].topics.get('Za'), [nodes[0].peerId.toB58String()])
297+
expectSet(nodes[0]['subscriptions'], ['Za'])
298+
expect(nodes[1]['peers'].size).to.equal(1)
299+
expectSet(nodes[1]['topics'].get('Za'), [nodes[0].peerId.toB58String()])
270300

271-
expectSet(nodes[1].subscriptions, ['Zb'])
272-
expect(nodes[0].peers.size).to.equal(1)
273-
expectSet(nodes[0].topics.get('Zb'), [nodes[1].peerId.toB58String()])
301+
expectSet(nodes[1]['subscriptions'], ['Zb'])
302+
expect(nodes[0]['peers'].size).to.equal(1)
303+
expectSet(nodes[0]['topics'].get('Zb'), [nodes[1].peerId.toB58String()])
274304
})
275305
})
276306

@@ -284,8 +314,8 @@ describe('2 nodes', () => {
284314

285315
it("nodes don't have peers after stopped", async () => {
286316
await Promise.all(nodes.map(stopNode))
287-
expect(nodes[0].peers.size).to.equal(0)
288-
expect(nodes[1].peers.size).to.equal(0)
317+
expect(nodes[0]['peers'].size).to.equal(0)
318+
expect(nodes[1]['peers'].size).to.equal(0)
289319
})
290320
})
291321
})

0 commit comments

Comments
 (0)