From bca35600ff2a18dc9f0c5a08093cab0349818627 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 6602bddb2b8e040d313f5bd7a19433e315a1c993 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 d7333ec8584a31a23dabac17b5464042ca473868 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 f95c16a78e83c25a7bb55b2ea07e49ca6cb10f06 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 178da3df26b514ee0523aa6a2d93c561f73532f9 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 3f8fefcb0e310642db4a13d5f1939feb200ea24b 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 804485a526adbb09d5fd3b4bef284ef1be8dd690 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 de434bb398827a306af6bb65f7e75bd2f88d5b5c 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 184ca3c66220e1f82240df5f4bc81af398b926ac 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 6333f3aa4702d7aae8c58ce47f1c1c4a8df7a6b4 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 b00e0b6a735ecda0f2d87f58f7369355f3aed96e 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 720c2b88078adb0acade9c1f24e315ecbbb6ca8a 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 4dec152df018ae795c3b176a19346c06db2c4c7c 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 7ab05d815dc381c1128a9f8cc93e7b45be14575f 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 81ec54fcb3eca267f4b6c05eeb676c8d16724e30 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 369db7a63ca53925329570e074057932f8ea92dd 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 07f16165ff9a635c7d4944df6d575747af070e8e 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 c81509d762bf2c43baae722e2da254394d7e8839 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 31ea2e1d4bef21d4aa037599e4a81b80c0444ffe 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 ea420773204d51981dcfb1489f2880f75bc32813 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 264c02eca1f38b97a3b3b86b639cc207aacff8dc 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 ad4c7d7c0b5c53b75e6fb921aff0c9c93faeb5bb 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 714208a3669000c4f20777f6d0118ed8b4f35a83 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 349ba613ddc40d8d87f1907797e9bc2fbbc9c030 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 aeb896e200281af1bdb2190c9dd64612eac583a0 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 038f9659bb9b55c5634729f5e6aef1a8a5160256 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 8ffe2f3156d61c577325c39ddd68219e70166cb2 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 5711c939d75b18524b37b8c7ed1ef18b7ef07d6e 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 ac73de31b5f099006940b71dd4f17cabb8c8f221 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 9fa1eebc02d2aac516bee0141abde45e0071c814 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 ce00814bbf5b167fdd041375e131812805db3a69 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 9d4b58604b43706bcf5a369ec1231ad7a95af724 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 8b1dff6d15697d21b3853c3c3c3793a73d9127b7 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 37dd95a4a01094e0947261cc55026d81147563f5 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 9e1de656c1d05a288a0d66a43f491b107ae63fdf 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 689319437a24c1499b389b07321497d176c3c805 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 386037d1db872fecca10b00ed46ea4c29fbc3094 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 fd30bff9c6e4f6b707d58e5dcea5039de8ed3126 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 57ac1486a009ef2bc599aa7ae57688d6752523bb 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 @@