@streamr/dht 100.0.0-testnet-one.0 → 100.0.0-testnet-one.1

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.
Files changed (107) hide show
  1. package/dist/src/connection/ConnectionLockRpcRemote.js +1 -25
  2. package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
  3. package/dist/src/connection/ConnectionManager.d.ts +0 -1
  4. package/dist/src/connection/ConnectionManager.js +7 -6
  5. package/dist/src/connection/ConnectionManager.js.map +1 -1
  6. package/dist/src/connection/ConnectorFacade.d.ts +2 -2
  7. package/dist/src/connection/ConnectorFacade.js +1 -2
  8. package/dist/src/connection/ConnectorFacade.js.map +1 -1
  9. package/dist/src/connection/connectivityChecker.js +3 -2
  10. package/dist/src/connection/connectivityChecker.js.map +1 -1
  11. package/dist/src/connection/websocket/ClientWebsocket.d.ts +1 -0
  12. package/dist/src/connection/websocket/ClientWebsocket.js +6 -3
  13. package/dist/src/connection/websocket/ClientWebsocket.js.map +1 -1
  14. package/dist/src/connection/websocket/ServerWebsocket.d.ts +4 -0
  15. package/dist/src/connection/websocket/ServerWebsocket.js +32 -21
  16. package/dist/src/connection/websocket/ServerWebsocket.js.map +1 -1
  17. package/dist/src/connection/websocket/WebsocketConnector.d.ts +0 -1
  18. package/dist/src/connection/websocket/WebsocketConnector.js +21 -10
  19. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  20. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.d.ts +1 -1
  21. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js +8 -11
  22. package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js.map +1 -1
  23. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.d.ts +2 -2
  24. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js +3 -37
  25. package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js.map +1 -1
  26. package/dist/src/connection/websocket/WebsocketServer.js +21 -4
  27. package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
  28. package/dist/src/dht/DhtNode.d.ts +4 -4
  29. package/dist/src/dht/DhtNode.js +30 -19
  30. package/dist/src/dht/DhtNode.js.map +1 -1
  31. package/dist/src/dht/DhtNodeRpcLocal.d.ts +1 -4
  32. package/dist/src/dht/DhtNodeRpcLocal.js +1 -5
  33. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  34. package/dist/src/dht/PeerManager.d.ts +10 -6
  35. package/dist/src/dht/PeerManager.js +95 -30
  36. package/dist/src/dht/PeerManager.js.map +1 -1
  37. package/dist/src/dht/contact/SortedContactList.d.ts +20 -6
  38. package/dist/src/dht/contact/SortedContactList.js +55 -24
  39. package/dist/src/dht/contact/SortedContactList.js.map +1 -1
  40. package/dist/src/dht/discovery/DiscoverySession.d.ts +2 -5
  41. package/dist/src/dht/discovery/DiscoverySession.js +12 -9
  42. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  43. package/dist/src/dht/discovery/PeerDiscovery.d.ts +1 -1
  44. package/dist/src/dht/discovery/PeerDiscovery.js +4 -10
  45. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  46. package/dist/src/dht/find/FindSession.js +6 -1
  47. package/dist/src/dht/find/FindSession.js.map +1 -1
  48. package/dist/src/dht/find/Finder.js +6 -1
  49. package/dist/src/dht/find/Finder.js.map +1 -1
  50. package/dist/src/dht/routing/Router.d.ts +1 -1
  51. package/dist/src/dht/routing/Router.js +8 -4
  52. package/dist/src/dht/routing/Router.js.map +1 -1
  53. package/dist/src/dht/routing/RoutingSession.js +8 -1
  54. package/dist/src/dht/routing/RoutingSession.js.map +1 -1
  55. package/dist/src/dht/store/StoreRpcLocal.js +19 -5
  56. package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
  57. package/dist/src/helpers/PeerID.d.ts +1 -0
  58. package/dist/src/helpers/PeerID.js +7 -2
  59. package/dist/src/helpers/PeerID.js.map +1 -1
  60. package/dist/src/helpers/peerIdFromPeerDescriptor.js +2 -2
  61. package/dist/src/helpers/peerIdFromPeerDescriptor.js.map +1 -1
  62. package/package.json +5 -5
  63. package/src/connection/ConnectionLockRpcRemote.ts +1 -2
  64. package/src/connection/ConnectionManager.ts +16 -17
  65. package/src/connection/ConnectorFacade.ts +0 -3
  66. package/src/connection/connectivityChecker.ts +3 -2
  67. package/src/connection/websocket/ClientWebsocket.ts +5 -2
  68. package/src/connection/websocket/ServerWebsocket.ts +40 -25
  69. package/src/connection/websocket/WebsocketConnector.ts +23 -12
  70. package/src/connection/websocket/WebsocketConnectorRpcLocal.ts +9 -11
  71. package/src/connection/websocket/WebsocketConnectorRpcRemote.ts +5 -14
  72. package/src/connection/websocket/WebsocketServer.ts +20 -5
  73. package/src/dht/DhtNode.ts +31 -21
  74. package/src/dht/DhtNodeRpcLocal.ts +2 -9
  75. package/src/dht/PeerManager.ts +110 -36
  76. package/src/dht/contact/SortedContactList.ts +87 -44
  77. package/src/dht/discovery/DiscoverySession.ts +14 -14
  78. package/src/dht/discovery/PeerDiscovery.ts +9 -16
  79. package/src/dht/find/FindSession.ts +6 -1
  80. package/src/dht/find/Finder.ts +6 -7
  81. package/src/dht/routing/Router.ts +8 -4
  82. package/src/dht/routing/RoutingSession.ts +8 -8
  83. package/src/dht/store/StoreRpcLocal.ts +19 -7
  84. package/src/helpers/PeerID.ts +6 -2
  85. package/src/helpers/peerIdFromPeerDescriptor.ts +4 -4
  86. package/test/benchmark/Find.test.ts +1 -1
  87. package/test/benchmark/KademliaCorrectness.test.ts +1 -1
  88. package/test/benchmark/SortedContactListBenchmark.test.ts +150 -0
  89. package/test/benchmark/WebsocketServerMemoryLeak.test.ts +41 -0
  90. package/test/benchmark/kademlia-simulation/SimulationNode.ts +6 -1
  91. package/test/end-to-end/Layer0.test.ts +4 -4
  92. package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +10 -10
  93. package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +4 -4
  94. package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +2 -2
  95. package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +2 -2
  96. package/test/end-to-end/RecoveryFromFailedAutoCertification.test.ts +1 -1
  97. package/test/end-to-end/memory-leak.test.ts +1 -0
  98. package/test/integration/DhtJoinPeerDiscovery.test.ts +2 -2
  99. package/test/integration/Layer1-scale.test.ts +1 -1
  100. package/test/integration/Mock-Layer1-Layer0.test.ts +15 -15
  101. package/test/integration/MultipleEntryPointJoining.test.ts +7 -7
  102. package/test/integration/ReplicateData.test.ts +6 -1
  103. package/test/integration/SimultaneousConnections.test.ts +81 -49
  104. package/test/integration/StoreOnDhtWithTwoNodes.test.ts +1 -1
  105. package/test/integration/WebsocketConnectionManagement.test.ts +41 -3
  106. package/test/integration/WebsocketConnectorRpc.test.ts +3 -5
  107. package/test/unit/SortedContactList.test.ts +15 -10
@@ -275,13 +275,12 @@ export class Finder implements IFinder {
275
275
 
276
276
  private getClosestConnections(nodeId: Uint8Array, limit: number): PeerDescriptor[] {
277
277
  const connectedPeers = Array.from(this.connections.values())
278
- const closestPeers = new SortedContactList<DhtNodeRpcRemote>(
279
- PeerID.fromValue(nodeId),
280
- limit,
281
- undefined,
282
- true,
283
- undefined
284
- )
278
+ const closestPeers = new SortedContactList<DhtNodeRpcRemote>({
279
+ referenceId: PeerID.fromValue(nodeId),
280
+ maxSize: limit,
281
+ allowToContainReferenceId: true,
282
+ emitEvents: false
283
+ })
285
284
  closestPeers.addContacts(connectedPeers)
286
285
  return closestPeers.getClosestContacts(limit).map((peer) => peer.getPeerDescriptor())
287
286
  }
@@ -134,13 +134,13 @@ export class Router implements IRouter {
134
134
  }
135
135
  }
136
136
 
137
- public doRouteMessage(routedMessage: RouteMessageWrapper, mode = RoutingMode.ROUTE): RouteMessageAck {
137
+ public doRouteMessage(routedMessage: RouteMessageWrapper, mode = RoutingMode.ROUTE, excludedPeer?: PeerDescriptor): RouteMessageAck {
138
138
  if (this.stopped) {
139
139
  return createRouteMessageAck(routedMessage, RouteMessageError.STOPPED)
140
140
  }
141
141
  logger.trace(`Routing message ${routedMessage.requestId} from ${getNodeIdFromPeerDescriptor(routedMessage.sourcePeer!)} `
142
142
  + `to ${getNodeIdFromPeerDescriptor(routedMessage.destinationPeer!)}`)
143
- const session = this.createRoutingSession(routedMessage, mode)
143
+ const session = this.createRoutingSession(routedMessage, mode, excludedPeer)
144
144
  const contacts = session.updateAndGetRoutablePeers()
145
145
  if (contacts.length > 0) {
146
146
  this.addRoutingSession(session)
@@ -173,7 +173,11 @@ export class Router implements IRouter {
173
173
  }
174
174
  }
175
175
 
176
- private createRoutingSession(routedMessage: RouteMessageWrapper, mode: RoutingMode): RoutingSession {
176
+ private createRoutingSession(routedMessage: RouteMessageWrapper, mode: RoutingMode, excludedPeer?: PeerDescriptor): RoutingSession {
177
+ const excludedPeers = routedMessage.routingPath.map((descriptor) => peerIdFromPeerDescriptor(descriptor))
178
+ if (excludedPeer) {
179
+ excludedPeers.push(peerIdFromPeerDescriptor(excludedPeer))
180
+ }
177
181
  logger.trace('routing session created with connections: ' + this.connections.size)
178
182
  return new RoutingSession(
179
183
  this.rpcCommunicator,
@@ -182,7 +186,7 @@ export class Router implements IRouter {
182
186
  this.connections,
183
187
  areEqualPeerDescriptors(this.localPeerDescriptor, routedMessage.sourcePeer!) ? 2 : 1,
184
188
  mode,
185
- routedMessage.routingPath.map((descriptor) => peerIdFromPeerDescriptor(descriptor))
189
+ excludedPeers
186
190
  )
187
191
  }
188
192
 
@@ -98,14 +98,14 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
98
98
  this.mode = mode
99
99
  const previousPeer = getPreviousPeer(messageToRoute)
100
100
  const previousId = previousPeer ? PeerID.fromValue(previousPeer.nodeId) : undefined
101
- this.contactList = new SortedContactList(
102
- PeerID.fromValue(this.messageToRoute.destinationPeer!.nodeId),
103
- 10000,
104
- undefined,
105
- true,
106
- previousId,
107
- excludedPeerIDs
108
- )
101
+ this.contactList = new SortedContactList({
102
+ referenceId: PeerID.fromValue(this.messageToRoute.destinationPeer!.nodeId),
103
+ maxSize: 10000, // TODO use config option or named constant?
104
+ allowToContainReferenceId: true,
105
+ peerIdDistanceLimit: previousId,
106
+ excludedPeerIDs: excludedPeerIDs,
107
+ emitEvents: false
108
+ })
109
109
  }
110
110
 
111
111
  private onRequestFailed(peerId: PeerID) {
@@ -93,8 +93,12 @@ export class StoreRpcLocal implements IStoreRpc {
93
93
  const localPeerId = PeerID.fromValue(this.localPeerDescriptor.nodeId)
94
94
 
95
95
  const closestToData = this.getNodesClosestToIdFromBucket(dataEntry.key, 10)
96
-
97
- const sortedList = new SortedContactList<Contact>(dataId, 20, undefined, true)
96
+ const sortedList = new SortedContactList<Contact>({
97
+ referenceId: PeerID.fromValue(dataEntry.key),
98
+ maxSize: 20, // TODO use config option or named constant?
99
+ allowToContainReferenceId: true,
100
+ emitEvents: false
101
+ })
98
102
  sortedList.addContact(new Contact(this.localPeerDescriptor))
99
103
 
100
104
  closestToData.forEach((con) => {
@@ -108,6 +112,7 @@ export class StoreRpcLocal implements IStoreRpc {
108
112
  return false
109
113
  }
110
114
 
115
+ this.localDataStore.setStale(dataId, dataEntry.creator!, false)
111
116
  const newPeerId = PeerID.fromValue(newNode.nodeId)
112
117
  sortedList.addContact(new Contact(newNode))
113
118
 
@@ -125,10 +130,8 @@ export class StoreRpcLocal implements IStoreRpc {
125
130
  // do replicate data to it
126
131
 
127
132
  if (index < this.redundancyFactor) {
128
- this.localDataStore.setStale(dataId, dataEntry.creator!, false)
129
133
  return true
130
134
  } else {
131
- this.localDataStore.setStale(dataId, dataEntry.creator!, true)
132
135
  return false
133
136
  }
134
137
  }
@@ -201,7 +204,12 @@ export class StoreRpcLocal implements IStoreRpc {
201
204
  private selfIsOneOfClosestPeers(dataId: Uint8Array): boolean {
202
205
  const localPeerId = PeerID.fromValue(this.localPeerDescriptor.nodeId)
203
206
  const closestPeers = this.getNodesClosestToIdFromBucket(dataId, this.redundancyFactor)
204
- const sortedList = new SortedContactList<Contact>(localPeerId, this.redundancyFactor, undefined, true)
207
+ const sortedList = new SortedContactList<Contact>({
208
+ referenceId: localPeerId,
209
+ maxSize: this.redundancyFactor,
210
+ allowToContainReferenceId: true,
211
+ emitEvents: false
212
+ })
205
213
  sortedList.addContact(new Contact(this.localPeerDescriptor))
206
214
  closestPeers.forEach((con) => sortedList.addContact(new Contact(con.getPeerDescriptor())))
207
215
  return sortedList.getClosestContacts().some((node) => node.getPeerId().equals(localPeerId))
@@ -282,8 +290,12 @@ export class StoreRpcLocal implements IStoreRpc {
282
290
  const dataId = PeerID.fromValue(dataEntry.key)
283
291
  const incomingPeerId = PeerID.fromValue(incomingPeer.nodeId)
284
292
  const closestToData = this.getNodesClosestToIdFromBucket(dataEntry.key, 10)
285
-
286
- const sortedList = new SortedContactList<Contact>(dataId, this.redundancyFactor, undefined, true)
293
+ const sortedList = new SortedContactList<Contact>({
294
+ referenceId: dataId,
295
+ maxSize: this.redundancyFactor,
296
+ allowToContainReferenceId: true,
297
+ emitEvents: false
298
+ })
287
299
  sortedList.addContact(new Contact(this.localPeerDescriptor))
288
300
 
289
301
  closestToData.forEach((con) => {
@@ -1,10 +1,14 @@
1
- import { BrandedString } from '@streamr/utils'
1
+ import { BrandedString, binaryToHex } from '@streamr/utils'
2
2
  import { UUID } from './UUID'
3
3
  import { IllegalArguments } from './errors'
4
4
  import crypto from 'crypto'
5
5
 
6
6
  export type PeerIDKey = BrandedString<'PeerIDKey'>
7
7
 
8
+ export const createPeerIDKey = (nodeId: Uint8Array): PeerIDKey => {
9
+ return binaryToHex(nodeId) as PeerIDKey
10
+ }
11
+
8
12
  export class PeerID {
9
13
  // avoid creating a new instance for every operation
10
14
  private static readonly textEncoder = new TextEncoder()
@@ -30,7 +34,7 @@ export class PeerID {
30
34
  throw new IllegalArguments('Constructor of PeerID must be given either ip, value or stringValue')
31
35
  }
32
36
 
33
- this.key = Buffer.from(this.data).toString('hex') as PeerIDKey
37
+ this.key = createPeerIDKey(this.data)
34
38
  }
35
39
 
36
40
  static fromIp(ip: string): PeerID {
@@ -1,6 +1,6 @@
1
- import { binaryToHex } from '@streamr/utils'
1
+ import { areEqualBinaries, binaryToHex } from '@streamr/utils'
2
2
  import { PeerDescriptor } from '../proto/packages/dht/protos/DhtRpc'
3
- import { PeerID, PeerIDKey } from './PeerID'
3
+ import { PeerID, PeerIDKey, createPeerIDKey } from './PeerID'
4
4
 
5
5
  export const peerIdFromPeerDescriptor = (peerDescriptor: PeerDescriptor): PeerID => {
6
6
  return PeerID.fromValue(peerDescriptor.nodeId)
@@ -12,9 +12,9 @@ export const getNodeIdFromPeerDescriptor = (peerDescriptor: PeerDescriptor): str
12
12
  }
13
13
 
14
14
  export const keyFromPeerDescriptor = (peerDescriptor: PeerDescriptor): PeerIDKey => {
15
- return PeerID.fromValue(peerDescriptor.nodeId).toKey()
15
+ return createPeerIDKey(peerDescriptor.nodeId)
16
16
  }
17
17
 
18
18
  export const areEqualPeerDescriptors = (peerDescriptor1: PeerDescriptor, peerDescriptor2: PeerDescriptor): boolean => {
19
- return peerIdFromPeerDescriptor(peerDescriptor1).equals(peerIdFromPeerDescriptor(peerDescriptor2))
19
+ return areEqualBinaries(peerDescriptor1.nodeId, peerDescriptor2.nodeId)
20
20
  }
@@ -71,7 +71,7 @@ describe('Find correctness', () => {
71
71
  logger.info('waiting over')
72
72
 
73
73
  nodes.forEach((node) => logger.info(getNodeIdFromPeerDescriptor(node.getLocalPeerDescriptor()) + ': connections:' +
74
- node.getNumberOfConnections() + ', kbucket: ' + node.getBucketSize()
74
+ node.getNumberOfConnections() + ', kbucket: ' + node.getNumberOfNeighbors()
75
75
  + ', localLocked: ' + node.getNumberOfLocalLockedConnections()
76
76
  + ', remoteLocked: ' + node.getNumberOfRemoteLockedConnections()
77
77
  + ', weakLocked: ' + node.getNumberOfWeakLockedConnections()))
@@ -102,7 +102,7 @@ describe('Kademlia correctness', () => {
102
102
  }
103
103
 
104
104
  if (i > 0) {
105
- sumKbucketSize += nodes[i].getBucketSize()
105
+ sumKbucketSize += nodes[i].getNumberOfNeighbors()
106
106
  sumCorrectNeighbors += correctNeighbors
107
107
  }
108
108
  }
@@ -0,0 +1,150 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import KBucket from 'k-bucket'
4
+ import { SortedContactList } from '../../src/dht/contact/SortedContactList'
5
+ import { PeerID } from '../../src/helpers/PeerID'
6
+ import crypto from 'crypto'
7
+
8
+ const NUM_ADDS = 1000
9
+ interface Item {
10
+ id: Uint8Array
11
+ vectorClock: number
12
+ getPeerId: () => PeerID
13
+ }
14
+
15
+ const createRandomItem = (index: number): Item => {
16
+ const rand = new Uint8Array(crypto.randomBytes(20))
17
+ return {
18
+ getPeerId: () => PeerID.fromValue(rand),
19
+ id: rand,
20
+ vectorClock: index
21
+ }
22
+ }
23
+
24
+ function shuffleArray<T>(array: T[]): T[] {
25
+ for (let i = array.length - 1; i > 0; i--) {
26
+ const j = Math.floor(Math.random() * (i + 1));
27
+ [array[i], array[j]] = [array[j], array[i]]
28
+ }
29
+ return array
30
+ }
31
+
32
+ describe('SortedContactListBenchmark', () => {
33
+
34
+ it('adds ' + NUM_ADDS + ' random peerIDs', async () => {
35
+ const randomIds = []
36
+ for (let i = 0; i < NUM_ADDS; i++) {
37
+ randomIds.push(createRandomItem(i))
38
+ }
39
+ const list = new SortedContactList({
40
+ referenceId: PeerID.fromValue(crypto.randomBytes(20)),
41
+ allowToContainReferenceId: true,
42
+ emitEvents: true
43
+ })
44
+
45
+ console.time('SortedContactList.addContact() with emitEvents=true')
46
+ for (let i = 0; i < NUM_ADDS; i++) {
47
+ list.addContact(randomIds[i])
48
+ }
49
+ console.timeEnd('SortedContactList.addContact() with emitEvents=true')
50
+
51
+ const list2 = new SortedContactList({
52
+ referenceId: PeerID.fromValue(crypto.randomBytes(20)),
53
+ allowToContainReferenceId: true,
54
+ emitEvents: false
55
+ })
56
+
57
+ console.time('SortedContactList.addContact() with emitEvents=false')
58
+ for (let i = 0; i < NUM_ADDS; i++) {
59
+ list2.addContact(randomIds[i])
60
+ }
61
+ console.timeEnd('SortedContactList.addContact() with emitEvents=false')
62
+
63
+ const kBucket = new KBucket<Item>({ localNodeId: crypto.randomBytes(20) })
64
+ console.time('KBucket.add()')
65
+ for (let i = 0; i < NUM_ADDS; i++) {
66
+ kBucket.add(randomIds[i])
67
+ }
68
+ console.timeEnd('KBucket.add()')
69
+
70
+ console.time('kBucket toArray()')
71
+
72
+ for (let i = 0; i < NUM_ADDS; i++) {
73
+ kBucket.toArray()
74
+ }
75
+ console.timeEnd('kBucket toArray()')
76
+
77
+ console.time('kBucket closest()')
78
+ for (let i = 0; i < NUM_ADDS; i++) {
79
+ kBucket.closest(crypto.randomBytes(20), 20)
80
+ }
81
+ console.timeEnd('kBucket closest()')
82
+
83
+ console.time('SortedContactList.getClosestContacts() with emitEvents=true')
84
+ for (let i = 0; i < NUM_ADDS; i++) {
85
+ const closest = new SortedContactList<Item>({
86
+ referenceId: PeerID.fromValue(crypto.randomBytes(20)),
87
+ allowToContainReferenceId: true,
88
+ emitEvents: true
89
+ })
90
+
91
+ const arrayFromBucket = kBucket.toArray()
92
+ arrayFromBucket.map((contact) => closest.addContact(contact))
93
+ closest.getClosestContacts(20)
94
+ }
95
+ console.timeEnd('SortedContactList.getClosestContacts() with emitEvents=true')
96
+
97
+ console.time('SortedContactList.getClosestContacts() with emitEvents=false')
98
+ for (let i = 0; i < NUM_ADDS; i++) {
99
+ const closest = new SortedContactList<Item>({
100
+ referenceId: PeerID.fromValue(crypto.randomBytes(20)),
101
+ allowToContainReferenceId: true,
102
+ emitEvents: false
103
+ })
104
+
105
+ const arrayFromBucket = kBucket.toArray()
106
+ arrayFromBucket.map((contact) => closest.addContact(contact))
107
+ closest.getClosestContacts(20)
108
+ }
109
+ console.timeEnd('SortedContactList.getClosestContacts() with emitEvents=false')
110
+
111
+ console.time('SortedContactList.getClosestContacts() with emitEvents=false and lodash')
112
+ for (let i = 0; i < NUM_ADDS; i++) {
113
+ const closest = new SortedContactList<Item>({
114
+ referenceId: PeerID.fromValue(crypto.randomBytes(20)),
115
+ allowToContainReferenceId: true,
116
+ emitEvents: false
117
+ })
118
+
119
+ const arrayFromBucket = kBucket.toArray()
120
+ arrayFromBucket.map((contact) => closest.addContact(contact))
121
+ closest.getClosestContacts(20)
122
+ }
123
+ console.timeEnd('SortedContactList.getClosestContacts() with emitEvents=false and lodash')
124
+
125
+ console.time('SortedContactList.getClosestContacts() with emitEvents=false and addContacts()')
126
+ for (let i = 0; i < NUM_ADDS; i++) {
127
+ const closest = new SortedContactList<Item>({
128
+ referenceId: PeerID.fromValue(crypto.randomBytes(20)),
129
+ allowToContainReferenceId: true,
130
+ emitEvents: false
131
+ })
132
+
133
+ const arrayFromBucket = kBucket.toArray()
134
+ closest.addContacts(arrayFromBucket)
135
+ closest.getClosestContacts(20)
136
+ }
137
+ console.timeEnd('SortedContactList.getClosestContacts() with emitEvents=false and addContacts()')
138
+
139
+ const shuffled = shuffleArray(kBucket.toArray())
140
+ console.time('kbucket add and closest')
141
+ for (let i = 0; i < NUM_ADDS; i++) {
142
+ const bucket2 = new KBucket<Item>({ localNodeId: crypto.randomBytes(20) })
143
+
144
+ shuffled.map((contact) => bucket2.add(contact))
145
+ bucket2.closest(crypto.randomBytes(20), 20)
146
+ }
147
+ console.timeEnd('kbucket add and closest')
148
+
149
+ })
150
+ })
@@ -0,0 +1,41 @@
1
+ /* eslint-disable no-console */
2
+
3
+ import { wait } from '@streamr/utils'
4
+ import { WebsocketServer } from '../../src/connection/websocket/WebsocketServer'
5
+ import { ClientWebsocket } from '../../src/exports'
6
+
7
+ // This 'test' is meant to be run manually using the following command:
8
+ // node --inspect ../../../../node_modules/.bin/jest WebsocketServerMemoryLeak.test.ts
9
+ // while wathing for memory leaks in Chrome DevTools
10
+
11
+ describe('WebsocketServermemoryLeak', () => {
12
+
13
+ it('Accepts and detroys connections', async () => {
14
+ const server = new WebsocketServer({
15
+ portRange: { min: 19792, max: 19792 },
16
+ enableTls: false
17
+ })
18
+
19
+ server.on('connected', (connection) => {
20
+ console.log('ServerWebsocket connected')
21
+ connection.destroy()
22
+ console.log('ServerWebsocket destroyed')
23
+ })
24
+
25
+ const port = await server.start()
26
+ expect(port).toEqual(19792)
27
+
28
+ for (let i = 0; i < 10000; i++) {
29
+ const clientWebsocket: ClientWebsocket = new ClientWebsocket()
30
+ clientWebsocket.on('connected', () => {
31
+ console.log('clientWebsocket connected ' + i)
32
+ })
33
+
34
+ clientWebsocket.connect(`ws://127.0.0.1:${port}`)
35
+ i++
36
+ await wait(3000)
37
+ }
38
+
39
+ await server.stop()
40
+ }, 120000000)
41
+ })
@@ -26,7 +26,12 @@ export class SimulationNode {
26
26
  numberOfNodesPerKBucket: this.numberOfNodesPerKBucket
27
27
  })
28
28
 
29
- this.neighborList = new SortedContactList(this.ownId, 1000)
29
+ this.neighborList = new SortedContactList({
30
+ referenceId: this.ownId,
31
+ maxSize: 1000,
32
+ allowToContainReferenceId: false,
33
+ emitEvents: false
34
+ })
30
35
  }
31
36
 
32
37
  // For simulation use
@@ -71,9 +71,9 @@ describe('Layer0', () => {
71
71
  node4.joinDht([epPeerDescriptor])
72
72
  ])
73
73
 
74
- expect(node1.getBucketSize()).toBeGreaterThanOrEqual(2)
75
- expect(node2.getBucketSize()).toBeGreaterThanOrEqual(2)
76
- expect(node3.getBucketSize()).toBeGreaterThanOrEqual(2)
77
- expect(node4.getBucketSize()).toBeGreaterThanOrEqual(2)
74
+ expect(node1.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
75
+ expect(node2.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
76
+ expect(node3.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
77
+ expect(node4.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
78
78
  }, 10000)
79
79
  })
@@ -89,11 +89,11 @@ describe('Layer0MixedConnectionTypes', () => {
89
89
  node5.joinDht([epPeerDescriptor])
90
90
  ])
91
91
 
92
- expect(node1.getBucketSize()).toBeGreaterThanOrEqual(2)
93
- expect(node2.getBucketSize()).toBeGreaterThanOrEqual(2)
94
- expect(node3.getBucketSize()).toBeGreaterThanOrEqual(2)
95
- expect(node4.getBucketSize()).toBeGreaterThanOrEqual(2)
96
- expect(node5.getBucketSize()).toBeGreaterThanOrEqual(1)
92
+ expect(node1.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
93
+ expect(node2.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
94
+ expect(node3.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
95
+ expect(node4.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
96
+ expect(node5.getNumberOfNeighbors()).toBeGreaterThanOrEqual(1)
97
97
 
98
98
  }, 15000)
99
99
 
@@ -105,10 +105,10 @@ describe('Layer0MixedConnectionTypes', () => {
105
105
  node4.joinDht([epPeerDescriptor]),
106
106
  node5.joinDht([epPeerDescriptor])
107
107
  ])
108
- expect(node1.getBucketSize()).toBeGreaterThanOrEqual(2)
109
- expect(node2.getBucketSize()).toBeGreaterThanOrEqual(2)
110
- expect(node3.getBucketSize()).toBeGreaterThanOrEqual(2)
111
- expect(node4.getBucketSize()).toBeGreaterThanOrEqual(2)
112
- expect(node5.getBucketSize()).toBeGreaterThanOrEqual(2)
108
+ expect(node1.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
109
+ expect(node2.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
110
+ expect(node3.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
111
+ expect(node4.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
112
+ expect(node5.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
113
113
  }, 30000)
114
114
  })
@@ -125,9 +125,9 @@ describe('Layer 1 on Layer 0 with mocked connections', () => {
125
125
  await layer1Node3.joinDht([entrypointDescriptor])
126
126
  await layer1Node4.joinDht([entrypointDescriptor])
127
127
 
128
- expect(layer1Node1.getBucketSize()).toBeGreaterThanOrEqual(2)
129
- expect(layer1Node2.getBucketSize()).toBeGreaterThanOrEqual(2)
130
- expect(layer1Node3.getBucketSize()).toBeGreaterThanOrEqual(2)
131
- expect(layer1Node4.getBucketSize()).toBeGreaterThanOrEqual(2)
128
+ expect(layer1Node1.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
129
+ expect(layer1Node2.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
130
+ expect(layer1Node3.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
131
+ expect(layer1Node4.getNumberOfNeighbors()).toBeGreaterThanOrEqual(2)
132
132
  }, 60000)
133
133
  })
@@ -75,10 +75,10 @@ describe('Layer1 Scale', () => {
75
75
  // TODO: fix flaky test in NET-1021
76
76
  it('bucket sizes', async () => {
77
77
  layer0Nodes.forEach((node) => {
78
- expect(node.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET - 1)
78
+ expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET - 1)
79
79
  })
80
80
  layer1Nodes.forEach((node ) => {
81
- expect(node.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
81
+ expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
82
82
  })
83
83
  })
84
84
  })
@@ -65,10 +65,10 @@ describe('Layer1 Scale', () => {
65
65
 
66
66
  it('bucket sizes', async () => {
67
67
  layer0Nodes.forEach((node) => {
68
- expect(node.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET - 1)
68
+ expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET - 1)
69
69
  })
70
70
  layer1Nodes.forEach((node) => {
71
- expect(node.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
71
+ expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
72
72
  })
73
73
  })
74
74
  })
@@ -46,7 +46,7 @@ describe('Failed autocertification', () => {
46
46
  const failedAutocertificationPeerDescriptor = failedAutocertificationNode.getLocalPeerDescriptor()
47
47
  expect(failedAutocertificationPeerDescriptor.websocket!.tls).toBe(false)
48
48
  await failedAutocertificationNode.joinDht([entryPointPeerDescriptor])
49
- expect(failedAutocertificationNode.getBucketSize()).toEqual(2)
49
+ expect(failedAutocertificationNode.getNumberOfNeighbors()).toEqual(2)
50
50
  })
51
51
 
52
52
  })
@@ -68,6 +68,7 @@ describe('memory leak', () => {
68
68
 
69
69
  const detector1 = new LeakDetector(entryPoint)
70
70
  entryPoint = undefined
71
+ await detector1.isLeaking()
71
72
  expect(await detector1.isLeaking()).toBe(false)
72
73
 
73
74
  const detector2 = new LeakDetector(sender)
@@ -25,10 +25,10 @@ const runTest = async (latencyType: LatencyType) => {
25
25
  await entryPoint.joinDht([entrypointDescriptor])
26
26
  await Promise.all(nodes.map((node) => node.joinDht([entrypointDescriptor])))
27
27
  nodes.forEach((node) => {
28
- expect(node.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
28
+ expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
29
29
  expect(node.getClosestContacts().length).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
30
30
  })
31
- expect(entryPoint.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
31
+ expect(entryPoint.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
32
32
 
33
33
  await Promise.all([
34
34
  entryPoint.stop(),
@@ -75,7 +75,7 @@ describe('Layer1', () => {
75
75
  const layer1Node = layer1Nodes[i]
76
76
  expect(layer1Node.getNodeId().equals(layer0Node.getNodeId())).toEqual(true)
77
77
  expect(layer1Node.getNumberOfConnections()).toEqual(layer0Node.getNumberOfConnections())
78
- expect(layer1Node.getBucketSize()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
78
+ expect(layer1Node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET / 2)
79
79
  expect(layer1Node.getAllConnectionPeerDescriptors()).toEqual(layer0Node.getAllConnectionPeerDescriptors())
80
80
  }
81
81
  }, 120000)
@@ -85,21 +85,21 @@ describe('Layer 1 on Layer 0 with mocked connections', () => {
85
85
  await layer1Node3.joinDht([entryPointDescriptor])
86
86
  await layer1Node4.joinDht([entryPointDescriptor])
87
87
 
88
- logger.info('layer1EntryPoint.getBucketSize() ' + layer1EntryPoint.getBucketSize())
89
- logger.info('layer1Node1.getBucketSize()' + layer1Node1.getBucketSize())
90
- logger.info('layer1Node2.getBucketSize()' + layer1Node2.getBucketSize())
91
- logger.info('layer1Node3.getBucketSize()' + layer1Node3.getBucketSize())
92
- logger.info('layer1Node4.getBucketSize()' + layer1Node4.getBucketSize())
93
-
94
- expect(layer1Node1.getBucketSize()).toEqual(layer0Node1.getBucketSize())
95
- expect(layer1Node2.getBucketSize()).toEqual(layer0Node2.getBucketSize())
96
- expect(layer1Node3.getBucketSize()).toEqual(layer0Node3.getBucketSize())
97
- expect(layer1Node4.getBucketSize()).toEqual(layer0Node4.getBucketSize())
98
-
99
- expect(layer1Node1.getKBucketPeers()).toContainValues(layer0Node1.getKBucketPeers())
100
- expect(layer1Node2.getKBucketPeers()).toContainValues(layer0Node2.getKBucketPeers())
101
- expect(layer1Node3.getKBucketPeers()).toContainValues(layer0Node3.getKBucketPeers())
102
- expect(layer1Node4.getKBucketPeers()).toContainValues(layer0Node4.getKBucketPeers())
88
+ logger.info('layer1EntryPoint.getNumberOfNeighbors() ' + layer1EntryPoint.getNumberOfNeighbors())
89
+ logger.info('layer1Node1.getNumberOfNeighbors()' + layer1Node1.getNumberOfNeighbors())
90
+ logger.info('layer1Node2.getNumberOfNeighbors()' + layer1Node2.getNumberOfNeighbors())
91
+ logger.info('layer1Node3.getNumberOfNeighbors()' + layer1Node3.getNumberOfNeighbors())
92
+ logger.info('layer1Node4.getNumberOfNeighbors()' + layer1Node4.getNumberOfNeighbors())
93
+
94
+ expect(layer1Node1.getNumberOfNeighbors()).toEqual(layer0Node1.getNumberOfNeighbors())
95
+ expect(layer1Node2.getNumberOfNeighbors()).toEqual(layer0Node2.getNumberOfNeighbors())
96
+ expect(layer1Node3.getNumberOfNeighbors()).toEqual(layer0Node3.getNumberOfNeighbors())
97
+ expect(layer1Node4.getNumberOfNeighbors()).toEqual(layer0Node4.getNumberOfNeighbors())
98
+
99
+ expect(layer1Node1.getAllNeighborPeerDescriptors()).toContainValues(layer0Node1.getAllNeighborPeerDescriptors())
100
+ expect(layer1Node2.getAllNeighborPeerDescriptors()).toContainValues(layer0Node2.getAllNeighborPeerDescriptors())
101
+ expect(layer1Node3.getAllNeighborPeerDescriptors()).toContainValues(layer0Node3.getAllNeighborPeerDescriptors())
102
+ expect(layer1Node4.getAllNeighborPeerDescriptors()).toContainValues(layer0Node4.getAllNeighborPeerDescriptors())
103
103
 
104
104
  }, 60000)
105
105
  })
@@ -42,9 +42,9 @@ describe('multiple entry point joining', () => {
42
42
  node2.joinDht(entryPoints),
43
43
  node3.joinDht(entryPoints)
44
44
  ])
45
- expect(node1.getBucketSize()).toEqual(2)
46
- expect(node2.getBucketSize()).toEqual(2)
47
- expect(node3.getBucketSize()).toEqual(2)
45
+ expect(node1.getNumberOfNeighbors()).toEqual(2)
46
+ expect(node2.getNumberOfNeighbors()).toEqual(2)
47
+ expect(node3.getNumberOfNeighbors()).toEqual(2)
48
48
  })
49
49
 
50
50
  it('can join even if a node is offline', async () => {
@@ -53,8 +53,8 @@ describe('multiple entry point joining', () => {
53
53
  node1.joinDht(entryPoints),
54
54
  node2.joinDht(entryPoints)
55
55
  ])
56
- expect(node1.getBucketSize()).toEqual(1)
57
- expect(node2.getBucketSize()).toEqual(1)
56
+ expect(node1.getNumberOfNeighbors()).toEqual(1)
57
+ expect(node2.getNumberOfNeighbors()).toEqual(1)
58
58
  }, 10000)
59
59
  })
60
60
 
@@ -96,9 +96,9 @@ describe('multiple entry point joining', () => {
96
96
 
97
97
  it('non-entry point nodes can join', async () => {
98
98
  await node1.joinDht(entryPoints)
99
- expect(node1.getBucketSize()).toEqual(2)
99
+ expect(node1.getNumberOfNeighbors()).toEqual(2)
100
100
  await node2.joinDht(entryPoints)
101
- expect(node2.getBucketSize()).toEqual(3)
101
+ expect(node2.getNumberOfNeighbors()).toEqual(3)
102
102
  })
103
103
 
104
104
  })
@@ -80,7 +80,12 @@ describe('Replicate data from node to node in DHT', () => {
80
80
 
81
81
  // calculate offline which node is closest to the data
82
82
 
83
- const sortedList = new SortedContactList<Contact>(dataKey, 10000)
83
+ const sortedList = new SortedContactList<Contact>({
84
+ referenceId: dataKey,
85
+ maxSize: 10000,
86
+ allowToContainReferenceId: true,
87
+ emitEvents: false
88
+ })
84
89
 
85
90
  nodes.forEach((node) => {
86
91
  sortedList.addContact(new Contact(node.getLocalPeerDescriptor())