diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts index 906cc0f95..9cdf052f2 100644 --- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts +++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts @@ -7,8 +7,10 @@ export interface AbstractBitcoinApi { $getTxIdsForBlock(hash: string): Promise; $getBlockHash(height: number): Promise; $getBlockHeader(hash: string): Promise; + $getRawBlock(hash: string): Promise; $getBlock(hash: string): Promise; $getAddress(address: string): Promise; $getAddressTransactions(address: string, lastSeenTxId: string): Promise; $getAddressPrefix(prefix: string): string[]; + } diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts index 0af44d2a8..2110dc659 100644 --- a/backend/src/api/bitcoin/bitcoin-api.ts +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -56,6 +56,11 @@ class BitcoinApi implements AbstractBitcoinApi { .then((rpcBlock: IBitcoinApi.Block) => rpcBlock.tx); } + $getRawBlock(hash: string): Promise { + return this.bitcoindClient.getBlock(hash, 0); + } + + $getBlockHash(height: number): Promise { return this.bitcoindClient.getBlockHash(height); } diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index 86d4179ad..aa1d46e04 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -40,6 +40,12 @@ class ElectrsApi implements AbstractBitcoinApi { .then((response) => response.data); } + $getRawBlock(hash: string): Promise { + return axios.get(config.ESPLORA.REST_API_URL + '/block/' + hash + '/raw', this.axiosConfig) + .then((response) => response.data); + } + + $getBlock(hash: string): Promise { return axios.get(config.ESPLORA.REST_API_URL + '/block/' + hash, this.axiosConfig) .then((response) => response.data); diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts index 2a5d3a9ad..cb84396ba 100644 --- a/backend/src/api/transaction-utils.ts +++ b/backend/src/api/transaction-utils.ts @@ -25,6 +25,11 @@ class TransactionUtils { return this.extendTransaction(transaction); } + public async $getRawTransactionExtended(txId: string, addPrevouts = false): Promise { + const transaction: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(txId, true, addPrevouts); + return this.extendTransaction(transaction); + } + private extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended { // @ts-ignore if (transaction.vsize) { diff --git a/backend/src/index.ts b/backend/src/index.ts index 2d1ed5456..3b1e4e1d8 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -235,10 +235,12 @@ class Server { .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/raw', routes.getRawTransaction) .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 + 'block/:hash/header', routes.getBlockHeader) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/raw', routes.getRawBlock) .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) diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index fae78ef9b..bac267a05 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -31,6 +31,7 @@ export interface TransactionExtended extends IEsploraApi.Transaction { bestDescendant?: BestDescendant | null; cpfpChecked?: boolean; deleteAfter?: number; + hex?:string } interface Ancestor { diff --git a/backend/src/routes.ts b/backend/src/routes.ts index bc42a9868..2bfc9b4fd 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -484,6 +484,20 @@ class Routes { } } + public async getRawTransaction(req: Request, res: Response) { + try { + const transaction = await transactionUtils.$getRawTransactionExtended(req.params.txId, true); + res.setHeader('content-type', 'text/plain'); + res.send(transaction.hex); + } 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 getTransactionStatus(req: Request, res: Response) { try { const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true); @@ -516,6 +530,16 @@ class Routes { } } + public async getRawBlock(req: Request, res: Response) { + try { + const blockHeader = await bitcoinApi.$getRawBlock(req.params.hash); + res.setHeader('content-type', 'text/plain'); + res.send(blockHeader); + } catch (e) { + res.status(500).send(e.message || e); + } + } + public async getBlocks(req: Request, res: Response) { try { loadingIndicators.setProgress('blocks', 0); diff --git a/frontend/angular.json b/frontend/angular.json index 3a2c2d94c..1e4fdfc8a 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -1,5 +1,8 @@ { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "cli": { + "analytics": false + }, "version": 1, "newProjectRoot": "projects", "projects": { diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 51740e636..5e98d712d 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -118,6 +118,10 @@ Block Header Hex + + Raw Block + + diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 88d85fe87..80ad6d5f8 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -216,6 +216,10 @@ Weight + + Raw Tx + +