@@ -24,6 +24,8 @@ import { mockNetwork } from '@libp2p/interface-mocks'
2424import { stop } from '@libp2p/interfaces/startable'
2525import { TopicScoreParams } from '../../src/score/peer-score-params.js'
2626import { awaitEvents , checkReceivedSubscription , checkReceivedSubscriptions } from '../utils/events.js'
27+ import sinon , { SinonStubbedInstance } from 'sinon'
28+ import { Tag } from '@libp2p/interface-peer-store'
2729
2830/**
2931 * These tests were translated from:
@@ -76,6 +78,115 @@ describe('go-libp2p-pubsub gossipsub tests', function () {
7678 mockNetwork . reset ( )
7779 } )
7880
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+
79190 it ( 'test sparse gossipsub' , async function ( ) {
80191 // Create 20 gossipsub nodes
81192 // Subscribe to the topic, all nodes
@@ -924,7 +1035,7 @@ describe('go-libp2p-pubsub gossipsub tests', function () {
9241035 // Assert that the nodes are connected
9251036 // Subscribe to the topic, all nodes
9261037 // Publish a message from each node
927- // Assert that all nodes receive the messages
1038+ // Assert that all nodes receive t he messages
9281039 // Disconnect peers
9291040 // Assert peers reconnect
9301041 // Publish a message from each node
0 commit comments