@streamr/dht 0.0.1-tatum.5 → 0.0.1-tatum.6
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/ConnectionManager.d.ts +1 -0
- package/dist/src/connection/ConnectionManager.js +14 -2
- package/dist/src/connection/ConnectionManager.js.map +1 -1
- package/dist/src/dht/DhtNode.d.ts +1 -3
- package/dist/src/dht/DhtNode.js +12 -11
- package/dist/src/dht/DhtNode.js.map +1 -1
- package/dist/src/dht/DhtPeer.d.ts +2 -0
- package/dist/src/dht/DhtPeer.js +4 -0
- package/dist/src/dht/DhtPeer.js.map +1 -1
- package/dist/src/dht/contact/Contact.d.ts +1 -15
- package/dist/src/dht/contact/Contact.js +1 -9
- package/dist/src/dht/contact/Contact.js.map +1 -1
- package/dist/src/dht/contact/ContactList.d.ts +13 -2
- package/dist/src/dht/contact/ContactList.js +9 -1
- package/dist/src/dht/contact/ContactList.js.map +1 -1
- package/dist/src/dht/contact/RandomContactList.d.ts +3 -2
- package/dist/src/dht/contact/RandomContactList.js +4 -5
- package/dist/src/dht/contact/RandomContactList.js.map +1 -1
- package/dist/src/dht/contact/Remote.d.ts +1 -5
- package/dist/src/dht/contact/Remote.js +0 -5
- package/dist/src/dht/contact/Remote.js.map +1 -1
- package/dist/src/dht/contact/SortedContactList.d.ts +3 -2
- package/dist/src/dht/contact/SortedContactList.js +9 -10
- package/dist/src/dht/contact/SortedContactList.js.map +1 -1
- package/dist/src/dht/routing/RemoteRouter.js +3 -3
- package/dist/src/dht/routing/RemoteRouter.js.map +1 -1
- package/dist/src/dht/routing/RoutingSession.d.ts +0 -1
- package/dist/src/dht/routing/RoutingSession.js +15 -10
- package/dist/src/dht/routing/RoutingSession.js.map +1 -1
- package/dist/src/exports.d.ts +0 -1
- package/dist/src/exports.js +1 -3
- package/dist/src/exports.js.map +1 -1
- package/package.json +4 -4
- package/src/connection/ConnectionManager.ts +16 -3
- package/src/dht/DhtNode.ts +17 -16
- package/src/dht/DhtPeer.ts +5 -0
- package/src/dht/contact/Contact.ts +1 -18
- package/src/dht/contact/ContactList.ts +16 -2
- package/src/dht/contact/RandomContactList.ts +6 -7
- package/src/dht/contact/Remote.ts +1 -10
- package/src/dht/contact/SortedContactList.ts +12 -13
- package/src/dht/find/RecursiveFinder.ts +1 -1
- package/src/dht/routing/RemoteRouter.ts +3 -3
- package/src/dht/routing/RoutingSession.ts +29 -20
- package/src/exports.ts +0 -1
- package/test/benchmark/KademliaCorrectness.test.ts +2 -1
- package/test/end-to-end/Layer0-Layer1.test.ts +10 -10
- package/test/integration/DhtWithMockConnectionLatencies.test.ts +1 -1
- package/test/integration/DhtWithMockConnections.test.ts +1 -1
- package/test/integration/DhtWithRealConnectionLatencies.test.ts +1 -1
- package/test/unit/RandomContactList.test.ts +26 -75
- package/test/unit/SortedContactList.test.ts +62 -112
|
@@ -237,7 +237,7 @@ export class RecursiveFinder implements IRecursiveFinder {
|
|
|
237
237
|
|
|
238
238
|
private getClosestConnections(kademliaId: Uint8Array, limit: number): PeerDescriptor[] {
|
|
239
239
|
const connectedPeers = Array.from(this.connections.values())
|
|
240
|
-
const closestPeers = new SortedContactList(
|
|
240
|
+
const closestPeers = new SortedContactList<DhtPeer>(
|
|
241
241
|
PeerID.fromValue(kademliaId),
|
|
242
242
|
limit,
|
|
243
243
|
undefined,
|
|
@@ -40,7 +40,7 @@ export class RemoteRouter extends Remote<IRoutingServiceClient> {
|
|
|
40
40
|
} catch (err) {
|
|
41
41
|
const fromNode = params.previousPeer ?
|
|
42
42
|
peerIdFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
|
|
43
|
-
logger.trace(`Failed to send routeMessage from ${fromNode} to ${this.
|
|
43
|
+
logger.trace(`Failed to send routeMessage from ${fromNode} to ${keyFromPeerDescriptor(this.getPeerDescriptor())} with: ${err}`)
|
|
44
44
|
return false
|
|
45
45
|
}
|
|
46
46
|
return true
|
|
@@ -69,7 +69,7 @@ export class RemoteRouter extends Remote<IRoutingServiceClient> {
|
|
|
69
69
|
keyFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
|
|
70
70
|
|
|
71
71
|
logger.trace(
|
|
72
|
-
`Failed to send forwardMessage from ${fromNode} to ${this.
|
|
72
|
+
`Failed to send forwardMessage from ${fromNode} to ${keyFromPeerDescriptor(this.getPeerDescriptor())} with: ${err}`
|
|
73
73
|
)
|
|
74
74
|
return false
|
|
75
75
|
}
|
|
@@ -97,7 +97,7 @@ export class RemoteRouter extends Remote<IRoutingServiceClient> {
|
|
|
97
97
|
}
|
|
98
98
|
} catch (err) {
|
|
99
99
|
const fromNode = params.previousPeer ? keyFromPeerDescriptor(params.previousPeer) : keyFromPeerDescriptor(params.sourcePeer!)
|
|
100
|
-
logger.debug(`Failed to send recursiveFind message from ${fromNode} to ${this.
|
|
100
|
+
logger.debug(`Failed to send recursiveFind message from ${fromNode} to ${keyFromPeerDescriptor(this.getPeerDescriptor())} with: ${err}`)
|
|
101
101
|
return false
|
|
102
102
|
}
|
|
103
103
|
return true
|
|
@@ -10,11 +10,31 @@ import { RemoteRouter } from './RemoteRouter'
|
|
|
10
10
|
import { RoutingRpcCommunicator } from '../../transport/RoutingRpcCommunicator'
|
|
11
11
|
import { RoutingServiceClient } from '../../proto/packages/dht/protos/DhtRpc.client'
|
|
12
12
|
import { toProtoRpcClient } from '@streamr/proto-rpc'
|
|
13
|
+
import { Contact } from '../contact/Contact'
|
|
13
14
|
|
|
14
15
|
const logger = new Logger(module)
|
|
15
16
|
|
|
16
17
|
const MAX_FAILED_HOPS = 2
|
|
17
18
|
|
|
19
|
+
class RemoteContact extends Contact {
|
|
20
|
+
|
|
21
|
+
private router: RemoteRouter
|
|
22
|
+
|
|
23
|
+
constructor(peer: DhtPeer, ownPeerDescriptor: PeerDescriptor, rpcCommunicator: RoutingRpcCommunicator) {
|
|
24
|
+
super(peer.getPeerDescriptor())
|
|
25
|
+
this.router = new RemoteRouter(
|
|
26
|
+
ownPeerDescriptor,
|
|
27
|
+
peer.getPeerDescriptor(),
|
|
28
|
+
peer.getServiceId(),
|
|
29
|
+
toProtoRpcClient(new RoutingServiceClient(rpcCommunicator.getRpcClientTransport()))
|
|
30
|
+
)
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
getRouter(): RemoteRouter {
|
|
34
|
+
return this.router
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
18
38
|
export interface RoutingSessionEvents {
|
|
19
39
|
// This event is emitted when a peer responds with a success ack
|
|
20
40
|
// to routeMessage call
|
|
@@ -35,7 +55,7 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
35
55
|
public readonly sessionId = v4()
|
|
36
56
|
private readonly rpcCommunicator: RoutingRpcCommunicator
|
|
37
57
|
private ongoingRequests: Set<PeerIDKey> = new Set()
|
|
38
|
-
private contactList: SortedContactList<
|
|
58
|
+
private contactList: SortedContactList<RemoteContact>
|
|
39
59
|
private readonly ownPeerDescriptor: PeerDescriptor
|
|
40
60
|
private readonly messageToRoute: RouteMessageWrapper
|
|
41
61
|
private connections: Map<PeerIDKey, DhtPeer>
|
|
@@ -117,51 +137,40 @@ export class RoutingSession extends EventEmitter<RoutingSessionEvents> {
|
|
|
117
137
|
}
|
|
118
138
|
}
|
|
119
139
|
|
|
120
|
-
private sendRouteMessageRequest = async (contact:
|
|
140
|
+
private sendRouteMessageRequest = async (contact: RemoteContact): Promise<boolean> => {
|
|
121
141
|
if (this.stopped) {
|
|
122
142
|
return false
|
|
123
143
|
}
|
|
144
|
+
const router = contact.getRouter()
|
|
124
145
|
if (this.mode === RoutingMode.FORWARD) {
|
|
125
|
-
return
|
|
146
|
+
return router.forwardMessage({
|
|
126
147
|
...this.messageToRoute,
|
|
127
148
|
previousPeer: this.ownPeerDescriptor
|
|
128
149
|
})
|
|
129
150
|
} else if (this.mode === RoutingMode.RECURSIVE_FIND) {
|
|
130
|
-
return
|
|
151
|
+
return router.findRecursively({
|
|
131
152
|
...this.messageToRoute,
|
|
132
153
|
previousPeer: this.ownPeerDescriptor
|
|
133
154
|
})
|
|
134
155
|
} else {
|
|
135
|
-
return
|
|
156
|
+
return router.routeMessage({
|
|
136
157
|
...this.messageToRoute,
|
|
137
158
|
previousPeer: this.ownPeerDescriptor
|
|
138
159
|
})
|
|
139
160
|
}
|
|
140
161
|
}
|
|
141
162
|
|
|
142
|
-
private findMoreContacts = ():
|
|
163
|
+
private findMoreContacts = (): RemoteContact[] => {
|
|
143
164
|
logger.trace('findMoreContacts() sessionId: ' + this.sessionId)
|
|
144
165
|
// the contents of the connections might have changed between the rounds
|
|
145
166
|
// addContacts() will only add new contacts that were not there yet
|
|
146
167
|
const contacts = Array.from(this.connections.values())
|
|
147
|
-
.map((
|
|
148
|
-
return new RemoteRouter(
|
|
149
|
-
this.ownPeerDescriptor,
|
|
150
|
-
contact.getPeerDescriptor(),
|
|
151
|
-
contact.getServiceId(),
|
|
152
|
-
toProtoRpcClient(new RoutingServiceClient(this.rpcCommunicator.getRpcClientTransport()))
|
|
153
|
-
)
|
|
154
|
-
})
|
|
168
|
+
.map((peer) => new RemoteContact(peer, this.ownPeerDescriptor, this.rpcCommunicator))
|
|
155
169
|
this.contactList.addContacts(contacts)
|
|
156
170
|
return this.contactList.getUncontactedContacts(this.parallelism)
|
|
157
171
|
}
|
|
158
172
|
|
|
159
|
-
|
|
160
|
-
const contacts = this.contactList.getClosestContacts(limit)
|
|
161
|
-
return contacts.map((contact) => contact.getPeerDescriptor())
|
|
162
|
-
}
|
|
163
|
-
|
|
164
|
-
private sendMoreRequests = (uncontacted: RemoteRouter[]) => {
|
|
173
|
+
private sendMoreRequests = (uncontacted: RemoteContact[]) => {
|
|
165
174
|
logger.trace('sendMoreRequests() sessionId: ' + this.sessionId)
|
|
166
175
|
if (this.stopped) {
|
|
167
176
|
return
|
package/src/exports.ts
CHANGED
|
@@ -7,7 +7,6 @@ export { PeerDescriptor, Message, NodeType, DataEntry } from './proto/packages/d
|
|
|
7
7
|
export { ITransport } from './transport/ITransport'
|
|
8
8
|
export { ConnectionManager, ConnectionLocker, PortRange, TlsCertificate } from './connection/ConnectionManager'
|
|
9
9
|
export { PeerID, PeerIDKey } from './helpers/PeerID'
|
|
10
|
-
export { DhtPeer } from './dht/DhtPeer'
|
|
11
10
|
export { UUID } from './helpers/UUID'
|
|
12
11
|
export { DhtRpcOptions } from './rpc-protocol/DhtRpcOptions'
|
|
13
12
|
export { protoClasses } from './helpers/protoClasses'
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
/* eslint-disable no-console */
|
|
2
2
|
import { Simulator } from '../../src/connection/Simulator/Simulator'
|
|
3
3
|
import { DhtNode } from '../../src/dht/DhtNode'
|
|
4
|
+
import { PeerID } from '../../src/exports'
|
|
4
5
|
import { NodeType, PeerDescriptor } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
5
6
|
import { createMockConnectionDhtNode } from '../utils/utils'
|
|
6
7
|
import { execSync } from 'child_process'
|
|
@@ -70,7 +71,7 @@ describe('Kademlia correctness', () => {
|
|
|
70
71
|
groundTruthString += groundTruth[i + ''][j].name + ','
|
|
71
72
|
}
|
|
72
73
|
|
|
73
|
-
const kademliaNeighbors = nodes[i].
|
|
74
|
+
const kademliaNeighbors = nodes[i].getClosestContacts().map((p) => PeerID.fromValue(p.kademliaId))
|
|
74
75
|
|
|
75
76
|
let kadString = 'kademliaNeighbors: '
|
|
76
77
|
kademliaNeighbors.forEach((neighbor) => {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { NodeType, PeerDescriptor } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
2
2
|
import { DhtNode } from '../../src/dht/DhtNode'
|
|
3
|
-
import {
|
|
3
|
+
import { isSamePeerDescriptor } from '../../src/helpers/peerIdFromPeerDescriptor'
|
|
4
4
|
|
|
5
5
|
describe('Layer0-Layer1', () => {
|
|
6
6
|
const epPeerDescriptor: PeerDescriptor = {
|
|
@@ -76,14 +76,14 @@ describe('Layer0-Layer1', () => {
|
|
|
76
76
|
stream2Node1.joinDht([epPeerDescriptor]),
|
|
77
77
|
stream2Node2.joinDht([epPeerDescriptor])
|
|
78
78
|
])
|
|
79
|
-
expect(stream1Node1.
|
|
80
|
-
expect(stream1Node2.
|
|
81
|
-
expect(stream2Node1.
|
|
82
|
-
expect(stream2Node2.
|
|
83
|
-
|
|
84
|
-
expect(stream1Node1.
|
|
85
|
-
expect(stream1Node2.
|
|
86
|
-
expect(stream2Node1.
|
|
87
|
-
expect(stream2Node2.
|
|
79
|
+
expect(stream1Node1.getClosestContacts()).toHaveLength(1)
|
|
80
|
+
expect(stream1Node2.getClosestContacts()).toHaveLength(1)
|
|
81
|
+
expect(stream2Node1.getClosestContacts()).toHaveLength(1)
|
|
82
|
+
expect(stream2Node2.getClosestContacts()).toHaveLength(1)
|
|
83
|
+
|
|
84
|
+
expect(isSamePeerDescriptor(stream1Node1.getClosestContacts()[0], node1.getPeerDescriptor())).toBe(true)
|
|
85
|
+
expect(isSamePeerDescriptor(stream1Node2.getClosestContacts()[0], epPeerDescriptor)).toBe(true)
|
|
86
|
+
expect(isSamePeerDescriptor(stream2Node1.getClosestContacts()[0], node2.getPeerDescriptor())).toBe(true)
|
|
87
|
+
expect(isSamePeerDescriptor(stream2Node2.getClosestContacts()[0], epPeerDescriptor)).toBe(true)
|
|
88
88
|
})
|
|
89
89
|
})
|
|
@@ -39,7 +39,7 @@ describe('Mock connection Dht joining with latencies', () => {
|
|
|
39
39
|
await Promise.all(nodes.map((node) => node.joinDht([entrypointDescriptor])))
|
|
40
40
|
nodes.forEach((node) => {
|
|
41
41
|
expect(node.getBucketSize()).toBeGreaterThanOrEqual(node.getK() - 2)
|
|
42
|
-
expect(node.
|
|
42
|
+
expect(node.getClosestContacts().length).toBeGreaterThanOrEqual(node.getK() - 2)
|
|
43
43
|
})
|
|
44
44
|
expect(entryPoint.getBucketSize()).toBeGreaterThanOrEqual(entryPoint.getK() - 2)
|
|
45
45
|
}, 60 * 1000)
|
|
@@ -39,7 +39,7 @@ describe('Mock IConnection DHT Joining', () => {
|
|
|
39
39
|
await Promise.all(nodes.map((node) => node.joinDht([entrypointDescriptor])))
|
|
40
40
|
nodes.forEach((node) => {
|
|
41
41
|
expect(node.getBucketSize()).toBeGreaterThanOrEqual(node.getK() - 2)
|
|
42
|
-
expect(node.
|
|
42
|
+
expect(node.getClosestContacts().length).toBeGreaterThanOrEqual(node.getK() - 2)
|
|
43
43
|
})
|
|
44
44
|
expect(entryPoint.getBucketSize()).toBeGreaterThanOrEqual(entryPoint.getK() - 2)
|
|
45
45
|
}, 60000)
|
|
@@ -40,7 +40,7 @@ describe('Mock connection Dht joining with real latencies', () => {
|
|
|
40
40
|
await Promise.all(nodes.map((node) => node.joinDht([entrypointDescriptor])))
|
|
41
41
|
nodes.forEach((node) => {
|
|
42
42
|
expect(node.getBucketSize()).toBeGreaterThanOrEqual(node.getK() - 3)
|
|
43
|
-
expect(node.
|
|
43
|
+
expect(node.getClosestContacts().length).toBeGreaterThanOrEqual(node.getK() - 3)
|
|
44
44
|
})
|
|
45
45
|
expect(entryPoint.getBucketSize()).toBeGreaterThanOrEqual(entryPoint.getK())
|
|
46
46
|
}, 60 * 1000)
|
|
@@ -1,92 +1,43 @@
|
|
|
1
1
|
import { RandomContactList } from '../../src/dht/contact/RandomContactList'
|
|
2
|
-
import
|
|
3
|
-
import { PeerID } from '../../src/helpers/PeerID'
|
|
4
|
-
import { toProtoRpcClient } from '@streamr/proto-rpc'
|
|
5
|
-
import { IDhtRpcServiceClient } from '../../src/proto/packages/dht/protos/DhtRpc.client'
|
|
6
|
-
import { LeaveNotice, NodeType, PeerDescriptor } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
7
|
-
import type { FindDataRequest, FindDataResponse, PingResponse } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
8
|
-
import type { PingRequest } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
9
|
-
import type { ClosestPeersResponse } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
10
|
-
import type { ClosestPeersRequest } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
11
|
-
import { UnaryCall } from '@protobuf-ts/runtime-rpc'
|
|
12
|
-
import type { RpcOptions } from '@protobuf-ts/runtime-rpc'
|
|
13
|
-
import { DhtPeer } from '../../src/dht/DhtPeer'
|
|
14
|
-
import { IMessageType } from '@protobuf-ts/runtime'
|
|
15
|
-
import { Empty } from '../../src/proto/google/protobuf/empty'
|
|
2
|
+
import { PeerID } from '../../src/exports'
|
|
16
3
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
methods: MethodInfo<any, any> [] = [
|
|
20
|
-
{ name: 'getClosestPeers', O: {} as IMessageType<ClosestPeersResponse> } as MethodInfo<any, any>,
|
|
21
|
-
{ name: 'ping', O: {} as IMessageType<PingResponse> } as MethodInfo<any, any>,
|
|
22
|
-
{ name: 'findData', O: {} as IMessageType<FindDataRequest> } as MethodInfo<any, any>,
|
|
23
|
-
{ name: 'leaveNotice', O: {} as IMessageType<Empty> } as MethodInfo<any, any>
|
|
24
|
-
]
|
|
25
|
-
options = {}
|
|
26
|
-
|
|
27
|
-
// eslint-disable-next-line class-methods-use-this
|
|
28
|
-
getClosestPeers(_input: ClosestPeersRequest, _options?: RpcOptions): UnaryCall<ClosestPeersRequest, ClosestPeersResponse> {
|
|
29
|
-
return {} as UnaryCall<ClosestPeersRequest, ClosestPeersResponse>
|
|
30
|
-
}
|
|
31
|
-
|
|
32
|
-
// eslint-disable-next-line class-methods-use-this
|
|
33
|
-
ping(_input: PingRequest, _options?: RpcOptions): UnaryCall <PingRequest, PingResponse> {
|
|
34
|
-
return {} as UnaryCall<PingRequest, PingResponse>
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
// eslint-disable-next-line class-methods-use-this
|
|
38
|
-
findData(_input: FindDataRequest, _options?: RpcOptions): UnaryCall<FindDataRequest, FindDataResponse> {
|
|
39
|
-
return {} as UnaryCall<FindDataRequest, FindDataResponse>
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
// eslint-disable-next-line class-methods-use-this
|
|
43
|
-
leaveNotice(_input: LeaveNotice, _options?: RpcOptions): UnaryCall<LeaveNotice, Empty> {
|
|
44
|
-
return {} as UnaryCall<LeaveNotice, Empty>
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
const getId = (descriptor: PeerDescriptor): PeerID => {
|
|
49
|
-
return PeerID.fromValue(descriptor.kademliaId)
|
|
4
|
+
const createItem = (kademliaId: Uint8Array): { getPeerId: () => PeerID } => {
|
|
5
|
+
return { getPeerId: () => PeerID.fromValue(kademliaId) }
|
|
50
6
|
}
|
|
51
7
|
|
|
52
8
|
describe('RandomContactList', () => {
|
|
53
|
-
const
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
const
|
|
57
|
-
const
|
|
58
|
-
const descriptor4: PeerDescriptor = { kademliaId: new Uint8Array([0, 0, 0, 4]), type: NodeType.NODEJS }
|
|
59
|
-
const peer1 = new DhtPeer(descriptor0, descriptor1, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
60
|
-
const peer2 = new DhtPeer(descriptor0, descriptor2, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
61
|
-
const peer3 = new DhtPeer(descriptor0, descriptor3, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
62
|
-
const peer4 = new DhtPeer(descriptor0, descriptor4, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
9
|
+
const item0 = createItem(new Uint8Array([0, 0, 0, 0]))
|
|
10
|
+
const item1 = createItem(new Uint8Array([0, 0, 0, 1]))
|
|
11
|
+
const item2 = createItem(new Uint8Array([0, 0, 0, 2]))
|
|
12
|
+
const item3 = createItem(new Uint8Array([0, 0, 0, 3]))
|
|
13
|
+
const item4 = createItem(new Uint8Array([0, 0, 0, 4]))
|
|
63
14
|
|
|
64
15
|
it('adds contacts correctly', () => {
|
|
65
|
-
const list = new RandomContactList(
|
|
66
|
-
list.addContact(
|
|
67
|
-
list.addContact(
|
|
68
|
-
list.addContact(
|
|
69
|
-
list.addContact(
|
|
70
|
-
list.addContact(
|
|
71
|
-
list.addContact(
|
|
16
|
+
const list = new RandomContactList(item0.getPeerId(), 5, 1)
|
|
17
|
+
list.addContact(item1)
|
|
18
|
+
list.addContact(item2)
|
|
19
|
+
list.addContact(item3)
|
|
20
|
+
list.addContact(item3)
|
|
21
|
+
list.addContact(item4)
|
|
22
|
+
list.addContact(item4)
|
|
72
23
|
expect(list.getSize()).toEqual(4)
|
|
73
24
|
expect(list.getContacts()).toEqual(
|
|
74
|
-
[
|
|
25
|
+
[item1, item2, item3, item4]
|
|
75
26
|
)
|
|
76
27
|
})
|
|
77
28
|
|
|
78
29
|
it('removes contacts correctly', () => {
|
|
79
|
-
const list = new RandomContactList(
|
|
80
|
-
list.addContact(
|
|
81
|
-
list.addContact(
|
|
82
|
-
list.addContact(
|
|
83
|
-
list.addContact(
|
|
84
|
-
list.removeContact(
|
|
85
|
-
expect(list.getContact(
|
|
86
|
-
expect(list.getContact(
|
|
87
|
-
expect(list.getContact(
|
|
30
|
+
const list = new RandomContactList(item0.getPeerId(), 5, 1)
|
|
31
|
+
list.addContact(item1)
|
|
32
|
+
list.addContact(item2)
|
|
33
|
+
list.addContact(item3)
|
|
34
|
+
list.addContact(item4)
|
|
35
|
+
list.removeContact(item2.getPeerId())
|
|
36
|
+
expect(list.getContact(item1.getPeerId())).toBeTruthy()
|
|
37
|
+
expect(list.getContact(item3.getPeerId())).toBeTruthy()
|
|
38
|
+
expect(list.getContact(item4.getPeerId())).toBeTruthy()
|
|
88
39
|
expect(list.getContacts()).toEqual(
|
|
89
|
-
[
|
|
40
|
+
[item1, item3, item4]
|
|
90
41
|
)
|
|
91
42
|
expect(list.getSize()).toEqual(3)
|
|
92
43
|
})
|
|
@@ -1,153 +1,103 @@
|
|
|
1
1
|
import { SortedContactList } from '../../src/dht/contact/SortedContactList'
|
|
2
|
-
import type { ServiceInfo, MethodInfo } from '@protobuf-ts/runtime-rpc'
|
|
3
2
|
import { PeerID } from '../../src/helpers/PeerID'
|
|
4
|
-
import { toProtoRpcClient } from '@streamr/proto-rpc'
|
|
5
|
-
import { IDhtRpcServiceClient } from '../../src/proto/packages/dht/protos/DhtRpc.client'
|
|
6
|
-
import { LeaveNotice, NodeType, PeerDescriptor, RouteMessageAck } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
7
|
-
import type { FindDataRequest, FindDataResponse, PingResponse } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
8
|
-
import type { PingRequest } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
9
|
-
import type { ClosestPeersResponse } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
10
|
-
import type { ClosestPeersRequest } from '../../src/proto/packages/dht/protos/DhtRpc'
|
|
11
|
-
import { UnaryCall } from '@protobuf-ts/runtime-rpc'
|
|
12
|
-
import type { RpcOptions } from '@protobuf-ts/runtime-rpc'
|
|
13
|
-
import { DhtPeer } from '../../src/dht/DhtPeer'
|
|
14
|
-
import { IMessageType } from '@protobuf-ts/runtime'
|
|
15
|
-
import { Empty } from '../../src/proto/google/protobuf/empty'
|
|
16
3
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
typeName = 'MockRpcClient'
|
|
20
|
-
methods: MethodInfo<any, any> [] = [
|
|
21
|
-
{ name: 'getClosestPeers', O: {} as IMessageType<ClosestPeersResponse> } as MethodInfo<any, any>,
|
|
22
|
-
{ name: 'ping', O: {} as IMessageType<PingResponse> } as MethodInfo<any, any>,
|
|
23
|
-
{ name: 'findData', O: {} as IMessageType<RouteMessageAck> } as MethodInfo<any, any>,
|
|
24
|
-
{ name: 'leaveNotice', O: {} as IMessageType<Empty> } as MethodInfo<any, any>
|
|
25
|
-
]
|
|
26
|
-
options = {}
|
|
27
|
-
getClosestPeers(_input: ClosestPeersRequest, _options?: RpcOptions): UnaryCall<ClosestPeersRequest, ClosestPeersResponse> {
|
|
28
|
-
return {} as UnaryCall<ClosestPeersRequest, ClosestPeersResponse>
|
|
29
|
-
}
|
|
30
|
-
ping(_input: PingRequest, _options?: RpcOptions): UnaryCall <PingRequest, PingResponse> {
|
|
31
|
-
return {} as UnaryCall<PingRequest, PingResponse>
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// eslint-disable-next-line class-methods-use-this
|
|
35
|
-
findData(_input: FindDataRequest, _options?: RpcOptions): UnaryCall<FindDataRequest, FindDataResponse> {
|
|
36
|
-
return {} as UnaryCall<FindDataRequest, FindDataResponse>
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
leaveNotice(_input: LeaveNotice, _options?: RpcOptions): UnaryCall<LeaveNotice, Empty> {
|
|
40
|
-
return {} as UnaryCall<LeaveNotice, Empty>
|
|
41
|
-
}
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
const getId = (descriptor: PeerDescriptor): PeerID => {
|
|
45
|
-
return PeerID.fromValue(descriptor.kademliaId)
|
|
4
|
+
const createItem = (kademliaId: Uint8Array): { getPeerId: () => PeerID } => {
|
|
5
|
+
return { getPeerId: () => PeerID.fromValue(kademliaId) }
|
|
46
6
|
}
|
|
47
7
|
|
|
48
8
|
describe('SortedContactList', () => {
|
|
49
|
-
const
|
|
50
|
-
const
|
|
51
|
-
const
|
|
52
|
-
const
|
|
53
|
-
const
|
|
54
|
-
const descriptor4: PeerDescriptor = { kademliaId: new Uint8Array([0, 0, 0, 4]), type: NodeType.NODEJS }
|
|
55
|
-
const peer1 = new DhtPeer(descriptor0, descriptor1, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
56
|
-
const peer2 = new DhtPeer(descriptor0, descriptor2, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
57
|
-
const peer3 = new DhtPeer(descriptor0, descriptor3, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
58
|
-
const peer4 = new DhtPeer(descriptor0, descriptor4, toProtoRpcClient(new MockRpcClient()), serviceId)
|
|
9
|
+
const item0 = createItem(new Uint8Array([0, 0, 0, 0]))
|
|
10
|
+
const item1 = createItem(new Uint8Array([0, 0, 0, 1]))
|
|
11
|
+
const item2 = createItem(new Uint8Array([0, 0, 0, 2]))
|
|
12
|
+
const item3 = createItem(new Uint8Array([0, 0, 0, 3]))
|
|
13
|
+
const item4 = createItem(new Uint8Array([0, 0, 0, 4]))
|
|
59
14
|
|
|
60
15
|
it('compares Ids correctly', async () => {
|
|
61
|
-
const list = new SortedContactList(
|
|
62
|
-
expect(list.compareIds(
|
|
63
|
-
expect(list.compareIds(
|
|
64
|
-
expect(list.compareIds(
|
|
65
|
-
expect(list.compareIds(
|
|
66
|
-
expect(list.compareIds(
|
|
67
|
-
expect(list.compareIds(
|
|
68
|
-
expect(list.compareIds(
|
|
69
|
-
expect(list.compareIds(
|
|
16
|
+
const list = new SortedContactList(item0.getPeerId(), 10)
|
|
17
|
+
expect(list.compareIds(item0.getPeerId(), item0.getPeerId())).toBe(0)
|
|
18
|
+
expect(list.compareIds(item1.getPeerId(), item1.getPeerId())).toBe(0)
|
|
19
|
+
expect(list.compareIds(item0.getPeerId(), item1.getPeerId())).toBe(-1)
|
|
20
|
+
expect(list.compareIds(item0.getPeerId(), item2.getPeerId())).toBe(-2)
|
|
21
|
+
expect(list.compareIds(item1.getPeerId(), item0.getPeerId())).toBe(1)
|
|
22
|
+
expect(list.compareIds(item2.getPeerId(), item0.getPeerId())).toBe(2)
|
|
23
|
+
expect(list.compareIds(item2.getPeerId(), item3.getPeerId())).toBe(-1)
|
|
24
|
+
expect(list.compareIds(item1.getPeerId(), item4.getPeerId())).toBe(-3)
|
|
70
25
|
})
|
|
71
26
|
|
|
72
27
|
it('orders itself correctly', async () => {
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
list.addContact(
|
|
77
|
-
list.addContact(peer2)
|
|
78
|
-
list.addContact(peer1)
|
|
79
|
-
|
|
28
|
+
const list = new SortedContactList(item0.getPeerId(), 10)
|
|
29
|
+
list.addContact(item3)
|
|
30
|
+
list.addContact(item2)
|
|
31
|
+
list.addContact(item1)
|
|
80
32
|
const contacts = list.getUncontactedContacts(3)
|
|
81
33
|
expect(contacts.length).toEqual(3)
|
|
82
|
-
expect(contacts[0]).toEqual(
|
|
83
|
-
expect(contacts[1]).toEqual(
|
|
84
|
-
expect(contacts[2]).toEqual(
|
|
34
|
+
expect(contacts[0]).toEqual(item1)
|
|
35
|
+
expect(contacts[1]).toEqual(item2)
|
|
36
|
+
expect(contacts[2]).toEqual(item3)
|
|
85
37
|
})
|
|
86
38
|
|
|
87
39
|
it('handles contacted nodes correctly', async () => {
|
|
88
|
-
const list = new SortedContactList(
|
|
89
|
-
|
|
90
|
-
list.addContact(
|
|
91
|
-
list.addContact(
|
|
92
|
-
list.
|
|
93
|
-
|
|
94
|
-
list.setContacted(getId(descriptor2))
|
|
40
|
+
const list = new SortedContactList(item0.getPeerId(), 10)
|
|
41
|
+
list.addContact(item3)
|
|
42
|
+
list.addContact(item2)
|
|
43
|
+
list.addContact(item1)
|
|
44
|
+
list.setContacted(item2.getPeerId())
|
|
95
45
|
const contacts = list.getUncontactedContacts(3)
|
|
96
46
|
expect(contacts.length).toEqual(2)
|
|
97
|
-
expect(contacts[0]).toEqual(
|
|
98
|
-
expect(contacts[1]).toEqual(
|
|
47
|
+
expect(contacts[0]).toEqual(item1)
|
|
48
|
+
expect(contacts[1]).toEqual(item3)
|
|
99
49
|
})
|
|
100
50
|
|
|
101
51
|
it('cannot exceed maxSize', async () => {
|
|
102
|
-
const list = new SortedContactList(
|
|
52
|
+
const list = new SortedContactList(item0.getPeerId(), 3)
|
|
103
53
|
const onContactRemoved = jest.fn()
|
|
104
54
|
list.on('contactRemoved', onContactRemoved)
|
|
105
|
-
list.addContact(
|
|
106
|
-
list.addContact(
|
|
107
|
-
list.addContact(
|
|
108
|
-
list.addContact(
|
|
55
|
+
list.addContact(item1)
|
|
56
|
+
list.addContact(item4)
|
|
57
|
+
list.addContact(item3)
|
|
58
|
+
list.addContact(item2)
|
|
109
59
|
expect(list.getSize()).toEqual(3)
|
|
110
|
-
expect(onContactRemoved).toBeCalledWith(
|
|
111
|
-
expect(list.getContact(
|
|
60
|
+
expect(onContactRemoved).toBeCalledWith(item4, [item1, item2, item3])
|
|
61
|
+
expect(list.getContact(item4.getPeerId())).toBeFalsy()
|
|
112
62
|
})
|
|
113
63
|
|
|
114
64
|
it('removing contacts', async () => {
|
|
115
|
-
const list = new SortedContactList(
|
|
65
|
+
const list = new SortedContactList(item0.getPeerId(), 8)
|
|
116
66
|
const onContactRemoved = jest.fn()
|
|
117
67
|
list.on('contactRemoved', onContactRemoved)
|
|
118
|
-
list.addContact(
|
|
119
|
-
list.addContact(
|
|
120
|
-
list.addContact(
|
|
121
|
-
list.addContact(
|
|
122
|
-
list.removeContact(
|
|
68
|
+
list.addContact(item4)
|
|
69
|
+
list.addContact(item3)
|
|
70
|
+
list.addContact(item2)
|
|
71
|
+
list.addContact(item1)
|
|
72
|
+
list.removeContact(item2.getPeerId())
|
|
123
73
|
expect(list.getSize()).toEqual(3)
|
|
124
|
-
expect(list.getContact(
|
|
74
|
+
expect(list.getContact(item2.getPeerId())).toBeFalsy()
|
|
125
75
|
expect(list.getContactIds()).toEqual(list.getContactIds().sort(list.compareIds))
|
|
126
|
-
expect(list.getAllContacts()).toEqual([
|
|
127
|
-
expect(onContactRemoved).toBeCalledWith(
|
|
76
|
+
expect(list.getAllContacts()).toEqual([item1, item3, item4])
|
|
77
|
+
expect(onContactRemoved).toBeCalledWith(item2, [item1, item3, item4])
|
|
128
78
|
const ret = list.removeContact(PeerID.fromValue(Buffer.from([0, 0, 0, 6])))
|
|
129
79
|
expect(ret).toEqual(false)
|
|
130
80
|
})
|
|
131
81
|
|
|
132
82
|
it('get closes contacts', () => {
|
|
133
|
-
const list = new SortedContactList(
|
|
134
|
-
list.addContact(
|
|
135
|
-
list.addContact(
|
|
136
|
-
list.addContact(
|
|
137
|
-
list.addContact(
|
|
138
|
-
expect(list.getClosestContacts(2)).toEqual([
|
|
139
|
-
expect(list.getClosestContacts()).toEqual([
|
|
83
|
+
const list = new SortedContactList(item0.getPeerId(), 8)
|
|
84
|
+
list.addContact(item1)
|
|
85
|
+
list.addContact(item3)
|
|
86
|
+
list.addContact(item4)
|
|
87
|
+
list.addContact(item2)
|
|
88
|
+
expect(list.getClosestContacts(2)).toEqual([item1, item2])
|
|
89
|
+
expect(list.getClosestContacts()).toEqual([item1, item2, item3, item4])
|
|
140
90
|
})
|
|
141
91
|
|
|
142
92
|
it('get active contacts', () => {
|
|
143
|
-
const list = new SortedContactList(
|
|
144
|
-
list.addContact(
|
|
145
|
-
list.addContact(
|
|
146
|
-
list.addContact(
|
|
147
|
-
list.addContact(
|
|
148
|
-
list.setActive(
|
|
149
|
-
list.setActive(
|
|
150
|
-
list.setActive(
|
|
151
|
-
expect(list.getActiveContacts()).toEqual([
|
|
93
|
+
const list = new SortedContactList(item0.getPeerId(), 8)
|
|
94
|
+
list.addContact(item1)
|
|
95
|
+
list.addContact(item3)
|
|
96
|
+
list.addContact(item4)
|
|
97
|
+
list.addContact(item2)
|
|
98
|
+
list.setActive(item2.getPeerId())
|
|
99
|
+
list.setActive(item3.getPeerId())
|
|
100
|
+
list.setActive(item4.getPeerId())
|
|
101
|
+
expect(list.getActiveContacts()).toEqual([item2, item3, item4])
|
|
152
102
|
})
|
|
153
103
|
})
|