diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts index 53c731e1f..71269da31 100644 --- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts +++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts @@ -2,7 +2,7 @@ import { IEsploraApi } from './esplora-api.interface'; export interface AbstractBitcoinApi { $getRawMempool(): Promise; - $getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean): Promise; + $getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean, lazyPrevouts?: boolean): Promise; $getBlockHeightTip(): Promise; $getTxIdsForBlock(hash: string): Promise; $getBlockHash(height: number): Promise; diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index e52aaffaf..41671ede1 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -31,7 +31,8 @@ class BitcoinApi implements AbstractBitcoinApi { }; } - $getRawTransaction(txId: string, skipConversion = false, addPrevout = false): Promise { + + $getRawTransaction(txId: string, skipConversion = false, addPrevout = false, lazyPrevouts = false): Promise { // If the transaction is in the mempool we already converted and fetched the fee. Only prevouts are missing const txInMempool = mempool.getMempool()[txId]; if (txInMempool && addPrevout) { @@ -46,7 +47,7 @@ class BitcoinApi implements AbstractBitcoinApi { }); return transaction; } - return this.$convertTransaction(transaction, addPrevout); + return this.$convertTransaction(transaction, addPrevout, lazyPrevouts); }) .catch((e: Error) => { if (e.message.startsWith('The genesis block coinbase')) { @@ -126,7 +127,7 @@ class BitcoinApi implements AbstractBitcoinApi { const outSpends: IEsploraApi.Outspend[] = []; const tx = await this.$getRawTransaction(txId, true, false); for (let i = 0; i < tx.vout.length; i++) { - if (tx.status && tx.status.block_height == 0) { + if (tx.status && tx.status.block_height === 0) { outSpends.push({ spent: false }); @@ -145,7 +146,7 @@ class BitcoinApi implements AbstractBitcoinApi { return this.bitcoindClient.getNetworkHashPs(120, blockHeight); } - protected async $convertTransaction(transaction: IBitcoinApi.Transaction, addPrevout: boolean): Promise { + protected async $convertTransaction(transaction: IBitcoinApi.Transaction, addPrevout: boolean, lazyPrevouts = false): Promise { let esploraTransaction: IEsploraApi.Transaction = { txid: transaction.txid, version: transaction.version, @@ -192,7 +193,7 @@ class BitcoinApi implements AbstractBitcoinApi { } if (addPrevout) { - esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction); + esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, false, lazyPrevouts); } else if (!transaction.confirmations) { esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction); } @@ -268,20 +269,30 @@ class BitcoinApi implements AbstractBitcoinApi { return this.bitcoindClient.getRawMemPool(true); } - private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction): Promise { + + private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction, addPrevout: boolean, lazyPrevouts: boolean): Promise { if (transaction.vin[0].is_coinbase) { transaction.fee = 0; return transaction; } let totalIn = 0; - for (const vin of transaction.vin) { - const innerTx = await this.$getRawTransaction(vin.txid, false, false); - vin.prevout = innerTx.vout[vin.vout]; - this.addInnerScriptsToVin(vin); - totalIn += innerTx.vout[vin.vout].value; + + for (let i = 0; i < transaction.vin.length; i++) { + if (lazyPrevouts && i > 12) { + transaction.vin[i].lazy = true; + continue; + } + const innerTx = await this.$getRawTransaction(transaction.vin[i].txid, false, false); + transaction.vin[i].prevout = innerTx.vout[transaction.vin[i].vout]; + this.addInnerScriptsToVin(transaction.vin[i]); + totalIn += innerTx.vout[transaction.vin[i].vout].value; + } + if (lazyPrevouts && transaction.vin.length > 12) { + transaction.fee = -1; + } else { + const totalOut = transaction.vout.reduce((p, output) => p + output.value, 0); + transaction.fee = parseFloat((totalIn - totalOut).toFixed(8)); } - const totalOut = transaction.vout.reduce((p, output) => p + output.value, 0); - transaction.fee = parseFloat((totalIn - totalOut).toFixed(8)); return transaction; } diff --git a/backend/src/api/bitcoin/esplora-api.interface.ts b/backend/src/api/bitcoin/esplora-api.interface.ts index 73ccbd88f..f825c60f9 100644 --- a/backend/src/api/bitcoin/esplora-api.interface.ts +++ b/backend/src/api/bitcoin/esplora-api.interface.ts @@ -33,6 +33,8 @@ export namespace IEsploraApi { // Elements is_pegin?: boolean; issuance?: Issuance; + // Custom + lazy?: boolean; } interface Issuance { diff --git a/backend/src/api/mining.ts b/backend/src/api/mining.ts index cbd412068..81821b6f7 100644 --- a/backend/src/api/mining.ts +++ b/backend/src/api/mining.ts @@ -7,6 +7,7 @@ import logger from '../logger'; import blocks from './blocks'; import { Common } from './common'; import loadingIndicators from './loading-indicators'; +import { escape } from 'mysql2'; class Mining { hashrateIndexingStarted = false; @@ -110,7 +111,7 @@ class Mining { public async $getPoolStat(slug: string): Promise { const pool = await PoolsRepository.$getPool(slug); if (!pool) { - throw new Error(`This mining pool does not exist`); + throw new Error('This mining pool does not exist ' + escape(slug)); } const blockCount: number = await BlocksRepository.$blockCount(pool.id); diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts index 2e669d709..5b92cea5f 100644 --- a/backend/src/api/transaction-utils.ts +++ b/backend/src/api/transaction-utils.ts @@ -21,8 +21,8 @@ class TransactionUtils { }; } - public async $getTransactionExtended(txId: string, addPrevouts = false): Promise { - const transaction: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts); + public async $getTransactionExtended(txId: string, addPrevouts = false, lazyPrevouts = false): Promise { + const transaction: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts, lazyPrevouts); return this.extendTransaction(transaction); } diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index c22491839..dcd5b48d1 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -5,6 +5,7 @@ import { Common } from '../api/common'; import { prepareBlock } from '../utils/blocks-utils'; import PoolsRepository from './PoolsRepository'; import HashratesRepository from './HashratesRepository'; +import { escape } from 'mysql2'; class BlocksRepository { /** @@ -235,7 +236,7 @@ class BlocksRepository { public async $getBlocksByPool(slug: string, startHeight?: number): Promise { const pool = await PoolsRepository.$getPool(slug); if (!pool) { - throw new Error(`This mining pool does not exist`); + throw new Error('This mining pool does not exist ' + escape(slug)); } const params: any[] = []; diff --git a/backend/src/repositories/HashratesRepository.ts b/backend/src/repositories/HashratesRepository.ts index 661535aa3..531b6cdcf 100644 --- a/backend/src/repositories/HashratesRepository.ts +++ b/backend/src/repositories/HashratesRepository.ts @@ -1,3 +1,4 @@ +import { escape } from 'mysql2'; import { Common } from '../api/common'; import DB from '../database'; import logger from '../logger'; @@ -105,7 +106,7 @@ class HashratesRepository { public async $getPoolWeeklyHashrate(slug: string): Promise { const pool = await PoolsRepository.$getPool(slug); if (!pool) { - throw new Error(`This mining pool does not exist`); + throw new Error('This mining pool does not exist ' + escape(slug)); } // Find hashrate boundaries diff --git a/backend/src/repositories/PoolsRepository.ts b/backend/src/repositories/PoolsRepository.ts index 037a6250a..c7cc6cba3 100644 --- a/backend/src/repositories/PoolsRepository.ts +++ b/backend/src/repositories/PoolsRepository.ts @@ -78,7 +78,6 @@ class PoolsRepository { const [rows]: any[] = await DB.query(query, [slug]); if (rows.length < 1) { - logger.debug(`This slug does not match any known pool`); return null; } diff --git a/backend/src/routes.ts b/backend/src/routes.ts index d65b4f836..cf28dd71d 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -778,9 +778,9 @@ class Routes { const endIndex = Math.min(startingIndex + 10, txIds.length); for (let i = startingIndex; i < endIndex; i++) { try { - const transaction = await transactionUtils.$getTransactionExtended(txIds[i], true); + const transaction = await transactionUtils.$getTransactionExtended(txIds[i], true, true); transactions.push(transaction); - loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i + 1) / endIndex * 100); + loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i - startingIndex + 1) / (endIndex - startingIndex) * 100); } catch (e) { logger.debug('getBlockTransactions error: ' + (e instanceof Error ? e.message : e)); } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index ae5860c78..672d68686 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -500,7 +500,7 @@ if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { }, { path: '**', - redirectTo: 'all' + redirectTo: 'featured' } ] }, diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index fa9e14651..6111075e4 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -66,9 +66,14 @@
-
- -
+ + +
+
+
+
+
+
@@ -81,13 +86,6 @@
- -
-
-
-
-
-
@@ -155,3 +153,9 @@ Confidential + + +
+ +
+
diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 1450fe1d3..c0ff29889 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -200,9 +200,13 @@
-
- -
+ +
+
+
+
+
+
@@ -215,14 +219,6 @@
- - -
-
-
-
-
-
@@ -281,6 +277,12 @@ + +
+ +
+
+
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 73543663b..c3c9b7ae3 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -38,7 +38,7 @@