diff --git a/Dockerfile b/Dockerfile index 3be11db2e..d8e5d0f95 100644 --- a/Dockerfile +++ b/Dockerfile @@ -40,7 +40,7 @@ ENV CHAT_SSL_ENABLED false #ENV CHAT_SSL_CHAIN ENV MEMPOOL_REFRESH_RATE_MS 500 ENV INITIAL_BLOCK_AMOUNT 8 -ENV DEFAULT_PROJECTED_BLOCKS_AMOUNT 3 +ENV DEFAULT_PROJECTED_BLOCKS_AMOUNT 8 ENV KEEP_BLOCK_AMOUNT 24 ENV BITCOIN_NODE_HOST bitcoinhost ENV BITCOIN_NODE_PORT 8332 diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 9a9fae5cb..a8c5d13ef 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -8,7 +8,7 @@ "API_ENDPOINT": "/api/v1/", "ELECTRS_POLL_RATE_MS": 2000, "MEMPOOL_REFRESH_RATE_MS": 2000, - "DEFAULT_PROJECTED_BLOCKS_AMOUNT": 3, + "DEFAULT_PROJECTED_BLOCKS_AMOUNT": 8, "KEEP_BLOCK_AMOUNT": 24, "INITIAL_BLOCK_AMOUNT": 8, "TX_PER_SECOND_SPAN_SECONDS": 150, diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 090514e5c..7ee902a69 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -73,8 +73,8 @@ class Blocks { block.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0); transactions.sort((a, b) => b.feePerVsize - a.feePerVsize); - block.medianFee = transactions.length ? this.median(transactions.map((tx) => tx.feePerVsize)) : 0; - block.feeRange = transactions.length ? this.getFeesInRange(transactions, 8) : [0, 0]; + block.medianFee = transactions.length > 1 ? this.median(transactions.map((tx) => tx.feePerVsize)) : 0; + block.feeRange = transactions.length > 1 ? this.getFeesInRange(transactions, 8) : [0, 0]; this.blocks.push(block); if (this.blocks.length > config.KEEP_BLOCK_AMOUNT) { @@ -111,7 +111,7 @@ class Blocks { itemsToAdd--; } - arr.push(transactions[0].feePerVsize); + arr.push(transactions[1].feePerVsize); return arr; } } diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index d0bae4dd0..215671b0a 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -29,7 +29,7 @@ class MempoolBlocks { let blockSize = 0; let transactions: TransactionExtended[] = []; transactionsSorted.forEach((tx) => { - if (blockWeight + tx.vsize < 1000000 || mempoolBlocks.length === config.DEFAULT_PROJECTED_BLOCKS_AMOUNT) { + if (blockWeight + tx.vsize < 1000000 || mempoolBlocks.length === config.DEFAULT_PROJECTED_BLOCKS_AMOUNT - 1) { blockWeight += tx.vsize; blockSize += tx.size; transactions.push(tx); diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html index c09bb369a..eb6e3113c 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.html @@ -10,8 +10,8 @@
{{ projectedBlock.blockSize | bytes: 2 }}
{{ projectedBlock.nTx }} transactions
-
In ~{{ 10 * i + 10 }} minutes
- +
In ~{{ 10 * i + 10 }} minutes
+
+{{ projectedBlock.blockVSize / 1000000 | ceil }} blocks
diff --git a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts index f77f7468d..f22e919a1 100644 --- a/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts +++ b/frontend/src/app/components/mempool-blocks/mempool-blocks.component.ts @@ -1,4 +1,4 @@ -import { Component, OnInit, OnDestroy, Input, EventEmitter, Output, OnChanges } from '@angular/core'; +import { Component, OnInit, OnDestroy, Input, EventEmitter, Output, OnChanges, HostListener } from '@angular/core'; import { Subscription } from 'rxjs'; import { MempoolBlock } from 'src/app/interfaces/websocket.interface'; import { StateService } from 'src/app/services/state.service'; @@ -10,6 +10,7 @@ import { StateService } from 'src/app/services/state.service'; }) export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { mempoolBlocks: MempoolBlock[]; + mempoolBlocksFull: MempoolBlock[]; mempoolBlocksSubscription: Subscription; blockWidth = 125; @@ -27,11 +28,21 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { ngOnInit() { this.mempoolBlocksSubscription = this.stateService.mempoolBlocks$ .subscribe((blocks) => { - this.mempoolBlocks = blocks; + this.mempoolBlocksFull = JSON.parse(JSON.stringify(blocks)); + this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(blocks); this.calculateTransactionPosition(); }); } + @HostListener('window:resize', ['$event']) + onResize() { + console.log('onResize'); + if (this.mempoolBlocks.length) { + this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(JSON.parse(JSON.stringify(this.mempoolBlocksFull))); + } + } + + ngOnChanges() { this.calculateTransactionPosition(); } @@ -44,6 +55,32 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy { return index; } + reduceMempoolBlocksToFitScreen(blocks: MempoolBlock[]): MempoolBlock[] { + const blocksAmount = Math.max(1, Math.floor(window.innerWidth / 2 / (this.blockWidth + this.blockPadding))); + while (blocks.length > blocksAmount) { + const block = blocks.pop(); + const lastBlock = blocks[blocks.length - 1]; + lastBlock.blockSize += block.blockSize; + lastBlock.blockVSize += block.blockVSize; + lastBlock.nTx += block.nTx; + lastBlock.feeRange = lastBlock.feeRange.concat(block.feeRange); + lastBlock.feeRange.sort((a, b) => a - b); + lastBlock.medianFee = this.median(lastBlock.feeRange); + } + return blocks; + } + + median(numbers: number[]) { + let medianNr = 0; + const numsLen = numbers.length; + if (numsLen % 2 === 0) { + medianNr = (numbers[numsLen / 2 - 1] + numbers[numsLen / 2]) / 2; + } else { + medianNr = numbers[(numsLen - 1) / 2]; + } + return medianNr; + } + getStyleForMempoolBlockAtIndex(index: number) { const greenBackgroundHeight = 100 - this.mempoolBlocks[index].blockVSize / 1000000 * 100; return { diff --git a/frontend/src/app/services/websocket.service.ts b/frontend/src/app/services/websocket.service.ts index daa654c16..ab724a847 100644 --- a/frontend/src/app/services/websocket.service.ts +++ b/frontend/src/app/services/websocket.service.ts @@ -1,6 +1,6 @@ import { Injectable } from '@angular/core'; import { webSocket, WebSocketSubject } from 'rxjs/webSocket'; -import { WebsocketResponse } from '../interfaces/websocket.interface'; +import { WebsocketResponse, MempoolBlock } from '../interfaces/websocket.interface'; import { StateService } from './state.service'; import { Block, Transaction } from '../interfaces/electrs.interface'; import { Subscription } from 'rxjs';