Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 9 additions & 14 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1524,10 +1524,9 @@ export class GossipSub extends TypedEventEmitter<GossipsubEvents> implements Pub

let iwantList = Array.from(iwant.values())
// ask in random order
shuffle(iwantList)

// truncate to the messages we are actually asking for and update the iasked counter
iwantList = iwantList.slice(0, iask)
iwantList = shuffle(iwantList, iask)

this.iasked.set(id, iasked + iask)

// do not add gossipTracer promise here until a successful sendRpc()
Expand Down Expand Up @@ -1847,8 +1846,7 @@ export class GossipSub extends TypedEventEmitter<GossipsubEvents> implements Pub
*/
private async pxConnect (peers: RPC.PeerInfo[]): Promise<void> {
if (peers.length > this.opts.prunePeers) {
shuffle(peers)
peers = peers.slice(0, this.opts.prunePeers)
peers = shuffle(peers, this.opts.prunePeers)
}
const toconnect: string[] = []

Expand Down Expand Up @@ -2597,13 +2595,13 @@ export class GossipSub extends TypedEventEmitter<GossipsubEvents> implements Pub
return
}

// shuffle to emit in random order
shuffle(messageIDs)

// if we are emitting more than GossipsubMaxIHaveLength ids, truncate the list
if (messageIDs.length > constants.GossipsubMaxIHaveLength) {
// we do the truncation (with shuffling) per peer below
this.log('too many messages for gossip; will truncate IHAVE list (%d messages)', messageIDs.length)
} else {
// shuffle to emit in random order
shuffle(messageIDs)
}

if (candidateToGossip.size === 0) return
Expand All @@ -2618,7 +2616,7 @@ export class GossipSub extends TypedEventEmitter<GossipsubEvents> implements Pub
target = peersToGossip.size
} else {
// only shuffle if needed
peersToGossip = shuffle(Array.from(peersToGossip)).slice(0, target)
peersToGossip = shuffle(Array.from(peersToGossip), target)
}

// Emit the IHAVE gossip to the selected peers up to the target
Expand All @@ -2628,7 +2626,7 @@ export class GossipSub extends TypedEventEmitter<GossipsubEvents> implements Pub
// shuffle and slice message IDs per peer so that we emit a different set for each peer
// we have enough reduncancy in the system that this will significantly increase the message
// coverage when we do truncate
peerMessageIDs = shuffle(peerMessageIDs.slice()).slice(0, constants.GossipsubMaxIHaveLength)
peerMessageIDs = shuffle(messageIDs.slice(), constants.GossipsubMaxIHaveLength)
}
this.pushGossip(id, {
topicID: topic,
Expand Down Expand Up @@ -3129,10 +3127,7 @@ export class GossipSub extends TypedEventEmitter<GossipsubEvents> implements Pub
})

// Pseudo-randomly shuffles peers
peers = shuffle(peers)
if (count > 0 && peers.length > count) {
peers = peers.slice(0, count)
}
peers = shuffle(peers, count)

return new Set(peers)
}
Expand Down
18 changes: 12 additions & 6 deletions src/utils/shuffle.ts
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
/**
* Pseudo-randomly shuffles an array
*
* If k is specified, only the first k elements of the array are shuffled and returned
*
* Mutates the input array
*/
export function shuffle<T> (arr: T[]): T[] {
export function shuffle<T> (arr: T[], k?: number): T[] {
// short circuit for trivial array
if (arr.length <= 1) {
return arr
}
const randInt = (): number => {
return Math.floor(Math.random() * Math.floor(arr.length))
}

for (let i = 0; i < arr.length; i++) {
const j = randInt()
const n = arr.length
const K = Math.min(k ?? Infinity, n)
for (let i = 0; i < K; i++) {
const j = i + Math.floor(Math.random() * (n - i))
const tmp = arr[i]
arr[i] = arr[j]
arr[j] = tmp
}

if (k !== undefined) {
return arr.slice(0, k)
}
return arr
}