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

Fix mix node #113

Merged
merged 7 commits into from
Nov 24, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 0 additions & 1 deletion src/config/config.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,6 @@
"API_NODE_PORT": 3000,
"PEER_NODE_PORT": 7900,
"REQUEST_TIMEOUT": 5000,
"NETWORK_IDENTIFIER": 152,
"NUMBER_OF_NODE_REQUEST_CHUNK": 10,
"PREFERRED_NODES": ["*.symboldev.network"],
"MIN_PARTNER_NODE_VERSION": 16777728
Expand Down
6 changes: 0 additions & 6 deletions src/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
import * as config from './config.json';
import * as utils from '@src/utils';
import { NetworkType } from 'symbol-sdk';

interface Network {
PORT: number;
Expand All @@ -24,7 +23,6 @@ interface Monitor {
API_NODE_PORT: number;
PEER_NODE_PORT: number;
REQUEST_TIMEOUT: number;
NETWORK_IDENTIFIER: NetworkType;
}

export interface Config {
Expand Down Expand Up @@ -58,7 +56,6 @@ export const monitor: Monitor = {
API_NODE_PORT: Number(process.env.API_NODE_PORT) || config.API_NODE_PORT,
PEER_NODE_PORT: Number(process.env.PEER_NODE_PORT) || config.PEER_NODE_PORT,
REQUEST_TIMEOUT: Number(process.env.REQUEST_TIMEOUT) || config.REQUEST_TIMEOUT,
NETWORK_IDENTIFIER: Number(process.env.NETWORK_IDENTIFIER) || config.NETWORK_IDENTIFIER,
};

export const verifyConfig = (cfg: Config): boolean => {
Expand Down Expand Up @@ -96,9 +93,6 @@ export const verifyConfig = (cfg: Config): boolean => {

if (isNaN(cfg.monitor.REQUEST_TIMEOUT) || cfg.monitor.REQUEST_TIMEOUT <= 0) error = 'Invalid "REQUEST_TIMEOUT"';

if (isNaN(cfg.monitor.NETWORK_IDENTIFIER) || !Object.values(NetworkType).includes(cfg.monitor.NETWORK_IDENTIFIER))
error = 'Invalid "NETWORK_IDENTIFIER"';

if (error) throw 'Invalid config. ' + error;
return true;
};
88 changes: 45 additions & 43 deletions src/services/NodeMonitor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { Logger } from '@src/infrastructure';

import { INode, validateNodeModel } from '@src/models/Node';
import { symbol, monitor } from '@src/config';
import { isAPIRole, isPeerRole, getNodeURL, basename, splitArray, sleep } from '@src/utils';
import { isAPIRole, isPeerRole, basename, splitArray, sleep } from '@src/utils';

const logger: winston.Logger = Logger.getLogger(basename(__filename));

Expand All @@ -26,6 +26,7 @@ export class NodeMonitor {
private nodeInfoChunks: number;
private nodeInfoDelay: number;
private networkIdentifier: number;
private generationHashSeed: string;

constructor(_interval: number) {
this.nodesStats = new NodesStats();
Expand All @@ -39,7 +40,9 @@ export class NodeMonitor {
this.interval = _interval || 300000;
this.nodeInfoChunks = monitor.NUMBER_OF_NODE_REQUEST_CHUNK;
this.nodeInfoDelay = 1000;
this.networkIdentifier = 152; // default Testnet
this.networkIdentifier = 0;
this.generationHashSeed = '';

this.cacheCollection();
}

Expand All @@ -54,10 +57,10 @@ export class NodeMonitor {
this.isRunning = true;
this.clear();

await this.getNetworkType(); // Read network Type from provided nodes.
await this.fetchAndSetNetworkInfo(); // Read network Type and generated hash seed from provided nodes.

await this.getNodeList();
await this.getNodeListInfo(); //HostInfo.getInfoForListOfNodes(this.nodeList);
await this.getNodeList(); // Fetch node from peers
await this.getNodeListInfo();

if (this.isRunning) {
await this.updateCollection();
Expand All @@ -78,19 +81,21 @@ export class NodeMonitor {
};

private getNodeList = async (): Promise<any> => {
// Init fetch node list from config nodes
logger.info(`Getting node list`);

// Fetch node list from config nodes
for (const nodeUrl of symbol.NODES) {
const peers = await this.fetchNodesByURL(nodeUrl, true);
const peers = await this.fetchNodePeersByURL(nodeUrl);

this.addNodesToList(peers);
}

// Nested fetch node list from current nodeList[]
const nodeListPromises = this.nodeList.map(async (node) => {
if (isAPIRole(node.roles)) {
return this.fetchNodesByURL(getNodeURL(node, monitor.API_NODE_PORT));
const hostUrl = await ApiNodeService.buildHostUrl(node.host);

return this.fetchNodePeersByURL(hostUrl);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe I miss it, are pulling node/peers from every api node?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, every API node.

}

return [];
Expand All @@ -104,48 +109,37 @@ export class NodeMonitor {
return Promise.resolve();
};

private fetchNodesByURL = async (nodeUrl: string, includeCurrent: boolean = false): Promise<Array<INode>> => {
let nodeList = [];

if (includeCurrent) {
try {
const nodeInfo = await HTTP.get(nodeUrl + '/node/info', {
timeout: monitor.REQUEST_TIMEOUT,
});
const host = new URL(nodeUrl).hostname;

nodeList.push({
...nodeInfo.data,
host,
});
} catch (e) {
logger.error(`FetchNodesByURL. Failed to get /node/info from "${nodeUrl}". ${e.message}`);
}
}
/**
* Fetch nodes from peers.
* @param hostUrl
* @returns INode[]
*/
private fetchNodePeersByURL = async (hostUrl: string): Promise<Array<INode>> => {
let nodeList: INode[] = [];

try {
const nodePeers = await HTTP.get(nodeUrl + '/node/peers', {
const nodePeers = await HTTP.get(hostUrl + '/node/peers', {
timeout: monitor.REQUEST_TIMEOUT,
});

if (Array.isArray(nodePeers.data)) nodeList = [...nodeList, ...nodePeers.data];
if (Array.isArray(nodePeers.data)) nodeList = [...nodePeers.data];
} catch (e) {
logger.error(`FetchNodesByURL. Failed to get /node/peers from "${nodeUrl}". ${e.message}`);
logger.error(`FetchNodePeersByURL. Failed to get /node/peers from "${hostUrl}". ${e.message}`);
}

return nodeList;
};

private getNodeListInfo = async () => {
logger.info(`Getting node info total for ${this.nodeList.length} nodes`);
logger.info(`Getting node from peers total ${this.nodeList.length} nodes`);
const nodeListChunks = splitArray(this.nodeList, this.nodeInfoChunks);

this.nodeList = [];

for (const nodes of nodeListChunks) {
logger.info(`Getting node info for chunk of ${nodes.length} nodes`);

const nodeInfoPromises = [...nodes].map(this.getNodeInfo);
const nodeInfoPromises = [...nodes].map((node) => this.getNodeInfo(node));

this.addNodesToList((await Promise.all(nodeInfoPromises)) as INode[]);
await sleep(this.nodeInfoDelay);
Expand All @@ -161,25 +155,30 @@ export class NodeMonitor {

if (hostDetail) nodeWithInfo.hostDetail = hostDetail;

if (isPeerRole(node.roles)) {
if (isPeerRole(nodeWithInfo.roles)) {
nodeWithInfo.peerStatus = await PeerNodeService.getStatus(node.host, node.port);
}

if (isAPIRole(node.roles)) {
const hostUrl = await ApiNodeService.buildHostUrl(node.host);
// To fix version 0 issue return from `/node/peers`
if (isAPIRole(nodeWithInfo.roles)) {
const hostUrl = await ApiNodeService.buildHostUrl(nodeWithInfo.host);

// Get node info and overwrite info from /node/peers
const nodeStatus = await ApiNodeService.getNodeInfo(hostUrl);

if (node.version === 0) {
const nodeStatus = await ApiNodeService.getNodeInfo(hostUrl);
if (nodeStatus) {
Object.assign(nodeWithInfo, nodeStatus);
}

if (nodeStatus) {
nodeWithInfo.version = nodeStatus.version;
}
// Request API Status, if node belong to the network
if (
nodeWithInfo.networkIdentifier === this.networkIdentifier &&
nodeWithInfo.networkGenerationHashSeed === this.generationHashSeed
) {
nodeWithInfo.apiStatus = await ApiNodeService.getStatus(hostUrl);
}
nodeWithInfo.apiStatus = await ApiNodeService.getStatus(hostUrl);
}
} catch (e) {
logger.error(`GetNodeInfo. Failed to fetch info for "${node}". ${e.message}`);
logger.error(`GetNodeInfo. Failed to fetch info for "${nodeWithInfo.host}". ${e.message}`);
}

return nodeWithInfo;
Expand Down Expand Up @@ -223,7 +222,7 @@ export class NodeMonitor {
}
};

private getNetworkType = async (): Promise<void> => {
private fetchAndSetNetworkInfo = async (): Promise<void> => {
for (const nodeUrl of symbol.NODES) {
const url = new URL(nodeUrl);
const hostUrl = await ApiNodeService.buildHostUrl(url.hostname);
Expand All @@ -232,7 +231,9 @@ export class NodeMonitor {

if (nodeInfo) {
this.networkIdentifier = nodeInfo.networkIdentifier;
this.generationHashSeed = nodeInfo.networkGenerationHashSeed;
logger.info(`Found network identifier ${nodeInfo.networkIdentifier}`);
logger.info(`Found network hash ${nodeInfo.networkGenerationHashSeed}`);
return;
}
}
Expand All @@ -244,6 +245,7 @@ export class NodeMonitor {
nodes.forEach((node: INode) => {
if (
node.networkIdentifier !== this.networkIdentifier ||
node.networkGenerationHashSeed !== this.generationHashSeed ||
!!this.nodeList.find((addedNode) => addedNode.publicKey === node.publicKey) ||
!validateNodeModel(node)
)
Expand Down