mirror of
https://github.com/mempool/mempool.git
synced 2025-01-05 21:24:27 +01:00
Merge pull request #474 from mempool/simon/bitcoind-tx-push-break-fix
Fix crash issues related to new unconfirmed transactions in bitcoind …
This commit is contained in:
commit
1000f4dd4d
@ -147,6 +147,9 @@ class BitcoinApi implements AbstractBitcoinApi {
|
|||||||
esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, addPrevout);
|
esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, addPrevout);
|
||||||
} else {
|
} else {
|
||||||
esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction);
|
esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction);
|
||||||
|
if (addPrevout) {
|
||||||
|
esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, addPrevout);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return esploraTransaction;
|
return esploraTransaction;
|
||||||
|
@ -34,7 +34,7 @@ class WebsocketHandler {
|
|||||||
|
|
||||||
this.wss.on('connection', (client: WebSocket) => {
|
this.wss.on('connection', (client: WebSocket) => {
|
||||||
client.on('error', logger.info);
|
client.on('error', logger.info);
|
||||||
client.on('message', (message: string) => {
|
client.on('message', async (message: string) => {
|
||||||
try {
|
try {
|
||||||
const parsedMessage: WebsocketResponse = JSON.parse(message);
|
const parsedMessage: WebsocketResponse = JSON.parse(message);
|
||||||
const response = {};
|
const response = {};
|
||||||
@ -53,7 +53,16 @@ class WebsocketHandler {
|
|||||||
if (parsedMessage['watch-mempool']) {
|
if (parsedMessage['watch-mempool']) {
|
||||||
const tx = memPool.getMempool()[client['track-tx']];
|
const tx = memPool.getMempool()[client['track-tx']];
|
||||||
if (tx) {
|
if (tx) {
|
||||||
response['tx'] = tx;
|
if (config.MEMPOOL.BACKEND !== 'esplora') {
|
||||||
|
try {
|
||||||
|
const fullTx = await transactionUtils.$getTransactionExtended(tx.txid, true);
|
||||||
|
response['tx'] = fullTx;
|
||||||
|
} catch (e) {
|
||||||
|
logger.debug('Error finding transaction in mempool: ' + e.message || e);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
response['tx'] = tx;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
client['track-mempool-tx'] = parsedMessage['track-tx'];
|
client['track-mempool-tx'] = parsedMessage['track-tx'];
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
import { Component, OnInit, OnDestroy } from '@angular/core';
|
import { Component, OnInit, OnDestroy } from '@angular/core';
|
||||||
import { ElectrsApiService } from '../../services/electrs-api.service';
|
import { ElectrsApiService } from '../../services/electrs-api.service';
|
||||||
import { ActivatedRoute, ParamMap } from '@angular/router';
|
import { ActivatedRoute, ParamMap } from '@angular/router';
|
||||||
import { switchMap, filter, catchError } from 'rxjs/operators';
|
import { switchMap, filter, catchError, retryWhen, delay } from 'rxjs/operators';
|
||||||
import { Transaction, Block } from '../../interfaces/electrs.interface';
|
import { Transaction, Block } from '../../interfaces/electrs.interface';
|
||||||
import { of, merge, Subscription, Observable } from 'rxjs';
|
import { of, merge, Subscription, Observable, Subject } from 'rxjs';
|
||||||
import { StateService } from '../../services/state.service';
|
import { StateService } from '../../services/state.service';
|
||||||
import { WebsocketService } from '../../services/websocket.service';
|
import { WebsocketService } from '../../services/websocket.service';
|
||||||
import { AudioService } from 'src/app/services/audio.service';
|
import { AudioService } from 'src/app/services/audio.service';
|
||||||
@ -27,9 +27,11 @@ export class TransactionComponent implements OnInit, OnDestroy {
|
|||||||
latestBlock: Block;
|
latestBlock: Block;
|
||||||
transactionTime = -1;
|
transactionTime = -1;
|
||||||
subscription: Subscription;
|
subscription: Subscription;
|
||||||
|
fetchCpfpSubscription: Subscription;
|
||||||
rbfTransaction: undefined | Transaction;
|
rbfTransaction: undefined | Transaction;
|
||||||
cpfpInfo: CpfpInfo | null;
|
cpfpInfo: CpfpInfo | null;
|
||||||
showCpfpDetails = false;
|
showCpfpDetails = false;
|
||||||
|
fetchCpfp$ = new Subject<string>();
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
private route: ActivatedRoute,
|
private route: ActivatedRoute,
|
||||||
@ -99,28 +101,14 @@ export class TransactionComponent implements OnInit, OnDestroy {
|
|||||||
if (this.tx.status.confirmed) {
|
if (this.tx.status.confirmed) {
|
||||||
this.stateService.markBlock$.next({ blockHeight: tx.status.block_height });
|
this.stateService.markBlock$.next({ blockHeight: tx.status.block_height });
|
||||||
} else {
|
} else {
|
||||||
if (tx.effectiveFeePerVsize) {
|
if (tx.cpfpChecked) {
|
||||||
this.stateService.markBlock$.next({ txFeePerVSize: tx.effectiveFeePerVsize });
|
this.stateService.markBlock$.next({ txFeePerVSize: tx.effectiveFeePerVsize });
|
||||||
this.cpfpInfo = {
|
this.cpfpInfo = {
|
||||||
ancestors: tx.ancestors,
|
ancestors: tx.ancestors,
|
||||||
bestDescendant: tx.bestDescendant,
|
bestDescendant: tx.bestDescendant,
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
this.apiService.getCpfpinfo$(this.tx.txid)
|
this.fetchCpfp$.next(this.tx.txid);
|
||||||
.subscribe((cpfpInfo) => {
|
|
||||||
const lowerFeeParents = cpfpInfo.ancestors.filter((parent) => (parent.fee / (parent.weight / 4)) < tx.feePerVsize);
|
|
||||||
let totalWeight = tx.weight + lowerFeeParents.reduce((prev, val) => prev + val.weight, 0);
|
|
||||||
let totalFees = tx.fee + lowerFeeParents.reduce((prev, val) => prev + val.fee, 0);
|
|
||||||
|
|
||||||
if (cpfpInfo.bestDescendant) {
|
|
||||||
totalWeight += cpfpInfo.bestDescendant.weight;
|
|
||||||
totalFees += cpfpInfo.bestDescendant.fee;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4);
|
|
||||||
this.stateService.markBlock$.next({ txFeePerVSize: this.tx.effectiveFeePerVsize });
|
|
||||||
this.cpfpInfo = cpfpInfo;
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -129,6 +117,32 @@ export class TransactionComponent implements OnInit, OnDestroy {
|
|||||||
this.isLoadingTx = false;
|
this.isLoadingTx = false;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.fetchCpfpSubscription = this.fetchCpfp$
|
||||||
|
.pipe(
|
||||||
|
switchMap((txId) => this.apiService.getCpfpinfo$(txId)
|
||||||
|
.pipe(
|
||||||
|
retryWhen((errors) => errors.pipe(delay(2000)))
|
||||||
|
)
|
||||||
|
),
|
||||||
|
)
|
||||||
|
.subscribe((cpfpInfo) => {
|
||||||
|
if (!this.tx) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const lowerFeeParents = cpfpInfo.ancestors.filter((parent) => (parent.fee / (parent.weight / 4)) < this.tx.feePerVsize);
|
||||||
|
let totalWeight = this.tx.weight + lowerFeeParents.reduce((prev, val) => prev + val.weight, 0);
|
||||||
|
let totalFees = this.tx.fee + lowerFeeParents.reduce((prev, val) => prev + val.fee, 0);
|
||||||
|
|
||||||
|
if (cpfpInfo.bestDescendant) {
|
||||||
|
totalWeight += cpfpInfo.bestDescendant.weight;
|
||||||
|
totalFees += cpfpInfo.bestDescendant.fee;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.tx.effectiveFeePerVsize = totalFees / (totalWeight / 4);
|
||||||
|
this.stateService.markBlock$.next({ txFeePerVSize: this.tx.effectiveFeePerVsize });
|
||||||
|
this.cpfpInfo = cpfpInfo;
|
||||||
|
});
|
||||||
|
|
||||||
this.stateService.blocks$
|
this.stateService.blocks$
|
||||||
.subscribe(([block, txConfirmed]) => {
|
.subscribe(([block, txConfirmed]) => {
|
||||||
this.latestBlock = block;
|
this.latestBlock = block;
|
||||||
@ -209,6 +223,7 @@ export class TransactionComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
ngOnDestroy() {
|
ngOnDestroy() {
|
||||||
this.subscription.unsubscribe();
|
this.subscription.unsubscribe();
|
||||||
|
this.fetchCpfpSubscription.unsubscribe();
|
||||||
this.leaveTransaction();
|
this.leaveTransaction();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user