Replacing ln-service library and wait for graph sync.
This commit is contained in:
		
							parent
							
								
									1f2254681a
								
							
						
					
					
						commit
						73c4a934ce
					
				@ -37,7 +37,7 @@
 | 
			
		||||
    "bolt07": "^1.8.1",
 | 
			
		||||
    "crypto-js": "^4.0.0",
 | 
			
		||||
    "express": "^4.18.0",
 | 
			
		||||
    "ln-service": "^53.17.4",
 | 
			
		||||
    "lightning": "^5.16.3",
 | 
			
		||||
    "mysql2": "2.3.3",
 | 
			
		||||
    "node-worker-threads-pool": "^1.5.1",
 | 
			
		||||
    "socks-proxy-agent": "~7.0.0",
 | 
			
		||||
 | 
			
		||||
@ -3,5 +3,5 @@ import { ILightningApi } from './lightning-api.interface';
 | 
			
		||||
export interface AbstractLightningApi {
 | 
			
		||||
  $getNetworkInfo(): Promise<ILightningApi.NetworkInfo>;
 | 
			
		||||
  $getNetworkGraph(): Promise<ILightningApi.NetworkGraph>;
 | 
			
		||||
  $getChanInfo(id: string): Promise<ILightningApi.Channel>;
 | 
			
		||||
  $getInfo(): Promise<ILightningApi.Info>;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -21,17 +21,17 @@ export namespace ILightningApi {
 | 
			
		||||
    policies: Policy[];
 | 
			
		||||
    transaction_id: string;
 | 
			
		||||
    transaction_vout: number;
 | 
			
		||||
    updated_at: string;
 | 
			
		||||
    updated_at?: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  interface Policy {
 | 
			
		||||
    public_key: string;
 | 
			
		||||
    base_fee_mtokens?: number;
 | 
			
		||||
    base_fee_mtokens?: string;
 | 
			
		||||
    cltv_delta?: number;
 | 
			
		||||
    fee_rate?: number;
 | 
			
		||||
    is_disabled?: boolean;
 | 
			
		||||
    max_htlc_mtokens?: number;
 | 
			
		||||
    min_htlc_mtokens?: number;
 | 
			
		||||
    max_htlc_mtokens?: string;
 | 
			
		||||
    min_htlc_mtokens?: string;
 | 
			
		||||
    updated_at?: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
@ -41,13 +41,31 @@ export namespace ILightningApi {
 | 
			
		||||
    features: Feature[];
 | 
			
		||||
    public_key: string;
 | 
			
		||||
    sockets: string[];
 | 
			
		||||
    updated_at: string;
 | 
			
		||||
    updated_at?: string;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  interface Feature {
 | 
			
		||||
  export interface Info {
 | 
			
		||||
    chains: string[];
 | 
			
		||||
    color: string;
 | 
			
		||||
    active_channels_count: number;
 | 
			
		||||
    alias: string;
 | 
			
		||||
    current_block_hash: string;
 | 
			
		||||
    current_block_height: number;
 | 
			
		||||
    features: Feature[];
 | 
			
		||||
    is_synced_to_chain: boolean;
 | 
			
		||||
    is_synced_to_graph: boolean;
 | 
			
		||||
    latest_block_at: string;
 | 
			
		||||
    peers_count: number;
 | 
			
		||||
    pending_channels_count: number;
 | 
			
		||||
    public_key: string;
 | 
			
		||||
    uris: any[];
 | 
			
		||||
    version: string;
 | 
			
		||||
  }
 | 
			
		||||
  
 | 
			
		||||
  export interface Feature {
 | 
			
		||||
    bit: number;
 | 
			
		||||
    is_known: boolean;
 | 
			
		||||
    is_required: boolean;
 | 
			
		||||
    type: string;
 | 
			
		||||
    type?: string;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { AbstractLightningApi } from '../lightning-api-abstract-factory';
 | 
			
		||||
import { ILightningApi } from '../lightning-api.interface';
 | 
			
		||||
import * as fs from 'fs';
 | 
			
		||||
import * as lnService from 'ln-service';
 | 
			
		||||
import { authenticatedLndGrpc, getWalletInfo, getNetworkGraph, getNetworkInfo } from 'lightning';
 | 
			
		||||
import config from '../../../config';
 | 
			
		||||
import logger from '../../../logger';
 | 
			
		||||
 | 
			
		||||
@ -15,7 +15,7 @@ class LndApi implements AbstractLightningApi {
 | 
			
		||||
      const tls = fs.readFileSync(config.LND.TLS_CERT_PATH).toString('base64');
 | 
			
		||||
      const macaroon = fs.readFileSync(config.LND.MACAROON_PATH).toString('base64');
 | 
			
		||||
 | 
			
		||||
      const { lnd } = lnService.authenticatedLndGrpc({
 | 
			
		||||
      const { lnd } = authenticatedLndGrpc({
 | 
			
		||||
        cert: tls,
 | 
			
		||||
        macaroon: macaroon,
 | 
			
		||||
        socket: config.LND.SOCKET,
 | 
			
		||||
@ -29,15 +29,16 @@ class LndApi implements AbstractLightningApi {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async $getNetworkInfo(): Promise<ILightningApi.NetworkInfo> {
 | 
			
		||||
    return await lnService.getNetworkInfo({ lnd: this.lnd });
 | 
			
		||||
    return await getNetworkInfo({ lnd: this.lnd });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async $getInfo(): Promise<ILightningApi.Info> {
 | 
			
		||||
    // @ts-ignore
 | 
			
		||||
    return await getWalletInfo({ lnd: this.lnd });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async $getNetworkGraph(): Promise<ILightningApi.NetworkGraph> {
 | 
			
		||||
    return await lnService.getNetworkGraph({ lnd: this.lnd });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  async $getChanInfo(id: string): Promise<ILightningApi.Channel> {
 | 
			
		||||
    return await lnService.getChannel({ lnd: this.lnd, id });
 | 
			
		||||
    return await getNetworkGraph({ lnd: this.lnd });
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
import express from "express";
 | 
			
		||||
import { Application, Request, Response, NextFunction, Express } from 'express';
 | 
			
		||||
import { Application, Request, Response, NextFunction } from 'express';
 | 
			
		||||
import * as http from 'http';
 | 
			
		||||
import * as WebSocket from 'ws';
 | 
			
		||||
import cluster from 'cluster';
 | 
			
		||||
@ -28,12 +28,12 @@ import { Common } from './api/common';
 | 
			
		||||
import poolsUpdater from './tasks/pools-updater';
 | 
			
		||||
import indexer from './indexer';
 | 
			
		||||
import priceUpdater from './tasks/price-updater';
 | 
			
		||||
import BlocksAuditsRepository from './repositories/BlocksAuditsRepository';
 | 
			
		||||
import nodeSyncService from './tasks/lightning/node-sync.service';
 | 
			
		||||
import lightningStatsUpdater from './tasks/lightning/stats-updater.service';
 | 
			
		||||
import nodesRoutes from './api/explorer/nodes.routes';
 | 
			
		||||
import channelsRoutes from './api/explorer/channels.routes';
 | 
			
		||||
import generalLightningRoutes from './api/explorer/general.routes';
 | 
			
		||||
import lightningStatsUpdater from './tasks/lightning/stats-updater.service';
 | 
			
		||||
import nodeSyncService from './tasks/lightning/node-sync.service';
 | 
			
		||||
import BlocksAuditsRepository from './repositories/BlocksAuditsRepository';
 | 
			
		||||
 | 
			
		||||
class Server {
 | 
			
		||||
  private wss: WebSocket.Server | undefined;
 | 
			
		||||
@ -137,9 +137,7 @@ class Server {
 | 
			
		||||
 | 
			
		||||
    if (config.LIGHTNING.ENABLED) {
 | 
			
		||||
      nodeSyncService.$startService()
 | 
			
		||||
        .then(() => {
 | 
			
		||||
          lightningStatsUpdater.$startService();
 | 
			
		||||
        });
 | 
			
		||||
        .then(() => lightningStatsUpdater.$startService());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.server.listen(config.MEMPOOL.HTTP_PORT, () => {
 | 
			
		||||
 | 
			
		||||
@ -245,7 +245,6 @@ class NodeSyncService {
 | 
			
		||||
    const fromChannel = chanNumber({ channel: channel.id }).number;
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const d = new Date(Date.parse(channel.updated_at));
 | 
			
		||||
      const query = `INSERT INTO channels
 | 
			
		||||
        (
 | 
			
		||||
          id,
 | 
			
		||||
@ -360,7 +359,7 @@ class NodeSyncService {
 | 
			
		||||
 | 
			
		||||
  private async $saveNode(node: ILightningApi.Node): Promise<void> {
 | 
			
		||||
    try {
 | 
			
		||||
      const updatedAt = this.utcDateToMysql(node.updated_at);
 | 
			
		||||
      const updatedAt = node.updated_at ? this.utcDateToMysql(node.updated_at) : '0000-00-00 00:00:00';
 | 
			
		||||
      const sockets = node.sockets.join(',');
 | 
			
		||||
      const query = `INSERT INTO nodes(
 | 
			
		||||
          public_key,
 | 
			
		||||
 | 
			
		||||
@ -6,21 +6,43 @@ class LightningStatsUpdater {
 | 
			
		||||
  constructor() {}
 | 
			
		||||
 | 
			
		||||
  public async $startService() {
 | 
			
		||||
    logger.info('Starting Stats service');
 | 
			
		||||
    logger.info('Starting Lightning Stats service');
 | 
			
		||||
    let isInSync = false;
 | 
			
		||||
    let error: any;
 | 
			
		||||
    try {
 | 
			
		||||
      error = null;
 | 
			
		||||
      isInSync = await this.$lightningIsSynced();
 | 
			
		||||
    } catch (e) {
 | 
			
		||||
      error = e;
 | 
			
		||||
    }
 | 
			
		||||
    if (!isInSync) {
 | 
			
		||||
      if (error) {
 | 
			
		||||
        logger.warn('Was not able to fetch Lightning Node status: ' + (error instanceof Error ? error.message : error) + '. Retrying in 1 minute...');
 | 
			
		||||
      } else {
 | 
			
		||||
        logger.notice('The Lightning graph is not yet in sync. Retrying in 1 minute...');
 | 
			
		||||
      }
 | 
			
		||||
      setTimeout(() => this.$startService(), 60 * 1000);
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const now = new Date();
 | 
			
		||||
    const nextHourInterval = new Date(now.getFullYear(), now.getMonth(), now.getDate(), Math.floor(now.getHours() / 1) + 1, 0, 0, 0);
 | 
			
		||||
    const difference = nextHourInterval.getTime() - now.getTime();
 | 
			
		||||
 | 
			
		||||
    // setTimeout(() => {
 | 
			
		||||
    setTimeout(() => {
 | 
			
		||||
      setInterval(async () => {
 | 
			
		||||
        await this.$runTasks();
 | 
			
		||||
      }, 1000 * 60 * 60);
 | 
			
		||||
    //}, difference);
 | 
			
		||||
    }, difference);
 | 
			
		||||
 | 
			
		||||
    await this.$runTasks();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $lightningIsSynced(): Promise<boolean> {
 | 
			
		||||
    const nodeInfo = await lightningApi.$getInfo();
 | 
			
		||||
    return nodeInfo.is_synced_to_chain && nodeInfo.is_synced_to_graph;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $runTasks() {
 | 
			
		||||
    await this.$populateHistoricalData();
 | 
			
		||||
    await this.$logLightningStatsDaily();
 | 
			
		||||
@ -28,8 +50,6 @@ class LightningStatsUpdater {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $logNodeStatsDaily() {
 | 
			
		||||
    logger.info(`Running daily node stats update...`);
 | 
			
		||||
 | 
			
		||||
    const currentDate = new Date().toISOString().split('T')[0];
 | 
			
		||||
    try {
 | 
			
		||||
      const [state]: any = await DB.query(`SELECT string FROM state WHERE name = 'last_node_stats'`);
 | 
			
		||||
@ -38,6 +58,8 @@ class LightningStatsUpdater {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      logger.info(`Running daily node stats update...`);
 | 
			
		||||
 | 
			
		||||
      const query = `SELECT nodes.public_key, c1.channels_count_left, c2.channels_count_right, c1.channels_capacity_left, c2.channels_capacity_right FROM nodes LEFT JOIN (SELECT node1_public_key, COUNT(id) AS channels_count_left, SUM(capacity) AS channels_capacity_left FROM channels WHERE channels.status < 2 GROUP BY node1_public_key) c1 ON c1.node1_public_key = nodes.public_key LEFT JOIN (SELECT node2_public_key, COUNT(id) AS channels_count_right, SUM(capacity) AS channels_capacity_right FROM channels WHERE channels.status < 2 GROUP BY node2_public_key) c2 ON c2.node2_public_key = nodes.public_key`;
 | 
			
		||||
      const [nodes]: any = await DB.query(query);
 | 
			
		||||
 | 
			
		||||
@ -61,8 +83,6 @@ class LightningStatsUpdater {
 | 
			
		||||
 | 
			
		||||
  // We only run this on first launch
 | 
			
		||||
  private async $populateHistoricalData() {
 | 
			
		||||
    logger.info(`Running historical stats population...`);
 | 
			
		||||
 | 
			
		||||
    const startTime = '2018-01-13';
 | 
			
		||||
    try {
 | 
			
		||||
      const [rows]: any = await DB.query(`SELECT COUNT(*) FROM lightning_stats`);
 | 
			
		||||
@ -70,6 +90,8 @@ class LightningStatsUpdater {
 | 
			
		||||
      if (rows[0]['COUNT(*)'] > 0) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      logger.info(`Running historical stats population...`);
 | 
			
		||||
 | 
			
		||||
      const [channels]: any = await DB.query(`SELECT capacity, created, closing_date FROM channels ORDER BY created ASC`);
 | 
			
		||||
 | 
			
		||||
      let date: Date = new Date(startTime);
 | 
			
		||||
@ -138,8 +160,6 @@ class LightningStatsUpdater {
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $logLightningStatsDaily() {
 | 
			
		||||
    logger.info(`Running lightning daily stats log...`);
 | 
			
		||||
 | 
			
		||||
    const currentDate = new Date().toISOString().split('T')[0];
 | 
			
		||||
    try {
 | 
			
		||||
      const [state]: any = await DB.query(`SELECT string FROM state WHERE name = 'last_node_stats'`);
 | 
			
		||||
@ -148,6 +168,8 @@ class LightningStatsUpdater {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      logger.info(`Running lightning daily stats log...`);  
 | 
			
		||||
 | 
			
		||||
      const networkGraph = await lightningApi.$getNetworkGraph();
 | 
			
		||||
      let total_capacity = 0;
 | 
			
		||||
      for (const channel of networkGraph.channels) {
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user