UNPKG

xud

Version:
289 lines 14.5 kB
"use strict"; var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } return new (P || (P = Promise))(function (resolve, reject) { function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } step((generator = generator.apply(thisArg, _arguments || [])).next()); }); }; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); const assert_1 = require("assert"); const events_1 = require("events"); const fs_1 = require("fs"); const path_1 = __importDefault(require("path")); const bootstrap_1 = __importDefault(require("./bootstrap")); const Config_1 = __importDefault(require("./Config")); const enums_1 = require("./constants/enums"); const DB_1 = __importDefault(require("./db/DB")); const GrpcServer_1 = __importDefault(require("./grpc/GrpcServer")); const GrpcWebProxyServer_1 = __importDefault(require("./grpc/webproxy/GrpcWebProxyServer")); const HttpServer_1 = __importDefault(require("./http/HttpServer")); const Logger_1 = __importDefault(require("./Logger")); const NodeKey_1 = __importDefault(require("./nodekey/NodeKey")); const OrderBook_1 = __importDefault(require("./orderbook/OrderBook")); const Pool_1 = __importDefault(require("./p2p/Pool")); const InitService_1 = __importDefault(require("./service/InitService")); const Service_1 = __importDefault(require("./service/Service")); const SwapClientManager_1 = __importDefault(require("./swaps/SwapClientManager")); const Swaps_1 = __importDefault(require("./swaps/Swaps")); const simnet_connext_channels_1 = require("./utils/simnet-connext-channels"); const UnitConverter_1 = require("./utils/UnitConverter"); const version = require('../package.json').version; bootstrap_1.default(); /** Class representing a complete Exchange Union daemon. */ class Xud extends events_1.EventEmitter { /** * Create an Exchange Union daemon. */ constructor() { super(); this.shuttingDown = false; /** * Start all processes necessary for the operation of an Exchange Union node. * @param args optional arguments to override configuration parameters. */ this.start = (args) => __awaiter(this, void 0, void 0, function* () { var _a, _b; let configFileLoaded; try { configFileLoaded = yield this.config.load(args); } catch (err) { if (err instanceof assert_1.AssertionError) { console.error(err.message); process.exit(1); } else { throw err; } } const loggers = Logger_1.default.createLoggers(this.config.loglevel, this.config.logpath, this.config.instanceid, this.config.logdateformat); this.logger = loggers.global; if (configFileLoaded) { this.logger.info('config file loaded'); } try { if (!this.config.rpc.disable) { // start rpc server first, it will respond with UNAVAILABLE error // indicating xud is starting until xud finishes initializing this.rpcServer = new GrpcServer_1.default(loggers.rpc); yield this.rpcServer.listen(this.config.rpc.port, this.config.rpc.host, path_1.default.join(this.config.xudir, 'tls.cert'), path_1.default.join(this.config.xudir, 'tls.key')); if (!this.config.webproxy.disable) { this.grpcAPIProxy = new GrpcWebProxyServer_1.default(loggers.rpc); yield this.grpcAPIProxy.listen(this.config.webproxy.port, this.config.rpc.port, this.config.rpc.host, path_1.default.join(this.config.xudir, 'tls.cert')); } } this.db = new DB_1.default(loggers.db, this.config.dbpath); yield this.db.init(this.config.network, this.config.initdb); this.unitConverter = new UnitConverter_1.UnitConverter(); this.unitConverter.init(); const nodeKeyPath = NodeKey_1.default.getPath(this.config.xudir, this.config.instanceid); const nodeKeyExists = yield fs_1.promises.access(nodeKeyPath).then(() => true).catch(() => false); this.swapClientManager = new SwapClientManager_1.default(this.config, loggers, this.unitConverter, this.db.models); yield this.swapClientManager.init(); let nodeKey; if (this.config.noencrypt) { if (nodeKeyExists) { nodeKey = yield NodeKey_1.default.fromFile(nodeKeyPath); } else { nodeKey = yield NodeKey_1.default.generate(nodeKeyPath); yield nodeKey.toFile(); } // we need to initialize connext every time xud starts, even in noencrypt mode // the call below is in lieu of the UnlockNode/CreateNode call flow yield this.swapClientManager.initConnext(nodeKey.childSeed(enums_1.SwapClientType.Connext)); } else if (this.rpcServer) { this.rpcServer.grpcService.locked = true; const initService = new InitService_1.default(this.swapClientManager, nodeKeyPath, nodeKeyExists, this.config.dbpath); this.rpcServer.grpcInitService.setInitService(initService); this.logger.info("Node key is encrypted, unlock with 'xucli unlock', 'xucli create', or 'xucli restore'"); nodeKey = yield new Promise((resolve) => { initService.once('nodekey', resolve); this.on('shutdown', () => { // in case we shutdown before unlocking xud resolve(); initService.removeListener('nodekey', resolve); }); }); if (!nodeKey) { return; // we interrupted before unlocking xud } this.rpcServer.grpcService.locked = false; } else { throw new Error('rpc server cannot be disabled when xud is locked'); } if (this.rpcServer) { this.rpcServer.grpcInitService.disable(); } this.logger.info(`Local nodePubKey is ${nodeKey.pubKey}`); this.pool = new Pool_1.default({ nodeKey, version, config: this.config.p2p, xuNetwork: this.config.network, logger: loggers.p2p, models: this.db.models, strict: this.config.strict, }); const initPromises = []; this.swaps = new Swaps_1.default({ logger: loggers.swaps, models: this.db.models, pool: this.pool, swapClientManager: this.swapClientManager, strict: this.config.strict, }); initPromises.push(this.swaps.init()); this.orderBook = new OrderBook_1.default({ logger: loggers.orderbook, models: this.db.models, thresholds: this.config.orderthresholds, nomatching: this.config.nomatching, pool: this.pool, swaps: this.swaps, nosanityswaps: this.config.nosanityswaps, nobalancechecks: this.config.nobalancechecks, strict: this.config.strict, }); initPromises.push(this.orderBook.init()); // wait for components to initialize in parallel yield Promise.all(initPromises); // initialize pool and start listening/connecting only once other components are initialized yield this.pool.init(); this.service = new Service_1.default({ version, nodeKey, orderBook: this.orderBook, swapClientManager: this.swapClientManager, pool: this.pool, swaps: this.swaps, logger: loggers.service, shutdown: this.beginShutdown, }); this.service.on('logLevel', (level) => { var _a; (_a = this.swapClientManager) === null || _a === void 0 ? void 0 : _a.setLogLevel(level); Object.values(loggers).forEach((logger) => { logger.setLogLevel(level); }); }); if ((_a = this.swapClientManager.connextClient) === null || _a === void 0 ? void 0 : _a.isOperational()) { this.httpServer = new HttpServer_1.default(loggers.http, this.service); yield this.httpServer.listen(this.config.http.port, this.config.http.host); } // if we're running in simnet mode and Connext is enabled we'll // attempt to request funds from the faucet and open a channel // to the node once we have received the on-chain funds if (this.config.network === enums_1.XuNetwork.SimNet && ((_b = this.swapClientManager.connextClient) === null || _b === void 0 ? void 0 : _b.isOperational())) { this.simnetChannels$ = simnet_connext_channels_1.createSimnetChannels({ channels: [ { currency: 'ETH', // amount of currency to put in the channel channelAmount: 1000000000, // minimum channelBalance threshold minChannelAmount: 100000000, }, { currency: 'USDT', channelAmount: 100000000000, minChannelAmount: 100000000, }, { currency: 'DAI', channelAmount: 150000000000, minChannelAmount: 100000000, }, ], // we check the channel and on-chain balance every 10 seconds // and refund from faucet if below the walletAmount retryInterval: 10000, }).subscribe({ next: (currency) => { this.logger.info(`Connext wallet funded and channel opened for ${currency}`); }, error: (e) => { this.logger.error(`Failed to fund Connext wallet and open a channel: ${e}`); }, complete: () => { this.logger.info('Stopped monitoring Connext balances for automatic funding and channel creation'); }, }); } // initialize rpc server last if (this.rpcServer) { this.rpcServer.grpcService.setService(this.service); } else { this.logger.info('RPC server is disabled.'); } } catch (err) { this.logger.error('Unexpected error during initialization, shutting down...', err); yield this.shutdown(); } }); this.shutdown = () => __awaiter(this, void 0, void 0, function* () { var _c; if (this.shuttingDown) { this.logger.info('XUD is already shutting down'); return; } this.shuttingDown = true; this.logger.info('XUD is shutting down'); // TODO: ensure we are not in the middle of executing any trades const closePromises = []; (_c = this.simnetChannels$) === null || _c === void 0 ? void 0 : _c.unsubscribe(); if (this.swapClientManager) { this.swapClientManager.close(); } if (this.httpServer) { closePromises.push(this.httpServer.close()); } if (this.pool) { closePromises.push(this.pool.disconnect()); } if (this.rpcServer) { closePromises.push(this.rpcServer.close()); } if (this.grpcAPIProxy) { closePromises.push(this.grpcAPIProxy.close()); } if (this.swaps) { this.swaps.close(); } yield Promise.all(closePromises); yield this.db.close(); this.logger.info('XUD shutdown gracefully'); this.emit('shutdown'); }); /** * Initiate graceful shutdown of xud. Emits the `shutdown` event when shutdown is complete. */ this.beginShutdown = () => { // we begin the shutdown process but return a response before it completes. void (this.shutdown()); }; this.config = new Config_1.default(); process.on('SIGINT', () => { this.beginShutdown(); }); process.on('SIGTERM', () => { this.beginShutdown(); }); } } if (!module.parent) { const xud = new Xud(); void xud.start(); } exports.default = Xud; //# sourceMappingURL=Xud.js.map