@streamr/dht 100.2.1 → 100.2.3

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 (118) hide show
  1. package/dist/package.json +6 -6
  2. package/dist/src/connection/ConnectionLockStates.js +4 -6
  3. package/dist/src/connection/ConnectionLockStates.js.map +1 -1
  4. package/dist/src/connection/ConnectionManager.d.ts +1 -0
  5. package/dist/src/connection/ConnectionManager.js +8 -2
  6. package/dist/src/connection/ConnectionManager.js.map +1 -1
  7. package/dist/src/connection/ManagedConnection.js +7 -9
  8. package/dist/src/connection/ManagedConnection.js.map +1 -1
  9. package/dist/src/connection/connectivityChecker.js +0 -3
  10. package/dist/src/connection/connectivityChecker.js.map +1 -1
  11. package/dist/src/connection/websocket/WebsocketConnector.js +1 -1
  12. package/dist/src/connection/websocket/WebsocketConnector.js.map +1 -1
  13. package/dist/src/dht/DhtNode.d.ts +10 -7
  14. package/dist/src/dht/DhtNode.js +51 -32
  15. package/dist/src/dht/DhtNode.js.map +1 -1
  16. package/dist/src/dht/DhtNodeRpcLocal.d.ts +2 -2
  17. package/dist/src/dht/DhtNodeRpcLocal.js +5 -4
  18. package/dist/src/dht/DhtNodeRpcLocal.js.map +1 -1
  19. package/dist/src/dht/DhtNodeRpcRemote.js +1 -0
  20. package/dist/src/dht/DhtNodeRpcRemote.js.map +1 -1
  21. package/dist/src/dht/PeerManager.d.ts +14 -14
  22. package/dist/src/dht/PeerManager.js +23 -59
  23. package/dist/src/dht/PeerManager.js.map +1 -1
  24. package/dist/src/dht/contact/ContactList.d.ts +2 -2
  25. package/dist/src/dht/contact/RandomContactList.js +2 -2
  26. package/dist/src/dht/contact/RandomContactList.js.map +1 -1
  27. package/dist/src/dht/contact/RingContactList.d.ts +2 -5
  28. package/dist/src/dht/contact/RingContactList.js +3 -11
  29. package/dist/src/dht/contact/RingContactList.js.map +1 -1
  30. package/dist/src/dht/contact/SortedContactList.d.ts +4 -1
  31. package/dist/src/dht/contact/SortedContactList.js +4 -5
  32. package/dist/src/dht/contact/SortedContactList.js.map +1 -1
  33. package/dist/src/dht/contact/getClosestContacts.d.ts +7 -0
  34. package/dist/src/dht/contact/getClosestContacts.js +18 -0
  35. package/dist/src/dht/contact/getClosestContacts.js.map +1 -0
  36. package/dist/src/dht/discovery/DiscoverySession.d.ts +8 -8
  37. package/dist/src/dht/discovery/DiscoverySession.js +30 -35
  38. package/dist/src/dht/discovery/DiscoverySession.js.map +1 -1
  39. package/dist/src/dht/discovery/PeerDiscovery.d.ts +1 -2
  40. package/dist/src/dht/discovery/PeerDiscovery.js +6 -8
  41. package/dist/src/dht/discovery/PeerDiscovery.js.map +1 -1
  42. package/dist/src/dht/discovery/RingDiscoverySession.d.ts +4 -4
  43. package/dist/src/dht/discovery/RingDiscoverySession.js +13 -13
  44. package/dist/src/dht/discovery/RingDiscoverySession.js.map +1 -1
  45. package/dist/src/dht/recursive-operation/RecursiveOperationManager.d.ts +2 -2
  46. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js +15 -15
  47. package/dist/src/dht/recursive-operation/RecursiveOperationManager.js.map +1 -1
  48. package/dist/src/dht/recursive-operation/RecursiveOperationSession.d.ts +1 -1
  49. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js +11 -13
  50. package/dist/src/dht/recursive-operation/RecursiveOperationSession.js.map +1 -1
  51. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.js +1 -1
  52. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.d.ts +1 -1
  53. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.js +2 -2
  54. package/dist/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.js.map +1 -1
  55. package/dist/src/dht/routing/Router.d.ts +1 -2
  56. package/dist/src/dht/routing/Router.js +2 -3
  57. package/dist/src/dht/routing/Router.js.map +1 -1
  58. package/dist/src/dht/routing/RoutingSession.d.ts +1 -2
  59. package/dist/src/dht/routing/RoutingSession.js +2 -2
  60. package/dist/src/dht/routing/RoutingSession.js.map +1 -1
  61. package/dist/src/dht/store/StoreRpcLocal.js +3 -3
  62. package/dist/src/dht/store/StoreRpcLocal.js.map +1 -1
  63. package/dist/src/proto/packages/dht/protos/DhtRpc.client.d.ts +8 -0
  64. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js +4 -0
  65. package/dist/src/proto/packages/dht/protos/DhtRpc.client.js.map +1 -1
  66. package/dist/src/proto/packages/dht/protos/DhtRpc.d.ts +10 -2
  67. package/dist/src/proto/packages/dht/protos/DhtRpc.js +1 -1
  68. package/dist/src/proto/packages/dht/protos/DhtRpc.js.map +1 -1
  69. package/dist/src/proto/packages/dht/protos/DhtRpc.server.d.ts +4 -0
  70. package/dist/src/transport/ITransport.d.ts +3 -0
  71. package/dist/src/transport/ITransport.js.map +1 -1
  72. package/package.json +6 -6
  73. package/protos/DhtRpc.proto +7 -1
  74. package/src/connection/ConnectionLockStates.ts +3 -5
  75. package/src/connection/ConnectionManager.ts +9 -2
  76. package/src/connection/ManagedConnection.ts +11 -14
  77. package/src/connection/connectivityChecker.ts +0 -2
  78. package/src/connection/webrtc/BrowserWebrtcConnection.ts +0 -1
  79. package/src/connection/websocket/WebsocketConnector.ts +1 -1
  80. package/src/dht/DhtNode.ts +63 -44
  81. package/src/dht/DhtNodeRpcLocal.ts +7 -6
  82. package/src/dht/DhtNodeRpcRemote.ts +1 -0
  83. package/src/dht/PeerManager.ts +38 -73
  84. package/src/dht/contact/ContactList.ts +2 -2
  85. package/src/dht/contact/RandomContactList.ts +2 -3
  86. package/src/dht/contact/RingContactList.ts +6 -16
  87. package/src/dht/contact/SortedContactList.ts +9 -10
  88. package/src/dht/contact/getClosestContacts.ts +22 -0
  89. package/src/dht/discovery/DiscoverySession.ts +35 -45
  90. package/src/dht/discovery/PeerDiscovery.ts +6 -9
  91. package/src/dht/discovery/RingDiscoverySession.ts +13 -13
  92. package/src/dht/recursive-operation/RecursiveOperationManager.ts +16 -16
  93. package/src/dht/recursive-operation/RecursiveOperationSession.ts +11 -13
  94. package/src/dht/recursive-operation/RecursiveOperationSessionRpcLocal.ts +1 -1
  95. package/src/dht/recursive-operation/RecursiveOperationSessionRpcRemote.ts +2 -2
  96. package/src/dht/routing/Router.ts +3 -5
  97. package/src/dht/routing/RoutingSession.ts +3 -4
  98. package/src/dht/store/StoreRpcLocal.ts +3 -3
  99. package/src/proto/packages/dht/protos/DhtRpc.client.ts +8 -0
  100. package/src/proto/packages/dht/protos/DhtRpc.server.ts +4 -0
  101. package/src/proto/packages/dht/protos/DhtRpc.ts +11 -3
  102. package/src/transport/ITransport.ts +3 -0
  103. package/test/end-to-end/Layer0MixedConnectionTypes.test.ts +3 -5
  104. package/test/integration/DhtNode.test.ts +81 -0
  105. package/test/integration/Layer1-scale.test.ts +1 -1
  106. package/test/integration/ScaleDownDht.test.ts +7 -4
  107. package/test/unit/DiscoverySession.test.ts +85 -0
  108. package/test/unit/PeerManager.test.ts +3 -17
  109. package/test/unit/RecursiveOperationManager.test.ts +5 -3
  110. package/test/unit/Router.test.ts +2 -2
  111. package/test/unit/RoutingSession.test.ts +2 -2
  112. package/test/unit/SortedContactList.test.ts +4 -4
  113. package/test/unit/getClosestContacts.test.ts +28 -0
  114. package/test/utils/FakeTransport.ts +34 -7
  115. package/test/utils/mock/Router.ts +0 -3
  116. package/test/utils/mock/Transport.ts +10 -0
  117. package/test/utils/topology.ts +80 -0
  118. package/test/RandomGraphSimulation.ts +0 -53
@@ -1,11 +1,16 @@
1
1
  import { EventEmitter } from 'eventemitter3'
2
- import { ITransport, TransportEvents } from '../../src/transport/ITransport'
2
+ import { DhtAddress, getDhtAddressFromRaw, getNodeIdFromPeerDescriptor } from '../../src/identifiers'
3
3
  import { Message, PeerDescriptor } from '../../src/proto/packages/dht/protos/DhtRpc'
4
+ import { DEFAULT_SEND_OPTIONS, ITransport, SendOptions, TransportEvents } from '../../src/transport/ITransport'
4
5
 
5
6
  class FakeTransport extends EventEmitter<TransportEvents> implements ITransport {
6
7
 
7
8
  private onSend: (msg: Message) => void
8
9
  private readonly localPeerDescriptor: PeerDescriptor
10
+ // currently adds a peerDescription to the connections array when a "connect" option is seen in
11
+ // in send() call and never disconnects (TODO could add some disconnection logic? and maybe
12
+ // the connection should be seen by another FakeTransport instance, too?)
13
+ private connections: PeerDescriptor[] = []
9
14
 
10
15
  constructor(peerDescriptor: PeerDescriptor, onSend: (msg: Message) => void) {
11
16
  super()
@@ -13,19 +18,37 @@ class FakeTransport extends EventEmitter<TransportEvents> implements ITransport
13
18
  this.localPeerDescriptor = peerDescriptor
14
19
  }
15
20
 
16
- async send(msg: Message): Promise<void> {
21
+ async send(msg: Message, opts?: SendOptions): Promise<void> {
22
+ const connect = opts?.connect ?? DEFAULT_SEND_OPTIONS.connect
23
+ const targetNodeId = getNodeIdFromPeerDescriptor(msg.targetDescriptor!)
24
+ if (connect && !this.connections.some((c) => getNodeIdFromPeerDescriptor(c) === targetNodeId)) {
25
+ this.connect(msg.targetDescriptor!)
26
+ }
17
27
  msg.sourceDescriptor = this.localPeerDescriptor
18
28
  this.onSend(msg)
19
29
  }
20
30
 
21
- // eslint-disable-next-line class-methods-use-this
22
31
  getLocalPeerDescriptor(): PeerDescriptor {
23
- throw new Error('not implemented')
32
+ return this.localPeerDescriptor
33
+ }
34
+
35
+ private connect(peerDescriptor: PeerDescriptor) {
36
+ this.connections.push(peerDescriptor)
37
+ this.emit('connected', peerDescriptor)
24
38
  }
25
39
 
26
- // eslint-disable-next-line class-methods-use-this
27
40
  getConnections(): PeerDescriptor[] {
28
- throw new Error('not implemented')
41
+ return this.connections
42
+ }
43
+
44
+ // eslint-disable-next-line class-methods-use-this
45
+ getConnectionCount(): number {
46
+ return this.connections.length
47
+ }
48
+
49
+ // eslint-disable-next-line class-methods-use-this
50
+ hasConnection(nodeId: DhtAddress): boolean {
51
+ return this.connections.some((c) => getNodeIdFromPeerDescriptor(c) === nodeId)
29
52
  }
30
53
 
31
54
  // eslint-disable-next-line class-methods-use-this
@@ -39,7 +62,11 @@ export class FakeEnvironment {
39
62
 
40
63
  createTransport(peerDescriptor: PeerDescriptor): ITransport {
41
64
  const transport = new FakeTransport(peerDescriptor, (msg) => {
42
- this.transports.forEach((t) => t.emit('message', msg))
65
+ const targetNode = getDhtAddressFromRaw(msg.targetDescriptor!.nodeId)
66
+ const targetTransport = this.transports.find((t) => getNodeIdFromPeerDescriptor(t.getLocalPeerDescriptor()) === targetNode)
67
+ if (targetTransport !== undefined) {
68
+ targetTransport.emit('message', msg)
69
+ }
43
70
  })
44
71
  this.transports.push(transport)
45
72
  return transport
@@ -6,17 +6,14 @@ export class MockRouter implements Methods<Router> {
6
6
 
7
7
  // eslint-disable-next-line class-methods-use-this
8
8
  addRoutingSession(): void {
9
- return
10
9
  }
11
10
 
12
11
  // eslint-disable-next-line class-methods-use-this
13
12
  removeRoutingSession(): void {
14
- return
15
13
  }
16
14
 
17
15
  // eslint-disable-next-line class-methods-use-this
18
16
  addToDuplicateDetector(): void {
19
- return
20
17
  }
21
18
 
22
19
  // eslint-disable-next-line class-methods-use-this
@@ -19,6 +19,16 @@ export class MockTransport extends EventEmitter<TransportEvents> implements ITra
19
19
  return []
20
20
  }
21
21
 
22
+ // eslint-disable-next-line class-methods-use-this
23
+ getConnectionCount(): number {
24
+ return 0
25
+ }
26
+
27
+ // eslint-disable-next-line class-methods-use-this
28
+ hasConnection(): boolean {
29
+ return false
30
+ }
31
+
22
32
  // eslint-disable-next-line class-methods-use-this
23
33
  stop(): void {
24
34
 
@@ -0,0 +1,80 @@
1
+ import { Multimap } from '@streamr/utils'
2
+ import { DhtAddress, createRandomDhtAddress, getRawFromDhtAddress } from '../../src/identifiers'
3
+ import { minBy, range, without } from 'lodash'
4
+ import { SortedContactList } from '../../src/dht/contact/SortedContactList'
5
+ import { getDistance } from '../../src/dht/PeerManager'
6
+
7
+ export const getTopologyPartitions = (topology: Multimap<DhtAddress, DhtAddress>): Set<DhtAddress>[] => {
8
+ let partitions: Set<DhtAddress>[] = []
9
+ for (const nodeId of topology.keys()) {
10
+ const neighbors = topology.get(nodeId)
11
+ const existingPartition = partitions.find((partition) => partition.has(nodeId))
12
+ if (existingPartition !== undefined) {
13
+ for (const neighbor of neighbors) {
14
+ if (!existingPartition.has(neighbor)) {
15
+ const otherPartition = partitions.find((partition) => partition.has(neighbor))
16
+ if (otherPartition !== undefined) {
17
+ for (const otherNode of otherPartition) {
18
+ existingPartition.add(otherNode)
19
+ }
20
+ partitions = without(partitions, otherPartition)
21
+ } else {
22
+ existingPartition.add(neighbor)
23
+ }
24
+ }
25
+ }
26
+ } else {
27
+ const partition = new Set([nodeId, ...neighbors])
28
+ partitions.push(partition)
29
+ }
30
+ }
31
+ return partitions
32
+ }
33
+
34
+ const getClosestNodes = (referenceId: DhtAddress, nodeIds: DhtAddress[], count: number, allowToContainReferenceId: boolean): DhtAddress[] => {
35
+ const list = new SortedContactList({
36
+ referenceId,
37
+ allowToContainReferenceId,
38
+ maxSize: count
39
+ })
40
+ list.addContacts(nodeIds.map((n) => ({ getNodeId: () => n })))
41
+ return list.getClosestContacts().map((c) => c.getNodeId())
42
+ }
43
+
44
+ /*
45
+ * There are no network splits, and each node has only neighbors which are globally closest
46
+ * to the node's ID.
47
+ */
48
+ export const createTestTopology = (nodeCount: number, minNeighorCount: number): Multimap<DhtAddress, DhtAddress> => {
49
+ const topology: Multimap<DhtAddress, DhtAddress> = new Multimap()
50
+ const nodeIds = range(nodeCount).map(() => createRandomDhtAddress())
51
+ for (const nodeId of nodeIds) {
52
+ const closestNodes = getClosestNodes(nodeId, nodeIds, minNeighorCount, false)
53
+ for (const closestNode of closestNodes) {
54
+ if (!topology.has(nodeId, closestNode)) {
55
+ topology.add(nodeId, closestNode)
56
+ }
57
+ if (!topology.has(closestNode, nodeId)) {
58
+ topology.add(closestNode, nodeId)
59
+ }
60
+ }
61
+ }
62
+ // eslint-disable-next-line no-constant-condition
63
+ while (true) {
64
+ const partitions = getTopologyPartitions(topology)
65
+ if (partitions.length === 1) {
66
+ break
67
+ } else {
68
+ const closestPairs = nodeIds.map((nodeId: DhtAddress) => {
69
+ const ownPartition = partitions.find((partition) => partition.has(nodeId))!
70
+ const otherNodes = without(nodeIds, ...[...ownPartition])
71
+ const closestNodedId = getClosestNodes(nodeId, otherNodes, 1, false)[0]
72
+ return [nodeId, closestNodedId]
73
+ })
74
+ const mergePair = minBy(closestPairs, (pair) => getDistance(getRawFromDhtAddress(pair[0]), getRawFromDhtAddress(pair[1])))!
75
+ topology.add(mergePair[0], mergePair[1])
76
+ topology.add(mergePair[1], mergePair[0])
77
+ }
78
+ }
79
+ return topology
80
+ }
@@ -1,53 +0,0 @@
1
- /* eslint-disable no-console */
2
-
3
- import KBucket from 'k-bucket'
4
- import { range } from 'lodash'
5
- import { DhtAddressRaw } from '../src/identifiers'
6
-
7
- const compareIds = (id1: DhtAddressRaw, id2: DhtAddressRaw) => {
8
- const sorted = [id1, id2].sort()
9
- return KBucket.distance(sorted[0], sorted[1])
10
- }
11
-
12
- const generateIDs = (count: number): DhtAddressRaw[] => {
13
- return range(count).map((i) => new Uint8Array([i, 1, 1]))
14
- }
15
-
16
- const count = 9
17
- const ids = generateIDs(count)
18
-
19
- const distances = ids.map((id1) => ids.map((id2) => {
20
- return {
21
- distance: compareIds(id1, id2),
22
- id: id2.toString()
23
- }
24
- }))
25
-
26
- const graph: any[] = []
27
- for (let i = 0; i < count; i++) {
28
- const sorted = distances[i].sort((a, b) => a.distance - b.distance)
29
- graph.push([sorted[1], sorted[2], sorted[3], sorted[4]])
30
- }
31
- const result = new Map<string, number>()
32
- ids.forEach((key) => {
33
- result.set(key.toString(), 0)
34
- })
35
-
36
- for (let i = 0; i < count; i++) {
37
- graph[i].forEach((val: any) => {
38
- result.set(val.id, result.get(val.id)! + 1)
39
- })
40
- }
41
-
42
- const bidirectional = ids.map((id, i) => {
43
- const stringId = id.toString()
44
- const allFound = graph[i].some((obj: any) => {
45
- const neighborId = obj.id
46
- const neighborIndex = parseInt(neighborId.split(',')[0])
47
- return graph[neighborIndex].some((obj: any) => obj.id === stringId)
48
- })
49
- return allFound
50
- })
51
-
52
- console.log(bidirectional)
53
- console.log(graph)