Replace acceleration API polling with websocket
This commit is contained in:
		
							parent
							
								
									8ec5dd70e0
								
							
						
					
					
						commit
						a29b29300e
					
				@ -404,6 +404,10 @@ class Mempool {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
      const newAccelerationMap: { [txid: string]: Acceleration } = {};
 | 
					      const newAccelerationMap: { [txid: string]: Acceleration } = {};
 | 
				
			||||||
      for (const acceleration of newAccelerations) {
 | 
					      for (const acceleration of newAccelerations) {
 | 
				
			||||||
 | 
					        // skip transactions we don't know about
 | 
				
			||||||
 | 
					        if (!this.mempoolCache[acceleration.txid]) {
 | 
				
			||||||
 | 
					          continue;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        newAccelerationMap[acceleration.txid] = acceleration;
 | 
					        newAccelerationMap[acceleration.txid] = acceleration;
 | 
				
			||||||
        if (this.accelerations[acceleration.txid] == null) {
 | 
					        if (this.accelerations[acceleration.txid] == null) {
 | 
				
			||||||
          // new acceleration
 | 
					          // new acceleration
 | 
				
			||||||
 | 
				
			|||||||
@ -347,6 +347,17 @@ class WebsocketHandler {
 | 
				
			|||||||
            }
 | 
					            }
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					          if (parsedMessage && parsedMessage['track-accelerations'] != null) {
 | 
				
			||||||
 | 
					            if (parsedMessage['track-accelerations']) {
 | 
				
			||||||
 | 
					              client['track-accelerations'] = true;
 | 
				
			||||||
 | 
					              response['accelerations'] = JSON.stringify({
 | 
				
			||||||
 | 
					                accelerations: Object.values(memPool.getAccelerations()),
 | 
				
			||||||
 | 
					              });
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					              client['track-accelerations'] = false;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
          if (parsedMessage.action === 'init') {
 | 
					          if (parsedMessage.action === 'init') {
 | 
				
			||||||
            if (!this.socketData['blocks']?.length || !this.socketData['da'] || !this.socketData['backendInfo'] || !this.socketData['conversions']) {
 | 
					            if (!this.socketData['blocks']?.length || !this.socketData['da'] || !this.socketData['backendInfo'] || !this.socketData['conversions']) {
 | 
				
			||||||
              this.updateSocketData();
 | 
					              this.updateSocketData();
 | 
				
			||||||
@ -537,6 +548,7 @@ class WebsocketHandler {
 | 
				
			|||||||
    const vBytesPerSecond = memPool.getVBytesPerSecond();
 | 
					    const vBytesPerSecond = memPool.getVBytesPerSecond();
 | 
				
			||||||
    const rbfTransactions = Common.findRbfTransactions(newTransactions, deletedTransactions);
 | 
					    const rbfTransactions = Common.findRbfTransactions(newTransactions, deletedTransactions);
 | 
				
			||||||
    const da = difficultyAdjustment.getDifficultyAdjustment();
 | 
					    const da = difficultyAdjustment.getDifficultyAdjustment();
 | 
				
			||||||
 | 
					    const accelerations = memPool.getAccelerations();
 | 
				
			||||||
    memPool.handleRbfTransactions(rbfTransactions);
 | 
					    memPool.handleRbfTransactions(rbfTransactions);
 | 
				
			||||||
    const rbfChanges = rbfCache.getRbfChanges();
 | 
					    const rbfChanges = rbfCache.getRbfChanges();
 | 
				
			||||||
    let rbfReplacements;
 | 
					    let rbfReplacements;
 | 
				
			||||||
@ -644,6 +656,12 @@ class WebsocketHandler {
 | 
				
			|||||||
    const addressCache = this.makeAddressCache(newTransactions);
 | 
					    const addressCache = this.makeAddressCache(newTransactions);
 | 
				
			||||||
    const removedAddressCache = this.makeAddressCache(deletedTransactions);
 | 
					    const removedAddressCache = this.makeAddressCache(deletedTransactions);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // pre-compute acceleration delta
 | 
				
			||||||
 | 
					    const accelerationUpdate = {
 | 
				
			||||||
 | 
					      added: accelerationDelta.map(txid => accelerations[txid]).filter(acc => acc != null),
 | 
				
			||||||
 | 
					      removed: accelerationDelta.filter(txid => !accelerations[txid]),
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // TODO - Fix indentation after PR is merged
 | 
					    // TODO - Fix indentation after PR is merged
 | 
				
			||||||
    for (const server of this.webSocketServers) {
 | 
					    for (const server of this.webSocketServers) {
 | 
				
			||||||
    server.clients.forEach(async (client) => {
 | 
					    server.clients.forEach(async (client) => {
 | 
				
			||||||
@ -891,6 +909,10 @@ class WebsocketHandler {
 | 
				
			|||||||
        response['mempool-transactions'] = getCachedResponse('mempool-transactions', mempoolDelta);
 | 
					        response['mempool-transactions'] = getCachedResponse('mempool-transactions', mempoolDelta);
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      if (client['track-accelerations'] && (accelerationUpdate.added.length || accelerationUpdate.removed.length)) {
 | 
				
			||||||
 | 
					        response['accelerations'] = getCachedResponse('accelerations', accelerationUpdate);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
      if (Object.keys(response).length) {
 | 
					      if (Object.keys(response).length) {
 | 
				
			||||||
        client.send(this.serializeResponse(response));
 | 
					        client.send(this.serializeResponse(response));
 | 
				
			||||||
      }
 | 
					      }
 | 
				
			||||||
 | 
				
			|||||||
@ -1,5 +1,5 @@
 | 
				
			|||||||
import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef } from '@angular/core';
 | 
					import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy } from '@angular/core';
 | 
				
			||||||
import { combineLatest, BehaviorSubject, Observable, catchError, of, switchMap, tap } from 'rxjs';
 | 
					import { BehaviorSubject, Observable, catchError, of, switchMap, tap } from 'rxjs';
 | 
				
			||||||
import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
 | 
					import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
 | 
				
			||||||
import { StateService } from '../../../services/state.service';
 | 
					import { StateService } from '../../../services/state.service';
 | 
				
			||||||
import { WebsocketService } from '../../../services/websocket.service';
 | 
					import { WebsocketService } from '../../../services/websocket.service';
 | 
				
			||||||
@ -11,7 +11,7 @@ import { ServicesApiServices } from '../../../services/services-api.service';
 | 
				
			|||||||
  styleUrls: ['./accelerations-list.component.scss'],
 | 
					  styleUrls: ['./accelerations-list.component.scss'],
 | 
				
			||||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
					  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class AccelerationsListComponent implements OnInit {
 | 
					export class AccelerationsListComponent implements OnInit, OnDestroy {
 | 
				
			||||||
  @Input() widget: boolean = false;
 | 
					  @Input() widget: boolean = false;
 | 
				
			||||||
  @Input() pending: boolean = false;
 | 
					  @Input() pending: boolean = false;
 | 
				
			||||||
  @Input() accelerations$: Observable<Acceleration[]>;
 | 
					  @Input() accelerations$: Observable<Acceleration[]>;
 | 
				
			||||||
@ -44,7 +44,10 @@ export class AccelerationsListComponent implements OnInit {
 | 
				
			|||||||
    
 | 
					    
 | 
				
			||||||
    this.accelerationList$ = this.pageSubject.pipe(
 | 
					    this.accelerationList$ = this.pageSubject.pipe(
 | 
				
			||||||
      switchMap((page) => {
 | 
					      switchMap((page) => {
 | 
				
			||||||
        const accelerationObservable$ = this.accelerations$ || (this.pending ? this.servicesApiService.getAccelerations$() : this.servicesApiService.getAccelerationHistoryObserveResponse$({ page: page }));
 | 
					        const accelerationObservable$ = this.accelerations$ || (this.pending ? this.stateService.liveAccelerations$ : this.servicesApiService.getAccelerationHistoryObserveResponse$({ page: page }));
 | 
				
			||||||
 | 
					        if (!this.accelerations$ && this.pending) {
 | 
				
			||||||
 | 
					          this.websocketService.ensureTrackAccelerations();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return accelerationObservable$.pipe(
 | 
					        return accelerationObservable$.pipe(
 | 
				
			||||||
          switchMap(response => {
 | 
					          switchMap(response => {
 | 
				
			||||||
            let accelerations = response;
 | 
					            let accelerations = response;
 | 
				
			||||||
@ -85,4 +88,8 @@ export class AccelerationsListComponent implements OnInit {
 | 
				
			|||||||
  trackByBlock(index: number, block: BlockExtended): number {
 | 
					  trackByBlock(index: number, block: BlockExtended): number {
 | 
				
			||||||
    return block.height;
 | 
					    return block.height;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnDestroy(): void {
 | 
				
			||||||
 | 
					    this.websocketService.stopTrackAccelerations();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -1,10 +1,10 @@
 | 
				
			|||||||
import { ChangeDetectionStrategy, Component, HostListener, Inject, OnInit, PLATFORM_ID } from '@angular/core';
 | 
					import { ChangeDetectionStrategy, Component, HostListener, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core';
 | 
				
			||||||
import { SeoService } from '../../../services/seo.service';
 | 
					import { SeoService } from '../../../services/seo.service';
 | 
				
			||||||
import { OpenGraphService } from '../../../services/opengraph.service';
 | 
					import { OpenGraphService } from '../../../services/opengraph.service';
 | 
				
			||||||
import { WebsocketService } from '../../../services/websocket.service';
 | 
					import { WebsocketService } from '../../../services/websocket.service';
 | 
				
			||||||
import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
 | 
					import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface';
 | 
				
			||||||
import { StateService } from '../../../services/state.service';
 | 
					import { StateService } from '../../../services/state.service';
 | 
				
			||||||
import { Observable, catchError, combineLatest, distinctUntilChanged, interval, map, of, share, startWith, switchMap, tap } from 'rxjs';
 | 
					import { Observable, Subscription, catchError, combineLatest, distinctUntilChanged, map, of, share, switchMap, tap } from 'rxjs';
 | 
				
			||||||
import { Color } from '../../block-overview-graph/sprite-types';
 | 
					import { Color } from '../../block-overview-graph/sprite-types';
 | 
				
			||||||
import { hexToColor } from '../../block-overview-graph/utils';
 | 
					import { hexToColor } from '../../block-overview-graph/utils';
 | 
				
			||||||
import TxView from '../../block-overview-graph/tx-view';
 | 
					import TxView from '../../block-overview-graph/tx-view';
 | 
				
			||||||
@ -28,7 +28,7 @@ interface AccelerationBlock extends BlockExtended {
 | 
				
			|||||||
  styleUrls: ['./accelerator-dashboard.component.scss'],
 | 
					  styleUrls: ['./accelerator-dashboard.component.scss'],
 | 
				
			||||||
  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
					  changeDetection: ChangeDetectionStrategy.OnPush,
 | 
				
			||||||
})
 | 
					})
 | 
				
			||||||
export class AcceleratorDashboardComponent implements OnInit {
 | 
					export class AcceleratorDashboardComponent implements OnInit, OnDestroy {
 | 
				
			||||||
  blocks$: Observable<AccelerationBlock[]>;
 | 
					  blocks$: Observable<AccelerationBlock[]>;
 | 
				
			||||||
  accelerations$: Observable<Acceleration[]>;
 | 
					  accelerations$: Observable<Acceleration[]>;
 | 
				
			||||||
  pendingAccelerations$: Observable<Acceleration[]>;
 | 
					  pendingAccelerations$: Observable<Acceleration[]>;
 | 
				
			||||||
@ -39,6 +39,8 @@ export class AcceleratorDashboardComponent implements OnInit {
 | 
				
			|||||||
  firstLoad = true;
 | 
					  firstLoad = true;
 | 
				
			||||||
  timespan: '3d' | '1w' | '1m' = '1w';
 | 
					  timespan: '3d' | '1w' | '1m' = '1w';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  accelerationDeltaSubscription: Subscription;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  graphHeight: number = 300;
 | 
					  graphHeight: number = 300;
 | 
				
			||||||
  theme: ThemeService;
 | 
					  theme: ThemeService;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -59,27 +61,28 @@ export class AcceleratorDashboardComponent implements OnInit {
 | 
				
			|||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
    this.onResize();
 | 
					    this.onResize();
 | 
				
			||||||
    this.websocketService.want(['blocks', 'mempool-blocks', 'stats']);
 | 
					    this.websocketService.want(['blocks', 'mempool-blocks', 'stats']);
 | 
				
			||||||
 | 
					    this.websocketService.startTrackAccelerations();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.pendingAccelerations$ = (this.stateService.isBrowser ? interval(30000) : of(null)).pipe(
 | 
					    this.pendingAccelerations$ = this.stateService.liveAccelerations$.pipe(
 | 
				
			||||||
      startWith(true),
 | 
					 | 
				
			||||||
      switchMap(() => {
 | 
					 | 
				
			||||||
        return this.serviceApiServices.getAccelerations$().pipe(
 | 
					 | 
				
			||||||
          catchError(() => {
 | 
					 | 
				
			||||||
            return of([]);
 | 
					 | 
				
			||||||
          }),
 | 
					 | 
				
			||||||
        );
 | 
					 | 
				
			||||||
      }),
 | 
					 | 
				
			||||||
      tap(accelerations => {
 | 
					 | 
				
			||||||
        if (!this.firstLoad && accelerations.some(acc => !this.seen.has(acc.txid))) {
 | 
					 | 
				
			||||||
          this.audioService.playSound('bright-harmony');
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        for(const acc of accelerations) {
 | 
					 | 
				
			||||||
          this.seen.add(acc.txid);
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
        this.firstLoad = false;
 | 
					 | 
				
			||||||
      }),
 | 
					 | 
				
			||||||
      share(),
 | 
					      share(),
 | 
				
			||||||
    );
 | 
					    );
 | 
				
			||||||
 | 
					    this.accelerationDeltaSubscription = this.stateService.accelerations$.subscribe((delta) => {
 | 
				
			||||||
 | 
					      if (!delta.reset) {
 | 
				
			||||||
 | 
					        let hasNewAcceleration = false;
 | 
				
			||||||
 | 
					        for (const acc of delta.added) {
 | 
				
			||||||
 | 
					          if (!this.seen.has(acc.txid)) {
 | 
				
			||||||
 | 
					            hasNewAcceleration = true;
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					          this.seen.add(acc.txid);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (const txid of delta.removed) {
 | 
				
			||||||
 | 
					          this.seen.delete(txid);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        if (hasNewAcceleration) {
 | 
				
			||||||
 | 
					          this.audioService.playSound('bright-harmony');
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.accelerations$ = this.stateService.chainTip$.pipe(
 | 
					    this.accelerations$ = this.stateService.chainTip$.pipe(
 | 
				
			||||||
      distinctUntilChanged(),
 | 
					      distinctUntilChanged(),
 | 
				
			||||||
@ -154,6 +157,11 @@ export class AcceleratorDashboardComponent implements OnInit {
 | 
				
			|||||||
    return false;
 | 
					    return false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ngOnDestroy(): void {
 | 
				
			||||||
 | 
					    this.accelerationDeltaSubscription.unsubscribe();
 | 
				
			||||||
 | 
					    this.websocketService.stopTrackAccelerations();
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  @HostListener('window:resize', ['$event'])
 | 
					  @HostListener('window:resize', ['$event'])
 | 
				
			||||||
  onResize(): void {
 | 
					  onResize(): void {
 | 
				
			||||||
    if (window.innerWidth >= 992) {
 | 
					    if (window.innerWidth >= 992) {
 | 
				
			||||||
 | 
				
			|||||||
@ -2,7 +2,8 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core
 | 
				
			|||||||
import { Observable, of } from 'rxjs';
 | 
					import { Observable, of } from 'rxjs';
 | 
				
			||||||
import { switchMap } from 'rxjs/operators';
 | 
					import { switchMap } from 'rxjs/operators';
 | 
				
			||||||
import { Acceleration } from '../../../interfaces/node-api.interface';
 | 
					import { Acceleration } from '../../../interfaces/node-api.interface';
 | 
				
			||||||
import { ServicesApiServices } from '../../../services/services-api.service';
 | 
					import { StateService } from '../../../services/state.service';
 | 
				
			||||||
 | 
					import { WebsocketService } from '../../../services/websocket.service';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@Component({
 | 
					@Component({
 | 
				
			||||||
  selector: 'app-pending-stats',
 | 
					  selector: 'app-pending-stats',
 | 
				
			||||||
@ -15,11 +16,12 @@ export class PendingStatsComponent implements OnInit {
 | 
				
			|||||||
  public accelerationStats$: Observable<any>;
 | 
					  public accelerationStats$: Observable<any>;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  constructor(
 | 
					  constructor(
 | 
				
			||||||
    private servicesApiService: ServicesApiServices,
 | 
					    private stateService: StateService,
 | 
				
			||||||
 | 
					    private websocketService: WebsocketService,
 | 
				
			||||||
  ) { }
 | 
					  ) { }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  ngOnInit(): void {
 | 
					  ngOnInit(): void {
 | 
				
			||||||
    this.accelerationStats$ = (this.accelerations$ || this.servicesApiService.getAccelerations$()).pipe(
 | 
					    this.accelerationStats$ = (this.accelerations$ || this.stateService.liveAccelerations$).pipe(
 | 
				
			||||||
      switchMap(accelerations => {
 | 
					      switchMap(accelerations => {
 | 
				
			||||||
        let totalAccelerations = 0;
 | 
					        let totalAccelerations = 0;
 | 
				
			||||||
        let totalFeeDelta = 0;
 | 
					        let totalFeeDelta = 0;
 | 
				
			||||||
 | 
				
			|||||||
@ -1,7 +1,7 @@
 | 
				
			|||||||
import { SafeResourceUrl } from '@angular/platform-browser';
 | 
					import { SafeResourceUrl } from '@angular/platform-browser';
 | 
				
			||||||
import { ILoadingIndicators } from '../services/state.service';
 | 
					import { ILoadingIndicators } from '../services/state.service';
 | 
				
			||||||
import { Transaction } from './electrs.interface';
 | 
					import { Transaction } from './electrs.interface';
 | 
				
			||||||
import { BlockExtended, DifficultyAdjustment, RbfTree, TransactionStripped } from './node-api.interface';
 | 
					import { Acceleration, BlockExtended, DifficultyAdjustment, RbfTree, TransactionStripped } from './node-api.interface';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface WebsocketResponse {
 | 
					export interface WebsocketResponse {
 | 
				
			||||||
  backend?: 'esplora' | 'electrum' | 'none';
 | 
					  backend?: 'esplora' | 'electrum' | 'none';
 | 
				
			||||||
@ -35,6 +35,7 @@ export interface WebsocketResponse {
 | 
				
			|||||||
  'track-mempool-block'?: number;
 | 
					  'track-mempool-block'?: number;
 | 
				
			||||||
  'track-rbf'?: string;
 | 
					  'track-rbf'?: string;
 | 
				
			||||||
  'track-rbf-summary'?: boolean;
 | 
					  'track-rbf-summary'?: boolean;
 | 
				
			||||||
 | 
					  'track-accelerations'?: boolean;
 | 
				
			||||||
  'watch-mempool'?: boolean;
 | 
					  'watch-mempool'?: boolean;
 | 
				
			||||||
  'refresh-blocks'?: boolean;
 | 
					  'refresh-blocks'?: boolean;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
@ -92,6 +93,12 @@ export interface MempoolBlockDeltaCompressed {
 | 
				
			|||||||
  changed: MempoolDeltaChange[];
 | 
					  changed: MempoolDeltaChange[];
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					export interface AccelerationDelta {
 | 
				
			||||||
 | 
					  added: Acceleration[];
 | 
				
			||||||
 | 
					  removed: string[];
 | 
				
			||||||
 | 
					  reset?: boolean;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export interface MempoolInfo {
 | 
					export interface MempoolInfo {
 | 
				
			||||||
  loaded: boolean;                 //  (boolean) True if the mempool is fully loaded
 | 
					  loaded: boolean;                 //  (boolean) True if the mempool is fully loaded
 | 
				
			||||||
  size: number;                    //  (numeric) Current tx count
 | 
					  size: number;                    //  (numeric) Current tx count
 | 
				
			||||||
 | 
				
			|||||||
@ -1,8 +1,8 @@
 | 
				
			|||||||
import { Inject, Injectable, PLATFORM_ID, LOCALE_ID } from '@angular/core';
 | 
					import { Inject, Injectable, PLATFORM_ID, LOCALE_ID } from '@angular/core';
 | 
				
			||||||
import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable, merge } from 'rxjs';
 | 
					import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable } from 'rxjs';
 | 
				
			||||||
import { Transaction } from '../interfaces/electrs.interface';
 | 
					import { Transaction } from '../interfaces/electrs.interface';
 | 
				
			||||||
import { HealthCheckHost, IBackendInfo, MempoolBlock, MempoolBlockDelta, MempoolBlockUpdate, MempoolInfo, Recommendedfees, ReplacedTransaction, ReplacementInfo, isMempoolState } from '../interfaces/websocket.interface';
 | 
					import { AccelerationDelta, HealthCheckHost, IBackendInfo, MempoolBlock, MempoolBlockUpdate, MempoolInfo, Recommendedfees, ReplacedTransaction, ReplacementInfo, isMempoolState } from '../interfaces/websocket.interface';
 | 
				
			||||||
import { BlockExtended, CpfpInfo, DifficultyAdjustment, MempoolPosition, OptimizedMempoolStats, RbfTree, TransactionStripped } from '../interfaces/node-api.interface';
 | 
					import { Acceleration, BlockExtended, CpfpInfo, DifficultyAdjustment, MempoolPosition, OptimizedMempoolStats, RbfTree, TransactionStripped } from '../interfaces/node-api.interface';
 | 
				
			||||||
import { Router, NavigationStart } from '@angular/router';
 | 
					import { Router, NavigationStart } from '@angular/router';
 | 
				
			||||||
import { isPlatformBrowser } from '@angular/common';
 | 
					import { isPlatformBrowser } from '@angular/common';
 | 
				
			||||||
import { filter, map, scan, shareReplay } from 'rxjs/operators';
 | 
					import { filter, map, scan, shareReplay } from 'rxjs/operators';
 | 
				
			||||||
@ -129,6 +129,8 @@ export class StateService {
 | 
				
			|||||||
  mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1);
 | 
					  mempoolBlocks$ = new ReplaySubject<MempoolBlock[]>(1);
 | 
				
			||||||
  mempoolBlockUpdate$ = new Subject<MempoolBlockUpdate>();
 | 
					  mempoolBlockUpdate$ = new Subject<MempoolBlockUpdate>();
 | 
				
			||||||
  liveMempoolBlockTransactions$: Observable<{ [txid: string]: TransactionStripped}>;
 | 
					  liveMempoolBlockTransactions$: Observable<{ [txid: string]: TransactionStripped}>;
 | 
				
			||||||
 | 
					  accelerations$ = new Subject<AccelerationDelta>();
 | 
				
			||||||
 | 
					  liveAccelerations$: Observable<Acceleration[]>;
 | 
				
			||||||
  txConfirmed$ = new Subject<[string, BlockExtended]>();
 | 
					  txConfirmed$ = new Subject<[string, BlockExtended]>();
 | 
				
			||||||
  txReplaced$ = new Subject<ReplacedTransaction>();
 | 
					  txReplaced$ = new Subject<ReplacedTransaction>();
 | 
				
			||||||
  txRbfInfo$ = new Subject<RbfTree>();
 | 
					  txRbfInfo$ = new Subject<RbfTree>();
 | 
				
			||||||
@ -238,6 +240,24 @@ export class StateService {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }, {}));
 | 
					    }, {}));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Emits the full list of pending accelerations each time it changes
 | 
				
			||||||
 | 
					    this.liveAccelerations$ = this.accelerations$.pipe(
 | 
				
			||||||
 | 
					      scan((accelerations: { [txid: string]: Acceleration }, delta: AccelerationDelta) => {
 | 
				
			||||||
 | 
					        if (delta.reset) {
 | 
				
			||||||
 | 
					          accelerations = {};
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					          for (const txid of delta.removed) {
 | 
				
			||||||
 | 
					            delete accelerations[txid];
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        for (const acc of delta.added) {
 | 
				
			||||||
 | 
					          accelerations[acc.txid] = acc;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return accelerations;
 | 
				
			||||||
 | 
					      }, {}),
 | 
				
			||||||
 | 
					      map((accMap) => Object.values(accMap).sort((a,b) => b.added - a.added))
 | 
				
			||||||
 | 
					    );
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    this.networkChanged$.subscribe((network) => {
 | 
					    this.networkChanged$.subscribe((network) => {
 | 
				
			||||||
      this.transactions$ = new BehaviorSubject<TransactionStripped[]>(null);
 | 
					      this.transactions$ = new BehaviorSubject<TransactionStripped[]>(null);
 | 
				
			||||||
      this.blocksSubject$.next([]);
 | 
					      this.blocksSubject$.next([]);
 | 
				
			||||||
 | 
				
			|||||||
@ -33,6 +33,7 @@ export class WebsocketService {
 | 
				
			|||||||
  private isTrackingRbfSummary = false;
 | 
					  private isTrackingRbfSummary = false;
 | 
				
			||||||
  private isTrackingAddress: string | false = false;
 | 
					  private isTrackingAddress: string | false = false;
 | 
				
			||||||
  private isTrackingAddresses: string[] | false = false;
 | 
					  private isTrackingAddresses: string[] | false = false;
 | 
				
			||||||
 | 
					  private isTrackingAccelerations: boolean = false;
 | 
				
			||||||
  private trackingMempoolBlock: number;
 | 
					  private trackingMempoolBlock: number;
 | 
				
			||||||
  private latestGitCommit = '';
 | 
					  private latestGitCommit = '';
 | 
				
			||||||
  private onlineCheckTimeout: number;
 | 
					  private onlineCheckTimeout: number;
 | 
				
			||||||
@ -132,6 +133,9 @@ export class WebsocketService {
 | 
				
			|||||||
          if (this.isTrackingAddresses) {
 | 
					          if (this.isTrackingAddresses) {
 | 
				
			||||||
            this.startTrackAddresses(this.isTrackingAddresses);
 | 
					            this.startTrackAddresses(this.isTrackingAddresses);
 | 
				
			||||||
          }
 | 
					          }
 | 
				
			||||||
 | 
					          if (this.isTrackingAccelerations) {
 | 
				
			||||||
 | 
					            this.startTrackAccelerations();
 | 
				
			||||||
 | 
					          }
 | 
				
			||||||
          this.stateService.connectionState$.next(2);
 | 
					          this.stateService.connectionState$.next(2);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -235,6 +239,24 @@ export class WebsocketService {
 | 
				
			|||||||
    this.isTrackingRbfSummary = false;
 | 
					    this.isTrackingRbfSummary = false;
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  startTrackAccelerations() {
 | 
				
			||||||
 | 
					    this.websocketSubject.next({ 'track-accelerations': true });
 | 
				
			||||||
 | 
					    this.isTrackingAccelerations = true;
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  stopTrackAccelerations() {
 | 
				
			||||||
 | 
					    if (this.isTrackingAccelerations) {
 | 
				
			||||||
 | 
					      this.websocketSubject.next({ 'track-accelerations': false });
 | 
				
			||||||
 | 
					      this.isTrackingAccelerations = false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  ensureTrackAccelerations() {
 | 
				
			||||||
 | 
					    if (!this.isTrackingAccelerations) {
 | 
				
			||||||
 | 
					      this.startTrackAccelerations();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
  fetchStatistics(historicalDate: string) {
 | 
					  fetchStatistics(historicalDate: string) {
 | 
				
			||||||
    this.websocketSubject.next({ historicalDate });
 | 
					    this.websocketSubject.next({ historicalDate });
 | 
				
			||||||
  }
 | 
					  }
 | 
				
			||||||
@ -416,6 +438,18 @@ export class WebsocketService {
 | 
				
			|||||||
      }
 | 
					      }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    if (response['accelerations']) {
 | 
				
			||||||
 | 
					      if (response['accelerations'].accelerations) {
 | 
				
			||||||
 | 
					        this.stateService.accelerations$.next({
 | 
				
			||||||
 | 
					          added: response['accelerations'].accelerations,
 | 
				
			||||||
 | 
					          removed: [],
 | 
				
			||||||
 | 
					          reset: true,
 | 
				
			||||||
 | 
					        });
 | 
				
			||||||
 | 
					      } else {
 | 
				
			||||||
 | 
					        this.stateService.accelerations$.next(response['accelerations']);
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    if (response['live-2h-chart']) {
 | 
					    if (response['live-2h-chart']) {
 | 
				
			||||||
      this.stateService.live2Chart$.next(response['live-2h-chart']);
 | 
					      this.stateService.live2Chart$.next(response['live-2h-chart']);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user