bitcore-node
Version:
A blockchain indexing node with extended capabilities using bitcore
180 lines • 6.88 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.P2P = exports.BaseP2PWorker = exports.P2pManager = void 0;
const os = __importStar(require("os"));
const logger_1 = __importDefault(require("../logger"));
const state_1 = require("../models/state");
const utils_1 = require("../utils");
const config_1 = require("./config");
class P2pManager {
constructor({ configService = config_1.Config } = {}) {
this.workerClasses = {};
this.configService = configService;
this.workers = new Array();
}
register(chain, network, worker) {
this.workerClasses[chain] = this.workerClasses[chain] || {};
this.workerClasses[chain][network] = worker;
}
get(chain, network) {
return this.workerClasses[chain][network];
}
async stop() {
logger_1.default.info('Stopping P2P Manager');
for (const worker of this.workers) {
await worker.stop();
}
this.workers = [];
}
async start() {
if (this.configService.isDisabled('p2p')) {
logger_1.default.info('Disabled P2P Manager');
return;
}
logger_1.default.info('Starting P2P Manager');
for (let chainNetwork of config_1.Config.chainNetworks()) {
const { chain, network } = chainNetwork;
const chainConfig = config_1.Config.chainConfig(chainNetwork);
if ((chainConfig.chainSource && chainConfig.chainSource !== 'p2p') || chainConfig.disabled) {
continue;
}
logger_1.default.info(`Starting P2P worker ${chain}:${network}`);
const p2pWorker = new this.workerClasses[chain][network]({
chain,
network,
chainConfig
});
this.workers.push(p2pWorker);
try {
p2pWorker.start();
}
catch (e) {
logger_1.default.error('P2P Worker %o:%o died: %o', chain, network, e.stack || e.message || e);
}
}
}
}
exports.P2pManager = P2pManager;
class BaseP2PWorker {
constructor(params) {
this.params = params;
this.lastHeartBeat = '';
this.queuedRegistrations = new Array();
this.stopping = false;
this.chain = '';
this.network = '';
this.isSyncingNode = false;
}
async start() { }
async stop() { }
async sync() { }
getIsSyncingNode() {
if (!this.lastHeartBeat) {
return false;
}
const [hostname, pid, timestamp] = this.lastHeartBeat.split(':');
const hostNameMatches = hostname === os.hostname();
const pidMatches = pid === process.pid.toString();
const timestampIsFresh = Date.now() - parseInt(timestamp) < 5 * 60 * 1000;
const amSyncingNode = hostNameMatches && pidMatches && timestampIsFresh;
return amSyncingNode;
}
async waitTilSync() {
while (true) {
if (this.isSyncingNode) {
return;
}
await (0, utils_1.wait)(500);
}
}
async refreshSyncingNode() {
while (!this.stopping) {
const wasSyncingNode = this.getIsSyncingNode();
this.lastHeartBeat = await state_1.StateStorage.getSyncingNode({ chain: this.chain, network: this.network });
const nowSyncingNode = this.getIsSyncingNode();
this.isSyncingNode = nowSyncingNode;
if (wasSyncingNode && !nowSyncingNode) {
throw new Error('Syncing Node Renewal Failure');
}
if (!wasSyncingNode && nowSyncingNode) {
logger_1.default.info(`This worker is now the syncing node for ${this.chain} ${this.network}`);
this.sync();
}
if (!this.lastHeartBeat || this.getIsSyncingNode()) {
this.registerSyncingNode({ primary: true });
}
else {
logger_1.default.info('Another node is the primary syncing node');
this.registerSyncingNode({ primary: false });
}
await (0, utils_1.wait)(500);
}
}
async registerSyncingNode({ primary }) {
const lastHeartBeat = this.lastHeartBeat;
const queuedRegistration = setTimeout(() => {
state_1.StateStorage.selfNominateSyncingNode({
chain: this.chain,
network: this.network,
lastHeartBeat
});
}, primary ? 0 : 5 * 60 * 1000);
this.queuedRegistrations.push(queuedRegistration);
}
async unregisterSyncingNode() {
await (0, utils_1.wait)(1000);
try {
this.lastHeartBeat = await state_1.StateStorage.getSyncingNode({ chain: this.chain, network: this.network });
if (this.getIsSyncingNode()) {
await state_1.StateStorage.selfResignSyncingNode({
chain: this.chain,
network: this.network,
lastHeartBeat: this.lastHeartBeat
});
}
}
catch (e) {
logger_1.default.warn('Issue unregistering');
logger_1.default.error('%o', e);
}
}
}
exports.BaseP2PWorker = BaseP2PWorker;
exports.P2P = new P2pManager();
//# sourceMappingURL=p2p.js.map