From 4a6231c93cf9ee56b23d0dafcf621b3011af4c39 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 29 Feb 2024 05:06:01 +0000 Subject: [PATCH 01/15] Bump ip from 2.0.0 to 2.0.1 in /frontend Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1. - [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1) --- updated-dependencies: - dependency-name: ip dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 0fab7e887..5393f3273 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -10397,9 +10397,9 @@ } }, "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "node_modules/ipaddr.js": { "version": "2.1.0", @@ -24802,9 +24802,9 @@ } }, "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "ipaddr.js": { "version": "2.1.0", From 7cee1512a38f7ee0800ce3d4cc201df46bf4230c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Mar 2024 13:52:17 +0000 Subject: [PATCH 02/15] Bump ip from 2.0.0 to 2.0.1 in /backend Bumps [ip](https://github.com/indutny/node-ip) from 2.0.0 to 2.0.1. - [Commits](https://github.com/indutny/node-ip/compare/v2.0.0...v2.0.1) --- updated-dependencies: - dependency-name: ip dependency-type: indirect ... Signed-off-by: dependabot[bot] --- backend/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/backend/package-lock.json b/backend/package-lock.json index 95a949ef5..706290470 100644 --- a/backend/package-lock.json +++ b/backend/package-lock.json @@ -4027,9 +4027,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "node_modules/ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "node_modules/ipaddr.js": { "version": "1.9.1", @@ -10683,9 +10683,9 @@ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" }, "ip": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.0.tgz", - "integrity": "sha512-WKa+XuLG1A1R0UWhl2+1XQSi+fZWMsYKffMZTTYsiZaUD8k2yDAj5atimTUD2TZkyCkNEeYE5NhFZmupOGtjYQ==" + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" }, "ipaddr.js": { "version": "1.9.1", From f5e1e5f1a216c03b72d2116496052ac59e2edb91 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Thu, 7 Mar 2024 18:32:04 +0900 Subject: [PATCH 03/15] [enterprise] implement subdomain logo cache buster --- .../master-page/master-page.component.html | 4 ++-- .../master-page/master-page.component.ts | 18 +++++++++++++++--- .../src/app/services/enterprise.service.ts | 5 +++-- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/frontend/src/app/components/master-page/master-page.component.html b/frontend/src/app/components/master-page/master-page.component.html index 828ece1e5..da0bbfcea 100644 --- a/frontend/src/app/components/master-page/master-page.component.html +++ b/frontend/src/app/components/master-page/master-page.component.html @@ -16,9 +16,9 @@ - +
- +
diff --git a/frontend/src/app/components/master-page/master-page.component.ts b/frontend/src/app/components/master-page/master-page.component.ts index a92f77cf9..6f376f923 100644 --- a/frontend/src/app/components/master-page/master-page.component.ts +++ b/frontend/src/app/components/master-page/master-page.component.ts @@ -1,7 +1,7 @@ -import { Component, OnInit, Input, ViewChild } from '@angular/core'; +import { Component, OnInit, OnDestroy, Input, ViewChild } from '@angular/core'; import { Router } from '@angular/router'; import { Env, StateService } from '../../services/state.service'; -import { Observable, merge, of } from 'rxjs'; +import { Observable, merge, of, Subscription } from 'rxjs'; import { LanguageService } from '../../services/language.service'; import { EnterpriseService } from '../../services/enterprise.service'; import { NavigationService } from '../../services/navigation.service'; @@ -14,7 +14,7 @@ import { ApiService } from '../../services/api.service'; templateUrl: './master-page.component.html', styleUrls: ['./master-page.component.scss'], }) -export class MasterPageComponent implements OnInit { +export class MasterPageComponent implements OnInit, OnDestroy { @Input() headerVisible = true; @Input() footerVisibleOverride: boolean | null = null; @@ -32,6 +32,9 @@ export class MasterPageComponent implements OnInit { user: any = undefined; servicesEnabled = false; menuOpen = false; + + enterpriseInfo: any; + enterpriseInfo$: Subscription; @ViewChild(MenuComponent) public menuComponent!: MenuComponent; @@ -64,6 +67,9 @@ export class MasterPageComponent implements OnInit { this.footerVisible = this.footerVisibleOverride; } }); + this.enterpriseInfo$ = this.enterpriseService.info$.subscribe(info => { + this.enterpriseInfo = info; + }); this.servicesEnabled = this.officialMempoolSpace && this.stateService.env.ACCELERATOR === true && this.stateService.network === ''; this.refreshAuth(); @@ -72,6 +78,12 @@ export class MasterPageComponent implements OnInit { this.menuOpen = isServicesPage && !this.isSmallScreen(); } + ngOnDestroy() { + if (this.enterpriseInfo$) { + this.enterpriseInfo$.unsubscribe(); + } + } + collapse(): void { this.navCollapsed = !this.navCollapsed; } diff --git a/frontend/src/app/services/enterprise.service.ts b/frontend/src/app/services/enterprise.service.ts index d1e3624f9..698af138b 100644 --- a/frontend/src/app/services/enterprise.service.ts +++ b/frontend/src/app/services/enterprise.service.ts @@ -4,6 +4,7 @@ import { ApiService } from './api.service'; import { SeoService } from './seo.service'; import { StateService } from './state.service'; import { ActivatedRoute } from '@angular/router'; +import { BehaviorSubject } from 'rxjs'; @Injectable({ providedIn: 'root' @@ -11,9 +12,9 @@ import { ActivatedRoute } from '@angular/router'; export class EnterpriseService { exclusiveHostName = '.mempool.space'; subdomain: string | null = null; - info: object = {}; statsUrl: string; siteId: number; + info$: BehaviorSubject = new BehaviorSubject(null); constructor( @Inject(DOCUMENT) private document: Document, @@ -47,9 +48,9 @@ export class EnterpriseService { fetchSubdomainInfo(): void { this.apiService.getEnterpriseInfo$(this.subdomain).subscribe((info) => { - this.info = info; this.insertMatomo(info.site_id); this.seoService.setEnterpriseTitle(info.title); + this.info$.next(info); }, (error) => { if (error.status === 404) { From 7491fb512c80f35ea23d038dae55bad5e3fc9ce1 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 5 Mar 2024 00:40:49 +0000 Subject: [PATCH 04/15] Show accelerator audit total on block page --- .../repositories/AccelerationRepository.ts | 3 ++ .../app/components/block/block.component.html | 3 ++ .../app/components/block/block.component.scss | 4 +++ .../app/components/block/block.component.ts | 34 +++++++++++++++++-- .../src/app/interfaces/node-api.interface.ts | 14 ++++++++ frontend/src/app/services/api.service.ts | 20 ++++++++++- 6 files changed, 75 insertions(+), 3 deletions(-) diff --git a/backend/src/repositories/AccelerationRepository.ts b/backend/src/repositories/AccelerationRepository.ts index 868f8526f..b30e563ef 100644 --- a/backend/src/repositories/AccelerationRepository.ts +++ b/backend/src/repositories/AccelerationRepository.ts @@ -56,6 +56,9 @@ class AccelerationRepository { } public async $getAccelerationInfo(poolSlug: string | null = null, height: number | null = null, interval: string | null = null): Promise { + if (!interval || !['24h', '3d', '1w', '1m'].includes(interval)) { + interval = '1m'; + } interval = Common.getSqlInterval(interval); if (!config.MEMPOOL_SERVICES.ACCELERATIONS || (interval == null && poolSlug == null && height == null)) { diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index 89699a68c..777be0907 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -433,6 +433,9 @@ Total fees + + + + {{ blockAudit.feeDelta < 0 ? '+' : '' }}{{ (-blockAudit.feeDelta * 100) | amountShortener: 2 }}% diff --git a/frontend/src/app/components/block/block.component.scss b/frontend/src/app/components/block/block.component.scss index 6deb2cb4b..4dd079eb8 100644 --- a/frontend/src/app/components/block/block.component.scss +++ b/frontend/src/app/components/block/block.component.scss @@ -288,6 +288,10 @@ h1 { @media (max-width: 767.98px) { margin-top: 0.75rem; } + + .oobFees { + color: #653b9c; + } } .graph-col { diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index 5bba24852..c68108af1 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -9,7 +9,7 @@ import { StateService } from '../../services/state.service'; import { SeoService } from '../../services/seo.service'; import { WebsocketService } from '../../services/websocket.service'; import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; -import { BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; +import { AccelerationInfo, BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; import { ApiService } from '../../services/api.service'; import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; import { detectWebGL } from '../../shared/graphs.utils'; @@ -43,6 +43,7 @@ export class BlockComponent implements OnInit, OnDestroy { latestBlock: BlockExtended; latestBlocks: BlockExtended[] = []; transactions: Transaction[]; + oobFees: number = 0; isLoadingTransactions = true; strippedTransactions: TransactionStripped[]; overviewTransitionDirection: string; @@ -85,6 +86,7 @@ export class BlockComponent implements OnInit, OnDestroy { timeLtr: boolean; childChangeSubscription: Subscription; auditPrefSubscription: Subscription; + oobSubscription: Subscription; priceSubscription: Subscription; blockConversion: Price; @@ -168,6 +170,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.page = 1; this.error = undefined; this.fees = undefined; + this.oobFees = 0; if (history.state.data && history.state.data.blockHeight) { this.blockHeight = history.state.data.blockHeight; @@ -446,7 +449,7 @@ export class BlockComponent implements OnInit, OnDestroy { inBlock[tx.txid] = true; } - blockAudit.feeDelta = blockAudit.expectedFees > 0 ? (blockAudit.expectedFees - this.block.extras.totalFees) / blockAudit.expectedFees : 0; + blockAudit.feeDelta = blockAudit.expectedFees > 0 ? (blockAudit.expectedFees - (this.block.extras.totalFees + this.oobFees)) / blockAudit.expectedFees : 0; blockAudit.weightDelta = blockAudit.expectedWeight > 0 ? (blockAudit.expectedWeight - this.block.weight) / blockAudit.expectedWeight : 0; blockAudit.txDelta = blockAudit.template.length > 0 ? (blockAudit.template.length - this.block.tx_count) / blockAudit.template.length : 0; this.blockAudit = blockAudit; @@ -462,6 +465,32 @@ export class BlockComponent implements OnInit, OnDestroy { this.setupBlockGraphs(); }); + this.oobSubscription = block$.pipe( + switchMap((block) => this.apiService.getAccelerationsByHeight$(block.height) + .pipe( + map(accelerations => { + return { block, accelerations }; + }), + catchError((err) => { + return of({ block, accelerations: [] }); + })) + ), + ).subscribe(({ block, accelerations}) => { + let totalFees = 0; + for (const acc of accelerations) { + totalFees += acc.boost_cost; + } + this.oobFees = totalFees; + if (block.height === this.block.height && this.blockAudit) { + this.blockAudit.feeDelta = this.blockAudit.expectedFees > 0 ? (this.blockAudit.expectedFees - (this.block.extras.totalFees + this.oobFees)) / this.blockAudit.expectedFees : 0; + } + }, + (error) => { + this.error = error; + this.isLoadingBlock = false; + this.isLoadingOverview = false; + }); + this.networkChangedSubscription = this.stateService.networkChanged$ .subscribe((network) => this.network = network); @@ -529,6 +558,7 @@ export class BlockComponent implements OnInit, OnDestroy { this.unsubscribeNextBlockSubscriptions(); this.childChangeSubscription?.unsubscribe(); this.priceSubscription?.unsubscribe(); + this.oobSubscription?.unsubscribe(); } unsubscribeNextBlockSubscriptions() { diff --git a/frontend/src/app/interfaces/node-api.interface.ts b/frontend/src/app/interfaces/node-api.interface.ts index e5764e785..07ec4f68d 100644 --- a/frontend/src/app/interfaces/node-api.interface.ts +++ b/frontend/src/app/interfaces/node-api.interface.ts @@ -400,4 +400,18 @@ export interface AccelerationHistoryParams { blockHeight?: number; page?: number; pageLength?: number; +} + +export interface AccelerationInfo { + txid: string, + height: number, + pool: { + id: number, + slug: string, + name: string, + }, + effective_vsize: number, + effective_fee: number, + boost_rate: number, + boost_cost: number, } \ No newline at end of file diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 7bd41c8a0..f90bfb838 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -1,7 +1,7 @@ import { Injectable } from '@angular/core'; import { HttpClient, HttpParams, HttpResponse } from '@angular/common/http'; import { CpfpInfo, OptimizedMempoolStats, AddressInformation, LiquidPegs, ITranslators, - PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit, Acceleration, AccelerationHistoryParams, CurrentPegs, AuditStatus, FederationAddress, FederationUtxo, RecentPeg, PegsVolume } from '../interfaces/node-api.interface'; + PoolStat, BlockExtended, TransactionStripped, RewardStats, AuditScore, BlockSizesAndWeights, RbfTree, BlockAudit, Acceleration, AccelerationHistoryParams, CurrentPegs, AuditStatus, FederationAddress, FederationUtxo, RecentPeg, PegsVolume, AccelerationInfo } from '../interfaces/node-api.interface'; import { BehaviorSubject, Observable, catchError, filter, of, shareReplay, take, tap } from 'rxjs'; import { StateService } from './state.service'; import { Transaction } from '../interfaces/electrs.interface'; @@ -412,4 +412,22 @@ export class ApiService { (timestamp ? `?timestamp=${timestamp}` : '') ); } + + getAccelerationsByPool$(slug: string): Observable { + return this.httpClient.get( + this.apiBaseUrl + this.apiBasePath + `/api/v1/accelerations/pool/${slug}` + ); + } + + getAccelerationsByHeight$(height: number): Observable { + return this.httpClient.get( + this.apiBaseUrl + this.apiBasePath + `/api/v1/accelerations/block/${height}` + ); + } + + getRecentAccelerations$(interval: string | undefined): Observable { + return this.httpClient.get( + this.apiBaseUrl + this.apiBasePath + '/api/v1/accelerations/interval' + (interval !== undefined ? `/${interval}` : '') + ); + } } From e7788133faf3fa53b79aef0755f1cffca4b669fc Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 7 Mar 2024 19:52:42 +0000 Subject: [PATCH 05/15] Add missing null check in block accelerations subscription --- frontend/src/app/components/block/block.component.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index c68108af1..1eb1c4798 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -481,7 +481,7 @@ export class BlockComponent implements OnInit, OnDestroy { totalFees += acc.boost_cost; } this.oobFees = totalFees; - if (block.height === this.block.height && this.blockAudit) { + if (block && this.block && this.blockAudit && block?.height === this.block?.height) { this.blockAudit.feeDelta = this.blockAudit.expectedFees > 0 ? (this.blockAudit.expectedFees - (this.block.extras.totalFees + this.oobFees)) / this.blockAudit.expectedFees : 0; } }, From 1d56bfa9b87eae66864399ae1f3909f6b503075f Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Fri, 8 Mar 2024 10:32:32 +0900 Subject: [PATCH 06/15] [accelerator] remove query params for acceleration list --- .../accelerations-list/accelerations-list.component.ts | 2 +- .../accelerator-dashboard/accelerator-dashboard.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts index 974f9b71b..1a0aacbb6 100644 --- a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts +++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts @@ -44,7 +44,7 @@ export class AccelerationsListComponent implements OnInit { this.accelerationList$ = this.pageSubject.pipe( switchMap((page) => { - const accelerationObservable$ = this.accelerations$ || (this.pending ? this.servicesApiService.getAccelerations$() : this.servicesApiService.getAccelerationHistoryObserveResponse$({ timeframe: '1y', page: page })); + const accelerationObservable$ = this.accelerations$ || (this.pending ? this.servicesApiService.getAccelerations$() : this.servicesApiService.getAccelerationHistoryObserveResponse$({ page: page })); return accelerationObservable$.pipe( switchMap(response => { let accelerations = response; diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts index ba9240d1b..91b77f5e8 100644 --- a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts @@ -60,7 +60,7 @@ export class AcceleratorDashboardComponent implements OnInit { this.accelerations$ = this.stateService.chainTip$.pipe( distinctUntilChanged(), switchMap(() => { - return this.serviceApiServices.getAccelerationHistory$({ timeframe: '3m', page: 1, pageLength: 100}).pipe( + return this.serviceApiServices.getAccelerationHistory$({}).pipe( catchError(() => { return of([]); }), From 007f424d153c5bf06c46999573ec01b8affc2794 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Fri, 8 Mar 2024 10:52:02 +0900 Subject: [PATCH 07/15] [accelerator] update doc, split public/authenticated --- .../src/app/docs/api-docs/api-docs-data.ts | 334 +++++++++--------- 1 file changed, 171 insertions(+), 163 deletions(-) diff --git a/frontend/src/app/docs/api-docs/api-docs-data.ts b/frontend/src/app/docs/api-docs/api-docs-data.ts index d79c23e4a..9461a2271 100644 --- a/frontend/src/app/docs/api-docs/api-docs-data.ts +++ b/frontend/src/app/docs/api-docs/api-docs-data.ts @@ -9878,16 +9878,179 @@ export const restApiDocsData = [ }, { type: "category", - category: "accelerator", - fragment: "accelerator", - title: "Accelerator", + category: "accelerator-public", + fragment: "accelerator-public", + title: "Accelerator (Public)", showConditions: [""], options: { officialOnly: true }, }, { options: { officialOnly: true }, type: "endpoint", - category: "accelerator", + category: "accelerator-public", + httpRequestMethod: "POST", + fragment: "accelerator-estimate", + title: "POST Calculate Estimated Costs", + description: { + default: "

Returns estimated costs to accelerate a transaction. Optionally set the api_key header to get customized estimation.

" + }, + urlString: "/v1/services/accelerator/estimate", + showConditions: [""], + showJsExamples: showJsExamplesDefaultFalse, + codeExample: { + default: { + codeTemplate: { + curl: `%{1}" "[[hostname]][[baseNetworkUrl]]/api/v1/services/accelerator/estimate`, //custom interpolation technique handled in replaceCurlPlaceholder() + commonJS: ``, + esModule: `` + }, + codeSampleMainnet: { + esModule: [], + commonJS: [], + curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29"], + headers: "api_key: stacksats", + response: `{ + "txSummary": { + "txid": "ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29", + "effectiveVsize": 154, + "effectiveFee": 154, + "ancestorCount": 1 + }, + "cost": 3850, + "targetFeeRate": 26, + "nextBlockFee": 4004, + "userBalance": 99900000, + "mempoolBaseFee": 40000, + "vsizeFee": 50000, + "hasAccess": true +}`, + }, + } + } + }, + { + options: { officialOnly: true }, + type: "endpoint", + category: "accelerator-public", + httpRequestMethod: "GET", + fragment: "accelerator-pending", + title: "GET Pending Accelerations", + description: { + default: "

Returns all transactions currently being accelerated.

" + }, + urlString: "/v1/services/accelerator/accelerations", + showConditions: [""], + showJsExamples: showJsExamplesDefaultFalse, + codeExample: { + default: { + codeTemplate: { + curl: `/api/v1/services/accelerator/accelerations`, + commonJS: ``, + esModule: `` + }, + codeSampleMainnet: { + esModule: [], + commonJS: [], + curl: [], + headers: '', + response: `[ + { + "txid": "8a183c8ae929a2afb857e7f2acd440aaefdf2797f8f7eab1c5f95ff8602abc81", + "added": 1707558316, + "feeDelta": 3500, + "effectiveVsize": 111, + "effectiveFee": 1671, + "pools": [ + 111 + ] + }, + { + "txid": "6097f295e21bdd8d725bd8d9ad4dd72b05bd795dc648bfef52150a9b2b7f7a45", + "added": 1707560464, + "feeDelta": 60000, + "effectiveVsize": 812, + "effectiveFee": 7790, + "pools": [ + 111 + ] + } +]`, + }, + } + } + }, + { + options: { officialOnly: true }, + type: "endpoint", + category: "accelerator-public", + httpRequestMethod: "GET", + fragment: "accelerator-public-history", + title: "GET Acceleration History", + description: { + default: `

Returns all past accelerated transactions. + Filters can be applied:

    +
  • status: all, requested, accelerating, mined, completed, failed
  • +
  • timeframe: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y, 4y, all
  • +
  • poolUniqueId: any id from https://github.com/mempool/mining-pools/blob/master/pools-v2.json. Note: This will return all acceleration requests accepted by the pool but the the listed transactions may have been mined by another pool. +
  • blockHash: a block hash +
  • blockHeight: a block height +
  • page: the requested page number if using pagination (min: 1) +
  • pageLength: the page lenght if using pagination (min: 1, max: 50) +

` + }, + urlString: "/v1/services/accelerator/accelerations/history", + showConditions: [""], + showJsExamples: showJsExamplesDefaultFalse, + codeExample: { + default: { + codeTemplate: { + curl: `/api/v1/services/accelerator/accelerations/history?blockHash=00000000000000000000482f0746d62141694b9210a813b97eb8445780a32003`, + commonJS: ``, + esModule: `` + }, + codeSampleMainnet: { + esModule: [], + commonJS: [], + curl: [], + headers: '', + response: `[ + { + "txid": "d7e1796d8eb4a09d4e6c174e36cfd852f1e6e6c9f7df4496339933cd32cbdd1d", + "status": "completed", + "feePaid": 53239, + "added": 1707421053, + "lastUpdated": 1707422952, + "baseFee": 50000, + "vsizeFee": 0, + "effectiveFee": 146, + "effectiveVsize": 141, + "feeDelta": 14000, + "blockHash": "00000000000000000000482f0746d62141694b9210a813b97eb8445780a32003", + "blockHeight": 829559, + "pools": [ + { + "pool_unique_id": 111, + "username": "foundryusa" + } + ] + } +]`, + }, + } + } + }, + { + type: "category", + category: "accelerator-private", + fragment: "accelerator-private", + title: "Accelerator (Authenticated)", + showConditions: [""], + options: { officialOnly: true }, + }, + { + options: { officialOnly: true }, + type: "endpoint", + category: "accelerator-private", httpRequestMethod: "GET", fragment: "accelerator-deposit-history", title: "GET Deposit History", @@ -9935,7 +10098,7 @@ export const restApiDocsData = [ { options: { officialOnly: true }, type: "endpoint", - category: "accelerator", + category: "accelerator-private", httpRequestMethod: "GET", fragment: "accelerator-balance", title: "GET Available Balance", @@ -9969,51 +10132,7 @@ export const restApiDocsData = [ { options: { officialOnly: true }, type: "endpoint", - category: "accelerator", - httpRequestMethod: "POST", - fragment: "accelerator-estimate", - title: "POST Calculate Estimated Costs", - description: { - default: "

Returns estimated costs to accelerate a transaction.

" - }, - urlString: "/v1/services/accelerator/estimate", - showConditions: [""], - showJsExamples: showJsExamplesDefaultFalse, - codeExample: { - default: { - codeTemplate: { - curl: `%{1}" "[[hostname]][[baseNetworkUrl]]/api/v1/services/accelerator/estimate`, //custom interpolation technique handled in replaceCurlPlaceholder() - commonJS: ``, - esModule: `` - }, - codeSampleMainnet: { - esModule: [], - commonJS: [], - curl: ["txInput=ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29"], - headers: "api_key: stacksats", - response: `{ - "txSummary": { - "txid": "ee13ebb99632377c15c94980357f674d285ac413452050031ea6dcd3e9b2dc29", - "effectiveVsize": 154, - "effectiveFee": 154, - "ancestorCount": 1 - }, - "cost": 3850, - "targetFeeRate": 26, - "nextBlockFee": 4004, - "userBalance": 99900000, - "mempoolBaseFee": 40000, - "vsizeFee": 50000, - "hasAccess": true -}`, - }, - } - } - }, - { - options: { officialOnly: true }, - type: "endpoint", - category: "accelerator", + category: "accelerator-private", httpRequestMethod: "POST", fragment: "accelerator-accelerate", title: "POST Accelerate A Transaction", @@ -10043,10 +10162,10 @@ export const restApiDocsData = [ { options: { officialOnly: true }, type: "endpoint", - category: "accelerator", + category: "accelerator-private", httpRequestMethod: "GET", fragment: "accelerator-history", - title: "GET Private Acceleration History", + title: "GET Acceleration History", description: { default: "

Returns the user's past acceleration requests.

Pass one of the following for :status: all, requested, accelerating, mined, completed, failed. Pass true in :details to get a detailed history of the acceleration request.

" }, @@ -10153,117 +10272,6 @@ export const restApiDocsData = [ } ] } -]`, - }, - } - } - }, - { - options: { officialOnly: true }, - type: "endpoint", - category: "accelerator", - httpRequestMethod: "GET", - fragment: "accelerator-pending", - title: "GET Pending Accelerations", - description: { - default: "

Returns all transactions currently being accelerated.

" - }, - urlString: "/v1/services/accelerator/accelerations", - showConditions: [""], - showJsExamples: showJsExamplesDefaultFalse, - codeExample: { - default: { - codeTemplate: { - curl: `/api/v1/services/accelerator/accelerations`, - commonJS: ``, - esModule: `` - }, - codeSampleMainnet: { - esModule: [], - commonJS: [], - curl: [], - headers: '', - response: `[ - { - "txid": "8a183c8ae929a2afb857e7f2acd440aaefdf2797f8f7eab1c5f95ff8602abc81", - "added": 1707558316, - "feeDelta": 3500, - "effectiveVsize": 111, - "effectiveFee": 1671, - "pools": [ - 111 - ] - }, - { - "txid": "6097f295e21bdd8d725bd8d9ad4dd72b05bd795dc648bfef52150a9b2b7f7a45", - "added": 1707560464, - "feeDelta": 60000, - "effectiveVsize": 812, - "effectiveFee": 7790, - "pools": [ - 111 - ] - } -]`, - }, - } - } - }, - { - options: { officialOnly: true }, - type: "endpoint", - category: "accelerator", - httpRequestMethod: "GET", - fragment: "accelerator-public-history", - title: "GET Public Acceleration History", - description: { - default: `

Returns all past accelerated transactions. - Filters can be applied:

    -
  • status: all, requested, accelerating, mined, completed, failed
  • -
  • timeframe: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y, all
  • -
  • poolUniqueId: any id from https://github.com/mempool/mining-pools/blob/master/pools-v2.json -
  • blockHash: a block hash -
  • blockHeight: a block height -
  • page: the requested page number if using pagination -
  • pageLength: the page lenght if using pagination -

` - }, - urlString: "/v1/services/accelerator/accelerations/history", - showConditions: [""], - showJsExamples: showJsExamplesDefaultFalse, - codeExample: { - default: { - codeTemplate: { - curl: `/api/v1/services/accelerator/accelerations/history?blockHash=00000000000000000000482f0746d62141694b9210a813b97eb8445780a32003`, - commonJS: ``, - esModule: `` - }, - codeSampleMainnet: { - esModule: [], - commonJS: [], - curl: [], - headers: '', - response: `[ - { - "txid": "d7e1796d8eb4a09d4e6c174e36cfd852f1e6e6c9f7df4496339933cd32cbdd1d", - "status": "completed", - "feePaid": 53239, - "added": 1707421053, - "lastUpdated": 1707422952, - "baseFee": 50000, - "vsizeFee": 0, - "effectiveFee": 146, - "effectiveVsize": 141, - "feeDelta": 14000, - "blockHash": "00000000000000000000482f0746d62141694b9210a813b97eb8445780a32003", - "blockHeight": 829559, - "pools": [ - { - "pool_unique_id": 111, - "username": "foundryusa" - } - ] - } ]`, }, } From aac3b1aa5c16af9a269d90ce5cd82a5ffde0940c Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 8 Mar 2024 03:21:24 +0000 Subject: [PATCH 08/15] Bump es5-ext from 0.10.53 to 0.10.64 in /frontend Bumps [es5-ext](https://github.com/medikoo/es5-ext) from 0.10.53 to 0.10.64. - [Release notes](https://github.com/medikoo/es5-ext/releases) - [Changelog](https://github.com/medikoo/es5-ext/blob/main/CHANGELOG.md) - [Commits](https://github.com/medikoo/es5-ext/compare/v0.10.53...v0.10.64) --- updated-dependencies: - dependency-name: es5-ext dependency-type: indirect ... Signed-off-by: dependabot[bot] --- frontend/package-lock.json | 79 +++++++++++++++++++++++++++++--------- 1 file changed, 61 insertions(+), 18 deletions(-) diff --git a/frontend/package-lock.json b/frontend/package-lock.json index 5393f3273..7df618dbd 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -8070,13 +8070,18 @@ } }, "node_modules/es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, "dependencies": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" } }, "node_modules/es6-iterator": { @@ -8624,6 +8629,25 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esniff/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, "node_modules/espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -12508,9 +12532,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "node_modules/next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, "node_modules/ngx-echarts": { "version": "16.2.0", @@ -23055,13 +23079,14 @@ } }, "es5-ext": { - "version": "0.10.53", - "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.53.tgz", - "integrity": "sha512-Xs2Stw6NiNHWypzRTY1MtaG/uJlwCk8kH81920ma8mvN8Xq1gsfhZvpkImLQArw8AHnv8MT2I45J3c0R8slE+Q==", + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", "requires": { - "es6-iterator": "~2.0.3", - "es6-symbol": "~3.1.3", - "next-tick": "~1.0.0" + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" } }, "es6-iterator": { @@ -23472,6 +23497,24 @@ "integrity": "sha512-mQ+suqKJVyeuwGYHAdjMFqjCyfl8+Ldnxuyp3ldiMBFKkvytrXUZWaiPCEav8qDHKty44bD+qV1IP4T+w+xXRA==", "dev": true }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + } + } + }, "espree": { "version": "9.4.1", "resolved": "https://registry.npmjs.org/espree/-/espree-9.4.1.tgz", @@ -26374,9 +26417,9 @@ "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" }, "next-tick": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", - "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=" + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" }, "ngx-echarts": { "version": "16.2.0", From faa5887c3b5de3cec6e704055ecec795d9c57aac Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Fri, 8 Mar 2024 18:00:57 +0900 Subject: [PATCH 09/15] [accelerator] dynamically show timespan selector based on the oldest acceleration --- .../acceleration-fees-graph.component.html | 25 +++++++++++++++---- .../acceleration-fees-graph.component.ts | 17 +++++++------ .../src/app/services/services-api.service.ts | 4 +-- 3 files changed, 32 insertions(+), 14 deletions(-) diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html index faf48eac7..0a567bd0a 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html @@ -9,23 +9,38 @@ -
+
-
diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts index 001f005a1..a40ab9114 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts @@ -1,6 +1,6 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, OnDestroy, OnInit } from '@angular/core'; import { EChartsOption } from 'echarts'; -import { Observable, Subscription, combineLatest, fromEvent } from 'rxjs'; +import { Observable, Subscription, combineLatest, fromEvent, share } from 'rxjs'; import { startWith, switchMap, tap } from 'rxjs/operators'; import { SeoService } from '../../../services/seo.service'; import { formatNumber } from '@angular/common'; @@ -41,8 +41,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { renderer: 'svg', }; - hrStatsObservable$: Observable; - statsObservable$: Observable; + aggregatedHistory$: Observable; statsSubscription: Subscription; isLoading = true; formatNumber = formatNumber; @@ -50,6 +49,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { chartInstance: any = undefined; currency: string; + daysAvailable: number = 0; constructor( @Inject(LOCALE_ID) public locale: string, @@ -81,7 +81,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); } }); - this.statsObservable$ = combineLatest([ + this.aggregatedHistory$ = combineLatest([ this.radioGroupForm.get('dateSpan').valueChanges.pipe( startWith(this.radioGroupForm.controls.dateSpan.value), switchMap((timespan) => { @@ -95,14 +95,17 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { ), fromEvent(window, 'resize').pipe(startWith(null)), ]).pipe( - tap(([history]) => { + tap(([response]) => { + const history: Acceleration[] = response.body; + this.daysAvailable = (new Date().getTime() / 1000 - response.headers.get('x-oldest-accel')) / (24 * 3600); this.isLoading = false; this.prepareChartOptions(history); this.cd.markForCheck(); - }) + }), + share(), ); - this.statsObservable$.subscribe(); + this.aggregatedHistory$.subscribe(); } prepareChartOptions(data) { diff --git a/frontend/src/app/services/services-api.service.ts b/frontend/src/app/services/services-api.service.ts index f41c5b42c..ad8af5536 100644 --- a/frontend/src/app/services/services-api.service.ts +++ b/frontend/src/app/services/services-api.service.ts @@ -145,8 +145,8 @@ export class ServicesApiServices { return this.httpClient.get(`${SERVICES_API_PREFIX}/accelerator/accelerations`); } - getAggregatedAccelerationHistory$(params: AccelerationHistoryParams): Observable { - return this.httpClient.get(`${SERVICES_API_PREFIX}/accelerator/accelerations/history/aggregated`, { params: { ...params } }); + getAggregatedAccelerationHistory$(params: AccelerationHistoryParams): Observable { + return this.httpClient.get(`${SERVICES_API_PREFIX}/accelerator/accelerations/history/aggregated`, { params: { ...params }, observe: 'response' }); } getAccelerationHistory$(params: AccelerationHistoryParams): Observable { From c17b77fe31b3815d0d74855c9d5d5b5789cbc9a9 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 7 Mar 2024 23:21:27 +0000 Subject: [PATCH 10/15] Display basic mining info on transaction page --- .../transaction/transaction.component.html | 21 +++- .../transaction/transaction.component.scss | 4 + .../transaction/transaction.component.ts | 99 ++++++++++++++++++- 3 files changed, 121 insertions(+), 3 deletions(-) diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 2748b9ffc..211149b9d 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -70,6 +70,25 @@ + + Mining + + + {{ pool.name }} + + + Expected in Block + Seen in Mempool + Not seen in Mempool + Added + Conflict + + + + + + @@ -509,7 +528,7 @@ - + diff --git a/frontend/src/app/components/transaction/transaction.component.scss b/frontend/src/app/components/transaction/transaction.component.scss index d78edf85b..d24d57a93 100644 --- a/frontend/src/app/components/transaction/transaction.component.scss +++ b/frontend/src/app/components/transaction/transaction.component.scss @@ -149,6 +149,10 @@ .btn { display: block; } + + &.wrap-cell { + white-space: normal; + } } } diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 60797a9a1..eb9f49995 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -8,10 +8,11 @@ import { retryWhen, delay, mergeMap, - tap + tap, + map } from 'rxjs/operators'; import { Transaction } from '../../interfaces/electrs.interface'; -import { of, merge, Subscription, Observable, Subject, from, throwError } from 'rxjs'; +import { of, merge, Subscription, Observable, Subject, from, throwError, combineLatest } from 'rxjs'; import { StateService } from '../../services/state.service'; import { CacheService } from '../../services/cache.service'; import { WebsocketService } from '../../services/websocket.service'; @@ -28,6 +29,21 @@ import { isFeatureActive } from '../../bitcoin.utils'; import { ServicesApiServices } from '../../services/services-api.service'; import { EnterpriseService } from '../../services/enterprise.service'; +interface Pool { + id: number; + name: string; + slug: string; +} + +interface AuditStatus { + seen: boolean; + expected: boolean; + added: boolean; + delayed?: number; + accelerated: boolean; + conflict: boolean; +} + @Component({ selector: 'app-transaction', templateUrl: './transaction.component.html', @@ -58,6 +74,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { urlFragmentSubscription: Subscription; mempoolBlocksSubscription: Subscription; blocksSubscription: Subscription; + miningSubscription: Subscription; fragmentParams: URLSearchParams; rbfTransaction: undefined | Transaction; replaced: boolean = false; @@ -67,11 +84,14 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { accelerationInfo: Acceleration | null = null; sigops: number | null; adjustedVsize: number | null; + pool: Pool | null; + auditStatus: AuditStatus | null; showCpfpDetails = false; fetchCpfp$ = new Subject(); fetchRbfHistory$ = new Subject(); fetchCachedTx$ = new Subject(); fetchAcceleration$ = new Subject(); + fetchMiningInfo$ = new Subject<{ hash: string, height: number, txid: string }>(); isCached: boolean = false; now = Date.now(); da$: Observable; @@ -100,6 +120,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { acceleratorAvailable: boolean = this.stateService.env.OFFICIAL_MEMPOOL_SPACE && this.stateService.env.ACCELERATOR && this.stateService.network === ''; showAccelerationSummary = false; scrollIntoAccelPreview = false; + auditEnabled: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true; @ViewChild('graphContainer') graphContainer: ElementRef; @@ -266,6 +287,52 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { } }); + this.miningSubscription = this.fetchMiningInfo$.pipe( + filter((target) => target.txid === this.txId), + tap(() => { + this.pool = null; + this.auditStatus = null; + }), + switchMap(({ hash, height, txid }) => { + const foundBlock = this.cacheService.getCachedBlock(height) || null; + const auditAvailable = this.isAuditAvailable(height); + return combineLatest([ + foundBlock ? of(foundBlock.extras.pool) : this.apiService.getBlock$(hash).pipe( + map(block => { + return block.extras.pool; + }), + catchError(() => { + return of(null); + }) + ), + auditAvailable ? this.apiService.getBlockAudit$(hash).pipe( + map(audit => { + const isAdded = audit.addedTxs.includes(txid); + const isAccelerated = audit.acceleratedTxs.includes(txid); + const isConflict = audit.fullrbfTxs.includes(txid); + const isExpected = audit.template.some(tx => tx.txid === txid); + return { + seen: isExpected || !(isAdded || isConflict), + expected: isExpected, + added: isAdded, + conflict: isConflict, + accelerated: isAccelerated, + }; + }), + catchError(() => { + return of(null); + }) + ) : of(null) + ]); + }), + catchError(() => { + return of(null); + }) + ).subscribe(([pool, auditStatus]) => { + this.pool = pool; + this.auditStatus = auditStatus; + }); + this.mempoolPositionSubscription = this.stateService.mempoolTxPosition$.subscribe(txPosition => { this.now = Date.now(); if (txPosition && txPosition.txid === this.txId && txPosition.position) { @@ -396,6 +463,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { } } else { this.fetchAcceleration$.next(tx.status.block_hash); + this.fetchMiningInfo$.next({ hash: tx.status.block_hash, height: tx.status.block_height, txid: tx.txid }); this.transactionTime = 0; } @@ -453,6 +521,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.audioService.playSound('magic'); } this.fetchAcceleration$.next(block.id); + this.fetchMiningInfo$.next({ hash: block.id, height: block.height, txid: this.tx.txid }); } }); @@ -606,6 +675,29 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.featuresEnabled = this.segwitEnabled || this.taprootEnabled || this.rbfEnabled; } + isAuditAvailable(blockHeight: number): boolean { + if (!this.auditEnabled) { + return false; + } + switch (this.stateService.network) { + case 'testnet': + if (blockHeight < this.stateService.env.TESTNET_BLOCK_AUDIT_START_HEIGHT) { + return false; + } + break; + case 'signet': + if (blockHeight < this.stateService.env.SIGNET_BLOCK_AUDIT_START_HEIGHT) { + return false; + } + break; + default: + if (blockHeight < this.stateService.env.MAINNET_BLOCK_AUDIT_START_HEIGHT) { + return false; + } + } + return true; + } + resetTransaction() { this.error = undefined; this.tx = null; @@ -625,6 +717,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.accelerationInfo = null; this.txInBlockIndex = null; this.mempoolPosition = null; + this.pool = null; + this.auditStatus = null; document.body.scrollTo(0, 0); this.leaveTransaction(); } @@ -712,6 +806,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.mempoolPositionSubscription.unsubscribe(); this.mempoolBlocksSubscription.unsubscribe(); this.blocksSubscription.unsubscribe(); + this.miningSubscription?.unsubscribe(); this.leaveTransaction(); } } From 7af185a9197fedac093a8b2ebdba3170f5cdc14c Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 8 Mar 2024 15:21:37 +0000 Subject: [PATCH 11/15] Tx audit tags handle coinbase --- .../transaction/transaction.component.html | 3 ++- .../transaction/transaction.component.ts | 17 ++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 211149b9d..188868b11 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -78,7 +78,8 @@ {{ pool.name }} - Expected in Block + Coinbase + Expected in Block Seen in Mempool Not seen in Mempool Added diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index eb9f49995..0167a3d43 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -36,12 +36,13 @@ interface Pool { } interface AuditStatus { - seen: boolean; - expected: boolean; - added: boolean; + seen?: boolean; + expected?: boolean; + added?: boolean; delayed?: number; - accelerated: boolean; - conflict: boolean; + accelerated?: boolean; + conflict?: boolean; + coinbase?: boolean; } @Component({ @@ -296,6 +297,8 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { switchMap(({ hash, height, txid }) => { const foundBlock = this.cacheService.getCachedBlock(height) || null; const auditAvailable = this.isAuditAvailable(height); + const isCoinbase = this.tx.vin.some(v => v.is_coinbase); + const fetchAudit = auditAvailable && !isCoinbase; return combineLatest([ foundBlock ? of(foundBlock.extras.pool) : this.apiService.getBlock$(hash).pipe( map(block => { @@ -305,7 +308,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { return of(null); }) ), - auditAvailable ? this.apiService.getBlockAudit$(hash).pipe( + fetchAudit ? this.apiService.getBlockAudit$(hash).pipe( map(audit => { const isAdded = audit.addedTxs.includes(txid); const isAccelerated = audit.acceleratedTxs.includes(txid); @@ -322,7 +325,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { catchError(() => { return of(null); }) - ) : of(null) + ) : of(isCoinbase ? { coinbase: true } : null) ]); }), catchError(() => { From dde671930649ba98f1b858a92d0fd4765f340bef Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 8 Mar 2024 16:47:15 +0000 Subject: [PATCH 12/15] Fix stuck Goggles on websocket reconnect --- .../block-overview-graph.component.html | 2 +- .../block-overview-graph.component.scss | 1 - frontend/src/app/dashboard/dashboard.component.ts | 2 +- frontend/src/app/services/websocket.service.ts | 6 +++--- 4 files changed, 5 insertions(+), 6 deletions(-) diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html index 34d192678..1d13e8b4e 100644 --- a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html @@ -3,7 +3,7 @@
-
+
not available
Date: Fri, 8 Mar 2024 19:16:09 +0000 Subject: [PATCH 13/15] Hide mining pools on clock blockchain --- .../blockchain-blocks/blockchain-blocks.component.html | 2 +- .../components/blockchain-blocks/blockchain-blocks.component.ts | 1 + .../src/app/components/clockchain/clockchain.component.html | 1 + 3 files changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index e9f64b9b8..2224ec0bf 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -56,7 +56,7 @@
-
+
{{ block.extras.pool.name}} diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 0da8ca7b5..760e9261d 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -27,6 +27,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { @Input() minimal: boolean = false; @Input() blockWidth: number = 125; @Input() spotlight: number = 0; + @Input() showPools: boolean = true; @Input() getHref?: (index, block) => string = (index, block) => `/block/${block.id}`; specialBlocks = specialBlocks; diff --git a/frontend/src/app/components/clockchain/clockchain.component.html b/frontend/src/app/components/clockchain/clockchain.component.html index 2f299cb3b..b1f64cd74 100644 --- a/frontend/src/app/components/clockchain/clockchain.component.html +++ b/frontend/src/app/components/clockchain/clockchain.component.html @@ -16,6 +16,7 @@ [minimal]="true" [count]="blockchainBlocks" [blockWidth]="blockWidth" + [showPools]="false" [spotlight]="mode === 'mined' ? -index - 1 : 0" [getHref]="getMinedUrl" > From 1665b0d9152aa6418297cda5c76bc5db89e69a57 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 9 Mar 2024 09:24:25 +0900 Subject: [PATCH 14/15] [accelerator] set accel graph bar min height --- .../acceleration-fees-graph/acceleration-fees-graph.component.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts index 001f005a1..c4ed65a77 100644 --- a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts @@ -247,6 +247,7 @@ export class AccelerationFeesGraphComponent implements OnInit, OnDestroy { type: 'bar', barWidth: '90%', large: true, + barMinHeight: 1, }, ], dataZoom: (this.widget || data.length === 0 )? undefined : [{ From bfde456ca8155a78a6389fd70518af005a9ebac6 Mon Sep 17 00:00:00 2001 From: softsimon Date: Sat, 9 Mar 2024 15:38:16 +0700 Subject: [PATCH 15/15] Only display docs enterprise upsell on official mempool --- frontend/src/app/docs/api-docs/api-docs-nav.component.html | 2 +- frontend/src/app/docs/api-docs/api-docs.component.html | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/docs/api-docs/api-docs-nav.component.html b/frontend/src/app/docs/api-docs/api-docs-nav.component.html index b2b34cb1e..7ec57714d 100644 --- a/frontend/src/app/docs/api-docs/api-docs-nav.component.html +++ b/frontend/src/app/docs/api-docs/api-docs-nav.component.html @@ -1,4 +1,4 @@ -
+

Get higher API limits with Mempool Enterprise®

More Info
diff --git a/frontend/src/app/docs/api-docs/api-docs.component.html b/frontend/src/app/docs/api-docs/api-docs.component.html index 2a48157d9..89165c90e 100644 --- a/frontend/src/app/docs/api-docs/api-docs.component.html +++ b/frontend/src/app/docs/api-docs/api-docs.component.html @@ -39,7 +39,7 @@
-
+

Get higher API limits with Mempool Enterprise®

Fee {{ tx.fee | number }} sat