Merge pull request #5245 from mempool/mononaut/no-replaceable-inputs
don't accelerate txs with replaceable inputs
This commit is contained in:
commit
a86709d7b0
@ -122,7 +122,7 @@
|
|||||||
<span class="explainer"> </span>
|
<span class="explainer"> </span>
|
||||||
} @else if (showAccelerationSummary) {
|
} @else if (showAccelerationSummary) {
|
||||||
<ng-container *ngIf="(ETA$ | async) as eta;">
|
<ng-container *ngIf="(ETA$ | async) as eta;">
|
||||||
<app-accelerate-checkout *ngIf="(da$ | async) as da;" [cashappEnabled]="accelerationEligible" [advancedEnabled]="false" [forceMobile]="true" [tx]="tx" [miningStats]="miningStats" [eta]="eta" [scrollEvent]="scrollIntoAccelPreview" class="h-100 w-100"></app-accelerate-checkout>
|
<app-accelerate-checkout *ngIf="(da$ | async) as da;" [cashappEnabled]="cashappEligible" [advancedEnabled]="false" [forceMobile]="true" [tx]="tx" [miningStats]="miningStats" [eta]="eta" [scrollEvent]="scrollIntoAccelPreview" class="h-100 w-100"></app-accelerate-checkout>
|
||||||
</ng-container>
|
</ng-container>
|
||||||
} @else {
|
} @else {
|
||||||
@if (tx?.acceleration && !tx.status?.confirmed) {
|
@if (tx?.acceleration && !tx.status?.confirmed) {
|
||||||
|
@ -21,7 +21,7 @@ import { AudioService } from '../../services/audio.service';
|
|||||||
import { ApiService } from '../../services/api.service';
|
import { ApiService } from '../../services/api.service';
|
||||||
import { SeoService } from '../../services/seo.service';
|
import { SeoService } from '../../services/seo.service';
|
||||||
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { Filter } from '../../shared/filters.utils';
|
import { Filter, TransactionFlags } from '../../shared/filters.utils';
|
||||||
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment, Acceleration, AccelerationPosition } from '../../interfaces/node-api.interface';
|
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment, Acceleration, AccelerationPosition } from '../../interfaces/node-api.interface';
|
||||||
import { PriceService } from '../../services/price.service';
|
import { PriceService } from '../../services/price.service';
|
||||||
import { ServicesApiServices } from '../../services/services-api.service';
|
import { ServicesApiServices } from '../../services/services-api.service';
|
||||||
@ -30,7 +30,7 @@ import { ZONE_SERVICE } from '../../injection-tokens';
|
|||||||
import { TrackerStage } from './tracker-bar.component';
|
import { TrackerStage } from './tracker-bar.component';
|
||||||
import { MiningService, MiningStats } from '../../services/mining.service';
|
import { MiningService, MiningStats } from '../../services/mining.service';
|
||||||
import { ETA, EtaService } from '../../services/eta.service';
|
import { ETA, EtaService } from '../../services/eta.service';
|
||||||
import { getUnacceleratedFeeRate } from '../../shared/transaction.utils';
|
import { getTransactionFlags, getUnacceleratedFeeRate } from '../../shared/transaction.utils';
|
||||||
|
|
||||||
interface Pool {
|
interface Pool {
|
||||||
id: number;
|
id: number;
|
||||||
@ -117,8 +117,7 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
hasEffectiveFeeRate: boolean;
|
hasEffectiveFeeRate: boolean;
|
||||||
accelerateCtaType: 'alert' | 'button' = 'button';
|
accelerateCtaType: 'alert' | 'button' = 'button';
|
||||||
acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR && this.stateService.network === '';
|
acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR && this.stateService.network === '';
|
||||||
accelerationEligible: boolean = false;
|
eligibleForAcceleration: boolean = false;
|
||||||
showAccelerationSummary = false;
|
|
||||||
accelerationFlowCompleted = false;
|
accelerationFlowCompleted = false;
|
||||||
scrollIntoAccelPreview = false;
|
scrollIntoAccelPreview = false;
|
||||||
auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true;
|
auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true;
|
||||||
@ -155,11 +154,6 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
this.miningStats = stats;
|
this.miningStats = stats;
|
||||||
});
|
});
|
||||||
|
|
||||||
const urlParams = new URLSearchParams(window.location.search);
|
|
||||||
if (urlParams.get('cash_request_id')) {
|
|
||||||
this.showAccelerationSummary = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.enterpriseService.page();
|
this.enterpriseService.page();
|
||||||
|
|
||||||
this.enterpriseInfo$ = this.enterpriseService.info$.subscribe(info => {
|
this.enterpriseInfo$ = this.enterpriseService.info$.subscribe(info => {
|
||||||
@ -267,6 +261,7 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
|
|
||||||
if (!this.tx) {
|
if (!this.tx) {
|
||||||
this.tx = tx;
|
this.tx = tx;
|
||||||
|
this.checkAccelerationEligibility();
|
||||||
this.isCached = true;
|
this.isCached = true;
|
||||||
if (tx.fee === undefined) {
|
if (tx.fee === undefined) {
|
||||||
this.tx.fee = 0;
|
this.tx.fee = 0;
|
||||||
@ -385,20 +380,9 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
this.trackerStage = 'replaced';
|
this.trackerStage = 'replaced';
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!this.mempoolPosition.accelerated) {
|
if (this.mempoolPosition.accelerated && this.showAccelerationSummary) {
|
||||||
if (!this.accelerationFlowCompleted && !this.showAccelerationSummary && this.mempoolPosition.block > 0) {
|
|
||||||
this.showAccelerationSummary = true;
|
|
||||||
this.miningService.getMiningStats('1w').subscribe(stats => {
|
|
||||||
this.miningStats = stats;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
if (txPosition.position?.block > 0) {
|
|
||||||
this.accelerationEligible = true;
|
|
||||||
}
|
|
||||||
} else if (this.showAccelerationSummary) {
|
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.accelerationFlowCompleted = true;
|
this.accelerationFlowCompleted = true;
|
||||||
this.showAccelerationSummary = false;
|
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -462,6 +446,7 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
this.seoService.clearSoft404();
|
this.seoService.clearSoft404();
|
||||||
|
|
||||||
this.tx = tx;
|
this.tx = tx;
|
||||||
|
this.checkAccelerationEligibility();
|
||||||
this.isCached = false;
|
this.isCached = false;
|
||||||
if (tx.fee === undefined) {
|
if (tx.fee === undefined) {
|
||||||
this.tx.fee = 0;
|
this.tx.fee = 0;
|
||||||
@ -744,8 +729,9 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
}
|
}
|
||||||
this.enterpriseService.goal(8);
|
this.enterpriseService.goal(8);
|
||||||
this.accelerationFlowCompleted = false;
|
this.accelerationFlowCompleted = false;
|
||||||
this.showAccelerationSummary = true && this.acceleratorAvailable;
|
if (this.showAccelerationSummary) {
|
||||||
this.scrollIntoAccelPreview = true;
|
this.scrollIntoAccelPreview = true;
|
||||||
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -753,6 +739,31 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
return this.isLoadingTx || this.loadingCachedTx || this.loadingPosition;
|
return this.isLoadingTx || this.loadingCachedTx || this.loadingPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkAccelerationEligibility() {
|
||||||
|
if (this.tx) {
|
||||||
|
this.tx.flags = getTransactionFlags(this.tx);
|
||||||
|
const replaceableInputs = (this.tx.flags & (TransactionFlags.sighash_none | TransactionFlags.sighash_acp)) > 0n;
|
||||||
|
const highSigop = (this.tx.sigops * 20) > this.tx.weight;
|
||||||
|
this.eligibleForAcceleration = !replaceableInputs && !highSigop;
|
||||||
|
} else {
|
||||||
|
this.eligibleForAcceleration = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
get cashappEligible(): boolean {
|
||||||
|
return this.mempoolPosition?.block > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
get showAccelerationSummary(): boolean {
|
||||||
|
return (
|
||||||
|
this.tx
|
||||||
|
&& !this.tx.acceleration
|
||||||
|
&& this.acceleratorAvailable
|
||||||
|
&& this.eligibleForAcceleration
|
||||||
|
&& !this.accelerationFlowCompleted
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
resetTransaction() {
|
resetTransaction() {
|
||||||
this.error = undefined;
|
this.error = undefined;
|
||||||
this.tx = null;
|
this.tx = null;
|
||||||
@ -778,7 +789,7 @@ export class TrackerComponent implements OnInit, OnDestroy {
|
|||||||
this.pool = null;
|
this.pool = null;
|
||||||
this.auditStatus = null;
|
this.auditStatus = null;
|
||||||
this.accelerationPositions = null;
|
this.accelerationPositions = null;
|
||||||
this.accelerationEligible = false;
|
this.eligibleForAcceleration = false;
|
||||||
this.trackerStage = 'waiting';
|
this.trackerStage = 'waiting';
|
||||||
document.body.scrollTo(0, 0);
|
document.body.scrollTo(0, 0);
|
||||||
this.leaveTransaction();
|
this.leaveTransaction();
|
||||||
|
@ -147,7 +147,7 @@
|
|||||||
<ng-container *ngIf="(ETA$ | async) as eta;">
|
<ng-container *ngIf="(ETA$ | async) as eta;">
|
||||||
<app-accelerate-checkout
|
<app-accelerate-checkout
|
||||||
*ngIf="(da$ | async) as da;"
|
*ngIf="(da$ | async) as da;"
|
||||||
[cashappEnabled]="accelerationEligible"
|
[cashappEnabled]="cashappEligible"
|
||||||
[advancedEnabled]="true"
|
[advancedEnabled]="true"
|
||||||
[tx]="tx"
|
[tx]="tx"
|
||||||
[eta]="eta"
|
[eta]="eta"
|
||||||
@ -551,18 +551,18 @@
|
|||||||
<td>
|
<td>
|
||||||
<ng-container *ngIf="(ETA$ | async) as eta; else etaSkeleton">
|
<ng-container *ngIf="(ETA$ | async) as eta; else etaSkeleton">
|
||||||
@if (eta.blocks >= 7) {
|
@if (eta.blocks >= 7) {
|
||||||
<span [class]="(!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary) ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''">
|
<span [class]="(!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary && eligibleForAcceleration) ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''">
|
||||||
<span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
|
<span i18n="transaction.eta.in-several-hours|Transaction ETA in several hours or more">In several hours (or more)</span>
|
||||||
@if (!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary) {
|
@if (!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary && eligibleForAcceleration) {
|
||||||
<a class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
<a class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
} @else if (network === 'liquid' || network === 'liquidtestnet') {
|
} @else if (network === 'liquid' || network === 'liquidtestnet') {
|
||||||
<app-time kind="until" [time]="eta.time" [fastRender]="false" [fixedRender]="true"></app-time>
|
<app-time kind="until" [time]="eta.time" [fastRender]="false" [fixedRender]="true"></app-time>
|
||||||
} @else {
|
} @else {
|
||||||
<span [class]="(!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary) ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''">
|
<span [class]="(!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary && eligibleForAcceleration) ? 'etaDeepMempool d-flex justify-content-end align-items-center' : ''">
|
||||||
<app-time kind="until" [time]="eta.time" [fastRender]="false" [fixedRender]="true"></app-time>
|
<app-time kind="until" [time]="eta.time" [fastRender]="false" [fixedRender]="true"></app-time>
|
||||||
@if (!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary) {
|
@if (!tx?.acceleration && acceleratorAvailable && accelerateCtaType === 'button' && !showAccelerationSummary && eligibleForAcceleration) {
|
||||||
<a class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
<a class="btn btn-sm accelerateDeepMempool btn-small-height" i18n="transaction.accelerate|Accelerate button label" (click)="onAccelerateClicked()">Accelerate</a>
|
||||||
}
|
}
|
||||||
</span>
|
</span>
|
||||||
|
@ -24,8 +24,8 @@ import { SeoService } from '../../services/seo.service';
|
|||||||
import { StorageService } from '../../services/storage.service';
|
import { StorageService } from '../../services/storage.service';
|
||||||
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
import { seoDescriptionNetwork } from '../../shared/common.utils';
|
||||||
import { getTransactionFlags, getUnacceleratedFeeRate } from '../../shared/transaction.utils';
|
import { getTransactionFlags, getUnacceleratedFeeRate } from '../../shared/transaction.utils';
|
||||||
import { Filter, toFilters } from '../../shared/filters.utils';
|
import { Filter, TransactionFlags, toFilters } from '../../shared/filters.utils';
|
||||||
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment, Acceleration, AccelerationPosition, SinglePoolStats } from '../../interfaces/node-api.interface';
|
import { BlockExtended, CpfpInfo, RbfTree, MempoolPosition, DifficultyAdjustment, Acceleration, AccelerationPosition } from '../../interfaces/node-api.interface';
|
||||||
import { LiquidUnblinding } from './liquid-ublinding';
|
import { LiquidUnblinding } from './liquid-ublinding';
|
||||||
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe';
|
||||||
import { PriceService } from '../../services/price.service';
|
import { PriceService } from '../../services/price.service';
|
||||||
@ -137,13 +137,14 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
hasEffectiveFeeRate: boolean;
|
hasEffectiveFeeRate: boolean;
|
||||||
accelerateCtaType: 'alert' | 'button' = 'button';
|
accelerateCtaType: 'alert' | 'button' = 'button';
|
||||||
acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR && this.stateService.network === '';
|
acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR && this.stateService.network === '';
|
||||||
|
eligibleForAcceleration: boolean = false;
|
||||||
forceAccelerationSummary = false;
|
forceAccelerationSummary = false;
|
||||||
hideAccelerationSummary = false;
|
hideAccelerationSummary = false;
|
||||||
accelerationFlowCompleted = false;
|
accelerationFlowCompleted = false;
|
||||||
showAccelerationDetails = false;
|
showAccelerationDetails = false;
|
||||||
hasAccelerationDetails = false;
|
hasAccelerationDetails = false;
|
||||||
scrollIntoAccelPreview = false;
|
scrollIntoAccelPreview = false;
|
||||||
accelerationEligible = false;
|
cashappEligible = false;
|
||||||
auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true;
|
auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true;
|
||||||
|
|
||||||
@ViewChild('graphContainer')
|
@ViewChild('graphContainer')
|
||||||
@ -421,7 +422,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
if (txPosition.position?.block > 0 && this.tx.weight < 4000) {
|
if (txPosition.position?.block > 0 && this.tx.weight < 4000) {
|
||||||
this.accelerationEligible = true;
|
this.cashappEligible = true;
|
||||||
}
|
}
|
||||||
} else if (this.showAccelerationSummary) {
|
} else if (this.showAccelerationSummary) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
@ -819,6 +820,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.rbfEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'rbf');
|
this.rbfEnabled = !this.tx.status.confirmed || isFeatureActive(this.stateService.network, this.tx.status.block_height, 'rbf');
|
||||||
this.tx.flags = getTransactionFlags(this.tx);
|
this.tx.flags = getTransactionFlags(this.tx);
|
||||||
this.filters = this.tx.flags ? toFilters(this.tx.flags).filter(f => f.txPage) : [];
|
this.filters = this.tx.flags ? toFilters(this.tx.flags).filter(f => f.txPage) : [];
|
||||||
|
this.checkAccelerationEligibility();
|
||||||
} else {
|
} else {
|
||||||
this.segwitEnabled = false;
|
this.segwitEnabled = false;
|
||||||
this.taprootEnabled = false;
|
this.taprootEnabled = false;
|
||||||
@ -827,6 +829,16 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.featuresEnabled = this.segwitEnabled || this.taprootEnabled || this.rbfEnabled;
|
this.featuresEnabled = this.segwitEnabled || this.taprootEnabled || this.rbfEnabled;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
checkAccelerationEligibility() {
|
||||||
|
if (this.tx && this.tx.flags) {
|
||||||
|
const replaceableInputs = (this.tx.flags & (TransactionFlags.sighash_none | TransactionFlags.sighash_acp)) > 0n;
|
||||||
|
const highSigop = (this.tx.sigops * 20) > this.tx.weight;
|
||||||
|
this.eligibleForAcceleration = !replaceableInputs && !highSigop;
|
||||||
|
} else {
|
||||||
|
this.eligibleForAcceleration = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
isAuditAvailable(blockHeight: number): boolean {
|
isAuditAvailable(blockHeight: number): boolean {
|
||||||
if (!this.auditEnabled) {
|
if (!this.auditEnabled) {
|
||||||
return false;
|
return false;
|
||||||
@ -871,7 +883,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.showCpfpDetails = false;
|
this.showCpfpDetails = false;
|
||||||
this.showAccelerationDetails = false;
|
this.showAccelerationDetails = false;
|
||||||
this.accelerationInfo = null;
|
this.accelerationInfo = null;
|
||||||
this.accelerationEligible = false;
|
this.cashappEligible = false;
|
||||||
this.txInBlockIndex = null;
|
this.txInBlockIndex = null;
|
||||||
this.mempoolPosition = null;
|
this.mempoolPosition = null;
|
||||||
this.pool = null;
|
this.pool = null;
|
||||||
@ -880,6 +892,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
document.body.scrollTo(0, 0);
|
document.body.scrollTo(0, 0);
|
||||||
this.isAcceleration = false;
|
this.isAcceleration = false;
|
||||||
this.isAccelerated$.next(this.isAcceleration);
|
this.isAccelerated$.next(this.isAcceleration);
|
||||||
|
this.eligibleForAcceleration = false;
|
||||||
this.leaveTransaction();
|
this.leaveTransaction();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -974,6 +987,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy {
|
|||||||
this.tx
|
this.tx
|
||||||
&& !this.tx.acceleration
|
&& !this.tx.acceleration
|
||||||
&& this.acceleratorAvailable
|
&& this.acceleratorAvailable
|
||||||
|
&& this.eligibleForAcceleration
|
||||||
&& (
|
&& (
|
||||||
(!this.hideAccelerationSummary && !this.accelerationFlowCompleted)
|
(!this.hideAccelerationSummary && !this.accelerationFlowCompleted)
|
||||||
|| this.forceAccelerationSummary
|
|| this.forceAccelerationSummary
|
||||||
|
Loading…
x
Reference in New Issue
Block a user