Compare commits

...

13 Commits

Author SHA1 Message Date
wiz
ad6503c7b3 Merge pull request #755 from knorrium/fix_dashboard_memory_leak
Add a potential fix for the memory leak on the Dashboard
2021-09-02 19:12:42 +09:00
softsimon
f8c11c8b6b Merge pull request #759 from knorrium/cypress_831
Update Cypress to v8.3.1
2021-09-02 13:45:12 +04:00
Felipe Knorr Kuhn
ba5421e77b Add some search tests (#758) 2021-09-02 13:42:18 +04:00
Felipe Knorr Kuhn
20fa803cee Add a potential fix for the memory leak on the Dashboard
Fix the broken experience after unsubscribing for network changes

Fix the broken experience after unsubscribing for network changes
2021-09-02 00:47:00 -07:00
Felipe Knorr Kuhn
393fa78a43 Increase waitForSkeletonGone timeout to 15s 2021-09-01 21:09:14 -07:00
Felipe Knorr Kuhn
3f290dae06 Upgrade Cypress to v8.3.1 2021-09-01 21:08:10 -07:00
wiz
24d18b9f2f Merge pull request #757 from mempool/wiz/revert-search-input-lowercase-conversion
Revert "Support uppercase addresses when searching."
2021-09-02 01:37:56 +09:00
wiz
79ef8ca371 Revert "Support uppercase addresses when searching."
This reverts commit fc28b06a0f.
2021-09-02 00:57:43 +09:00
softsimon
ec12f21113 Backend: Bumping Typescript version to 4.4.2 (#748)
* Backend: Bumping Typescript version to 4.4.2

* Replacing any types with instanceOf checks.
2021-08-31 15:09:33 +03:00
Priyansh
2e8ecc7277 Made Price feed update configurable (#751) 2021-08-29 22:30:11 +03:00
softsimon
fc28b06a0f Support uppercase addresses when searching.
fixes #301
2021-08-29 15:58:39 +03:00
softsimon
8fdbfdc04c Use block cache when searching or opening a recent block. (#749)
* Use block cache when searching or opening a recent block.

fixes #715

* Fixed linting errors.
2021-08-29 04:55:46 +03:00
Felipe Knorr Kuhn
bdfcfc96a8 Add script to pull digests from docker images (#705) 2021-08-27 19:04:51 +09:00
27 changed files with 207 additions and 127 deletions

4
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"editor.tabSize": 2,
"typescript.tsdk": "./backend/node_modules/typescript/lib"
}

4
backend/.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,4 @@
{
"editor.tabSize": 2,
"typescript.tsdk": "../backend/node_modules/typescript/lib"
}

View File

@@ -11,7 +11,8 @@
"RECOMMENDED_FEE_PERCENTILE": 50, "RECOMMENDED_FEE_PERCENTILE": 50,
"BLOCK_WEIGHT_UNITS": 4000000, "BLOCK_WEIGHT_UNITS": 4000000,
"INITIAL_BLOCKS_AMOUNT": 8, "INITIAL_BLOCKS_AMOUNT": 8,
"MEMPOOL_BLOCKS_AMOUNT": 8 "MEMPOOL_BLOCKS_AMOUNT": 8,
"PRICE_FEED_UPDATE_INTERVAL": 3600
}, },
"CORE_RPC": { "CORE_RPC": {
"HOST": "127.0.0.1", "HOST": "127.0.0.1",

View File

@@ -26,7 +26,7 @@
"@types/locutus": "^0.0.6", "@types/locutus": "^0.0.6",
"@types/ws": "^7.4.4", "@types/ws": "^7.4.4",
"tslint": "^6.1.0", "tslint": "^6.1.0",
"typescript": "^4.1.5" "typescript": "4.4.2"
} }
}, },
"node_modules/@babel/code-frame": { "node_modules/@babel/code-frame": {
@@ -1473,10 +1473,11 @@
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
}, },
"node_modules/typescript": { "node_modules/typescript": {
"version": "4.2.3", "version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true, "dev": true,
"license": "Apache-2.0",
"bin": { "bin": {
"tsc": "bin/tsc", "tsc": "bin/tsc",
"tsserver": "bin/tsserver" "tsserver": "bin/tsserver"
@@ -2770,9 +2771,9 @@
"integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g=="
}, },
"typescript": { "typescript": {
"version": "4.2.3", "version": "4.4.2",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-4.2.3.tgz", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.4.2.tgz",
"integrity": "sha512-qOcYwxaByStAWrBf4x0fibwZvMRG+r4cQoTjbPtUlrWjBHbmCAww1i448U0GJ+3cNNEtebDteo/cHOR3xJ4wEw==", "integrity": "sha512-gzP+t5W4hdy4c+68bfcv0t400HVJMMd2+H9B7gae1nQlBzCqvrXX+6GL/b3GAgyTH966pzrZ70/fRjwAtZksSQ==",
"dev": true "dev": true
}, },
"unpipe": { "unpipe": {
@@ -2820,7 +2821,8 @@
"ws": { "ws": {
"version": "7.4.6", "version": "7.4.6",
"resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-7.4.6.tgz",
"integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==" "integrity": "sha512-YmhHDO4MzaDLB+M9ym/mDA5z0naX8j7SIlT8f8z+I0VtzsRbekxEutHSme7NPS2qE8StCYQNUnfWdXta/Yu85A==",
"requires": {}
}, },
"yallist": { "yallist": {
"version": "4.0.0", "version": "4.0.0",

View File

@@ -45,6 +45,6 @@
"@types/locutus": "^0.0.6", "@types/locutus": "^0.0.6",
"@types/ws": "^7.4.4", "@types/ws": "^7.4.4",
"tslint": "^6.1.0", "tslint": "^6.1.0",
"typescript": "^4.1.5" "typescript": "4.4.2"
} }
} }

View File

@@ -30,7 +30,7 @@ class BackendInfo {
try { try {
this.gitCommitHash = fs.readFileSync('../.git/refs/heads/master').toString().trim(); this.gitCommitHash = fs.readFileSync('../.git/refs/heads/master').toString().trim();
} catch (e) { } catch (e) {
logger.err('Could not load git commit info: ' + e.message || e); logger.err('Could not load git commit info: ' + (e instanceof Error ? e.message : e));
} }
} }
@@ -39,7 +39,7 @@ class BackendInfo {
const packageJson = fs.readFileSync('package.json').toString(); const packageJson = fs.readFileSync('package.json').toString();
this.version = JSON.parse(packageJson).version; this.version = JSON.parse(packageJson).version;
} catch (e) { } catch (e) {
throw new Error(e); throw new Error(e instanceof Error ? e.message : 'Error');
} }
} }
} }

View File

@@ -162,7 +162,7 @@ class Bisq {
this.buildIndex(); this.buildIndex();
this.calculateStats(); this.calculateStats();
} catch (e) { } catch (e) {
logger.info('loadBisqDumpFile() error.' + e.message || e); logger.info('loadBisqDumpFile() error.' + (e instanceof Error ? e.message : e));
} }
} }

View File

@@ -102,7 +102,7 @@ class Bisq {
logger.debug('Bisq market data updated in ' + time + ' ms'); logger.debug('Bisq market data updated in ' + time + ' ms');
} }
} catch (e) { } catch (e) {
logger.err('loadBisqMarketDataDumpFile() error.' + e.message || e); logger.err('loadBisqMarketDataDumpFile() error.' + (e instanceof Error ? e.message : e));
} }
} }

View File

@@ -93,7 +93,7 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi {
if (e === 'failed to get confirmed status') { if (e === 'failed to get confirmed status') {
e = 'The number of transactions on this address exceeds the Electrum server limit'; e = 'The number of transactions on this address exceeds the Electrum server limit';
} }
throw new Error(e); throw new Error(e instanceof Error ? e.message : 'Error');
} }
} }
@@ -131,7 +131,7 @@ class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi {
if (e === 'failed to get confirmed status') { if (e === 'failed to get confirmed status') {
e = 'The number of transactions on this address exceeds the Electrum server limit'; e = 'The number of transactions on this address exceeds the Electrum server limit';
} }
throw new Error(e); throw new Error(e instanceof Error ? e.message : 'Error');
} }
} }

View File

@@ -89,7 +89,7 @@ class Blocks {
const tx = await transactionUtils.$getTransactionExtended(txIds[i]); const tx = await transactionUtils.$getTransactionExtended(txIds[i]);
transactions.push(tx); transactions.push(tx);
} catch (e) { } catch (e) {
logger.debug('Error fetching block tx: ' + e.message || e); logger.debug('Error fetching block tx: ' + (e instanceof Error ? e.message : e));
if (i === 0) { if (i === 0) {
throw new Error('Failed to fetch Coinbase transaction: ' + txIds[i]); throw new Error('Failed to fetch Coinbase transaction: ' + txIds[i]);
} }

View File

@@ -52,7 +52,7 @@ class DiskCache {
logger.debug('Mempool and blocks data saved to disk cache'); logger.debug('Mempool and blocks data saved to disk cache');
this.isWritingCache = false; this.isWritingCache = false;
} catch (e) { } catch (e) {
logger.warn('Error writing to cache file: ' + e.message || e); logger.warn('Error writing to cache file: ' + (e instanceof Error ? e.message : e));
this.isWritingCache = false; this.isWritingCache = false;
} }
} }

View File

@@ -1,6 +1,7 @@
import logger from '../logger'; import logger from '../logger';
import axios from 'axios'; import axios from 'axios';
import { IConversionRates } from '../mempool.interfaces'; import { IConversionRates } from '../mempool.interfaces';
import config from '../config';
class FiatConversion { class FiatConversion {
private conversionRates: IConversionRates = { private conversionRates: IConversionRates = {
@@ -16,7 +17,7 @@ class FiatConversion {
public startService() { public startService() {
logger.info('Starting currency rates service'); logger.info('Starting currency rates service');
setInterval(this.updateCurrency.bind(this), 1000 * 60); setInterval(this.updateCurrency.bind(this), 1000 * config.MEMPOOL.PRICE_FEED_UPDATE_INTERVAL);
this.updateCurrency(); this.updateCurrency();
} }
@@ -35,7 +36,7 @@ class FiatConversion {
this.ratesChangedCallback(this.conversionRates); this.ratesChangedCallback(this.conversionRates);
} }
} catch (e) { } catch (e) {
logger.err('Error updating fiat conversion rates: ' + e); logger.err('Error updating fiat conversion rates: ' + (e instanceof Error ? e.message : e));
} }
} }
} }

View File

@@ -124,7 +124,7 @@ class Mempool {
} }
newTransactions.push(transaction); newTransactions.push(transaction);
} catch (e) { } catch (e) {
logger.debug('Error finding transaction in mempool: ' + e.message || e); logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
} }
} }

View File

@@ -255,7 +255,7 @@ class Statistics {
connection.release(); connection.release();
return result.insertId; return result.insertId;
} catch (e) { } catch (e) {
logger.err('$create() error' + e.message || e); logger.err('$create() error' + (e instanceof Error ? e.message : e));
} }
} }
@@ -313,7 +313,7 @@ class Statistics {
return this.mapStatisticToOptimizedStatistic([rows[0]])[0]; return this.mapStatisticToOptimizedStatistic([rows[0]])[0];
} }
} catch (e) { } catch (e) {
logger.err('$list2H() error' + e.message || e); logger.err('$list2H() error' + (e instanceof Error ? e.message : e));
} }
} }
@@ -325,7 +325,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list2H() error' + e.message || e); logger.err('$list2H() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }
@@ -338,7 +338,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list24h() error' + e.message || e); logger.err('$list24h() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }
@@ -351,7 +351,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list1W() error' + e); logger.err('$list1W() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }
@@ -364,7 +364,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list1M() error' + e); logger.err('$list1M() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }
@@ -377,7 +377,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list3M() error' + e); logger.err('$list3M() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }
@@ -390,7 +390,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list6M() error' + e); logger.err('$list6M() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }
@@ -403,7 +403,7 @@ class Statistics {
connection.release(); connection.release();
return this.mapStatisticToOptimizedStatistic(rows); return this.mapStatisticToOptimizedStatistic(rows);
} catch (e) { } catch (e) {
logger.err('$list6M() error' + e); logger.err('$list6M() error' + (e instanceof Error ? e.message : e));
return []; return [];
} }
} }

View File

@@ -61,7 +61,7 @@ class WebsocketHandler {
const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true); const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true);
response['tx'] = fullTx; response['tx'] = fullTx;
} catch (e) { } catch (e) {
logger.debug('Error finding transaction: ' + e.message || e); logger.debug('Error finding transaction: ' + (e instanceof Error ? e.message : e));
} }
} }
} else { } else {
@@ -69,7 +69,7 @@ class WebsocketHandler {
const fullTx = await transactionUtils.$getTransactionExtended(client['track-tx'], true); const fullTx = await transactionUtils.$getTransactionExtended(client['track-tx'], true);
response['tx'] = fullTx; response['tx'] = fullTx;
} catch (e) { } catch (e) {
logger.debug('Error finding transaction. ' + e.message || e); logger.debug('Error finding transaction. ' + (e instanceof Error ? e.message : e));
client['track-mempool-tx'] = parsedMessage['track-tx']; client['track-mempool-tx'] = parsedMessage['track-tx'];
} }
} }
@@ -124,7 +124,7 @@ class WebsocketHandler {
client.send(JSON.stringify(response)); client.send(JSON.stringify(response));
} }
} catch (e) { } catch (e) {
logger.debug('Error parsing websocket message: ' + e.message || e); logger.debug('Error parsing websocket message: ' + (e instanceof Error ? e.message : e));
} }
}); });
}); });
@@ -252,7 +252,7 @@ class WebsocketHandler {
const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true); const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true);
response['tx'] = fullTx; response['tx'] = fullTx;
} catch (e) { } catch (e) {
logger.debug('Error finding transaction in mempool: ' + e.message || e); logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
} }
} else { } else {
response['tx'] = tx; response['tx'] = tx;
@@ -272,7 +272,7 @@ class WebsocketHandler {
const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true); const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true);
foundTransactions.push(fullTx); foundTransactions.push(fullTx);
} catch (e) { } catch (e) {
logger.debug('Error finding transaction in mempool: ' + e.message || e); logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
} }
} else { } else {
foundTransactions.push(tx); foundTransactions.push(tx);
@@ -286,7 +286,7 @@ class WebsocketHandler {
const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true); const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true);
foundTransactions.push(fullTx); foundTransactions.push(fullTx);
} catch (e) { } catch (e) {
logger.debug('Error finding transaction in mempool: ' + e.message || e); logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
} }
} else { } else {
foundTransactions.push(tx); foundTransactions.push(tx);
@@ -337,7 +337,7 @@ class WebsocketHandler {
const fullTx = await transactionUtils.$getTransactionExtended(rbfTransaction, true); const fullTx = await transactionUtils.$getTransactionExtended(rbfTransaction, true);
response['rbfTransaction'] = fullTx; response['rbfTransaction'] = fullTx;
} catch (e) { } catch (e) {
logger.debug('Error finding transaction in mempool: ' + e.message || e); logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
} }
} else { } else {
response['rbfTransaction'] = rbfTx; response['rbfTransaction'] = rbfTx;

View File

@@ -14,6 +14,7 @@ interface IConfig {
BLOCK_WEIGHT_UNITS: number; BLOCK_WEIGHT_UNITS: number;
INITIAL_BLOCKS_AMOUNT: number; INITIAL_BLOCKS_AMOUNT: number;
MEMPOOL_BLOCKS_AMOUNT: number; MEMPOOL_BLOCKS_AMOUNT: number;
PRICE_FEED_UPDATE_INTERVAL: number;
}; };
ESPLORA: { ESPLORA: {
REST_API_URL: string; REST_API_URL: string;
@@ -75,6 +76,7 @@ const defaults: IConfig = {
'BLOCK_WEIGHT_UNITS': 4000000, 'BLOCK_WEIGHT_UNITS': 4000000,
'INITIAL_BLOCKS_AMOUNT': 8, 'INITIAL_BLOCKS_AMOUNT': 8,
'MEMPOOL_BLOCKS_AMOUNT': 8, 'MEMPOOL_BLOCKS_AMOUNT': 8,
'PRICE_FEED_UPDATE_INTERVAL': 3600,
}, },
'ESPLORA': { 'ESPLORA': {
'REST_API_URL': 'http://127.0.0.1:3000', 'REST_API_URL': 'http://127.0.0.1:3000',

View File

@@ -20,7 +20,7 @@ export async function checkDbConnection() {
logger.info('Database connection established.'); logger.info('Database connection established.');
connection.release(); connection.release();
} catch (e) { } catch (e) {
logger.err('Could not connect to database: ' + e.message || e); logger.err('Could not connect to database: ' + (e instanceof Error ? e.message : e));
process.exit(1); process.exit(1);
} }
} }

View File

@@ -111,7 +111,7 @@ class Server {
try { try {
await memPool.$updateMemPoolInfo(); await memPool.$updateMemPoolInfo();
} catch (e) { } catch (e) {
const msg = `updateMempoolInfo: ${(e.message || e)}`; const msg = `updateMempoolInfo: ${(e instanceof Error ? e.message : e)}`;
if (config.CORE_RPC_MINFEE.ENABLED) { if (config.CORE_RPC_MINFEE.ENABLED) {
logger.warn(msg); logger.warn(msg);
} else { } else {
@@ -123,7 +123,7 @@ class Server {
setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS);
this.currentBackendRetryInterval = 5; this.currentBackendRetryInterval = 5;
} catch (e) { } catch (e) {
const loggerMsg = `runMainLoop error: ${(e.message || e)}. Retrying in ${this.currentBackendRetryInterval} sec.`; const loggerMsg = `runMainLoop error: ${(e instanceof Error ? e.message : e)}. Retrying in ${this.currentBackendRetryInterval} sec.`;
if (this.currentBackendRetryInterval > 5) { if (this.currentBackendRetryInterval > 5) {
logger.warn(loggerMsg); logger.warn(loggerMsg);
mempool.setOutOfSync(); mempool.setOutOfSync();

View File

@@ -55,7 +55,7 @@ class Routes {
const result = websocketHandler.getInitData(); const result = websocketHandler.getInitData();
res.json(result); res.json(result);
} catch (e) { } catch (e) {
res.status(500).send(e.message); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -74,7 +74,7 @@ class Routes {
const result = mempoolBlocks.getMempoolBlocks(); const result = mempoolBlocks.getMempoolBlocks();
res.json(result); res.json(result);
} catch (e) { } catch (e) {
res.status(500).send(e.message); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -477,10 +477,10 @@ class Routes {
res.json(transaction); res.json(transaction);
} catch (e) { } catch (e) {
let statusCode = 500; let statusCode = 500;
if (e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { if (e instanceof Error && e instanceof Error && e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) {
statusCode = 404; statusCode = 404;
} }
res.status(statusCode).send(e.message || e); res.status(statusCode).send(e instanceof Error ? e.message : e);
} }
} }
@@ -491,10 +491,10 @@ class Routes {
res.send(transaction.hex); res.send(transaction.hex);
} catch (e) { } catch (e) {
let statusCode = 500; let statusCode = 500;
if (e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { if (e instanceof Error && e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) {
statusCode = 404; statusCode = 404;
} }
res.status(statusCode).send(e.message || e); res.status(statusCode).send(e instanceof Error ? e.message : e);
} }
} }
@@ -504,10 +504,10 @@ class Routes {
res.json(transaction.status); res.json(transaction.status);
} catch (e) { } catch (e) {
let statusCode = 500; let statusCode = 500;
if (e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { if (e instanceof Error && e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) {
statusCode = 404; statusCode = 404;
} }
res.status(statusCode).send(e.message || e); res.status(statusCode).send(e instanceof Error ? e.message : e);
} }
} }
@@ -516,7 +516,7 @@ class Routes {
const result = await bitcoinApi.$getBlock(req.params.hash); const result = await bitcoinApi.$getBlock(req.params.hash);
res.json(result); res.json(result);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -526,7 +526,7 @@ class Routes {
res.setHeader('content-type', 'text/plain'); res.setHeader('content-type', 'text/plain');
res.send(blockHeader); res.send(blockHeader);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -563,7 +563,7 @@ class Routes {
res.json(returnBlocks); res.json(returnBlocks);
} catch (e) { } catch (e) {
loadingIndicators.setProgress('blocks', 100); loadingIndicators.setProgress('blocks', 100);
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -582,13 +582,13 @@ class Routes {
transactions.push(transaction); transactions.push(transaction);
loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i + 1) / endIndex * 100); loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i + 1) / endIndex * 100);
} catch (e) { } catch (e) {
logger.debug('getBlockTransactions error: ' + e.message || e); logger.debug('getBlockTransactions error: ' + (e instanceof Error ? e.message : e));
} }
} }
res.json(transactions); res.json(transactions);
} catch (e) { } catch (e) {
loadingIndicators.setProgress('blocktxs-' + req.params.hash, 100); loadingIndicators.setProgress('blocktxs-' + req.params.hash, 100);
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -597,7 +597,7 @@ class Routes {
const blockHash = await bitcoinApi.$getBlockHash(parseInt(req.params.height, 10)); const blockHash = await bitcoinApi.$getBlockHash(parseInt(req.params.height, 10));
res.send(blockHash); res.send(blockHash);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -611,10 +611,10 @@ class Routes {
const addressData = await bitcoinApi.$getAddress(req.params.address); const addressData = await bitcoinApi.$getAddress(req.params.address);
res.json(addressData); res.json(addressData);
} catch (e) { } catch (e) {
if (e.message && e.message.indexOf('exceeds') > 0) { if (e instanceof Error && e.message && e.message.indexOf('exceeds') > 0) {
return res.status(413).send(e.message); return res.status(413).send(e instanceof Error ? e.message : e);
} }
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -628,10 +628,10 @@ class Routes {
const transactions = await bitcoinApi.$getAddressTransactions(req.params.address, req.params.txId); const transactions = await bitcoinApi.$getAddressTransactions(req.params.address, req.params.txId);
res.json(transactions); res.json(transactions);
} catch (e) { } catch (e) {
if (e.message && e.message.indexOf('exceeds') > 0) { if (e instanceof Error && e.message && e.message.indexOf('exceeds') > 0) {
return res.status(413).send(e.message); return res.status(413).send(e instanceof Error ? e.message : e);
} }
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -644,7 +644,7 @@ class Routes {
const blockHash = await bitcoinApi.$getAddressPrefix(req.params.prefix); const blockHash = await bitcoinApi.$getAddressPrefix(req.params.prefix);
res.send(blockHash); res.send(blockHash);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -665,7 +665,7 @@ class Routes {
const rawMempool = await bitcoinApi.$getRawMempool(); const rawMempool = await bitcoinApi.$getRawMempool();
res.send(rawMempool); res.send(rawMempool);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -674,7 +674,7 @@ class Routes {
const result = await bitcoinApi.$getBlockHeightTip(); const result = await bitcoinApi.$getBlockHeightTip();
res.json(result); res.json(result);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -683,7 +683,7 @@ class Routes {
const result = await bitcoinApi.$getTxIdsForBlock(req.params.hash); const result = await bitcoinApi.$getTxIdsForBlock(req.params.hash);
res.json(result); res.json(result);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
@@ -741,7 +741,7 @@ class Routes {
res.json(result); res.json(result);
} catch (e) { } catch (e) {
res.status(500).send(e.message || e); res.status(500).send(e instanceof Error ? e.message : e);
} }
} }
} }

View File

@@ -0,0 +1,18 @@
#!/bin/sh
VERSION=$1
IMAGE=""
if [ -z "${VERSION}" ]; then
echo "no version provided (i.e, v2.2.0), using latest tag"
VERSION="latest"
fi
for package in frontend backend; do
PACKAGE=mempool/"$package"
IMAGE="$PACKAGE":"$VERSION"
HASH=`docker pull $IMAGE > /dev/null && docker inspect $IMAGE | sed -n '/RepoDigests/{n;p;}' | grep -o '[0-9a-f]\{64\}'`
if [ -n "${HASH}" ]; then
echo "$IMAGE"@sha256:"$HASH"
fi
done

View File

@@ -9,6 +9,11 @@ describe('Mainnet', () => {
cy.intercept('/api/tx/*/outspends').as('tx-outspends'); cy.intercept('/api/tx/*/outspends').as('tx-outspends');
cy.intercept('/resources/pools.json').as('pools'); cy.intercept('/resources/pools.json').as('pools');
// Search Auto Complete
cy.intercept('/api/address-prefix/1wiz').as('search-1wiz');
cy.intercept('/api/address-prefix/1wizS').as('search-1wizS');
cy.intercept('/api/address-prefix/1wizSA').as('search-1wizSA');
Cypress.Commands.add('waitForBlockData', () => { Cypress.Commands.add('waitForBlockData', () => {
cy.wait('@tx-outspends'); cy.wait('@tx-outspends');
cy.wait('@pools'); cy.wait('@pools');
@@ -56,6 +61,46 @@ describe('Mainnet', () => {
cy.waitForSkeletonGone(); cy.waitForSkeletonGone();
}); });
describe('search', () => {
it('allows searching for partial Bitcoin addresses', () => {
cy.visit('/');
cy.get('.search-box-container > .form-control').type('1wiz').then(() => {
cy.wait('@search-1wiz');
cy.get('ngb-typeahead-window button.dropdown-item').should('have.length', 10);
});
cy.get('.search-box-container > .form-control').type('S').then(() => {
cy.wait('@search-1wizS');
cy.get('ngb-typeahead-window button.dropdown-item').should('have.length', 5);
});
cy.get('.search-box-container > .form-control').type('A').then(() => {
cy.wait('@search-1wizSA');
cy.get('ngb-typeahead-window button.dropdown-item').should('have.length', 1)
});
cy.get('ngb-typeahead-window button.dropdown-item.active').click().then(() => {
cy.url().should('include', '/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC');
cy.waitForSkeletonGone();
cy.get('.text-center').should('not.have.text', 'Invalid Bitcoin address');
});
});
['BC1PQYQSZQ', 'bc1PqYqSzQ'].forEach((searchTerm) => {
it(`allows searching for partial case insensitive bc1 addresses: ${searchTerm}`, () => {
cy.visit('/');
cy.get('.search-box-container > .form-control').type(searchTerm).then(() => {
cy.get('ngb-typeahead-window button.dropdown-item').should('have.length', 1);
cy.get('ngb-typeahead-window button.dropdown-item.active').click().then(() => {
cy.url().should('include', '/address/bc1pqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqszqgpqyqs3wf0qm');
cy.waitForSkeletonGone();
cy.get('.text-center').should('not.have.text', 'Invalid Bitcoin address');
});
});
});
});
});
describe('blocks navigation', () => { describe('blocks navigation', () => {
describe('keyboard events', () => { describe('keyboard events', () => {

View File

@@ -59,7 +59,7 @@ const codes = {
Cypress.Commands.add('waitForSkeletonGone', () => { Cypress.Commands.add('waitForSkeletonGone', () => {
cy.waitUntil(() => { cy.waitUntil(() => {
return Cypress.$('.skeleton-loader').length === 0; return Cypress.$('.skeleton-loader').length === 0;
}, { verbose: true, description: "waitForSkeletonGone", errorMsg: "skeleton loaders never went away", timeout: 7000, interval: 50}); }, { verbose: true, description: "waitForSkeletonGone", errorMsg: "skeleton loaders never went away", timeout: 15000, interval: 50});
}); });
Cypress.Commands.add( Cypress.Commands.add(

View File

@@ -68,7 +68,7 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"@cypress/schematic": "^1.3.0", "@cypress/schematic": "^1.3.0",
"cypress": "^7.7.0", "cypress": "^8.3.1",
"cypress-fail-on-console-error": "^2.1.0", "cypress-fail-on-console-error": "^2.1.0",
"cypress-wait-until": "^1.7.1", "cypress-wait-until": "^1.7.1",
"mock-socket": "^9.0.3", "mock-socket": "^9.0.3",
@@ -1815,9 +1815,9 @@
} }
}, },
"node_modules/@cypress/request": { "node_modules/@cypress/request": {
"version": "2.88.5", "version": "2.88.6",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.5.tgz", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz",
"integrity": "sha512-TzEC1XMi1hJkywWpRfD2clreTa/Z+lOrXDCxxBTBPEcY5azdPi56A6Xw+O4tWJnaJH3iIE7G5aDXZC6JgRZLcA==", "integrity": "sha512-z0UxBE/+qaESAHY9p9sM2h8Y4XqtsbDCt0/DPOrqA/RZgKi4PkxdpXyK4wCCnSk1xHqWHZZAE+gV6aDAR6+caQ==",
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"aws-sign2": "~0.7.0", "aws-sign2": "~0.7.0",
@@ -1833,13 +1833,12 @@
"isstream": "~0.1.2", "isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1", "json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19", "mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0", "performance-now": "^2.1.0",
"qs": "~6.5.2", "qs": "~6.5.2",
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0", "tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0", "tunnel-agent": "^0.6.0",
"uuid": "^3.3.2" "uuid": "^8.3.2"
}, },
"engines": { "engines": {
"node": ">= 6" "node": ">= 6"
@@ -1867,15 +1866,6 @@
"node": ">=0.8" "node": ">=0.8"
} }
}, },
"node_modules/@cypress/request/node_modules/uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"optional": true,
"bin": {
"uuid": "bin/uuid"
}
},
"node_modules/@cypress/schematic": { "node_modules/@cypress/schematic": {
"version": "1.3.0", "version": "1.3.0",
"resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-1.3.0.tgz", "resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-1.3.0.tgz",
@@ -6069,12 +6059,13 @@
"dev": true "dev": true
}, },
"node_modules/cypress": { "node_modules/cypress": {
"version": "7.7.0", "version": "8.3.1",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-7.7.0.tgz", "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.3.1.tgz",
"integrity": "sha512-uYBYXNoI5ym0UxROwhQXWTi8JbUEjpC6l/bzoGZNxoKGsLrC1SDPgIDJMgLX/MeEdPL0UInXLDUWN/rSyZUCjQ==", "integrity": "sha512-1v6pfx+/5cXhaT5T6QKOvnkawmEHWHLiVzm3MYMoQN1fkX2Ma1C32STd3jBStE9qT5qPSTILjGzypVRxCBi40g==",
"hasInstallScript": true,
"optional": true, "optional": true,
"dependencies": { "dependencies": {
"@cypress/request": "^2.88.5", "@cypress/request": "^2.88.6",
"@cypress/xvfb": "^1.2.4", "@cypress/xvfb": "^1.2.4",
"@types/node": "^14.14.31", "@types/node": "^14.14.31",
"@types/sinonjs__fake-timers": "^6.0.2", "@types/sinonjs__fake-timers": "^6.0.2",
@@ -12222,7 +12213,7 @@
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"devOptional": true, "dev": true,
"engines": { "engines": {
"node": "*" "node": "*"
} }
@@ -17553,7 +17544,7 @@
"version": "8.3.2", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true, "devOptional": true,
"bin": { "bin": {
"uuid": "dist/bin/uuid" "uuid": "dist/bin/uuid"
} }
@@ -21510,9 +21501,9 @@
} }
}, },
"@cypress/request": { "@cypress/request": {
"version": "2.88.5", "version": "2.88.6",
"resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.5.tgz", "resolved": "https://registry.npmjs.org/@cypress/request/-/request-2.88.6.tgz",
"integrity": "sha512-TzEC1XMi1hJkywWpRfD2clreTa/Z+lOrXDCxxBTBPEcY5azdPi56A6Xw+O4tWJnaJH3iIE7G5aDXZC6JgRZLcA==", "integrity": "sha512-z0UxBE/+qaESAHY9p9sM2h8Y4XqtsbDCt0/DPOrqA/RZgKi4PkxdpXyK4wCCnSk1xHqWHZZAE+gV6aDAR6+caQ==",
"optional": true, "optional": true,
"requires": { "requires": {
"aws-sign2": "~0.7.0", "aws-sign2": "~0.7.0",
@@ -21528,13 +21519,12 @@
"isstream": "~0.1.2", "isstream": "~0.1.2",
"json-stringify-safe": "~5.0.1", "json-stringify-safe": "~5.0.1",
"mime-types": "~2.1.19", "mime-types": "~2.1.19",
"oauth-sign": "~0.9.0",
"performance-now": "^2.1.0", "performance-now": "^2.1.0",
"qs": "~6.5.2", "qs": "~6.5.2",
"safe-buffer": "^5.1.2", "safe-buffer": "^5.1.2",
"tough-cookie": "~2.5.0", "tough-cookie": "~2.5.0",
"tunnel-agent": "^0.6.0", "tunnel-agent": "^0.6.0",
"uuid": "^3.3.2" "uuid": "^8.3.2"
}, },
"dependencies": { "dependencies": {
"qs": { "qs": {
@@ -21552,12 +21542,6 @@
"psl": "^1.1.28", "psl": "^1.1.28",
"punycode": "^2.1.1" "punycode": "^2.1.1"
} }
},
"uuid": {
"version": "3.4.0",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz",
"integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==",
"optional": true
} }
} }
}, },
@@ -25229,12 +25213,12 @@
"dev": true "dev": true
}, },
"cypress": { "cypress": {
"version": "7.7.0", "version": "8.3.1",
"resolved": "https://registry.npmjs.org/cypress/-/cypress-7.7.0.tgz", "resolved": "https://registry.npmjs.org/cypress/-/cypress-8.3.1.tgz",
"integrity": "sha512-uYBYXNoI5ym0UxROwhQXWTi8JbUEjpC6l/bzoGZNxoKGsLrC1SDPgIDJMgLX/MeEdPL0UInXLDUWN/rSyZUCjQ==", "integrity": "sha512-1v6pfx+/5cXhaT5T6QKOvnkawmEHWHLiVzm3MYMoQN1fkX2Ma1C32STd3jBStE9qT5qPSTILjGzypVRxCBi40g==",
"optional": true, "optional": true,
"requires": { "requires": {
"@cypress/request": "^2.88.5", "@cypress/request": "^2.88.6",
"@cypress/xvfb": "^1.2.4", "@cypress/xvfb": "^1.2.4",
"@types/node": "^14.14.31", "@types/node": "^14.14.31",
"@types/sinonjs__fake-timers": "^6.0.2", "@types/sinonjs__fake-timers": "^6.0.2",
@@ -30373,7 +30357,7 @@
"version": "0.9.0", "version": "0.9.0",
"resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz",
"integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==",
"devOptional": true "dev": true
}, },
"object-assign": { "object-assign": {
"version": "4.1.1", "version": "4.1.1",
@@ -34803,7 +34787,7 @@
"version": "8.3.2", "version": "8.3.2",
"resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
"integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
"dev": true "devOptional": true
}, },
"validate-npm-package-name": { "validate-npm-package-name": {
"version": "3.0.0", "version": "3.0.0",

View File

@@ -112,7 +112,7 @@
}, },
"optionalDependencies": { "optionalDependencies": {
"@cypress/schematic": "^1.3.0", "@cypress/schematic": "^1.3.0",
"cypress": "^7.7.0", "cypress": "^8.3.1",
"cypress-fail-on-console-error": "^2.1.0", "cypress-fail-on-console-error": "^2.1.0",
"cypress-wait-until": "^1.7.1", "cypress-wait-until": "^1.7.1",
"mock-socket": "^9.0.3", "mock-socket": "^9.0.3",

View File

@@ -1,6 +1,6 @@
import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core'; import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy } from '@angular/core';
import { StateService } from '../../services/state.service'; import { StateService } from '../../services/state.service';
import { Observable } from 'rxjs'; import { Observable, Subscription } from 'rxjs';
@Component({ @Component({
selector: 'app-amount', selector: 'app-amount',
@@ -8,11 +8,13 @@ import { Observable } from 'rxjs';
styleUrls: ['./amount.component.scss'], styleUrls: ['./amount.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush, changeDetection: ChangeDetectionStrategy.OnPush,
}) })
export class AmountComponent implements OnInit { export class AmountComponent implements OnInit, OnDestroy {
conversions$: Observable<any>; conversions$: Observable<any>;
viewFiat$: Observable<boolean>; viewFiat$: Observable<boolean>;
network = ''; network = '';
stateSubscription: Subscription;
@Input() satoshis: number; @Input() satoshis: number;
@Input() digitsInfo = '1.8-8'; @Input() digitsInfo = '1.8-8';
@Input() noFiat = false; @Input() noFiat = false;
@@ -24,7 +26,13 @@ export class AmountComponent implements OnInit {
ngOnInit() { ngOnInit() {
this.viewFiat$ = this.stateService.viewFiat$.asObservable(); this.viewFiat$ = this.stateService.viewFiat$.asObservable();
this.conversions$ = this.stateService.conversions$.asObservable(); this.conversions$ = this.stateService.conversions$.asObservable();
this.stateService.networkChanged$.subscribe((network) => this.network = network); this.stateSubscription = this.stateService.networkChanged$.subscribe((network) => this.network = network);
}
ngOnDestroy() {
if (this.stateSubscription) {
this.stateSubscription.unsubscribe();
}
} }
} }

View File

@@ -65,8 +65,20 @@ export class BlockComponent implements OnInit, OnDestroy {
map((indicators) => indicators['blocktxs-' + this.blockHash] !== undefined ? indicators['blocktxs-' + this.blockHash] : 0) map((indicators) => indicators['blocktxs-' + this.blockHash] !== undefined ? indicators['blocktxs-' + this.blockHash] : 0)
); );
this.subscription = this.route.paramMap this.blocksSubscription = this.stateService.blocks$
.pipe( .subscribe(([block]) => {
this.latestBlock = block;
this.latestBlocks.unshift(block);
this.latestBlocks = this.latestBlocks.slice(0, this.stateService.env.KEEP_BLOCKS_AMOUNT);
this.setNextAndPreviousBlockLink();
if (block.id === this.blockHash) {
this.block = block;
this.fees = block.reward / 100000000 - this.blockSubsidy;
}
});
this.subscription = this.route.paramMap.pipe(
switchMap((params: ParamMap) => { switchMap((params: ParamMap) => {
const blockHash: string = params.get('id') || ''; const blockHash: string = params.get('id') || '';
this.block = undefined; this.block = undefined;
@@ -94,7 +106,12 @@ export class BlockComponent implements OnInit, OnDestroy {
} else { } else {
this.isLoadingBlock = true; this.isLoadingBlock = true;
let blockInCache: Block;
if (isBlockHeight) { if (isBlockHeight) {
blockInCache = this.latestBlocks.find((block) => block.height === parseInt(blockHash, 10));
if (blockInCache) {
return of(blockInCache);
}
return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10)) return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10))
.pipe( .pipe(
switchMap((hash) => { switchMap((hash) => {
@@ -107,12 +124,11 @@ export class BlockComponent implements OnInit, OnDestroy {
); );
} }
this.stateService.blocks$.subscribe(([block]) => { blockInCache = this.latestBlocks.find((block) => block.id === this.blockHash);
if (block.id === blockHash) { if (blockInCache) {
this.block = block; return of(blockInCache);
} }
});
return this.electrsApiService.getBlock$(blockHash); return this.electrsApiService.getBlock$(blockHash);
} }
}), }),
@@ -159,14 +175,6 @@ export class BlockComponent implements OnInit, OnDestroy {
this.isLoadingBlock = false; this.isLoadingBlock = false;
}); });
this.blocksSubscription = this.stateService.blocks$
.subscribe(([block]) => {
this.latestBlock = block;
this.latestBlocks.unshift(block);
this.latestBlocks = this.latestBlocks.slice(0, this.stateService.env.KEEP_BLOCKS_AMOUNT);
this.setNextAndPreviousBlockLink();
});
this.networkChangedSubscription = this.stateService.networkChanged$ this.networkChangedSubscription = this.stateService.networkChanged$
.subscribe((network) => this.network = network); .subscribe((network) => this.network = network);
@@ -269,12 +277,14 @@ export class BlockComponent implements OnInit, OnDestroy {
return; return;
} }
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight - 2); const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight - 2);
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/', block ? block.id : this.block.previousblockhash], { state: { data: { block, blockHeight: this.nextBlockHeight - 2 } } }); this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/',
block ? block.id : this.block.previousblockhash], { state: { data: { block, blockHeight: this.nextBlockHeight - 2 } } });
} }
navigateToNextBlock() { navigateToNextBlock() {
const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight); const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight);
this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/', block ? block.id : this.nextBlockHeight], { state: { data: { block, blockHeight: this.nextBlockHeight } } }); this.router.navigate([(this.network && this.stateService.env.BASE_MODULE === 'mempool' ? '/' + this.network : '') + '/block/',
block ? block.id : this.nextBlockHeight], { state: { data: { block, blockHeight: this.nextBlockHeight } } });
} }
setNextAndPreviousBlockLink(){ setNextAndPreviousBlockLink(){

View File

@@ -12,6 +12,7 @@
"arrow-parens": false, "arrow-parens": false,
"arrow-return-shorthand": true, "arrow-return-shorthand": true,
"curly": true, "curly": true,
"no-bitwise": false,
"deprecation": { "deprecation": {
"severity": "warning" "severity": "warning"
}, },