Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Preparing for Testnet Deployment #378

Merged
merged 39 commits into from
Jun 14, 2022
Merged
Changes from 1 commit
Commits
Show all changes
39 commits
Select commit Hold shift + click to select a range
8ff9207
feat: added `nodesGetAll` bin command and service handler
joshuakarp Feb 18, 2022
3c78427
fix: general fixes
CMCDragonkai Feb 21, 2022
c2b77b4
feat: added `NodeGraph.getClosestNodes()`
tegefaulkes Mar 15, 2022
6518e58
fix: `NodeManager.setNode` Properly handles adding new node when buck…
tegefaulkes Mar 17, 2022
8e77768
test: fixed `nodeGraph` `get all buckets` test
tegefaulkes Mar 23, 2022
685538f
feat: added `connectionEstablishedCallback` to `Proxy`
tegefaulkes Mar 24, 2022
e18a748
feat: `Proxy` trigger adding nodes to `Nodegraph`
tegefaulkes Mar 24, 2022
22c4974
feat: added optional timeout timers to `NodeConnectionManager` methods
tegefaulkes Mar 25, 2022
44434eb
refactor: updated implementation of `nodePing`
tegefaulkes Mar 25, 2022
b62c664
feat: `NodeManager.setNode` authenticates the added node
tegefaulkes Mar 28, 2022
00eefec
syntax: general linting and fixes from api changes
tegefaulkes Mar 29, 2022
062f4e3
fix: squash into ping node changes.
tegefaulkes Mar 31, 2022
45731ed
fix: setNode now does not ping the new node
tegefaulkes Mar 31, 2022
f8b3320
feat: setNode concurrently pings multiple nodes
tegefaulkes Mar 31, 2022
faf712d
feat: nodeManager is now startStop
tegefaulkes Mar 31, 2022
55e7dd7
feat: async queueing for setting nodes
tegefaulkes Mar 31, 2022
9ed6e2b
feat: establishing a `NodeConnection` adds the node to the nodeGraph
tegefaulkes Apr 7, 2022
b4fbc0b
feat: implemented `NodeManager.refreshBucket()`
tegefaulkes Apr 8, 2022
077195f
feat: implemented no activity timers and queuing for `refreshBucket`
tegefaulkes Apr 11, 2022
2b8d971
feat: refreshing buckets when entering network
tegefaulkes Apr 11, 2022
d7f2419
feat: abort controller support for `NodeManager.refreshBucket`
tegefaulkes Apr 14, 2022
b9717e1
fix: `setNode` no longer adds node twice when `force` is true
emmacasolin Apr 19, 2022
93f53c8
feat: generic `SetNodeQueue` class for queuing `setNode` operations
emmacasolin Apr 21, 2022
217c449
fix: `syncNodeGraph` during agent startup is now non-blocking
emmacasolin Apr 21, 2022
6fc465b
refactor: renamed `SetNodeQueue` to `Queue`
emmacasolin Apr 21, 2022
4ed0870
tests: general fixes for failing tests
tegefaulkes Apr 27, 2022
8f4398f
syntax: added `@typescript-eslint/await-thenable` linting rule
tegefaulkes Apr 27, 2022
f444f62
fix: updated `@types/node-forge` version and fixed `keysUtils.getRand…
tegefaulkes Apr 28, 2022
9d28625
tests: added test to check if nodes are properly added to the seed no…
tegefaulkes Apr 28, 2022
2a5f2ff
tests: Added agent service tests for `nodesChainDataGet`, `nodesClose…
tegefaulkes Apr 29, 2022
dadfb34
fix: post re-base fixes
tegefaulkes Jun 2, 2022
a0a42f5
syntax: style fixes
tegefaulkes Jun 7, 2022
7860714
build: removing `node-abort-controller` polyfill
tegefaulkes Jun 7, 2022
fb46b13
build: removing unneeded files
tegefaulkes Jun 7, 2022
891fb8c
fix: `NodeConnectionManager.syncNodeGraph` now pings nodes
tegefaulkes Jun 7, 2022
376292a
fix: small fixes to nodes utils parsing functions
tegefaulkes Jun 9, 2022
22e1491
tests: expanding tests for root keypair changing
tegefaulkes Jun 9, 2022
c52bf2c
build: updating package-lock.json
tegefaulkes Jun 10, 2022
7253de8
fix: removed unneeded timer from NodeConnection test
tegefaulkes Jun 10, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
feat: implemented NodeManager.refreshBucket()
This method preforms the kademlia `refreshBucket` operation. It selects a random node within the bucket and preforms a search for that node. The process exchanges node information with any nodes it connects to.

#345
tegefaulkes authored and emmacasolin committed Jun 14, 2022
commit b4fbc0b6ca862d04c605ccafa3cac11cce98453b
28 changes: 26 additions & 2 deletions src/nodes/NodeManager.ts
Original file line number Diff line number Diff line change
@@ -5,11 +5,17 @@ import type KeyManager from '../keys/KeyManager';
import type { PublicKeyPem } from '../keys/types';
import type Sigchain from '../sigchain/Sigchain';
import type { ChainData, ChainDataEncoded } from '../sigchain/types';
import type { NodeId, NodeAddress, NodeBucket } from '../nodes/types';
import type {
NodeId,
NodeAddress,
NodeBucket,
NodeBucketIndex,
} from '../nodes/types';
import type { ClaimEncoded } from '../claims/types';
import type { Timer } from '../types';
import Logger from '@matrixai/logger';
import { StartStop, ready } from '@matrixai/async-init/dist/StartStop';
import { IdInternal } from '@matrixai/id';
import * as nodesErrors from './errors';
import * as nodesUtils from './utils';
import * as networkUtils from '../network/utils';
@@ -514,7 +520,7 @@ class NodeManager {
// return await this.nodeGraph.getAllBuckets(tran);
// }

// FIXME
// FIXME potentially confusing name, should we rename this to renewBuckets?
/**
* To be called on key renewal. Re-orders all nodes in all buckets with respect
* to the new node ID.
@@ -609,6 +615,24 @@ class NodeManager {
public async queueDrained(): Promise<void> {
await this.setNodeQueueEmpty;
}

/**
* Kademlia refresh bucket operation.
* It picks a random node within a bucket and does a search for that node.
* Connections during the search will will share node information with other
* nodes.
* @param bucketIndex
*/
private async refreshBucket(bucketIndex: NodeBucketIndex) {
// We need to generate a random nodeId for this bucket
const nodeId = this.keyManager.getNodeId();
const bucketRandomNodeId = nodesUtils.generateRandomNodeIdForBucket(
nodeId,
bucketIndex,
);
// We then need to start a findNode procedure
await this.nodeConnectionManager.findNode(bucketRandomNodeId);
}
}

export default NodeManager;
42 changes: 42 additions & 0 deletions src/nodes/utils.ts
Original file line number Diff line number Diff line change
@@ -7,6 +7,7 @@ import type {
import { IdInternal } from '@matrixai/id';
import lexi from 'lexicographic-integer';
import { bytes2BigInt, bufferSplit } from '../utils';
import * as keysUtils from '../keys/utils';

// FIXME:
const prefixBuffer = Buffer.from([33]);
@@ -283,6 +284,44 @@ function bucketSortByDistance(
}
}

function generateRandomDistanceForBucket(bucketIndex: NodeBucketIndex): NodeId {
const buffer = keysUtils.getRandomBytesSync(32);
// Calculate the most significant byte for bucket
const base = bucketIndex / 8;
const mSigByte = Math.floor(base);
const mSigBit = (base - mSigByte) * 8 + 1;
const mSigByteIndex = buffer.length - mSigByte - 1;
// Creating masks
// AND mask should look like 0b00011111
// OR mask should look like 0b00010000
const shift = 8 - mSigBit;
const andMask = 0b11111111 >>> shift;
const orMask = 0b10000000 >>> shift;
let byte = buffer[mSigByteIndex];
byte = byte & andMask; // Forces 0 for bits above bucket bit
byte = byte | orMask; // Forces 1 in the desired bucket bit
buffer[mSigByteIndex] = byte;
// Zero out byte 'above' mSigByte
for (let byteIndex = 0; byteIndex < mSigByteIndex; byteIndex++) {
buffer[byteIndex] = 0;
}
return IdInternal.fromBuffer<NodeId>(buffer);
}

function xOrNodeId(node1: NodeId, node2: NodeId): NodeId {
const xOrNodeArray = node1.map((byte, i) => byte ^ node2[i]);
const xOrNodeBuffer = Buffer.from(xOrNodeArray);
return IdInternal.fromBuffer<NodeId>(xOrNodeBuffer);
}

function generateRandomNodeIdForBucket(
nodeId: NodeId,
bucket: NodeBucketIndex,
): NodeId {
const randomDistanceForBucket = generateRandomDistanceForBucket(bucket);
return xOrNodeId(nodeId, randomDistanceForBucket);
}

export {
prefixBuffer,
encodeNodeId,
@@ -299,4 +338,7 @@ export {
parseLastUpdatedBucketDbKey,
nodeDistance,
bucketSortByDistance,
generateRandomDistanceForBucket,
xOrNodeId,
generateRandomNodeIdForBucket,
};
18 changes: 18 additions & 0 deletions tests/nodes/utils.test.ts
Original file line number Diff line number Diff line change
@@ -171,4 +171,22 @@ describe('nodes/utils', () => {
i++;
}
});
test('should generate random distance for a bucket', async () => {
// Const baseNodeId = testNodesUtils.generateRandomNodeId();
const zeroNodeId = IdInternal.fromBuffer<NodeId>(Buffer.alloc(32, 0));
for (let i = 0; i < 255; i++) {
const randomDistance = nodesUtils.generateRandomDistanceForBucket(i);
expect(nodesUtils.bucketIndex(zeroNodeId, randomDistance)).toEqual(i);
}
});
test('should generate random NodeId for a bucket', async () => {
const baseNodeId = testNodesUtils.generateRandomNodeId();
for (let i = 0; i < 255; i++) {
const randomDistance = nodesUtils.generateRandomNodeIdForBucket(
baseNodeId,
i,
);
expect(nodesUtils.bucketIndex(baseNodeId, randomDistance)).toEqual(i);
}
});
});