@@ -24,6 +24,8 @@ import { mockNetwork } from '@libp2p/interface-mocks'
24
24
import { stop } from '@libp2p/interfaces/startable'
25
25
import { TopicScoreParams } from '../../src/score/peer-score-params.js'
26
26
import { awaitEvents , checkReceivedSubscription , checkReceivedSubscriptions } from '../utils/events.js'
27
+ import sinon , { SinonStubbedInstance } from 'sinon'
28
+ import { Tag } from '@libp2p/interface-peer-store'
27
29
28
30
/**
29
31
* These tests were translated from:
@@ -76,6 +78,115 @@ describe('go-libp2p-pubsub gossipsub tests', function () {
76
78
mockNetwork . reset ( )
77
79
} )
78
80
81
+ it ( 'should add the tag gossipsub-mesh-peer upon grafting' , async function ( ) {
82
+ // Create 20 gossipsub nodes
83
+ // Sparsely connect nodes
84
+ // Subscribe to the topic, all nodes, waiting for each subscription to propagate first
85
+ // Publish 100 messages, each from a random node
86
+ // Assert that the subscribed nodes receive every message
87
+ psubs = await createComponentsArray ( {
88
+ number : 20 ,
89
+ init : {
90
+ scoreParams : {
91
+ IPColocationFactorThreshold : 20 ,
92
+ behaviourPenaltyWeight : 0
93
+ }
94
+ }
95
+ } )
96
+ const topic = 'foobar'
97
+
98
+ await sparseConnect ( psubs )
99
+
100
+ const nodeAGraftSpy = psubs [ 0 ] . pubsub as Partial < GossipSub > as SinonStubbedInstance < {
101
+ handleGraft : GossipSub [ 'handleGraft' ]
102
+ } >
103
+ sinon . spy ( nodeAGraftSpy , 'handleGraft' )
104
+
105
+ // add subscriptions to each node
106
+ for ( const ps of psubs ) {
107
+ ps . pubsub . subscribe ( topic )
108
+ // wait for announce to propagate
109
+ await delay ( 100 )
110
+ }
111
+ // await mesh rebalancing
112
+ await Promise . all ( psubs . map ( async ( ps ) => await awaitEvents ( ps . pubsub , 'gossipsub:heartbeat' , 2 ) ) )
113
+
114
+ const allTags : Tag [ ] [ ] = [ ]
115
+
116
+ psubs . forEach ( async ( subscribedPeer ) => {
117
+ const tagArray = await subscribedPeer . components . peerStore . getTags ( subscribedPeer . components . peerId )
118
+ allTags . push ( tagArray )
119
+ } )
120
+
121
+ expect ( nodeAGraftSpy . handleGraft . callCount ) . to . be . greaterThan ( 0 )
122
+ expect (
123
+ allTags . map ( ( tags ) => {
124
+ tags . map ( ( tag ) => {
125
+ tag . name . toString ( )
126
+ } )
127
+ } )
128
+ ) . to . include ( 'gossipsub-mesh-peer' )
129
+ } )
130
+ it ( 'should remove the tag gossipsub-mesh-peer upon pruning' , async function ( ) {
131
+ // Create 20 gossipsub nodes
132
+ // Sparsely connect nodes
133
+ // Subscribe to the topic, all nodes, waiting for each subscription to propagate first
134
+ // Publish 100 messages, each from a random node
135
+ // Assert that the subscribed nodes receive every message
136
+ psubs = await createComponentsArray ( {
137
+ number : 20 ,
138
+ init : {
139
+ scoreParams : {
140
+ IPColocationFactorThreshold : 20 ,
141
+ behaviourPenaltyWeight : 0
142
+ }
143
+ }
144
+ } )
145
+ const topic = 'foobar'
146
+ psubs . forEach ( ( ps ) => ps . pubsub . subscribe ( topic ) )
147
+
148
+ const unsubscribedPeers : GossipSubAndComponents [ ] = [ ]
149
+
150
+ // every node connected to every other
151
+ await denseConnect ( psubs )
152
+ // wait a bit to take effect
153
+ await Promise . all ( psubs . map ( async ( ps ) => await awaitEvents ( ps . pubsub , 'gossipsub:heartbeat' , 2 ) ) )
154
+
155
+ // disconnect some peers from the mesh to get some PRUNEs
156
+ psubs . slice ( 0 , 5 ) . forEach ( ( ps ) => {
157
+ unsubscribedPeers . push ( ps )
158
+ ps . pubsub . unsubscribe ( topic )
159
+ } )
160
+
161
+ // wait a bit to take effect
162
+ await Promise . all ( psubs . map ( async ( ps ) => await awaitEvents ( ps . pubsub , 'gossipsub:heartbeat' , 2 ) ) )
163
+
164
+ const nodeAPruneSpy = unsubscribedPeers [ 0 ] . pubsub as Partial < GossipSub > as SinonStubbedInstance < {
165
+ handlePrune : GossipSub [ 'handlePrune' ]
166
+ } >
167
+ sinon . spy ( nodeAPruneSpy , 'handlePrune' )
168
+
169
+ // await mesh rebalancing
170
+ await Promise . all ( psubs . map ( async ( ps ) => await awaitEvents ( ps . pubsub , 'gossipsub:heartbeat' , 2 ) ) )
171
+
172
+ const allTags : Tag [ ] [ ] = [ ]
173
+
174
+ unsubscribedPeers . forEach ( async ( unsubscribedPeer ) => {
175
+ const tagArray = await unsubscribedPeer . components . peerStore . getTags ( unsubscribedPeer . components . peerId )
176
+ console . log ( 'pushing tag array: ' , tagArray )
177
+ allTags . push ( tagArray )
178
+ } )
179
+
180
+ expect ( nodeAPruneSpy . handlePrune . callCount ) . to . be . greaterThan ( 0 )
181
+ expect (
182
+ allTags . map ( ( tags ) => {
183
+ tags . map ( ( tag ) => {
184
+ tag . name . toString ( )
185
+ } )
186
+ } )
187
+ ) . not . to . include ( 'gossipsub-mesh-peer' )
188
+ } )
189
+
79
190
it ( 'test sparse gossipsub' , async function ( ) {
80
191
// Create 20 gossipsub nodes
81
192
// Subscribe to the topic, all nodes
@@ -924,7 +1035,7 @@ describe('go-libp2p-pubsub gossipsub tests', function () {
924
1035
// Assert that the nodes are connected
925
1036
// Subscribe to the topic, all nodes
926
1037
// Publish a message from each node
927
- // Assert that all nodes receive the messages
1038
+ // Assert that all nodes receive t he messages
928
1039
// Disconnect peers
929
1040
// Assert peers reconnect
930
1041
// Publish a message from each node
0 commit comments