mirror of
https://github.com/mempool/mempool.git
synced 2025-01-18 21:32:55 +01:00
Responsive mempool blocks.
This commit is contained in:
parent
82ac10af93
commit
2f94200a45
@ -40,7 +40,7 @@ ENV CHAT_SSL_ENABLED false
|
|||||||
#ENV CHAT_SSL_CHAIN
|
#ENV CHAT_SSL_CHAIN
|
||||||
ENV MEMPOOL_REFRESH_RATE_MS 500
|
ENV MEMPOOL_REFRESH_RATE_MS 500
|
||||||
ENV INITIAL_BLOCK_AMOUNT 8
|
ENV INITIAL_BLOCK_AMOUNT 8
|
||||||
ENV DEFAULT_PROJECTED_BLOCKS_AMOUNT 3
|
ENV DEFAULT_PROJECTED_BLOCKS_AMOUNT 8
|
||||||
ENV KEEP_BLOCK_AMOUNT 24
|
ENV KEEP_BLOCK_AMOUNT 24
|
||||||
ENV BITCOIN_NODE_HOST bitcoinhost
|
ENV BITCOIN_NODE_HOST bitcoinhost
|
||||||
ENV BITCOIN_NODE_PORT 8332
|
ENV BITCOIN_NODE_PORT 8332
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
"API_ENDPOINT": "/api/v1/",
|
"API_ENDPOINT": "/api/v1/",
|
||||||
"ELECTRS_POLL_RATE_MS": 2000,
|
"ELECTRS_POLL_RATE_MS": 2000,
|
||||||
"MEMPOOL_REFRESH_RATE_MS": 2000,
|
"MEMPOOL_REFRESH_RATE_MS": 2000,
|
||||||
"DEFAULT_PROJECTED_BLOCKS_AMOUNT": 3,
|
"DEFAULT_PROJECTED_BLOCKS_AMOUNT": 8,
|
||||||
"KEEP_BLOCK_AMOUNT": 24,
|
"KEEP_BLOCK_AMOUNT": 24,
|
||||||
"INITIAL_BLOCK_AMOUNT": 8,
|
"INITIAL_BLOCK_AMOUNT": 8,
|
||||||
"TX_PER_SECOND_SPAN_SECONDS": 150,
|
"TX_PER_SECOND_SPAN_SECONDS": 150,
|
||||||
|
@ -73,8 +73,8 @@ class Blocks {
|
|||||||
|
|
||||||
block.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0);
|
block.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0);
|
||||||
transactions.sort((a, b) => b.feePerVsize - a.feePerVsize);
|
transactions.sort((a, b) => b.feePerVsize - a.feePerVsize);
|
||||||
block.medianFee = transactions.length ? this.median(transactions.map((tx) => tx.feePerVsize)) : 0;
|
block.medianFee = transactions.length > 1 ? this.median(transactions.map((tx) => tx.feePerVsize)) : 0;
|
||||||
block.feeRange = transactions.length ? this.getFeesInRange(transactions, 8) : [0, 0];
|
block.feeRange = transactions.length > 1 ? this.getFeesInRange(transactions, 8) : [0, 0];
|
||||||
|
|
||||||
this.blocks.push(block);
|
this.blocks.push(block);
|
||||||
if (this.blocks.length > config.KEEP_BLOCK_AMOUNT) {
|
if (this.blocks.length > config.KEEP_BLOCK_AMOUNT) {
|
||||||
@ -111,7 +111,7 @@ class Blocks {
|
|||||||
itemsToAdd--;
|
itemsToAdd--;
|
||||||
}
|
}
|
||||||
|
|
||||||
arr.push(transactions[0].feePerVsize);
|
arr.push(transactions[1].feePerVsize);
|
||||||
return arr;
|
return arr;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ class MempoolBlocks {
|
|||||||
let blockSize = 0;
|
let blockSize = 0;
|
||||||
let transactions: TransactionExtended[] = [];
|
let transactions: TransactionExtended[] = [];
|
||||||
transactionsSorted.forEach((tx) => {
|
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;
|
blockWeight += tx.vsize;
|
||||||
blockSize += tx.size;
|
blockSize += tx.size;
|
||||||
transactions.push(tx);
|
transactions.push(tx);
|
||||||
|
@ -10,8 +10,8 @@
|
|||||||
</div>
|
</div>
|
||||||
<div class="block-size">{{ projectedBlock.blockSize | bytes: 2 }}</div>
|
<div class="block-size">{{ projectedBlock.blockSize | bytes: 2 }}</div>
|
||||||
<div class="transaction-count">{{ projectedBlock.nTx }} transactions</div>
|
<div class="transaction-count">{{ projectedBlock.nTx }} transactions</div>
|
||||||
<div class="time-difference" *ngIf="i !== 3">In ~{{ 10 * i + 10 }} minutes</div>
|
<div class="time-difference" *ngIf="projectedBlock.blockVSize < 1000000">In ~{{ 10 * i + 10 }} minutes</div>
|
||||||
<ng-template [ngIf]="i === 3 && mempoolBlocks?.length >= 4 && (projectedBlock.blockVSize / 1000000 | ceil) > 1">
|
<ng-template [ngIf]="i === mempoolBlocks.length - 1 && projectedBlock.blockVSize >= 1000000">
|
||||||
<div class="time-difference">+{{ projectedBlock.blockVSize / 1000000 | ceil }} blocks</div>
|
<div class="time-difference">+{{ projectedBlock.blockVSize / 1000000 | ceil }} blocks</div>
|
||||||
</ng-template>
|
</ng-template>
|
||||||
</div>
|
</div>
|
||||||
|
@ -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 { Subscription } from 'rxjs';
|
||||||
import { MempoolBlock } from 'src/app/interfaces/websocket.interface';
|
import { MempoolBlock } from 'src/app/interfaces/websocket.interface';
|
||||||
import { StateService } from 'src/app/services/state.service';
|
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 {
|
export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
||||||
mempoolBlocks: MempoolBlock[];
|
mempoolBlocks: MempoolBlock[];
|
||||||
|
mempoolBlocksFull: MempoolBlock[];
|
||||||
mempoolBlocksSubscription: Subscription;
|
mempoolBlocksSubscription: Subscription;
|
||||||
|
|
||||||
blockWidth = 125;
|
blockWidth = 125;
|
||||||
@ -27,11 +28,21 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
ngOnInit() {
|
ngOnInit() {
|
||||||
this.mempoolBlocksSubscription = this.stateService.mempoolBlocks$
|
this.mempoolBlocksSubscription = this.stateService.mempoolBlocks$
|
||||||
.subscribe((blocks) => {
|
.subscribe((blocks) => {
|
||||||
this.mempoolBlocks = blocks;
|
this.mempoolBlocksFull = JSON.parse(JSON.stringify(blocks));
|
||||||
|
this.mempoolBlocks = this.reduceMempoolBlocksToFitScreen(blocks);
|
||||||
this.calculateTransactionPosition();
|
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() {
|
ngOnChanges() {
|
||||||
this.calculateTransactionPosition();
|
this.calculateTransactionPosition();
|
||||||
}
|
}
|
||||||
@ -44,6 +55,32 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
|
|||||||
return index;
|
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) {
|
getStyleForMempoolBlockAtIndex(index: number) {
|
||||||
const greenBackgroundHeight = 100 - this.mempoolBlocks[index].blockVSize / 1000000 * 100;
|
const greenBackgroundHeight = 100 - this.mempoolBlocks[index].blockVSize / 1000000 * 100;
|
||||||
return {
|
return {
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { Injectable } from '@angular/core';
|
import { Injectable } from '@angular/core';
|
||||||
import { webSocket, WebSocketSubject } from 'rxjs/webSocket';
|
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 { StateService } from './state.service';
|
||||||
import { Block, Transaction } from '../interfaces/electrs.interface';
|
import { Block, Transaction } from '../interfaces/electrs.interface';
|
||||||
import { Subscription } from 'rxjs';
|
import { Subscription } from 'rxjs';
|
||||||
|
Loading…
Reference in New Issue
Block a user