From e35ac6e1a2ca0cfd2b26b81be874540fd099e83a Mon Sep 17 00:00:00 2001 From: Mononaut Date: Mon, 1 Jul 2024 07:28:25 +0000 Subject: [PATCH] [accelerator] check for input replaceability --- .../components/tracker/tracker.component.html | 2 +- .../components/tracker/tracker.component.ts | 58 +++++++++++-------- .../transaction/transaction.component.html | 2 +- .../transaction/transaction.component.ts | 23 ++++++-- 4 files changed, 54 insertions(+), 31 deletions(-) diff --git a/frontend/src/app/components/tracker/tracker.component.html b/frontend/src/app/components/tracker/tracker.component.html index a0f242d46..628214ce5 100644 --- a/frontend/src/app/components/tracker/tracker.component.html +++ b/frontend/src/app/components/tracker/tracker.component.html @@ -122,7 +122,7 @@   } @else if (showAccelerationSummary) { - + } @else { @if (tx?.acceleration && !tx.status?.confirmed) { diff --git a/frontend/src/app/components/tracker/tracker.component.ts b/frontend/src/app/components/tracker/tracker.component.ts index 349e8d43b..ed386b927 100644 --- a/frontend/src/app/components/tracker/tracker.component.ts +++ b/frontend/src/app/components/tracker/tracker.component.ts @@ -21,7 +21,7 @@ import { AudioService } from '../../services/audio.service'; import { ApiService } from '../../services/api.service'; import { SeoService } from '../../services/seo.service'; 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 { PriceService } from '../../services/price.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 { MiningService, MiningStats } from '../../services/mining.service'; import { ETA, EtaService } from '../../services/eta.service'; -import { getUnacceleratedFeeRate } from '../../shared/transaction.utils'; +import { getTransactionFlags, getUnacceleratedFeeRate } from '../../shared/transaction.utils'; interface Pool { id: number; @@ -117,8 +117,7 @@ export class TrackerComponent implements OnInit, OnDestroy { hasEffectiveFeeRate: boolean; accelerateCtaType: 'alert' | 'button' = 'button'; acceleratorAvailable: boolean = this.stateService.env.ACCELERATOR && this.stateService.network === ''; - accelerationEligible: boolean = false; - showAccelerationSummary = false; + eligibleForAcceleration: boolean = false; accelerationFlowCompleted = false; scrollIntoAccelPreview = false; 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; }); - const urlParams = new URLSearchParams(window.location.search); - if (urlParams.get('cash_request_id')) { - this.showAccelerationSummary = true; - } - this.enterpriseService.page(); this.enterpriseInfo$ = this.enterpriseService.info$.subscribe(info => { @@ -267,6 +261,7 @@ export class TrackerComponent implements OnInit, OnDestroy { if (!this.tx) { this.tx = tx; + this.checkAccelerationEligibility(); this.isCached = true; if (tx.fee === undefined) { this.tx.fee = 0; @@ -385,20 +380,9 @@ export class TrackerComponent implements OnInit, OnDestroy { this.trackerStage = 'replaced'; } - if (!this.mempoolPosition.accelerated) { - 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) { + if (this.mempoolPosition.accelerated && this.showAccelerationSummary) { setTimeout(() => { this.accelerationFlowCompleted = true; - this.showAccelerationSummary = false; }, 2000); } } @@ -462,6 +446,7 @@ export class TrackerComponent implements OnInit, OnDestroy { this.seoService.clearSoft404(); this.tx = tx; + this.checkAccelerationEligibility(); this.isCached = false; if (tx.fee === undefined) { this.tx.fee = 0; @@ -744,8 +729,9 @@ export class TrackerComponent implements OnInit, OnDestroy { } this.enterpriseService.goal(8); this.accelerationFlowCompleted = false; - this.showAccelerationSummary = true && this.acceleratorAvailable; - this.scrollIntoAccelPreview = true; + if (this.showAccelerationSummary) { + this.scrollIntoAccelPreview = true; + } return false; } @@ -753,6 +739,30 @@ export class TrackerComponent implements OnInit, OnDestroy { 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; + this.eligibleForAcceleration = !replaceableInputs; + } 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() { this.error = undefined; this.tx = null; @@ -778,7 +788,7 @@ export class TrackerComponent implements OnInit, OnDestroy { this.pool = null; this.auditStatus = null; this.accelerationPositions = null; - this.accelerationEligible = false; + this.eligibleForAcceleration = false; this.trackerStage = 'waiting'; document.body.scrollTo(0, 0); this.leaveTransaction(); diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 606f49c7f..2e1c2a519 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -147,7 +147,7 @@ 0 && this.tx.weight < 4000) { - this.accelerationEligible = true; + this.cashappEligible = true; } } else if (this.showAccelerationSummary) { 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.tx.flags = getTransactionFlags(this.tx); this.filters = this.tx.flags ? toFilters(this.tx.flags).filter(f => f.txPage) : []; + this.checkAccelerationEligibility(); } else { this.segwitEnabled = false; this.taprootEnabled = false; @@ -827,6 +829,15 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { 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; + this.eligibleForAcceleration = !replaceableInputs; + } else { + this.eligibleForAcceleration = false; + } + } + isAuditAvailable(blockHeight: number): boolean { if (!this.auditEnabled) { return false; @@ -871,7 +882,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.showCpfpDetails = false; this.showAccelerationDetails = false; this.accelerationInfo = null; - this.accelerationEligible = false; + this.cashappEligible = false; this.txInBlockIndex = null; this.mempoolPosition = null; this.pool = null; @@ -880,6 +891,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { document.body.scrollTo(0, 0); this.isAcceleration = false; this.isAccelerated$.next(this.isAcceleration); + this.eligibleForAcceleration = false; this.leaveTransaction(); } @@ -974,6 +986,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.tx && !this.tx.acceleration && this.acceleratorAvailable + && this.eligibleForAcceleration && ( (!this.hideAccelerationSummary && !this.accelerationFlowCompleted) || this.forceAccelerationSummary