Send cpfp/effective fee rate changes to subscribed ws clients
This commit is contained in:
@@ -161,34 +161,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
})
|
||||
)
|
||||
.subscribe((cpfpInfo) => {
|
||||
if (!cpfpInfo || !this.tx) {
|
||||
this.cpfpInfo = null;
|
||||
this.hasEffectiveFeeRate = false;
|
||||
return;
|
||||
}
|
||||
// merge ancestors/descendants
|
||||
const relatives = [...(cpfpInfo.ancestors || []), ...(cpfpInfo.descendants || [])];
|
||||
if (cpfpInfo.bestDescendant && !cpfpInfo.descendants?.length) {
|
||||
relatives.push(cpfpInfo.bestDescendant);
|
||||
}
|
||||
const hasRelatives = !!relatives.length;
|
||||
if (!cpfpInfo.effectiveFeePerVsize && hasRelatives) {
|
||||
let totalWeight =
|
||||
this.tx.weight +
|
||||
relatives.reduce((prev, val) => prev + val.weight, 0);
|
||||
let totalFees =
|
||||
this.tx.fee +
|
||||
relatives.reduce((prev, val) => prev + val.fee, 0);
|
||||
this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4);
|
||||
} else {
|
||||
this.tx.effectiveFeePerVsize = cpfpInfo.effectiveFeePerVsize;
|
||||
}
|
||||
if (cpfpInfo.acceleration) {
|
||||
this.tx.acceleration = cpfpInfo.acceleration;
|
||||
}
|
||||
|
||||
this.cpfpInfo = cpfpInfo;
|
||||
this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01));
|
||||
this.setCpfpInfo(cpfpInfo);
|
||||
});
|
||||
|
||||
this.fetchRbfSubscription = this.fetchRbfHistory$
|
||||
@@ -259,6 +232,10 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
mempoolPosition: this.mempoolPosition
|
||||
});
|
||||
this.txInBlockIndex = this.mempoolPosition.block;
|
||||
|
||||
if (txPosition.cpfp !== undefined) {
|
||||
this.setCpfpInfo(txPosition.cpfp);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
this.mempoolPosition = null;
|
||||
@@ -507,6 +484,37 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
||||
});
|
||||
}
|
||||
|
||||
setCpfpInfo(cpfpInfo: CpfpInfo): void {
|
||||
if (!cpfpInfo || !this.tx) {
|
||||
this.cpfpInfo = null;
|
||||
this.hasEffectiveFeeRate = false;
|
||||
return;
|
||||
}
|
||||
// merge ancestors/descendants
|
||||
const relatives = [...(cpfpInfo.ancestors || []), ...(cpfpInfo.descendants || [])];
|
||||
if (cpfpInfo.bestDescendant && !cpfpInfo.descendants?.length) {
|
||||
relatives.push(cpfpInfo.bestDescendant);
|
||||
}
|
||||
const hasRelatives = !!relatives.length;
|
||||
if (!cpfpInfo.effectiveFeePerVsize && hasRelatives) {
|
||||
const totalWeight =
|
||||
this.tx.weight +
|
||||
relatives.reduce((prev, val) => prev + val.weight, 0);
|
||||
const totalFees =
|
||||
this.tx.fee +
|
||||
relatives.reduce((prev, val) => prev + val.fee, 0);
|
||||
this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4);
|
||||
} else {
|
||||
this.tx.effectiveFeePerVsize = cpfpInfo.effectiveFeePerVsize;
|
||||
}
|
||||
if (cpfpInfo.acceleration) {
|
||||
this.tx.acceleration = cpfpInfo.acceleration;
|
||||
}
|
||||
|
||||
this.cpfpInfo = cpfpInfo;
|
||||
this.hasEffectiveFeeRate = hasRelatives || (this.tx.effectiveFeePerVsize && (Math.abs(this.tx.effectiveFeePerVsize - this.tx.feePerVsize) > 0.01));
|
||||
}
|
||||
|
||||
setFeatures(): void {
|
||||
if (this.tx) {
|
||||
this.segwitEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'segwit');
|
||||
|
||||
@@ -19,7 +19,7 @@ export interface Transaction {
|
||||
ancestors?: Ancestor[];
|
||||
bestDescendant?: BestDescendant | null;
|
||||
cpfpChecked?: boolean;
|
||||
acceleration?: number;
|
||||
acceleration?: boolean;
|
||||
deleteAfter?: number;
|
||||
_unblinded?: any;
|
||||
_deduced?: boolean;
|
||||
|
||||
@@ -27,7 +27,7 @@ export interface CpfpInfo {
|
||||
effectiveFeePerVsize?: number;
|
||||
sigops?: number;
|
||||
adjustedVsize?: number;
|
||||
acceleration?: number;
|
||||
acceleration?: boolean;
|
||||
}
|
||||
|
||||
export interface RbfInfo {
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Inject, Injectable, PLATFORM_ID, LOCALE_ID } from '@angular/core';
|
||||
import { ReplaySubject, BehaviorSubject, Subject, fromEvent, Observable, merge } from 'rxjs';
|
||||
import { Transaction } from '../interfaces/electrs.interface';
|
||||
import { IBackendInfo, MempoolBlock, MempoolBlockDelta, MempoolInfo, Recommendedfees, ReplacedTransaction, ReplacementInfo, TransactionStripped } from '../interfaces/websocket.interface';
|
||||
import { BlockExtended, DifficultyAdjustment, MempoolPosition, OptimizedMempoolStats, RbfTree } from '../interfaces/node-api.interface';
|
||||
import { BlockExtended, CpfpInfo, DifficultyAdjustment, MempoolPosition, OptimizedMempoolStats, RbfTree } from '../interfaces/node-api.interface';
|
||||
import { Router, NavigationStart } from '@angular/router';
|
||||
import { isPlatformBrowser } from '@angular/common';
|
||||
import { filter, map, scan, shareReplay } from 'rxjs/operators';
|
||||
@@ -113,7 +113,7 @@ export class StateService {
|
||||
utxoSpent$ = new Subject<object>();
|
||||
difficultyAdjustment$ = new ReplaySubject<DifficultyAdjustment>(1);
|
||||
mempoolTransactions$ = new Subject<Transaction>();
|
||||
mempoolTxPosition$ = new Subject<{ txid: string, position: MempoolPosition}>();
|
||||
mempoolTxPosition$ = new Subject<{ txid: string, position: MempoolPosition, cpfp: CpfpInfo | null}>();
|
||||
blockTransactions$ = new Subject<Transaction>();
|
||||
isLoadingWebSocket$ = new ReplaySubject<boolean>(1);
|
||||
isLoadingMempool$ = new BehaviorSubject<boolean>(true);
|
||||
|
||||
Reference in New Issue
Block a user