Switch "latest blocks" to "latest replacements"
This commit is contained in:
		
							parent
							
								
									427b1ef617
								
							
						
					
					
						commit
						e9eef579ed
					
				@ -75,36 +75,31 @@
 | 
			
		||||
    <div class="col" style="max-height: 410px">
 | 
			
		||||
      <div class="card">
 | 
			
		||||
        <div class="card-body">
 | 
			
		||||
          <a class="title-link" href="" [routerLink]="['/blocks' | relativeUrl]">
 | 
			
		||||
            <h5 class="card-title d-inline" i18n="dashboard.latest-blocks">Latest blocks</h5>
 | 
			
		||||
          <a class="title-link" href="" [routerLink]="['/rbf' | relativeUrl]">
 | 
			
		||||
            <h5 class="card-title d-inline" i18n="dashboard.latest-rbf-replacements">Latest Replacements</h5>
 | 
			
		||||
            <span> </span>
 | 
			
		||||
            <fa-icon [icon]="['fas', 'external-link-alt']" [fixedWidth]="true" style="vertical-align: 'text-top'; font-size: 13px; color: '#4a68b9'"></fa-icon>
 | 
			
		||||
          </a>
 | 
			
		||||
          <table class="table lastest-blocks-table">
 | 
			
		||||
          <table class="table lastest-replacements-table">
 | 
			
		||||
            <thead>
 | 
			
		||||
              <th class="table-cell-height" i18n="dashboard.latest-blocks.height">Height</th>
 | 
			
		||||
              <th *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" i18n="dashboard.latest-blocks.mined">Mined</th>
 | 
			
		||||
              <th *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4" i18n="mining.pool-name">Pool</th>
 | 
			
		||||
              <th class="table-cell-transaction-count" i18n="dashboard.latest-blocks.transaction-count">TXs</th>
 | 
			
		||||
              <th class="table-cell-size" i18n="dashboard.latest-blocks.size">Size</th>
 | 
			
		||||
              <th class="table-cell-txid" i18n="dashboard.latest-transactions.txid">TXID</th>
 | 
			
		||||
              <th class="table-cell-old-fee" i18n="dashboard.old-transaction-fee">Old fee</th>
 | 
			
		||||
              <th class="table-cell-new-fee" i18n="dashboard.new-transaction-fee">New fee</th>
 | 
			
		||||
              <th class="table-cell-badges"></th>
 | 
			
		||||
            </thead>
 | 
			
		||||
            <tbody>
 | 
			
		||||
              <tr *ngFor="let block of blocks$ | async; let i = index; trackBy: trackByBlock">
 | 
			
		||||
                <td class="table-cell-height" ><a [routerLink]="['/block' | relativeUrl, block.id]" [state]="{ data: { block: block } }">{{ block.height }}</a></td>
 | 
			
		||||
                <td *ngIf="!stateService.env.MINING_DASHBOARD" class="table-cell-mined" ><app-time kind="since" [time]="block.timestamp" [fastRender]="true"></app-time></td>
 | 
			
		||||
                <td *ngIf="stateService.env.MINING_DASHBOARD" class="table-cell-mined pl-lg-4">
 | 
			
		||||
                  <a class="clear-link" [routerLink]="[('/mining/pool/' + block.extras.pool.slug) | relativeUrl]">
 | 
			
		||||
                    <img width="22" height="22" src="{{ block.extras.pool['logo'] }}"
 | 
			
		||||
                      onError="this.src = '/resources/mining-pools/default.svg'">
 | 
			
		||||
                    <span class="pool-name">{{ block.extras.pool.name }}</span>
 | 
			
		||||
              <tr *ngFor="let replacement of replacements$ | async;">
 | 
			
		||||
                <td class="table-cell-txid">
 | 
			
		||||
                  <a [routerLink]="['/tx' | relativeUrl, replacement.txid]">
 | 
			
		||||
                    <app-truncate [text]="replacement.txid" [lastChars]="5"></app-truncate>
 | 
			
		||||
                  </a>
 | 
			
		||||
                </td>
 | 
			
		||||
                <td class="table-cell-transaction-count">{{ block.tx_count | number }}</td>
 | 
			
		||||
                <td class="table-cell-size">
 | 
			
		||||
                  <div class="progress">
 | 
			
		||||
                    <div class="progress-bar progress-mempool {{ network$ | async }}" role="progressbar" [ngStyle]="{'width': (block.weight / stateService.env.BLOCK_WEIGHT_UNITS)*100 + '%' }"> </div>
 | 
			
		||||
                    <div class="progress-text" [innerHTML]="block.size | bytes: 2"></div>
 | 
			
		||||
                  </div>
 | 
			
		||||
                <td class="table-cell-old-fee"><app-fee-rate [fee]="replacement.oldFee" [weight]="replacement.oldVsize * 4"></app-fee-rate></td>
 | 
			
		||||
                <td class="table-cell-new-fee"><app-fee-rate [fee]="replacement.newFee" [weight]="replacement.newVsize * 4"></app-fee-rate></td>
 | 
			
		||||
                <td class="table-cell-badges">
 | 
			
		||||
                  <span *ngIf="replacement.mined" class="badge badge-success" i18n="transaction.rbf.mined">Mined</span>
 | 
			
		||||
                  <span *ngIf="replacement.fullRbf" class="badge badge-info" i18n="transaction.full-rbf">Full RBF</span>
 | 
			
		||||
                  <span *ngIf="!replacement.fullRbf" class="badge badge-success" i18n="transaction.rbf">RBF</span>
 | 
			
		||||
                </td>
 | 
			
		||||
              </tr>
 | 
			
		||||
            </tbody>
 | 
			
		||||
 | 
			
		||||
@ -175,40 +175,34 @@
 | 
			
		||||
  height: 18px;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
.lastest-blocks-table {
 | 
			
		||||
.lastest-replacements-table {
 | 
			
		||||
  width: 100%;
 | 
			
		||||
  text-align: left;
 | 
			
		||||
  table-layout:fixed;
 | 
			
		||||
  tr, td, th {
 | 
			
		||||
    border: 0px;
 | 
			
		||||
    padding-top: 0.65rem !important;
 | 
			
		||||
    padding-bottom: 0.7rem !important;
 | 
			
		||||
    padding-top: 0.71rem !important;
 | 
			
		||||
    padding-bottom: 0.75rem !important;
 | 
			
		||||
  }
 | 
			
		||||
  .table-cell-height {
 | 
			
		||||
    width: 15%;
 | 
			
		||||
  td {
 | 
			
		||||
    overflow:hidden;
 | 
			
		||||
    width: 25%;
 | 
			
		||||
  }
 | 
			
		||||
  .table-cell-mined {
 | 
			
		||||
    width: 35%;
 | 
			
		||||
    text-align: left;
 | 
			
		||||
  .table-cell-txid {
 | 
			
		||||
    width: 33%;
 | 
			
		||||
    text-align: start;
 | 
			
		||||
  }
 | 
			
		||||
  .table-cell-transaction-count {
 | 
			
		||||
    display: none;
 | 
			
		||||
    text-align: right;
 | 
			
		||||
    width: 20%;
 | 
			
		||||
    display: table-cell;
 | 
			
		||||
  .table-cell-old-fee {
 | 
			
		||||
    width: 33%;
 | 
			
		||||
    text-align: end;
 | 
			
		||||
  }
 | 
			
		||||
  .table-cell-size {
 | 
			
		||||
    display: none;
 | 
			
		||||
    text-align: center;
 | 
			
		||||
    width: 30%;
 | 
			
		||||
    @media (min-width: 485px) {
 | 
			
		||||
      display: table-cell;
 | 
			
		||||
    }
 | 
			
		||||
    @media (min-width: 768px) {
 | 
			
		||||
      display: none;
 | 
			
		||||
    }
 | 
			
		||||
    @media (min-width: 992px) {
 | 
			
		||||
      display: table-cell;
 | 
			
		||||
    }
 | 
			
		||||
  .table-cell-new-fee {
 | 
			
		||||
    width: 33%;
 | 
			
		||||
    text-align: end;
 | 
			
		||||
  }
 | 
			
		||||
  .table-cell-badges {
 | 
			
		||||
    width: 25%;
 | 
			
		||||
    text-align: end;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -1,7 +1,7 @@
 | 
			
		||||
import { ChangeDetectionStrategy, Component, OnDestroy, OnInit } from '@angular/core';
 | 
			
		||||
import { combineLatest, merge, Observable, of, Subscription } from 'rxjs';
 | 
			
		||||
import { filter, map, scan, share, switchMap, tap } from 'rxjs/operators';
 | 
			
		||||
import { BlockExtended, OptimizedMempoolStats } from '../interfaces/node-api.interface';
 | 
			
		||||
import { BlockExtended, OptimizedMempoolStats, RbfTree } from '../interfaces/node-api.interface';
 | 
			
		||||
import { MempoolInfo, TransactionStripped } from '../interfaces/websocket.interface';
 | 
			
		||||
import { ApiService } from '../services/api.service';
 | 
			
		||||
import { StateService } from '../services/state.service';
 | 
			
		||||
@ -25,6 +25,17 @@ interface MempoolStatsData {
 | 
			
		||||
  weightPerSecond: any;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
interface ReplacementInfo {
 | 
			
		||||
  tree: RbfTree;
 | 
			
		||||
  mined: boolean;
 | 
			
		||||
  fullRbf: boolean;
 | 
			
		||||
  txid: string;
 | 
			
		||||
  oldFee: number;
 | 
			
		||||
  oldVsize: number;
 | 
			
		||||
  newFee: number;
 | 
			
		||||
  newVsize: number;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@Component({
 | 
			
		||||
  selector: 'app-dashboard',
 | 
			
		||||
  templateUrl: './dashboard.component.html',
 | 
			
		||||
@ -38,8 +49,8 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
  mempoolInfoData$: Observable<MempoolInfoData>;
 | 
			
		||||
  mempoolLoadingStatus$: Observable<number>;
 | 
			
		||||
  vBytesPerSecondLimit = 1667;
 | 
			
		||||
  blocks$: Observable<BlockExtended[]>;
 | 
			
		||||
  transactions$: Observable<TransactionStripped[]>;
 | 
			
		||||
  replacements$: Observable<ReplacementInfo[]>;
 | 
			
		||||
  latestBlockHeight: number;
 | 
			
		||||
  mempoolTransactionsWeightPerSecondData: any;
 | 
			
		||||
  mempoolStats$: Observable<MempoolStatsData>;
 | 
			
		||||
@ -64,6 +75,7 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
    this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$;
 | 
			
		||||
    this.seoService.resetTitle();
 | 
			
		||||
    this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']);
 | 
			
		||||
    this.websocketService.startTrackRbf('all');
 | 
			
		||||
    this.network$ = merge(of(''), this.stateService.networkChanged$);
 | 
			
		||||
    this.mempoolLoadingStatus$ = this.stateService.loadingIndicators$
 | 
			
		||||
      .pipe(
 | 
			
		||||
@ -130,23 +142,6 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
        }),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    this.blocks$ = this.stateService.blocks$
 | 
			
		||||
      .pipe(
 | 
			
		||||
        tap((blocks) => {
 | 
			
		||||
          this.latestBlockHeight = blocks[0].height;
 | 
			
		||||
        }),
 | 
			
		||||
        switchMap((blocks) => {
 | 
			
		||||
          if (this.stateService.env.MINING_DASHBOARD === true) {
 | 
			
		||||
            for (const block of blocks) {
 | 
			
		||||
              // @ts-ignore: Need to add an extra field for the template
 | 
			
		||||
              block.extras.pool.logo = `/resources/mining-pools/` +
 | 
			
		||||
                block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg';
 | 
			
		||||
            }
 | 
			
		||||
          }
 | 
			
		||||
          return of(blocks.slice(0, 6));
 | 
			
		||||
        })
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    this.transactions$ = this.stateService.transactions$
 | 
			
		||||
      .pipe(
 | 
			
		||||
        scan((acc, tx) => {
 | 
			
		||||
@ -159,6 +154,31 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
        }, []),
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
    this.replacements$ = this.stateService.rbfLatest$.pipe(
 | 
			
		||||
      switchMap((rbfList) => {
 | 
			
		||||
        const replacements = rbfList.slice(0, 6).map(rbfTree => {
 | 
			
		||||
          let oldFee = 0;
 | 
			
		||||
          let oldVsize = 0;
 | 
			
		||||
          for (const replaced of rbfTree.replaces) {
 | 
			
		||||
            oldFee += replaced.tx.fee;
 | 
			
		||||
            oldVsize += replaced.tx.vsize;
 | 
			
		||||
          }
 | 
			
		||||
          this.checkFullRbf(rbfTree);
 | 
			
		||||
          return {
 | 
			
		||||
            tree: rbfTree,
 | 
			
		||||
            txid: rbfTree.tx.txid,
 | 
			
		||||
            mined: rbfTree.tx.mined,
 | 
			
		||||
            fullRbf: rbfTree.tx.fullRbf,
 | 
			
		||||
            oldFee,
 | 
			
		||||
            oldVsize,
 | 
			
		||||
            newFee: rbfTree.tx.fee,
 | 
			
		||||
            newVsize: rbfTree.tx.vsize,
 | 
			
		||||
          };
 | 
			
		||||
        });
 | 
			
		||||
        return of(replacements);
 | 
			
		||||
      })
 | 
			
		||||
    );
 | 
			
		||||
 | 
			
		||||
    this.mempoolStats$ = this.stateService.connectionState$
 | 
			
		||||
      .pipe(
 | 
			
		||||
        filter((state) => state === 2),
 | 
			
		||||
@ -219,4 +239,16 @@ export class DashboardComponent implements OnInit, OnDestroy {
 | 
			
		||||
  trackByBlock(index: number, block: BlockExtended) {
 | 
			
		||||
    return block.height;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  checkFullRbf(tree: RbfTree): void {
 | 
			
		||||
    let fullRbf = false;
 | 
			
		||||
    for (const replaced of tree.replaces) {
 | 
			
		||||
      if (!replaced.tx.rbf) {
 | 
			
		||||
        fullRbf = true;
 | 
			
		||||
      }
 | 
			
		||||
      replaced.replacedBy = tree.tx;
 | 
			
		||||
      this.checkFullRbf(replaced);
 | 
			
		||||
    }
 | 
			
		||||
    tree.tx.fullRbf = fullRbf;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user