From 309e851ead676c434bdde2cd4eac4ede7ee580f7 Mon Sep 17 00:00:00 2001 From: Simon Lindh Date: Tue, 12 Nov 2019 16:39:59 +0800 Subject: [PATCH] Block view. --- .../bitcoin/bitcoin-api-abstract-factory.ts | 5 +- backend/src/api/bitcoin/bitcoind-api.ts | 14 ++- backend/src/api/bitcoin/esplora-api.ts | 35 ++++++- backend/src/api/blocks.ts | 2 +- backend/src/index.ts | 5 +- backend/src/routes.ts | 27 ++++++ .../block-modal/block-modal.component.html | 5 +- .../block-modal/block-modal.component.ts | 3 +- .../app/explorer/block/block.component.html | 78 ++++++++++++++- .../src/app/explorer/block/block.component.ts | 52 +++++++++- frontend/src/app/explorer/explorer.module.ts | 3 +- .../explorer/explorer/explorer.component.html | 6 +- .../transaction/transaction.component.html | 96 ++----------------- .../transaction/transaction.component.ts | 10 -- .../transactions-list.component.html | 94 ++++++++++++++++++ .../transactions-list.component.scss | 3 + .../transactions-list.component.ts | 36 +++++++ frontend/src/app/services/api.service.ts | 16 +++- .../shared/pipes/bytes-pipe/wubytes.pipe.ts | 63 ++++++++++++ .../shorten-string.pipe.ts | 9 ++ frontend/src/app/shared/shared.module.ts | 8 ++ .../app/tx-bubble/tx-bubble.component.html | 4 +- .../src/app/tx-bubble/tx-bubble.component.ts | 3 - frontend/src/styles.scss | 4 - 24 files changed, 455 insertions(+), 126 deletions(-) create mode 100644 frontend/src/app/explorer/transactions-list/transactions-list.component.html create mode 100644 frontend/src/app/explorer/transactions-list/transactions-list.component.scss create mode 100644 frontend/src/app/explorer/transactions-list/transactions-list.component.ts create mode 100644 frontend/src/app/shared/pipes/bytes-pipe/wubytes.pipe.ts create mode 100644 frontend/src/app/shared/pipes/shorten-string-pipe/shorten-string.pipe.ts diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts index ae7191c82..cf4d07a40 100644 --- a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts +++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts @@ -5,9 +5,12 @@ export interface AbstractBitcoinApi { getRawMempool(): Promise; getRawTransaction(txId: string): Promise; getBlockCount(): Promise; - getBlock(hash: string): Promise; + getBlockAndTransactions(hash: string): Promise; getBlockHash(height: number): Promise; + getBlock(hash: string): Promise; + getBlockTransactions(hash: string): Promise; + getBlockTransactionsFromIndex(hash: string, index: number): Promise; getBlocks(): Promise; getBlocksFromHeight(height: number): Promise; } diff --git a/backend/src/api/bitcoin/bitcoind-api.ts b/backend/src/api/bitcoin/bitcoind-api.ts index 372db12d2..c4b2caeb0 100644 --- a/backend/src/api/bitcoin/bitcoind-api.ts +++ b/backend/src/api/bitcoin/bitcoind-api.ts @@ -59,7 +59,7 @@ class BitcoindApi implements AbstractBitcoinApi { }); } - getBlock(hash: string, verbosity: 1 | 2 = 1): Promise { + getBlockAndTransactions(hash: string, verbosity: 1 | 2 = 1): Promise { return new Promise((resolve, reject) => { this.client.getBlock(hash, verbosity, (err: Error, block: IBlock) => { if (err) { @@ -81,6 +81,10 @@ class BitcoindApi implements AbstractBitcoinApi { }); } + getBlock(hash: string): Promise { + throw new Error('Method not implemented.'); + } + getBlocks(): Promise { throw new Error('Method not implemented.'); } @@ -88,6 +92,14 @@ class BitcoindApi implements AbstractBitcoinApi { getBlocksFromHeight(height: number): Promise { throw new Error('Method not implemented.'); } + + getBlockTransactions(hash: string): Promise { + throw new Error('Method not implemented.'); + } + + getBlockTransactionsFromIndex(hash: string, index: number): Promise { + throw new Error('Method not implemented.'); + } } export default BitcoindApi; diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts index 77683fd4d..2c5cc0927 100644 --- a/backend/src/api/bitcoin/esplora-api.ts +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -65,7 +65,7 @@ class EsploraApi implements AbstractBitcoinApi { }); } - getBlock(hash: string): Promise { + getBlockAndTransactions(hash: string): Promise { return new Promise(async (resolve, reject) => { try { const blockInfo: AxiosResponse = await this.client.get('/block/' + hash); @@ -116,6 +116,39 @@ class EsploraApi implements AbstractBitcoinApi { } }); } + + getBlock(hash: string): Promise { + return new Promise(async (resolve, reject) => { + try { + const blockInfo: AxiosResponse = await this.client.get('/block/' + hash); + resolve(blockInfo.data); + } catch (error) { + reject(error); + } + }); + } + + getBlockTransactions(hash: string): Promise { + return new Promise(async (resolve, reject) => { + try { + const blockInfo: AxiosResponse = await this.client.get('/block/' + hash + '/txs'); + resolve(blockInfo.data); + } catch (error) { + reject(error); + } + }); + } + + getBlockTransactionsFromIndex(hash: string, index: number): Promise { + return new Promise(async (resolve, reject) => { + try { + const blockInfo: AxiosResponse = await this.client.get('/block/' + hash + '/txs/' + index); + resolve(blockInfo.data); + } catch (error) { + reject(error); + } + }); + } } export default EsploraApi; diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 4a2b0b557..d8af00cf4 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -56,7 +56,7 @@ class Blocks { block = storedBlock; } else { const blockHash = await bitcoinApi.getBlockHash(this.currentBlockHeight); - block = await bitcoinApi.getBlock(blockHash); + block = await bitcoinApi.getBlockAndTransactions(blockHash); const coinbase = await memPool.getRawTransaction(block.tx[0], true); if (coinbase && coinbase.totalOut) { diff --git a/backend/src/index.ts b/backend/src/index.ts index 97c1bf92b..654c18bca 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -120,7 +120,7 @@ class MempoolSpace { console.log('Found block by looking in local cache'); client['blockHeight'] = foundBlock.height; } else { - const theBlock = await bitcoinApi.getBlock(tx.blockhash); + const theBlock = await bitcoinApi.getBlockAndTransactions(tx.blockhash); if (theBlock) { client['blockHeight'] = theBlock.height; } @@ -269,6 +269,9 @@ class MempoolSpace { .get(config.API_ENDPOINT + 'explorer/blocks', routes.getBlocks) .get(config.API_ENDPOINT + 'explorer/blocks/:height', routes.getBlocks) .get(config.API_ENDPOINT + 'explorer/tx/:id', routes.getRawTransaction) + .get(config.API_ENDPOINT + 'explorer/block/:hash', routes.getBlock) + .get(config.API_ENDPOINT + 'explorer/block/:hash/tx', routes.getBlockTransactions) + .get(config.API_ENDPOINT + 'explorer/block/:hash/tx/:index', routes.getBlockTransactionsFromIndex) ; } diff --git a/backend/src/routes.ts b/backend/src/routes.ts index adf3e0daf..9d1d15bf7 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -99,6 +99,33 @@ class Routes { res.status(500).send(e.message); } } + + public async getBlock(req, res) { + try { + const result = await bitcoinApi.getBlock(req.params.hash); + res.send(result); + } catch (e) { + res.status(500).send(e.message); + } + } + + public async getBlockTransactions(req, res) { + try { + const result = await bitcoinApi.getBlockTransactions(req.params.hash); + res.send(result); + } catch (e) { + res.status(500).send(e.message); + } + } + + public async getBlockTransactionsFromIndex(req, res) { + try { + const result = await bitcoinApi.getBlockTransactionsFromIndex(req.params.hash, req.params.index); + res.send(result); + } catch (e) { + res.status(500).send(e.message); + } + } } export default new Routes(); diff --git a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html index 7050174d6..5cd09ed9e 100644 --- a/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html +++ b/frontend/src/app/blockchain-blocks/block-modal/block-modal.component.html @@ -1,5 +1,8 @@