From 6fe08acebdf2222953d70d45df5d38a211dcb31a Mon Sep 17 00:00:00 2001 From: wiz Date: Tue, 4 Apr 2023 20:18:46 +0900 Subject: [PATCH 01/53] ops: Fix installer creation of CLN folders --- production/install | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/production/install b/production/install index 27c4dbd14..b97ef16d1 100755 --- a/production/install +++ b/production/install @@ -1312,8 +1312,13 @@ case $OS in osSudo "${ROOT_USER}" pw usermod ${MEMPOOL_USER} -G "${CLN_GROUP}" osSudo "${ROOT_USER}" chsh -s `which zsh` "${CLN_USER}" echo "export PATH=$PATH:$HOME/.local/bin" >> "${CLN_HOME}/.zshrc" - osSudo "${ROOT_USER}" mkdir -p "${CLN_HOME}/.lightning/{bitcoin,signet,testnet}" - osSudo "${ROOT_USER}" chmod 750 "${CLN_HOME}" "${CLN_HOME}/.lightning" "${CLN_HOME}/.lightning/{bitcoin,signet,testnet}" + osSudo "${ROOT_USER}" mkdir -p "${CLN_HOME}/.lightning/bitcoin" + osSudo "${ROOT_USER}" mkdir -p "${CLN_HOME}/.lightning/signet" + osSudo "${ROOT_USER}" mkdir -p "${CLN_HOME}/.lightning/testnet" + osSudo "${ROOT_USER}" chmod 750 "${CLN_HOME}" "${CLN_HOME}/.lightning" + osSudo "${ROOT_USER}" chmod 750 "${CLN_HOME}" "${CLN_HOME}/.lightning/bitcoin" + osSudo "${ROOT_USER}" chmod 750 "${CLN_HOME}" "${CLN_HOME}/.lightning/signet" + osSudo "${ROOT_USER}" chmod 750 "${CLN_HOME}" "${CLN_HOME}/.lightning/testnet" osSudo "${ROOT_USER}" chown -R "${CLN_USER}:${CLN_GROUP}" "${CLN_HOME}" echo "[*] Creating symlink to .bitcoin folder" osSudo "${CLN_USER}" ln -s "${BITCOIN_HOME}/.bitcoin" "${CLN_HOME}/.bitcoin" From 6faa86d433b56de3849326892a72a8cdc605d764 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 7 Apr 2023 03:25:02 +0900 Subject: [PATCH 02/53] Fit mempool block skeleton loaders to screen --- .../mempool-blocks.component.ts | 23 ++++++++++++++++++- 1 file changed, 22 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index 1b647fc53..ab0a7fd08 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -97,7 +97,7 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { this.mempoolEmptyBlocks.forEach((b) => { this.mempoolEmptyBlockStyles.push(this.getStyleForMempoolEmptyBlock(b.index)); }); - this.reduceMempoolBlocksToFitScreen(this.mempoolEmptyBlocks); + this.reduceEmptyBlocksToFitScreen(this.mempoolEmptyBlocks); this.mempoolBlocks.map(() => { this.updateMempoolBlockStyles(); @@ -225,12 +225,33 @@ export class MempoolBlocksComponent implements OnInit, OnDestroy { @HostListener('window:resize', ['$event']) onResize(): void { this.animateEntry = false; + this.reduceEmptyBlocksToFitScreen(this.mempoolEmptyBlocks); } trackByFn(index: number, block: MempoolBlock) { return (block.isStack) ? `stack-${block.index}` : block.index; } + reduceEmptyBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { + const innerWidth = this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2; + const blocksAmount = Math.min(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT, Math.floor(innerWidth / (this.blockWidth + this.blockPadding))); + while (blocks.length < blocksAmount) { + blocks.push({ + blockSize: 0, + blockVSize: 0, + feeRange: [], + index: blocks.length, + medianFee: 0, + nTx: 0, + totalFees: 0 + }); + } + while (blocks.length > blocksAmount) { + blocks.pop(); + } + return blocks; + } + reduceMempoolBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { const innerWidth = this.stateService.env.BASE_MODULE !== 'liquid' && window.innerWidth <= 767.98 ? window.innerWidth : window.innerWidth / 2; const blocksAmount = Math.min(this.stateService.env.MEMPOOL_BLOCKS_AMOUNT, Math.floor(innerWidth / (this.blockWidth + this.blockPadding))); From ceed573019ff072277991674b1cf520bae913716 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 3 May 2023 14:59:27 -0600 Subject: [PATCH 03/53] display fee box skeleton while mempool not in sync --- .../app/components/fees-box/fees-box.component.html | 2 +- .../app/components/fees-box/fees-box.component.ts | 13 +++++++++---- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/components/fees-box/fees-box.component.html b/frontend/src/app/components/fees-box/fees-box.component.html index b56663571..1aea85429 100644 --- a/frontend/src/app/components/fees-box/fees-box.component.html +++ b/frontend/src/app/components/fees-box/fees-box.component.html @@ -1,4 +1,4 @@ -
+
No Priority diff --git a/frontend/src/app/components/fees-box/fees-box.component.ts b/frontend/src/app/components/fees-box/fees-box.component.ts index 48098db7b..4f9772b22 100644 --- a/frontend/src/app/components/fees-box/fees-box.component.ts +++ b/frontend/src/app/components/fees-box/fees-box.component.ts @@ -1,9 +1,9 @@ import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; import { StateService } from '../../services/state.service'; -import { Observable } from 'rxjs'; +import { Observable, combineLatest } from 'rxjs'; import { Recommendedfees } from '../../interfaces/websocket.interface'; import { feeLevels, mempoolFeeColors } from '../../app.constants'; -import { tap } from 'rxjs/operators'; +import { map, startWith, tap } from 'rxjs/operators'; @Component({ selector: 'app-fees-box', @@ -12,7 +12,7 @@ import { tap } from 'rxjs/operators'; changeDetection: ChangeDetectionStrategy.OnPush, }) export class FeesBoxComponent implements OnInit { - isLoadingWebSocket$: Observable; + isLoading$: Observable; recommendedFees$: Observable; gradient = 'linear-gradient(to right, #2e324e, #2e324e)'; noPriority = '#2e324e'; @@ -22,7 +22,12 @@ export class FeesBoxComponent implements OnInit { ) { } ngOnInit(): void { - this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$; + this.isLoading$ = combineLatest( + this.stateService.isLoadingWebSocket$.pipe(startWith(false)), + this.stateService.loadingIndicators$.pipe(startWith({ mempool: 0 })), + ).pipe(map(([socket, indicators]) => { + return socket || (indicators.mempool != null && indicators.mempool !== 100); + })); this.recommendedFees$ = this.stateService.recommendedFees$ .pipe( tap((fees) => { From 8b999cc99bb383c45214441e5c96edd505b2d0e9 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 13 May 2023 15:28:29 +0200 Subject: [PATCH 04/53] [audit] warn if we cannot save templates and remove exception re-throw --- backend/src/repositories/BlocksSummariesRepository.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts index f2560fbe7..3a883585a 100644 --- a/backend/src/repositories/BlocksSummariesRepository.ts +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -45,8 +45,7 @@ class BlocksSummariesRepository { if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart logger.debug(`Cannot save block template for ${blockId} because it has already been indexed, ignoring`); } else { - logger.debug(`Cannot save block template for ${blockId}. Reason: ${e instanceof Error ? e.message : e}`); - throw e; + logger.warn(`Cannot save block template for ${blockId}. Reason: ${e instanceof Error ? e.message : e}`); } } } From 51f91dc44d13ae2d7afcff25591c505ab63e1ae5 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 13:13:37 -0700 Subject: [PATCH 05/53] Use the same delimiter for all substitutions --- docker/backend/start.sh | 100 ++++++++++++++++++++-------------------- 1 file changed, 50 insertions(+), 50 deletions(-) diff --git a/docker/backend/start.sh b/docker/backend/start.sh index a54f16ec6..54f0825d5 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -46,7 +46,7 @@ __ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS_ENABLED:=false} # ESPLORA __ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000} -__ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:=null} +__ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:="null"} __ESPLORA_RETRY_UNIX_SOCKET_AFTER__=${ESPLORA_RETRY_UNIX_SOCKET_AFTER:=30000} # SECOND_CORE_RPC @@ -127,28 +127,28 @@ __MAXMIND_GEOIP2_ISP__=${MAXMIND_GEOIP2_ISP:=""} mkdir -p "${__MEMPOOL_CACHE_DIR__}" -sed -i "s/__MEMPOOL_NETWORK__/${__MEMPOOL_NETWORK__}/g" mempool-config.json -sed -i "s/__MEMPOOL_BACKEND__/${__MEMPOOL_BACKEND__}/g" mempool-config.json -sed -i "s/__MEMPOOL_ENABLED__/${__MEMPOOL_ENABLED__}/g" mempool-config.json -sed -i "s/__MEMPOOL_HTTP_PORT__/${__MEMPOOL_HTTP_PORT__}/g" mempool-config.json -sed -i "s/__MEMPOOL_SPAWN_CLUSTER_PROCS__/${__MEMPOOL_SPAWN_CLUSTER_PROCS__}/g" mempool-config.json +sed -i "s!__MEMPOOL_NETWORK__!${__MEMPOOL_NETWORK__}!g" mempool-config.json +sed -i "s!__MEMPOOL_BACKEND__!${__MEMPOOL_BACKEND__}!g" mempool-config.json +sed -i "s!__MEMPOOL_ENABLED__!${__MEMPOOL_ENABLED__}!g" mempool-config.json +sed -i "s!__MEMPOOL_HTTP_PORT__!${__MEMPOOL_HTTP_PORT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_SPAWN_CLUSTER_PROCS__!${__MEMPOOL_SPAWN_CLUSTER_PROCS__}!g" mempool-config.json sed -i "s!__MEMPOOL_API_URL_PREFIX__!${__MEMPOOL_API_URL_PREFIX__}!g" mempool-config.json -sed -i "s/__MEMPOOL_POLL_RATE_MS__/${__MEMPOOL_POLL_RATE_MS__}/g" mempool-config.json +sed -i "s!__MEMPOOL_POLL_RATE_MS__!${__MEMPOOL_POLL_RATE_MS__}!g" mempool-config.json sed -i "s!__MEMPOOL_CACHE_DIR__!${__MEMPOOL_CACHE_DIR__}!g" mempool-config.json -sed -i "s/__MEMPOOL_CLEAR_PROTECTION_MINUTES__/${__MEMPOOL_CLEAR_PROTECTION_MINUTES__}/g" mempool-config.json -sed -i "s/__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__/${__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__}/g" mempool-config.json -sed -i "s/__MEMPOOL_BLOCK_WEIGHT_UNITS__/${__MEMPOOL_BLOCK_WEIGHT_UNITS__}/g" mempool-config.json -sed -i "s/__MEMPOOL_INITIAL_BLOCKS_AMOUNT__/${__MEMPOOL_INITIAL_BLOCKS_AMOUNT__}/g" mempool-config.json -sed -i "s/__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__/${__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__}/g" mempool-config.json -sed -i "s/__MEMPOOL_INDEXING_BLOCKS_AMOUNT__/${__MEMPOOL_INDEXING_BLOCKS_AMOUNT__}/g" mempool-config.json -sed -i "s/__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__/${__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__}/g" mempool-config.json -sed -i "s/__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__/${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}/g" mempool-config.json +sed -i "s!__MEMPOOL_CLEAR_PROTECTION_MINUTES__!${__MEMPOOL_CLEAR_PROTECTION_MINUTES__}!g" mempool-config.json +sed -i "s!__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__!${__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__}!g" mempool-config.json +sed -i "s!__MEMPOOL_BLOCK_WEIGHT_UNITS__!${__MEMPOOL_BLOCK_WEIGHT_UNITS__}!g" mempool-config.json +sed -i "s!__MEMPOOL_INITIAL_BLOCKS_AMOUNT__!${__MEMPOOL_INITIAL_BLOCKS_AMOUNT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__!${__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_INDEXING_BLOCKS_AMOUNT__!${__MEMPOOL_INDEXING_BLOCKS_AMOUNT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__!${__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__}!g" mempool-config.json +sed -i "s!__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__!${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}!g" mempool-config.json sed -i "s!__MEMPOOL_EXTERNAL_ASSETS__!${__MEMPOOL_EXTERNAL_ASSETS__}!g" mempool-config.json sed -i "s!__MEMPOOL_EXTERNAL_MAX_RETRY__!${__MEMPOOL_EXTERNAL_MAX_RETRY__}!g" mempool-config.json sed -i "s!__MEMPOOL_EXTERNAL_RETRY_INTERVAL__!${__MEMPOOL_EXTERNAL_RETRY_INTERVAL__}!g" mempool-config.json sed -i "s!__MEMPOOL_USER_AGENT__!${__MEMPOOL_USER_AGENT__}!g" mempool-config.json -sed -i "s/__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__/${__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__}/g" mempool-config.json -sed -i "s/__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__/${__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__}/g" mempool-config.json +sed -i "s!__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__!${__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__}!g" mempool-config.json +sed -i "s!__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__!${__MEMPOOL_AUTOMATIC_BLOCK_REINDEXING__}!g" mempool-config.json sed -i "s!__MEMPOOL_POOLS_JSON_URL__!${__MEMPOOL_POOLS_JSON_URL__}!g" mempool-config.json sed -i "s!__MEMPOOL_POOLS_JSON_TREE_URL__!${__MEMPOOL_POOLS_JSON_TREE_URL__}!g" mempool-config.json sed -i "s!__MEMPOOL_AUDIT__!${__MEMPOOL_AUDIT__}!g" mempool-config.json @@ -158,53 +158,53 @@ sed -i "s!__MEMPOOL_CPFP_INDEXING__!${__MEMPOOL_CPFP_INDEXING__}!g" mempool-conf sed -i "s!__MEMPOOL_MAX_BLOCKS_BULK_QUERY__!${__MEMPOOL_MAX_BLOCKS_BULK_QUERY__}!g" mempool-config.json sed -i "s!__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__!${__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__}!g" mempool-config.json -sed -i "s/__CORE_RPC_HOST__/${__CORE_RPC_HOST__}/g" mempool-config.json -sed -i "s/__CORE_RPC_PORT__/${__CORE_RPC_PORT__}/g" mempool-config.json -sed -i "s/__CORE_RPC_USERNAME__/${__CORE_RPC_USERNAME__}/g" mempool-config.json -sed -i "s/__CORE_RPC_PASSWORD__/${__CORE_RPC_PASSWORD__}/g" mempool-config.json -sed -i "s/__CORE_RPC_TIMEOUT__/${__CORE_RPC_TIMEOUT__}/g" mempool-config.json +sed -i "s!__CORE_RPC_HOST__!${__CORE_RPC_HOST__}!g" mempool-config.json +sed -i "s!__CORE_RPC_PORT__!${__CORE_RPC_PORT__}!g" mempool-config.json +sed -i "s!__CORE_RPC_USERNAME__!${__CORE_RPC_USERNAME__}!g" mempool-config.json +sed -i "s!__CORE_RPC_PASSWORD__!${__CORE_RPC_PASSWORD__}!g" mempool-config.json +sed -i "s!__CORE_RPC_TIMEOUT__!${__CORE_RPC_TIMEOUT__}!g" mempool-config.json -sed -i "s/__ELECTRUM_HOST__/${__ELECTRUM_HOST__}/g" mempool-config.json -sed -i "s/__ELECTRUM_PORT__/${__ELECTRUM_PORT__}/g" mempool-config.json -sed -i "s/__ELECTRUM_TLS_ENABLED__/${__ELECTRUM_TLS_ENABLED__}/g" mempool-config.json +sed -i "s!__ELECTRUM_HOST__!${__ELECTRUM_HOST__}!g" mempool-config.json +sed -i "s!__ELECTRUM_PORT__!${__ELECTRUM_PORT__}!g" mempool-config.json +sed -i "s!__ELECTRUM_TLS_ENABLED__!${__ELECTRUM_TLS_ENABLED__}!g" mempool-config.json sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json sed -i "s!__ESPLORA_UNIX_SOCKET_PATH__!${__ESPLORA_UNIX_SOCKET_PATH__}!g" mempool-config.json sed -i "s!__ESPLORA_RETRY_UNIX_SOCKET_AFTER__!${__ESPLORA_RETRY_UNIX_SOCKET_AFTER__}!g" mempool-config.json -sed -i "s/__SECOND_CORE_RPC_HOST__/${__SECOND_CORE_RPC_HOST__}/g" mempool-config.json -sed -i "s/__SECOND_CORE_RPC_PORT__/${__SECOND_CORE_RPC_PORT__}/g" mempool-config.json -sed -i "s/__SECOND_CORE_RPC_USERNAME__/${__SECOND_CORE_RPC_USERNAME__}/g" mempool-config.json -sed -i "s/__SECOND_CORE_RPC_PASSWORD__/${__SECOND_CORE_RPC_PASSWORD__}/g" mempool-config.json -sed -i "s/__SECOND_CORE_RPC_TIMEOUT__/${__SECOND_CORE_RPC_TIMEOUT__}/g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_HOST__!${__SECOND_CORE_RPC_HOST__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_PORT__!${__SECOND_CORE_RPC_PORT__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_USERNAME__!${__SECOND_CORE_RPC_USERNAME__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_PASSWORD__!${__SECOND_CORE_RPC_PASSWORD__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_TIMEOUT__!${__SECOND_CORE_RPC_TIMEOUT__}!g" mempool-config.json -sed -i "s/__DATABASE_ENABLED__/${__DATABASE_ENABLED__}/g" mempool-config.json -sed -i "s/__DATABASE_HOST__/${__DATABASE_HOST__}/g" mempool-config.json +sed -i "s!__DATABASE_ENABLED__!${__DATABASE_ENABLED__}!g" mempool-config.json +sed -i "s!__DATABASE_HOST__!${__DATABASE_HOST__}!g" mempool-config.json sed -i "s!__DATABASE_SOCKET__!${__DATABASE_SOCKET__}!g" mempool-config.json -sed -i "s/__DATABASE_PORT__/${__DATABASE_PORT__}/g" mempool-config.json -sed -i "s/__DATABASE_DATABASE__/${__DATABASE_DATABASE__}/g" mempool-config.json -sed -i "s/__DATABASE_USERNAME__/${__DATABASE_USERNAME__}/g" mempool-config.json -sed -i "s/__DATABASE_PASSWORD__/${__DATABASE_PASSWORD__}/g" mempool-config.json +sed -i "s!__DATABASE_PORT__!${__DATABASE_PORT__}!g" mempool-config.json +sed -i "s!__DATABASE_DATABASE__!${__DATABASE_DATABASE__}!g" mempool-config.json +sed -i "s!__DATABASE_USERNAME__!${__DATABASE_USERNAME__}!g" mempool-config.json +sed -i "s!__DATABASE_PASSWORD__!${__DATABASE_PASSWORD__}!g" mempool-config.json -sed -i "s/__SYSLOG_ENABLED__/${__SYSLOG_ENABLED__}/g" mempool-config.json -sed -i "s/__SYSLOG_HOST__/${__SYSLOG_HOST__}/g" mempool-config.json -sed -i "s/__SYSLOG_PORT__/${__SYSLOG_PORT__}/g" mempool-config.json -sed -i "s/__SYSLOG_MIN_PRIORITY__/${__SYSLOG_MIN_PRIORITY__}/g" mempool-config.json -sed -i "s/__SYSLOG_FACILITY__/${__SYSLOG_FACILITY__}/g" mempool-config.json +sed -i "s!__SYSLOG_ENABLED__!${__SYSLOG_ENABLED__}!g" mempool-config.json +sed -i "s!__SYSLOG_HOST__!${__SYSLOG_HOST__}!g" mempool-config.json +sed -i "s!__SYSLOG_PORT__!${__SYSLOG_PORT__}!g" mempool-config.json +sed -i "s!__SYSLOG_MIN_PRIORITY__!${__SYSLOG_MIN_PRIORITY__}!g" mempool-config.json +sed -i "s!__SYSLOG_FACILITY__!${__SYSLOG_FACILITY__}!g" mempool-config.json -sed -i "s/__STATISTICS_ENABLED__/${__STATISTICS_ENABLED__}/g" mempool-config.json -sed -i "s/__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__/${__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__}/g" mempool-config.json +sed -i "s!__STATISTICS_ENABLED__!${__STATISTICS_ENABLED__}!g" mempool-config.json +sed -i "s!__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__!${__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__}!g" mempool-config.json -sed -i "s/__BISQ_ENABLED__/${__BISQ_ENABLED__}/g" mempool-config.json +sed -i "s!__BISQ_ENABLED__!${__BISQ_ENABLED__}!g" mempool-config.json sed -i "s!__BISQ_DATA_PATH__!${__BISQ_DATA_PATH__}!g" mempool-config.json -sed -i "s/__SOCKS5PROXY_ENABLED__/${__SOCKS5PROXY_ENABLED__}/g" mempool-config.json -sed -i "s/__SOCKS5PROXY_USE_ONION__/${__SOCKS5PROXY_USE_ONION__}/g" mempool-config.json -sed -i "s/__SOCKS5PROXY_HOST__/${__SOCKS5PROXY_HOST__}/g" mempool-config.json -sed -i "s/__SOCKS5PROXY_PORT__/${__SOCKS5PROXY_PORT__}/g" mempool-config.json -sed -i "s/__SOCKS5PROXY_USERNAME__/${__SOCKS5PROXY_USERNAME__}/g" mempool-config.json -sed -i "s/__SOCKS5PROXY_PASSWORD__/${__SOCKS5PROXY_PASSWORD__}/g" mempool-config.json +sed -i "s!__SOCKS5PROXY_ENABLED__!${__SOCKS5PROXY_ENABLED__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_USE_ONION__!${__SOCKS5PROXY_USE_ONION__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_HOST__!${__SOCKS5PROXY_HOST__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_PORT__!${__SOCKS5PROXY_PORT__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_USERNAME__!${__SOCKS5PROXY_USERNAME__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_PASSWORD__!${__SOCKS5PROXY_PASSWORD__}!g" mempool-config.json sed -i "s!__PRICE_DATA_SERVER_TOR_URL__!${__PRICE_DATA_SERVER_TOR_URL__}!g" mempool-config.json sed -i "s!__PRICE_DATA_SERVER_CLEARNET_URL__!${__PRICE_DATA_SERVER_CLEARNET_URL__}!g" mempool-config.json From b54dbcd5f843f554c6daa8d778b7c51189f2fca1 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 13:14:44 -0700 Subject: [PATCH 06/53] Add a test to check if all the vars are on the Docker script --- backend/src/__tests__/config.test.ts | 48 ++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index aa287308b..4971403af 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -152,4 +152,52 @@ describe('Mempool Backend Config', () => { expect(config.EXTERNAL_DATA_SERVER).toStrictEqual(fixture.EXTERNAL_DATA_SERVER); }); }); + + test('should ensure the docker start.sh script has default values', () => { + jest.isolateModules(() => { + const startSh = fs.readFileSync(`${__dirname}/../../../docker/backend/start.sh`, 'utf-8'); + const fixture = JSON.parse(fs.readFileSync(`${__dirname}/../__fixtures__/mempool-config.template.json`, 'utf8')); + + function parseJson(jsonObj, root?) { + for (const [key, value] of Object.entries(jsonObj)) { + // We have a few cases where we can't follow the pattern + if (root === 'MEMPOOL' && key === 'HTTP_PORT') { + console.log('skipping check for MEMPOOL_HTTP_PORT'); + return; + } + switch (typeof value) { + case 'object': { + if (Array.isArray(value)) { + return; + } else { + parseJson(value, key); + } + break; + } + default: { + //The flattened string, i.e, __MEMPOOL_ENABLED__ + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + + //The string used as the environment variable, i.e, MEMPOOL_ENABLED + const envVarStr = `${root ? root : ''}_${key}`; + + //The string used as the default value, to be checked as a regex, i.e, __MEMPOOL_ENABLED__=${MEMPOOL_ENABLED:=(.*)} + const defaultEntry = replaceStr + '=' + '\\${' + envVarStr + ':=(.*)' + '}'; + + console.log(`looking for ${defaultEntry} in the start.sh script`); + const re = new RegExp(defaultEntry); + expect(startSh).toMatch(re); + + //The string that actually replaces the values in the config file + const sedStr = 'sed -i "s!' + replaceStr + '!${' + replaceStr + '}!g" mempool-config.json'; + console.log(`looking for ${sedStr} in the start.sh script`); + expect(startSh).toContain(sedStr); + break; + } + } + } + } + parseJson(fixture); + }); + }); }); From 730afb8f6864f67dbe28a97e94a7540c143bf8a7 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 13:20:18 -0700 Subject: [PATCH 07/53] Add missing DATABASE_TIMEOUT config --- docker/backend/start.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 54f0825d5..f1ddba3fd 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -181,11 +181,11 @@ sed -i "s!__SECOND_CORE_RPC_TIMEOUT__!${__SECOND_CORE_RPC_TIMEOUT__}!g" mempool- sed -i "s!__DATABASE_ENABLED__!${__DATABASE_ENABLED__}!g" mempool-config.json sed -i "s!__DATABASE_HOST__!${__DATABASE_HOST__}!g" mempool-config.json sed -i "s!__DATABASE_SOCKET__!${__DATABASE_SOCKET__}!g" mempool-config.json - sed -i "s!__DATABASE_PORT__!${__DATABASE_PORT__}!g" mempool-config.json sed -i "s!__DATABASE_DATABASE__!${__DATABASE_DATABASE__}!g" mempool-config.json sed -i "s!__DATABASE_USERNAME__!${__DATABASE_USERNAME__}!g" mempool-config.json sed -i "s!__DATABASE_PASSWORD__!${__DATABASE_PASSWORD__}!g" mempool-config.json +sed -i "s!__DATABASE_TIMEOUT__!${__DATABASE_TIMEOUT__}!g" mempool-config.json sed -i "s!__SYSLOG_ENABLED__!${__SYSLOG_ENABLED__}!g" mempool-config.json sed -i "s!__SYSLOG_HOST__!${__SYSLOG_HOST__}!g" mempool-config.json From e2f1ae9cf67b398424206004554d4a119276bf7d Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 13:26:35 -0700 Subject: [PATCH 08/53] Add missing Lightning config --- docker/backend/start.sh | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docker/backend/start.sh b/docker/backend/start.sh index f1ddba3fd..cb1108a05 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -108,6 +108,8 @@ __LIGHTNING_TOPOLOGY_FOLDER__=${LIGHTNING_TOPOLOGY_FOLDER:=""} __LIGHTNING_STATS_REFRESH_INTERVAL__=${LIGHTNING_STATS_REFRESH_INTERVAL:=600} __LIGHTNING_GRAPH_REFRESH_INTERVAL__=${LIGHTNING_GRAPH_REFRESH_INTERVAL:=600} __LIGHTNING_LOGGER_UPDATE_INTERVAL__=${LIGHTNING_LOGGER_UPDATE_INTERVAL:=30} +__LIGHTNING_FORENSICS_INTERVAL__=${LIGHTNING_FORENSICS_INTERVAL:=43200} +__LIGHTNING_FORENSICS_RATE_LIMIT__=${LIGHTNING_FORENSICS_RATE_LIMIT:=20} # LND __LND_TLS_CERT_PATH__=${LND_TLS_CERT_PATH:=""} @@ -223,6 +225,8 @@ sed -i "s!__LIGHTNING_TOPOLOGY_FOLDER__!${__LIGHTNING_TOPOLOGY_FOLDER__}!g" memp sed -i "s!__LIGHTNING_STATS_REFRESH_INTERVAL__!${__LIGHTNING_STATS_REFRESH_INTERVAL__}!g" mempool-config.json sed -i "s!__LIGHTNING_GRAPH_REFRESH_INTERVAL__!${__LIGHTNING_GRAPH_REFRESH_INTERVAL__}!g" mempool-config.json sed -i "s!__LIGHTNING_LOGGER_UPDATE_INTERVAL__!${__LIGHTNING_LOGGER_UPDATE_INTERVAL__}!g" mempool-config.json +sed -i "s!__LIGHTNING_FORENSICS_INTERVAL__!${__LIGHTNING_FORENSICS_INTERVAL__}!g" mempool-config.json +sed -i "s!__LIGHTNING_FORENSICS_RATE_LIMIT__!${__LIGHTNING_FORENSICS_RATE_LIMIT__}!g" mempool-config.json # LND sed -i "s!__LND_TLS_CERT_PATH__!${__LND_TLS_CERT_PATH__}!g" mempool-config.json From 270bf760361c5c2b182733f5fb78c30818d8c4e1 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 14:17:53 -0700 Subject: [PATCH 09/53] Add a test to check that the docker json is in sync with the template --- backend/src/__tests__/config.test.ts | 42 ++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 4971403af..278d83f50 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -200,4 +200,46 @@ describe('Mempool Backend Config', () => { parseJson(fixture); }); }); + + test('should ensure that the mempool-config.json Docker template has all the keys', () => { + jest.isolateModules(() => { + const fixture = JSON.parse(fs.readFileSync(`${__dirname}/../__fixtures__/mempool-config.template.json`, 'utf8')); + const dockerJson = fs.readFileSync(`${__dirname}/../../../docker/backend/mempool-config.json`, 'utf-8'); + + function parseJson(jsonObj, root?) { + for (const [key, value] of Object.entries(jsonObj)) { + switch (typeof value) { + case 'object': { + if (Array.isArray(value)) { + // numbers, arrays and booleans won't be enclosed by quotes + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + expect(dockerJson).toContain(`"${key}": ${replaceStr}`); + break; + } else { + //Check for top level config keys + expect(dockerJson).toContain(`"${key}"`); + parseJson(value, key); + break; + } + } + case 'string': { + // strings should be enclosed by quotes + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + expect(dockerJson).toContain(`"${key}": "${replaceStr}"`); + break; + } + default: { + // numbers, arrays and booleans won't be enclosed by quotes + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + expect(dockerJson).toContain(`"${key}": ${replaceStr}`); + break; + } + } + }; + } + parseJson(fixture); + }); + }); + + }); From 0253904b5a0dc00b9b88c392b262804eb6c3851e Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 14:25:23 -0700 Subject: [PATCH 10/53] Update the backend config fixture --- .../__fixtures__/mempool-config.template.json | 28 +++++++++---------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index eb082d89f..919784464 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -16,7 +16,7 @@ "INITIAL_BLOCKS_AMOUNT": 7, "MEMPOOL_BLOCKS_AMOUNT": 8, "USE_SECOND_NODE_FOR_MINFEE": 10, - "EXTERNAL_ASSETS": 11, + "EXTERNAL_ASSETS": [], "EXTERNAL_MAX_RETRY": 12, "EXTERNAL_RETRY_INTERVAL": 13, "USER_AGENT": "__MEMPOOL_USER_AGENT__", @@ -24,19 +24,19 @@ "INDEXING_BLOCKS_AMOUNT": 14, "POOLS_JSON_TREE_URL": "__POOLS_JSON_TREE_URL__", "POOLS_JSON_URL": "__POOLS_JSON_URL__", - "AUDIT": "__MEMPOOL_AUDIT__", - "ADVANCED_GBT_AUDIT": "__MEMPOOL_ADVANCED_GBT_AUDIT__", - "ADVANCED_GBT_MEMPOOL": "__MEMPOOL_ADVANCED_GBT_MEMPOOL__", - "CPFP_INDEXING": "__MEMPOOL_CPFP_INDEXING__", - "MAX_BLOCKS_BULK_QUERY": "__MEMPOOL_MAX_BLOCKS_BULK_QUERY__", - "DISK_CACHE_BLOCK_INTERVAL": "__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__" + "AUDIT": true, + "ADVANCED_GBT_AUDIT": true, + "ADVANCED_GBT_MEMPOOL": true, + "CPFP_INDEXING": true, + "MAX_BLOCKS_BULK_QUERY": 999, + "DISK_CACHE_BLOCK_INTERVAL": 999 }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", "PORT": 15, "USERNAME": "__CORE_RPC_USERNAME__", "PASSWORD": "__CORE_RPC_PASSWORD__", - "TIMEOUT": "__CORE_RPC_TIMEOUT__" + "TIMEOUT": 1000 }, "ELECTRUM": { "HOST": "__ELECTRUM_HOST__", @@ -46,14 +46,14 @@ "ESPLORA": { "REST_API_URL": "__ESPLORA_REST_API_URL__", "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", - "RETRY_UNIX_SOCKET_AFTER": "__ESPLORA_RETRY_UNIX_SOCKET_AFTER__" + "RETRY_UNIX_SOCKET_AFTER": 888 }, "SECOND_CORE_RPC": { "HOST": "__SECOND_CORE_RPC_HOST__", "PORT": 17, "USERNAME": "__SECOND_CORE_RPC_USERNAME__", "PASSWORD": "__SECOND_CORE_RPC_PASSWORD__", - "TIMEOUT": "__SECOND_CORE_RPC_TIMEOUT__" + "TIMEOUT": 2000 }, "DATABASE": { "ENABLED": false, @@ -63,7 +63,7 @@ "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", "PASSWORD": "__DATABASE_PASSWORD__", - "TIMEOUT": "__DATABASE_TIMEOUT__" + "TIMEOUT": 3000 }, "SYSLOG": { "ENABLED": false, @@ -101,14 +101,14 @@ "BISQ_ONION": "__EXTERNAL_DATA_SERVER_BISQ_ONION__" }, "LIGHTNING": { - "ENABLED": "__LIGHTNING_ENABLED__", + "ENABLED": true, "BACKEND": "__LIGHTNING_BACKEND__", "TOPOLOGY_FOLDER": "__LIGHTNING_TOPOLOGY_FOLDER__", "STATS_REFRESH_INTERVAL": 600, "GRAPH_REFRESH_INTERVAL": 600, "LOGGER_UPDATE_INTERVAL": 30, "FORENSICS_INTERVAL": 43200, - "FORENSICS_RATE_LIMIT": "__FORENSICS_RATE_LIMIT__" + "FORENSICS_RATE_LIMIT": 1234 }, "LND": { "TLS_CERT_PATH": "", @@ -119,4 +119,4 @@ "CLIGHTNING": { "SOCKET": "__CLIGHTNING_SOCKET__" } -} +} \ No newline at end of file From a79d715ad416634a60248134c21e7501cd9ffea8 Mon Sep 17 00:00:00 2001 From: Felipe Knorr Kuhn <100320+knorrium@users.noreply.github.com> Date: Sun, 14 May 2023 14:26:38 -0700 Subject: [PATCH 11/53] Fix Docker config file to use the correct types --- docker/backend/mempool-config.json | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index fd8abaf02..06ed51f41 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -27,7 +27,9 @@ "ADVANCED_GBT_MEMPOOL": __MEMPOOL_ADVANCED_GBT_MEMPOOL__, "CPFP_INDEXING": __MEMPOOL_CPFP_INDEXING__, "MAX_BLOCKS_BULK_QUERY": __MEMPOOL_MAX_BLOCKS_BULK_QUERY__, - "DISK_CACHE_BLOCK_INTERVAL": __MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__ + "DISK_CACHE_BLOCK_INTERVAL": __MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__, + "POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__", + "POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__" }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", @@ -61,7 +63,7 @@ "DATABASE": "__DATABASE_DATABASE__", "USERNAME": "__DATABASE_USERNAME__", "PASSWORD": "__DATABASE_PASSWORD__", - "TIMEOUT": "__DATABASE_TIMEOUT__" + "TIMEOUT": __DATABASE_TIMEOUT__ }, "SYSLOG": { "ENABLED": __SYSLOG_ENABLED__, @@ -84,13 +86,15 @@ "STATS_REFRESH_INTERVAL": __LIGHTNING_STATS_REFRESH_INTERVAL__, "GRAPH_REFRESH_INTERVAL": __LIGHTNING_GRAPH_REFRESH_INTERVAL__, "LOGGER_UPDATE_INTERVAL": __LIGHTNING_LOGGER_UPDATE_INTERVAL__, - "TOPOLOGY_FOLDER": "__LIGHTNING_TOPOLOGY_FOLDER__" + "TOPOLOGY_FOLDER": "__LIGHTNING_TOPOLOGY_FOLDER__", + "FORENSICS_INTERVAL": __LIGHTNING_FORENSICS_INTERVAL__, + "FORENSICS_RATE_LIMIT": __LIGHTNING_FORENSICS_RATE_LIMIT__ }, "LND": { "TLS_CERT_PATH": "__LND_TLS_CERT_PATH__", "MACAROON_PATH": "__LND_MACAROON_PATH__", "REST_API_URL": "__LND_REST_API_URL__", - "TIMEOUT": "__LND_TIMEOUT__" + "TIMEOUT": __LND_TIMEOUT__ }, "CLIGHTNING": { "SOCKET": "__CLIGHTNING_SOCKET__" @@ -121,4 +125,4 @@ "GEOLITE2_ASN": "__MAXMIND_GEOLITE2_ASN__", "GEOIP2_ISP": "__MAXMIND_GEOIP2_ISP__" } -} +} \ No newline at end of file From 3a1fd2a4637a710439dfc9c934e747259679ecd5 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 16 Mar 2023 17:03:32 +0900 Subject: [PATCH 12/53] Block prediction -> Block health - Fix wrong chart download name --- backend/src/api/mining/mining-routes.ts | 10 +++---- backend/src/api/mining/mining.ts | 7 ++--- .../repositories/BlocksAuditsRepository.ts | 8 +++--- .../block-health-graph.component.html} | 22 +++++++-------- .../block-health-graph.component.scss} | 0 .../block-health-graph.component.ts} | 28 +++++++++---------- .../components/graphs/graphs.component.html | 2 +- frontend/src/app/graphs/graphs.module.ts | 4 +-- .../src/app/graphs/graphs.routing.module.ts | 6 ++-- .../node-fee-chart.component.ts | 16 ----------- .../node-statistics-chart.component.ts | 17 ----------- .../nodes-networks-chart.component.ts | 2 +- frontend/src/app/services/api.service.ts | 2 +- 13 files changed, 45 insertions(+), 79 deletions(-) rename frontend/src/app/components/{block-prediction-graph/block-prediction-graph.component.html => block-health-graph/block-health-graph.component.html} (75%) rename frontend/src/app/components/{block-prediction-graph/block-prediction-graph.component.scss => block-health-graph/block-health-graph.component.scss} (100%) rename frontend/src/app/components/{block-prediction-graph/block-prediction-graph.component.ts => block-health-graph/block-health-graph.component.ts} (92%) diff --git a/backend/src/api/mining/mining-routes.ts b/backend/src/api/mining/mining-routes.ts index 0198f9ab4..1c9a0de30 100644 --- a/backend/src/api/mining/mining-routes.ts +++ b/backend/src/api/mining/mining-routes.ts @@ -26,7 +26,7 @@ class MiningRoutes { .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fee-rates/:interval', this.$getHistoricalBlockFeeRates) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/sizes-weights/:interval', this.$getHistoricalBlockSizeAndWeight) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments/:interval', this.$getDifficultyAdjustments) - .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/predictions/:interval', this.$getHistoricalBlockPrediction) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/predictions/:interval', this.$getHistoricalBlocksHealth) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/scores', this.$getBlockAuditScores) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/scores/:height', this.$getBlockAuditScores) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/score/:hash', this.$getBlockAuditScore) @@ -244,15 +244,15 @@ class MiningRoutes { } } - private async $getHistoricalBlockPrediction(req: Request, res: Response) { + private async $getHistoricalBlocksHealth(req: Request, res: Response) { try { - const blockPredictions = await mining.$getBlockPredictionsHistory(req.params.interval); - const blockCount = await BlocksAuditsRepository.$getPredictionsCount(); + const blocksHealth = await mining.$getBlocksHealthHistory(req.params.interval); + const blockCount = await BlocksAuditsRepository.$getBlocksHealthCount(); res.header('Pragma', 'public'); res.header('Cache-control', 'public'); res.header('X-total-count', blockCount.toString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); - res.json(blockPredictions.map(prediction => [prediction.time, prediction.height, prediction.match_rate])); + res.json(blocksHealth.map(health => [health.time, health.height, health.match_rate])); } catch (e) { res.status(500).send(e instanceof Error ? e.message : e); } diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts index 27ac426bd..20da92de3 100644 --- a/backend/src/api/mining/mining.ts +++ b/backend/src/api/mining/mining.ts @@ -13,7 +13,6 @@ import BlocksAuditsRepository from '../../repositories/BlocksAuditsRepository'; import PricesRepository from '../../repositories/PricesRepository'; import { bitcoinCoreApi } from '../bitcoin/bitcoin-api-factory'; import { IEsploraApi } from '../bitcoin/esplora-api.interface'; -import database from '../../database'; class Mining { private blocksPriceIndexingRunning = false; @@ -21,10 +20,10 @@ class Mining { public lastWeeklyHashrateIndexingDate: number | null = null; /** - * Get historical block predictions match rate + * Get historical blocks health */ - public async $getBlockPredictionsHistory(interval: string | null = null): Promise { - return await BlocksAuditsRepository.$getBlockPredictionsHistory( + public async $getBlocksHealthHistory(interval: string | null = null): Promise { + return await BlocksAuditsRepository.$getBlocksHealthHistory( this.getTimeRange(interval), Common.getSqlInterval(interval) ); diff --git a/backend/src/repositories/BlocksAuditsRepository.ts b/backend/src/repositories/BlocksAuditsRepository.ts index c6156334b..70565a1c8 100644 --- a/backend/src/repositories/BlocksAuditsRepository.ts +++ b/backend/src/repositories/BlocksAuditsRepository.ts @@ -19,7 +19,7 @@ class BlocksAuditRepositories { } } - public async $getBlockPredictionsHistory(div: number, interval: string | null): Promise { + public async $getBlocksHealthHistory(div: number, interval: string | null): Promise { try { let query = `SELECT UNIX_TIMESTAMP(time) as time, height, match_rate FROM blocks_audits`; @@ -32,17 +32,17 @@ class BlocksAuditRepositories { const [rows] = await DB.query(query); return rows; } catch (e: any) { - logger.err(`Cannot fetch block prediction history. Reason: ` + (e instanceof Error ? e.message : e)); + logger.err(`Cannot fetch blocks health history. Reason: ` + (e instanceof Error ? e.message : e)); throw e; } } - public async $getPredictionsCount(): Promise { + public async $getBlocksHealthCount(): Promise { try { const [rows] = await DB.query(`SELECT count(hash) as count FROM blocks_audits`); return rows[0].count; } catch (e: any) { - logger.err(`Cannot fetch block prediction history. Reason: ` + (e instanceof Error ? e.message : e)); + logger.err(`Cannot fetch blocks health count. Reason: ` + (e instanceof Error ? e.message : e)); throw e; } } diff --git a/frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.html b/frontend/src/app/components/block-health-graph/block-health-graph.component.html similarity index 75% rename from frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.html rename to frontend/src/app/components/block-health-graph/block-health-graph.component.html index 7dcd81c69..4cd10f2dd 100644 --- a/frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.html +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.html @@ -3,7 +3,7 @@
- Block Prediction Accuracy + Block Health @@ -12,34 +12,34 @@
diff --git a/frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.scss b/frontend/src/app/components/block-health-graph/block-health-graph.component.scss similarity index 100% rename from frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.scss rename to frontend/src/app/components/block-health-graph/block-health-graph.component.scss diff --git a/frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.ts b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts similarity index 92% rename from frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.ts rename to frontend/src/app/components/block-health-graph/block-health-graph.component.ts index e04565751..46aebdd6e 100644 --- a/frontend/src/app/components/block-prediction-graph/block-prediction-graph.component.ts +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts @@ -13,9 +13,9 @@ import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pi import { StateService } from '../../services/state.service'; @Component({ - selector: 'app-block-prediction-graph', - templateUrl: './block-prediction-graph.component.html', - styleUrls: ['./block-prediction-graph.component.scss'], + selector: 'app-block-health-graph', + templateUrl: './block-health-graph.component.html', + styleUrls: ['./block-health-graph.component.scss'], styles: [` .loadingGraphs { position: absolute; @@ -26,7 +26,7 @@ import { StateService } from '../../services/state.service'; `], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class BlockPredictionGraphComponent implements OnInit { +export class BlockHealthGraphComponent implements OnInit { @Input() right: number | string = 45; @Input() left: number | string = 75; @@ -60,7 +60,7 @@ export class BlockPredictionGraphComponent implements OnInit { } ngOnInit(): void { - this.seoService.setTitle($localize`:@@d7d5fcf50179ad70c938491c517efb82de2c8146:Block Prediction Accuracy`); + this.seoService.setTitle($localize`:@@d7d5fcf50179ad70c938491c517efb82de2c8146:Block Health`); this.miningWindowPreference = '24h';//this.miningService.getDefaultTimespan('24h'); this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); @@ -80,7 +80,7 @@ export class BlockPredictionGraphComponent implements OnInit { this.storageService.setValue('miningWindowPreference', timespan); this.timespan = timespan; this.isLoading = true; - return this.apiService.getHistoricalBlockPrediction$(timespan) + return this.apiService.getHistoricalBlocksHealth$(timespan) .pipe( tap((response) => { this.prepareChartOptions(response.body); @@ -163,7 +163,7 @@ export class BlockPredictionGraphComponent implements OnInit { hideOverlap: true, padding: [0, 5], }, - data: data.map(prediction => prediction[0]) + data: data.map(health => health[0]) }, yAxis: data.length === 0 ? undefined : [ { @@ -186,12 +186,12 @@ export class BlockPredictionGraphComponent implements OnInit { series: data.length === 0 ? undefined : [ { zlevel: 0, - name: $localize`Match rate`, - data: data.map(prediction => ({ - value: prediction[2], - block: prediction[1], + name: $localize`Health`, + data: data.map(health => ({ + value: health[2], + block: health[1], itemStyle: { - color: this.getPredictionColor(prediction[2]) + color: this.getHealthColor(health[2]) } })), type: 'bar', @@ -257,7 +257,7 @@ export class BlockPredictionGraphComponent implements OnInit { return 'rgb(' + gradient.red + ',' + gradient.green + ',' + gradient.blue + ')'; } - getPredictionColor(matchRate) { + getHealthColor(matchRate) { return this.colorGradient( Math.pow((100 - matchRate) / 100, 0.5), {red: 67, green: 171, blue: 71}, @@ -294,7 +294,7 @@ export class BlockPredictionGraphComponent implements OnInit { download(this.chartInstance.getDataURL({ pixelRatio: 2, excludeComponents: ['dataZoom'], - }), `block-fees-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + }), `block-health-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); // @ts-ignore this.chartOptions.grid.bottom = prevBottom; this.chartOptions.backgroundColor = 'none'; diff --git a/frontend/src/app/components/graphs/graphs.component.html b/frontend/src/app/components/graphs/graphs.component.html index 105c6cbf2..c3053427e 100644 --- a/frontend/src/app/components/graphs/graphs.component.html +++ b/frontend/src/app/components/graphs/graphs.component.html @@ -22,7 +22,7 @@ Block Sizes and Weights Block Prediction Accuracy + [routerLink]="['/graphs/mining/block-health' | relativeUrl]" i18n="mining.blocks-health">Blocks Health
diff --git a/frontend/src/app/graphs/graphs.module.ts b/frontend/src/app/graphs/graphs.module.ts index a4e4f5bfc..87e8a620b 100644 --- a/frontend/src/app/graphs/graphs.module.ts +++ b/frontend/src/app/graphs/graphs.module.ts @@ -21,7 +21,7 @@ import { DashboardComponent } from '../dashboard/dashboard.component'; import { MiningDashboardComponent } from '../components/mining-dashboard/mining-dashboard.component'; import { HashrateChartComponent } from '../components/hashrate-chart/hashrate-chart.component'; import { HashrateChartPoolsComponent } from '../components/hashrates-chart-pools/hashrate-chart-pools.component'; -import { BlockPredictionGraphComponent } from '../components/block-prediction-graph/block-prediction-graph.component'; +import { BlockHealthGraphComponent } from '../components/block-health-graph/block-health-graph.component'; import { CommonModule } from '@angular/common'; @NgModule({ @@ -46,7 +46,7 @@ import { CommonModule } from '@angular/common'; LbtcPegsGraphComponent, HashrateChartComponent, HashrateChartPoolsComponent, - BlockPredictionGraphComponent, + BlockHealthGraphComponent, ], imports: [ CommonModule, diff --git a/frontend/src/app/graphs/graphs.routing.module.ts b/frontend/src/app/graphs/graphs.routing.module.ts index a31f3a30a..03800dcfc 100644 --- a/frontend/src/app/graphs/graphs.routing.module.ts +++ b/frontend/src/app/graphs/graphs.routing.module.ts @@ -1,6 +1,6 @@ import { NgModule } from '@angular/core'; import { RouterModule, Routes } from '@angular/router'; -import { BlockPredictionGraphComponent } from '../components/block-prediction-graph/block-prediction-graph.component'; +import { BlockHealthGraphComponent } from '../components/block-health-graph/block-health-graph.component'; import { BlockFeeRatesGraphComponent } from '../components/block-fee-rates-graph/block-fee-rates-graph.component'; import { BlockFeesGraphComponent } from '../components/block-fees-graph/block-fees-graph.component'; import { BlockRewardsGraphComponent } from '../components/block-rewards-graph/block-rewards-graph.component'; @@ -143,9 +143,9 @@ const routes: Routes = [ redirectTo: 'mempool', }, { - path: 'mining/block-prediction', + path: 'mining/block-health', data: { networks: ['bitcoin'] }, - component: BlockPredictionGraphComponent, + component: BlockHealthGraphComponent, }, ] }, diff --git a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts index 97268226d..f20142e47 100644 --- a/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts +++ b/frontend/src/app/lightning/node-fee-chart/node-fee-chart.component.ts @@ -253,20 +253,4 @@ export class NodeFeeChartComponent implements OnInit { isMobile() { return (window.innerWidth <= 767.98); } - - onSaveChart() { - // @ts-ignore - const prevBottom = this.chartOptions.grid.bottom; - // @ts-ignore - this.chartOptions.grid.bottom = 40; - this.chartOptions.backgroundColor = '#11131f'; - this.chartInstance.setOption(this.chartOptions); - download(this.chartInstance.getDataURL({ - pixelRatio: 2, - }), `node-fee-chart.svg`); - // @ts-ignore - this.chartOptions.grid.bottom = prevBottom; - this.chartOptions.backgroundColor = 'none'; - this.chartInstance.setOption(this.chartOptions); - } } diff --git a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts index 21e3fc2c5..9b10152b5 100644 --- a/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts +++ b/frontend/src/app/lightning/node-statistics-chart/node-statistics-chart.component.ts @@ -252,21 +252,4 @@ export class NodeStatisticsChartComponent implements OnInit { isMobile() { return (window.innerWidth <= 767.98); } - - onSaveChart() { - // @ts-ignore - const prevBottom = this.chartOptions.grid.bottom; - const now = new Date(); - // @ts-ignore - this.chartOptions.grid.bottom = 40; - this.chartOptions.backgroundColor = '#11131f'; - this.chartInstance.setOption(this.chartOptions); - download(this.chartInstance.getDataURL({ - pixelRatio: 2, - }), `block-sizes-weights-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); - // @ts-ignore - this.chartOptions.grid.bottom = prevBottom; - this.chartOptions.backgroundColor = 'none'; - this.chartInstance.setOption(this.chartOptions); - } } diff --git a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts index 603f6d714..db04e9e00 100644 --- a/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts +++ b/frontend/src/app/lightning/nodes-networks-chart/nodes-networks-chart.component.ts @@ -442,7 +442,7 @@ export class NodesNetworksChartComponent implements OnInit { download(this.chartInstance.getDataURL({ pixelRatio: 2, excludeComponents: ['dataZoom'], - }), `block-sizes-weights-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + }), `lightning-nodes-per-network-${Math.round(now.getTime() / 1000)}.svg`); // @ts-ignore this.chartOptions.grid.bottom = prevBottom; this.chartOptions.backgroundColor = 'none'; diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 64bf080f9..8521ddc83 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -238,7 +238,7 @@ export class ApiService { ); } - getHistoricalBlockPrediction$(interval: string | undefined) : Observable { + getHistoricalBlocksHealth$(interval: string | undefined) : Observable { return this.httpClient.get( this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/predictions` + (interval !== undefined ? `/${interval}` : ''), { observe: 'response' } From b8f3f15256e2ee98e6e19829a66716fdb49246e7 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 1 Apr 2023 19:26:34 +0900 Subject: [PATCH 13/53] Blocks Health -> Block Health --- frontend/src/app/components/graphs/graphs.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/graphs/graphs.component.html b/frontend/src/app/components/graphs/graphs.component.html index c3053427e..8468deb82 100644 --- a/frontend/src/app/components/graphs/graphs.component.html +++ b/frontend/src/app/components/graphs/graphs.component.html @@ -22,7 +22,7 @@ Block Sizes and Weights Blocks Health + [routerLink]="['/graphs/mining/block-health' | relativeUrl]" i18n="mining.block-health">Block Health
From 6267562bda91bacb4195219419722b3e30ff19c5 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 16 May 2023 16:25:38 -0600 Subject: [PATCH 14/53] Fix mempool graph fee filtering --- .../mempool-graph/mempool-graph.component.ts | 24 +++++++++---- .../statistics/statistics.component.html | 5 +-- .../statistics/statistics.component.ts | 35 ++++++++++++++++--- .../app/dashboard/dashboard.component.html | 1 - 4 files changed, 51 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts index 416b8f538..4ab8c33fc 100644 --- a/frontend/src/app/components/mempool-graph/mempool-graph.component.ts +++ b/frontend/src/app/components/mempool-graph/mempool-graph.component.ts @@ -24,6 +24,7 @@ import { download, formatterXAxis, formatterXAxisLabel } from '../../shared/grap export class MempoolGraphComponent implements OnInit, OnChanges { @Input() data: any[]; @Input() filterSize = 100000; + @Input() limitFilterFee = 1; @Input() height: number | string = 200; @Input() top: number | string = 20; @Input() right: number | string = 10; @@ -40,7 +41,9 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }; windowPreference: string; hoverIndexSerie = 0; + maxFee: number; feeLimitIndex: number; + maxFeeIndex: number; feeLevelsOrdered = []; chartColorsOrdered = chartColors; inverted: boolean; @@ -98,8 +101,9 @@ export class MempoolGraphComponent implements OnInit, OnChanges { } generateArray(mempoolStats: OptimizedMempoolStats[]) { - let finalArray: number[][][] = []; + const finalArray: number[][][] = []; let feesArray: number[][] = []; + let maxTier = 0; for (let index = 37; index > -1; index--) { feesArray = []; @@ -111,7 +115,8 @@ export class MempoolGraphComponent implements OnInit, OnChanges { }); finalArray.push(feesArray); } - this.feeLimitIndex = maxTier; + this.maxFeeIndex = maxTier; + finalArray.reverse(); return finalArray; } @@ -124,7 +129,7 @@ export class MempoolGraphComponent implements OnInit, OnChanges { const newColors = []; for (let index = 0; index < series.length; index++) { const value = series[index]; - if (index < this.feeLimitIndex) { + if (index >= this.feeLimitIndex && index <= this.maxFeeIndex) { newColors.push(this.chartColorsOrdered[index]); seriesGraph.push({ zlevel: 0, @@ -383,21 +388,26 @@ export class MempoolGraphComponent implements OnInit, OnChanges { orderLevels() { this.feeLevelsOrdered = []; - let maxIndex = Math.min(feeLevels.length, this.feeLimitIndex); - for (let i = 0; i < maxIndex; i++) { + const maxIndex = Math.min(feeLevels.length, this.maxFeeIndex); + for (let i = 0; i < feeLevels.length; i++) { + if (feeLevels[i] === this.limitFilterFee) { + this.feeLimitIndex = i; + } + if (feeLevels[i] <= feeLevels[this.maxFeeIndex]) { if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { - if (i === maxIndex - 1) { + if (i === maxIndex || feeLevels[i] == null) { this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)}+`); } else { this.feeLevelsOrdered.push(`${(feeLevels[i] / 10).toFixed(1)} - ${(feeLevels[i + 1] / 10).toFixed(1)}`); } } else { - if (i === maxIndex - 1) { + if (i === maxIndex || feeLevels[i] == null) { this.feeLevelsOrdered.push(`${feeLevels[i]}+`); } else { this.feeLevelsOrdered.push(`${feeLevels[i]} - ${feeLevels[i + 1]}`); } } + } } this.chartColorsOrdered = chartColors.slice(0, this.feeLevelsOrdered.length); } diff --git a/frontend/src/app/components/statistics/statistics.component.html b/frontend/src/app/components/statistics/statistics.component.html index 2133b2615..172f0e7ea 100644 --- a/frontend/src/app/components/statistics/statistics.component.html +++ b/frontend/src/app/components/statistics/statistics.component.html @@ -62,7 +62,7 @@
-
diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts index 263906a8e..5e638af31 100644 --- a/frontend/src/app/components/statistics/statistics.component.ts +++ b/frontend/src/app/components/statistics/statistics.component.ts @@ -30,7 +30,9 @@ export class StatisticsComponent implements OnInit { spinnerLoading = false; feeLevels = feeLevels; chartColors = chartColors; + filterSize = 100000; filterFeeIndex = 1; + maxFeeIndex: number; dropDownOpen = false; mempoolStats: OptimizedMempoolStats[] = []; @@ -134,6 +136,16 @@ export class StatisticsComponent implements OnInit { mempoolStats.reverse(); const labels = mempoolStats.map(stats => stats.added); + let maxTier = 0; + for (let index = 37; index > -1; index--) { + mempoolStats.forEach((stats) => { + if (stats.vsizes[index] >= this.filterSize) { + maxTier = Math.max(maxTier, index); + } + }); + } + this.maxFeeIndex = maxTier; + this.capExtremeVbytesValues(); this.mempoolTransactionsWeightPerSecondData = { @@ -152,27 +164,42 @@ export class StatisticsComponent implements OnInit { } setFeeLevelDropdownData() { - let _feeLevels = feeLevels + let _feeLevels = feeLevels; let _chartColors = chartColors; if (!this.inverted) { _feeLevels = [...feeLevels].reverse(); _chartColors = [...chartColors].reverse(); } _feeLevels.forEach((fee, i) => { + let range; + const nextIndex = this.inverted ? i + 1 : i - 1; + if (this.stateService.isLiquid()) { + if (_feeLevels[nextIndex] == null) { + range = `${(_feeLevels[i] / 10).toFixed(1)}+`; + } else { + range = `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[nextIndex] / 10).toFixed(1)}`; + } + } else { + if (_feeLevels[nextIndex] == null) { + range = `${_feeLevels[i]}+`; + } else { + range = `${_feeLevels[i]} - ${_feeLevels[nextIndex]}`; + } + } if (this.inverted) { this.feeLevelDropdownData.push({ fee: fee, - range: this.stateService.isLiquid() ? `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[i + 1] / 10).toFixed(1)}` : `${_feeLevels[i]} - ${_feeLevels[i + 1]}`, + range, color: _chartColors[i], }); } else { this.feeLevelDropdownData.push({ fee: fee, - range: this.stateService.isLiquid() ? `${(_feeLevels[i] / 10).toFixed(1)} - ${(_feeLevels[i - 1] / 10).toFixed(1)}` : `${_feeLevels[i]} - ${_feeLevels[i - 1]}`, + range, color: _chartColors[i - 1], }); } - }) + }); } /** diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index 72da5e3be..e5504c84a 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -26,7 +26,6 @@
From bdb44c4609fce7b95550505ce6664342043c9ad5 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Wed, 17 May 2023 11:46:50 -0400 Subject: [PATCH 15/53] Omit possible high-sigop txs from block health score --- backend/src/api/audit.ts | 16 ++++++++++++++-- backend/src/api/database-migration.ts | 7 ++++++- backend/src/api/websocket-handler.ts | 3 ++- backend/src/mempool.interfaces.ts | 1 + .../src/repositories/BlocksAuditsRepository.ts | 9 +++++---- .../components/block-overview-graph/tx-view.ts | 3 ++- .../block-overview-tooltip.component.html | 1 + .../src/app/components/block/block.component.ts | 6 +++++- .../src/app/interfaces/node-api.interface.ts | 2 +- .../src/app/interfaces/websocket.interface.ts | 2 +- 10 files changed, 38 insertions(+), 12 deletions(-) diff --git a/backend/src/api/audit.ts b/backend/src/api/audit.ts index 7435e3b99..1ec1ae65a 100644 --- a/backend/src/api/audit.ts +++ b/backend/src/api/audit.ts @@ -6,14 +6,15 @@ const PROPAGATION_MARGIN = 180; // in seconds, time since a transaction is first class Audit { auditBlock(transactions: TransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: TransactionExtended }) - : { censored: string[], added: string[], fresh: string[], score: number, similarity: number } { + : { censored: string[], added: string[], fresh: string[], sigop: string[], score: number, similarity: number } { if (!projectedBlocks?.[0]?.transactionIds || !mempool) { - return { censored: [], added: [], fresh: [], score: 0, similarity: 1 }; + return { censored: [], added: [], fresh: [], sigop: [], score: 0, similarity: 1 }; } const matches: string[] = []; // present in both mined block and template const added: string[] = []; // present in mined block, not in template const fresh: string[] = []; // missing, but firstSeen within PROPAGATION_MARGIN + const sigop: string[] = []; // missing, but possibly has an adjusted vsize due to high sigop count const isCensored = {}; // missing, without excuse const isDisplaced = {}; let displacedWeight = 0; @@ -37,6 +38,8 @@ class Audit { // tx is recent, may have reached the miner too late for inclusion if (mempool[txid]?.firstSeen != null && (now - (mempool[txid]?.firstSeen || 0)) <= PROPAGATION_MARGIN) { fresh.push(txid); + } else if (this.isPossibleHighSigop(mempool[txid])) { + sigop.push(txid); } else { isCensored[txid] = true; } @@ -137,10 +140,19 @@ class Audit { censored: Object.keys(isCensored), added, fresh, + sigop, score, similarity, }; } + + // Detect transactions with a possibly adjusted vsize due to high sigop count + // very rough heuristic based on number of OP_CHECKMULTISIG outputs + // will miss cases with other sources of sigops + isPossibleHighSigop(tx: TransactionExtended): boolean { + const numBareMultisig = tx.vout.reduce((count, vout) => count + (vout.scriptpubkey_asm.includes('OP_CHECKMULTISIG') ? 1 : 0), 0); + return (numBareMultisig * 400) > tx.vsize; + } } export default new Audit(); \ No newline at end of file diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 11039815f..21c87f9e2 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -7,7 +7,7 @@ import cpfpRepository from '../repositories/CpfpRepository'; import { RowDataPacket } from 'mysql2'; class DatabaseMigration { - private static currentVersion = 59; + private static currentVersion = 60; private queryTimeout = 3600_000; private statisticsAddedIndexed = false; private uniqueLogs: string[] = []; @@ -516,6 +516,11 @@ class DatabaseMigration { // https://github.com/mempool/mempool/issues/3360 await this.$executeQuery(`TRUNCATE prices`); } + + if (databaseSchemaVersion < 60 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD sigop_txs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(60); + } } /** diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 3fa7006fb..8b6604522 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -557,7 +557,7 @@ class WebsocketHandler { } if (Common.indexingEnabled() && memPool.isInSync()) { - const { censored, added, fresh, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool); + const { censored, added, fresh, sigop, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool); const matchRate = Math.round(score * 100 * 100) / 100; const stripped = projectedBlocks[0]?.transactions ? projectedBlocks[0].transactions.map((tx) => { @@ -584,6 +584,7 @@ class WebsocketHandler { addedTxs: added, missingTxs: censored, freshTxs: fresh, + sigopTxs: sigop, matchRate: matchRate, }); diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 7204c174e..63f33d222 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -32,6 +32,7 @@ export interface BlockAudit { hash: string, missingTxs: string[], freshTxs: string[], + sigopTxs: string[], addedTxs: string[], matchRate: number, } diff --git a/backend/src/repositories/BlocksAuditsRepository.ts b/backend/src/repositories/BlocksAuditsRepository.ts index 70565a1c8..33075f43c 100644 --- a/backend/src/repositories/BlocksAuditsRepository.ts +++ b/backend/src/repositories/BlocksAuditsRepository.ts @@ -6,9 +6,9 @@ import { BlockAudit, AuditScore } from '../mempool.interfaces'; class BlocksAuditRepositories { public async $saveAudit(audit: BlockAudit): Promise { try { - await DB.query(`INSERT INTO blocks_audits(time, height, hash, missing_txs, added_txs, fresh_txs, match_rate) - VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?)`, [audit.time, audit.height, audit.hash, JSON.stringify(audit.missingTxs), - JSON.stringify(audit.addedTxs), JSON.stringify(audit.freshTxs), audit.matchRate]); + await DB.query(`INSERT INTO blocks_audits(time, height, hash, missing_txs, added_txs, fresh_txs, sigop_txs, match_rate) + VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?)`, [audit.time, audit.height, audit.hash, JSON.stringify(audit.missingTxs), + JSON.stringify(audit.addedTxs), JSON.stringify(audit.freshTxs), JSON.stringify(audit.sigopTxs), audit.matchRate]); } catch (e: any) { if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart logger.debug(`Cannot save block audit for block ${audit.hash} because it has already been indexed, ignoring`); @@ -52,7 +52,7 @@ class BlocksAuditRepositories { const [rows]: any[] = await DB.query( `SELECT blocks.height, blocks.hash as id, UNIX_TIMESTAMP(blocks.blockTimestamp) as timestamp, blocks.size, blocks.weight, blocks.tx_count, - transactions, template, missing_txs as missingTxs, added_txs as addedTxs, fresh_txs as freshTxs, match_rate as matchRate + transactions, template, missing_txs as missingTxs, added_txs as addedTxs, fresh_txs as freshTxs, sigop_txs as sigopTxs, match_rate as matchRate FROM blocks_audits JOIN blocks ON blocks.hash = blocks_audits.hash JOIN blocks_summaries ON blocks_summaries.id = blocks_audits.hash @@ -63,6 +63,7 @@ class BlocksAuditRepositories { rows[0].missingTxs = JSON.parse(rows[0].missingTxs); rows[0].addedTxs = JSON.parse(rows[0].addedTxs); rows[0].freshTxs = JSON.parse(rows[0].freshTxs); + rows[0].sigopTxs = JSON.parse(rows[0].sigopTxs); rows[0].transactions = JSON.parse(rows[0].transactions); rows[0].template = JSON.parse(rows[0].template); diff --git a/frontend/src/app/components/block-overview-graph/tx-view.ts b/frontend/src/app/components/block-overview-graph/tx-view.ts index f2e67da5b..bb3d9563c 100644 --- a/frontend/src/app/components/block-overview-graph/tx-view.ts +++ b/frontend/src/app/components/block-overview-graph/tx-view.ts @@ -37,7 +37,7 @@ export default class TxView implements TransactionStripped { value: number; feerate: number; rate?: number; - status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected'; + status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'added' | 'censored' | 'selected'; context?: 'projected' | 'actual'; scene?: BlockScene; @@ -171,6 +171,7 @@ export default class TxView implements TransactionStripped { case 'censored': return auditColors.censored; case 'missing': + case 'sigop': return marginalFeeColors[feeLevelIndex] || marginalFeeColors[mempoolFeeColors.length - 1]; case 'fresh': return auditColors.missing; diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html index 7e2de8d67..795958fe3 100644 --- a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html @@ -44,6 +44,7 @@ Match Removed Marginal fee rate + High sigop count Recently broadcasted Added Marginal fee rate diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index a11be9ad2..f5fe1a469 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -335,6 +335,7 @@ export class BlockComponent implements OnInit, OnDestroy { const isMissing = {}; const isSelected = {}; const isFresh = {}; + const isSigop = {}; this.numMissing = 0; this.numUnexpected = 0; @@ -354,6 +355,9 @@ export class BlockComponent implements OnInit, OnDestroy { for (const txid of blockAudit.freshTxs || []) { isFresh[txid] = true; } + for (const txid of blockAudit.sigopTxs || []) { + isSigop[txid] = true; + } // set transaction statuses for (const tx of blockAudit.template) { tx.context = 'projected'; @@ -362,7 +366,7 @@ export class BlockComponent implements OnInit, OnDestroy { } else if (inBlock[tx.txid]) { tx.status = 'found'; } else { - tx.status = isFresh[tx.txid] ? 'fresh' : 'missing'; + tx.status = isFresh[tx.txid] ? 'fresh' : (isSigop[tx.txid] ? 'sigop' : 'missing'); isMissing[tx.txid] = true; this.numMissing++; } diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index 8d5d71da7..321ee5841 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -155,7 +155,7 @@ export interface TransactionStripped { fee: number; vsize: number; value: number; - status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected'; + status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'added' | 'censored' | 'selected'; } interface RbfTransaction extends TransactionStripped { diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index bcabf5a29..eaf937a5f 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -76,7 +76,7 @@ export interface TransactionStripped { vsize: number; value: number; rate?: number; // effective fee rate - status?: 'found' | 'missing' | 'fresh' | 'added' | 'censored' | 'selected'; + status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'added' | 'censored' | 'selected'; context?: 'projected' | 'actual'; } From 72586eda6e83c62299d0f85dd8333fbd7c5d2010 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 18 May 2023 09:51:41 -0400 Subject: [PATCH 16/53] Detect RBF by mined transactions --- backend/src/api/common.ts | 18 +++++++++++++++ backend/src/api/mempool.ts | 34 ++++++++++++++++++++++++++++ backend/src/api/rbf-cache.ts | 2 +- backend/src/api/websocket-handler.ts | 6 +++++ 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index fc952d6a8..ba06c53b3 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -77,6 +77,24 @@ export class Common { return matches; } + static findMinedRbfTransactions(minedTransactions: TransactionExtended[], spendMap: Map): { [txid: string]: { replaced: TransactionExtended[], replacedBy: TransactionExtended }} { + const matches: { [txid: string]: { replaced: TransactionExtended[], replacedBy: TransactionExtended }} = {}; + for (const tx of minedTransactions) { + const replaced: Set = new Set(); + for (let i = 0; i < tx.vin.length; i++) { + const vin = tx.vin[i]; + const match = spendMap.get(`${vin.txid}:${vin.vout}`); + if (match && match.txid !== tx.txid) { + replaced.add(match); + } + } + if (replaced.size) { + matches[tx.txid] = { replaced: Array.from(replaced), replacedBy: tx }; + } + } + return matches; + } + static stripTransaction(tx: TransactionExtended): TransactionStripped { return { txid: tx.txid, diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 5746ca6d4..fe84fb8e4 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -14,6 +14,7 @@ class Mempool { private inSync: boolean = false; private mempoolCacheDelta: number = -1; private mempoolCache: { [txId: string]: TransactionExtended } = {}; + private spendMap = new Map(); private mempoolInfo: IBitcoinApi.MempoolInfo = { loaded: false, size: 0, bytes: 0, usage: 0, total_fee: 0, maxmempool: 300000000, mempoolminfee: 0.00001000, minrelaytxfee: 0.00001000 }; private mempoolChangedCallback: ((newMempool: {[txId: string]: TransactionExtended; }, newTransactions: TransactionExtended[], @@ -77,6 +78,10 @@ class Mempool { return this.mempoolCache; } + public getSpendMap(): Map { + return this.spendMap; + } + public async $setMempool(mempoolData: { [txId: string]: TransactionExtended }) { this.mempoolCache = mempoolData; if (this.mempoolChangedCallback) { @@ -85,6 +90,7 @@ class Mempool { if (this.$asyncMempoolChangedCallback) { await this.$asyncMempoolChangedCallback(this.mempoolCache, [], []); } + this.addToSpendMap(Object.values(this.mempoolCache)); } public async $updateMemPoolInfo() { @@ -276,6 +282,34 @@ class Mempool { } } + public handleMinedRbfTransactions(rbfTransactions: { [txid: string]: { replaced: TransactionExtended[], replacedBy: TransactionExtended }}): void { + for (const rbfTransaction in rbfTransactions) { + if (rbfTransactions[rbfTransaction].replacedBy && rbfTransactions[rbfTransaction]?.replaced?.length) { + // Store replaced transactions + rbfCache.add(rbfTransactions[rbfTransaction].replaced, rbfTransactions[rbfTransaction].replacedBy); + } + } + } + + public addToSpendMap(transactions: TransactionExtended[]): void { + for (const tx of transactions) { + for (const vin of tx.vin) { + this.spendMap.set(`${vin.txid}:${vin.vout}`, tx); + } + } + } + + public removeFromSpendMap(transactions: TransactionExtended[]): void { + for (const tx of transactions) { + for (const vin of tx.vin) { + const key = `${vin.txid}:${vin.vout}`; + if (this.spendMap.get(key)?.txid === tx.txid) { + this.spendMap.delete(key); + } + } + } + } + private updateTxPerSecond() { const nowMinusTimeSpan = new Date().getTime() - (1000 * config.STATISTICS.TX_PER_SECOND_SAMPLE_PERIOD); this.txPerSecondArray = this.txPerSecondArray.filter((unixTime) => unixTime > nowMinusTimeSpan); diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts index d8fb8656c..51f8ffeca 100644 --- a/backend/src/api/rbf-cache.ts +++ b/backend/src/api/rbf-cache.ts @@ -31,7 +31,7 @@ class RbfCache { } public add(replaced: TransactionExtended[], newTxExtended: TransactionExtended): void { - if (!newTxExtended || !replaced?.length) { + if (!newTxExtended || !replaced?.length || this.txs.has(newTxExtended.txid)) { return; } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 3fa7006fb..04f18765f 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -332,6 +332,8 @@ class WebsocketHandler { for (const deletedTx of deletedTransactions) { rbfCache.evict(deletedTx.txid); } + memPool.removeFromSpendMap(deletedTransactions); + memPool.addToSpendMap(newTransactions); const recommendedFees = feeApi.getRecommendedFee(); // update init data @@ -599,6 +601,10 @@ class WebsocketHandler { } } + const rbfTransactions = Common.findMinedRbfTransactions(transactions, memPool.getSpendMap()); + memPool.handleMinedRbfTransactions(rbfTransactions); + memPool.removeFromSpendMap(transactions); + // Update mempool to remove transactions included in the new block for (const txId of txIds) { delete _memPool[txId]; From 9aaae7ca1e268c363c6df07ad2e25892a2ca9db7 Mon Sep 17 00:00:00 2001 From: wiz Date: Tue, 23 May 2023 17:23:51 -0300 Subject: [PATCH 17/53] ops: Disable buggy CLN crontab job in install --- production/install | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) diff --git a/production/install b/production/install index b50fa5f11..b7c863051 100755 --- a/production/install +++ b/production/install @@ -1321,16 +1321,18 @@ case $OS in echo "[*] Installing Core Lightning package" osPackageInstall ${CLN_PKG} - echo "[*] Installing Core Lightning mainnet Cronjob" - public_ipv4=$( ifconfig | grep 'inet ' | awk -F ' ' '{ print $2 }' | grep -v '^103\.165\.192\.' | grep -v '^127\.0\.0\.1' ) - public_ipv6=$( ifconfig | grep 'inet6' | awk -F ' ' '{ print $2 }' | grep -v '^2001:df6:7280::' | grep -v '^fe80::' | grep -v '^::1' ) - - crontab_cln+="@reboot sleep 10 ; screen -dmS main lightningd --rpc-file-mode 0660 --alias `hostname` --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" - crontab_cln+="@reboot sleep 10 ; screen -dmS tes lightningd --rpc-file-mode 0660 --alias `hostname` --network testnet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" - crontab_cln+="@reboot sleep 10 ; screen -dmS sig lightningd --rpc-file-mode 0660 --alias `hostname` --network signet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6 \n" - crontab_cln+="@reboot sleep 20 ; /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" - crontab_cln+="1 * * * * /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" - echo "${crontab_cln}" | crontab -u "${CLN_USER}" - +######## FIXME: this code doesn't work properly, needs fixing +# +# echo "[*] Installing Core Lightning mainnet Cronjob" +# public_ipv4=$( ifconfig | grep 'inet ' | awk -F ' ' '{ print $2 }' | grep -v '^103\.165\.192\.' | grep -v '^127\.0\.0\.1' ) +# public_ipv6=$( ifconfig | grep 'inet6' | awk -F ' ' '{ print $2 }' | grep -v '^2001:df6:7280::' | grep -v '^fe80::' | grep -v '^::1' ) +# +# crontab_cln+="@reboot sleep 10 ; screen -dmS main lightningd --rpc-file-mode 0660 --alias `hostname` --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" +# crontab_cln+="@reboot sleep 10 ; screen -dmS tes lightningd --rpc-file-mode 0660 --alias `hostname` --network testnet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6\n" +# crontab_cln+="@reboot sleep 10 ; screen -dmS sig lightningd --rpc-file-mode 0660 --alias `hostname` --network signet --disable-ip-discovery --autolisten false --bind-addr $public_ipv4 --announce-addr $public_ipv4 --bind-addr $public_ipv6 --announce-addr $public_ipv6 \n" +# crontab_cln+="@reboot sleep 20 ; /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" +# crontab_cln+="1 * * * * /mempool/mempool.space/lightning-seeder >/dev/null 2>&1\n" +# echo "${crontab_cln}" | crontab -u "${CLN_USER}" - ;; Debian) ;; From ea0cac23509032477ae83921eb4776254bc0c343 Mon Sep 17 00:00:00 2001 From: wiz Date: Tue, 23 May 2023 17:57:27 -0300 Subject: [PATCH 18/53] ops: Start mysql-server using onestart from install --- production/install | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/production/install b/production/install index b7c863051..5a79092a6 100755 --- a/production/install +++ b/production/install @@ -1815,7 +1815,7 @@ echo "[*] Adding MySQL configuration" case $OS in FreeBSD) - osSudo "${ROOT_USER}" service mysql-server start + osSudo "${ROOT_USER}" service mysql-server onestart ;; Debian) osSudo "${ROOT_USER}" service mysql start From 6154bf3b1a761bef315b886178a6523ceb609800 Mon Sep 17 00:00:00 2001 From: softsimon Date: Wed, 24 May 2023 01:22:01 +0400 Subject: [PATCH 19/53] Fix for pool output address matching fixes #3782 --- backend/src/api/blocks.ts | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 23814a87e..bce7983d3 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -306,7 +306,7 @@ class Blocks { } const asciiScriptSig = transactionUtils.hex2ascii(txMinerInfo.vin[0].scriptsig); - const address = txMinerInfo.vout[0].scriptpubkey_address; + const addresses = txMinerInfo.vout.map((vout) => vout.scriptpubkey_address).filter((address) => address); let pools: PoolTag[] = []; if (config.DATABASE.ENABLED === true) { @@ -316,11 +316,13 @@ class Blocks { } for (let i = 0; i < pools.length; ++i) { - if (address !== undefined) { - const addresses: string[] = typeof pools[i].addresses === 'string' ? + if (addresses.length) { + const poolAddresses: string[] = typeof pools[i].addresses === 'string' ? JSON.parse(pools[i].addresses) : pools[i].addresses; - if (addresses.indexOf(address) !== -1) { - return pools[i]; + for (let y = 0; y < poolAddresses.length; y++) { + if (addresses.indexOf(poolAddresses[y]) !== -1) { + return pools[i]; + } } } From 137de7a723488ea281d5ed017c4e3978f5cade55 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Thu, 25 May 2023 00:31:44 -0400 Subject: [PATCH 20/53] Change embassyos to startos --- frontend/src/app/components/about/about.component.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index e67facfe1..095b311b9 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -205,9 +205,9 @@ NixOS - + - EmbassyOS + StartOS From 9b34d2245a105bd6cbb034a649d1ed842e1fe926 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Thu, 25 May 2023 01:29:55 -0400 Subject: [PATCH 21/53] Add bull bitcoin as enterprise sponsor --- frontend/src/app/components/about/about.component.html | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index e67facfe1..aa604f678 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -119,6 +119,10 @@ Gemini + + + Bull Bitcoin + From 8401b80738b153233262ea1a0483555c30d37d08 Mon Sep 17 00:00:00 2001 From: Stephan Oeste Date: Thu, 25 May 2023 16:50:56 +0200 Subject: [PATCH 22/53] Fix exact match of .js files. Was also matching .json before. --- production/nginx/server-common.conf | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/production/nginx/server-common.conf b/production/nginx/server-common.conf index dedd36411..6b737b056 100644 --- a/production/nginx/server-common.conf +++ b/production/nginx/server-common.conf @@ -59,7 +59,7 @@ location = / { } # cache //main.f40e91d908a068a2.js forever since they never change -location ~ ^/([a-z][a-z])/(.+\..+\.(js|css)) { +location ~ ^/([a-z][a-z])/(.+\..+\.(js|css))$ { try_files $uri =404; expires 1y; } @@ -82,7 +82,7 @@ location /resources { expires 1w; } # cache /main.f40e91d908a068a2.js forever since they never change -location ~* ^/.+\..+\.(js|css) { +location ~* ^/.+\..+\.(js|css)$ { try_files /$lang/$uri /en-US/$uri =404; expires 1y; } From 6f8a9052f2e4671dd4384b8c5f5e67d92aabe7ec Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 25 May 2023 19:05:29 +0400 Subject: [PATCH 23/53] Don't wipe mempool cache in pools updater --- backend/src/api/disk-cache.ts | 11 +++++++++-- backend/src/api/pools-parser.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 0264fe1a3..2e3ff6fb1 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -21,6 +21,7 @@ class DiskCache { private static RBF_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/rbfcache.json'; private static CHUNK_FILES = 25; private isWritingCache = false; + private ignoreBlocksCache = false; private semaphore: { resume: (() => void)[], locks: number } = { resume: [], @@ -218,8 +219,10 @@ class DiskCache { } await memPool.$setMempool(data.mempool); - blocks.setBlocks(data.blocks); - blocks.setBlockSummaries(data.blockSummaries || []); + if (!this.ignoreBlocksCache) { + blocks.setBlocks(data.blocks); + blocks.setBlockSummaries(data.blockSummaries || []); + } } catch (e) { logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); } @@ -273,6 +276,10 @@ class DiskCache { } } } + + public setIgnoreBlocksCache(): void { + this.ignoreBlocksCache = true; + } } export default new DiskCache(); diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index f94c147a2..7397c5639 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -41,7 +41,7 @@ class PoolsParser { public async migratePoolsJson(): Promise { // We also need to wipe the backend cache to make sure we don't serve blocks with // the wrong mining pool (usually happen with unknown blocks) - diskCache.wipeCache(); + diskCache.setIgnoreBlocksCache(); await this.$insertUnknownPool(); From 056e0b0c043cd1206b8978299aeb081630fc1455 Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 25 May 2023 19:06:45 +0400 Subject: [PATCH 24/53] Revert "Don't wipe mempool cache in pools updater" This reverts commit 714208a3669000c4f20777f6d0118ed8b4f35a83. --- backend/src/api/disk-cache.ts | 11 ++--------- backend/src/api/pools-parser.ts | 2 +- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 2e3ff6fb1..0264fe1a3 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -21,7 +21,6 @@ class DiskCache { private static RBF_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/rbfcache.json'; private static CHUNK_FILES = 25; private isWritingCache = false; - private ignoreBlocksCache = false; private semaphore: { resume: (() => void)[], locks: number } = { resume: [], @@ -219,10 +218,8 @@ class DiskCache { } await memPool.$setMempool(data.mempool); - if (!this.ignoreBlocksCache) { - blocks.setBlocks(data.blocks); - blocks.setBlockSummaries(data.blockSummaries || []); - } + blocks.setBlocks(data.blocks); + blocks.setBlockSummaries(data.blockSummaries || []); } catch (e) { logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); } @@ -276,10 +273,6 @@ class DiskCache { } } } - - public setIgnoreBlocksCache(): void { - this.ignoreBlocksCache = true; - } } export default new DiskCache(); diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 7397c5639..f94c147a2 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -41,7 +41,7 @@ class PoolsParser { public async migratePoolsJson(): Promise { // We also need to wipe the backend cache to make sure we don't serve blocks with // the wrong mining pool (usually happen with unknown blocks) - diskCache.setIgnoreBlocksCache(); + diskCache.wipeCache(); await this.$insertUnknownPool(); From 9d8b4812ee0e249d9d081e692f57774f4b08c5dd Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 25 May 2023 19:05:29 +0400 Subject: [PATCH 25/53] Don't wipe mempool cache in pools updater --- backend/src/api/disk-cache.ts | 11 +++++++++-- backend/src/api/pools-parser.ts | 2 +- 2 files changed, 10 insertions(+), 3 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 0264fe1a3..2e3ff6fb1 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -21,6 +21,7 @@ class DiskCache { private static RBF_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/rbfcache.json'; private static CHUNK_FILES = 25; private isWritingCache = false; + private ignoreBlocksCache = false; private semaphore: { resume: (() => void)[], locks: number } = { resume: [], @@ -218,8 +219,10 @@ class DiskCache { } await memPool.$setMempool(data.mempool); - blocks.setBlocks(data.blocks); - blocks.setBlockSummaries(data.blockSummaries || []); + if (!this.ignoreBlocksCache) { + blocks.setBlocks(data.blocks); + blocks.setBlockSummaries(data.blockSummaries || []); + } } catch (e) { logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); } @@ -273,6 +276,10 @@ class DiskCache { } } } + + public setIgnoreBlocksCache(): void { + this.ignoreBlocksCache = true; + } } export default new DiskCache(); diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index f94c147a2..7397c5639 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -41,7 +41,7 @@ class PoolsParser { public async migratePoolsJson(): Promise { // We also need to wipe the backend cache to make sure we don't serve blocks with // the wrong mining pool (usually happen with unknown blocks) - diskCache.wipeCache(); + diskCache.setIgnoreBlocksCache(); await this.$insertUnknownPool(); From cf8aeb6db96eda841ff559dacfeb16a3f9088ed0 Mon Sep 17 00:00:00 2001 From: softsimon Date: Thu, 25 May 2023 19:19:14 +0400 Subject: [PATCH 26/53] Save new disk cache after ignoring blocks --- backend/src/api/disk-cache.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 2e3ff6fb1..17d75d07b 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -222,6 +222,9 @@ class DiskCache { if (!this.ignoreBlocksCache) { blocks.setBlocks(data.blocks); blocks.setBlockSummaries(data.blockSummaries || []); + } else { + logger.info('Re-saving cache with empty recent blocks data'); + await this.$saveCacheToDisk(true); } } catch (e) { logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); From f78a620faef8b1df45b50e3ec44ce1f579a3bace Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 25 May 2023 09:08:51 -0700 Subject: [PATCH 27/53] Always re-indexing blocks when updating mining pools --- backend/src/api/pools-parser.ts | 4 ---- 1 file changed, 4 deletions(-) diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 7397c5639..0d34925ab 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -118,10 +118,6 @@ class PoolsParser { * @param pool */ private async $deleteBlocksForPool(pool: PoolTag): Promise { - if (config.MEMPOOL.AUTOMATIC_BLOCK_REINDEXING === false) { - return; - } - // 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 const [oldestPoolBlock]: any[] = await DB.query(` From 748665d3f6041de1ad14ae7a5fa640815f2f5794 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Thu, 25 May 2023 15:58:48 -0400 Subject: [PATCH 28/53] Make svg pretty --- frontend/src/app/components/about/about.component.html | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index aa604f678..8655ab800 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -120,7 +120,15 @@ Gemini - + Bull Bitcoin From 53233a8639d6609d6c2decd73674b54e9648794a Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 26 May 2023 02:56:38 +0000 Subject: [PATCH 29/53] Bump bitcoinjs-lib from 6.1.0 to 6.1.1 in /backend Bumps [bitcoinjs-lib](https://github.com/bitcoinjs/bitcoinjs-lib) from 6.1.0 to 6.1.1. - [Changelog](https://github.com/bitcoinjs/bitcoinjs-lib/blob/master/CHANGELOG.md) - [Commits](https://github.com/bitcoinjs/bitcoinjs-lib/compare/v6.1.0...v6.1.1) --- updated-dependencies: - dependency-name: bitcoinjs-lib dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- backend/package-lock.json | 289 +++++++------------------------------- 1 file changed, 52 insertions(+), 237 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index a2106ac9f..a7b0a5877 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -1485,6 +1485,17 @@ "node": ">=6" } }, + "node_modules/@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -2403,12 +2414,9 @@ "dev": true }, "node_modules/base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "dependencies": { - "safe-buffer": "^5.0.1" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" }, "node_modules/bech32": { "version": "2.0.0", @@ -2424,18 +2432,16 @@ } }, "node_modules/bitcoinjs-lib": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.0.tgz", - "integrity": "sha512-eupi1FBTJmPuAZdChnzTXLv2HBqFW2AICpzXZQLniP0V9FWWeeUQSMKES6sP8isy/xO0ijDexbgkdEyFVrsuJw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.1.tgz", + "integrity": "sha512-FYihfgTk29lt1eK2y48OtuarEDUnTprNBW3ctT8yHiOhvmeS3DzAVG6gI0VCvMkydz6UdlXlYNWIPqGD0SUYRQ==", "dependencies": { + "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", "bip174": "^2.1.0", - "bs58check": "^2.1.2", - "create-hash": "^1.1.0", - "ripemd160": "^2.0.2", + "bs58check": "^3.0.1", "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.1.2", - "wif": "^2.0.1" + "varuint-bitcoin": "^1.1.2" }, "engines": { "node": ">=8.0.0" @@ -2540,21 +2546,20 @@ } }, "node_modules/bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", "dependencies": { - "base-x": "^3.0.2" + "base-x": "^4.0.0" } }, "node_modules/bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", + "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", "dependencies": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" + "@noble/hashes": "^1.2.0", + "bs58": "^5.0.0" } }, "node_modules/bser": { @@ -2668,15 +2673,6 @@ "node": ">=8" } }, - "node_modules/cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "node_modules/cjs-module-lexer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", @@ -2783,18 +2779,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, - "node_modules/create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "dependencies": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, "node_modules/create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -3825,19 +3809,6 @@ "url": "https://github.com/sponsors/ljharb" } }, - "node_modules/hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "dependencies": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - }, - "engines": { - "node": ">=4" - } - }, "node_modules/html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -5916,16 +5887,6 @@ "npm": ">=6" } }, - "node_modules/md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "node_modules/media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -6591,19 +6552,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "node_modules/readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "dependencies": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - }, - "engines": { - "node": ">= 6" - } - }, "node_modules/require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -6694,15 +6642,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "dependencies": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -6824,18 +6763,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "node_modules/sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "dependencies": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - }, - "bin": { - "sha.js": "bin.js" - } - }, "node_modules/shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -6988,14 +6915,6 @@ "node": ">= 0.8" } }, - "node_modules/string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "dependencies": { - "safe-buffer": "~5.2.0" - } - }, "node_modules/string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -7397,11 +7316,6 @@ "punycode": "^2.1.0" } }, - "node_modules/util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, "node_modules/utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -7470,14 +7384,6 @@ "node": ">= 8" } }, - "node_modules/wif": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", - "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", - "dependencies": { - "bs58check": "<3.0.0" - } - }, "node_modules/word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", @@ -8725,6 +8631,11 @@ "resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.9.tgz", "integrity": "sha512-mlvPiCzUlaETpYW3i6V87A24jjMYgsebaXtUo3WQyyLnYUuxs0KiXQ2mnKh3h15j8Xg/hfxeGIi+5OC9u0nftQ==" }, + "@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==" + }, "@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -9445,12 +9356,9 @@ "dev": true }, "base-x": { - "version": "3.0.9", - "resolved": "https://registry.npmjs.org/base-x/-/base-x-3.0.9.tgz", - "integrity": "sha512-H7JU6iBHTal1gp56aKoaa//YUxEaAOUiydvrV/pILqIHXTtqxSkATOnDA2u+jZ/61sD+L/412+7kzXRtWukhpQ==", - "requires": { - "safe-buffer": "^5.0.1" - } + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" }, "bech32": { "version": "2.0.0", @@ -9463,18 +9371,16 @@ "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA==" }, "bitcoinjs-lib": { - "version": "6.1.0", - "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.0.tgz", - "integrity": "sha512-eupi1FBTJmPuAZdChnzTXLv2HBqFW2AICpzXZQLniP0V9FWWeeUQSMKES6sP8isy/xO0ijDexbgkdEyFVrsuJw==", + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.1.tgz", + "integrity": "sha512-FYihfgTk29lt1eK2y48OtuarEDUnTprNBW3ctT8yHiOhvmeS3DzAVG6gI0VCvMkydz6UdlXlYNWIPqGD0SUYRQ==", "requires": { + "@noble/hashes": "^1.2.0", "bech32": "^2.0.0", "bip174": "^2.1.0", - "bs58check": "^2.1.2", - "create-hash": "^1.1.0", - "ripemd160": "^2.0.2", + "bs58check": "^3.0.1", "typeforce": "^1.11.3", - "varuint-bitcoin": "^1.1.2", - "wif": "^2.0.1" + "varuint-bitcoin": "^1.1.2" } }, "body-parser": { @@ -9552,21 +9458,20 @@ } }, "bs58": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/bs58/-/bs58-4.0.1.tgz", - "integrity": "sha512-Ok3Wdf5vOIlBrgCvTq96gBkJw+JUEzdBgyaza5HLtPm7yTHkjRy8+JzNyHF7BHa0bNWOQIp3m5YF0nnFcOIKLw==", + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", "requires": { - "base-x": "^3.0.2" + "base-x": "^4.0.0" } }, "bs58check": { - "version": "2.1.2", - "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-2.1.2.tgz", - "integrity": "sha512-0TS1jicxdU09dwJMNZtVAfzPi6Q6QeN0pM1Fkzrjn+XYHvzMKPU3pHVpva+769iNVSfIYWf7LJ6WR+BuuMf8cA==", + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", + "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", "requires": { - "bs58": "^4.0.0", - "create-hash": "^1.1.0", - "safe-buffer": "^5.1.2" + "@noble/hashes": "^1.2.0", + "bs58": "^5.0.0" } }, "bser": { @@ -9639,15 +9544,6 @@ "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", "dev": true }, - "cipher-base": { - "version": "1.0.4", - "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", - "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "cjs-module-lexer": { "version": "1.2.2", "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", @@ -9735,18 +9631,6 @@ "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" }, - "create-hash": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", - "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", - "requires": { - "cipher-base": "^1.0.1", - "inherits": "^2.0.1", - "md5.js": "^1.3.4", - "ripemd160": "^2.0.1", - "sha.js": "^2.4.0" - } - }, "create-require": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", @@ -10513,16 +10397,6 @@ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" }, - "hash-base": { - "version": "3.1.0", - "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", - "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", - "requires": { - "inherits": "^2.0.4", - "readable-stream": "^3.6.0", - "safe-buffer": "^5.2.0" - } - }, "html-escaper": { "version": "2.0.2", "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", @@ -12069,16 +11943,6 @@ "tiny-lru": "10.3.0" } }, - "md5.js": { - "version": "1.3.5", - "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", - "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1", - "safe-buffer": "^5.1.2" - } - }, "media-typer": { "version": "0.3.0", "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", @@ -12547,16 +12411,6 @@ "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", "dev": true }, - "readable-stream": { - "version": "3.6.2", - "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", - "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", - "requires": { - "inherits": "^2.0.3", - "string_decoder": "^1.1.1", - "util-deprecate": "^1.0.1" - } - }, "require-directory": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", @@ -12618,15 +12472,6 @@ "glob": "^7.1.3" } }, - "ripemd160": { - "version": "2.0.2", - "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", - "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", - "requires": { - "hash-base": "^3.0.0", - "inherits": "^2.0.1" - } - }, "run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", @@ -12715,15 +12560,6 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, - "sha.js": { - "version": "2.4.11", - "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", - "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", - "requires": { - "inherits": "^2.0.1", - "safe-buffer": "^5.0.1" - } - }, "shebang-command": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", @@ -12840,14 +12676,6 @@ "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" }, - "string_decoder": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz", - "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==", - "requires": { - "safe-buffer": "~5.2.0" - } - }, "string-length": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", @@ -13101,11 +12929,6 @@ "punycode": "^2.1.0" } }, - "util-deprecate": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", - "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==" - }, "utils-merge": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", @@ -13159,14 +12982,6 @@ "isexe": "^2.0.0" } }, - "wif": { - "version": "2.0.6", - "resolved": "https://registry.npmjs.org/wif/-/wif-2.0.6.tgz", - "integrity": "sha512-HIanZn1zmduSF+BQhkE+YXIbEiH0xPr1012QbFEGB0xsKqJii0/SqJjyn8dFv6y36kOznMgMB+LGcbZTJ1xACQ==", - "requires": { - "bs58check": "<3.0.0" - } - }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", From d51e94c93533220c0467aeb08df39be05d7add58 Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Fri, 26 May 2023 17:25:52 -0400 Subject: [PATCH 30/53] Switch tm to r for registered trademarks --- frontend/src/app/components/about/about.component.html | 4 ++-- .../trademark-policy/trademark-policy.component.html | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 9a778be44..c59f700a8 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -1,7 +1,7 @@
- + ®
v{{ packetJsonVersion }} [{{ frontendGitCommitHash }}] @@ -396,7 +396,7 @@ Trademark Notice

- The Mempool Open Source Project™, mempool.space™, the mempool logo™, the mempool.space logos™, the mempool square logo™, and the mempool blocks logo™ are either registered trademarks or trademarks of Mempool Space K.K in Japan, the United States, and/or other countries. + The Mempool Open Source Project™, mempool.space™, the mempool logo®, the mempool.space logos™, the mempool square logo®, and the mempool blocks logo™ are either registered trademarks or trademarks of Mempool Space K.K in Japan, the United States, and/or other countries.

While our software is available under an open source software license, the copyright license does not include an implied right or license to use our trademarks. See our Trademark Policy and Guidelines for more details, published on <https://mempool.space/trademark-policy>. diff --git a/frontend/src/app/components/trademark-policy/trademark-policy.component.html b/frontend/src/app/components/trademark-policy/trademark-policy.component.html index 4526a6c0c..4f9419642 100644 --- a/frontend/src/app/components/trademark-policy/trademark-policy.component.html +++ b/frontend/src/app/components/trademark-policy/trademark-policy.component.html @@ -304,7 +304,7 @@

Also, if you are using our Marks in a way described in the sections "Uses for Which We Are Granting a License," you must include the following trademark attribution at the foot of the webpage where you have used the Mark (or, if in a book, on the credits page), on any packaging or labeling, and on advertising or marketing materials:

-

“The Mempool Space K.K.™, The Mempool Open Source Project™, mempool.space™, the mempool logo™, the mempool.space logos™, the mempool square logo™, and the mempool blocks logo™ are either registered trademarks or trademarks of Mempool Space K.K in Japan, the United States, and/or other countries, and are used with permission. Mempool Space K.K. has no affiliation with and does not sponsor or endorse the information provided herein.”

+

“The Mempool Space K.K.™, The Mempool Open Source Project™, mempool.space™, the mempool logo®, the mempool.space logos™, the mempool square logo®, and the mempool blocks logo™ are either registered trademarks or trademarks of Mempool Space K.K in Japan, the United States, and/or other countries, and are used with permission. Mempool Space K.K. has no affiliation with and does not sponsor or endorse the information provided herein.”

  • What to Do When You See Abuse
  • From 6b893fd75d04525bc1654824443b03769ad3a99c Mon Sep 17 00:00:00 2001 From: hunicus <93150691+hunicus@users.noreply.github.com> Date: Sat, 27 May 2023 12:38:20 -0400 Subject: [PATCH 31/53] Unmute about promo video on click --- frontend/src/app/components/about/about.component.html | 2 +- frontend/src/app/components/about/about.component.ts | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index c59f700a8..cc50a4a5b 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -13,7 +13,7 @@

    Our mempool and blockchain explorer for the Bitcoin community, focusing on the transaction fee market and multi-layer ecosystem, completely self-hosted without any trusted third-parties.

    -
    -
    -
    diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 60051634d..dd32b05e8 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -391,7 +391,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.blocksSubscription = this.stateService.blocks$.subscribe(([block, txConfirmed]) => { this.latestBlock = block; - if (txConfirmed && this.tx && !this.tx.status.confirmed) { + if (txConfirmed && this.tx && !this.tx.status.confirmed && txConfirmed === this.tx.txid) { this.tx.status = { confirmed: true, block_height: block.height, diff --git a/frontend/src/app/components/transactions-list/transactions-list.component.html b/frontend/src/app/components/transactions-list/transactions-list.component.html index 0d195f2ff..c509a799d 100644 --- a/frontend/src/app/components/transactions-list/transactions-list.component.html +++ b/frontend/src/app/components/transactions-list/transactions-list.component.html @@ -298,14 +298,7 @@
    - - - - + + + + + + + + \ No newline at end of file diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.scss b/frontend/src/app/shared/components/confirmations/confirmations.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.ts b/frontend/src/app/shared/components/confirmations/confirmations.component.ts new file mode 100644 index 000000000..dc66673ed --- /dev/null +++ b/frontend/src/app/shared/components/confirmations/confirmations.component.ts @@ -0,0 +1,25 @@ +import { Component, Input, OnChanges } from '@angular/core'; + + +@Component({ + selector: 'app-confirmations', + templateUrl: './confirmations.component.html', + styleUrls: ['./confirmations.component.scss'], +}) +export class ConfirmationsComponent implements OnChanges { + @Input() chainTip: number; + @Input() height: number; + @Input() replaced: boolean = false; + @Input() hideUnconfirmed: boolean = false; + @Input() buttonClass: string = ''; + + confirmations: number = 0; + + ngOnChanges(): void { + if (this.chainTip != null && this.height != null) { + this.confirmations = Math.max(1, this.chainTip - this.height + 1); + } else { + this.confirmations = 0; + } + } +} diff --git a/frontend/src/app/shared/shared.module.ts b/frontend/src/app/shared/shared.module.ts index 6e8d8d0f2..d24f5356e 100644 --- a/frontend/src/app/shared/shared.module.ts +++ b/frontend/src/app/shared/shared.module.ts @@ -85,6 +85,7 @@ import { SatsComponent } from './components/sats/sats.component'; import { TruncateComponent } from './components/truncate/truncate.component'; import { SearchResultsComponent } from '../components/search-form/search-results/search-results.component'; import { TimestampComponent } from './components/timestamp/timestamp.component'; +import { ConfirmationsComponent } from './components/confirmations/confirmations.component'; import { ToggleComponent } from './components/toggle/toggle.component'; import { GeolocationComponent } from '../shared/components/geolocation/geolocation.component'; import { TestnetAlertComponent } from './components/testnet-alert/testnet-alert.component'; @@ -175,6 +176,7 @@ import { ClockMempoolComponent } from '../components/clock/clock-mempool.compone TruncateComponent, SearchResultsComponent, TimestampComponent, + ConfirmationsComponent, ToggleComponent, GeolocationComponent, TestnetAlertComponent, @@ -289,6 +291,7 @@ import { ClockMempoolComponent } from '../components/clock/clock-mempool.compone TruncateComponent, SearchResultsComponent, TimestampComponent, + ConfirmationsComponent, ToggleComponent, GeolocationComponent, PreviewTitleComponent, From 1d129447cfa4ad28629ff8a62c86a960a36a40e1 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sun, 4 Jun 2023 10:32:24 +0400 Subject: [PATCH 46/53] Optimize change detection --- .../shared/components/confirmations/confirmations.component.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/shared/components/confirmations/confirmations.component.ts b/frontend/src/app/shared/components/confirmations/confirmations.component.ts index dc66673ed..8d14128e5 100644 --- a/frontend/src/app/shared/components/confirmations/confirmations.component.ts +++ b/frontend/src/app/shared/components/confirmations/confirmations.component.ts @@ -1,10 +1,11 @@ -import { Component, Input, OnChanges } from '@angular/core'; +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; @Component({ selector: 'app-confirmations', templateUrl: './confirmations.component.html', styleUrls: ['./confirmations.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ConfirmationsComponent implements OnChanges { @Input() chainTip: number; From 56a9990f8861919b38573623126d789a3501f862 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 4 Jun 2023 11:44:40 -0400 Subject: [PATCH 47/53] fix txConfirmed type --- frontend/src/app/interfaces/websocket.interface.ts | 2 +- frontend/src/app/services/state.service.ts | 4 ++-- frontend/src/app/services/websocket.service.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 20d1cbeed..83a0c636e 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -6,7 +6,7 @@ export interface WebsocketResponse { block?: BlockExtended; blocks?: BlockExtended[]; conversions?: any; - txConfirmed?: string | boolean; + txConfirmed?: string; historicalDate?: string; mempoolInfo?: MempoolInfo; vBytesPerSecond?: number; diff --git a/frontend/src/app/services/state.service.ts b/frontend/src/app/services/state.service.ts index d6e39ddc9..55f349cc1 100644 --- a/frontend/src/app/services/state.service.ts +++ b/frontend/src/app/services/state.service.ts @@ -92,7 +92,7 @@ export class StateService { networkChanged$ = new ReplaySubject(1); lightningChanged$ = new ReplaySubject(1); - blocks$: ReplaySubject<[BlockExtended, string | boolean]>; + blocks$: ReplaySubject<[BlockExtended, string]>; transactions$ = new ReplaySubject(6); conversions$ = new ReplaySubject(1); bsqPrice$ = new ReplaySubject(1); @@ -163,7 +163,7 @@ export class StateService { } }); - this.blocks$ = new ReplaySubject<[BlockExtended, boolean]>(this.env.KEEP_BLOCKS_AMOUNT); + this.blocks$ = new ReplaySubject<[BlockExtended, string]>(this.env.KEEP_BLOCKS_AMOUNT); if (this.env.BASE_MODULE === 'bisq') { this.network = this.env.BASE_MODULE; diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index 7a84aadd7..af7a465f8 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -241,7 +241,7 @@ export class WebsocketService { blocks.forEach((block: BlockExtended) => { if (block.height > this.stateService.latestBlockHeight) { maxHeight = Math.max(maxHeight, block.height); - this.stateService.blocks$.next([block, false]); + this.stateService.blocks$.next([block, '']); } }); this.stateService.updateChainTip(maxHeight); @@ -258,7 +258,7 @@ export class WebsocketService { if (response.block) { if (response.block.height > this.stateService.latestBlockHeight) { this.stateService.updateChainTip(response.block.height); - this.stateService.blocks$.next([response.block, response.txConfirmed]); + this.stateService.blocks$.next([response.block, response.txConfirmed || '']); } if (response.txConfirmed) { From e51d4584ab1230c9525f17545adbbd6e25be2b92 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Sun, 4 Jun 2023 12:36:27 -0400 Subject: [PATCH 48/53] fix firstSeen reset bug --- backend/src/api/transaction-utils.ts | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts index 2d1f0f955..8523a938e 100644 --- a/backend/src/api/transaction-utils.ts +++ b/backend/src/api/transaction-utils.ts @@ -59,8 +59,8 @@ class TransactionUtils { feePerVsize: feePerVbytes, effectiveFeePerVsize: feePerVbytes, }, transaction); - if (!transaction?.status?.confirmed) { - transactionExtended.firstSeen = Math.round((new Date().getTime() / 1000)); + if (!transaction?.status?.confirmed && !transactionExtended.firstSeen) { + transactionExtended.firstSeen = Math.round((Date.now() / 1000)); } return transactionExtended; } @@ -83,8 +83,8 @@ class TransactionUtils { adjustedFeePerVsize: adjustedFeePerVsize, effectiveFeePerVsize: adjustedFeePerVsize, }); - if (!transaction?.status?.confirmed) { - transactionExtended.firstSeen = Math.round((new Date().getTime() / 1000)); + if (!transactionExtended?.status?.confirmed && !transactionExtended.firstSeen) { + transactionExtended.firstSeen = Math.round((Date.now() / 1000)); } return transactionExtended; } From 523c52e0ed180b563b5d1b0d66f941aa7b25fb4a Mon Sep 17 00:00:00 2001 From: junderw Date: Mon, 5 Jun 2023 07:21:55 -0700 Subject: [PATCH 49/53] Fix: Annex parsing for p2tr on bitcoind/romanz backends --- backend/src/api/bitcoin/bitcoin-api.ts | 32 +++++++++++++++++++++++--- 1 file changed, 29 insertions(+), 3 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index e20fe9e34..307736737 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -415,12 +415,38 @@ class BitcoinApi implements AbstractBitcoinApi { vin.inner_witnessscript_asm = this.convertScriptSigAsm(witnessScript); } - if (vin.prevout.scriptpubkey_type === 'v1_p2tr' && vin.witness && vin.witness.length > 1) { - const witnessScript = vin.witness[vin.witness.length - 2]; - vin.inner_witnessscript_asm = this.convertScriptSigAsm(witnessScript); + if (vin.prevout.scriptpubkey_type === 'v1_p2tr' && vin.witness) { + const witnessScript = this.witnessToP2TRScript(vin.witness); + if (witnessScript !== null) { + vin.inner_witnessscript_asm = this.convertScriptSigAsm(witnessScript); + } } } + /** + * This function must only be called when we know the witness we are parsing + * is a taproot witness. + * @param witness An array of hex strings that represents the witness stack of + * the input. + * @returns null if the witness is not a script spend, and the hex string of + * the script item if it is a script spend. + */ + private witnessToP2TRScript(witness: string[]): string | null { + if (witness.length < 2) return null; + // Note: see BIP341 for parsing details of witness stack + + // If there are at least two witness elements, and the first byte of the + // last element is 0x50, this last element is called annex a and + // is removed from the witness stack. + const hasAnnex = witness[witness.length - 1].substring(0, 2) === '50'; + // If there are at least two witness elements left, script path spending is used. + // Call the second-to-last stack element s, the script. + // (Note: this phrasing from BIP341 assumes we've *removed* the annex from the stack) + if (hasAnnex && witness.length < 3) return null; + const positionOfScript = hasAnnex ? witness.length - 3 : witness.length - 2; + return witness[positionOfScript]; + } + } export default BitcoinApi; From 50aaa55bbec825b9f5ea88bf2c0d2fa29727230f Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 5 Jun 2023 14:23:37 -0400 Subject: [PATCH 50/53] fix graph filter dropdown colors --- frontend/src/app/components/statistics/statistics.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/statistics/statistics.component.ts b/frontend/src/app/components/statistics/statistics.component.ts index 5e638af31..35137bff1 100644 --- a/frontend/src/app/components/statistics/statistics.component.ts +++ b/frontend/src/app/components/statistics/statistics.component.ts @@ -196,7 +196,7 @@ export class StatisticsComponent implements OnInit { this.feeLevelDropdownData.push({ fee: fee, range, - color: _chartColors[i - 1], + color: _chartColors[i], }); } }); From 102b6a291f7d76d3751f445e1f9d66d725eb4876 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 26 May 2023 19:12:12 -0400 Subject: [PATCH 51/53] Fix missing fees in $updateBlocks without esplora --- backend/src/api/blocks.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index fc12b5998..9e56db027 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -600,6 +600,14 @@ class Blocks { const block = BitcoinApi.convertBlock(verboseBlock); const txIds: string[] = await bitcoinApi.$getTxIdsForBlock(blockHash); const transactions = await this.$getTransactionsExtended(blockHash, block.height, false, false, true); + if (config.MEMPOOL.BACKEND !== 'esplora') { + // fill in missing transaction fee data from verboseBlock + for (let i = 0; i < transactions.length; i++) { + if (!transactions[i].fee && transactions[i].txid === verboseBlock.tx[i].txid) { + transactions[i].fee = verboseBlock.tx[i].fee * 100_000_000; + } + } + } const cpfpSummary: CpfpSummary = Common.calculateCpfp(block.height, transactions); const blockExtended: BlockExtended = await this.$getBlockExtended(block, cpfpSummary.transactions); const blockSummary: BlockSummary = this.summarizeBlock(verboseBlock); From 9941c32e534c37810519fc39ac5ff5cad2991b03 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Wed, 7 Jun 2023 18:04:21 +0200 Subject: [PATCH 52/53] don't throw when BlocksAuditRepositories.$saveAudit fails --- backend/src/repositories/BlocksAuditsRepository.ts | 1 - 1 file changed, 1 deletion(-) diff --git a/backend/src/repositories/BlocksAuditsRepository.ts b/backend/src/repositories/BlocksAuditsRepository.ts index c6156334b..1149b8a93 100644 --- a/backend/src/repositories/BlocksAuditsRepository.ts +++ b/backend/src/repositories/BlocksAuditsRepository.ts @@ -14,7 +14,6 @@ class BlocksAuditRepositories { logger.debug(`Cannot save block audit for block ${audit.hash} because it has already been indexed, ignoring`); } else { logger.err(`Cannot save block audit into db. Reason: ` + (e instanceof Error ? e.message : e)); - throw e; } } } From 9c7458a42f60db8fce73e7b8b7ee6ac84578ce47 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 9 Jun 2023 19:03:47 -0400 Subject: [PATCH 53/53] Reset blockchain scroll on logo click --- .../app/components/master-page/master-page.component.html | 2 +- .../app/components/master-page/master-page.component.ts | 4 ++++ frontend/src/app/components/start/start.component.ts | 8 ++++++++ frontend/src/app/services/state.service.ts | 1 + 4 files changed, 14 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html index 9e4cd1513..48028ab47 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -1,7 +1,7 @@