CPFP support (#395)

* CPFP support.

fixes #5
fixes #353
fixes #360

* Use effectiveFeePerVsize for mempool statistics.

* Renaming endpoint cpfp-info to just cpfp.

* Renaming decended to BestDescendant.

* Updating language file with new strings.
This commit is contained in:
softsimon
2021-03-18 23:47:40 +07:00
committed by GitHub
parent f633adef84
commit 58402c008f
19 changed files with 487 additions and 289 deletions

View File

@@ -40,6 +40,10 @@
<td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/mempool-blocks" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/v1/fees/mempool-blocks</a></td>
<td i18n="api-docs.fees.mempool-blocks|API Docs for /api/v1/fees/mempool-blocks">Returns current mempool as projected blocks.</td>
</tr>
<tr>
<td class="nowrap"><a href="{{ network.val === '' ? '' : '/' + network.val }}/api/v1/cpfp/TXID" target="_blank">GET {{ network.val === '' ? '' : '/' + network.val }}/api/v1/cpfp/:txid</a></td>
<td i18n="api-docs.fees.cpfp|API Docs for /api/v1/fees/cpfp">Returns the ancestors and the best descendant fees for a transaction.</td>
</tr>
</table>
</ng-template>

View File

@@ -73,22 +73,7 @@
</table>
</div>
<div class="col-sm">
<table class="table table-borderless table-striped">
<tbody>
<tr>
<td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td>
<td>{{ tx.fee | number }} <span i18n="transaction.fee.sat|Transaction Fee sat">sat</span> (<app-fiat [value]="tx.fee"></app-fiat>)</td>
</tr>
<tr>
<td i18n="transaction.fee-per-vbyte|Transaction fee">Fee per vByte</td>
<td>
{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
&nbsp;
<app-tx-fee-rating *ngIf="tx.fee" [tx]="tx"></app-tx-fee-rating>
</td>
</tr>
</tbody>
</table>
<ng-container *ngTemplateOutlet="feeTable"></ng-container>
</div>
</div>
@@ -146,18 +131,7 @@
</table>
</div>
<div class="col-sm">
<table class="table table-borderless table-striped">
<tbody>
<tr>
<td class="td-width" i18n="transaction.fee|Transaction Fee">Fee</td>
<td>{{ tx.fee | number }} <span i18n="transaction.fee.sat|Transaction Fee sat">sat</span> (<app-fiat [value]="tx.fee"></app-fiat>)</td>
</tr>
<tr>
<td i18n="transaction.fee-per-vbyte|Transaction fee">Fee per vByte</td>
<td>{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span></td>
</tr>
</tbody>
</table>
<ng-container *ngTemplateOutlet="feeTable"></ng-container>
</div>
</div>
</div>
@@ -295,4 +269,36 @@
<ng-template let-i #nextBlockEta i18n="mempool-blocks.eta-of-next-block|Block Frequency">In ~{{ i }} minute</ng-template>
<ng-template #blocksSingular let-i i18n="shared.block">{{ i }} block</ng-template>
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} blocks</ng-template>
<ng-template #blocksPlural let-i i18n="shared.blocks">{{ i }} blocks</ng-template>
<ng-template #feeTable>
<table class="table table-borderless table-striped">
<tbody>
<tr>
<td class="td-width" i18n="transaction.fee|Transaction fee">Fee</td>
<td>{{ tx.fee | number }} <span i18n="transaction.fee.sat|Transaction Fee sat">sat</span> (<app-fiat [value]="tx.fee"></app-fiat>)</td>
</tr>
<tr>
<td i18n="transaction.fee-per-vbyte|Transaction fee">Fee per vByte</td>
<td>
{{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
<ng-template [ngIf]="tx.status.confirmed">
&nbsp;
<app-tx-fee-rating *ngIf="tx.fee && (!tx.effectiveFeePerVsize || tx.effectiveFeePerVsize === tx.fee / (tx.weight / 4))" [tx]="tx"></app-tx-fee-rating>
</ng-template>
</td>
</tr>
<tr *ngIf="tx.effectiveFeePerVsize && tx.effectiveFeePerVsize !== tx.fee / (tx.weight / 4)">
<td i18n="transaction.effective-fee|Effective transaction fee">Effective fee</td>
<td>
{{ tx.effectiveFeePerVsize | number : '1.1-1' }} <span i18n="shared.sat-vbyte|sat/vB">sat/vB</span>
<ng-template [ngIf]="tx.status.confirmed">
&nbsp;
<app-tx-fee-rating *ngIf="tx.fee" [tx]="tx"></app-tx-fee-rating>
</ng-template>
</td>
</tr>
</tbody>
</table>
</ng-template>

View File

@@ -91,10 +91,28 @@ export class TransactionComponent implements OnInit, OnDestroy {
this.getTransactionTime();
}
}
if (this.tx.status.confirmed) {
this.stateService.markBlock$.next({ blockHeight: tx.status.block_height });
} else {
this.stateService.markBlock$.next({ txFeePerVSize: tx.fee / (tx.weight / 4) });
if (tx.effectiveFeePerVsize) {
this.stateService.markBlock$.next({ txFeePerVSize: tx.effectiveFeePerVsize });
} else {
this.apiService.getCpfpinfo$(this.tx.txid)
.subscribe((cpfpInfo) => {
let totalWeight = tx.weight + cpfpInfo.ancestors.reduce((prev, val) => prev + val.weight, 0);
let totalFees = tx.fee + cpfpInfo.ancestors.reduce((prev, val) => prev + val.fee, 0);
if (cpfpInfo.bestDescendant) {
totalWeight += cpfpInfo.bestDescendant.weight;
totalFees += cpfpInfo.bestDescendant.fee;
}
const effectiveFeePerVsize = totalFees / (totalWeight / 4);
this.tx.effectiveFeePerVsize = effectiveFeePerVsize;
this.stateService.markBlock$.next({ txFeePerVSize: effectiveFeePerVsize });
});
}
}
},
(error) => {
@@ -139,7 +157,7 @@ export class TransactionComponent implements OnInit, OnDestroy {
return;
}
const txFeePerVSize = this.tx.fee / (this.tx.weight / 4);
const txFeePerVSize = this.tx.effectiveFeePerVsize || this.tx.fee / (this.tx.weight / 4);
for (const block of mempoolBlocks) {
for (let i = 0; i < block.feeRange.length - 1; i++) {

View File

@@ -52,7 +52,7 @@ export class TxFeeRatingComponent implements OnInit, OnChanges, OnDestroy {
}
calculateRatings(block: Block) {
const feePervByte = this.tx.fee / (this.tx.weight / 4);
const feePervByte = this.tx.effectiveFeePerVsize || this.tx.fee / (this.tx.weight / 4);
this.medianFeeNeeded = block.medianFee;
// Block not filled