Skip to content

Commit 882d66b

Browse files
committed
wip: added test to check if nodes are properly added to the seed nodes when entering the network
This tests for if the Seed node contains the new nodes when they are created. It also checks if the new nodes discover each other after being created. There is a problem that needs to be fixed. With the RefreshBucket operations happening when syncing the node graph. It is extremely likely that a node will not be found when preforming a `findNode`. Currently, this WILL throw an error but we need to allow for the case where the node can't be found. So when a node can't be found the thing calling `findNode` should throw the error.
1 parent 08beafc commit 882d66b

3 files changed

Lines changed: 98 additions & 6 deletions

File tree

src/nodes/NodeConnectionManager.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -458,9 +458,12 @@ class NodeConnectionManager {
458458
});
459459
// TODO: This currently just does one iteration
460460
// If not found in this single iteration, we throw an exception
461-
if (address == null) {
462-
throw new nodesErrors.ErrorNodeGraphNodeIdNotFound();
463-
}
461+
// FIXME: This can and will not find nodes when refreshing a bucket.
462+
// We can't throw an error here, we need to handle it.
463+
// if (address == null) {
464+
// throw new nodesErrors.ErrorNodeGraphNodeIdNotFound();
465+
// }
466+
address = { host: '1.1.1.1' as Host, port: 55555 as Port };
464467
}
465468
// We ensure that we always return a NodeAddress (either by lookup, or
466469
// network search) - if we can't locate it from either, we throw an exception
@@ -633,6 +636,7 @@ class NodeConnectionManager {
633636
*/
634637
@ready(new nodesErrors.ErrorNodeConnectionManagerNotRunning())
635638
public async syncNodeGraph(block: boolean = true, timer?: Timer) {
639+
this.logger.info('Syncing nodeGraph');
636640
for (const seedNodeId of this.getSeedNodes()) {
637641
// Check if the connection is viable
638642
try {
@@ -646,6 +650,7 @@ class NodeConnectionManager {
646650
this.keyManager.getNodeId(),
647651
timer,
648652
);
653+
// FIXME: we need to ping a node before setting it
649654
for (const [nodeId, nodeData] of nodes) {
650655
if (!block) {
651656
this.queue.push(() =>

src/nodes/NodeManager.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,8 @@ class NodeManager {
4747
protected refreshBucketQueue: Set<NodeBucketIndex> = new Set();
4848
protected refreshBucketQueueRunning: boolean = false;
4949
protected refreshBucketQueueRunner: Promise<void>;
50-
protected refreshBucketQueuePlug_: PromiseType<void>;
51-
protected refreshBucketQueueDrained_: PromiseType<void>;
50+
protected refreshBucketQueuePlug_: PromiseType<void> = promise();
51+
protected refreshBucketQueueDrained_: PromiseType<void> = promise();
5252
protected refreshBucketQueueAbortController: AbortController;
5353

5454
constructor({

tests/nodes/NodeConnectionManager.seednodes.test.ts

Lines changed: 88 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import type { NodeId, SeedNodes } from '@/nodes/types';
1+
import type { NodeId, NodeIdEncoded, SeedNodes } from '@/nodes/types';
22
import type { Host, Port } from '@/network/types';
33
import type { Sigchain } from '@/sigchain';
44
import fs from 'fs';
@@ -123,6 +123,13 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => {
123123
});
124124

125125
beforeEach(async () => {
126+
// Clearing nodes from graphs
127+
for await (const [nodeId] of remoteNode1.nodeGraph.getNodes()) {
128+
await remoteNode1.nodeGraph.unsetNode(nodeId);
129+
}
130+
for await (const [nodeId] of remoteNode2.nodeGraph.getNodes()) {
131+
await remoteNode2.nodeGraph.unsetNode(nodeId);
132+
}
126133
dataDir = await fs.promises.mkdtemp(
127134
path.join(os.tmpdir(), 'polykey-test-'),
128135
);
@@ -417,4 +424,84 @@ describe(`${NodeConnectionManager.name} seed nodes test`, () => {
417424
await queue?.stop();
418425
}
419426
});
427+
test('should expand the network when nodes enter', async () => {
428+
// Using a single seed node we need to check that each entering node adds itself to the seed node.
429+
// Also need to check that the new nodes can be seen in the network.
430+
let node1: PolykeyAgent | undefined;
431+
let node2: PolykeyAgent | undefined;
432+
const seedNodes: SeedNodes = {};
433+
seedNodes[nodesUtils.encodeNodeId(remoteNodeId1)] = {
434+
host: remoteNode1.proxy.getProxyHost(),
435+
port: remoteNode1.proxy.getProxyPort(),
436+
};
437+
seedNodes[nodesUtils.encodeNodeId(remoteNodeId2)] = {
438+
host: remoteNode2.proxy.getProxyHost(),
439+
port: remoteNode2.proxy.getProxyPort(),
440+
};
441+
try {
442+
logger.setLevel(LogLevel.WARN);
443+
node1 = await PolykeyAgent.createPolykeyAgent({
444+
nodePath: path.join(dataDir, 'node1'),
445+
password: 'password',
446+
networkConfig: {
447+
proxyHost: localHost,
448+
agentHost: localHost,
449+
clientHost: localHost,
450+
forwardHost: localHost,
451+
},
452+
seedNodes,
453+
logger,
454+
});
455+
node2 = await PolykeyAgent.createPolykeyAgent({
456+
nodePath: path.join(dataDir, 'node2'),
457+
password: 'password',
458+
networkConfig: {
459+
proxyHost: localHost,
460+
agentHost: localHost,
461+
clientHost: localHost,
462+
forwardHost: localHost,
463+
},
464+
seedNodes,
465+
logger,
466+
});
467+
468+
await node1.queue.drained();
469+
await node1.nodeManager.refreshBucketQueueDrained();
470+
await node2.queue.drained();
471+
await node2.nodeManager.refreshBucketQueueDrained();
472+
473+
const getAllNodes = async (node: PolykeyAgent) => {
474+
const nodes: Array<NodeIdEncoded> = [];
475+
for await (const [nodeId] of node.nodeGraph.getNodes()) {
476+
nodes.push(nodesUtils.encodeNodeId(nodeId));
477+
}
478+
return nodes;
479+
};
480+
const rNode1Nodes = await getAllNodes(remoteNode1);
481+
const rNode2Nodes = await getAllNodes(remoteNode2);
482+
const node1Nodes = await getAllNodes(node1);
483+
const node2Nodes = await getAllNodes(node2);
484+
485+
const nodeIdR1 = nodesUtils.encodeNodeId(remoteNodeId1);
486+
const nodeIdR2 = nodesUtils.encodeNodeId(remoteNodeId2);
487+
const nodeId1 = nodesUtils.encodeNodeId(node1.keyManager.getNodeId());
488+
const nodeId2 = nodesUtils.encodeNodeId(node2.keyManager.getNodeId());
489+
expect(rNode1Nodes).toContain(nodeId1);
490+
expect(rNode1Nodes).toContain(nodeId2);
491+
expect(rNode2Nodes).toContain(nodeId1);
492+
expect(rNode2Nodes).toContain(nodeId2);
493+
expect(node1Nodes).toContain(nodeIdR1);
494+
expect(node1Nodes).toContain(nodeIdR2);
495+
expect(node1Nodes).toContain(nodeId2);
496+
expect(node2Nodes).toContain(nodeIdR1);
497+
expect(node2Nodes).toContain(nodeIdR2);
498+
expect(node2Nodes).toContain(nodeId1);
499+
} finally {
500+
logger.setLevel(LogLevel.WARN);
501+
await node1?.stop();
502+
await node1?.destroy();
503+
await node2?.stop();
504+
await node2?.destroy();
505+
}
506+
});
420507
});

0 commit comments

Comments
 (0)