diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index 3d6fb7161..c0ec6861e 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -52,7 +52,8 @@ export class Common { return { txid: tx.txid, fee: tx.fee, - weight: tx.weight, + weight: tx.weight, // Deprecated + vsize: tx.weight / 4, value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0), }; } diff --git a/backend/src/index.ts b/backend/src/index.ts index ac7acca50..e4e88a8da 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -220,12 +220,19 @@ class Server { if (config.MEMPOOL.BACKEND !== 'esplora') { this.app + .get(config.MEMPOOL.API_URL_PREFIX + 'mempool', routes.getMempool) + .get(config.MEMPOOL.API_URL_PREFIX + 'mempool/txids', routes.getMempoolTxIds) + .get(config.MEMPOOL.API_URL_PREFIX + 'mempool/recent', routes.getRecentMempoolTransactions) .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId', routes.getTransaction) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/status', routes.getTransactionStatus) .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/outspends', routes.getTransactionOutspends) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash', routes.getBlock) .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/:height', routes.getBlocks) - .get(config.MEMPOOL.API_URL_PREFIX + 'blocks', routes.getBlocks) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/:height', routes.getBlocks) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/height', routes.getBlockTipHeight) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txs', routes.getBlockTransactions) .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txs/:index', routes.getBlockTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txids', routes.getTxIdsForBlock) .get(config.MEMPOOL.API_URL_PREFIX + 'block-height/:height', routes.getBlockHeight) .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address', routes.getAddress) .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address/txs', routes.getAddressTransactions) diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 30227ba08..db36fddff 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -31,7 +31,8 @@ export interface TransactionExtended extends IEsploraApi.Transaction { export interface TransactionStripped { txid: string; fee: number; - weight: number; + weight?: number // deprecated + vsize: number; value: number; } export interface BlockExtended extends IEsploraApi.Block { diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 425fa6620..4630696f2 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -17,6 +17,7 @@ import bitcoinApi from './api/bitcoin/bitcoin-api-factory'; import transactionUtils from './api/transaction-utils'; import blocks from './api/blocks'; import loadingIndicators from './api/loading-indicators'; +import { Common } from './api/common'; class Routes { private cache: { [date: string]: OptimizedStatistic[] } = { @@ -542,6 +543,19 @@ class Routes { } } + public async getTransactionStatus(req: Request, res: Response) { + try { + const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true); + res.json(transaction.status); + } catch (e) { + let statusCode = 500; + if (e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { + statusCode = 404; + } + res.status(statusCode).send(e.message || e); + } + } + public async getBlock(req: Request, res: Response) { try { const result = await bitcoinApi.$getBlock(req.params.hash); @@ -594,7 +608,7 @@ class Routes { const txIds = await bitcoinApi.$getTxIdsForBlock(req.params.hash); const transactions: TransactionExtended[] = []; - const startingIndex = Math.max(0, parseInt(req.params.index, 10)); + const startingIndex = Math.max(0, parseInt(req.params.index || '0', 10)); const endIndex = Math.min(startingIndex + 10, txIds.length); for (let i = startingIndex; i < endIndex; i++) { @@ -669,6 +683,45 @@ class Routes { } } + public async getRecentMempoolTransactions(req: Request, res: Response) { + const latestTransactions = Object.entries(mempool.getMempool()) + .sort((a, b) => (b[1].firstSeen || 0) - (a[1].firstSeen || 0)) + .slice(0, 10).map((tx) => Common.stripTransaction(tx[1])); + + res.json(latestTransactions); + } + + public async getMempool(req: Request, res: Response) { + res.status(501).send('Not implemented'); + } + + public async getMempoolTxIds(req: Request, res: Response) { + try { + const rawMempool = await bitcoinApi.$getRawMempool(); + res.send(rawMempool); + } catch (e) { + res.status(500).send(e.message || e); + } + } + + public async getBlockTipHeight(req: Request, res: Response) { + try { + const result = await bitcoinApi.$getBlockHeightTip(); + res.json(result); + } catch (e) { + res.status(500).send(e.message || e); + } + } + + public async getTxIdsForBlock(req: Request, res: Response) { + try { + const result = await bitcoinApi.$getTxIdsForBlock(req.params.hash); + res.json(result); + } catch (e) { + res.status(500).send(e.message || e); + } + } + public getTransactionOutspends(req: Request, res: Response) { res.status(501).send('Not implemented'); } diff --git a/frontend/src/app/dashboard/dashboard.component.html b/frontend/src/app/dashboard/dashboard.component.html index dbf0b074c..60e419795 100644 --- a/frontend/src/app/dashboard/dashboard.component.html +++ b/frontend/src/app/dashboard/dashboard.component.html @@ -114,7 +114,7 @@