From 34645908e9e2e5778bcd94f579a52db14db655ab Mon Sep 17 00:00:00 2001 From: Simon Lindh Date: Mon, 17 Feb 2020 20:39:20 +0700 Subject: [PATCH] Refactor. API explanations. UX revamp. --- backend/src/api/bitcoin/electrs-api.ts | 23 +++++- backend/src/api/mempool.ts | 8 +++ backend/src/index.ts | 65 +++++++++++------ frontend/src/app/app-routing.module.ts | 5 ++ frontend/src/app/app.module.ts | 4 ++ .../app/components/about/about.component.html | 72 ++++++++++++------- .../app/components/about/about.component.scss | 8 +++ .../app/components/about/about.component.ts | 2 +- .../app/components/block/block.component.html | 2 +- .../app/components/block/block.component.ts | 5 ++ .../blockchain-blocks.component.html | 3 +- .../blockchain-blocks.component.scss | 9 ++- .../blockchain/blockchain.component.html | 14 ++-- .../blockchain/blockchain.component.scss | 10 ++- .../blockchain/blockchain.component.ts | 56 +-------------- .../clipboard/clipboard.component.html | 2 +- .../explorer/explorer.component.html | 20 ++++++ .../explorer/explorer.component.scss | 3 + .../explorer/explorer.component.spec.ts | 25 +++++++ .../components/explorer/explorer.component.ts | 25 +++++++ .../components/footer/footer.component.html | 18 +++++ .../components/footer/footer.component.scss | 44 ++++++++++++ .../app/components/footer/footer.component.ts | 61 ++++++++++++++++ .../latest-blocks.component.html | 6 +- .../latest-transactions.component.html | 2 +- .../master-page/master-page.component.html | 5 +- .../search-form/search-form.component.html | 35 +++------ .../search-form/search-form.component.ts | 1 - .../app/components/start/start.component.html | 19 +---- .../app/components/start/start.component.ts | 13 +++- .../statistics/statistics.component.ts | 4 +- .../television/television.component.scss | 4 +- .../television/television.component.ts | 5 +- .../transaction/transaction.component.html | 30 ++++---- .../transaction/transaction.component.ts | 2 + .../transactions-list.component.html | 18 +++-- .../src/app/interfaces/websocket.interface.ts | 18 +++++ frontend/src/app/services/state.service.ts | 3 +- .../src/app/services/websocket.service.ts | 26 +++++-- frontend/src/styles.scss | 9 ++- 40 files changed, 474 insertions(+), 210 deletions(-) create mode 100644 frontend/src/app/components/explorer/explorer.component.html create mode 100644 frontend/src/app/components/explorer/explorer.component.scss create mode 100644 frontend/src/app/components/explorer/explorer.component.spec.ts create mode 100644 frontend/src/app/components/explorer/explorer.component.ts create mode 100644 frontend/src/app/components/footer/footer.component.html create mode 100644 frontend/src/app/components/footer/footer.component.scss create mode 100644 frontend/src/app/components/footer/footer.component.ts diff --git a/backend/src/api/bitcoin/electrs-api.ts b/backend/src/api/bitcoin/electrs-api.ts index 9a52e4f75..34c210a99 100644 --- a/backend/src/api/bitcoin/electrs-api.ts +++ b/backend/src/api/bitcoin/electrs-api.ts @@ -1,5 +1,5 @@ const config = require('../../../mempool-config.json'); -import { Transaction, Block } from '../../interfaces'; +import { Transaction, Block, MempoolInfo } from '../../interfaces'; import * as request from 'request'; class ElectrsApi { @@ -7,6 +7,27 @@ class ElectrsApi { constructor() { } + getMempoolInfo(): Promise { + return new Promise((resolve, reject) => { + request(config.ELECTRS_API_URL + '/mempool', { json: true, timeout: 10000 }, (err, res, response) => { + if (err) { + reject(err); + } else if (res.statusCode !== 200) { + reject(response); + } else { + if (!response.count) { + reject('Empty data'); + return; + } + resolve({ + size: response.count, + bytes: response.vsize, + }); + } + }); + }); + } + getRawMempool(): Promise { return new Promise((resolve, reject) => { request(config.ELECTRS_API_URL + '/mempool/txids', { json: true, timeout: 10000, forever: true }, (err, res, response) => { diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index dde4e6f7f..0ef0de801 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -32,6 +32,14 @@ class Mempool { } } + public async updateMemPoolInfo() { + try { + this.mempoolInfo = await bitcoinApi.getMempoolInfo(); + } catch (err) { + console.log('Error getMempoolInfo', err); + } + } + public getMempoolInfo(): MempoolInfo | undefined { return this.mempoolInfo; } diff --git a/backend/src/index.ts b/backend/src/index.ts index f5ef97f24..74d348ecf 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -58,6 +58,7 @@ class Server { } private async runMempoolIntervalFunctions() { + await memPool.updateMemPoolInfo(); await blocks.updateBlocks(); await memPool.updateMempool(); setTimeout(this.runMempoolIntervalFunctions.bind(this), config.ELECTRS_POLL_RATE_MS); @@ -83,28 +84,33 @@ class Server { const parsedMessage = JSON.parse(message); if (parsedMessage.action === 'want') { - client['want-stats'] = parsedMessage.data.indexOf('stats') > -1; + client['want-blocks'] = parsedMessage.data.indexOf('blocks') > -1; + client['want-mempool-blocks'] = parsedMessage.data.indexOf('mempool-blocks') > -1; client['want-live-2h-chart'] = parsedMessage.data.indexOf('live-2h-chart') > -1; + client['want-stats'] = parsedMessage.data.indexOf('stats') > -1; } if (parsedMessage && parsedMessage.txId && /^[a-fA-F0-9]{64}$/.test(parsedMessage.txId)) { client['txId'] = parsedMessage.txId; } + + if (parsedMessage.action === 'init') { + const _blocks = blocks.getBlocks(); + if (!_blocks) { + return; + } + client.send(JSON.stringify({ + 'mempoolInfo': memPool.getMempoolInfo(), + 'vBytesPerSecond': memPool.getVBytesPerSecond(), + 'blocks': _blocks, + 'conversions': fiatConversion.getTickers()['BTCUSD'], + 'mempool-blocks': mempoolBlocks.getMempoolBlocks(), + })); + } } catch (e) { console.log(e); } }); - - const _blocks = blocks.getBlocks(); - if (!_blocks) { - return; - } - client.send(JSON.stringify({ - 'blocks': _blocks, - 'conversions': fiatConversion.getTickers()['BTCUSD'], - 'mempool-blocks': mempoolBlocks.getMempoolBlocks(), - })); - }); statistics.setNewStatisticsEntryCallback((stats: Statistic) => { @@ -113,11 +119,13 @@ class Server { return; } - if (client['want-live-2h-chart']) { - client.send(JSON.stringify({ - 'live-2h-chart': stats - })); + if (!client['want-live-2h-chart']) { + return; } + + client.send(JSON.stringify({ + 'live-2h-chart': stats + })); }); }); @@ -127,6 +135,10 @@ class Server { return; } + if (!client['want-blocks']) { + return; + } + if (client['txId'] && txIds.indexOf(client['txId']) > -1) { client['txId'] = null; client.send(JSON.stringify({ @@ -143,16 +155,29 @@ class Server { memPool.setMempoolChangedCallback((newMempool: { [txid: string]: SimpleTransaction }) => { mempoolBlocks.updateMempoolBlocks(newMempool); - const pBlocks = mempoolBlocks.getMempoolBlocks(); + const mBlocks = mempoolBlocks.getMempoolBlocks(); + const mempoolInfo = memPool.getMempoolInfo(); + const vBytesPerSecond = memPool.getVBytesPerSecond(); this.wss.clients.forEach((client: WebSocket) => { if (client.readyState !== WebSocket.OPEN) { return; } - client.send(JSON.stringify({ - 'mempool-blocks': pBlocks - })); + const response = {}; + + if (client['want-stats']) { + response['mempoolInfo'] = mempoolInfo; + response['vBytesPerSecond'] = vBytesPerSecond; + } + + if (client['want-mempool-blocks']) { + response['mempool-blocks'] = mBlocks; + } + + if (Object.keys(response).length) { + client.send(JSON.stringify(response)); + } }); }); } diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 09676ad92..715ec3ef4 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -8,6 +8,7 @@ import { MasterPageComponent } from './components/master-page/master-page.compon import { AboutComponent } from './components/about/about.component'; import { TelevisionComponent } from './components/television/television.component'; import { StatisticsComponent } from './components/statistics/statistics.component'; +import { ExplorerComponent } from './components/explorer/explorer.component'; const routes: Routes = [ { @@ -18,6 +19,10 @@ const routes: Routes = [ path: '', component: StartComponent, }, + { + path: 'explorer', + component: ExplorerComponent, + }, { path: 'graphs', component: StatisticsComponent, diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 086e7e52e..ebb9abd24 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -38,6 +38,8 @@ import { StatisticsComponent } from './components/statistics/statistics.componen import { ChartistComponent } from './components/statistics/chartist.component'; import { BlockchainBlocksComponent } from './components/blockchain-blocks/blockchain-blocks.component'; import { BlockchainComponent } from './components/blockchain/blockchain.component'; +import { FooterComponent } from './components/footer/footer.component'; +import { ExplorerComponent } from './components/explorer/explorer.component'; @NgModule({ declarations: [ @@ -68,7 +70,9 @@ import { BlockchainComponent } from './components/blockchain/blockchain.componen LatestTransactionsComponent, QrcodeComponent, ClipboardComponent, + ExplorerComponent, ChartistComponent, + FooterComponent, ], imports: [ BrowserModule, diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index e20d385d9..c6cee8cc3 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -1,34 +1,54 @@ -
- -

+
+
+ +

-

About

+

About

-

Mempool.Space is a realtime Bitcoin blockchain explorer and mempool visualizer.

-

Created by @softbtc -
Hosted by @wiz -
Designed by @markjborg - - -

Fee API

- -
- +

Mempool.Space is a realtime Bitcoin blockchain explorer and mempool visualizer.

+

Created by @softbtc +
Hosted by @wiz +
Designed by @markjborg

-
+

HTTP API

-

Donate

- -
- bc1qqrmgr60uetlmrpylhtllawyha9z5gw6hwdmk2t + + + + + + + + + +
Fee API +
+ +
+
Mempool blocks +
+ +
+
+ +

WebSocket API

+ + + + + + +
+ + Upon connection, send object {{ '{' }} action: 'want', data: ['blocks', ...] {{ '}' }} + to express what you want pushed. Available: 'blocks', 'mempool-blocks', 'live-2h-chart' and 'stats'. + + +
+ +
+
-

-

PayNym

- -
-

- PM8TJZWDn1XbYmVVMR3RP9Kt1BW69VCSLTC12UB8iWUiKcEBJsxB4UUKBMJxc3LVaxtU5d524sLFrTy9kFuyPQ73QkEagGcMfCE6M38E5C67EF8KAqvS -

diff --git a/frontend/src/app/components/about/about.component.scss b/frontend/src/app/components/about/about.component.scss index e69de29bb..1616a58cf 100644 --- a/frontend/src/app/components/about/about.component.scss +++ b/frontend/src/app/components/about/about.component.scss @@ -0,0 +1,8 @@ +.text-small { + font-size: 12px; +} + +.code { + background-color: #1d1f31; + font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New; +} \ No newline at end of file diff --git a/frontend/src/app/components/about/about.component.ts b/frontend/src/app/components/about/about.component.ts index 44f29154f..1f94f0267 100644 --- a/frontend/src/app/components/about/about.component.ts +++ b/frontend/src/app/components/about/about.component.ts @@ -13,7 +13,7 @@ export class AboutComponent implements OnInit { ) { } ngOnInit() { - this.websocketService.want([]); + this.websocketService.want(['blocks']); } } diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index bc320f6f0..73e8fbd33 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -1,6 +1,6 @@
- +

Block #{{ blockHeight }}

diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index 76a1019e9..7351aab0d 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -5,6 +5,7 @@ import { switchMap } from 'rxjs/operators'; import { Block, Transaction } from '../../interfaces/electrs.interface'; import { of } from 'rxjs'; import { StateService } from '../../services/state.service'; +import { WebsocketService } from 'src/app/services/websocket.service'; @Component({ selector: 'app-block', @@ -25,9 +26,12 @@ export class BlockComponent implements OnInit { private route: ActivatedRoute, private electrsApiService: ElectrsApiService, private stateService: StateService, + private websocketService: WebsocketService, ) { } ngOnInit() { + this.websocketService.want(['blocks', 'mempool-blocks']); + this.route.paramMap.pipe( switchMap((params: ParamMap) => { const blockHash: string = params.get('id') || ''; @@ -40,6 +44,7 @@ export class BlockComponent implements OnInit { this.blockHash = blockHash; if (history.state.data && history.state.data.block) { + this.blockHeight = history.state.data.block.height; return of(history.state.data.block); } else { this.isLoadingBlock = true; diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 42959b937..07f00d68b 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -1,6 +1,7 @@
-
+
+   diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index a7ef50cd3..f3e3589c1 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -1,7 +1,14 @@ .bitcoin-block { width: 125px; height: 125px; - cursor: pointer; +} + +.blockLink { + width: 100%; + height: 100%; + position: absolute; + left: 0; + z-index: 10; } .mined-block { diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 98cfc03a3..6bf4e8b5e 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,20 +1,14 @@ -
-

Loading blocks...

+
+

Waiting for blocks...


-
-

Locating transaction...

-
-
-

Transaction not found!

-
-
+
-
+
\ No newline at end of file diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index 89db920e1..c2a77b3be 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -23,8 +23,6 @@ .position-container { position: absolute; left: 50%; - /* top: calc(50% - 60px); */ - top: 180px; } @media (max-width: 767.98px) { @@ -48,3 +46,11 @@ z-index: 100; position: relative; } + +.loading-block { + position: absolute; + text-align: center; + margin: auto; + width: 100%; + top: 80px; +} \ No newline at end of file diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index 29bffb911..d29849272 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -1,8 +1,6 @@ -import { Component, OnInit, OnDestroy, Renderer2 } from '@angular/core'; -import { ActivatedRoute, ParamMap } from '@angular/router'; +import { Component, OnInit, OnDestroy, Input } from '@angular/core'; import { Subscription } from 'rxjs'; import { take } from 'rxjs/operators'; -import { WebsocketService } from 'src/app/services/websocket.service'; import { StateService } from 'src/app/services/state.service'; @Component({ @@ -11,6 +9,8 @@ import { StateService } from 'src/app/services/state.service'; styleUrls: ['./blockchain.component.scss'] }) export class BlockchainComponent implements OnInit, OnDestroy { + @Input() position: 'middle' | 'top' = 'middle'; + txTrackingSubscription: Subscription; blocksSubscription: Subscription; @@ -19,59 +19,10 @@ export class BlockchainComponent implements OnInit, OnDestroy { isLoading = true; constructor( - private route: ActivatedRoute, - private websocketService: WebsocketService, private stateService: StateService, ) {} ngOnInit() { - /* - this.apiService.webSocketWant(['stats', 'blocks', 'mempool-blocks']); - - this.txTrackingSubscription = this.memPoolService.txTracking$ - .subscribe((response: ITxTracking) => { - this.txTrackingLoading = false; - this.txShowTxNotFound = response.notFound; - if (this.txShowTxNotFound) { - setTimeout(() => { this.txShowTxNotFound = false; }, 2000); - } - }); - */ - - /* - this.route.paramMap - .subscribe((params: ParamMap) => { - if (this.memPoolService.txTracking$.value.enabled) { - return; - } - - const txId: string | null = params.get('id'); - if (!txId) { - return; - } - this.txTrackingLoading = true; - this.apiService.webSocketStartTrackTx(txId); - }); - - */ - - /* - this.memPoolService.txIdSearch$ - .subscribe((txId) => { - if (txId) { - - if (this.memPoolService.txTracking$.value.enabled - && this.memPoolService.txTracking$.value.tx - && this.memPoolService.txTracking$.value.tx.txid === txId) { - return; - } - console.log('enabling tracking loading from idSearch!'); - this.txTrackingLoading = true; - this.websocketService.startTrackTx(txId); - } - }); - */ - this.blocksSubscription = this.stateService.blocks$ .pipe( take(1) @@ -81,6 +32,5 @@ export class BlockchainComponent implements OnInit, OnDestroy { ngOnDestroy() { this.blocksSubscription.unsubscribe(); - // this.txTrackingSubscription.unsubscribe(); } } diff --git a/frontend/src/app/components/clipboard/clipboard.component.html b/frontend/src/app/components/clipboard/clipboard.component.html index 0ac7f7530..fd99e6832 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.html +++ b/frontend/src/app/components/clipboard/clipboard.component.html @@ -1,4 +1,4 @@ - + diff --git a/frontend/src/app/components/explorer/explorer.component.html b/frontend/src/app/components/explorer/explorer.component.html new file mode 100644 index 000000000..ca7c97f3c --- /dev/null +++ b/frontend/src/app/components/explorer/explorer.component.html @@ -0,0 +1,20 @@ +
+ +
+ + + + + + + +
+ +
diff --git a/frontend/src/app/components/explorer/explorer.component.scss b/frontend/src/app/components/explorer/explorer.component.scss new file mode 100644 index 000000000..c65e3bcbe --- /dev/null +++ b/frontend/src/app/components/explorer/explorer.component.scss @@ -0,0 +1,3 @@ +.search-container { + padding-top: 50px; +} diff --git a/frontend/src/app/components/explorer/explorer.component.spec.ts b/frontend/src/app/components/explorer/explorer.component.spec.ts new file mode 100644 index 000000000..918214ae6 --- /dev/null +++ b/frontend/src/app/components/explorer/explorer.component.spec.ts @@ -0,0 +1,25 @@ +import { async, ComponentFixture, TestBed } from '@angular/core/testing'; + +import { ExplorerComponent } from './explorer.component'; + +describe('ExplorerComponent', () => { + let component: ExplorerComponent; + let fixture: ComponentFixture; + + beforeEach(async(() => { + TestBed.configureTestingModule({ + declarations: [ ExplorerComponent ] + }) + .compileComponents(); + })); + + beforeEach(() => { + fixture = TestBed.createComponent(ExplorerComponent); + component = fixture.componentInstance; + fixture.detectChanges(); + }); + + it('should create', () => { + expect(component).toBeTruthy(); + }); +}); diff --git a/frontend/src/app/components/explorer/explorer.component.ts b/frontend/src/app/components/explorer/explorer.component.ts new file mode 100644 index 000000000..fb4924df2 --- /dev/null +++ b/frontend/src/app/components/explorer/explorer.component.ts @@ -0,0 +1,25 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute } from '@angular/router'; + +@Component({ + selector: 'app-explorer', + templateUrl: './explorer.component.html', + styleUrls: ['./explorer.component.scss'] +}) +export class ExplorerComponent implements OnInit { + view: 'blocks' | 'transactions' = 'blocks'; + + constructor( + private route: ActivatedRoute, + ) {} + + ngOnInit() { + this.route.fragment + .subscribe((fragment: string) => { + if (fragment === 'transactions' ) { + this.view = 'transactions'; + } + }); + } + +} diff --git a/frontend/src/app/components/footer/footer.component.html b/frontend/src/app/components/footer/footer.component.html new file mode 100644 index 000000000..13a303a68 --- /dev/null +++ b/frontend/src/app/components/footer/footer.component.html @@ -0,0 +1,18 @@ +
+
+
+
+ Unconfirmed transactions: {{ memPoolInfo?.memPoolInfo?.size | number }} +
+ Mempool size: {{ mempoolSize | bytes }} ({{ mempoolBlocks }} blocks) +
+ Tx weight per second:  + +
+
{{ memPoolInfo?.vBytesPerSecond | ceil | number }} vBytes/s
+
+ +
+
+
+
diff --git a/frontend/src/app/components/footer/footer.component.scss b/frontend/src/app/components/footer/footer.component.scss new file mode 100644 index 000000000..6cb20d2ad --- /dev/null +++ b/frontend/src/app/components/footer/footer.component.scss @@ -0,0 +1,44 @@ +.footer { + position: fixed; + bottom: 0; + width: 100%; + height: 120px; + background-color: #1d1f31; +} + +.footer > .container { + margin-top: 25px; +} + +.txPerSecond { + color: #4a9ff4; +} + +.mempoolSize { + color: #4a68b9; +} + +.unconfirmedTx { + color: #f14d80; +} + +.info-block { + float: left; + width: 350px; + line-height: 25px; +} + +.progress { + display: inline-flex; + width: 160px; + background-color: #2d3348; + height: 1.1rem; +} + +.progress-bar { + padding: 4px; +} + +.bg-warning { + background-color: #b58800 !important; +} diff --git a/frontend/src/app/components/footer/footer.component.ts b/frontend/src/app/components/footer/footer.component.ts new file mode 100644 index 000000000..889033b0c --- /dev/null +++ b/frontend/src/app/components/footer/footer.component.ts @@ -0,0 +1,61 @@ +import { Component, OnInit } from '@angular/core'; +import { StateService } from 'src/app/services/state.service'; +import { MemPoolState } from 'src/app/interfaces/websocket.interface'; + +@Component({ + selector: 'app-footer', + templateUrl: './footer.component.html', + styleUrls: ['./footer.component.scss'] +}) +export class FooterComponent implements OnInit { + memPoolInfo: MemPoolState | undefined; + mempoolBlocks = 0; + progressWidth = ''; + progressClass: string; + mempoolSize = 0; + + constructor( + private stateService: StateService, + ) { } + + ngOnInit() { + this.stateService.mempoolStats$ + .subscribe((mempoolState) => { + this.memPoolInfo = mempoolState; + this.updateProgress(); + }); + + this.stateService.mempoolBlocks$ + .subscribe((mempoolBlocks) => { + if (!mempoolBlocks.length) { return; } + const size = mempoolBlocks.map((m) => m.blockSize).reduce((a, b) => a + b); + const vsize = mempoolBlocks.map((m) => m.blockVSize).reduce((a, b) => a + b); + this.mempoolSize = size; + this.mempoolBlocks = Math.ceil(vsize / 1000000); + }); + } + + updateProgress() { + if (!this.memPoolInfo) { + return; + } + + const vBytesPerSecondLimit = 1667; + + let vBytesPerSecond = this.memPoolInfo.vBytesPerSecond; + if (vBytesPerSecond > 1667) { + vBytesPerSecond = 1667; + } + + const percent = Math.round((vBytesPerSecond / vBytesPerSecondLimit) * 100); + this.progressWidth = percent + '%'; + + if (percent <= 75) { + this.progressClass = 'bg-success'; + } else if (percent <= 99) { + this.progressClass = 'bg-warning'; + } else { + this.progressClass = 'bg-danger'; + } + } +} diff --git a/frontend/src/app/components/latest-blocks/latest-blocks.component.html b/frontend/src/app/components/latest-blocks/latest-blocks.component.html index 708148183..fd52451c1 100644 --- a/frontend/src/app/components/latest-blocks/latest-blocks.component.html +++ b/frontend/src/app/components/latest-blocks/latest-blocks.component.html @@ -9,7 +9,7 @@ - #{{ block.height }} + #{{ block.height }} {{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} {{ block.timestamp | timeSince : trigger }} ago {{ block.tx_count }} @@ -34,10 +34,6 @@
- -
-

-

diff --git a/frontend/src/app/components/latest-transactions/latest-transactions.component.html b/frontend/src/app/components/latest-transactions/latest-transactions.component.html index ad88f1bbe..984ef3406 100644 --- a/frontend/src/app/components/latest-transactions/latest-transactions.component.html +++ b/frontend/src/app/components/latest-transactions/latest-transactions.component.html @@ -9,7 +9,7 @@ - {{ transaction.txid }} + {{ transaction.txid }} {{ transaction.value / 100000000 }} BTC {{ transaction.vsize | vbytes: 2 }} {{ transaction.fee / transaction.vsize | number : '1.2-2'}} sats/vB 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 48098a48e..2f58ebb00 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -9,7 +9,10 @@