Merge branch 'master' into frontend_runtime_config
This commit is contained in:
		
						commit
						235ac204b4
					
				@ -2,6 +2,7 @@
 | 
				
			|||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
    "NETWORK": "mainnet",
 | 
					    "NETWORK": "mainnet",
 | 
				
			||||||
    "BACKEND": "electrum",
 | 
					    "BACKEND": "electrum",
 | 
				
			||||||
 | 
					    "ENABLED": true,
 | 
				
			||||||
    "HTTP_PORT": 8999,
 | 
					    "HTTP_PORT": 8999,
 | 
				
			||||||
    "SPAWN_CLUSTER_PROCS": 0,
 | 
					    "SPAWN_CLUSTER_PROCS": 0,
 | 
				
			||||||
    "API_URL_PREFIX": "/api/v1/",
 | 
					    "API_URL_PREFIX": "/api/v1/",
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,9 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
 | 
					    "ENABLED": true,
 | 
				
			||||||
    "NETWORK": "__MEMPOOL_NETWORK__",
 | 
					    "NETWORK": "__MEMPOOL_NETWORK__",
 | 
				
			||||||
    "BACKEND": "__MEMPOOL_BACKEND__",
 | 
					    "BACKEND": "__MEMPOOL_BACKEND__",
 | 
				
			||||||
 | 
					    "ENABLED": true,
 | 
				
			||||||
    "BLOCKS_SUMMARIES_INDEXING": true,
 | 
					    "BLOCKS_SUMMARIES_INDEXING": true,
 | 
				
			||||||
    "HTTP_PORT": 1,
 | 
					    "HTTP_PORT": 1,
 | 
				
			||||||
    "SPAWN_CLUSTER_PROCS": 2,
 | 
					    "SPAWN_CLUSTER_PROCS": 2,
 | 
				
			||||||
 | 
				
			|||||||
@ -13,6 +13,7 @@ describe('Mempool Backend Config', () => {
 | 
				
			|||||||
      const config = jest.requireActual('../config').default;
 | 
					      const config = jest.requireActual('../config').default;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      expect(config.MEMPOOL).toStrictEqual({
 | 
					      expect(config.MEMPOOL).toStrictEqual({
 | 
				
			||||||
 | 
					        ENABLED: true,
 | 
				
			||||||
        NETWORK: 'mainnet',
 | 
					        NETWORK: 'mainnet',
 | 
				
			||||||
        BACKEND: 'none',
 | 
					        BACKEND: 'none',
 | 
				
			||||||
        BLOCKS_SUMMARIES_INDEXING: false,
 | 
					        BLOCKS_SUMMARIES_INDEXING: false,
 | 
				
			||||||
 | 
				
			|||||||
@ -103,12 +103,11 @@ class Mempool {
 | 
				
			|||||||
    return txTimes;
 | 
					    return txTimes;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public async $updateMempool() {
 | 
					  public async $updateMempool(): Promise<void> {
 | 
				
			||||||
    logger.debug('Updating mempool');
 | 
					    logger.debug(`Updating mempool...`);
 | 
				
			||||||
    const start = new Date().getTime();
 | 
					    const start = new Date().getTime();
 | 
				
			||||||
    let hasChange: boolean = false;
 | 
					    let hasChange: boolean = false;
 | 
				
			||||||
    const currentMempoolSize = Object.keys(this.mempoolCache).length;
 | 
					    const currentMempoolSize = Object.keys(this.mempoolCache).length;
 | 
				
			||||||
    let txCount = 0;
 | 
					 | 
				
			||||||
    const transactions = await bitcoinApi.$getRawMempool();
 | 
					    const transactions = await bitcoinApi.$getRawMempool();
 | 
				
			||||||
    const diff = transactions.length - currentMempoolSize;
 | 
					    const diff = transactions.length - currentMempoolSize;
 | 
				
			||||||
    const newTransactions: TransactionExtended[] = [];
 | 
					    const newTransactions: TransactionExtended[] = [];
 | 
				
			||||||
@ -124,7 +123,6 @@ class Mempool {
 | 
				
			|||||||
        try {
 | 
					        try {
 | 
				
			||||||
          const transaction = await transactionUtils.$getTransactionExtended(txid);
 | 
					          const transaction = await transactionUtils.$getTransactionExtended(txid);
 | 
				
			||||||
          this.mempoolCache[txid] = transaction;
 | 
					          this.mempoolCache[txid] = transaction;
 | 
				
			||||||
          txCount++;
 | 
					 | 
				
			||||||
          if (this.inSync) {
 | 
					          if (this.inSync) {
 | 
				
			||||||
            this.txPerSecondArray.push(new Date().getTime());
 | 
					            this.txPerSecondArray.push(new Date().getTime());
 | 
				
			||||||
            this.vBytesPerSecondArray.push({
 | 
					            this.vBytesPerSecondArray.push({
 | 
				
			||||||
@ -133,14 +131,9 @@ class Mempool {
 | 
				
			|||||||
            });
 | 
					            });
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
          hasChange = true;
 | 
					          hasChange = true;
 | 
				
			||||||
          if (diff > 0) {
 | 
					 | 
				
			||||||
            logger.debug('Fetched transaction ' + txCount + ' / ' + diff);
 | 
					 | 
				
			||||||
          } else {
 | 
					 | 
				
			||||||
            logger.debug('Fetched transaction ' + txCount);
 | 
					 | 
				
			||||||
          }
 | 
					 | 
				
			||||||
          newTransactions.push(transaction);
 | 
					          newTransactions.push(transaction);
 | 
				
			||||||
        } catch (e) {
 | 
					        } catch (e) {
 | 
				
			||||||
          logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
 | 
					          logger.debug(`Error finding transaction '${txid}' in the mempool: ` + (e instanceof Error ? e.message : e));
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -197,8 +190,7 @@ class Mempool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    const end = new Date().getTime();
 | 
					    const end = new Date().getTime();
 | 
				
			||||||
    const time = end - start;
 | 
					    const time = end - start;
 | 
				
			||||||
    logger.debug(`New mempool size: ${Object.keys(this.mempoolCache).length} Change: ${diff}`);
 | 
					    logger.debug(`Mempool updated in ${time / 1000} seconds. New size: ${Object.keys(this.mempoolCache).length} (${diff > 0 ? '+' + diff : diff})`);
 | 
				
			||||||
    logger.debug('Mempool updated in ' + time / 1000 + ' seconds');
 | 
					 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  public handleRbfTransactions(rbfTransactions: { [txid: string]: TransactionExtended; }) {
 | 
					  public handleRbfTransactions(rbfTransactions: { [txid: string]: TransactionExtended; }) {
 | 
				
			||||||
 | 
				
			|||||||
@ -27,6 +27,7 @@ class MiningRoutes {
 | 
				
			|||||||
      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments/:interval', this.$getDifficultyAdjustments)
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments/:interval', this.$getDifficultyAdjustments)
 | 
				
			||||||
      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/predictions/:interval', this.$getHistoricalBlockPrediction)
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/predictions/:interval', this.$getHistoricalBlockPrediction)
 | 
				
			||||||
      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/:hash', this.$getBlockAudit)
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/:hash', this.$getBlockAudit)
 | 
				
			||||||
 | 
					      .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/timestamp/:timestamp', this.$getHeightFromTimestamp)
 | 
				
			||||||
    ;
 | 
					    ;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -252,6 +253,29 @@ class MiningRoutes {
 | 
				
			|||||||
      res.status(500).send(e instanceof Error ? e.message : e);
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  private async $getHeightFromTimestamp(req: Request, res: Response) {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      const timestamp = parseInt(req.params.timestamp, 10);
 | 
				
			||||||
 | 
					      // This will prevent people from entering milliseconds etc.
 | 
				
			||||||
 | 
					      // Block timestamps are allowed to be up to 2 hours off, so 24 hours
 | 
				
			||||||
 | 
					      // will never put the maximum value before the most recent block
 | 
				
			||||||
 | 
					      const nowPlus1day = Math.floor(Date.now() / 1000) + 60 * 60 * 24;
 | 
				
			||||||
 | 
					      // Prevent non-integers that are not seconds
 | 
				
			||||||
 | 
					      if (!/^[1-9][0-9]*$/.test(req.params.timestamp) || timestamp > nowPlus1day) {
 | 
				
			||||||
 | 
					        throw new Error(`Invalid timestamp, value must be Unix seconds`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      const result = await BlocksRepository.$getBlockHeightFromTimestamp(
 | 
				
			||||||
 | 
					        timestamp,
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      res.header('Pragma', 'public');
 | 
				
			||||||
 | 
					      res.header('Cache-control', 'public');
 | 
				
			||||||
 | 
					      res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
 | 
				
			||||||
 | 
					      res.json(result);
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      res.status(500).send(e instanceof Error ? e.message : e);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export default new MiningRoutes();
 | 
					export default new MiningRoutes();
 | 
				
			||||||
 | 
				
			|||||||
@ -4,6 +4,7 @@ const configFromFile = require(
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
interface IConfig {
 | 
					interface IConfig {
 | 
				
			||||||
  MEMPOOL: {
 | 
					  MEMPOOL: {
 | 
				
			||||||
 | 
					    ENABLED: boolean;
 | 
				
			||||||
    NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid' | 'liquidtestnet';
 | 
					    NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid' | 'liquidtestnet';
 | 
				
			||||||
    BACKEND: 'esplora' | 'electrum' | 'none';
 | 
					    BACKEND: 'esplora' | 'electrum' | 'none';
 | 
				
			||||||
    HTTP_PORT: number;
 | 
					    HTTP_PORT: number;
 | 
				
			||||||
@ -119,6 +120,7 @@ interface IConfig {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
const defaults: IConfig = {
 | 
					const defaults: IConfig = {
 | 
				
			||||||
  'MEMPOOL': {
 | 
					  'MEMPOOL': {
 | 
				
			||||||
 | 
					    'ENABLED': true,
 | 
				
			||||||
    'NETWORK': 'mainnet',
 | 
					    'NETWORK': 'mainnet',
 | 
				
			||||||
    'BACKEND': 'none',
 | 
					    'BACKEND': 'none',
 | 
				
			||||||
    'HTTP_PORT': 8999,
 | 
					    'HTTP_PORT': 8999,
 | 
				
			||||||
@ -224,11 +226,11 @@ const defaults: IConfig = {
 | 
				
			|||||||
    'BISQ_URL': 'https://bisq.markets/api',
 | 
					    'BISQ_URL': 'https://bisq.markets/api',
 | 
				
			||||||
    'BISQ_ONION': 'http://bisqmktse2cabavbr2xjq7xw3h6g5ottemo5rolfcwt6aly6tp5fdryd.onion/api'
 | 
					    'BISQ_ONION': 'http://bisqmktse2cabavbr2xjq7xw3h6g5ottemo5rolfcwt6aly6tp5fdryd.onion/api'
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
  "MAXMIND": {
 | 
					  'MAXMIND': {
 | 
				
			||||||
    'ENABLED': false,
 | 
					    'ENABLED': false,
 | 
				
			||||||
    "GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb",
 | 
					    'GEOLITE2_CITY': '/usr/local/share/GeoIP/GeoLite2-City.mmdb',
 | 
				
			||||||
    "GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb",
 | 
					    'GEOLITE2_ASN': '/usr/local/share/GeoIP/GeoLite2-ASN.mmdb',
 | 
				
			||||||
    "GEOIP2_ISP": "/usr/local/share/GeoIP/GeoIP2-ISP.mmdb"
 | 
					    'GEOIP2_ISP': '/usr/local/share/GeoIP/GeoIP2-ISP.mmdb'
 | 
				
			||||||
  },
 | 
					  },
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import express from "express";
 | 
					import express from 'express';
 | 
				
			||||||
import { Application, Request, Response, NextFunction } from 'express';
 | 
					import { Application, Request, Response, NextFunction } from 'express';
 | 
				
			||||||
import * as http from 'http';
 | 
					import * as http from 'http';
 | 
				
			||||||
import * as WebSocket from 'ws';
 | 
					import * as WebSocket from 'ws';
 | 
				
			||||||
@ -34,7 +34,7 @@ import miningRoutes from './api/mining/mining-routes';
 | 
				
			|||||||
import bisqRoutes from './api/bisq/bisq.routes';
 | 
					import bisqRoutes from './api/bisq/bisq.routes';
 | 
				
			||||||
import liquidRoutes from './api/liquid/liquid.routes';
 | 
					import liquidRoutes from './api/liquid/liquid.routes';
 | 
				
			||||||
import bitcoinRoutes from './api/bitcoin/bitcoin.routes';
 | 
					import bitcoinRoutes from './api/bitcoin/bitcoin.routes';
 | 
				
			||||||
import fundingTxFetcher from "./tasks/lightning/sync-tasks/funding-tx-fetcher";
 | 
					import fundingTxFetcher from './tasks/lightning/sync-tasks/funding-tx-fetcher';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class Server {
 | 
					class Server {
 | 
				
			||||||
  private wss: WebSocket.Server | undefined;
 | 
					  private wss: WebSocket.Server | undefined;
 | 
				
			||||||
@ -74,7 +74,7 @@ class Server {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async startServer(worker = false) {
 | 
					  async startServer(worker = false): Promise<void> {
 | 
				
			||||||
    logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`);
 | 
					    logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.app
 | 
					    this.app
 | 
				
			||||||
@ -92,7 +92,9 @@ class Server {
 | 
				
			|||||||
    this.setUpWebsocketHandling();
 | 
					    this.setUpWebsocketHandling();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    await syncAssets.syncAssets$();
 | 
					    await syncAssets.syncAssets$();
 | 
				
			||||||
    diskCache.loadMempoolCache();
 | 
					    if (config.MEMPOOL.ENABLED) {
 | 
				
			||||||
 | 
					      diskCache.loadMempoolCache();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.DATABASE.ENABLED) {
 | 
					    if (config.DATABASE.ENABLED) {
 | 
				
			||||||
      await DB.checkDbConnection();
 | 
					      await DB.checkDbConnection();
 | 
				
			||||||
@ -127,7 +129,10 @@ class Server {
 | 
				
			|||||||
    fiatConversion.startService();
 | 
					    fiatConversion.startService();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.setUpHttpApiRoutes();
 | 
					    this.setUpHttpApiRoutes();
 | 
				
			||||||
    this.runMainUpdateLoop();
 | 
					
 | 
				
			||||||
 | 
					    if (config.MEMPOOL.ENABLED) {
 | 
				
			||||||
 | 
					      this.runMainUpdateLoop();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (config.BISQ.ENABLED) {
 | 
					    if (config.BISQ.ENABLED) {
 | 
				
			||||||
      bisq.startBisqService();
 | 
					      bisq.startBisqService();
 | 
				
			||||||
@ -149,7 +154,7 @@ class Server {
 | 
				
			|||||||
    });
 | 
					    });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async runMainUpdateLoop() {
 | 
					  async runMainUpdateLoop(): Promise<void> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      try {
 | 
					      try {
 | 
				
			||||||
        await memPool.$updateMemPoolInfo();
 | 
					        await memPool.$updateMemPoolInfo();
 | 
				
			||||||
@ -183,7 +188,7 @@ class Server {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  async $runLightningBackend() {
 | 
					  async $runLightningBackend(): Promise<void> {
 | 
				
			||||||
    try {
 | 
					    try {
 | 
				
			||||||
      await fundingTxFetcher.$init();
 | 
					      await fundingTxFetcher.$init();
 | 
				
			||||||
      await networkSyncService.$startService();
 | 
					      await networkSyncService.$startService();
 | 
				
			||||||
@ -195,7 +200,7 @@ class Server {
 | 
				
			|||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  setUpWebsocketHandling() {
 | 
					  setUpWebsocketHandling(): void {
 | 
				
			||||||
    if (this.wss) {
 | 
					    if (this.wss) {
 | 
				
			||||||
      websocketHandler.setWebsocketServer(this.wss);
 | 
					      websocketHandler.setWebsocketServer(this.wss);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -209,19 +214,21 @@ class Server {
 | 
				
			|||||||
      });
 | 
					      });
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    websocketHandler.setupConnectionHandling();
 | 
					    websocketHandler.setupConnectionHandling();
 | 
				
			||||||
    statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler));
 | 
					    if (config.MEMPOOL.ENABLED) {
 | 
				
			||||||
    blocks.setNewBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler));
 | 
					      statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler));
 | 
				
			||||||
    memPool.setMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler));
 | 
					      blocks.setNewBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler));
 | 
				
			||||||
 | 
					      memPool.setMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler));
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
    fiatConversion.setProgressChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler));
 | 
					    fiatConversion.setProgressChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler));
 | 
				
			||||||
    loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler));
 | 
					    loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler));
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
  setUpHttpApiRoutes() {
 | 
					  setUpHttpApiRoutes(): void {
 | 
				
			||||||
    bitcoinRoutes.initRoutes(this.app);
 | 
					    bitcoinRoutes.initRoutes(this.app);
 | 
				
			||||||
    if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED) {
 | 
					    if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && config.MEMPOOL.ENABLED) {
 | 
				
			||||||
      statisticsRoutes.initRoutes(this.app);
 | 
					      statisticsRoutes.initRoutes(this.app);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (Common.indexingEnabled()) {
 | 
					    if (Common.indexingEnabled() && config.MEMPOOL.ENABLED) {
 | 
				
			||||||
      miningRoutes.initRoutes(this.app);
 | 
					      miningRoutes.initRoutes(this.app);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
    if (config.BISQ.ENABLED) {
 | 
					    if (config.BISQ.ENABLED) {
 | 
				
			||||||
@ -238,4 +245,4 @@ class Server {
 | 
				
			|||||||
  }
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
const server = new Server();
 | 
					((): Server => new Server())();
 | 
				
			||||||
 | 
				
			|||||||
@ -392,6 +392,36 @@ class BlocksRepository {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /**
 | 
				
			||||||
 | 
					   * Get the first block at or directly after a given timestamp
 | 
				
			||||||
 | 
					   * @param timestamp number unix time in seconds
 | 
				
			||||||
 | 
					   * @returns The height and timestamp of a block (timestamp might vary from given timestamp)
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  public async $getBlockHeightFromTimestamp(
 | 
				
			||||||
 | 
					    timestamp: number,
 | 
				
			||||||
 | 
					  ): Promise<{ height: number; hash: string; timestamp: number }> {
 | 
				
			||||||
 | 
					    try {
 | 
				
			||||||
 | 
					      // Get first block at or after the given timestamp
 | 
				
			||||||
 | 
					      const query = `SELECT height, hash, blockTimestamp as timestamp FROM blocks
 | 
				
			||||||
 | 
					        WHERE blockTimestamp <= FROM_UNIXTIME(?)
 | 
				
			||||||
 | 
					        ORDER BY blockTimestamp DESC
 | 
				
			||||||
 | 
					        LIMIT 1`;
 | 
				
			||||||
 | 
					      const params = [timestamp];
 | 
				
			||||||
 | 
					      const [rows]: any[][] = await DB.query(query, params);
 | 
				
			||||||
 | 
					      if (rows.length === 0) {
 | 
				
			||||||
 | 
					        throw new Error(`No block was found before timestamp ${timestamp}`);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      return rows[0];
 | 
				
			||||||
 | 
					    } catch (e) {
 | 
				
			||||||
 | 
					      logger.err(
 | 
				
			||||||
 | 
					        'Cannot get block height from timestamp from the db. Reason: ' +
 | 
				
			||||||
 | 
					          (e instanceof Error ? e.message : e),
 | 
				
			||||||
 | 
					      );
 | 
				
			||||||
 | 
					      throw e;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  /**
 | 
					  /**
 | 
				
			||||||
   * Return blocks height
 | 
					   * Return blocks height
 | 
				
			||||||
   */
 | 
					   */
 | 
				
			||||||
 | 
				
			|||||||
@ -89,6 +89,7 @@ Below we list all settings from `mempool-config.json` and the corresponding over
 | 
				
			|||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
    "NETWORK": "mainnet",
 | 
					    "NETWORK": "mainnet",
 | 
				
			||||||
    "BACKEND": "electrum",
 | 
					    "BACKEND": "electrum",
 | 
				
			||||||
 | 
					    "ENABLED": true,
 | 
				
			||||||
    "HTTP_PORT": 8999,
 | 
					    "HTTP_PORT": 8999,
 | 
				
			||||||
    "SPAWN_CLUSTER_PROCS": 0,
 | 
					    "SPAWN_CLUSTER_PROCS": 0,
 | 
				
			||||||
    "API_URL_PREFIX": "/api/v1/",
 | 
					    "API_URL_PREFIX": "/api/v1/",
 | 
				
			||||||
 | 
				
			|||||||
@ -2,6 +2,7 @@
 | 
				
			|||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
    "NETWORK": "__MEMPOOL_NETWORK__",
 | 
					    "NETWORK": "__MEMPOOL_NETWORK__",
 | 
				
			||||||
    "BACKEND": "__MEMPOOL_BACKEND__",
 | 
					    "BACKEND": "__MEMPOOL_BACKEND__",
 | 
				
			||||||
 | 
					    "ENABLED": __MEMPOOL_ENABLED__,
 | 
				
			||||||
    "HTTP_PORT": __MEMPOOL_HTTP_PORT__,
 | 
					    "HTTP_PORT": __MEMPOOL_HTTP_PORT__,
 | 
				
			||||||
    "SPAWN_CLUSTER_PROCS": __MEMPOOL_SPAWN_CLUSTER_PROCS__,
 | 
					    "SPAWN_CLUSTER_PROCS": __MEMPOOL_SPAWN_CLUSTER_PROCS__,
 | 
				
			||||||
    "API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__",
 | 
					    "API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__",
 | 
				
			||||||
 | 
				
			|||||||
@ -3,6 +3,7 @@
 | 
				
			|||||||
# MEMPOOL
 | 
					# MEMPOOL
 | 
				
			||||||
__MEMPOOL_NETWORK__=${MEMPOOL_NETWORK:=mainnet}
 | 
					__MEMPOOL_NETWORK__=${MEMPOOL_NETWORK:=mainnet}
 | 
				
			||||||
__MEMPOOL_BACKEND__=${MEMPOOL_BACKEND:=electrum}
 | 
					__MEMPOOL_BACKEND__=${MEMPOOL_BACKEND:=electrum}
 | 
				
			||||||
 | 
					__MEMPOOL_ENABLED__=${MEMPOOL_ENABLED:=true}
 | 
				
			||||||
__MEMPOOL_HTTP_PORT__=${BACKEND_HTTP_PORT:=8999}
 | 
					__MEMPOOL_HTTP_PORT__=${BACKEND_HTTP_PORT:=8999}
 | 
				
			||||||
__MEMPOOL_SPAWN_CLUSTER_PROCS__=${MEMPOOL_SPAWN_CLUSTER_PROCS:=0}
 | 
					__MEMPOOL_SPAWN_CLUSTER_PROCS__=${MEMPOOL_SPAWN_CLUSTER_PROCS:=0}
 | 
				
			||||||
__MEMPOOL_API_URL_PREFIX__=${MEMPOOL_API_URL_PREFIX:=/api/v1/}
 | 
					__MEMPOOL_API_URL_PREFIX__=${MEMPOOL_API_URL_PREFIX:=/api/v1/}
 | 
				
			||||||
@ -111,6 +112,7 @@ mkdir -p "${__MEMPOOL_CACHE_DIR__}"
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
sed -i "s/__MEMPOOL_NETWORK__/${__MEMPOOL_NETWORK__}/g" mempool-config.json
 | 
					sed -i "s/__MEMPOOL_NETWORK__/${__MEMPOOL_NETWORK__}/g" mempool-config.json
 | 
				
			||||||
sed -i "s/__MEMPOOL_BACKEND__/${__MEMPOOL_BACKEND__}/g" mempool-config.json
 | 
					sed -i "s/__MEMPOOL_BACKEND__/${__MEMPOOL_BACKEND__}/g" mempool-config.json
 | 
				
			||||||
 | 
					sed -i "s/__MEMPOOL_ENABLED__/${__MEMPOOL_ENABLED__}/g" mempool-config.json
 | 
				
			||||||
sed -i "s/__MEMPOOL_HTTP_PORT__/${__MEMPOOL_HTTP_PORT__}/g" mempool-config.json
 | 
					sed -i "s/__MEMPOOL_HTTP_PORT__/${__MEMPOOL_HTTP_PORT__}/g" mempool-config.json
 | 
				
			||||||
sed -i "s/__MEMPOOL_SPAWN_CLUSTER_PROCS__/${__MEMPOOL_SPAWN_CLUSTER_PROCS__}/g" mempool-config.json
 | 
					sed -i "s/__MEMPOOL_SPAWN_CLUSTER_PROCS__/${__MEMPOOL_SPAWN_CLUSTER_PROCS__}/g" mempool-config.json
 | 
				
			||||||
sed -i "s!__MEMPOOL_API_URL_PREFIX__!${__MEMPOOL_API_URL_PREFIX__}!g" mempool-config.json
 | 
					sed -i "s!__MEMPOOL_API_URL_PREFIX__!${__MEMPOOL_API_URL_PREFIX__}!g" mempool-config.json
 | 
				
			||||||
 | 
				
			|||||||
@ -221,6 +221,10 @@
 | 
				
			|||||||
              "proxyConfig": "proxy.conf.local.js",
 | 
					              "proxyConfig": "proxy.conf.local.js",
 | 
				
			||||||
              "verbose": true
 | 
					              "verbose": true
 | 
				
			||||||
            },
 | 
					            },
 | 
				
			||||||
 | 
					            "local-esplora": {
 | 
				
			||||||
 | 
					              "proxyConfig": "proxy.conf.local-esplora.js",
 | 
				
			||||||
 | 
					              "verbose": true
 | 
				
			||||||
 | 
					            },
 | 
				
			||||||
            "mixed": {
 | 
					            "mixed": {
 | 
				
			||||||
              "proxyConfig": "proxy.conf.mixed.js",
 | 
					              "proxyConfig": "proxy.conf.mixed.js",
 | 
				
			||||||
              "verbose": true
 | 
					              "verbose": true
 | 
				
			||||||
 | 
				
			|||||||
@ -29,6 +29,7 @@
 | 
				
			|||||||
    "serve:local-prod": "npm run generate-config && npm run ng -- serve -c local-prod",
 | 
					    "serve:local-prod": "npm run generate-config && npm run ng -- serve -c local-prod",
 | 
				
			||||||
    "serve:local-staging": "npm run generate-config && npm run ng -- serve -c local-staging",
 | 
					    "serve:local-staging": "npm run generate-config && npm run ng -- serve -c local-staging",
 | 
				
			||||||
    "start": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local",
 | 
					    "start": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local",
 | 
				
			||||||
 | 
					    "start:local-esplora": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-esplora",
 | 
				
			||||||
    "start:stg": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c staging",
 | 
					    "start:stg": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c staging",
 | 
				
			||||||
    "start:local-prod": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-prod",
 | 
					    "start:local-prod": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-prod",
 | 
				
			||||||
    "start:local-staging": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-staging",
 | 
					    "start:local-staging": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-staging",
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										137
									
								
								frontend/proxy.conf.local-esplora.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								frontend/proxy.conf.local-esplora.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,137 @@
 | 
				
			|||||||
 | 
					const fs = require('fs');
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let configContent;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// Read frontend config 
 | 
				
			||||||
 | 
					try {
 | 
				
			||||||
 | 
					    const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME);
 | 
				
			||||||
 | 
					    configContent = JSON.parse(rawConfig);
 | 
				
			||||||
 | 
					    console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`);
 | 
				
			||||||
 | 
					} catch (e) {
 | 
				
			||||||
 | 
					    console.log(e);
 | 
				
			||||||
 | 
					    if (e.code !== 'ENOENT') {
 | 
				
			||||||
 | 
					      throw new Error(e);
 | 
				
			||||||
 | 
					  } else {
 | 
				
			||||||
 | 
					      console.log(`${FRONTEND_CONFIG_FILE_NAME} file not found, using default config`);
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					let PROXY_CONFIG = [];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (configContent && configContent.BASE_MODULE === 'liquid') {
 | 
				
			||||||
 | 
					  PROXY_CONFIG.push(...[
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/liquid/api/v1/**'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      ws: true,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					      pathRewrite: {
 | 
				
			||||||
 | 
					          "^/liquid": ""
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/liquid/api/**'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:3000`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					      pathRewrite: {
 | 
				
			||||||
 | 
					          "^/liquid/api/": ""
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/liquidtestnet/api/v1/**'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      ws: true,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					      pathRewrite: {
 | 
				
			||||||
 | 
					          "^/liquidtestnet": ""
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/liquidtestnet/api/**'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:3000`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					      pathRewrite: {
 | 
				
			||||||
 | 
					          "^/liquidtestnet/api/": "/"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  ]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if (configContent && configContent.BASE_MODULE === 'bisq') {
 | 
				
			||||||
 | 
					  PROXY_CONFIG.push(...[
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/bisq/api/v1/ws'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      ws: true,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					      pathRewrite: {
 | 
				
			||||||
 | 
					          "^/bisq": ""
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/bisq/api/v1/**'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					    {
 | 
				
			||||||
 | 
					      context: ['/bisq/api/**'],
 | 
				
			||||||
 | 
					      target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					      secure: false,
 | 
				
			||||||
 | 
					      changeOrigin: true,
 | 
				
			||||||
 | 
					      proxyTimeout: 30000,
 | 
				
			||||||
 | 
					      pathRewrite: {
 | 
				
			||||||
 | 
					          "^/bisq/api/": "/api/v1/bisq/"
 | 
				
			||||||
 | 
					      },
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  ]);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PROXY_CONFIG.push(...[
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    context: ['/testnet/api/v1/lightning/**'],
 | 
				
			||||||
 | 
					    target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					    secure: false,
 | 
				
			||||||
 | 
					    changeOrigin: true,
 | 
				
			||||||
 | 
					    proxyTimeout: 30000,
 | 
				
			||||||
 | 
					    pathRewrite: {
 | 
				
			||||||
 | 
					        "^/testnet": ""
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    context: ['/api/v1/**'],
 | 
				
			||||||
 | 
					    target: `http://127.0.0.1:8999`,
 | 
				
			||||||
 | 
					    secure: false,
 | 
				
			||||||
 | 
					    ws: true,
 | 
				
			||||||
 | 
					    changeOrigin: true,
 | 
				
			||||||
 | 
					    proxyTimeout: 30000,
 | 
				
			||||||
 | 
					  },
 | 
				
			||||||
 | 
					  {
 | 
				
			||||||
 | 
					    context: ['/api/**'],
 | 
				
			||||||
 | 
					    target: `http://127.0.0.1:3000`,
 | 
				
			||||||
 | 
					    secure: false,
 | 
				
			||||||
 | 
					    changeOrigin: true,
 | 
				
			||||||
 | 
					    proxyTimeout: 30000,
 | 
				
			||||||
 | 
					    pathRewrite: {
 | 
				
			||||||
 | 
					        "^/api": ""
 | 
				
			||||||
 | 
					    },
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					]);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					console.log(PROXY_CONFIG);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					module.exports = PROXY_CONFIG;
 | 
				
			||||||
@ -2,9 +2,7 @@
 | 
				
			|||||||
  <div class="d-flex">
 | 
					  <div class="d-flex">
 | 
				
			||||||
    <div class="search-box-container mr-2">
 | 
					    <div class="search-box-container mr-2">
 | 
				
			||||||
      <input (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="Explore the full Bitcoin ecosystem">
 | 
					      <input (focus)="focus$.next($any($event).target.value)" (click)="click$.next($any($event).target.value)" formControlName="searchText" type="text" class="form-control" i18n-placeholder="search-form.searchbar-placeholder" placeholder="Explore the full Bitcoin ecosystem">
 | 
				
			||||||
      
 | 
					      <app-search-results #searchResults [hidden]="dropdownHidden" [results]="typeAhead$ | async" (selectedResult)="selectedResult($event)"></app-search-results>
 | 
				
			||||||
      <app-search-results #searchResults [results]="typeAhead$ | async" (selectedResult)="selectedResult($event)"></app-search-results>
 | 
					 | 
				
			||||||
    
 | 
					 | 
				
			||||||
    </div>
 | 
					    </div>
 | 
				
			||||||
    <div>
 | 
					    <div>
 | 
				
			||||||
      <button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary">
 | 
					      <button [disabled]="isSearching" type="submit" class="btn btn-block btn-primary">
 | 
				
			||||||
 | 
				
			|||||||
@ -1,4 +1,4 @@
 | 
				
			|||||||
import { Component, OnInit, ChangeDetectionStrategy, EventEmitter, Output, ViewChild, HostListener } from '@angular/core';
 | 
					import { Component, OnInit, ChangeDetectionStrategy, EventEmitter, Output, ViewChild, HostListener, ElementRef } from '@angular/core';
 | 
				
			||||||
import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 | 
					import { FormBuilder, FormGroup, Validators } from '@angular/forms';
 | 
				
			||||||
import { Router } from '@angular/router';
 | 
					import { Router } from '@angular/router';
 | 
				
			||||||
import { AssetsService } from '../../services/assets.service';
 | 
					import { AssetsService } from '../../services/assets.service';
 | 
				
			||||||
@ -23,6 +23,16 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
  isTypeaheading$ = new BehaviorSubject<boolean>(false);
 | 
					  isTypeaheading$ = new BehaviorSubject<boolean>(false);
 | 
				
			||||||
  typeAhead$: Observable<any>;
 | 
					  typeAhead$: Observable<any>;
 | 
				
			||||||
  searchForm: FormGroup;
 | 
					  searchForm: FormGroup;
 | 
				
			||||||
 | 
					  dropdownHidden = false;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  @HostListener('document:click', ['$event'])
 | 
				
			||||||
 | 
					  onDocumentClick(event) {
 | 
				
			||||||
 | 
					    if (this.elementRef.nativeElement.contains(event.target)) {
 | 
				
			||||||
 | 
					      this.dropdownHidden = false;
 | 
				
			||||||
 | 
					    } else {
 | 
				
			||||||
 | 
					      this.dropdownHidden = true;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  regexAddress = /^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[A-z]{2,5}1[a-zA-HJ-NP-Z0-9]{39,59})$/;
 | 
					  regexAddress = /^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[A-z]{2,5}1[a-zA-HJ-NP-Z0-9]{39,59})$/;
 | 
				
			||||||
  regexBlockhash = /^[0]{8}[a-fA-F0-9]{56}$/;
 | 
					  regexBlockhash = /^[0]{8}[a-fA-F0-9]{56}$/;
 | 
				
			||||||
@ -45,6 +55,7 @@ export class SearchFormComponent implements OnInit {
 | 
				
			|||||||
    private electrsApiService: ElectrsApiService,
 | 
					    private electrsApiService: ElectrsApiService,
 | 
				
			||||||
    private apiService: ApiService,
 | 
					    private apiService: ApiService,
 | 
				
			||||||
    private relativeUrlPipe: RelativeUrlPipe,
 | 
					    private relativeUrlPipe: RelativeUrlPipe,
 | 
				
			||||||
 | 
					    private elementRef: ElementRef,
 | 
				
			||||||
  ) { }
 | 
					  ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
 | 
					    "ENABLED": false,
 | 
				
			||||||
    "NETWORK": "mainnet",
 | 
					    "NETWORK": "mainnet",
 | 
				
			||||||
    "BACKEND": "esplora",
 | 
					    "BACKEND": "esplora",
 | 
				
			||||||
    "HTTP_PORT": 8993,
 | 
					    "HTTP_PORT": 8993,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
 | 
					    "ENABLED": false,
 | 
				
			||||||
    "NETWORK": "signet",
 | 
					    "NETWORK": "signet",
 | 
				
			||||||
    "BACKEND": "esplora",
 | 
					    "BACKEND": "esplora",
 | 
				
			||||||
    "HTTP_PORT": 8991,
 | 
					    "HTTP_PORT": 8991,
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,6 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
  "MEMPOOL": {
 | 
					  "MEMPOOL": {
 | 
				
			||||||
 | 
					    "ENABLED": false,
 | 
				
			||||||
    "NETWORK": "testnet",
 | 
					    "NETWORK": "testnet",
 | 
				
			||||||
    "BACKEND": "esplora",
 | 
					    "BACKEND": "esplora",
 | 
				
			||||||
    "HTTP_PORT": 8992,
 | 
					    "HTTP_PORT": 8992,
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user