Adding "mempool block" details. Work in progress!

This commit is contained in:
softsimon 2020-03-17 21:53:20 +07:00
parent 3e6f382c4d
commit 72658c19f6
No known key found for this signature in database
GPG Key ID: 488D7DCFB5A430D7
18 changed files with 260 additions and 9 deletions

@ -62,6 +62,7 @@ class MempoolBlocks {
blockSize: blockSize,
blockVSize: blockVSize,
nTx: transactions.length,
totalFees: transactions.reduce((acc, cur) => acc + cur.fee, 0),
medianFee: this.median(transactions.map((tx) => tx.feePerVsize)),
feeRange: this.getFeesInRange(transactions, rangeLength),
};

@ -12,6 +12,7 @@ export interface MempoolBlock {
blockVSize: number;
nTx: number;
medianFee: number;
totalFees: number;
feeRange: number[];
}

@ -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 { MempoolBlockComponent } from './components/mempool-block/mempool-block.component';
const routes: Routes = [
{
@ -36,6 +37,11 @@ const routes: Routes = [
children: [],
component: BlockComponent
},
{
path: 'mempool-block/:id',
children: [],
component: MempoolBlockComponent
},
{
path: 'address/:id',
children: [],

@ -40,6 +40,8 @@ import { BlockchainComponent } from './components/blockchain/blockchain.componen
import { FooterComponent } from './components/footer/footer.component';
import { AudioService } from './services/audio.service';
import { FiatComponent } from './fiat/fiat.component';
import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component';
import { FeeDistributionGraphComponent } from './components/fee-distribution-graph/fee-distribution-graph.component';
@NgModule({
declarations: [
@ -71,6 +73,8 @@ import { FiatComponent } from './fiat/fiat.component';
ChartistComponent,
FooterComponent,
FiatComponent,
MempoolBlockComponent,
FeeDistributionGraphComponent,
],
imports: [
BrowserModule,

@ -1,6 +1,6 @@
<div class="text-center" class="blockchain-wrapper">
<div class="position-container">
<app-mempool-blocks [txFeePerVSize]="markHeight ? 0 : txFeePerVSize"></app-mempool-blocks>
<app-mempool-blocks [markIndex]="markMempoolBlockIndex" [txFeePerVSize]="markHeight ? 0 : txFeePerVSize"></app-mempool-blocks>
<app-blockchain-blocks [markHeight]="markHeight"></app-blockchain-blocks>
<div id="divider" *ngIf="!isLoading; else loadingTmpl"></div>

@ -12,6 +12,7 @@ export class BlockchainComponent implements OnInit, OnDestroy {
@Input() position: 'middle' | 'top' = 'middle';
@Input() markHeight: number;
@Input() txFeePerVSize: number;
@Input() markMempoolBlockIndex = -1;
txTrackingSubscription: Subscription;
blocksSubscription: Subscription;

@ -0,0 +1,13 @@
<div style="height: 400px;" *ngIf="mempoolVsizeFeesData; else loadingFees">
<app-chartist
[data]="mempoolVsizeFeesData"
[type]="'Line'"
[options]="mempoolVsizeFeesOptions">
</app-chartist>
</div>
<ng-template #loadingFees>
<div class="text-center">
<div class="spinner-border text-light"></div>
</div>
</ng-template>

@ -0,0 +1,66 @@
import { Component, OnInit, Input, OnChanges } from '@angular/core';
import { FormBuilder, FormGroup } from '@angular/forms';
import * as Chartist from 'chartist';
import { VbytesPipe } from 'src/app/pipes/bytes-pipe/vbytes.pipe';
@Component({
selector: 'app-fee-distribution-graph',
templateUrl: './fee-distribution-graph.component.html',
styleUrls: ['./fee-distribution-graph.component.scss']
})
export class FeeDistributionGraphComponent implements OnChanges {
@Input() feeRange;
mempoolVsizeFeesData: any;
mempoolVsizeFeesOptions: any;
mempoolVsizeFeesPieData: any;
mempoolVsizeFeesPieOptions: any;
feeLevels = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200,
250, 300, 350, 400, 500];
radioGroupForm: FormGroup;
constructor(
private vbytesPipe: VbytesPipe,
) { }
ngOnChanges() {
this.mempoolVsizeFeesOptions = {
showArea: true,
showLine: true,
fullWidth: true,
showPoint: false,
low: 0,
axisY: {
labelInterpolationFnc: (value: number): any => {
return this.vbytesPipe.transform(value, 2);
},
offset: 60
},
};
const fees = this.feeRange;
const series = [];
for (let i = 0; i < this.feeLevels.length; i++) {
let total = 0;
for (let j = 0; j < fees.length; j++) {
if (i === this.feeLevels.length - 1) {
if (fees[j] >= this.feeLevels[i]) {
total += 1;
}
} else if (fees[j] >= this.feeLevels[i] && fees[j] < this.feeLevels[i + 1]) {
total += 1;
}
}
series.push(total);
}
this.mempoolVsizeFeesData = {
series: [fees]
};
}
}

@ -6,6 +6,12 @@
background-color: #2d3348;
}
.progress-text {
position: absolute;
width: 100%;
text-align: center;
}
@media (min-width: 768px) {
.d-md-block {
display: table-cell !important;
@ -16,9 +22,3 @@
display: table-cell !important;
}
}
.progress-text {
position: absolute;
width: 100%;
text-align: center;
}

@ -0,0 +1,54 @@
<div class="container-xl" *ngIf="mempoolBlock">
<div style="position: relative;">
<app-blockchain position="top" [markMempoolBlockIndex]="mempoolBlockIndex"></app-blockchain>
</div>
<div class="title-block">
<h1>Mempool block</h1>
</div>
<br>
<div class="box">
<div class="row">
<div class="col-sm">
<table class="table table-borderless table-striped">
<tbody>
<tr>
<td>Median fee</td>
<td>~{{ mempoolBlock.medianFee | ceil }} sats/vB (<app-fiat [value]="mempoolBlock.medianFee * 250" digitsInfo="1.2-2"></app-fiat>)</td>
</tr>
<tr>
<td>Fee span</td>
<td><span class="yellow-color">{{ mempoolBlock.feeRange[0] | ceil }} - {{ mempoolBlock.feeRange[mempoolBlock.feeRange.length - 1] | ceil }} sat/vB</span></td>
</tr>
<tr>
<td>Total fees</td>
<td>{{ mempoolBlock.totalFees / 100000000 | number : '1.2-2' }} BTC (<app-fiat [value]="mempoolBlock.totalFees" digitsInfo="1.0-0"></app-fiat>)</td>
</tr>
<tr>
<td>Transactions</td>
<td>{{ mempoolBlock.nTx }}</td>
</tr>
<tr>
<td>Filled</td>
<td>
<div class="progress position-relative">
<div class="progress-bar progress-mempool" role="progressbar" [ngStyle]="{'width': (mempoolBlock.blockVSize / 1000000) * 100 + '%' }"></div>
<div class="progress-text">{{ mempoolBlock.blockSize | bytes: 2 }}</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>
<div class="col-sm">
<app-fee-distribution-graph [feeRange]="mempoolBlock.feeRange"></app-fee-distribution-graph>
</div>
</div>
</div>
<br>
</div>

@ -0,0 +1,25 @@
.progress-mempool {
background: repeating-linear-gradient(to right, #2d3348, #2d3348 0%, #105fb0 0%, #9339f4 100%);
}
.progress {
background-color: #2d3348;
}
.progress-text {
position: absolute;
width: 100%;
text-align: center;
}
.title-block {
color: #FFF;
padding-left: 10px;
padding-top: 20px;
padding-bottom: 3px;
border-top: 5px solid #FFF;
}
.title-block > h1 {
margin: 0;
}

@ -0,0 +1,25 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { MempoolBlockComponent } from './mempool-block.component';
describe('MempoolBlockComponent', () => {
let component: MempoolBlockComponent;
let fixture: ComponentFixture<MempoolBlockComponent>;
beforeEach(async(() => {
TestBed.configureTestingModule({
declarations: [ MempoolBlockComponent ]
})
.compileComponents();
}));
beforeEach(() => {
fixture = TestBed.createComponent(MempoolBlockComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});

@ -0,0 +1,40 @@
import { Component, OnInit } from '@angular/core';
import { StateService } from 'src/app/services/state.service';
import { ActivatedRoute, ParamMap } from '@angular/router';
import { switchMap, map } from 'rxjs/operators';
import { MempoolBlock } from 'src/app/interfaces/websocket.interface';
import { WebsocketService } from 'src/app/services/websocket.service';
@Component({
selector: 'app-mempool-block',
templateUrl: './mempool-block.component.html',
styleUrls: ['./mempool-block.component.scss']
})
export class MempoolBlockComponent implements OnInit {
mempoolBlockIndex: number;
mempoolBlock: MempoolBlock;
constructor(
private route: ActivatedRoute,
private stateService: StateService,
private websocketService: WebsocketService,
) { }
ngOnInit(): void {
this.websocketService.want(['blocks', 'stats', 'mempool-blocks']);
this.route.paramMap.pipe(
switchMap((params: ParamMap) => {
this.mempoolBlockIndex = parseInt(params.get('id'), 10) || 0;
return this.stateService.mempoolBlocks$
.pipe(
map((mempoolBlocks) => mempoolBlocks[this.mempoolBlockIndex])
);
})
)
.subscribe((mempoolBlock) => {
this.mempoolBlock = mempoolBlock;
});
}
}

@ -2,6 +2,7 @@
<div class="flashing">
<div *ngFor="let projectedBlock of mempoolBlocks; let i = index; trackBy: trackByFn">
<div class="bitcoin-block text-center mempool-block" id="mempool-block-{{ i }}" [ngStyle]="getStyleForMempoolBlockAtIndex(i)">
<a [routerLink]="['/mempool-block/', i]" class="blockLink">&nbsp;</a>
<div class="block-body" *ngIf="mempoolBlocks?.length">
<div class="fees">
<span class="yellow-color">~{{ projectedBlock.medianFee | ceil }} sats/vB</span>

@ -104,3 +104,11 @@
border-right: 35px solid transparent;
border-bottom: 35px solid #FFF;
}
.blockLink {
width: 100%;
height: 100%;
position: absolute;
left: 0;
z-index: 10;
}

@ -20,6 +20,7 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
rightPosition = 0;
@Input() txFeePerVSize: number;
@Input() markIndex: number;
constructor(
private stateService: StateService,
@ -42,7 +43,6 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
}
}
ngOnChanges() {
this.calculateTransactionPosition();
}
@ -91,13 +91,18 @@ export class MempoolBlocksComponent implements OnInit, OnChanges, OnDestroy {
}
calculateTransactionPosition() {
if (!this.txFeePerVSize || !this.mempoolBlocks) {
if ((!this.txFeePerVSize && this.markIndex === -1) || !this.mempoolBlocks) {
this.arrowVisible = false;
return;
}
this.arrowVisible = true;
if (this.markIndex > -1) {
this.rightPosition = this.markIndex * (this.blockWidth + this.blockPadding) + 0.5 * this.blockWidth;
return;
}
for (const block of this.mempoolBlocks) {
for (let i = 0; i < block.feeRange.length - 1; i++) {
if (this.txFeePerVSize < block.feeRange[i + 1] && this.txFeePerVSize >= block.feeRange[i]) {

@ -19,6 +19,7 @@ export interface MempoolBlock {
blockVSize: number;
nTx: number;
medianFee: number;
totalFees: number;
feeRange: number[];
}