Merge branch 'master' into fetch_conversion_rates_over_tor
This commit is contained in:
		
						commit
						d4cb6cd445
					
				@ -96,14 +96,20 @@ class Blocks {
 | 
			
		||||
   */
 | 
			
		||||
  private getBlockExtended(block: IEsploraApi.Block, transactions: TransactionExtended[]): BlockExtended {
 | 
			
		||||
    const blockExtended: BlockExtended = Object.assign({}, block);
 | 
			
		||||
    blockExtended.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0);
 | 
			
		||||
    blockExtended.coinbaseTx = transactionUtils.stripCoinbaseTransaction(transactions[0]);
 | 
			
		||||
 | 
			
		||||
    blockExtended.extras = {
 | 
			
		||||
      reward: transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0),
 | 
			
		||||
      coinbaseTx: transactionUtils.stripCoinbaseTransaction(transactions[0]),
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    const transactionsTmp = [...transactions];
 | 
			
		||||
    transactionsTmp.shift();
 | 
			
		||||
    transactionsTmp.sort((a, b) => b.effectiveFeePerVsize - a.effectiveFeePerVsize);
 | 
			
		||||
    blockExtended.medianFee = transactionsTmp.length > 0 ? Common.median(transactionsTmp.map((tx) => tx.effectiveFeePerVsize)) : 0;
 | 
			
		||||
    blockExtended.feeRange = transactionsTmp.length > 0 ? Common.getFeesInRange(transactionsTmp, 8) : [0, 0];
 | 
			
		||||
 | 
			
		||||
    blockExtended.extras.medianFee = transactionsTmp.length > 0 ?
 | 
			
		||||
      Common.median(transactionsTmp.map((tx) => tx.effectiveFeePerVsize)) : 0;
 | 
			
		||||
    blockExtended.extras.feeRange = transactionsTmp.length > 0 ?
 | 
			
		||||
      Common.getFeesInRange(transactionsTmp, 8) : [0, 0];
 | 
			
		||||
 | 
			
		||||
    return blockExtended;
 | 
			
		||||
  }
 | 
			
		||||
@ -197,7 +203,14 @@ class Blocks {
 | 
			
		||||
            const block = await bitcoinApi.$getBlock(blockHash);
 | 
			
		||||
            const transactions = await this.$getTransactionsExtended(blockHash, block.height, true);
 | 
			
		||||
            const blockExtended = this.getBlockExtended(block, transactions);
 | 
			
		||||
            const miner = await this.$findBlockMiner(blockExtended.coinbaseTx);
 | 
			
		||||
 | 
			
		||||
            let miner: PoolTag;
 | 
			
		||||
            if (blockExtended?.extras?.coinbaseTx) {
 | 
			
		||||
              miner = await this.$findBlockMiner(blockExtended.extras.coinbaseTx);
 | 
			
		||||
            } else {
 | 
			
		||||
              miner = await poolsRepository.$getUnknownPool();
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            const coinbase: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(transactions[0].txid, true);
 | 
			
		||||
            await blocksRepository.$saveBlockInDatabase(blockExtended, blockHash, coinbase.hex, miner);
 | 
			
		||||
          } catch (e) {
 | 
			
		||||
@ -262,7 +275,12 @@ class Blocks {
 | 
			
		||||
      const coinbase: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(transactions[0].txid, true);
 | 
			
		||||
 | 
			
		||||
      if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === true) {
 | 
			
		||||
        const miner = await this.$findBlockMiner(blockExtended.coinbaseTx);
 | 
			
		||||
        let miner: PoolTag;
 | 
			
		||||
        if (blockExtended?.extras?.coinbaseTx) {
 | 
			
		||||
          miner = await this.$findBlockMiner(blockExtended.extras.coinbaseTx);
 | 
			
		||||
        } else {
 | 
			
		||||
          miner = await poolsRepository.$getUnknownPool();
 | 
			
		||||
        }
 | 
			
		||||
        await blocksRepository.$saveBlockInDatabase(blockExtended, blockHash, coinbase.hex, miner);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -380,7 +380,9 @@ class WebsocketHandler {
 | 
			
		||||
      mBlocks = mempoolBlocks.getMempoolBlocks();
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    block.matchRate = matchRate;
 | 
			
		||||
    if (block.extras) {
 | 
			
		||||
      block.extras.matchRate = matchRate;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    this.wss.clients.forEach((client) => {
 | 
			
		||||
      if (client.readyState !== WebSocket.OPEN) {
 | 
			
		||||
 | 
			
		||||
@ -76,7 +76,8 @@ export interface TransactionStripped {
 | 
			
		||||
  vsize: number;
 | 
			
		||||
  value: number;
 | 
			
		||||
}
 | 
			
		||||
export interface BlockExtended extends IEsploraApi.Block {
 | 
			
		||||
 | 
			
		||||
export interface BlockExtension {
 | 
			
		||||
  medianFee?: number;
 | 
			
		||||
  feeRange?: number[];
 | 
			
		||||
  reward?: number;
 | 
			
		||||
@ -84,6 +85,10 @@ export interface BlockExtended extends IEsploraApi.Block {
 | 
			
		||||
  matchRate?: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BlockExtended extends IEsploraApi.Block {
 | 
			
		||||
  extras?: BlockExtension;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface TransactionMinerInfo {
 | 
			
		||||
  vin: VinStrippedToScriptsig[];
 | 
			
		||||
  vout: VoutStrippedToScriptPubkey[];
 | 
			
		||||
 | 
			
		||||
@ -31,9 +31,18 @@ class BlocksRepository {
 | 
			
		||||
      )`;
 | 
			
		||||
 | 
			
		||||
      const params: any[] = [
 | 
			
		||||
        block.height, blockHash, block.timestamp, block.size,
 | 
			
		||||
        block.weight, block.tx_count, coinbaseHex ? coinbaseHex : '', block.difficulty,
 | 
			
		||||
        poolTag.id, 0, '[]', block.medianFee,
 | 
			
		||||
        block.height,
 | 
			
		||||
        blockHash,
 | 
			
		||||
        block.timestamp,
 | 
			
		||||
        block.size,
 | 
			
		||||
        block.weight,
 | 
			
		||||
        block.tx_count,
 | 
			
		||||
        coinbaseHex ? coinbaseHex : '',
 | 
			
		||||
        block.difficulty,
 | 
			
		||||
        poolTag.id,
 | 
			
		||||
        0,
 | 
			
		||||
        '[]',
 | 
			
		||||
        block.extras ? block.extras.medianFee : 0,
 | 
			
		||||
      ];
 | 
			
		||||
 | 
			
		||||
      await connection.query(query, params);
 | 
			
		||||
 | 
			
		||||
@ -218,6 +218,10 @@
 | 
			
		||||
              "proxyConfig": "proxy.conf.local.js",
 | 
			
		||||
              "verbose": true
 | 
			
		||||
            },
 | 
			
		||||
            "mixed": {
 | 
			
		||||
              "proxyConfig": "proxy.conf.mixed.js",
 | 
			
		||||
              "verbose": true
 | 
			
		||||
            },
 | 
			
		||||
            "staging": {
 | 
			
		||||
              "proxyConfig": "proxy.conf.js",
 | 
			
		||||
              "disableHostCheck": true,
 | 
			
		||||
 | 
			
		||||
@ -30,6 +30,7 @@
 | 
			
		||||
    "start": "npm run generate-config && npm run sync-assets-dev && ng serve -c local",
 | 
			
		||||
    "start:stg": "npm run generate-config && npm run sync-assets-dev && ng serve -c staging",
 | 
			
		||||
    "start:local-prod": "npm run generate-config && npm run sync-assets-dev && ng serve -c local-prod",
 | 
			
		||||
    "start:mixed": "npm run generate-config && npm run sync-assets-dev && ng serve -c mixed",
 | 
			
		||||
    "build": "npm run generate-config && ng build --configuration production --localize && npm run sync-assets && npm run build-mempool.js",
 | 
			
		||||
    "sync-assets": "node sync-assets.js && rsync -av ./dist/mempool/browser/en-US/resources ./dist/mempool/browser/resources",
 | 
			
		||||
    "sync-assets-dev": "node sync-assets.js dev",
 | 
			
		||||
 | 
			
		||||
@ -1,17 +1,13 @@
 | 
			
		||||
 | 
			
		||||
const fs = require('fs');
 | 
			
		||||
 | 
			
		||||
let PROXY_CONFIG = require('./proxy.conf.js');
 | 
			
		||||
const BACKEND_CONFIG_FILE_NAME = '../backend/mempool-config.json';
 | 
			
		||||
const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json';
 | 
			
		||||
 | 
			
		||||
let backendConfigContent;
 | 
			
		||||
let frontendConfigContent;
 | 
			
		||||
let configContent;
 | 
			
		||||
 | 
			
		||||
// Read frontend config 
 | 
			
		||||
try {
 | 
			
		||||
    const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME);
 | 
			
		||||
    frontendConfigContent = JSON.parse(rawConfig);
 | 
			
		||||
    configContent = JSON.parse(rawConfig);
 | 
			
		||||
    console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    console.log(e);
 | 
			
		||||
@ -22,51 +18,88 @@ try {
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Read backend config
 | 
			
		||||
try {
 | 
			
		||||
    const rawConfig = fs.readFileSync(BACKEND_CONFIG_FILE_NAME);
 | 
			
		||||
    backendConfigContent = JSON.parse(rawConfig);
 | 
			
		||||
    console.log(`${BACKEND_CONFIG_FILE_NAME} file found, using provided config`);
 | 
			
		||||
} catch (e) {
 | 
			
		||||
    console.log(e);
 | 
			
		||||
    if (e.code !== 'ENOENT') {
 | 
			
		||||
      throw new Error(e);
 | 
			
		||||
  } else {
 | 
			
		||||
      console.log(`${BACKEND_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://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      ws: true,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/liquid": ""
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/liquid/api/**'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/liquid/api/": "/api/v1/"
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  ]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
if (configContent && configContent.BASE_MODULE === 'bisq') {
 | 
			
		||||
  PROXY_CONFIG.push(...[
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/bisq/api/v1/ws'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      ws: true,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/bisq": ""
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/bisq/api/v1/**'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/bisq/api/**'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/bisq/api/": "/api/v1/bisq/"
 | 
			
		||||
      },
 | 
			
		||||
    }
 | 
			
		||||
  ]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PROXY_CONFIG.push(...[
 | 
			
		||||
  {
 | 
			
		||||
    context: ['/api/v1/**'],
 | 
			
		||||
    target: `http://localhost:8999`,
 | 
			
		||||
    secure: false,
 | 
			
		||||
    ws: true,
 | 
			
		||||
    changeOrigin: true,
 | 
			
		||||
    proxyTimeout: 30000,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    context: ['/api/**'],
 | 
			
		||||
    target: `http://localhost:8999`,
 | 
			
		||||
    secure: false,
 | 
			
		||||
    changeOrigin: true,
 | 
			
		||||
    proxyTimeout: 30000,
 | 
			
		||||
    pathRewrite: {
 | 
			
		||||
        "^/api/": "/api/v1/"
 | 
			
		||||
    },
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Remove the "/api/**" entry from the default proxy config
 | 
			
		||||
let localDevContext = PROXY_CONFIG[0].context
 | 
			
		||||
 | 
			
		||||
localDevContext.splice(PROXY_CONFIG[0].context.indexOf('/api/**'), 1);
 | 
			
		||||
 | 
			
		||||
PROXY_CONFIG[0].context = localDevContext;
 | 
			
		||||
 | 
			
		||||
// Change all targets to localhost
 | 
			
		||||
PROXY_CONFIG.map(conf => conf.target = "http://localhost:8999");
 | 
			
		||||
 | 
			
		||||
// Add rules for local backend
 | 
			
		||||
if (backendConfigContent) {
 | 
			
		||||
    PROXY_CONFIG.push({
 | 
			
		||||
        context: ['/api/address/**', '/api/tx/**', '/api/block/**', '/api/blocks/**'],
 | 
			
		||||
        target: `http://localhost:8999`,
 | 
			
		||||
        secure: false,
 | 
			
		||||
        changeOrigin: true,
 | 
			
		||||
        proxyTimeout: 30000,
 | 
			
		||||
        pathRewrite: {
 | 
			
		||||
            "^/api/": "/api/v1/"
 | 
			
		||||
        },
 | 
			
		||||
    });    
 | 
			
		||||
    PROXY_CONFIG.push({
 | 
			
		||||
        context: ['/api/v1/**'],
 | 
			
		||||
        target: `http://localhost:8999`,
 | 
			
		||||
        secure: false,
 | 
			
		||||
        changeOrigin: true,
 | 
			
		||||
        proxyTimeout: 30000
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
console.log(PROXY_CONFIG);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										99
									
								
								frontend/proxy.conf.mixed.js
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										99
									
								
								frontend/proxy.conf.mixed.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,99 @@
 | 
			
		||||
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://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      ws: true,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/liquid": ""
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/liquid/api/**'],
 | 
			
		||||
      target: `https://liquid.network`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
    },
 | 
			
		||||
  ]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if (configContent && configContent.BASE_MODULE === 'bisq') {
 | 
			
		||||
  PROXY_CONFIG.push(...[
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/bisq/api/v1/ws'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      ws: true,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/bisq": ""
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/bisq/api/v1/**'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
    },
 | 
			
		||||
    {
 | 
			
		||||
      context: ['/bisq/api/**'],
 | 
			
		||||
      target: `http://localhost:8999`,
 | 
			
		||||
      secure: false,
 | 
			
		||||
      changeOrigin: true,
 | 
			
		||||
      proxyTimeout: 30000,
 | 
			
		||||
      pathRewrite: {
 | 
			
		||||
          "^/bisq/api/": "/api/v1/bisq/"
 | 
			
		||||
      },
 | 
			
		||||
    },
 | 
			
		||||
  ]);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
PROXY_CONFIG.push(...[
 | 
			
		||||
  {
 | 
			
		||||
    context: ['/api/v1/**'],
 | 
			
		||||
    target: `http://localhost:8999`,
 | 
			
		||||
    secure: false,
 | 
			
		||||
    ws: true,
 | 
			
		||||
    changeOrigin: true,
 | 
			
		||||
    proxyTimeout: 30000,
 | 
			
		||||
  },
 | 
			
		||||
  {
 | 
			
		||||
    context: ['/api/**'],
 | 
			
		||||
    target: `https://mempool.space`,
 | 
			
		||||
    secure: false,
 | 
			
		||||
    changeOrigin: true,
 | 
			
		||||
    proxyTimeout: 30000,
 | 
			
		||||
  }
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
console.log(PROXY_CONFIG);
 | 
			
		||||
 | 
			
		||||
module.exports = PROXY_CONFIG;
 | 
			
		||||
@ -74,9 +74,9 @@
 | 
			
		||||
        <div class="col-sm">
 | 
			
		||||
          <table class="table table-borderless table-striped">
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr *ngIf="block.medianFee !== undefined">
 | 
			
		||||
              <tr *ngIf="block?.extras?.medianFee != undefined">
 | 
			
		||||
                <td class="td-width" i18n="block.median-fee">Median fee</td>
 | 
			
		||||
                <td>~{{ block.medianFee | number:'1.0-0' }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span> <span class="fiat"><app-fiat [value]="block.medianFee * 140" digitsInfo="1.2-2" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat></span></td>
 | 
			
		||||
                <td>~{{ block?.extras?.medianFee | number:'1.0-0' }} <span class="symbol" i18n="shared.sat-vbyte|sat/vB">sat/vB</span> <span class="fiat"><app-fiat [value]="block?.extras?.medianFee * 140" digitsInfo="1.2-2" i18n-ngbTooltip="Transaction fee tooltip" ngbTooltip="Based on average native segwit transaction of 140 vBytes" placement="bottom"></app-fiat></span></td>
 | 
			
		||||
              </tr>
 | 
			
		||||
              <ng-template [ngIf]="fees !== undefined" [ngIfElse]="loadingFees">
 | 
			
		||||
                <tr>
 | 
			
		||||
 | 
			
		||||
@ -3,12 +3,13 @@ import { Location } from '@angular/common';
 | 
			
		||||
import { ActivatedRoute, ParamMap, Router } from '@angular/router';
 | 
			
		||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
import { switchMap, tap, debounceTime, catchError, map } from 'rxjs/operators';
 | 
			
		||||
import { Block, Transaction, Vout } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { Transaction, Vout } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { Observable, of, Subscription } from 'rxjs';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { WebsocketService } from 'src/app/services/websocket.service';
 | 
			
		||||
import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.pipe';
 | 
			
		||||
import { BlockExtended } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-block',
 | 
			
		||||
@ -17,13 +18,13 @@ import { RelativeUrlPipe } from 'src/app/shared/pipes/relative-url/relative-url.
 | 
			
		||||
})
 | 
			
		||||
export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
  network = '';
 | 
			
		||||
  block: Block;
 | 
			
		||||
  block: BlockExtended;
 | 
			
		||||
  blockHeight: number;
 | 
			
		||||
  nextBlockHeight: number;
 | 
			
		||||
  blockHash: string;
 | 
			
		||||
  isLoadingBlock = true;
 | 
			
		||||
  latestBlock: Block;
 | 
			
		||||
  latestBlocks: Block[] = [];
 | 
			
		||||
  latestBlock: BlockExtended;
 | 
			
		||||
  latestBlocks: BlockExtended[] = [];
 | 
			
		||||
  transactions: Transaction[];
 | 
			
		||||
  isLoadingTransactions = true;
 | 
			
		||||
  error: any;
 | 
			
		||||
@ -76,7 +77,9 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
        if (block.id === this.blockHash) {
 | 
			
		||||
          this.block = block;
 | 
			
		||||
          this.fees = block.reward / 100000000 - this.blockSubsidy;
 | 
			
		||||
          if (block?.extras?.reward != undefined) {
 | 
			
		||||
            this.fees = block.extras.reward / 100000000 - this.blockSubsidy;
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@ -108,7 +111,7 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
        } else {
 | 
			
		||||
          this.isLoadingBlock = true;
 | 
			
		||||
 | 
			
		||||
          let blockInCache: Block;
 | 
			
		||||
          let blockInCache: BlockExtended;
 | 
			
		||||
          if (isBlockHeight) {
 | 
			
		||||
            blockInCache = this.latestBlocks.find((block) => block.height === parseInt(blockHash, 10));
 | 
			
		||||
            if (blockInCache) {
 | 
			
		||||
@ -134,7 +137,7 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
          return this.electrsApiService.getBlock$(blockHash);
 | 
			
		||||
        }
 | 
			
		||||
      }),
 | 
			
		||||
      tap((block: Block) => {
 | 
			
		||||
      tap((block: BlockExtended) => {
 | 
			
		||||
        this.block = block;
 | 
			
		||||
        this.blockHeight = block.height;
 | 
			
		||||
        this.nextBlockHeight = block.height + 1;
 | 
			
		||||
@ -142,12 +145,10 @@ export class BlockComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
        this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`);
 | 
			
		||||
        this.isLoadingBlock = false;
 | 
			
		||||
        if (block.coinbaseTx) {
 | 
			
		||||
          this.coinbaseTx = block.coinbaseTx;
 | 
			
		||||
        }
 | 
			
		||||
        this.coinbaseTx = block?.extras?.coinbaseTx;
 | 
			
		||||
        this.setBlockSubsidy();
 | 
			
		||||
        if (block.reward !== undefined) {
 | 
			
		||||
          this.fees = block.reward / 100000000 - this.blockSubsidy;
 | 
			
		||||
        if (block?.extras?.reward !== undefined) {
 | 
			
		||||
          this.fees = block.extras.reward / 100000000 - this.blockSubsidy;
 | 
			
		||||
        }
 | 
			
		||||
        this.stateService.markBlock$.next({ blockHeight: this.blockHeight });
 | 
			
		||||
        this.isLoadingTransactions = true;
 | 
			
		||||
 | 
			
		||||
@ -8,10 +8,10 @@
 | 
			
		||||
      </div>
 | 
			
		||||
      <div class="block-body">
 | 
			
		||||
        <div class="fees">
 | 
			
		||||
          ~{{ block.medianFee | number:feeRounding }} <ng-container i18n="shared.sat-vbyte|sat/vB">sat/vB</ng-container>
 | 
			
		||||
          ~{{ block?.extras?.medianFee | number:feeRounding }} <ng-container i18n="shared.sat-vbyte|sat/vB">sat/vB</ng-container>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="fee-span">
 | 
			
		||||
          {{ block.feeRange[1] | number:feeRounding }} - {{ block.feeRange[block.feeRange.length - 1] | number:feeRounding }} <ng-container i18n="shared.sat-vbyte|sat/vB">sat/vB</ng-container>
 | 
			
		||||
          {{ block?.extras?.feeRange[1] | number:feeRounding }} - {{ block?.extras?.feeRange[block?.extras?.feeRange.length - 1] | number:feeRounding }} <ng-container i18n="shared.sat-vbyte|sat/vB">sat/vB</ng-container>
 | 
			
		||||
        </div>
 | 
			
		||||
        <div class="block-size" [innerHTML]="'‎' + (block.size | bytes: 2)"></div>
 | 
			
		||||
        <div class="transaction-count">
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,9 @@
 | 
			
		||||
import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
 | 
			
		||||
import { Observable, Subscription } from 'rxjs';
 | 
			
		||||
import { Block } from 'src/app/interfaces/electrs.interface';
 | 
			
		||||
import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
import { Router } from '@angular/router';
 | 
			
		||||
import { specialBlocks } from 'src/app/app.constants';
 | 
			
		||||
import { BlockExtended } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-blockchain-blocks',
 | 
			
		||||
@ -14,8 +14,8 @@ import { specialBlocks } from 'src/app/app.constants';
 | 
			
		||||
export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
  specialBlocks = specialBlocks;
 | 
			
		||||
  network = '';
 | 
			
		||||
  blocks: Block[] = [];
 | 
			
		||||
  emptyBlocks: Block[] = this.mountEmptyBlocks();
 | 
			
		||||
  blocks: BlockExtended[] = [];
 | 
			
		||||
  emptyBlocks: BlockExtended[] = this.mountEmptyBlocks();
 | 
			
		||||
  markHeight: number;
 | 
			
		||||
  blocksSubscription: Subscription;
 | 
			
		||||
  networkSubscription: Subscription;
 | 
			
		||||
@ -69,8 +69,8 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
        this.blocks.unshift(block);
 | 
			
		||||
        this.blocks = this.blocks.slice(0, this.stateService.env.KEEP_BLOCKS_AMOUNT);
 | 
			
		||||
 | 
			
		||||
        if (this.blocksFilled && !this.tabHidden) {
 | 
			
		||||
          block.stage = block.matchRate >= 66 ? 1 : 2;
 | 
			
		||||
        if (this.blocksFilled && !this.tabHidden && block.extras) {
 | 
			
		||||
          block.extras.stage = block.extras.matchRate >= 66 ? 1 : 2;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (txConfirmed) {
 | 
			
		||||
@ -143,16 +143,16 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackByBlocksFn(index: number, item: Block) {
 | 
			
		||||
  trackByBlocksFn(index: number, item: BlockExtended) {
 | 
			
		||||
    return item.height;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getStyleForBlock(block: Block) {
 | 
			
		||||
  getStyleForBlock(block: BlockExtended) {
 | 
			
		||||
    const greenBackgroundHeight = 100 - (block.weight / this.stateService.env.BLOCK_WEIGHT_UNITS) * 100;
 | 
			
		||||
    let addLeft = 0;
 | 
			
		||||
 | 
			
		||||
    if (block.stage === 1) {
 | 
			
		||||
      block.stage = 2;
 | 
			
		||||
    if (block?.extras?.stage === 1) {
 | 
			
		||||
      block.extras.stage = 2;
 | 
			
		||||
      addLeft = -205;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@ -167,11 +167,11 @@ export class BlockchainBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getStyleForEmptyBlock(block: Block) {
 | 
			
		||||
  getStyleForEmptyBlock(block: BlockExtended) {
 | 
			
		||||
    let addLeft = 0;
 | 
			
		||||
 | 
			
		||||
    if (block.stage === 1) {
 | 
			
		||||
      block.stage = 2;
 | 
			
		||||
    if (block?.extras?.stage === 1) {
 | 
			
		||||
      block.extras.stage = 2;
 | 
			
		||||
      addLeft = -205;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -153,7 +153,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy {
 | 
			
		||||
 | 
			
		||||
    this.blockSubscription = this.stateService.blocks$
 | 
			
		||||
      .subscribe(([block]) => {
 | 
			
		||||
        if (block.matchRate >= 66 && !this.tabHidden) {
 | 
			
		||||
        if (block?.extras?.matchRate >= 66 && !this.tabHidden) {
 | 
			
		||||
          this.blockIndex++;
 | 
			
		||||
        }
 | 
			
		||||
      });
 | 
			
		||||
 | 
			
		||||
@ -9,14 +9,14 @@ import {
 | 
			
		||||
  delay,
 | 
			
		||||
  map
 | 
			
		||||
} from 'rxjs/operators';
 | 
			
		||||
import { Transaction, Block } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { Transaction } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { of, merge, Subscription, Observable, Subject, timer, combineLatest, from } from 'rxjs';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
import { WebsocketService } from '../../services/websocket.service';
 | 
			
		||||
import { AudioService } from 'src/app/services/audio.service';
 | 
			
		||||
import { ApiService } from 'src/app/services/api.service';
 | 
			
		||||
import { SeoService } from 'src/app/services/seo.service';
 | 
			
		||||
import { CpfpInfo } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
import { BlockExtended, CpfpInfo } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
import { LiquidUnblinding } from './liquid-ublinding';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
@ -33,7 +33,7 @@ export class TransactionComponent implements OnInit, OnDestroy {
 | 
			
		||||
  error: any = undefined;
 | 
			
		||||
  errorUnblinded: any = undefined;
 | 
			
		||||
  waitingForTransaction = false;
 | 
			
		||||
  latestBlock: Block;
 | 
			
		||||
  latestBlock: BlockExtended;
 | 
			
		||||
  transactionTime = -1;
 | 
			
		||||
  subscription: Subscription;
 | 
			
		||||
  fetchCpfpSubscription: Subscription;
 | 
			
		||||
 | 
			
		||||
@ -1,11 +1,12 @@
 | 
			
		||||
import { Component, OnInit, Input, ChangeDetectionStrategy, OnChanges, ChangeDetectorRef, Output, EventEmitter } from '@angular/core';
 | 
			
		||||
import { StateService } from '../../services/state.service';
 | 
			
		||||
import { Observable, forkJoin } from 'rxjs';
 | 
			
		||||
import { Block, Outspend, Transaction } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { Outspend, Transaction } from '../../interfaces/electrs.interface';
 | 
			
		||||
import { ElectrsApiService } from '../../services/electrs-api.service';
 | 
			
		||||
import { environment } from 'src/environments/environment';
 | 
			
		||||
import { AssetsService } from 'src/app/services/assets.service';
 | 
			
		||||
import { map } from 'rxjs/operators';
 | 
			
		||||
import { BlockExtended } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-transactions-list',
 | 
			
		||||
@ -26,7 +27,7 @@ export class TransactionsListComponent implements OnInit, OnChanges {
 | 
			
		||||
 | 
			
		||||
  @Output() loadMore = new EventEmitter();
 | 
			
		||||
 | 
			
		||||
  latestBlock$: Observable<Block>;
 | 
			
		||||
  latestBlock$: Observable<BlockExtended>;
 | 
			
		||||
  outspends: Outspend[] = [];
 | 
			
		||||
  assetsMinimal: any;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,8 @@
 | 
			
		||||
import { Component, ChangeDetectionStrategy, OnChanges, Input, OnInit, ChangeDetectorRef, OnDestroy } from '@angular/core';
 | 
			
		||||
import { Transaction, Block } from 'src/app/interfaces/electrs.interface';
 | 
			
		||||
import { Transaction } from 'src/app/interfaces/electrs.interface';
 | 
			
		||||
import { StateService } from 'src/app/services/state.service';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { BlockExtended } from 'src/app/interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-tx-fee-rating',
 | 
			
		||||
@ -18,7 +19,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
  overpaidTimes: number;
 | 
			
		||||
  feeRating: number;
 | 
			
		||||
 | 
			
		||||
  blocks: Block[] = [];
 | 
			
		||||
  blocks: BlockExtended[] = [];
 | 
			
		||||
 | 
			
		||||
  constructor(
 | 
			
		||||
    private stateService: StateService,
 | 
			
		||||
@ -28,7 +29,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
  ngOnInit() {
 | 
			
		||||
    this.blocksSubscription = this.stateService.blocks$.subscribe(([block]) => {
 | 
			
		||||
      this.blocks.push(block);
 | 
			
		||||
      if (this.tx.status.confirmed && this.tx.status.block_height === block.height && block.medianFee > 0) {
 | 
			
		||||
      if (this.tx.status.confirmed && this.tx.status.block_height === block.height && block?.extras?.medianFee > 0) {
 | 
			
		||||
        this.calculateRatings(block);
 | 
			
		||||
        this.cd.markForCheck();
 | 
			
		||||
      }
 | 
			
		||||
@ -42,7 +43,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    const foundBlock = this.blocks.find((b) => b.height === this.tx.status.block_height);
 | 
			
		||||
    if (foundBlock && foundBlock.medianFee > 0) {
 | 
			
		||||
    if (foundBlock && foundBlock?.extras?.medianFee > 0) {
 | 
			
		||||
      this.calculateRatings(foundBlock);
 | 
			
		||||
    }
 | 
			
		||||
  }
 | 
			
		||||
@ -51,9 +52,9 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy {
 | 
			
		||||
    this.blocksSubscription.unsubscribe();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  calculateRatings(block: Block) {
 | 
			
		||||
  calculateRatings(block: BlockExtended) {
 | 
			
		||||
    const feePervByte = this.tx.effectiveFeePerVsize || this.tx.fee / (this.tx.weight / 4);
 | 
			
		||||
    this.medianFeeNeeded = block.medianFee;
 | 
			
		||||
    this.medianFeeNeeded = block?.extras?.medianFee;
 | 
			
		||||
 | 
			
		||||
    // Block not filled
 | 
			
		||||
    if (block.weight < this.stateService.env.BLOCK_WEIGHT_UNITS * 0.95) {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,7 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, Inject, LOCALE_ID, OnInit } from '@angular/core';
 | 
			
		||||
import { combineLatest, merge, Observable, of, timer } from 'rxjs';
 | 
			
		||||
import { filter, map, scan, share, switchMap, tap } from 'rxjs/operators';
 | 
			
		||||
import { Block } from '../interfaces/electrs.interface';
 | 
			
		||||
import { OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
			
		||||
import { BlockExtended, OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
			
		||||
import { MempoolInfo, TransactionStripped } from '../interfaces/websocket.interface';
 | 
			
		||||
import { ApiService } from '../services/api.service';
 | 
			
		||||
import { StateService } from '../services/state.service';
 | 
			
		||||
@ -40,7 +39,7 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
  mempoolInfoData$: Observable<MempoolInfoData>;
 | 
			
		||||
  mempoolLoadingStatus$: Observable<number>;
 | 
			
		||||
  vBytesPerSecondLimit = 1667;
 | 
			
		||||
  blocks$: Observable<Block[]>;
 | 
			
		||||
  blocks$: Observable<BlockExtended[]>;
 | 
			
		||||
  transactions$: Observable<TransactionStripped[]>;
 | 
			
		||||
  latestBlockHeight: number;
 | 
			
		||||
  mempoolTransactionsWeightPerSecondData: any;
 | 
			
		||||
@ -199,7 +198,7 @@ export class DashboardComponent implements OnInit {
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  trackByBlock(index: number, block: Block) {
 | 
			
		||||
  trackByBlock(index: number, block: BlockExtended) {
 | 
			
		||||
    return block.height;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -107,14 +107,6 @@ export interface Block {
 | 
			
		||||
  size: number;
 | 
			
		||||
  weight: number;
 | 
			
		||||
  previousblockhash: string;
 | 
			
		||||
 | 
			
		||||
  // Custom properties
 | 
			
		||||
  medianFee?: number;
 | 
			
		||||
  feeRange?: number[];
 | 
			
		||||
  reward?: number;
 | 
			
		||||
  coinbaseTx?: Transaction;
 | 
			
		||||
  matchRate: number;
 | 
			
		||||
  stage: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface Address {
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,5 @@
 | 
			
		||||
import { Block, Transaction } from "./electrs.interface";
 | 
			
		||||
 | 
			
		||||
export interface OptimizedMempoolStats {
 | 
			
		||||
  added: number;
 | 
			
		||||
  vbytes_per_second: number;
 | 
			
		||||
@ -80,3 +82,17 @@ export interface MiningStats {
 | 
			
		||||
  pools: SinglePoolStats[],
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BlockExtension {
 | 
			
		||||
  medianFee?: number;
 | 
			
		||||
  feeRange?: number[];
 | 
			
		||||
  reward?: number;
 | 
			
		||||
  coinbaseTx?: Transaction;
 | 
			
		||||
  matchRate?: number;
 | 
			
		||||
 | 
			
		||||
  stage?: number; // Frontend only
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export interface BlockExtended extends Block {
 | 
			
		||||
  extras?: BlockExtension;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,9 +1,10 @@
 | 
			
		||||
import { ILoadingIndicators } from '../services/state.service';
 | 
			
		||||
import { Block, Transaction } from './electrs.interface';
 | 
			
		||||
import { Transaction } from './electrs.interface';
 | 
			
		||||
import { BlockExtended } from './node-api.interface';
 | 
			
		||||
 | 
			
		||||
export interface WebsocketResponse {
 | 
			
		||||
  block?: Block;
 | 
			
		||||
  blocks?: Block[];
 | 
			
		||||
  block?: BlockExtended;
 | 
			
		||||
  blocks?: BlockExtended[];
 | 
			
		||||
  conversions?: any;
 | 
			
		||||
  txConfirmed?: boolean;
 | 
			
		||||
  historicalDate?: string;
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,9 @@
 | 
			
		||||
import { Injectable } from '@angular/core';
 | 
			
		||||
import { HttpClient } from '@angular/common/http';
 | 
			
		||||
import { Observable } from 'rxjs';
 | 
			
		||||
import { Block, Transaction, Address, Outspend, Recent, Asset } from '../interfaces/electrs.interface';
 | 
			
		||||
import { Transaction, Address, Outspend, Recent, Asset } from '../interfaces/electrs.interface';
 | 
			
		||||
import { StateService } from './state.service';
 | 
			
		||||
import { BlockExtended } from '../interfaces/node-api.interface';
 | 
			
		||||
 | 
			
		||||
@Injectable({
 | 
			
		||||
  providedIn: 'root'
 | 
			
		||||
@ -28,12 +29,12 @@ export class ElectrsApiService {
 | 
			
		||||
    });
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getBlock$(hash: string): Observable<Block> {
 | 
			
		||||
    return this.httpClient.get<Block>(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash);
 | 
			
		||||
  getBlock$(hash: string): Observable<BlockExtended> {
 | 
			
		||||
    return this.httpClient.get<BlockExtended>(this.apiBaseUrl + this.apiBasePath + '/api/block/' + hash);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  listBlocks$(height?: number): Observable<Block[]> {
 | 
			
		||||
    return this.httpClient.get<Block[]>(this.apiBaseUrl + this.apiBasePath + '/api/blocks/' + (height || ''));
 | 
			
		||||
  listBlocks$(height?: number): Observable<BlockExtended[]> {
 | 
			
		||||
    return this.httpClient.get<BlockExtended[]>(this.apiBaseUrl + this.apiBasePath + '/api/blocks/' + (height || ''));
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  getTransaction$(txId: string): Observable<Transaction> {
 | 
			
		||||
 | 
			
		||||
@ -1,8 +1,8 @@
 | 
			
		||||
import { Inject, Injectable, PLATFORM_ID } from '@angular/core';
 | 
			
		||||
import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable } from 'rxjs';
 | 
			
		||||
import { Block, Transaction } from '../interfaces/electrs.interface';
 | 
			
		||||
import { Transaction } from '../interfaces/electrs.interface';
 | 
			
		||||
import { IBackendInfo, MempoolBlock, MempoolInfo, TransactionStripped } from '../interfaces/websocket.interface';
 | 
			
		||||
import { OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
			
		||||
import { BlockExtended, OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
			
		||||
import { Router, NavigationStart } from '@angular/router';
 | 
			
		||||
import { isPlatformBrowser } from '@angular/common';
 | 
			
		||||
import { map, shareReplay } from 'rxjs/operators';
 | 
			
		||||
@ -72,7 +72,7 @@ export class StateService {
 | 
			
		||||
  latestBlockHeight = 0;
 | 
			
		||||
 | 
			
		||||
  networkChanged$ = new ReplaySubject<string>(1);
 | 
			
		||||
  blocks$: ReplaySubject<[Block, boolean]>;
 | 
			
		||||
  blocks$: ReplaySubject<[BlockExtended, boolean]>;
 | 
			
		||||
  transactions$ = new ReplaySubject<TransactionStripped>(6);
 | 
			
		||||
  conversions$ = new ReplaySubject<any>(1);
 | 
			
		||||
  bsqPrice$ = new ReplaySubject<number>(1);
 | 
			
		||||
@ -122,7 +122,7 @@ export class StateService {
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
    this.blocks$ = new ReplaySubject<[Block, boolean]>(this.env.KEEP_BLOCKS_AMOUNT);
 | 
			
		||||
    this.blocks$ = new ReplaySubject<[BlockExtended, boolean]>(this.env.KEEP_BLOCKS_AMOUNT);
 | 
			
		||||
 | 
			
		||||
    if (this.env.BASE_MODULE === 'bisq') {
 | 
			
		||||
      this.network = this.env.BASE_MODULE;
 | 
			
		||||
 | 
			
		||||
@ -2,11 +2,12 @@ import { Injectable } from '@angular/core';
 | 
			
		||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
 | 
			
		||||
import { WebsocketResponse, IBackendInfo } from '../interfaces/websocket.interface';
 | 
			
		||||
import { StateService } from './state.service';
 | 
			
		||||
import { Block, Transaction } from '../interfaces/electrs.interface';
 | 
			
		||||
import { Transaction } from '../interfaces/electrs.interface';
 | 
			
		||||
import { Subscription } from 'rxjs';
 | 
			
		||||
import { ApiService } from './api.service';
 | 
			
		||||
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;
 | 
			
		||||
@ -207,7 +208,7 @@ export class WebsocketService {
 | 
			
		||||
  handleResponse(response: WebsocketResponse) {
 | 
			
		||||
    if (response.blocks && response.blocks.length) {
 | 
			
		||||
      const blocks = response.blocks;
 | 
			
		||||
      blocks.forEach((block: Block) => {
 | 
			
		||||
      blocks.forEach((block: BlockExtended) => {
 | 
			
		||||
        if (block.height > this.stateService.latestBlockHeight) {
 | 
			
		||||
          this.stateService.latestBlockHeight = block.height;
 | 
			
		||||
          this.stateService.blocks$.next([block, false]);
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user