| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  | import express from 'express'; | 
					
						
							| 
									
										
										
										
											2022-07-06 21:43:47 +02:00
										 |  |  | import { Application, Request, Response, NextFunction } from 'express'; | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  | import * as http from 'http'; | 
					
						
							|  |  |  | import * as WebSocket from 'ws'; | 
					
						
							| 
									
										
										
										
											2023-04-07 09:41:25 +09:00
										 |  |  | import bitcoinApi from './api/bitcoin/bitcoin-api-factory'; | 
					
						
							| 
									
										
										
										
											2022-06-27 21:28:21 -07:00
										 |  |  | import cluster from 'cluster'; | 
					
						
							| 
									
										
										
										
											2022-04-13 17:38:42 +04:00
										 |  |  | import DB from './database'; | 
					
						
							| 
									
										
										
										
											2020-10-19 11:57:02 +07:00
										 |  |  | import config from './config'; | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  | import blocks from './api/blocks'; | 
					
						
							| 
									
										
										
										
											2020-02-16 22:15:07 +07:00
										 |  |  | import memPool from './api/mempool'; | 
					
						
							|  |  |  | import diskCache from './api/disk-cache'; | 
					
						
							| 
									
										
										
										
											2022-07-11 19:15:28 +02:00
										 |  |  | import statistics from './api/statistics/statistics'; | 
					
						
							| 
									
										
										
										
											2020-02-26 17:49:53 +07:00
										 |  |  | import websocketHandler from './api/websocket-handler'; | 
					
						
							| 
									
										
										
										
											2020-10-13 15:27:52 +07:00
										 |  |  | import logger from './logger'; | 
					
						
							| 
									
										
										
										
											2020-10-13 17:48:43 +07:00
										 |  |  | import backendInfo from './api/backend-info'; | 
					
						
							| 
									
										
										
										
											2021-01-05 18:57:06 +07:00
										 |  |  | import loadingIndicators from './api/loading-indicators'; | 
					
						
							| 
									
										
										
										
											2021-01-20 17:16:43 +07:00
										 |  |  | import mempool from './api/mempool'; | 
					
						
							| 
									
										
										
										
											2021-09-18 13:37:25 +04:00
										 |  |  | import elementsParser from './api/liquid/elements-parser'; | 
					
						
							| 
									
										
										
										
											2021-12-11 04:27:58 +04:00
										 |  |  | import databaseMigration from './api/database-migration'; | 
					
						
							| 
									
										
										
										
											2021-12-21 02:00:50 +04:00
										 |  |  | import syncAssets from './sync-assets'; | 
					
						
							|  |  |  | import icons from './api/liquid/icons'; | 
					
						
							| 
									
										
										
										
											2021-12-31 02:28:40 +04:00
										 |  |  | import { Common } from './api/common'; | 
					
						
							| 
									
										
										
										
											2022-04-07 14:37:16 +09:00
										 |  |  | import poolsUpdater from './tasks/pools-updater'; | 
					
						
							| 
									
										
										
										
											2022-05-19 16:40:38 +02:00
										 |  |  | import indexer from './indexer'; | 
					
						
							| 
									
										
										
										
											2022-07-06 11:58:06 +02:00
										 |  |  | import nodesRoutes from './api/explorer/nodes.routes'; | 
					
						
							|  |  |  | import channelsRoutes from './api/explorer/channels.routes'; | 
					
						
							|  |  |  | import generalLightningRoutes from './api/explorer/general.routes'; | 
					
						
							| 
									
										
										
										
											2022-07-06 21:43:47 +02:00
										 |  |  | import lightningStatsUpdater from './tasks/lightning/stats-updater.service'; | 
					
						
							| 
									
										
										
										
											2022-08-02 16:18:19 +02:00
										 |  |  | import networkSyncService from './tasks/lightning/network-sync.service'; | 
					
						
							| 
									
										
										
										
											2022-08-01 17:48:04 +02:00
										 |  |  | import statisticsRoutes from './api/statistics/statistics.routes'; | 
					
						
							| 
									
										
										
										
											2023-07-29 14:23:06 +09:00
										 |  |  | import pricesRoutes from './api/prices/prices.routes'; | 
					
						
							| 
									
										
										
										
											2022-08-01 17:48:04 +02:00
										 |  |  | import miningRoutes from './api/mining/mining-routes'; | 
					
						
							|  |  |  | import liquidRoutes from './api/liquid/liquid.routes'; | 
					
						
							|  |  |  | import bitcoinRoutes from './api/bitcoin/bitcoin.routes'; | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  | import fundingTxFetcher from './tasks/lightning/sync-tasks/funding-tx-fetcher'; | 
					
						
							| 
									
										
										
										
											2022-11-23 10:38:24 +09:00
										 |  |  | import forensicsService from './tasks/lightning/forensics.service'; | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:14 +09:00
										 |  |  | import priceUpdater from './tasks/price-updater'; | 
					
						
							| 
									
										
										
										
											2023-02-18 14:10:07 +09:00
										 |  |  | import chainTips from './api/chain-tips'; | 
					
						
							| 
									
										
										
										
											2023-02-07 20:56:33 -06:00
										 |  |  | import { AxiosError } from 'axios'; | 
					
						
							| 
									
										
										
										
											2023-03-04 23:13:55 -06:00
										 |  |  | import v8 from 'v8'; | 
					
						
							|  |  |  | import { formatBytes, getBytesUnit } from './utils/format'; | 
					
						
							| 
									
										
										
										
											2023-05-12 16:29:45 -06:00
										 |  |  | import redisCache from './api/redis-cache'; | 
					
						
							| 
									
										
										
										
											2023-12-06 12:09:28 +00:00
										 |  |  | import accelerationApi from './api/services/acceleration'; | 
					
						
							| 
									
										
										
										
											2024-01-08 11:48:55 +01:00
										 |  |  | import bitcoinCoreRoutes from './api/bitcoin/bitcoin-core.routes'; | 
					
						
							| 
									
										
										
										
											2023-02-17 17:54:29 -06:00
										 |  |  | import bitcoinSecondClient from './api/bitcoin/bitcoin-second-client'; | 
					
						
							| 
									
										
										
										
											2024-04-04 12:57:54 +09:00
										 |  |  | import accelerationRoutes from './api/acceleration/acceleration.routes'; | 
					
						
							| 
									
										
										
										
											2024-04-04 13:56:39 +09:00
										 |  |  | import aboutRoutes from './api/about.routes'; | 
					
						
							| 
									
										
										
										
											2024-06-04 20:57:40 +00:00
										 |  |  | import mempoolBlocks from './api/mempool-blocks'; | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-16 22:15:07 +07:00
										 |  |  | class Server { | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |   private wss: WebSocket.Server | undefined; | 
					
						
							| 
									
										
										
										
											2024-04-07 18:39:37 +09:00
										 |  |  |   private wssUnixSocket: WebSocket.Server | undefined; | 
					
						
							| 
									
										
										
										
											2021-02-07 02:20:07 +07:00
										 |  |  |   private server: http.Server | undefined; | 
					
						
							| 
									
										
										
										
											2024-04-07 18:39:37 +09:00
										 |  |  |   private serverUnixSocket: http.Server | undefined; | 
					
						
							| 
									
										
										
										
											2022-06-27 21:28:21 -07:00
										 |  |  |   private app: Application; | 
					
						
							| 
									
										
										
										
											2023-05-03 10:11:44 +04:00
										 |  |  |   private currentBackendRetryInterval = 1; | 
					
						
							|  |  |  |   private backendRetryCount = 0; | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-04 23:13:55 -06:00
										 |  |  |   private maxHeapSize: number = 0; | 
					
						
							|  |  |  |   private heapLogInterval: number = 60; | 
					
						
							|  |  |  |   private warnedHeapCritical: boolean = false; | 
					
						
							|  |  |  |   private lastHeapLogTime: number | null = null; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |   constructor() { | 
					
						
							|  |  |  |     this.app = express(); | 
					
						
							| 
									
										
										
										
											2020-02-16 22:15:07 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 11:57:02 +07:00
										 |  |  |     if (!config.MEMPOOL.SPAWN_CLUSTER_PROCS) { | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       this.startServer(); | 
					
						
							|  |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 21:28:21 -07:00
										 |  |  |     if (cluster.isPrimary) { | 
					
						
							| 
									
										
										
										
											2020-10-19 11:57:02 +07:00
										 |  |  |       logger.notice(`Mempool Server (Master) is running on port ${config.MEMPOOL.HTTP_PORT} (${backendInfo.getShortCommitHash()})`); | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 11:57:02 +07:00
										 |  |  |       const numCPUs = config.MEMPOOL.SPAWN_CLUSTER_PROCS; | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       for (let i = 0; i < numCPUs; i++) { | 
					
						
							| 
									
										
										
										
											2020-09-30 00:25:43 +07:00
										 |  |  |         const env = { workerId: i }; | 
					
						
							|  |  |  |         const worker = cluster.fork(env); | 
					
						
							|  |  |  |         worker.process['env'] = env; | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |       cluster.on('exit', (worker, code, signal) => { | 
					
						
							| 
									
										
										
										
											2020-09-30 00:25:43 +07:00
										 |  |  |         const workerId = worker.process['env'].workerId; | 
					
						
							| 
									
										
										
										
											2020-10-13 16:43:09 +07:00
										 |  |  |         logger.warn(`Mempool Worker PID #${worker.process.pid} workerId: ${workerId} died. Restarting in 10 seconds... ${signal || code}`); | 
					
						
							| 
									
										
										
										
											2020-09-30 00:25:43 +07:00
										 |  |  |         setTimeout(() => { | 
					
						
							|  |  |  |           const env = { workerId: workerId }; | 
					
						
							|  |  |  |           const newWorker = cluster.fork(env); | 
					
						
							|  |  |  |           newWorker.process['env'] = env; | 
					
						
							|  |  |  |         }, 10000); | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       }); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       this.startServer(true); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |   async startServer(worker = false): Promise<void> { | 
					
						
							| 
									
										
										
										
											2022-06-01 01:09:08 +09:00
										 |  |  |     logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`); | 
					
						
							| 
									
										
										
										
											2021-01-20 01:34:21 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  |     // Register cleanup listeners for exit events
 | 
					
						
							| 
									
										
										
										
											2023-11-14 05:00:05 +00:00
										 |  |  |     ['exit', 'SIGHUP', 'SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2'].forEach(event => { | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  |       process.on(event, () => { this.onExit(event); }); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-11-14 05:00:05 +00:00
										 |  |  |     process.on('uncaughtException', (error) => { | 
					
						
							|  |  |  |       this.onUnhandledException('uncaughtException', error); | 
					
						
							|  |  |  |     }); | 
					
						
							|  |  |  |     process.on('unhandledRejection', (reason, promise) => { | 
					
						
							|  |  |  |       this.onUnhandledException('unhandledRejection', reason); | 
					
						
							|  |  |  |     }); | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-08-05 13:08:47 +09:00
										 |  |  |     if (config.MEMPOOL.BACKEND === 'esplora') { | 
					
						
							|  |  |  |       bitcoinApi.startHealthChecks(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:13:10 +09:00
										 |  |  |     if (config.DATABASE.ENABLED) { | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  |       DB.getPidLock(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-02-15 16:13:10 +09:00
										 |  |  |       await DB.checkDbConnection(); | 
					
						
							|  |  |  |       try { | 
					
						
							| 
									
										
										
										
											2023-02-26 15:28:50 +09:00
										 |  |  |         if (process.env.npm_config_reindex_blocks === 'true') { // Re-index requests
 | 
					
						
							|  |  |  |           await databaseMigration.$blocksReindexingTruncate(); | 
					
						
							| 
									
										
										
										
											2023-02-15 16:13:10 +09:00
										 |  |  |         } | 
					
						
							|  |  |  |         await databaseMigration.$initializeOrMigrateDatabase(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							|  |  |  |         throw new Error(e instanceof Error ? e.message : 'Error'); | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |     this.app | 
					
						
							| 
									
										
										
										
											2020-06-07 17:30:32 +07:00
										 |  |  |       .use((req: Request, res: Response, next: NextFunction) => { | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |         res.setHeader('Access-Control-Allow-Origin', '*'); | 
					
						
							|  |  |  |         next(); | 
					
						
							|  |  |  |       }) | 
					
						
							| 
									
										
										
										
											2020-10-07 20:15:42 +07:00
										 |  |  |       .use(express.urlencoded({ extended: true })) | 
					
						
							| 
									
										
										
										
											2022-11-23 18:43:37 +09:00
										 |  |  |       .use(express.text({ type: ['text/plain', 'application/base64'] })) | 
					
						
							| 
									
										
										
										
											2024-03-25 05:52:03 +00:00
										 |  |  |       .use(express.json()) | 
					
						
							| 
									
										
										
										
											2022-06-27 21:28:21 -07:00
										 |  |  |       ; | 
					
						
							| 
									
										
										
										
											2020-02-16 22:15:07 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:19 +01:00
										 |  |  |     if (config.DATABASE.ENABLED && config.FIAT_PRICE.ENABLED) { | 
					
						
							| 
									
										
										
										
											2023-02-15 17:45:29 +09:00
										 |  |  |       await priceUpdater.$initializeLatestPriceWithDb(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-15 16:05:14 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 11:57:02 +07:00
										 |  |  |     this.server = http.createServer(this.app); | 
					
						
							|  |  |  |     this.wss = new WebSocket.Server({ server: this.server }); | 
					
						
							| 
									
										
										
										
											2024-04-09 15:11:40 +09:00
										 |  |  |     if (config.MEMPOOL.UNIX_SOCKET_PATH) { | 
					
						
							|  |  |  |       this.serverUnixSocket = http.createServer(this.app); | 
					
						
							|  |  |  |       this.wssUnixSocket = new WebSocket.Server({ server: this.serverUnixSocket }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-03-18 23:47:40 +07:00
										 |  |  |     this.setUpWebsocketHandling(); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-03 17:29:46 +09:00
										 |  |  |     await poolsUpdater.updatePoolsJson(); // Needs to be done before loading the disk cache because we sometimes wipe it
 | 
					
						
							| 
									
										
										
										
											2022-04-22 04:03:08 -04:00
										 |  |  |     await syncAssets.syncAssets$(); | 
					
						
							| 
									
										
										
										
											2024-06-04 20:57:40 +00:00
										 |  |  |     await mempoolBlocks.updatePools$(); | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |     if (config.MEMPOOL.ENABLED) { | 
					
						
							| 
									
										
										
										
											2023-05-12 16:29:45 -06:00
										 |  |  |       if (config.MEMPOOL.CACHE_ENABLED) { | 
					
						
							|  |  |  |         await diskCache.$loadMempoolCache(); | 
					
						
							|  |  |  |       } else if (config.REDIS.ENABLED) { | 
					
						
							|  |  |  |         await redisCache.$loadCache(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-20 01:34:21 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-06-27 21:28:21 -07:00
										 |  |  |     if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && cluster.isPrimary) { | 
					
						
							| 
									
										
										
										
											2020-07-23 00:04:29 +07:00
										 |  |  |       statistics.startStatistics(); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-31 02:28:40 +04:00
										 |  |  |     if (Common.isLiquid()) { | 
					
						
							| 
									
										
										
										
											2024-03-07 02:21:38 +09:00
										 |  |  |       const refreshIcons = () => { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           icons.loadIcons(); | 
					
						
							|  |  |  |         } catch (e) { | 
					
						
							|  |  |  |           logger.err('Cannot load liquid icons. Ignoring. Reason: ' + (e instanceof Error ? e.message : e)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }; | 
					
						
							|  |  |  |       // Run once on startup.
 | 
					
						
							|  |  |  |       refreshIcons(); | 
					
						
							| 
									
										
										
										
											2024-03-07 11:09:08 +07:00
										 |  |  |       // Matches crontab refresh interval for asset db.
 | 
					
						
							|  |  |  |       setInterval(refreshIcons, 3600_000); | 
					
						
							| 
									
										
										
										
											2021-12-21 02:00:50 +04:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:19 +01:00
										 |  |  |     if (config.FIAT_PRICE.ENABLED) { | 
					
						
							|  |  |  |       priceUpdater.$run(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-02-18 14:10:07 +09:00
										 |  |  |     await chainTips.updateOrphanedBlocks(); | 
					
						
							| 
									
										
										
										
											2021-01-30 22:12:22 +07:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-02-26 17:49:53 +07:00
										 |  |  |     this.setUpHttpApiRoutes(); | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  | 
 | 
					
						
							|  |  |  |     if (config.MEMPOOL.ENABLED) { | 
					
						
							|  |  |  |       this.runMainUpdateLoop(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-03-04 23:13:55 -06:00
										 |  |  |     setInterval(() => { this.healthCheck(); }, 2500); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-07-06 11:58:06 +02:00
										 |  |  |     if (config.LIGHTNING.ENABLED) { | 
					
						
							| 
									
										
										
										
											2022-08-03 12:43:41 +02:00
										 |  |  |       this.$runLightningBackend(); | 
					
						
							| 
									
										
										
										
											2022-07-06 11:58:06 +02:00
										 |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2020-10-19 11:57:02 +07:00
										 |  |  |     this.server.listen(config.MEMPOOL.HTTP_PORT, () => { | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       if (worker) { | 
					
						
							| 
									
										
										
										
											2020-10-13 15:27:52 +07:00
										 |  |  |         logger.info(`Mempool Server worker #${process.pid} started`); | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       } else { | 
					
						
							| 
									
										
										
										
											2021-01-20 01:34:21 +07:00
										 |  |  |         logger.notice(`Mempool Server is running on port ${config.MEMPOOL.HTTP_PORT}`); | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |     }); | 
					
						
							| 
									
										
										
										
											2024-04-07 18:39:37 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2024-04-09 15:11:40 +09:00
										 |  |  |     if (this.serverUnixSocket) { | 
					
						
							|  |  |  |       this.serverUnixSocket.listen(config.MEMPOOL.UNIX_SOCKET_PATH, () => { | 
					
						
							|  |  |  |         if (worker) { | 
					
						
							|  |  |  |           logger.info(`Mempool Server worker #${process.pid} started`); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           logger.notice(`Mempool Server is listening on ${config.MEMPOOL.UNIX_SOCKET_PATH}`); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |   async runMainUpdateLoop(): Promise<void> { | 
					
						
							| 
									
										
										
										
											2023-07-17 18:21:44 +09:00
										 |  |  |     const start = Date.now(); | 
					
						
							| 
									
										
										
										
											2020-10-18 21:47:47 +07:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2021-04-02 11:47:13 +04:00
										 |  |  |       try { | 
					
						
							|  |  |  |         await memPool.$updateMemPoolInfo(); | 
					
						
							|  |  |  |       } catch (e) { | 
					
						
							| 
									
										
										
										
											2021-08-31 15:09:33 +03:00
										 |  |  |         const msg = `updateMempoolInfo: ${(e instanceof Error ? e.message : e)}`; | 
					
						
							| 
									
										
										
										
											2021-09-19 02:40:16 +04:00
										 |  |  |         if (config.MEMPOOL.USE_SECOND_NODE_FOR_MINFEE) { | 
					
						
							| 
									
										
										
										
											2021-04-02 11:47:13 +04:00
										 |  |  |           logger.warn(msg); | 
					
						
							|  |  |  |         } else { | 
					
						
							|  |  |  |           logger.debug(msg); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-04-07 09:41:25 +09:00
										 |  |  |       const newMempool = await bitcoinApi.$getRawMempool(); | 
					
						
							| 
									
										
										
										
											2023-02-17 17:54:29 -06:00
										 |  |  |       const minFeeMempool = memPool.limitGBT ? await bitcoinSecondClient.getRawMemPool() : null; | 
					
						
							|  |  |  |       const minFeeTip = memPool.limitGBT ? await bitcoinSecondClient.getBlockCount() : -1; | 
					
						
							| 
									
										
										
										
											2024-07-23 14:00:23 +00:00
										 |  |  |       const newAccelerations = await accelerationApi.$updateAccelerations(); | 
					
						
							| 
									
										
										
										
											2023-04-07 09:41:25 +09:00
										 |  |  |       const numHandledBlocks = await blocks.$updateBlocks(); | 
					
						
							| 
									
										
										
										
											2023-09-21 17:50:53 +01:00
										 |  |  |       const pollRate = config.MEMPOOL.POLL_RATE_MS * (indexer.indexerIsRunning() ? 10 : 1); | 
					
						
							| 
									
										
										
										
											2023-04-07 09:41:25 +09:00
										 |  |  |       if (numHandledBlocks === 0) { | 
					
						
							| 
									
										
										
										
											2023-02-17 17:54:29 -06:00
										 |  |  |         await memPool.$updateMempool(newMempool, newAccelerations, minFeeMempool, minFeeTip, pollRate); | 
					
						
							| 
									
										
										
										
											2023-04-07 09:41:25 +09:00
										 |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-05-19 16:40:38 +02:00
										 |  |  |       indexer.$run(); | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:19 +01:00
										 |  |  |       if (config.FIAT_PRICE.ENABLED) { | 
					
						
							|  |  |  |         priceUpdater.$run(); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2022-01-05 15:41:14 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-07 09:41:25 +09:00
										 |  |  |       // rerun immediately if we skipped the mempool update, otherwise wait POLL_RATE_MS
 | 
					
						
							| 
									
										
										
										
											2023-07-17 18:21:44 +09:00
										 |  |  |       const elapsed = Date.now() - start; | 
					
						
							| 
									
										
										
										
											2023-07-31 16:41:36 +09:00
										 |  |  |       const remainingTime = Math.max(0, pollRate - elapsed); | 
					
						
							| 
									
										
										
										
											2023-07-17 18:21:44 +09:00
										 |  |  |       setTimeout(this.runMainUpdateLoop.bind(this), numHandledBlocks > 0 ? 0 : remainingTime); | 
					
						
							| 
									
										
										
										
											2023-05-03 10:11:44 +04:00
										 |  |  |       this.backendRetryCount = 0; | 
					
						
							| 
									
										
										
										
											2023-02-07 20:56:33 -06:00
										 |  |  |     } catch (e: any) { | 
					
						
							| 
									
										
										
										
											2023-05-03 10:11:44 +04:00
										 |  |  |       this.backendRetryCount++; | 
					
						
							|  |  |  |       let loggerMsg = `Exception in runMainUpdateLoop() (count: ${this.backendRetryCount}). Retrying in ${this.currentBackendRetryInterval} sec.`; | 
					
						
							| 
									
										
										
										
											2023-02-27 18:00:00 +09:00
										 |  |  |       loggerMsg += ` Reason: ${(e instanceof Error ? e.message : e)}.`; | 
					
						
							|  |  |  |       if (e?.stack) { | 
					
						
							|  |  |  |         loggerMsg += ` Stack trace: ${e.stack}`; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       // When we get a first Exception, only `logger.debug` it and retry after 5 seconds
 | 
					
						
							|  |  |  |       // From the second Exception, `logger.warn` the Exception and increase the retry delay
 | 
					
						
							| 
									
										
										
										
											2023-05-03 10:11:44 +04:00
										 |  |  |       if (this.backendRetryCount >= 5) { | 
					
						
							| 
									
										
										
										
											2020-10-23 16:27:02 +07:00
										 |  |  |         logger.warn(loggerMsg); | 
					
						
							| 
									
										
										
										
											2021-01-20 17:16:43 +07:00
										 |  |  |         mempool.setOutOfSync(); | 
					
						
							| 
									
										
										
										
											2020-10-23 16:27:02 +07:00
										 |  |  |       } else { | 
					
						
							|  |  |  |         logger.debug(loggerMsg); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2023-02-07 20:56:33 -06:00
										 |  |  |       if (e instanceof AxiosError) { | 
					
						
							|  |  |  |         logger.debug(`AxiosError: ${e?.message}`); | 
					
						
							|  |  |  |       } | 
					
						
							| 
									
										
										
										
											2021-01-06 22:49:28 +07:00
										 |  |  |       setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); | 
					
						
							| 
									
										
										
										
											2023-05-01 14:30:30 -06:00
										 |  |  |     } finally { | 
					
						
							|  |  |  |       diskCache.unlock(); | 
					
						
							| 
									
										
										
										
											2020-10-18 21:47:47 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |   async $runLightningBackend(): Promise<void> { | 
					
						
							| 
									
										
										
										
											2022-08-03 12:43:41 +02:00
										 |  |  |     try { | 
					
						
							|  |  |  |       await fundingTxFetcher.$init(); | 
					
						
							|  |  |  |       await networkSyncService.$startService(); | 
					
						
							|  |  |  |       await lightningStatsUpdater.$startService(); | 
					
						
							| 
									
										
										
										
											2023-03-01 16:52:24 +09:00
										 |  |  |       await forensicsService.$startService(); | 
					
						
							| 
									
										
										
										
											2022-08-03 12:43:41 +02:00
										 |  |  |     } catch(e) { | 
					
						
							| 
									
										
										
										
											2023-03-20 20:46:11 +09:00
										 |  |  |       logger.err(`Exception in $runLightningBackend. Restarting in 1 minute. Reason: ${(e instanceof Error ? e.message : e)}`); | 
					
						
							| 
									
										
										
										
											2022-08-03 12:43:41 +02:00
										 |  |  |       await Common.sleep$(1000 * 60); | 
					
						
							|  |  |  |       this.$runLightningBackend(); | 
					
						
							|  |  |  |     }; | 
					
						
							| 
									
										
										
										
											2023-03-20 20:46:11 +09:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-03 12:43:41 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |   setUpWebsocketHandling(): void { | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |     if (this.wss) { | 
					
						
							| 
									
										
										
										
											2024-04-07 18:39:37 +09:00
										 |  |  |       websocketHandler.addWebsocketServer(this.wss); | 
					
						
							| 
									
										
										
										
											2020-09-22 03:52:54 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-07 18:39:37 +09:00
										 |  |  |     if (this.wssUnixSocket) { | 
					
						
							|  |  |  |       websocketHandler.addWebsocketServer(this.wssUnixSocket); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-12-31 02:28:40 +04:00
										 |  |  |     if (Common.isLiquid() && config.DATABASE.ENABLED) { | 
					
						
							| 
									
										
										
										
											2021-09-18 13:37:25 +04:00
										 |  |  |       blocks.setNewBlockCallback(async () => { | 
					
						
							|  |  |  |         try { | 
					
						
							|  |  |  |           await elementsParser.$parse(); | 
					
						
							| 
									
										
										
										
											2024-01-20 15:15:15 +01:00
										 |  |  |           await elementsParser.$updateFederationUtxos(); | 
					
						
							| 
									
										
										
										
											2021-09-18 13:37:25 +04:00
										 |  |  |         } catch (e) { | 
					
						
							|  |  |  |           logger.warn('Elements parsing error: ' + (e instanceof Error ? e.message : e)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-26 17:49:53 +07:00
										 |  |  |     websocketHandler.setupConnectionHandling(); | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |     if (config.MEMPOOL.ENABLED) { | 
					
						
							|  |  |  |       statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler)); | 
					
						
							| 
									
										
										
										
											2023-04-30 15:28:34 -06:00
										 |  |  |       memPool.setAsyncMempoolChangedCallback(websocketHandler.$handleMempoolChange.bind(websocketHandler)); | 
					
						
							| 
									
										
										
										
											2022-11-20 16:12:39 +09:00
										 |  |  |       blocks.setNewAsyncBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler)); | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-03-10 17:12:19 +01:00
										 |  |  |     if (config.FIAT_PRICE.ENABLED) { | 
					
						
							|  |  |  |       priceUpdater.setRatesChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler)); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-01-05 18:57:06 +07:00
										 |  |  |     loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler)); | 
					
						
							| 
									
										
										
										
											2019-07-21 17:59:47 +03:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |    | 
					
						
							|  |  |  |   setUpHttpApiRoutes(): void { | 
					
						
							| 
									
										
										
										
											2022-07-11 19:15:28 +02:00
										 |  |  |     bitcoinRoutes.initRoutes(this.app); | 
					
						
							| 
									
										
										
										
											2024-01-08 11:48:55 +01:00
										 |  |  |     bitcoinCoreRoutes.initRoutes(this.app); | 
					
						
							| 
									
										
										
										
											2023-07-29 14:23:06 +09:00
										 |  |  |     pricesRoutes.initRoutes(this.app); | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |     if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && config.MEMPOOL.ENABLED) { | 
					
						
							| 
									
										
										
										
											2022-07-11 19:15:28 +02:00
										 |  |  |       statisticsRoutes.initRoutes(this.app); | 
					
						
							| 
									
										
										
										
											2022-02-08 18:28:53 +09:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  |     if (Common.indexingEnabled() && config.MEMPOOL.ENABLED) { | 
					
						
							| 
									
										
										
										
											2022-07-11 19:15:28 +02:00
										 |  |  |       miningRoutes.initRoutes(this.app); | 
					
						
							| 
									
										
										
										
											2020-10-19 18:47:10 +07:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2021-12-31 02:28:40 +04:00
										 |  |  |     if (Common.isLiquid()) { | 
					
						
							| 
									
										
										
										
											2022-07-11 19:15:28 +02:00
										 |  |  |       liquidRoutes.initRoutes(this.app); | 
					
						
							| 
									
										
										
										
											2021-12-14 16:06:03 +04:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2022-07-06 11:58:06 +02:00
										 |  |  |     if (config.LIGHTNING.ENABLED) { | 
					
						
							|  |  |  |       generalLightningRoutes.initRoutes(this.app); | 
					
						
							|  |  |  |       nodesRoutes.initRoutes(this.app); | 
					
						
							|  |  |  |       channelsRoutes.initRoutes(this.app); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-04 12:57:54 +09:00
										 |  |  |     if (config.MEMPOOL_SERVICES.ACCELERATIONS) { | 
					
						
							|  |  |  |       accelerationRoutes.initRoutes(this.app); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-07-09 06:27:26 +00:00
										 |  |  |     if (!config.MEMPOOL.OFFICIAL) { | 
					
						
							|  |  |  |       aboutRoutes.initRoutes(this.app); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2020-02-26 17:49:53 +07:00
										 |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-03-04 23:13:55 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |   healthCheck(): void { | 
					
						
							|  |  |  |     const now = Date.now(); | 
					
						
							|  |  |  |     const stats = v8.getHeapStatistics(); | 
					
						
							|  |  |  |     this.maxHeapSize = Math.max(stats.used_heap_size, this.maxHeapSize); | 
					
						
							| 
									
										
										
										
											2023-03-05 15:45:28 +09:00
										 |  |  |     const warnThreshold = 0.8 * stats.heap_size_limit; | 
					
						
							| 
									
										
										
										
											2023-03-04 23:13:55 -06:00
										 |  |  | 
 | 
					
						
							|  |  |  |     const byteUnits = getBytesUnit(Math.max(this.maxHeapSize, stats.heap_size_limit)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |     if (!this.warnedHeapCritical && this.maxHeapSize > warnThreshold) { | 
					
						
							|  |  |  |       this.warnedHeapCritical = true; | 
					
						
							| 
									
										
										
										
											2023-03-16 14:35:09 +09:00
										 |  |  |       logger.warn(`Used ${(this.maxHeapSize / stats.heap_size_limit * 100).toFixed(2)}% of heap limit (${formatBytes(this.maxHeapSize, byteUnits, true)} / ${formatBytes(stats.heap_size_limit, byteUnits)})!`); | 
					
						
							| 
									
										
										
										
											2023-03-04 23:13:55 -06:00
										 |  |  |     } | 
					
						
							|  |  |  |     if (this.lastHeapLogTime === null || (now - this.lastHeapLogTime) > (this.heapLogInterval * 1000)) { | 
					
						
							|  |  |  |       logger.debug(`Memory usage: ${formatBytes(this.maxHeapSize, byteUnits)} / ${formatBytes(stats.heap_size_limit, byteUnits)}`); | 
					
						
							|  |  |  |       this.warnedHeapCritical = false; | 
					
						
							|  |  |  |       this.maxHeapSize = 0; | 
					
						
							|  |  |  |       this.lastHeapLogTime = now; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-14 05:00:05 +00:00
										 |  |  |   onExit(exitEvent, code = 0): void { | 
					
						
							|  |  |  |     logger.debug(`onExit for signal: ${exitEvent}`); | 
					
						
							| 
									
										
										
										
											2023-10-01 16:38:45 +01:00
										 |  |  |     if (config.DATABASE.ENABLED) { | 
					
						
							|  |  |  |       DB.releasePidLock(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2024-04-07 18:39:37 +09:00
										 |  |  |     this.server?.close(); | 
					
						
							|  |  |  |     this.serverUnixSocket?.close(); | 
					
						
							|  |  |  |     this.wss?.close(); | 
					
						
							| 
									
										
										
										
											2024-04-09 15:11:40 +09:00
										 |  |  |     if (this.wssUnixSocket) { | 
					
						
							|  |  |  |       this.wssUnixSocket.close(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-11-14 05:00:05 +00:00
										 |  |  |     process.exit(code); | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-11-14 05:00:05 +00:00
										 |  |  |   onUnhandledException(type, error): void { | 
					
						
							|  |  |  |     console.error(`${type}:`, error); | 
					
						
							|  |  |  |     this.onExit(type, 1); | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | } | 
					
						
							| 
									
										
										
										
											2023-08-28 19:20:58 +09:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2022-08-23 20:25:29 +04:00
										 |  |  | ((): Server => new Server())(); |