Merge branch 'master' into simon/loading-indicator-ux
This commit is contained in:
		
						commit
						6f3739feb7
					
				@ -2,7 +2,7 @@ import { IEsploraApi } from './esplora-api.interface';
 | 
			
		||||
 | 
			
		||||
export interface AbstractBitcoinApi {
 | 
			
		||||
  $getRawMempool(): Promise<IEsploraApi.Transaction['txid'][]>;
 | 
			
		||||
  $getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean, blockHash?: string): Promise<IEsploraApi.Transaction>;
 | 
			
		||||
  $getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean): Promise<IEsploraApi.Transaction>;
 | 
			
		||||
  $getBlockHeightTip(): Promise<number>;
 | 
			
		||||
  $getTxIdsForBlock(hash: string): Promise<string[]>;
 | 
			
		||||
  $getBlockHash(height: number): Promise<string>;
 | 
			
		||||
 | 
			
		||||
@ -14,14 +14,31 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
			
		||||
    this.bitcoindClient = bitcoinClient;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $getRawTransaction(txId: string, skipConversion = false, addPrevout = false, blockHash?: string): Promise<IEsploraApi.Transaction> {
 | 
			
		||||
  static convertBlock(block: IBitcoinApi.Block): IEsploraApi.Block {
 | 
			
		||||
    return {
 | 
			
		||||
      id: block.hash,
 | 
			
		||||
      height: block.height,
 | 
			
		||||
      version: block.version,
 | 
			
		||||
      timestamp: block.time,
 | 
			
		||||
      bits: parseInt(block.bits, 16),
 | 
			
		||||
      nonce: block.nonce,
 | 
			
		||||
      difficulty: block.difficulty,
 | 
			
		||||
      merkle_root: block.merkleroot,
 | 
			
		||||
      tx_count: block.nTx,
 | 
			
		||||
      size: block.size,
 | 
			
		||||
      weight: block.weight,
 | 
			
		||||
      previousblockhash: block.previousblockhash,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  $getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise<IEsploraApi.Transaction> {
 | 
			
		||||
    // If the transaction is in the mempool we already converted and fetched the fee. Only prevouts are missing
 | 
			
		||||
    const txInMempool = mempool.getMempool()[txId];
 | 
			
		||||
    if (txInMempool && addPrevout) {
 | 
			
		||||
      return this.$addPrevouts(txInMempool);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return this.bitcoindClient.getRawTransaction(txId, true, blockHash)
 | 
			
		||||
    return this.bitcoindClient.getRawTransaction(txId, true)
 | 
			
		||||
      .then((transaction: IBitcoinApi.Transaction) => {
 | 
			
		||||
        if (skipConversion) {
 | 
			
		||||
          transaction.vout.forEach((vout) => {
 | 
			
		||||
@ -174,35 +191,18 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
			
		||||
      };
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (transaction.confirmations) {
 | 
			
		||||
      esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, addPrevout);
 | 
			
		||||
    } else {
 | 
			
		||||
      esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction);
 | 
			
		||||
      if (addPrevout) {
 | 
			
		||||
        esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, addPrevout);
 | 
			
		||||
    if (addPrevout) {
 | 
			
		||||
      if (transaction.confirmations) {
 | 
			
		||||
        esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction);
 | 
			
		||||
      } else {
 | 
			
		||||
        esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction);
 | 
			
		||||
        esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction);
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return esploraTransaction;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  static convertBlock(block: IBitcoinApi.Block): IEsploraApi.Block {
 | 
			
		||||
    return {
 | 
			
		||||
      id: block.hash,
 | 
			
		||||
      height: block.height,
 | 
			
		||||
      version: block.version,
 | 
			
		||||
      timestamp: block.time,
 | 
			
		||||
      bits: parseInt(block.bits, 16),
 | 
			
		||||
      nonce: block.nonce,
 | 
			
		||||
      difficulty: block.difficulty,
 | 
			
		||||
      merkle_root: block.merkleroot,
 | 
			
		||||
      tx_count: block.nTx,
 | 
			
		||||
      size: block.size,
 | 
			
		||||
      weight: block.weight,
 | 
			
		||||
      previousblockhash: block.previousblockhash,
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private translateScriptPubKeyType(outputType: string): string {
 | 
			
		||||
    const map = {
 | 
			
		||||
      'pubkey': 'p2pk',
 | 
			
		||||
@ -245,7 +245,7 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
			
		||||
      if (vin.prevout) {
 | 
			
		||||
        continue;
 | 
			
		||||
      }
 | 
			
		||||
      const innerTx = await this.$getRawTransaction(vin.txid, false);
 | 
			
		||||
      const innerTx = await this.$getRawTransaction(vin.txid, false, false);
 | 
			
		||||
      vin.prevout = innerTx.vout[vin.vout];
 | 
			
		||||
      this.addInnerScriptsToVin(vin);
 | 
			
		||||
    }
 | 
			
		||||
@ -271,18 +271,16 @@ class BitcoinApi implements AbstractBitcoinApi {
 | 
			
		||||
    return this.bitcoindClient.getRawMemPool(true);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction, addPrevout: boolean): Promise<IEsploraApi.Transaction> {
 | 
			
		||||
  private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction): Promise<IEsploraApi.Transaction> {
 | 
			
		||||
    if (transaction.vin[0].is_coinbase) {
 | 
			
		||||
      transaction.fee = 0;
 | 
			
		||||
      return transaction;
 | 
			
		||||
    }
 | 
			
		||||
    let totalIn = 0;
 | 
			
		||||
    for (const vin of transaction.vin) {
 | 
			
		||||
      const innerTx = await this.$getRawTransaction(vin.txid, !addPrevout);
 | 
			
		||||
      if (addPrevout) {
 | 
			
		||||
        vin.prevout = innerTx.vout[vin.vout];
 | 
			
		||||
        this.addInnerScriptsToVin(vin);
 | 
			
		||||
      }
 | 
			
		||||
      const innerTx = await this.$getRawTransaction(vin.txid, false, false);
 | 
			
		||||
      vin.prevout = innerTx.vout[vin.vout];
 | 
			
		||||
      this.addInnerScriptsToVin(vin);
 | 
			
		||||
      totalIn += innerTx.vout[vin.vout].value;
 | 
			
		||||
    }
 | 
			
		||||
    const totalOut = transaction.vout.reduce((p, output) => p + output.value, 0);
 | 
			
		||||
 | 
			
		||||
@ -32,7 +32,7 @@ class DifficultyAdjustmentApi {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    let timeAvgMins = blocksInEpoch ? diff / blocksInEpoch / 60 : 10;
 | 
			
		||||
    let timeAvgMins = blocksInEpoch && blocksInEpoch > 146 ? diff / blocksInEpoch / 60 : 10;
 | 
			
		||||
 | 
			
		||||
    // Testnet difficulty is set to 1 after 20 minutes of no blocks,
 | 
			
		||||
    // therefore the time between blocks will always be below 20 minutes (1200s).
 | 
			
		||||
 | 
			
		||||
@ -300,24 +300,12 @@ class Server {
 | 
			
		||||
 | 
			
		||||
    if (Common.indexingEnabled()) {
 | 
			
		||||
      this.app
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/24h', routes.$getPools.bind(routes, '24h'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/3d', routes.$getPools.bind(routes, '3d'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/1w', routes.$getPools.bind(routes, '1w'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/1m', routes.$getPools.bind(routes, '1m'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/3m', routes.$getPools.bind(routes, '3m'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/6m', routes.$getPools.bind(routes, '6m'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/1y', routes.$getPools.bind(routes, '1y'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/2y', routes.$getPools.bind(routes, '2y'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/3y', routes.$getPools.bind(routes, '3y'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/all', routes.$getPools.bind(routes, 'all'))
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/:interval', routes.$getPools)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/hashrate', routes.$getPoolHistoricalHashrate)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/blocks', routes.$getPoolBlocks)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/blocks/:height', routes.$getPoolBlocks)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug', routes.$getPool)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/:interval', routes.$getPool)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/pools', routes.$getPoolsHistoricalHashrate)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/pools/:interval', routes.$getPoolsHistoricalHashrate)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate', routes.$getHistoricalHashrate)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/:interval', routes.$getHistoricalHashrate)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/reward-stats/:blockCount', routes.$getRewardStats)
 | 
			
		||||
        .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fees/:interval', routes.$getHistoricalBlockFees)
 | 
			
		||||
 | 
			
		||||
@ -572,9 +572,9 @@ class Routes {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getPools(interval: string, req: Request, res: Response) {
 | 
			
		||||
  public async $getPools(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const stats = await miningStats.$getPoolsStats(interval);
 | 
			
		||||
      const stats = await miningStats.$getPoolsStats(req.params.interval);
 | 
			
		||||
      const blockCount = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
@ -588,7 +588,7 @@ class Routes {
 | 
			
		||||
 | 
			
		||||
  public async $getPoolsHistoricalHashrate(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const hashrates = await HashratesRepository.$getPoolsWeeklyHashrate(req.params.interval ?? null);
 | 
			
		||||
      const hashrates = await HashratesRepository.$getPoolsWeeklyHashrate(req.params.interval);
 | 
			
		||||
      const blockCount = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
@ -620,8 +620,8 @@ class Routes {
 | 
			
		||||
 | 
			
		||||
  public async $getHistoricalHashrate(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const hashrates = await HashratesRepository.$getNetworkDailyHashrate(req.params.interval ?? null);
 | 
			
		||||
      const difficulty = await BlocksRepository.$getBlocksDifficulty(req.params.interval ?? null);
 | 
			
		||||
      const hashrates = await HashratesRepository.$getNetworkDailyHashrate(req.params.interval);
 | 
			
		||||
      const difficulty = await BlocksRepository.$getBlocksDifficulty(req.params.interval);
 | 
			
		||||
      const blockCount = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
@ -640,7 +640,7 @@ class Routes {
 | 
			
		||||
 | 
			
		||||
  public async $getHistoricalBlockFees(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const blockFees = await mining.$getHistoricalBlockFees(req.params.interval ?? null);
 | 
			
		||||
      const blockFees = await mining.$getHistoricalBlockFees(req.params.interval);
 | 
			
		||||
      const blockCount = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
@ -654,7 +654,7 @@ class Routes {
 | 
			
		||||
 | 
			
		||||
  public async $getHistoricalBlockRewards(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const blockRewards = await mining.$getHistoricalBlockRewards(req.params.interval ?? null);
 | 
			
		||||
      const blockRewards = await mining.$getHistoricalBlockRewards(req.params.interval);
 | 
			
		||||
      const blockCount = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
@ -668,7 +668,7 @@ class Routes {
 | 
			
		||||
 | 
			
		||||
  public async $getHistoricalBlockFeeRates(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const blockFeeRates = await mining.$getHistoricalBlockFeeRates(req.params.interval ?? null);
 | 
			
		||||
      const blockFeeRates = await mining.$getHistoricalBlockFeeRates(req.params.interval);
 | 
			
		||||
      const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp();
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
@ -684,8 +684,8 @@ class Routes {
 | 
			
		||||
 | 
			
		||||
  public async $getHistoricalBlockSizeAndWeight(req: Request, res: Response) {
 | 
			
		||||
    try {
 | 
			
		||||
      const blockSizes = await mining.$getHistoricalBlockSizes(req.params.interval ?? null);
 | 
			
		||||
      const blockWeights = await mining.$getHistoricalBlockWeights(req.params.interval ?? null);
 | 
			
		||||
      const blockSizes = await mining.$getHistoricalBlockSizes(req.params.interval);
 | 
			
		||||
      const blockWeights = await mining.$getHistoricalBlockWeights(req.params.interval);
 | 
			
		||||
      const blockCount = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
      res.header('Pragma', 'public');
 | 
			
		||||
      res.header('Cache-control', 'public');
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,10 @@
 | 
			
		||||
const https = require('https');
 | 
			
		||||
import axios from 'axios';
 | 
			
		||||
import poolsParser from '../api/pools-parser';
 | 
			
		||||
import config from '../config';
 | 
			
		||||
import DB from '../database';
 | 
			
		||||
import logger from '../logger';
 | 
			
		||||
import { SocksProxyAgent } from 'socks-proxy-agent';
 | 
			
		||||
import * as https from 'https';
 | 
			
		||||
 | 
			
		||||
/**
 | 
			
		||||
 * Maintain the most recent version of pools.json
 | 
			
		||||
@ -28,6 +30,13 @@ class PoolsUpdater {
 | 
			
		||||
 | 
			
		||||
    this.lastRun = now;
 | 
			
		||||
 | 
			
		||||
    logger.info('Updating latest mining pools from Github');
 | 
			
		||||
    if (config.SOCKS5PROXY.ENABLED) {
 | 
			
		||||
      logger.info('List of public pools will be queried over the Tor network');
 | 
			
		||||
    } else {
 | 
			
		||||
      logger.info('List of public pools will be queried over clearnet');
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    try {
 | 
			
		||||
      const dbSha = await this.getShaFromDb();
 | 
			
		||||
      const githubSha = await this.fetchPoolsSha(); // Fetch pools.json sha from github
 | 
			
		||||
@ -41,7 +50,10 @@ class PoolsUpdater {
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      logger.warn('Pools.json is outdated, fetch latest from github');
 | 
			
		||||
      const poolsJson = await this.fetchPools();
 | 
			
		||||
      const poolsJson = await this.query('https://raw.githubusercontent.com/mempool/mining-pools/master/pools.json');
 | 
			
		||||
      if (poolsJson === undefined) {
 | 
			
		||||
        return;
 | 
			
		||||
      }
 | 
			
		||||
      await poolsParser.migratePoolsJson(poolsJson);
 | 
			
		||||
      await this.updateDBSha(githubSha);
 | 
			
		||||
      logger.notice('PoolsUpdater completed');
 | 
			
		||||
@ -52,14 +64,6 @@ class PoolsUpdater {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Fetch pools.json from github repo
 | 
			
		||||
   */
 | 
			
		||||
  private async fetchPools(): Promise<object> {
 | 
			
		||||
    const response = await this.query('/repos/mempool/mining-pools/contents/pools.json');
 | 
			
		||||
    return JSON.parse(Buffer.from(response['content'], 'base64').toString('utf8'));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Fetch our latest pools.json sha from the db
 | 
			
		||||
   */
 | 
			
		||||
@ -90,11 +94,13 @@ class PoolsUpdater {
 | 
			
		||||
   * Fetch our latest pools.json sha from github
 | 
			
		||||
   */
 | 
			
		||||
  private async fetchPoolsSha(): Promise<string | undefined> {
 | 
			
		||||
    const response = await this.query('/repos/mempool/mining-pools/git/trees/master');
 | 
			
		||||
    const response = await this.query('https://api.github.com/repos/mempool/mining-pools/git/trees/master');
 | 
			
		||||
 | 
			
		||||
    for (const file of response['tree']) {
 | 
			
		||||
      if (file['path'] === 'pools.json') {
 | 
			
		||||
        return file['sha'];
 | 
			
		||||
    if (response !== undefined) {
 | 
			
		||||
      for (const file of response['tree']) {
 | 
			
		||||
        if (file['path'] === 'pools.json') {
 | 
			
		||||
          return file['sha'];
 | 
			
		||||
        }
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -105,35 +111,45 @@ class PoolsUpdater {
 | 
			
		||||
  /**
 | 
			
		||||
   * Http request wrapper
 | 
			
		||||
   */
 | 
			
		||||
  private query(path): Promise<string> {
 | 
			
		||||
    return new Promise((resolve, reject) => {
 | 
			
		||||
      const options = {
 | 
			
		||||
        host: 'api.github.com',
 | 
			
		||||
        path: path,
 | 
			
		||||
        method: 'GET',
 | 
			
		||||
        headers: { 'user-agent': 'node.js' }
 | 
			
		||||
  private async query(path): Promise<object | undefined> {
 | 
			
		||||
    type axiosOptions = {
 | 
			
		||||
      httpsAgent?: https.Agent;
 | 
			
		||||
    }
 | 
			
		||||
    const setDelay = (secs: number = 1): Promise<void> => new Promise(resolve => setTimeout(() => resolve(), secs * 1000));
 | 
			
		||||
    const axiosOptions: axiosOptions = {};
 | 
			
		||||
    let retry = 0;
 | 
			
		||||
 | 
			
		||||
    if (config.SOCKS5PROXY.ENABLED) {
 | 
			
		||||
      const socksOptions: any = {
 | 
			
		||||
        agentOptions: {
 | 
			
		||||
          keepAlive: true,
 | 
			
		||||
        },
 | 
			
		||||
        hostname: config.SOCKS5PROXY.HOST,
 | 
			
		||||
        port: config.SOCKS5PROXY.PORT
 | 
			
		||||
      };
 | 
			
		||||
 | 
			
		||||
      logger.debug('Querying: api.github.com' + path);
 | 
			
		||||
      if (config.SOCKS5PROXY.USERNAME && config.SOCKS5PROXY.PASSWORD) {
 | 
			
		||||
        socksOptions.username = config.SOCKS5PROXY.USERNAME;
 | 
			
		||||
        socksOptions.password = config.SOCKS5PROXY.PASSWORD;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      const request = https.get(options, (response) => {
 | 
			
		||||
        const chunks_of_data: any[] = [];
 | 
			
		||||
        response.on('data', (fragments) => {
 | 
			
		||||
          chunks_of_data.push(fragments);
 | 
			
		||||
        });
 | 
			
		||||
        response.on('end', () => {
 | 
			
		||||
          resolve(JSON.parse(Buffer.concat(chunks_of_data).toString()));
 | 
			
		||||
        });
 | 
			
		||||
        response.on('error', (error) => {
 | 
			
		||||
          reject(error);
 | 
			
		||||
        });
 | 
			
		||||
      });
 | 
			
		||||
      axiosOptions.httpsAgent = new SocksProxyAgent(socksOptions);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
      request.on('error', (error) => {
 | 
			
		||||
        logger.err('Github API query failed. Reason: '  + error);
 | 
			
		||||
        reject(error);
 | 
			
		||||
      });
 | 
			
		||||
    });
 | 
			
		||||
    while(retry < 5) {
 | 
			
		||||
      try {
 | 
			
		||||
        const data = await axios.get(path, axiosOptions);
 | 
			
		||||
        if (data.statusText !== 'OK' || !data.data) {
 | 
			
		||||
          throw new Error(`Could not fetch data from Github, Error: ${data.status}`);
 | 
			
		||||
        }
 | 
			
		||||
        return data.data;
 | 
			
		||||
      } catch (e) {
 | 
			
		||||
        logger.err('Could not connect to Github. Reason: '  + (e instanceof Error ? e.message : e));
 | 
			
		||||
        retry++;
 | 
			
		||||
      }
 | 
			
		||||
      await setDelay();
 | 
			
		||||
    }
 | 
			
		||||
    return undefined;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								contributors/ayanamidev.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								contributors/ayanamidev.txt
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,3 @@
 | 
			
		||||
I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of May 15, 2022.
 | 
			
		||||
 | 
			
		||||
Signed: ayanamidev
 | 
			
		||||
@ -67,6 +67,7 @@ import { HashrateChartPoolsComponent } from './components/hashrates-chart-pools/
 | 
			
		||||
import { MiningStartComponent } from './components/mining-start/mining-start.component';
 | 
			
		||||
import { AmountShortenerPipe } from './shared/pipes/amount-shortener.pipe';
 | 
			
		||||
import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe';
 | 
			
		||||
import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe';
 | 
			
		||||
import { GraphsComponent } from './components/graphs/graphs.component';
 | 
			
		||||
import { DifficultyAdjustmentsTable } from './components/difficulty-adjustments-table/difficulty-adjustments-table.components';
 | 
			
		||||
import { BlocksList } from './components/blocks-list/blocks-list.component';
 | 
			
		||||
@ -161,6 +162,7 @@ import { BlockSizesWeightsGraphComponent } from './components/block-sizes-weight
 | 
			
		||||
    StorageService,
 | 
			
		||||
    LanguageService,
 | 
			
		||||
    ShortenStringPipe,
 | 
			
		||||
    CapAddressPipe,
 | 
			
		||||
    { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }
 | 
			
		||||
  ],
 | 
			
		||||
  bootstrap: [AppComponent]
 | 
			
		||||
 | 
			
		||||
@ -157,7 +157,7 @@ export class BlockFeesGraphComponent implements OnInit {
 | 
			
		||||
      series: [
 | 
			
		||||
        {
 | 
			
		||||
          zlevel: 0,
 | 
			
		||||
          name: 'Fees',
 | 
			
		||||
          name: $localize`:@@c20172223f84462032664d717d739297e5a9e2fe:Fees`,
 | 
			
		||||
          showSymbol: false,
 | 
			
		||||
          symbol: 'none',
 | 
			
		||||
          data: data.blockFees,
 | 
			
		||||
 | 
			
		||||
@ -157,7 +157,7 @@ export class BlockRewardsGraphComponent implements OnInit {
 | 
			
		||||
      series: [
 | 
			
		||||
        {
 | 
			
		||||
          zlevel: 0,
 | 
			
		||||
          name: 'Reward',
 | 
			
		||||
          name: $localize`:@@12f86e6747a5ad39e62d3480ddc472b1aeab5b76:Reward`,
 | 
			
		||||
          showSymbol: false,
 | 
			
		||||
          symbol: 'none',
 | 
			
		||||
          data: data.blockRewards,
 | 
			
		||||
 | 
			
		||||
@ -178,7 +178,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit {
 | 
			
		||||
        padding: 10,
 | 
			
		||||
        data: [
 | 
			
		||||
          {
 | 
			
		||||
            name: 'Size',
 | 
			
		||||
            name: $localize`:@@7faaaa08f56427999f3be41df1093ce4089bbd75:Size`,
 | 
			
		||||
            inactiveColor: 'rgb(110, 112, 121)',
 | 
			
		||||
            textStyle: {
 | 
			
		||||
              color: 'white',
 | 
			
		||||
@ -186,7 +186,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit {
 | 
			
		||||
            icon: 'roundRect',
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: 'Weight',
 | 
			
		||||
            name: $localize`:@@919f2fd60a898850c24b1584362bbf18a4628bcb:Weight`,
 | 
			
		||||
            inactiveColor: 'rgb(110, 112, 121)',
 | 
			
		||||
            textStyle: {
 | 
			
		||||
              color: 'white',
 | 
			
		||||
@ -224,7 +224,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit {
 | 
			
		||||
      series: data.sizes.length === 0 ? [] : [
 | 
			
		||||
        {
 | 
			
		||||
          zlevel: 1,
 | 
			
		||||
          name: 'Size',
 | 
			
		||||
          name: $localize`:@@7faaaa08f56427999f3be41df1093ce4089bbd75:Size`,
 | 
			
		||||
          showSymbol: false,
 | 
			
		||||
          symbol: 'none',
 | 
			
		||||
          data: data.sizes,
 | 
			
		||||
@ -255,7 +255,7 @@ export class BlockSizesWeightsGraphComponent implements OnInit {
 | 
			
		||||
        {
 | 
			
		||||
          zlevel: 1,
 | 
			
		||||
          yAxisIndex: 0,
 | 
			
		||||
          name: 'Weight',
 | 
			
		||||
          name: $localize`:@@919f2fd60a898850c24b1584362bbf18a4628bcb:Weight`,
 | 
			
		||||
          showSymbol: false,
 | 
			
		||||
          symbol: 'none',
 | 
			
		||||
          data: data.weights,
 | 
			
		||||
 | 
			
		||||
@ -195,7 +195,7 @@
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="clearfix"></div>
 | 
			
		||||
 | 
			
		||||
    <app-transactions-list [transactions]="transactions"></app-transactions-list>
 | 
			
		||||
    <app-transactions-list [transactions]="transactions" [paginated]="true"></app-transactions-list>
 | 
			
		||||
 | 
			
		||||
    <ng-template [ngIf]="isLoadingTransactions">
 | 
			
		||||
      <div class="text-center mb-4" class="tx-skeleton">
 | 
			
		||||
 | 
			
		||||
@ -40,10 +40,10 @@
 | 
			
		||||
            <app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td class="reward text-right" [class]="widget ? 'widget' : ''">
 | 
			
		||||
            <app-amount [satoshis]="block.extras.reward" digitsInfo="1.2-2"></app-amount>
 | 
			
		||||
            <app-amount [satoshis]="block.extras.reward" [noFiat]="true" digitsInfo="1.2-2"></app-amount>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td class="fees text-right" *ngIf="!widget">
 | 
			
		||||
            <app-amount [satoshis]="block.extras.totalFees" digitsInfo="1.2-2"></app-amount>
 | 
			
		||||
            <app-amount [satoshis]="block.extras.totalFees" [noFiat]="true" digitsInfo="1.2-2"></app-amount>
 | 
			
		||||
          </td>
 | 
			
		||||
          <td class="txs text-right" [class]="widget ? 'widget' : ''">
 | 
			
		||||
            {{ block.tx_count | number }}
 | 
			
		||||
 | 
			
		||||
@ -11,7 +11,7 @@
 | 
			
		||||
        </p>
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="item">
 | 
			
		||||
        <h5 class="card-title" i18n="master-page.blocks">Difficulty</h5>
 | 
			
		||||
        <h5 class="card-title" i18n="block.difficulty">Difficulty</h5>
 | 
			
		||||
        <p class="card-text">
 | 
			
		||||
          {{ hashrates.currentDifficulty | amountShortener }}
 | 
			
		||||
        </p>
 | 
			
		||||
@ -64,13 +64,13 @@
 | 
			
		||||
<ng-template #loadingStats>
 | 
			
		||||
  <div class="pool-distribution">
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="mining.miners-luck">Hashrate</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="mining.hashrate">Hashrate</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
    </div>
 | 
			
		||||
    <div class="item">
 | 
			
		||||
      <h5 class="card-title" i18n="master-page.blocks">Difficulty</h5>
 | 
			
		||||
      <h5 class="card-title" i18n="block.difficulty">Difficulty</h5>
 | 
			
		||||
      <p class="card-text">
 | 
			
		||||
        <span class="skeleton-loader skeleton-loader-big"></span>
 | 
			
		||||
      </p>
 | 
			
		||||
 | 
			
		||||
@ -223,7 +223,7 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
      legend: (this.widget || data.hashrates.length === 0) ? undefined : {
 | 
			
		||||
        data: [
 | 
			
		||||
          {
 | 
			
		||||
            name: 'Hashrate',
 | 
			
		||||
            name: $localize`:@@79a9dc5b1caca3cbeb1733a19515edacc5fc7920:Hashrate`,
 | 
			
		||||
            inactiveColor: 'rgb(110, 112, 121)',
 | 
			
		||||
            textStyle: {
 | 
			
		||||
              color: 'white',
 | 
			
		||||
@ -234,9 +234,9 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
            },
 | 
			
		||||
          },
 | 
			
		||||
          {
 | 
			
		||||
            name: 'Difficulty',
 | 
			
		||||
            name: $localize`:@@25148835d92465353fc5fe8897c27d5369978e5a:Difficulty`,
 | 
			
		||||
            inactiveColor: 'rgb(110, 112, 121)',
 | 
			
		||||
            textStyle: {
 | 
			
		||||
            textStyle: {  
 | 
			
		||||
              color: 'white',
 | 
			
		||||
            },
 | 
			
		||||
            icon: 'roundRect',
 | 
			
		||||
@ -290,7 +290,7 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
      series: data.hashrates.length === 0 ? [] : [
 | 
			
		||||
        {
 | 
			
		||||
          zlevel: 0,
 | 
			
		||||
          name: 'Hashrate',
 | 
			
		||||
          name: $localize`:@@79a9dc5b1caca3cbeb1733a19515edacc5fc7920:Hashrate`,
 | 
			
		||||
          showSymbol: false,
 | 
			
		||||
          symbol: 'none',
 | 
			
		||||
          data: data.hashrates,
 | 
			
		||||
@ -302,7 +302,7 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
        {
 | 
			
		||||
          zlevel: 1,
 | 
			
		||||
          yAxisIndex: 1,
 | 
			
		||||
          name: 'Difficulty',
 | 
			
		||||
          name: $localize`:@@25148835d92465353fc5fe8897c27d5369978e5a:Difficulty`,
 | 
			
		||||
          showSymbol: false,
 | 
			
		||||
          symbol: 'none',
 | 
			
		||||
          data: data.difficulty,
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@
 | 
			
		||||
    <button class="btn" style="margin: 0 0 4px 0px" (click)="onSaveChart()">
 | 
			
		||||
      <fa-icon [icon]="['fas', 'download']" [fixedWidth]="true"></fa-icon>
 | 
			
		||||
    </button>
 | 
			
		||||
    <span i18n="mining.pools-dominance">Pools Dominance</span>
 | 
			
		||||
    <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats">
 | 
			
		||||
      <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 4320">
 | 
			
		||||
 | 
			
		||||
@ -153,13 +153,14 @@ export class PoolRankingComponent implements OnInit {
 | 
			
		||||
          },
 | 
			
		||||
          borderColor: '#000',
 | 
			
		||||
          formatter: () => {
 | 
			
		||||
            const i = pool.blockCount.toString();
 | 
			
		||||
            if (this.miningWindowPreference === '24h') {
 | 
			
		||||
              return `<b style="color: white">${pool.name} (${pool.share}%)</b><br>` +
 | 
			
		||||
                pool.lastEstimatedHashrate.toString() + ' PH/s' +
 | 
			
		||||
                `<br>` + pool.blockCount.toString() + ` blocks`;
 | 
			
		||||
                `<br>` + $localize`${i} blocks`;
 | 
			
		||||
            } else {
 | 
			
		||||
              return `<b style="color: white">${pool.name} (${pool.share}%)</b><br>` +
 | 
			
		||||
                pool.blockCount.toString() + ` blocks`;
 | 
			
		||||
                $localize`${i} blocks`;
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
        },
 | 
			
		||||
 | 
			
		||||
@ -65,7 +65,10 @@
 | 
			
		||||
                      <ng-template #defaultAddress>
 | 
			
		||||
                        <a [routerLink]="['/address/' | relativeUrl, vin.prevout.scriptpubkey_address]" title="{{ vin.prevout.scriptpubkey_address }}">
 | 
			
		||||
                          <span class="d-block d-lg-none">{{ vin.prevout.scriptpubkey_address | shortenString : 16 }}</span>
 | 
			
		||||
                          <span class="d-none d-lg-block">{{ vin.prevout.scriptpubkey_address | shortenString : 35 }}</span>
 | 
			
		||||
                          <span class="d-none d-lg-flex justify-content-start">
 | 
			
		||||
                            <span class="addr-left flex-grow-1" [style]="vin.prevout.scriptpubkey_address.length > 40 ? 'max-width: 235px' : ''">{{ vin.prevout.scriptpubkey_address }}</span>
 | 
			
		||||
                            <span *ngIf="vin.prevout.scriptpubkey_address.length > 40" class="addr-right">{{ vin.prevout.scriptpubkey_address | capAddress: 40: 10 }}</span>
 | 
			
		||||
                          </span>
 | 
			
		||||
                        </a>
 | 
			
		||||
                        <div>
 | 
			
		||||
                          <app-address-labels [vin]="vin"></app-address-labels>
 | 
			
		||||
@ -156,7 +159,10 @@
 | 
			
		||||
                <td>
 | 
			
		||||
                  <a *ngIf="vout.scriptpubkey_address; else scriptpubkey_type" [routerLink]="['/address/' | relativeUrl, vout.scriptpubkey_address]" title="{{ vout.scriptpubkey_address }}">
 | 
			
		||||
                    <span class="d-block d-lg-none">{{ vout.scriptpubkey_address | shortenString : 16 }}</span>
 | 
			
		||||
                    <span class="d-none d-lg-block">{{ vout.scriptpubkey_address | shortenString : 35 }}</span>
 | 
			
		||||
                    <span class="d-none d-lg-flex justify-content-start">
 | 
			
		||||
                      <span class="addr-left flex-grow-1" [style]="vout.scriptpubkey_address.length > 40 ? 'max-width: 235px' : ''">{{ vout.scriptpubkey_address }}</span>
 | 
			
		||||
                      <span *ngIf="vout.scriptpubkey_address.length > 40" class="addr-right">{{ vout.scriptpubkey_address | capAddress: 40: 10 }}</span>
 | 
			
		||||
                    </span>
 | 
			
		||||
                  </a>
 | 
			
		||||
                  <div>
 | 
			
		||||
                    <app-address-labels [vout]="vout"></app-address-labels>
 | 
			
		||||
 | 
			
		||||
@ -129,3 +129,14 @@ h2 {
 | 
			
		||||
.summary {
 | 
			
		||||
	margin-top: 10px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.addr-left {
 | 
			
		||||
	font-family: monospace;
 | 
			
		||||
	overflow: hidden;
 | 
			
		||||
	text-overflow: ellipsis;
 | 
			
		||||
	margin-right: -7px
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.addr-right {
 | 
			
		||||
	font-family: monospace;
 | 
			
		||||
}
 | 
			
		||||
@ -22,6 +22,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
  @Input() showConfirmations = false;
 | 
			
		||||
  @Input() transactionPage = false;
 | 
			
		||||
  @Input() errorUnblinded = false;
 | 
			
		||||
  @Input() paginated = false;
 | 
			
		||||
  @Input() outputIndex: number;
 | 
			
		||||
  @Input() address: string = '';
 | 
			
		||||
 | 
			
		||||
@ -84,6 +85,9 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
    if (!this.transactions || !this.transactions.length) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    if (this.paginated) {
 | 
			
		||||
      this.outspends = [];
 | 
			
		||||
    }
 | 
			
		||||
    if (this.outputIndex) {
 | 
			
		||||
      setTimeout(() => {
 | 
			
		||||
        const assetBoxElements = document.getElementsByClassName('assetBox');
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,7 @@ export class ApiDocsComponent implements OnInit {
 | 
			
		||||
      }
 | 
			
		||||
      window.addEventListener('scroll', function() {
 | 
			
		||||
        that.desktopDocsNavPosition = ( window.pageYOffset > 182 ) ? "fixed" : "relative";
 | 
			
		||||
      });
 | 
			
		||||
      }, { passive: true} );
 | 
			
		||||
    }, 1 );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -9,9 +9,9 @@ import { take } from 'rxjs/operators';
 | 
			
		||||
import { TransferState, makeStateKey } from '@angular/platform-browser';
 | 
			
		||||
import { BlockExtended } from '../interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
const OFFLINE_RETRY_AFTER_MS = 10000;
 | 
			
		||||
const OFFLINE_PING_CHECK_AFTER_MS = 30000;
 | 
			
		||||
const EXPECT_PING_RESPONSE_AFTER_MS = 4000;
 | 
			
		||||
const OFFLINE_RETRY_AFTER_MS = 1000;
 | 
			
		||||
const OFFLINE_PING_CHECK_AFTER_MS = 10000;
 | 
			
		||||
const EXPECT_PING_RESPONSE_AFTER_MS = 5000;
 | 
			
		||||
 | 
			
		||||
const initData = makeStateKey('/api/v1/init-data');
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -0,0 +1,12 @@
 | 
			
		||||
import { Pipe, PipeTransform } from '@angular/core';
 | 
			
		||||
 | 
			
		||||
@Pipe({ name: 'capAddress' })
 | 
			
		||||
export class CapAddressPipe implements PipeTransform {
 | 
			
		||||
  transform(str: string, cap: number, leftover: number) {
 | 
			
		||||
    if (!str) { return; }
 | 
			
		||||
    if (str.length <= cap) {
 | 
			
		||||
      return str;
 | 
			
		||||
    }
 | 
			
		||||
    return str.slice(-Math.max(cap - str.length, leftover));
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
@ -29,6 +29,7 @@ import { MempoolBlocksComponent } from '../components/mempool-blocks/mempool-blo
 | 
			
		||||
import { BlockchainBlocksComponent } from '../components/blockchain-blocks/blockchain-blocks.component';
 | 
			
		||||
import { AmountComponent } from '../components/amount/amount.component';
 | 
			
		||||
import { RouterModule } from '@angular/router';
 | 
			
		||||
import { CapAddressPipe } from './pipes/cap-address-pipe/cap-address-pipe';
 | 
			
		||||
 | 
			
		||||
@NgModule({
 | 
			
		||||
  declarations: [
 | 
			
		||||
@ -51,6 +52,7 @@ import { RouterModule } from '@angular/router';
 | 
			
		||||
    WuBytesPipe,
 | 
			
		||||
    CeilPipe,
 | 
			
		||||
    ShortenStringPipe,
 | 
			
		||||
    CapAddressPipe,
 | 
			
		||||
    Decimal2HexPipe,
 | 
			
		||||
    FeeRoundingPipe,
 | 
			
		||||
    ColoredPriceDirective,
 | 
			
		||||
@ -103,6 +105,7 @@ import { RouterModule } from '@angular/router';
 | 
			
		||||
    WuBytesPipe,
 | 
			
		||||
    CeilPipe,
 | 
			
		||||
    ShortenStringPipe,
 | 
			
		||||
    CapAddressPipe,
 | 
			
		||||
    Decimal2HexPipe,
 | 
			
		||||
    FeeRoundingPipe,
 | 
			
		||||
    ColoredPriceDirective,
 | 
			
		||||
 | 
			
		||||
@ -1878,6 +1878,25 @@
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">mining.block-fees</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="c20172223f84462032664d717d739297e5a9e2fe" datatype="html">
 | 
			
		||||
        <source>Fees</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block-fees-graph/block-fees-graph.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">160,158</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/blocks-list/blocks-list.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">16,17</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">217,219</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">265,267</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="8ba8fe810458280a83df7fdf4c614dfc1a826445" datatype="html">
 | 
			
		||||
        <source>Block Rewards</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
@ -1894,6 +1913,25 @@
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">mining.block-rewards</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="12f86e6747a5ad39e62d3480ddc472b1aeab5b76" datatype="html">
 | 
			
		||||
        <source>Reward</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block-rewards-graph/block-rewards-graph.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">160,158</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/blocks-list/blocks-list.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">15,17</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">216,218</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">264,266</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="56fa1cd221491b6478998679cba2dc8d55ba330d" datatype="html">
 | 
			
		||||
        <source>Block Sizes and Weights</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
@ -1910,32 +1948,16 @@
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">mining.block-sizes-weights</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="bdf0e930eb22431140a2eaeacd809cc5f8ebd38c" datatype="html">
 | 
			
		||||
        <source>Next Block</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">7,8</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">19,20</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/mempool-block/mempool-block.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">71</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">Next Block</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="a0e07a711d171f4d40dd388d70ed32f9b8101e0a" datatype="html">
 | 
			
		||||
        <source>Previous Block</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">26,27</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">Previous Block</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="7faaaa08f56427999f3be41df1093ce4089bbd75" datatype="html">
 | 
			
		||||
        <source>Size</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">181,180</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">227,225</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">64,66</context>
 | 
			
		||||
@ -1972,10 +1994,17 @@
 | 
			
		||||
          <context context-type="sourcefile">src/app/dashboard/dashboard.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">116,119</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">block.size</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="919f2fd60a898850c24b1584362bbf18a4628bcb" datatype="html">
 | 
			
		||||
        <source>Weight</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">189,188</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">258,255</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">68,70</context>
 | 
			
		||||
@ -1984,7 +2013,30 @@
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/transaction/transaction.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">220,222</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">block.weight</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="bdf0e930eb22431140a2eaeacd809cc5f8ebd38c" datatype="html">
 | 
			
		||||
        <source>Next Block</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">7,8</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">19,20</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/mempool-block/mempool-block.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">71</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">Next Block</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="a0e07a711d171f4d40dd388d70ed32f9b8101e0a" datatype="html">
 | 
			
		||||
        <source>Previous Block</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/block/block.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">26,27</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">Previous Block</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="0b47a777f024ab4e3cdf0062acb4d86e9ae1f635" datatype="html">
 | 
			
		||||
        <source>Median fee</source>
 | 
			
		||||
@ -2167,6 +2219,14 @@
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrate-chart/hashrate-chart.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">73,75</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrate-chart/hashrate-chart.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">237,236</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrate-chart/hashrate-chart.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">305,302</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">block.difficulty</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="a6bb63d98a8a67689070a79ccf13960c25b572ef" datatype="html">
 | 
			
		||||
@ -2253,38 +2313,6 @@
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">latest-blocks.mined</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="12f86e6747a5ad39e62d3480ddc472b1aeab5b76" datatype="html">
 | 
			
		||||
        <source>Reward</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/blocks-list/blocks-list.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">15,17</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">216,218</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">264,266</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">latest-blocks.reward</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="c20172223f84462032664d717d739297e5a9e2fe" datatype="html">
 | 
			
		||||
        <source>Fees</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/blocks-list/blocks-list.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">16,17</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">217,219</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool/pool.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">265,267</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">latest-blocks.fees</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="e6213c3f05146287cf121868d9f3d3c3ff5f9714" datatype="html">
 | 
			
		||||
        <source>TXs</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
@ -2559,10 +2587,6 @@
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">6,8</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrates-chart-pools/hashrate-chart-pools.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">10,11</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <note priority="1" from="description">mining.pools-dominance</note>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="3510fc6daa1d975f331e3a717bdf1a34efa06dff" datatype="html">
 | 
			
		||||
@ -2591,6 +2615,14 @@
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrate-chart/hashrate-chart.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">67,69</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrate-chart/hashrate-chart.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">226,225</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/hashrate-chart/hashrate-chart.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">293,291</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool-ranking/pool-ranking.component.html</context>
 | 
			
		||||
          <context context-type="linenumber">87,89</context>
 | 
			
		||||
@ -2816,6 +2848,17 @@
 | 
			
		||||
          <context context-type="linenumber">55</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="6095122426142344316" datatype="html">
 | 
			
		||||
        <source><x id="PH" equiv-text="i"/> blocks</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool-ranking/pool-ranking.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">160,158</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
          <context context-type="sourcefile">src/app/components/pool-ranking/pool-ranking.component.ts</context>
 | 
			
		||||
          <context context-type="linenumber">163,162</context>
 | 
			
		||||
        </context-group>
 | 
			
		||||
      </trans-unit>
 | 
			
		||||
      <trans-unit id="cafc87479686947e2590b9f588a88040aeaf660b" datatype="html">
 | 
			
		||||
        <source>Tags</source>
 | 
			
		||||
        <context-group purpose="location">
 | 
			
		||||
 | 
			
		||||
@ -44,25 +44,6 @@
 | 
			
		||||
		try_files $uri $uri/ /en-US/index.html =404;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	# mainnet API
 | 
			
		||||
	location /api/v1/donations {
 | 
			
		||||
		proxy_pass https://mempool.space;
 | 
			
		||||
	}
 | 
			
		||||
	location /api/v1/donations/images {
 | 
			
		||||
		proxy_pass https://mempool.space;
 | 
			
		||||
	}
 | 
			
		||||
	location /api/v1/contributors {
 | 
			
		||||
		proxy_pass https://mempool.space;
 | 
			
		||||
	}
 | 
			
		||||
	location /api/v1/contributors/images {
 | 
			
		||||
		proxy_pass https://mempool.space;
 | 
			
		||||
	}
 | 
			
		||||
	location /api/v1/translators {
 | 
			
		||||
		proxy_pass https://mempool.space;
 | 
			
		||||
	}
 | 
			
		||||
	location /api/v1/translators/images {
 | 
			
		||||
		proxy_pass https://mempool.space;
 | 
			
		||||
	}
 | 
			
		||||
	location /api/v1/ws {
 | 
			
		||||
		proxy_pass http://127.0.0.1:8999/;
 | 
			
		||||
		proxy_http_version 1.1;
 | 
			
		||||
 | 
			
		||||
@ -276,7 +276,7 @@ MINFEE_HOME=/minfee
 | 
			
		||||
MEMPOOL_REPO_URL=https://github.com/mempool/mempool
 | 
			
		||||
MEMPOOL_REPO_NAME=mempool
 | 
			
		||||
MEMPOOL_REPO_BRANCH=master
 | 
			
		||||
MEMPOOL_LATEST_RELEASE=v2.3.1
 | 
			
		||||
MEMPOOL_LATEST_RELEASE=master
 | 
			
		||||
 | 
			
		||||
BITCOIN_REPO_URL=https://github.com/bitcoin/bitcoin
 | 
			
		||||
BITCOIN_REPO_NAME=bitcoin
 | 
			
		||||
@ -1016,7 +1016,7 @@ osSudo "${BITCOIN_USER}" sh -c "cd ${BITCOIN_ELECTRS_HOME} && cargo run --releas
 | 
			
		||||
echo "[*] Patching Bitcoin Electrs code for FreeBSD"
 | 
			
		||||
osSudo "${BITCOIN_USER}" sh -c "cd \"${BITCOIN_HOME}/.cargo/registry/src/github.com-1ecc6299db9ec823/sysconf-0.3.4\" && patch -p1 < \"${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME}/production/freebsd/sysconf.patch\""
 | 
			
		||||
osSudo "${BITCOIN_USER}" sh -c "cd \"${BITCOIN_ELECTRS_HOME}/src/new_index/\" && sed -i .bak -e s/Snappy/None/ db.rs && rm db.rs.bak"
 | 
			
		||||
osSudo "${BITCOIN_USER}" sh -c "cd \"${BITCOIN_ELECTRS_HOME}/src/bin/\" && sed -i .bak -e s/from_secs(5)/from_secs(1)/ electrs.rs && rm electrs.rs.bak"
 | 
			
		||||
osSudo "${BITCOIN_USER}" sh -c "cd \"${BITCOIN_ELECTRS_HOME}/src/bin/\" && sed -i .bak -e 's/from_secs(5)/from_secs(1)/' electrs.rs && rm electrs.rs.bak"
 | 
			
		||||
 | 
			
		||||
echo "[*] Building Bitcoin Electrs release binary"
 | 
			
		||||
osSudo "${BITCOIN_USER}" sh -c "cd ${BITCOIN_ELECTRS_HOME} && cargo run --release --bin electrs -- --version"
 | 
			
		||||
@ -1299,7 +1299,7 @@ if [ "${ELEMENTS_LIQUIDTESTNET_ENABLE}" = ON ];then
 | 
			
		||||
    osSudo "${MEMPOOL_USER}" sh -c "cd ${MEMPOOL_HOME}/${MEMPOOL_REPO_NAME} && git checkout ${MEMPOOL_LATEST_RELEASE}"
 | 
			
		||||
fi
 | 
			
		||||
 | 
			
		||||
if [ "${BISQ_ENABLE}" = ON ];then
 | 
			
		||||
if [ "${BISQ_INSTALL}" = ON ];then
 | 
			
		||||
    echo "[*] Creating Mempool instance for Bisq"
 | 
			
		||||
    osSudo "${MEMPOOL_USER}" git config --global advice.detachedHead false
 | 
			
		||||
    osSudo "${MEMPOOL_USER}" git clone --branch "${MEMPOOL_REPO_BRANCH}" "${MEMPOOL_REPO_URL}" "${MEMPOOL_HOME}/bisq"
 | 
			
		||||
 | 
			
		||||
@ -1,4 +1,4 @@
 | 
			
		||||
local7.>=notice |/usr/local/bin/sudo -u mempool /usr/local/bin/mempool-logger mempool.ops alerts
 | 
			
		||||
local7.info |/usr/local/bin/sudo -u mempool /usr/local/bin/mempool-logger mempool.ops node100
 | 
			
		||||
local7.info /var/log/mempool
 | 
			
		||||
local7.>=info |/usr/local/bin/sudo -u mempool /usr/local/bin/mempool-logger mempool.ops node100
 | 
			
		||||
local7.>=info /var/log/mempool
 | 
			
		||||
local7.* /var/log/mempool.debug
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user