@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.
- package/dist/src/connection/ConnectionLockRpcRemote.js +1 -25
- package/dist/src/connection/ConnectionLockRpcRemote.js.map +1 -1
- package/dist/src/connection/ConnectionManager.d.ts +0 -1
- package/dist/src/connection/ConnectionManager.js +7 -6
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/connection/ConnectorFacade.d.ts +2 -2
- package/dist/src/connection/ConnectorFacade.js +1 -2
- package/dist/src/connection/ConnectorFacade.js.map +1 -1
- package/dist/src/connection/connectivityChecker.js +3 -2
- package/dist/src/connection/connectivityChecker.js.map +1 -1
- package/dist/src/connection/websocket/ClientWebsocket.d.ts +1 -0
- package/dist/src/connection/websocket/ClientWebsocket.js +6 -3
- package/dist/src/connection/websocket/ClientWebsocket.js.map +1 -1
- package/dist/src/connection/websocket/ServerWebsocket.d.ts +4 -0
- package/dist/src/connection/websocket/ServerWebsocket.js +32 -21
- package/dist/src/connection/websocket/ServerWebsocket.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketConnector.d.ts +0 -1
- package/dist/src/connection/websocket/WebsocketConnector.js +21 -10
- package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.d.ts +1 -1
- package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js +8 -11
- package/dist/src/connection/websocket/WebsocketConnectorRpcLocal.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.d.ts +2 -2
- package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js +3 -37
- package/dist/src/connection/websocket/WebsocketConnectorRpcRemote.js.map +1 -1
- package/dist/src/connection/websocket/WebsocketServer.js +21 -4
- package/dist/src/connection/websocket/WebsocketServer.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +4 -4
- package/dist/src/dht/DhtNode.js +30 -19
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtNodeRpcLocal.d.ts +1 -4
- package/dist/src/dht/DhtNodeRpcLocal.js +1 -5
- package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
- package/dist/src/dht/PeerManager.d.ts +10 -6
- package/dist/src/dht/PeerManager.js +95 -30
- package/dist/src/dht/PeerManager.js.map +1 -1
- package/dist/src/dht/contact/SortedContactList.d.ts +20 -6
- package/dist/src/dht/contact/SortedContactList.js +55 -24
- package/dist/src/dht/contact/SortedContactList.js.map +1 -1
- package/dist/src/dht/discovery/DiscoverySession.d.ts +2 -5
- package/dist/src/dht/discovery/DiscoverySession.js +12 -9
- package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
- package/dist/src/dht/discovery/PeerDiscovery.d.ts +1 -1
- package/dist/src/dht/discovery/PeerDiscovery.js +4 -10
- package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
- package/dist/src/dht/find/FindSession.js +6 -1
- package/dist/src/dht/find/FindSession.js.map +1 -1
- package/dist/src/dht/find/Finder.js +6 -1
- package/dist/src/dht/find/Finder.js.map +1 -1
- package/dist/src/dht/routing/Router.d.ts +1 -1
- package/dist/src/dht/routing/Router.js +8 -4
- package/dist/src/dht/routing/Router.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.js +8 -1
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/dht/store/StoreRpcLocal.js +19 -5
- package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
- package/dist/src/helpers/PeerID.d.ts +1 -0
- package/dist/src/helpers/PeerID.js +7 -2
- package/dist/src/helpers/PeerID.js.map +1 -1
- package/dist/src/helpers/peerIdFromPeerDescriptor.js +2 -2
- package/dist/src/helpers/peerIdFromPeerDescriptor.js.map +1 -1
- package/package.json +5 -5
- package/src/connection/ConnectionLockRpcRemote.ts +1 -2
- package/src/connection/ConnectionManager.ts +16 -17
- package/src/connection/ConnectorFacade.ts +0 -3
- package/src/connection/connectivityChecker.ts +3 -2
- package/src/connection/websocket/ClientWebsocket.ts +5 -2
- package/src/connection/websocket/ServerWebsocket.ts +40 -25
- package/src/connection/websocket/WebsocketConnector.ts +23 -12
- package/src/connection/websocket/WebsocketConnectorRpcLocal.ts +9 -11
- package/src/connection/websocket/WebsocketConnectorRpcRemote.ts +5 -14
- package/src/connection/websocket/WebsocketServer.ts +20 -5
- package/src/dht/DhtNode.ts +31 -21
- package/src/dht/DhtNodeRpcLocal.ts +2 -9
- package/src/dht/PeerManager.ts +110 -36
- package/src/dht/contact/SortedContactList.ts +87 -44
- package/src/dht/discovery/DiscoverySession.ts +14 -14
- package/src/dht/discovery/PeerDiscovery.ts +9 -16
- package/src/dht/find/FindSession.ts +6 -1
- package/src/dht/find/Finder.ts +6 -7
- package/src/dht/routing/Router.ts +8 -4
- package/src/dht/routing/RoutingSession.ts +8 -8
- package/src/dht/store/StoreRpcLocal.ts +19 -7
- package/src/helpers/PeerID.ts +6 -2
- package/src/helpers/peerIdFromPeerDescriptor.ts +4 -4
- package/test/benchmark/Find.test.ts +1 -1
- package/test/benchmark/KademliaCorrectness.test.ts +1 -1
- package/test/benchmark/SortedContactListBenchmark.test.ts +150 -0
- package/test/benchmark/WebsocketServerMemoryLeak.test.ts +41 -0
- package/test/benchmark/kademlia-simulation/SimulationNode.ts +6 -1
- package/test/end-to-end/Layer0.test.ts +4 -4
- package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +10 -10
- package/test/end-to-end/Layer0Webrtc-Layer1.test.ts +4 -4
- package/test/end-to-end/Layer1-Scale-WebSocket.test.ts +2 -2
- package/test/end-to-end/Layer1-Scale-Webrtc.test.ts +2 -2
- package/test/end-to-end/RecoveryFromFailedAutoCertification.test.ts +1 -1
- package/test/end-to-end/memory-leak.test.ts +1 -0
- package/test/integration/DhtJoinPeerDiscovery.test.ts +2 -2
- package/test/integration/Layer1-scale.test.ts +1 -1
- package/test/integration/Mock-Layer1-Layer0.test.ts +15 -15
- package/test/integration/MultipleEntryPointJoining.test.ts +7 -7
- package/test/integration/ReplicateData.test.ts +6 -1
- package/test/integration/SimultaneousConnections.test.ts +81 -49
- package/test/integration/StoreOnDhtWithTwoNodes.test.ts +1 -1
- package/test/integration/WebsocketConnectionManagement.test.ts +41 -3
- package/test/integration/WebsocketConnectorRpc.test.ts +3 -5
- package/test/unit/SortedContactList.test.ts +15 -10
package/src/dht/find/Finder.ts
CHANGED
|
@@ -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
|
-
|
|
282
|
-
|
|
283
|
-
|
|
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
|
-
|
|
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
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
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
|
-
|
|
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>(
|
|
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
|
-
|
|
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) => {
|
package/src/helpers/PeerID.ts
CHANGED
|
@@ -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 =
|
|
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
|
|
15
|
+
return createPeerIDKey(peerDescriptor.nodeId)
|
|
16
16
|
}
|
|
17
17
|
|
|
18
18
|
export const areEqualPeerDescriptors = (peerDescriptor1: PeerDescriptor, peerDescriptor2: PeerDescriptor): boolean => {
|
|
19
|
-
return
|
|
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.
|
|
74
|
+
node.getNumberOfConnections() + ', kbucket: ' + node.getNumberOfNeighbors()
|
|
75
75
|
+ ', localLocked: ' + node.getNumberOfLocalLockedConnections()
|
|
76
76
|
+ ', remoteLocked: ' + node.getNumberOfRemoteLockedConnections()
|
|
77
77
|
+ ', weakLocked: ' + node.getNumberOfWeakLockedConnections()))
|
|
@@ -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(
|
|
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.
|
|
75
|
-
expect(node2.
|
|
76
|
-
expect(node3.
|
|
77
|
-
expect(node4.
|
|
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.
|
|
93
|
-
expect(node2.
|
|
94
|
-
expect(node3.
|
|
95
|
-
expect(node4.
|
|
96
|
-
expect(node5.
|
|
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.
|
|
109
|
-
expect(node2.
|
|
110
|
-
expect(node3.
|
|
111
|
-
expect(node4.
|
|
112
|
-
expect(node5.
|
|
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.
|
|
129
|
-
expect(layer1Node2.
|
|
130
|
-
expect(layer1Node3.
|
|
131
|
-
expect(layer1Node4.
|
|
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.
|
|
78
|
+
expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET - 1)
|
|
79
79
|
})
|
|
80
80
|
layer1Nodes.forEach((node ) => {
|
|
81
|
-
expect(node.
|
|
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.
|
|
68
|
+
expect(node.getNumberOfNeighbors()).toBeGreaterThanOrEqual(NUM_OF_NODES_PER_KBUCKET - 1)
|
|
69
69
|
})
|
|
70
70
|
layer1Nodes.forEach((node) => {
|
|
71
|
-
expect(node.
|
|
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.
|
|
49
|
+
expect(failedAutocertificationNode.getNumberOfNeighbors()).toEqual(2)
|
|
50
50
|
})
|
|
51
51
|
|
|
52
52
|
})
|
|
@@ -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.
|
|
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.
|
|
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.
|
|
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.
|
|
89
|
-
logger.info('layer1Node1.
|
|
90
|
-
logger.info('layer1Node2.
|
|
91
|
-
logger.info('layer1Node3.
|
|
92
|
-
logger.info('layer1Node4.
|
|
93
|
-
|
|
94
|
-
expect(layer1Node1.
|
|
95
|
-
expect(layer1Node2.
|
|
96
|
-
expect(layer1Node3.
|
|
97
|
-
expect(layer1Node4.
|
|
98
|
-
|
|
99
|
-
expect(layer1Node1.
|
|
100
|
-
expect(layer1Node2.
|
|
101
|
-
expect(layer1Node3.
|
|
102
|
-
expect(layer1Node4.
|
|
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.
|
|
46
|
-
expect(node2.
|
|
47
|
-
expect(node3.
|
|
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.
|
|
57
|
-
expect(node2.
|
|
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.
|
|
99
|
+
expect(node1.getNumberOfNeighbors()).toEqual(2)
|
|
100
100
|
await node2.joinDht(entryPoints)
|
|
101
|
-
expect(node2.
|
|
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>(
|
|
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())
|