Merge branch 'master' into nymkappa/bugfix/ignore-too-low-lightning-timestamps
This commit is contained in:
commit
c2dff72387
4
.github/workflows/ci.yml
vendored
4
.github/workflows/ci.yml
vendored
@ -9,7 +9,7 @@ jobs:
|
|||||||
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
|
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node: ["16.16.0", "18.14.1", "19.6.1"]
|
node: ["16.16.0", "18.14.1"]
|
||||||
flavor: ["dev", "prod"]
|
flavor: ["dev", "prod"]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
@ -55,7 +55,7 @@ jobs:
|
|||||||
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
|
if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')"
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
node: ["16.16.0", "18.14.1", "19.6.1"]
|
node: ["16.16.0", "18.14.1"]
|
||||||
flavor: ["dev", "prod"]
|
flavor: ["dev", "prod"]
|
||||||
fail-fast: false
|
fail-fast: false
|
||||||
runs-on: "ubuntu-latest"
|
runs-on: "ubuntu-latest"
|
||||||
|
2
LICENSE
2
LICENSE
@ -1,5 +1,5 @@
|
|||||||
The Mempool Open Source Project
|
The Mempool Open Source Project
|
||||||
Copyright (c) 2019-2022 The Mempool Open Source Project Developers
|
Copyright (c) 2019-2023 The Mempool Open Source Project Developers
|
||||||
|
|
||||||
This program is free software; you can redistribute it and/or modify it under
|
This program is free software; you can redistribute it and/or modify it under
|
||||||
the terms of (at your option) either:
|
the terms of (at your option) either:
|
||||||
|
@ -160,7 +160,7 @@ npm install -g ts-node nodemon
|
|||||||
Then, run the watcher:
|
Then, run the watcher:
|
||||||
|
|
||||||
```
|
```
|
||||||
nodemon src/index.ts --ignore cache/ --ignore pools.json
|
nodemon src/index.ts --ignore cache/
|
||||||
```
|
```
|
||||||
|
|
||||||
`nodemon` should be in npm's global binary folder. If needed, you can determine where that is with `npm -g bin`.
|
`nodemon` should be in npm's global binary folder. If needed, you can determine where that is with `npm -g bin`.
|
||||||
@ -219,6 +219,16 @@ Generate block at regular interval (every 10 seconds in this example):
|
|||||||
watch -n 10 "./src/bitcoin-cli -regtest -rpcport=8332 generatetoaddress 1 $address"
|
watch -n 10 "./src/bitcoin-cli -regtest -rpcport=8332 generatetoaddress 1 $address"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Mining pools update
|
||||||
|
|
||||||
|
By default, mining pools will be not automatically updated regularly (`config.MEMPOOL.AUTOMATIC_BLOCK_REINDEXING` is set to `false`).
|
||||||
|
|
||||||
|
To manually update your mining pools, you can use the `--update-pools` command line flag when you run the nodejs backend. For example `npm run start --update-pools`. This will trigger the mining pools update and automatically re-index appropriate blocks.
|
||||||
|
|
||||||
|
You can enabled the automatic mining pools update by settings `config.MEMPOOL.AUTOMATIC_BLOCK_REINDEXING` to `true` in your `mempool-config.json`.
|
||||||
|
|
||||||
|
When a `coinbase tag` or `coinbase address` change is detected, all blocks tagged to the `unknown` mining pools (starting from height 130635) will be deleted from the `blocks` table. Additionaly, all blocks which were tagged to the pool which has been updated will also be deleted from the `blocks` table. Of course, those blocks will be automatically reindexed.
|
||||||
|
|
||||||
### Re-index tables
|
### Re-index tables
|
||||||
|
|
||||||
You can manually force the nodejs backend to drop all data from a specified set of tables for future re-index. This is mostly useful for the mining dashboard and the lightning explorer.
|
You can manually force the nodejs backend to drop all data from a specified set of tables for future re-index. This is mostly useful for the mining dashboard and the lightning explorer.
|
||||||
|
@ -22,7 +22,7 @@
|
|||||||
"USER_AGENT": "mempool",
|
"USER_AGENT": "mempool",
|
||||||
"STDOUT_LOG_MIN_PRIORITY": "debug",
|
"STDOUT_LOG_MIN_PRIORITY": "debug",
|
||||||
"AUTOMATIC_BLOCK_REINDEXING": false,
|
"AUTOMATIC_BLOCK_REINDEXING": false,
|
||||||
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools.json",
|
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json",
|
||||||
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
||||||
"AUDIT": false,
|
"AUDIT": false,
|
||||||
"ADVANCED_GBT_AUDIT": false,
|
"ADVANCED_GBT_AUDIT": false,
|
||||||
|
@ -7,7 +7,7 @@
|
|||||||
"HTTP_PORT": 1,
|
"HTTP_PORT": 1,
|
||||||
"SPAWN_CLUSTER_PROCS": 2,
|
"SPAWN_CLUSTER_PROCS": 2,
|
||||||
"API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__",
|
"API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__",
|
||||||
"AUTOMATIC_BLOCK_REINDEXING": true,
|
"AUTOMATIC_BLOCK_REINDEXING": false,
|
||||||
"POLL_RATE_MS": 3,
|
"POLL_RATE_MS": 3,
|
||||||
"CACHE_DIR": "__MEMPOOL_CACHE_DIR__",
|
"CACHE_DIR": "__MEMPOOL_CACHE_DIR__",
|
||||||
"CLEAR_PROTECTION_MINUTES": 4,
|
"CLEAR_PROTECTION_MINUTES": 4,
|
||||||
|
@ -119,7 +119,8 @@ class Audit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const numCensored = Object.keys(isCensored).length;
|
const numCensored = Object.keys(isCensored).length;
|
||||||
const score = matches.length > 0 ? (matches.length / (matches.length + numCensored)) : 0;
|
const numMatches = matches.length - 1; // adjust for coinbase tx
|
||||||
|
const score = numMatches > 0 ? (numMatches / (numMatches + numCensored)) : 0;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
censored: Object.keys(isCensored),
|
censored: Object.keys(isCensored),
|
||||||
|
@ -1017,26 +1017,16 @@ class DatabaseMigration {
|
|||||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`;
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8;`;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $truncateIndexedData(tables: string[]) {
|
public async $blocksReindexingTruncate(): Promise<void> {
|
||||||
const allowedTables = ['blocks', 'hashrates', 'prices'];
|
logger.warn(`Truncating pools, blocks and hashrates for re-indexing (using '--reindex-blocks'). You can cancel this command within 5 seconds`);
|
||||||
|
await Common.sleep$(5000);
|
||||||
|
|
||||||
try {
|
await this.$executeQuery(`TRUNCATE blocks`);
|
||||||
for (const table of tables) {
|
await this.$executeQuery(`TRUNCATE hashrates`);
|
||||||
if (!allowedTables.includes(table)) {
|
await this.$executeQuery('DELETE FROM `pools`');
|
||||||
logger.debug(`Table ${table} cannot to be re-indexed (not allowed)`);
|
await this.$executeQuery('ALTER TABLE pools AUTO_INCREMENT = 1');
|
||||||
continue;
|
await this.$executeQuery(`UPDATE state SET string = NULL WHERE name = 'pools_json_sha'`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await this.$executeQuery(`TRUNCATE ${table}`, true);
|
|
||||||
if (table === 'hashrates') {
|
|
||||||
await this.$executeQuery('UPDATE state set number = 0 where name = "last_hashrates_indexing"', true);
|
|
||||||
}
|
|
||||||
logger.notice(`Table ${table} has been truncated`);
|
|
||||||
}
|
|
||||||
} catch (e) {
|
|
||||||
logger.warn(`Unable to erase indexed data`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private async $convertCompactCpfpTables(): Promise<void> {
|
private async $convertCompactCpfpTables(): Promise<void> {
|
||||||
try {
|
try {
|
||||||
|
@ -73,7 +73,7 @@ class PoolsParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info('Mining pools.json import completed');
|
logger.info('Mining pools-v2.json import completed');
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -115,7 +115,7 @@ class PoolsParser {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get oldest blocks mined by the pool and assume pools.json updates only concern most recent years
|
// Get oldest blocks mined by the pool and assume pools-v2.json updates only concern most recent years
|
||||||
// Ignore early days of Bitcoin as there were no mining pool yet
|
// Ignore early days of Bitcoin as there were no mining pool yet
|
||||||
const [oldestPoolBlock]: any[] = await DB.query(`
|
const [oldestPoolBlock]: any[] = await DB.query(`
|
||||||
SELECT height
|
SELECT height
|
||||||
|
@ -36,7 +36,6 @@ import bitcoinRoutes from './api/bitcoin/bitcoin.routes';
|
|||||||
import fundingTxFetcher from './tasks/lightning/sync-tasks/funding-tx-fetcher';
|
import fundingTxFetcher from './tasks/lightning/sync-tasks/funding-tx-fetcher';
|
||||||
import forensicsService from './tasks/lightning/forensics.service';
|
import forensicsService from './tasks/lightning/forensics.service';
|
||||||
import priceUpdater from './tasks/price-updater';
|
import priceUpdater from './tasks/price-updater';
|
||||||
import mining from './api/mining/mining';
|
|
||||||
import chainTips from './api/chain-tips';
|
import chainTips from './api/chain-tips';
|
||||||
import { AxiosError } from 'axios';
|
import { AxiosError } from 'axios';
|
||||||
|
|
||||||
@ -84,11 +83,8 @@ class Server {
|
|||||||
if (config.DATABASE.ENABLED) {
|
if (config.DATABASE.ENABLED) {
|
||||||
await DB.checkDbConnection();
|
await DB.checkDbConnection();
|
||||||
try {
|
try {
|
||||||
if (process.env.npm_config_reindex !== undefined) { // Re-index requests
|
if (process.env.npm_config_reindex_blocks === 'true') { // Re-index requests
|
||||||
const tables = process.env.npm_config_reindex.split(',');
|
await databaseMigration.$blocksReindexingTruncate();
|
||||||
logger.warn(`Indexed data for "${process.env.npm_config_reindex}" tables will be erased in 5 seconds (using '--reindex')`);
|
|
||||||
await Common.sleep$(5000);
|
|
||||||
await databaseMigration.$truncateIndexedData(tables);
|
|
||||||
}
|
}
|
||||||
await databaseMigration.$initializeOrMigrateDatabase();
|
await databaseMigration.$initializeOrMigrateDatabase();
|
||||||
if (Common.indexingEnabled()) {
|
if (Common.indexingEnabled()) {
|
||||||
|
@ -16,6 +16,9 @@ class BlocksRepository {
|
|||||||
* Save indexed block data in the database
|
* Save indexed block data in the database
|
||||||
*/
|
*/
|
||||||
public async $saveBlockInDatabase(block: BlockExtended) {
|
public async $saveBlockInDatabase(block: BlockExtended) {
|
||||||
|
const truncatedCoinbaseSignature = block?.extras?.coinbaseSignature?.substring(0, 500);
|
||||||
|
const truncatedCoinbaseSignatureAscii = block?.extras?.coinbaseSignatureAscii?.substring(0, 500);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const query = `INSERT INTO blocks(
|
const query = `INSERT INTO blocks(
|
||||||
height, hash, blockTimestamp, size,
|
height, hash, blockTimestamp, size,
|
||||||
@ -65,7 +68,7 @@ class BlocksRepository {
|
|||||||
block.extras.medianTimestamp,
|
block.extras.medianTimestamp,
|
||||||
block.extras.header,
|
block.extras.header,
|
||||||
block.extras.coinbaseAddress,
|
block.extras.coinbaseAddress,
|
||||||
block.extras.coinbaseSignature,
|
truncatedCoinbaseSignature,
|
||||||
block.extras.utxoSetSize,
|
block.extras.utxoSetSize,
|
||||||
block.extras.utxoSetChange,
|
block.extras.utxoSetChange,
|
||||||
block.extras.avgTxSize,
|
block.extras.avgTxSize,
|
||||||
@ -78,7 +81,7 @@ class BlocksRepository {
|
|||||||
block.extras.segwitTotalSize,
|
block.extras.segwitTotalSize,
|
||||||
block.extras.segwitTotalWeight,
|
block.extras.segwitTotalWeight,
|
||||||
block.extras.medianFeeAmt,
|
block.extras.medianFeeAmt,
|
||||||
block.extras.coinbaseSignatureAscii,
|
truncatedCoinbaseSignatureAscii,
|
||||||
];
|
];
|
||||||
|
|
||||||
await DB.query(query, params);
|
await DB.query(query, params);
|
||||||
|
@ -99,7 +99,7 @@ class PoolsRepository {
|
|||||||
rows[0].regexes = JSON.parse(rows[0].regexes);
|
rows[0].regexes = JSON.parse(rows[0].regexes);
|
||||||
}
|
}
|
||||||
if (['testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) {
|
if (['testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) {
|
||||||
rows[0].addresses = []; // pools.json only contains mainnet addresses
|
rows[0].addresses = []; // pools-v2.json only contains mainnet addresses
|
||||||
} else if (parse) {
|
} else if (parse) {
|
||||||
rows[0].addresses = JSON.parse(rows[0].addresses);
|
rows[0].addresses = JSON.parse(rows[0].addresses);
|
||||||
}
|
}
|
||||||
|
@ -17,11 +17,6 @@ class PoolsUpdater {
|
|||||||
treeUrl: string = config.MEMPOOL.POOLS_JSON_TREE_URL;
|
treeUrl: string = config.MEMPOOL.POOLS_JSON_TREE_URL;
|
||||||
|
|
||||||
public async updatePoolsJson(): Promise<void> {
|
public async updatePoolsJson(): Promise<void> {
|
||||||
if (config.MEMPOOL.AUTOMATIC_BLOCK_REINDEXING === false) {
|
|
||||||
logger.info(`Not updating mining pools to avoid inconsistency because AUTOMATIC_BLOCK_REINDEXING is set to false`)
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) {
|
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -36,12 +31,6 @@ class PoolsUpdater {
|
|||||||
|
|
||||||
this.lastRun = now;
|
this.lastRun = now;
|
||||||
|
|
||||||
if (config.SOCKS5PROXY.ENABLED) {
|
|
||||||
logger.info(`Updating latest mining pools from ${this.poolsUrl} over the Tor network`, logger.tags.mining);
|
|
||||||
} else {
|
|
||||||
logger.info(`Updating latest mining pools from ${this.poolsUrl} over clearnet`, logger.tags.mining);
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const githubSha = await this.fetchPoolsSha(); // Fetch pools-v2.json sha from github
|
const githubSha = await this.fetchPoolsSha(); // Fetch pools-v2.json sha from github
|
||||||
if (githubSha === undefined) {
|
if (githubSha === undefined) {
|
||||||
@ -57,10 +46,21 @@ class PoolsUpdater {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// See backend README for more details about the mining pools update process
|
||||||
|
if (this.currentSha !== undefined && // If we don't have any mining pool, download it at least once
|
||||||
|
config.MEMPOOL.AUTOMATIC_BLOCK_REINDEXING !== true && // Automatic pools update is disabled
|
||||||
|
!process.env.npm_config_update_pools // We're not manually updating mining pool
|
||||||
|
) {
|
||||||
|
logger.warn(`Updated mining pools data is available (${githubSha}) but AUTOMATIC_BLOCK_REINDEXING is disabled`);
|
||||||
|
logger.info(`You can update your mining pools using the --update-pools command flag. You may want to clear your nginx cache as well if applicable`);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const network = config.SOCKS5PROXY.ENABLED ? 'tor' : 'clearnet';
|
||||||
if (this.currentSha === undefined) {
|
if (this.currentSha === undefined) {
|
||||||
logger.info(`Downloading pools-v2.json for the first time from ${this.poolsUrl}`, logger.tags.mining);
|
logger.info(`Downloading pools-v2.json for the first time from ${this.poolsUrl} over ${network}`, logger.tags.mining);
|
||||||
} else {
|
} else {
|
||||||
logger.warn(`pools-v2.json is outdated, fetch latest from ${this.poolsUrl}`, logger.tags.mining);
|
logger.warn(`pools-v2.json is outdated, fetch latest from ${this.poolsUrl} over ${network}`, logger.tags.mining);
|
||||||
}
|
}
|
||||||
const poolsJson = await this.query(this.poolsUrl);
|
const poolsJson = await this.query(this.poolsUrl);
|
||||||
if (poolsJson === undefined) {
|
if (poolsJson === undefined) {
|
||||||
|
@ -102,11 +102,11 @@ Below we list all settings from `mempool-config.json` and the corresponding over
|
|||||||
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
"MEMPOOL_BLOCKS_AMOUNT": 8,
|
||||||
"BLOCKS_SUMMARIES_INDEXING": false,
|
"BLOCKS_SUMMARIES_INDEXING": false,
|
||||||
"USE_SECOND_NODE_FOR_MINFEE": false,
|
"USE_SECOND_NODE_FOR_MINFEE": false,
|
||||||
"EXTERNAL_ASSETS": ["https://raw.githubusercontent.com/mempool/mining-pools/master/pools.json"],
|
"EXTERNAL_ASSETS": [],
|
||||||
"STDOUT_LOG_MIN_PRIORITY": "info",
|
"STDOUT_LOG_MIN_PRIORITY": "info",
|
||||||
"INDEXING_BLOCKS_AMOUNT": false,
|
"INDEXING_BLOCKS_AMOUNT": false,
|
||||||
"AUTOMATIC_BLOCK_REINDEXING": false,
|
"AUTOMATIC_BLOCK_REINDEXING": false,
|
||||||
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools.json",
|
"POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json",
|
||||||
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
"POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master",
|
||||||
"ADVANCED_GBT_AUDIT": false,
|
"ADVANCED_GBT_AUDIT": false,
|
||||||
"ADVANCED_GBT_MEMPOOL": false,
|
"ADVANCED_GBT_MEMPOOL": false,
|
||||||
|
@ -24,7 +24,7 @@ __MEMPOOL_USER_AGENT__=${MEMPOOL_USER_AGENT:=mempool}
|
|||||||
__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=info}
|
__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=info}
|
||||||
__MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=false}
|
__MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=false}
|
||||||
__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__=${MEMPOOL_AUTOMATIC_BLOCK_REINDEXING:=false}
|
__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__=${MEMPOOL_AUTOMATIC_BLOCK_REINDEXING:=false}
|
||||||
__MEMPOOL_POOLS_JSON_URL__=${MEMPOOL_POOLS_JSON_URL:=https://raw.githubusercontent.com/mempool/mining-pools/master/pools.json}
|
__MEMPOOL_POOLS_JSON_URL__=${MEMPOOL_POOLS_JSON_URL:=https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json}
|
||||||
__MEMPOOL_POOLS_JSON_TREE_URL__=${MEMPOOL_POOLS_JSON_TREE_URL:=https://api.github.com/repos/mempool/mining-pools/git/trees/master}
|
__MEMPOOL_POOLS_JSON_TREE_URL__=${MEMPOOL_POOLS_JSON_TREE_URL:=https://api.github.com/repos/mempool/mining-pools/git/trees/master}
|
||||||
__MEMPOOL_AUDIT__=${MEMPOOL_AUDIT:=false}
|
__MEMPOOL_AUDIT__=${MEMPOOL_AUDIT:=false}
|
||||||
__MEMPOOL_ADVANCED_GBT_AUDIT__=${MEMPOOL_ADVANCED_GBT_AUDIT:=false}
|
__MEMPOOL_ADVANCED_GBT_AUDIT__=${MEMPOOL_ADVANCED_GBT_AUDIT:=false}
|
||||||
|
@ -352,7 +352,7 @@
|
|||||||
|
|
||||||
<div class="copyright">
|
<div class="copyright">
|
||||||
<div class="title">
|
<div class="title">
|
||||||
Copyright © 2019-2022<br>
|
Copyright © 2019-2023<br>
|
||||||
The Mempool Open Source Project
|
The Mempool Open Source Project
|
||||||
</div>
|
</div>
|
||||||
<p>
|
<p>
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { Observable, Subscription } from 'rxjs';
|
import { Observable, Subscription } from 'rxjs';
|
||||||
import { Price } from 'src/app/services/price.service';
|
import { Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-amount',
|
selector: 'app-amount',
|
||||||
|
@ -5,7 +5,7 @@ import BlockScene from './block-scene';
|
|||||||
import TxSprite from './tx-sprite';
|
import TxSprite from './tx-sprite';
|
||||||
import TxView from './tx-view';
|
import TxView from './tx-view';
|
||||||
import { Position } from './sprite-types';
|
import { Position } from './sprite-types';
|
||||||
import { Price } from 'src/app/services/price.service';
|
import { Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block-overview-graph',
|
selector: 'app-block-overview-graph',
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
import { Component, ElementRef, ViewChild, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
|
import { Component, ElementRef, ViewChild, Input, OnChanges, ChangeDetectionStrategy } from '@angular/core';
|
||||||
import { TransactionStripped } from '../../interfaces/websocket.interface';
|
import { TransactionStripped } from '../../interfaces/websocket.interface';
|
||||||
import { Position } from '../../components/block-overview-graph/sprite-types.js';
|
import { Position } from '../../components/block-overview-graph/sprite-types.js';
|
||||||
import { Price } from 'src/app/services/price.service';
|
import { Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block-overview-tooltip',
|
selector: 'app-block-overview-tooltip',
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="block-titles">
|
<div class="block-titles">
|
||||||
<h1 class="title">
|
<h1 class="title">
|
||||||
<ng-template [ngIf]="blockHeight === 0"><ng-container i18n="@@2303359202781425764">Genesis</ng-container></ng-template>
|
<ng-template [ngIf]="blockHeight === 0"><ng-container i18n="@@2303359202781425764">Genesis</ng-container></ng-template>
|
||||||
<ng-template [ngIf]="blockHeight" i18n="shared.block-title">{{ blockHeight }}</ng-template>
|
<ng-template [ngIf]="blockHeight">{{ blockHeight }}</ng-template>
|
||||||
</h1>
|
</h1>
|
||||||
<div class="blockhash" *ngIf="blockHash">
|
<div class="blockhash" *ngIf="blockHash">
|
||||||
<h2 class="truncate right">{{ blockHash.slice(0,32) }}</h2>
|
<h2 class="truncate right">{{ blockHash.slice(0,32) }}</h2>
|
||||||
|
@ -13,7 +13,7 @@ import { BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces
|
|||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component';
|
||||||
import { detectWebGL } from '../../shared/graphs.utils';
|
import { detectWebGL } from '../../shared/graphs.utils';
|
||||||
import { PriceService, Price } from 'src/app/services/price.service';
|
import { PriceService, Price } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-block',
|
selector: 'app-block',
|
||||||
|
@ -43,10 +43,8 @@
|
|||||||
<div [attr.data-cy]="'bitcoin-block-' + i + '-transactions'" class="transaction-count">
|
<div [attr.data-cy]="'bitcoin-block-' + i + '-transactions'" class="transaction-count">
|
||||||
<ng-container
|
<ng-container
|
||||||
*ngTemplateOutlet="block.tx_count === 1 ? transactionsSingular : transactionsPlural; context: {$implicit: block.tx_count | number}"></ng-container>
|
*ngTemplateOutlet="block.tx_count === 1 ? transactionsSingular : transactionsPlural; context: {$implicit: block.tx_count | number}"></ng-container>
|
||||||
<ng-template #transactionsSingular let-i i18n="shared.transaction-count.singular">{{ i }}
|
<ng-template #transactionsSingular let-i i18n="shared.transaction-count.singular">{{ i }} transaction</ng-template>
|
||||||
transaction</ng-template>
|
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }} transactions</ng-template>
|
||||||
<ng-template #transactionsPlural let-i i18n="shared.transaction-count.plural">{{ i }}
|
|
||||||
transactions</ng-template>
|
|
||||||
</div>
|
</div>
|
||||||
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-time'" class="time-difference">
|
<div [attr.data-cy]="'bitcoin-block-' + offset + '-index-' + i + '-time'" class="time-difference">
|
||||||
<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></div>
|
<app-time-since [time]="block.timestamp" [fastRender]="true"></app-time-since></div>
|
||||||
|
@ -1,30 +1,30 @@
|
|||||||
<div class="dropdown-menu show" *ngIf="results" [hidden]="!results.hashQuickMatch && !results.addresses.length && !results.nodes.length && !results.channels.length">
|
<div class="dropdown-menu show" *ngIf="results" [hidden]="!results.hashQuickMatch && !results.addresses.length && !results.nodes.length && !results.channels.length">
|
||||||
<ng-template [ngIf]="results.blockHeight">
|
<ng-template [ngIf]="results.blockHeight">
|
||||||
<div class="card-title">Bitcoin Block Height</div>
|
<div class="card-title" i18n="search.bitcoin-block-height">Bitcoin Block Height</div>
|
||||||
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
||||||
Go to "{{ results.searchText }}"
|
<ng-container *ngTemplateOutlet="goTo; context: { $implicit: results.searchText }"></ng-container>
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="results.txId">
|
<ng-template [ngIf]="results.txId">
|
||||||
<div class="card-title">Bitcoin Transaction</div>
|
<div class="card-title" i18n="search.bitcoin-transaction">Bitcoin Transaction</div>
|
||||||
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
||||||
Go to "{{ results.searchText | shortenString : 13 }}"
|
<ng-container *ngTemplateOutlet="goTo; context: { $implicit: results.searchText | shortenString : 13 }"></ng-container>
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="results.address">
|
<ng-template [ngIf]="results.address">
|
||||||
<div class="card-title">Bitcoin Address</div>
|
<div class="card-title" i18n="search.bitcoin-address">Bitcoin Address</div>
|
||||||
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
||||||
Go to "{{ results.searchText | shortenString : isMobile ? 20 : 30 }}"
|
<ng-container *ngTemplateOutlet="goTo; context: { $implicit: results.searchText | shortenString : isMobile ? 20 : 30 }"></ng-container>
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="results.blockHash">
|
<ng-template [ngIf]="results.blockHash">
|
||||||
<div class="card-title">Bitcoin Block</div>
|
<div class="card-title" i18n="search.bitcoin-block">Bitcoin Block</div>
|
||||||
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(0)" [class.active]="0 === activeIdx" type="button" role="option" class="dropdown-item">
|
||||||
Go to "{{ results.searchText | shortenString : 13 }}"
|
<ng-container *ngTemplateOutlet="goTo; context: { $implicit: results.searchText | shortenString : 13 }"></ng-container>
|
||||||
</button>
|
</button>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="results.addresses.length">
|
<ng-template [ngIf]="results.addresses.length">
|
||||||
<div class="card-title">Bitcoin Addresses</div>
|
<div class="card-title" i18n="search.bitcoin-addresses">Bitcoin Addresses</div>
|
||||||
<ng-template ngFor [ngForOf]="results.addresses" let-address let-i="index">
|
<ng-template ngFor [ngForOf]="results.addresses" let-address let-i="index">
|
||||||
<button (click)="clickItem(results.hashQuickMatch + i)" [class.active]="(results.hashQuickMatch + i) === activeIdx" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(results.hashQuickMatch + i)" [class.active]="(results.hashQuickMatch + i) === activeIdx" type="button" role="option" class="dropdown-item">
|
||||||
<ngb-highlight [result]="address | shortenString : isMobile ? 25 : 36" [term]="results.searchText"></ngb-highlight>
|
<ngb-highlight [result]="address | shortenString : isMobile ? 25 : 36" [term]="results.searchText"></ngb-highlight>
|
||||||
@ -32,7 +32,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="results.nodes.length">
|
<ng-template [ngIf]="results.nodes.length">
|
||||||
<div class="card-title">Lightning Nodes</div>
|
<div class="card-title" i18n="search.lightning-nodes">Lightning Nodes</div>
|
||||||
<ng-template ngFor [ngForOf]="results.nodes" let-node let-i="index">
|
<ng-template ngFor [ngForOf]="results.nodes" let-node let-i="index">
|
||||||
<button (click)="clickItem(results.hashQuickMatch + results.addresses.length + i)" [class.inactive]="node.status === 0" [class.active]="results.hashQuickMatch + results.addresses.length + i === activeIdx" [routerLink]="['/lightning/node' | relativeUrl, node.public_key]" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(results.hashQuickMatch + results.addresses.length + i)" [class.inactive]="node.status === 0" [class.active]="results.hashQuickMatch + results.addresses.length + i === activeIdx" [routerLink]="['/lightning/node' | relativeUrl, node.public_key]" type="button" role="option" class="dropdown-item">
|
||||||
<ngb-highlight [result]="node.alias" [term]="results.searchText"></ngb-highlight> <span class="symbol">{{ node.public_key | shortenString : 10 }}</span>
|
<ngb-highlight [result]="node.alias" [term]="results.searchText"></ngb-highlight> <span class="symbol">{{ node.public_key | shortenString : 10 }}</span>
|
||||||
@ -40,7 +40,7 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
<ng-template [ngIf]="results.channels.length">
|
<ng-template [ngIf]="results.channels.length">
|
||||||
<div class="card-title">Lightning Channels</div>
|
<div class="card-title" i18n="search.lightning-channels">Lightning Channels</div>
|
||||||
<ng-template ngFor [ngForOf]="results.channels" let-channel let-i="index">
|
<ng-template ngFor [ngForOf]="results.channels" let-channel let-i="index">
|
||||||
<button (click)="clickItem(results.hashQuickMatch + results.addresses.length + results.nodes.length + i)" [class.inactive]="channel.status === 2" [class.active]="results.hashQuickMatch + results.addresses.length + results.nodes.length + i === activeIdx" type="button" role="option" class="dropdown-item">
|
<button (click)="clickItem(results.hashQuickMatch + results.addresses.length + results.nodes.length + i)" [class.inactive]="channel.status === 2" [class.active]="results.hashQuickMatch + results.addresses.length + results.nodes.length + i === activeIdx" type="button" role="option" class="dropdown-item">
|
||||||
<ngb-highlight [result]="channel.short_id" [term]="results.searchText"></ngb-highlight> <span class="symbol">{{ channel.id }}</span>
|
<ngb-highlight [result]="channel.short_id" [term]="results.searchText"></ngb-highlight> <span class="symbol">{{ channel.id }}</span>
|
||||||
@ -48,3 +48,5 @@
|
|||||||
</ng-template>
|
</ng-template>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<ng-template #goTo let-x i18n="search.go-to">Go to "{{ x }}"</ng-template>
|
||||||
|
@ -22,7 +22,7 @@ import { SeoService } from '../../services/seo.service';
|
|||||||
import { BlockExtended, CpfpInfo } from '../../interfaces/node-api.interface';
|
import { BlockExtended, CpfpInfo } from '../../interfaces/node-api.interface';
|
||||||
import { LiquidUnblinding } from './liquid-ublinding';
|
import { LiquidUnblinding } from './liquid-ublinding';
|
||||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||||
import { Price, PriceService } from 'src/app/services/price.service';
|
import { Price, PriceService } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transaction',
|
selector: 'app-transaction',
|
||||||
|
@ -9,7 +9,7 @@ import { AssetsService } from '../../services/assets.service';
|
|||||||
import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators';
|
import { filter, map, tap, switchMap, shareReplay } from 'rxjs/operators';
|
||||||
import { BlockExtended } from '../../interfaces/node-api.interface';
|
import { BlockExtended } from '../../interfaces/node-api.interface';
|
||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { PriceService } from 'src/app/services/price.service';
|
import { PriceService } from '../../services/price.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-transactions-list',
|
selector: 'app-transactions-list',
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Component, ElementRef, ViewChild, Input, OnChanges, OnInit } from '@angular/core';
|
import { Component, ElementRef, ViewChild, Input, OnChanges, OnInit } from '@angular/core';
|
||||||
import { tap } from 'rxjs';
|
import { tap } from 'rxjs';
|
||||||
import { Price, PriceService } from 'src/app/services/price.service';
|
import { Price, PriceService } from '../../services/price.service';
|
||||||
|
|
||||||
interface Xput {
|
interface Xput {
|
||||||
type: 'input' | 'output' | 'fee';
|
type: 'input' | 'output' | 'fee';
|
||||||
|
@ -10,7 +10,7 @@
|
|||||||
<div class="doc-content">
|
<div class="doc-content">
|
||||||
|
|
||||||
<div id="disclaimer">
|
<div id="disclaimer">
|
||||||
<table><tr><td><svg viewBox="0 0 304 304" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" style="fill:#ffc107;fill-opacity:1"><path d="M135.3 34.474c-15.62 27.306-54.206 95.63-85.21 150.534L9.075 257.583C5.382 264.08 6.76 269.217 7.908 271.7c2.326 5.028 7.29 7.537 11.155 8.215l.78.133 264.698.006-.554-.02c4.152.255 9.664-1.24 12.677-6.194 1.926-3.18 3.31-8.589-1.073-16.278L213.637 114.37l-45.351-79.205c-5.681-9.932-12.272-12.022-16.8-12.022-4.42 0-10.818 1.964-16.181 11.331h-.006zm-69.072 159.94c30.997-54.885 69.563-123.184 85.16-150.446l.186-.297c.2.303.393.582.618.981l45.363 79.22s72.377 126.47 78.569 137.283l-247.618-.007 37.719-66.734" style="fill:#ffc107;fill-opacity:1"/><path d="M152.597 247.445c8.02 0 14.518-6.728 14.518-15.025 0-8.29-6.499-15.018-14.518-15.018-8.031 0-14.529 6.728-14.529 15.018 0 8.297 6.498 15.025 14.53 15.025m-.001-147.18c11.586 0 22.23 10.958 20.977 21.7l-9.922 75.564c-.966 6.601-4.95 11.433-11.055 11.433s-10.102-4.832-11.056-11.433l-9.927-75.564c-1.26-10.742 9.39-21.7 20.983-21.7" style="fill:#ffc107;fill-opacity:1"/></g></svg></td><td><p><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table>
|
<table><tr><td><svg viewBox="0 0 304 304" xmlns="http://www.w3.org/2000/svg"><g fill-rule="evenodd" style="fill:#ffc107;fill-opacity:1"><path d="M135.3 34.474c-15.62 27.306-54.206 95.63-85.21 150.534L9.075 257.583C5.382 264.08 6.76 269.217 7.908 271.7c2.326 5.028 7.29 7.537 11.155 8.215l.78.133 264.698.006-.554-.02c4.152.255 9.664-1.24 12.677-6.194 1.926-3.18 3.31-8.589-1.073-16.278L213.637 114.37l-45.351-79.205c-5.681-9.932-12.272-12.022-16.8-12.022-4.42 0-10.818 1.964-16.181 11.331h-.006zm-69.072 159.94c30.997-54.885 69.563-123.184 85.16-150.446l.186-.297c.2.303.393.582.618.981l45.363 79.22s72.377 126.47 78.569 137.283l-247.618-.007 37.719-66.734" style="fill:#ffc107;fill-opacity:1"/><path d="M152.597 247.445c8.02 0 14.518-6.728 14.518-15.025 0-8.29-6.499-15.018-14.518-15.018-8.031 0-14.529 6.728-14.529 15.018 0 8.297 6.498 15.025 14.53 15.025m-.001-147.18c11.586 0 22.23 10.958 20.977 21.7l-9.922 75.564c-.966 6.601-4.95 11.433-11.055 11.433s-10.102-4.832-11.056-11.433l-9.927-75.564c-1.26-10.742 9.39-21.7 20.983-21.7" style="fill:#ffc107;fill-opacity:1"/></g></svg></td><td><p i18n="faq.big-disclaimer"><b>mempool.space merely provides data about the Bitcoin network.</b> It cannot help you with retrieving funds, confirming your transaction quicker, etc.</p><p>For any such requests, you need to get in touch with the entity that helped make the transaction (wallet software, exchange company, etc).</p></td></tr></table>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
@ -1,25 +1,32 @@
|
|||||||
<div class="container-xl" *ngIf="(channel$ | async) as channel; else skeletonLoader">
|
<div class="container-xl" *ngIf="(channel$ | async) as channel; else skeletonLoader">
|
||||||
<h5 class="mb-0" style="color: #ffffff66" i18n="lightning.channel">Lightning channel</h5>
|
|
||||||
<div class="title-container">
|
<ng-container *ngIf="!error">
|
||||||
<h1 class="mb-0">{{ channel.short_id }}</h1>
|
<h5 class="mb-0" style="color: #ffffff66" i18n="lightning.channel">Lightning channel</h5>
|
||||||
<span class="tx-link">
|
<div class="title-container">
|
||||||
<a [routerLink]="['/lightning/channel' | relativeUrl, channel.id]">{{ channel.id }}</a>
|
<h1 class="mb-0">{{ channel.short_id }}</h1>
|
||||||
<app-clipboard [text]="channel.id"></app-clipboard>
|
<span class="tx-link">
|
||||||
</span>
|
<a [routerLink]="['/lightning/channel' | relativeUrl, channel.id]">{{ channel.id }}</a>
|
||||||
</div>
|
<app-clipboard [text]="channel.id"></app-clipboard>
|
||||||
<div class="badges mb-2">
|
</span>
|
||||||
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0" i18n="status.inactive">Inactive</span>
|
</div>
|
||||||
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1" i18n="status.active">Active</span>
|
<div class="badges mb-2">
|
||||||
<span class="badge rounded-pill badge-danger" *ngIf="channel.status === 2" i18n="status.closed">Closed</span>
|
<span class="badge rounded-pill badge-secondary" *ngIf="channel.status === 0" i18n="status.inactive">Inactive</span>
|
||||||
<app-closing-type *ngIf="channel.closing_reason" [type]="channel.closing_reason"></app-closing-type>
|
<span class="badge rounded-pill badge-success" *ngIf="channel.status === 1" i18n="status.active">Active</span>
|
||||||
</div>
|
<span class="badge rounded-pill badge-danger" *ngIf="channel.status === 2" i18n="status.closed">Closed</span>
|
||||||
|
<app-closing-type *ngIf="channel.closing_reason" [type]="channel.closing_reason"></app-closing-type>
|
||||||
|
</div>
|
||||||
|
</ng-container>
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
|
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
||||||
|
<span class="text-center" i18n="lightning.channel-not-found">No channel found for short id "{{ channel.short_id }}"</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
<app-nodes-channels-map *ngIf="!error && (channelGeo$ | async) as channelGeo" [style]="'channelpage'"
|
<app-nodes-channels-map *ngIf="!error && (channelGeo$ | async) as channelGeo" [style]="'channelpage'"
|
||||||
[channel]="channelGeo"></app-nodes-channels-map>
|
[channel]="channelGeo"></app-nodes-channels-map>
|
||||||
|
|
||||||
<div class="box">
|
<div class="box" *ngIf="!error">
|
||||||
|
|
||||||
<div class="row">
|
<div class="row">
|
||||||
<div class="col-md">
|
<div class="col-md">
|
||||||
@ -65,7 +72,7 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<div class="row row-cols-1 row-cols-md-2">
|
<div class="row row-cols-1 row-cols-md-2" *ngIf="!error">
|
||||||
<div class="col">
|
<div class="col">
|
||||||
<app-channel-box [channel]="channel.node_left"></app-channel-box>
|
<app-channel-box [channel]="channel.node_left"></app-channel-box>
|
||||||
<app-channel-close-box *ngIf="showCloseBoxes(channel)" [channel]="channel" [local]="channel.node_left" [remote]="channel.node_right"></app-channel-close-box>
|
<app-channel-close-box *ngIf="showCloseBoxes(channel)" [channel]="channel" [local]="channel.node_left" [remote]="channel.node_right"></app-channel-close-box>
|
||||||
@ -104,14 +111,6 @@
|
|||||||
|
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
<ng-template [ngIf]="error">
|
|
||||||
<div class="text-center">
|
|
||||||
<span i18n="error.general-loading-data">Error loading data.</span>
|
|
||||||
<br><br>
|
|
||||||
<i>{{ error.status }}: {{ error.error }}</i>
|
|
||||||
</div>
|
|
||||||
</ng-template>
|
|
||||||
|
|
||||||
<ng-template #skeletonLoader>
|
<ng-template #skeletonLoader>
|
||||||
<div class="container-xl">
|
<div class="container-xl">
|
||||||
<h5 class="mb-0" style="color: #ffffff66" i18n="lightning.channel">Lightning channel</h5>
|
<h5 class="mb-0" style="color: #ffffff66" i18n="lightning.channel">Lightning channel</h5>
|
||||||
|
@ -38,7 +38,9 @@ export class ChannelComponent implements OnInit {
|
|||||||
}),
|
}),
|
||||||
catchError((err) => {
|
catchError((err) => {
|
||||||
this.error = err;
|
this.error = err;
|
||||||
return of(null);
|
return [{
|
||||||
|
short_id: params.get('short_id')
|
||||||
|
}];
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
|
@ -17,19 +17,19 @@ export class ClosingTypeComponent implements OnChanges {
|
|||||||
getLabelFromType(type: number): { label: string; class: string } {
|
getLabelFromType(type: number): { label: string; class: string } {
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case 1: return {
|
case 1: return {
|
||||||
label: 'Mutually closed',
|
label: $localize`Mutually closed`,
|
||||||
class: 'success',
|
class: 'success',
|
||||||
};
|
};
|
||||||
case 2: return {
|
case 2: return {
|
||||||
label: 'Force closed',
|
label: $localize`Force closed`,
|
||||||
class: 'warning',
|
class: 'warning',
|
||||||
};
|
};
|
||||||
case 3: return {
|
case 3: return {
|
||||||
label: 'Force closed with penalty',
|
label: $localize`Force closed with penalty`,
|
||||||
class: 'danger',
|
class: 'danger',
|
||||||
};
|
};
|
||||||
default: return {
|
default: return {
|
||||||
label: 'Unknown',
|
label: $localize`:@@e5d8bb389c702588877f039d72178f219453a72d:Unknown`,
|
||||||
class: 'secondary',
|
class: 'secondary',
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
<div class="widget-toggler">
|
<div class="widget-toggler">
|
||||||
<a href="" (click)="switchMode('avg')" class="toggler-option"
|
<a href="" (click)="switchMode('avg')" class="toggler-option"
|
||||||
[ngClass]="{'inactive': mode === 'avg'}"><small>avg</small></a>
|
[ngClass]="{'inactive': mode === 'avg'}"><small i18n="statistics.average-small">avg</small></a>
|
||||||
<span style="color: #ffffff66; font-size: 8px"> | </span>
|
<span style="color: #ffffff66; font-size: 8px"> | </span>
|
||||||
<a href="" (click)="switchMode('med')" class="toggler-option"
|
<a href="" (click)="switchMode('med')" class="toggler-option"
|
||||||
[ngClass]="{'inactive': mode === 'med'}"><small>med</small></a>
|
[ngClass]="{'inactive': mode === 'med'}"><small i18n="statistics.median-small">med</small></a>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="fee-estimation-wrapper" *ngIf="statistics$ | async as statistics; else loadingReward">
|
<div class="fee-estimation-wrapper" *ngIf="statistics$ | async as statistics; else loadingReward">
|
||||||
|
@ -167,7 +167,7 @@ export class NodeFeeChartComponent implements OnInit {
|
|||||||
padding: 10,
|
padding: 10,
|
||||||
data: [
|
data: [
|
||||||
{
|
{
|
||||||
name: 'Outgoing Fees',
|
name: $localize`Outgoing Fees`,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
@ -175,7 +175,7 @@ export class NodeFeeChartComponent implements OnInit {
|
|||||||
icon: 'roundRect',
|
icon: 'roundRect',
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Incoming Fees',
|
name: $localize`Incoming Fees`,
|
||||||
inactiveColor: 'rgb(110, 112, 121)',
|
inactiveColor: 'rgb(110, 112, 121)',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: 'white',
|
color: 'white',
|
||||||
@ -205,7 +205,7 @@ export class NodeFeeChartComponent implements OnInit {
|
|||||||
series: outgoingData.length === 0 ? undefined : [
|
series: outgoingData.length === 0 ? undefined : [
|
||||||
{
|
{
|
||||||
zlevel: 0,
|
zlevel: 0,
|
||||||
name: 'Outgoing Fees',
|
name: $localize`Outgoing Fees`,
|
||||||
data: outgoingData.map(bucket => ({
|
data: outgoingData.map(bucket => ({
|
||||||
value: bucket.capacity,
|
value: bucket.capacity,
|
||||||
label: bucket.label,
|
label: bucket.label,
|
||||||
@ -219,7 +219,7 @@ export class NodeFeeChartComponent implements OnInit {
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
zlevel: 0,
|
zlevel: 0,
|
||||||
name: 'Incoming Fees',
|
name: $localize`Incoming Fees`,
|
||||||
data: incomingData.map(bucket => ({
|
data: incomingData.map(bucket => ({
|
||||||
value: -bucket.capacity,
|
value: -bucket.capacity,
|
||||||
label: bucket.label,
|
label: bucket.label,
|
||||||
|
@ -1,20 +1,23 @@
|
|||||||
<div class="container-xl" *ngIf="(node$ | async) as node; else skeletonLoader">
|
<div class="container-xl" *ngIf="(node$ | async) as node; else skeletonLoader">
|
||||||
<h5 class="mb-0" style="color: #ffffff66" i18n="lightning.node">Lightning node</h5>
|
|
||||||
<div class="title-container mb-2" *ngIf="!error">
|
<ng-container *ngIf="!error">
|
||||||
<h1 class="mb-0 text-truncate">{{ node.alias }}</h1>
|
<h5 class="mb-0" style="color: #ffffff66" i18n="lightning.node">Lightning node</h5>
|
||||||
<span class="tx-link">
|
<div class="title-container mb-2">
|
||||||
<span class="node-id">
|
<h1 class="mb-0 text-truncate">{{ node.alias }}</h1>
|
||||||
<app-truncate [text]="node.public_key" [lastChars]="8" [link]="['/lightning/node' | relativeUrl, node.public_key]">
|
<span class="tx-link">
|
||||||
<app-clipboard [text]="node.public_key"></app-clipboard>
|
<span class="node-id">
|
||||||
</app-truncate>
|
<app-truncate [text]="node.public_key" [lastChars]="8" [link]="['/lightning/node' | relativeUrl, node.public_key]">
|
||||||
|
<app-clipboard [text]="node.public_key"></app-clipboard>
|
||||||
|
</app-truncate>
|
||||||
|
</span>
|
||||||
</span>
|
</span>
|
||||||
</span>
|
</div>
|
||||||
</div>
|
</ng-container>
|
||||||
|
|
||||||
<div class="clearfix"></div>
|
<div class="clearfix"></div>
|
||||||
|
|
||||||
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
<div *ngIf="error" class="d-flex flex-column justify-content-around align-items-center mt-5 w-100" style="min-height: 100px">
|
||||||
<span i18n="lightning.node-not-found">No node found for public key "{{ node.public_key | shortenString : 12}}"</span>
|
<span class="text-center" i18n="lightning.node-not-found">No node found for public key "{{ node.public_key | shortenString : 12}}"</span>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="box" *ngIf="!error">
|
<div class="box" *ngIf="!error">
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -13,7 +13,7 @@
|
|||||||
"AUDIT": true,
|
"AUDIT": true,
|
||||||
"CPFP_INDEXING": true,
|
"CPFP_INDEXING": true,
|
||||||
"ADVANCED_GBT_AUDIT": true,
|
"ADVANCED_GBT_AUDIT": true,
|
||||||
"ADVANCED_GBT_MEMPOOL": false,
|
"ADVANCED_GBT_MEMPOOL": true,
|
||||||
"USE_SECOND_NODE_FOR_MINFEE": true
|
"USE_SECOND_NODE_FOR_MINFEE": true
|
||||||
},
|
},
|
||||||
"SYSLOG" : {
|
"SYSLOG" : {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"INDEXING_BLOCKS_AMOUNT": -1,
|
"INDEXING_BLOCKS_AMOUNT": -1,
|
||||||
"AUDIT": true,
|
"AUDIT": true,
|
||||||
"ADVANCED_GBT_AUDIT": true,
|
"ADVANCED_GBT_AUDIT": true,
|
||||||
"ADVANCED_GBT_MEMPOOL": false,
|
"ADVANCED_GBT_MEMPOOL": true,
|
||||||
"POLL_RATE_MS": 1000
|
"POLL_RATE_MS": 1000
|
||||||
},
|
},
|
||||||
"SYSLOG" : {
|
"SYSLOG" : {
|
||||||
|
@ -9,7 +9,7 @@
|
|||||||
"INDEXING_BLOCKS_AMOUNT": -1,
|
"INDEXING_BLOCKS_AMOUNT": -1,
|
||||||
"AUDIT": true,
|
"AUDIT": true,
|
||||||
"ADVANCED_GBT_AUDIT": true,
|
"ADVANCED_GBT_AUDIT": true,
|
||||||
"ADVANCED_GBT_MEMPOOL": false,
|
"ADVANCED_GBT_MEMPOOL": true,
|
||||||
"POLL_RATE_MS": 1000
|
"POLL_RATE_MS": 1000
|
||||||
},
|
},
|
||||||
"SYSLOG" : {
|
"SYSLOG" : {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
#!/usr/bin/env zsh
|
#!/usr/bin/env zsh
|
||||||
hostname=$(hostname)
|
hostname=$(hostname)
|
||||||
slugs=(`curl -sSL https://raw.githubusercontent.com/mempool/mining-pools/master/pools.json | jq -r '.slugs[]'`)
|
slugs=(`curl -sSL https://${hostname}/api/v1/mining/pools/3y|jq -r -S '(.pools[].slug)'`)
|
||||||
|
|
||||||
warm()
|
warm()
|
||||||
{
|
{
|
||||||
|
Loading…
x
Reference in New Issue
Block a user