From 57c3861ca625f0094caaec3230960e5a52d107ed Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 7 Aug 2023 10:52:40 +0900 Subject: [PATCH 1/7] Support multi address websocket subscriptions --- backend/src/api/websocket-handler.ts | 71 +++++++++++++++++++ .../src/app/interfaces/websocket.interface.ts | 1 + 2 files changed, 72 insertions(+) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 937d4a7c5..c0493d6c1 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -24,6 +24,12 @@ import { ApiPrice } from '../repositories/PricesRepository'; import accelerationApi from './services/acceleration'; import mempool from './mempool'; +interface AddressTransactions { + mempool: MempoolTransactionExtended[], + confirmed: MempoolTransactionExtended[], + removed: string[], +} + // valid 'want' subscriptions const wantable = [ 'blocks', @@ -213,6 +219,32 @@ class WebsocketHandler { } } + if (parsedMessage && parsedMessage['track-addresses'] && Array.isArray(parsedMessage['track-addresses'])) { + const addressMap: { [address: string]: string } = {}; + for (const address of parsedMessage['track-addresses']) { + if (/^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64})$/.test(address)) { + let matchedAddress = address; + if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}$/.test(address)) { + matchedAddress = matchedAddress.toLowerCase(); + } + if (/^04[a-fA-F0-9]{128}$/.test(address)) { + addressMap[address] = '41' + matchedAddress + 'ac'; + } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(address)) { + addressMap[address] = '21' + matchedAddress + 'ac'; + } else { + addressMap[address] = matchedAddress; + } + } else { + // skip invalid address formats + } + } + if (Object.keys(addressMap).length > 0) { + client['track-addresses'] = addressMap; + } else { + client['track-addresses'] = null; + } + } + if (parsedMessage && parsedMessage['track-asset']) { if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-asset'])) { client['track-asset'] = parsedMessage['track-asset']; @@ -544,6 +576,27 @@ class WebsocketHandler { } } + if (client['track-addresses']) { + const addressMap: { [address: string]: AddressTransactions } = {}; + for (const [address, key] of Object.entries(client['track-addresses'] || {})) { + const foundTransactions = Array.from(addressCache[key as string]?.values() || []); + // txs may be missing prevouts in non-esplora backends + // so fetch the full transactions now + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions; + if (fullTransactions?.length) { + addressMap[address] = { + mempool: fullTransactions, + confirmed: [], + removed: [], + }; + } + } + + if (Object.keys(addressMap).length > 0) { + response['multi-address-transactions'] = JSON.stringify(addressMap); + } + } + if (client['track-asset']) { const foundTransactions: TransactionExtended[] = []; @@ -843,6 +896,24 @@ class WebsocketHandler { } } + if (client['track-addresses']) { + const addressMap: { [address: string]: AddressTransactions } = {}; + for (const [address, key] of Object.entries(client['track-addresses'] || {})) { + const fullTransactions = Array.from(addressCache[key as string]?.values() || []); + if (fullTransactions?.length) { + addressMap[address] = { + mempool: [], + confirmed: fullTransactions, + removed: [], + }; + } + } + + if (Object.keys(addressMap).length > 0) { + response['multi-address-transactions'] = JSON.stringify(addressMap); + } + } + if (client['track-asset']) { const foundTransactions: TransactionExtended[] = []; diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index 20bc42bde..fb488e705 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -27,6 +27,7 @@ export interface WebsocketResponse { fees?: Recommendedfees; 'track-tx'?: string; 'track-address'?: string; + 'track-addresses'?: string[]; 'track-asset'?: string; 'track-mempool-block'?: number; 'track-rbf'?: string; From 8642956dc2bd9583374b6e57092ae0576224f0f0 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 7 Aug 2023 14:13:41 +0900 Subject: [PATCH 2/7] Add track-scriptpubkeys websocket subscription --- backend/src/api/websocket-handler.ts | 53 +++++++++++++++++++ .../src/app/interfaces/websocket.interface.ts | 1 + 2 files changed, 54 insertions(+) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index c0493d6c1..e20e41014 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -245,6 +245,20 @@ class WebsocketHandler { } } + if (parsedMessage && parsedMessage['track-scriptpubkeys'] && Array.isArray(parsedMessage['track-scriptpubkeys'])) { + const spks: string[] = []; + for (const spk of parsedMessage['track-scriptpubkeys']) { + if (/^[a-fA-F0-9]+$/.test(spk)) { + spks.push(spk); + } + } + if (spks.length) { + client['track-scriptpubkeys'] = spks; + } else { + client['track-scriptpubkeys'] = null; + } + } + if (parsedMessage && parsedMessage['track-asset']) { if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-asset'])) { client['track-asset'] = parsedMessage['track-asset']; @@ -597,6 +611,27 @@ class WebsocketHandler { } } + if (client['track-scriptpubkeys']) { + const spkMap: { [spk: string]: AddressTransactions } = {}; + for (const spk of client['track-scriptpubkeys'] || []) { + const foundTransactions = Array.from(addressCache[spk as string]?.values() || []); + // txs may be missing prevouts in non-esplora backends + // so fetch the full transactions now + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions; + if (fullTransactions?.length) { + spkMap[spk] = { + mempool: fullTransactions, + confirmed: [], + removed: [], + }; + } + } + + if (Object.keys(spkMap).length > 0) { + response['multi-scriptpubkey-transactions'] = JSON.stringify(spkMap); + } + } + if (client['track-asset']) { const foundTransactions: TransactionExtended[] = []; @@ -914,6 +949,24 @@ class WebsocketHandler { } } + if (client['track-scriptpubkeys']) { + const spkMap: { [spk: string]: AddressTransactions } = {}; + for (const spk of client['track-scriptpubkeys'] || []) { + const fullTransactions = Array.from(addressCache[spk as string]?.values() || []); + if (fullTransactions?.length) { + spkMap[spk] = { + mempool: [], + confirmed: fullTransactions, + removed: [], + }; + } + } + + if (Object.keys(spkMap).length > 0) { + response['multi-scriptpubkey-transactions'] = JSON.stringify(spkMap); + } + } + if (client['track-asset']) { const foundTransactions: TransactionExtended[] = []; diff --git a/frontend/src/app/interfaces/websocket.interface.ts b/frontend/src/app/interfaces/websocket.interface.ts index fb488e705..35bcbe9cc 100644 --- a/frontend/src/app/interfaces/websocket.interface.ts +++ b/frontend/src/app/interfaces/websocket.interface.ts @@ -28,6 +28,7 @@ export interface WebsocketResponse { 'track-tx'?: string; 'track-address'?: string; 'track-addresses'?: string[]; + 'track-scriptpubkeys'?: string[]; 'track-asset'?: string; 'track-mempool-block'?: number; 'track-rbf'?: string; From ccd9642a01554ec2d5d513b1a7a269a76c16c370 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 10 Aug 2023 18:42:10 +0900 Subject: [PATCH 3/7] Deduplicate address validation code --- backend/src/api/websocket-handler.ts | 55 ++++++++++++++-------------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index e20e41014..f48edf11e 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -201,19 +201,9 @@ class WebsocketHandler { } if (parsedMessage && parsedMessage['track-address']) { - if (/^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64})$/ - .test(parsedMessage['track-address'])) { - let matchedAddress = parsedMessage['track-address']; - if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}$/.test(parsedMessage['track-address'])) { - matchedAddress = matchedAddress.toLowerCase(); - } - if (/^04[a-fA-F0-9]{128}$/.test(parsedMessage['track-address'])) { - client['track-address'] = '41' + matchedAddress + 'ac'; - } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(parsedMessage['track-address'])) { - client['track-address'] = '21' + matchedAddress + 'ac'; - } else { - client['track-address'] = matchedAddress; - } + const validAddress = this.testAddress(parsedMessage['track-address']); + if (validAddress) { + client['track-address'] = validAddress; } else { client['track-address'] = null; } @@ -222,20 +212,9 @@ class WebsocketHandler { if (parsedMessage && parsedMessage['track-addresses'] && Array.isArray(parsedMessage['track-addresses'])) { const addressMap: { [address: string]: string } = {}; for (const address of parsedMessage['track-addresses']) { - if (/^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64})$/.test(address)) { - let matchedAddress = address; - if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}$/.test(address)) { - matchedAddress = matchedAddress.toLowerCase(); - } - if (/^04[a-fA-F0-9]{128}$/.test(address)) { - addressMap[address] = '41' + matchedAddress + 'ac'; - } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(address)) { - addressMap[address] = '21' + matchedAddress + 'ac'; - } else { - addressMap[address] = matchedAddress; - } - } else { - // skip invalid address formats + const validAddress = this.testAddress(address); + if (validAddress) { + addressMap[address] = validAddress; } } if (Object.keys(addressMap).length > 0) { @@ -1036,6 +1015,28 @@ class WebsocketHandler { + '}'; } + // checks if an address conforms to a valid format + // returns the canonical form: + // - lowercase for bech32(m) + // - lowercase scriptpubkey for P2PK + // or false if invalid + private testAddress(address): string | false { + if (/^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64})$/.test(address)) { + if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(address)) { + address = address.toLowerCase(); + } + if (/^04[a-fA-F0-9]{128}$/.test(address)) { + return '41' + address + 'ac'; + } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(address)) { + return '21' + address + 'ac'; + } else { + return address; + } + } else { + return false; + } + } + private makeAddressCache(transactions: MempoolTransactionExtended[]): { [address: string]: Set } { const addressCache: { [address: string]: Set } = {}; for (const tx of transactions) { From 77a526b91cf13aad8cb17a48bd4be44669be13dc Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 10 Aug 2023 18:45:17 +0900 Subject: [PATCH 4/7] Normalize scriptpubkeys to lowercase --- backend/src/api/websocket-handler.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index f48edf11e..3391cdc0b 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -228,7 +228,7 @@ class WebsocketHandler { const spks: string[] = []; for (const spk of parsedMessage['track-scriptpubkeys']) { if (/^[a-fA-F0-9]+$/.test(spk)) { - spks.push(spk); + spks.push(spk.toLowerCase()); } } if (spks.length) { From 8f7895cb2ee72183c5f902167f6269672402b6fb Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 25 Aug 2023 14:39:43 +0900 Subject: [PATCH 5/7] Track dropped txs in multi-address subscription --- backend/src/api/websocket-handler.ts | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 3391cdc0b..51144b365 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -27,7 +27,7 @@ import mempool from './mempool'; interface AddressTransactions { mempool: MempoolTransactionExtended[], confirmed: MempoolTransactionExtended[], - removed: string[], + removed: MempoolTransactionExtended[], } // valid 'want' subscriptions @@ -572,15 +572,16 @@ class WebsocketHandler { if (client['track-addresses']) { const addressMap: { [address: string]: AddressTransactions } = {}; for (const [address, key] of Object.entries(client['track-addresses'] || {})) { - const foundTransactions = Array.from(addressCache[key as string]?.values() || []); + const newTransactions = Array.from(addressCache[key as string]?.values() || []); + const removedTransactions = Array.from(removedAddressCache[key as string]?.values() || []); // txs may be missing prevouts in non-esplora backends // so fetch the full transactions now - const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions; + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(newTransactions) : newTransactions; if (fullTransactions?.length) { addressMap[address] = { mempool: fullTransactions, confirmed: [], - removed: [], + removed: removedTransactions, }; } } @@ -593,15 +594,16 @@ class WebsocketHandler { if (client['track-scriptpubkeys']) { const spkMap: { [spk: string]: AddressTransactions } = {}; for (const spk of client['track-scriptpubkeys'] || []) { - const foundTransactions = Array.from(addressCache[spk as string]?.values() || []); + const newTransactions = Array.from(addressCache[spk as string]?.values() || []); + const removedTransactions = Array.from(removedAddressCache[spk as string]?.values() || []); // txs may be missing prevouts in non-esplora backends // so fetch the full transactions now - const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(foundTransactions) : foundTransactions; + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(newTransactions) : newTransactions; if (fullTransactions?.length) { spkMap[spk] = { mempool: fullTransactions, confirmed: [], - removed: [], + removed: removedTransactions, }; } } From aa0948a15407a9dbf6ea2c47ca1d3b4d7368d1a1 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 12 Jan 2024 22:10:10 +0000 Subject: [PATCH 6/7] Add multi-address-tracking limit config --- backend/mempool-config.sample.json | 3 ++- backend/src/__fixtures__/mempool-config.template.json | 3 ++- backend/src/__tests__/config.test.ts | 1 + backend/src/api/websocket-handler.ts | 10 ++++++++-- backend/src/config.ts | 2 ++ docker/backend/mempool-config.json | 1 + docker/backend/start.sh | 2 ++ 7 files changed, 18 insertions(+), 4 deletions(-) diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 76b27d630..3cb79b909 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -33,7 +33,8 @@ "DISK_CACHE_BLOCK_INTERVAL": 6, "MAX_PUSH_TX_SIZE_WEIGHT": 4000000, "ALLOW_UNREACHABLE": true, - "PRICE_UPDATES_PER_HOUR": 1 + "PRICE_UPDATES_PER_HOUR": 1, + "MAX_TRACKED_ADDRESSES": 100 }, "CORE_RPC": { "HOST": "127.0.0.1", diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json index 0c30651ce..9445fc25d 100644 --- a/backend/src/__fixtures__/mempool-config.template.json +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -34,7 +34,8 @@ "DISK_CACHE_BLOCK_INTERVAL": 999, "MAX_PUSH_TX_SIZE_WEIGHT": 4000000, "ALLOW_UNREACHABLE": true, - "PRICE_UPDATES_PER_HOUR": 1 + "PRICE_UPDATES_PER_HOUR": 1, + "MAX_TRACKED_ADDRESSES": 1 }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts index 2991162e9..97c218370 100644 --- a/backend/src/__tests__/config.test.ts +++ b/backend/src/__tests__/config.test.ts @@ -48,6 +48,7 @@ describe('Mempool Backend Config', () => { MAX_PUSH_TX_SIZE_WEIGHT: 400000, ALLOW_UNREACHABLE: true, PRICE_UPDATES_PER_HOUR: 1, + MAX_TRACKED_ADDRESSES: 1, }); expect(config.ELECTRUM).toStrictEqual({ HOST: '127.0.0.1', PORT: 3306, TLS_ENABLED: true }); diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 51144b365..739e0efb7 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -217,7 +217,10 @@ class WebsocketHandler { addressMap[address] = validAddress; } } - if (Object.keys(addressMap).length > 0) { + if (Object.keys(addressMap).length > config.MEMPOOL.MAX_TRACKED_ADDRESSES) { + response['track-addresses-error'] = `too many addresses requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} addresses`; + client['track-addresses'] = null; + } else if (Object.keys(addressMap).length > 0) { client['track-addresses'] = addressMap; } else { client['track-addresses'] = null; @@ -231,7 +234,10 @@ class WebsocketHandler { spks.push(spk.toLowerCase()); } } - if (spks.length) { + if (spks.length > config.MEMPOOL.MAX_TRACKED_ADDRESSES) { + response['track-scriptpubkeys-error'] = `too many scriptpubkeys requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} scriptpubkeys`; + client['track-scriptpubkeys'] = null; + } else if (spks.length) { client['track-scriptpubkeys'] = spks; } else { client['track-scriptpubkeys'] = null; diff --git a/backend/src/config.ts b/backend/src/config.ts index 4115149e6..df1022a67 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -39,6 +39,7 @@ interface IConfig { MAX_PUSH_TX_SIZE_WEIGHT: number; ALLOW_UNREACHABLE: boolean; PRICE_UPDATES_PER_HOUR: number; + MAX_TRACKED_ADDRESSES: number; }; ESPLORA: { REST_API_URL: string; @@ -193,6 +194,7 @@ const defaults: IConfig = { 'MAX_PUSH_TX_SIZE_WEIGHT': 400000, 'ALLOW_UNREACHABLE': true, 'PRICE_UPDATES_PER_HOUR': 1, + 'MAX_TRACKED_ADDRESSES': 1, }, 'ESPLORA': { 'REST_API_URL': 'http://127.0.0.1:3000', diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json index e73fa1929..c68e37baa 100644 --- a/docker/backend/mempool-config.json +++ b/docker/backend/mempool-config.json @@ -35,6 +35,7 @@ "POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__", "POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__", "PRICE_UPDATES_PER_HOUR": __MEMPOOL_PRICE_UPDATES_PER_HOUR__ + "MAX_TRACKED_ADDRESSES": __MEMPOOL_MAX_TRACKED_ADDRESSES__ }, "CORE_RPC": { "HOST": "__CORE_RPC_HOST__", diff --git a/docker/backend/start.sh b/docker/backend/start.sh index 232cf7284..d73ea83fb 100755 --- a/docker/backend/start.sh +++ b/docker/backend/start.sh @@ -36,6 +36,7 @@ __MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__=${MEMPOOL_DISK_CACHE_BLOCK_INTERVAL:=6} __MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__=${MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT:=4000000} __MEMPOOL_ALLOW_UNREACHABLE__=${MEMPOOL_ALLOW_UNREACHABLE:=true} __MEMPOOL_PRICE_UPDATES_PER_HOUR__=${MEMPOOL_PRICE_UPDATES_PER_HOUR:=1} +__MEMPOOL_MAX_TRACKED_ADDRESSES__=${MEMPOOL_MAX_TRACKED_ADDRESSES:=1} # CORE_RPC __CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1} @@ -188,6 +189,7 @@ sed -i "s!__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__!${__MEMPOOL_DISK_CACHE_BLOCK_INT sed -i "s!__MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__!${__MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__}!g" mempool-config.json sed -i "s!__MEMPOOL_ALLOW_UNREACHABLE__!${__MEMPOOL_ALLOW_UNREACHABLE__}!g" mempool-config.json sed -i "s!__MEMPOOL_PRICE_UPDATES_PER_HOUR__!${__MEMPOOL_PRICE_UPDATES_PER_HOUR__}!g" mempool-config.json +sed -i "s!__MEMPOOL_MAX_TRACKED_ADDRESSES__!${__MEMPOOL_MAX_TRACKED_ADDRESSES__}!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 From 0cddfcfa64829e9bf9fb39568bd15dad6cb6543c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 23 Jan 2024 14:04:15 +0000 Subject: [PATCH 7/7] Fix missing quotes on multi-address-tracking error msg --- backend/src/api/websocket-handler.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 739e0efb7..1ca8d37d1 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -218,7 +218,7 @@ class WebsocketHandler { } } if (Object.keys(addressMap).length > config.MEMPOOL.MAX_TRACKED_ADDRESSES) { - response['track-addresses-error'] = `too many addresses requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} addresses`; + response['track-addresses-error'] = `"too many addresses requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} addresses"`; client['track-addresses'] = null; } else if (Object.keys(addressMap).length > 0) { client['track-addresses'] = addressMap; @@ -235,7 +235,7 @@ class WebsocketHandler { } } if (spks.length > config.MEMPOOL.MAX_TRACKED_ADDRESSES) { - response['track-scriptpubkeys-error'] = `too many scriptpubkeys requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} scriptpubkeys`; + response['track-scriptpubkeys-error'] = `"too many scriptpubkeys requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} scriptpubkeys"`; client['track-scriptpubkeys'] = null; } else if (spks.length) { client['track-scriptpubkeys'] = spks;