From b254be2f49b7491086743cb5ddeb6b880ea2a813 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 6 Sep 2024 17:46:12 +0000 Subject: [PATCH] add stratum job to pool page --- .../app/components/pool/pool.component.html | 114 ++++++++- .../app/components/pool/pool.component.scss | 232 +++++++++++------- .../src/app/components/pool/pool.component.ts | 36 ++- .../stratum-list/stratum-list.component.ts | 5 +- 4 files changed, 292 insertions(+), 95 deletions(-) diff --git a/frontend/src/app/components/pool/pool.component.html b/frontend/src/app/components/pool/pool.component.html index b3c6430a8..faa0003c4 100644 --- a/frontend/src/app/components/pool/pool.component.html +++ b/frontend/src/app/components/pool/pool.component.html @@ -10,7 +10,7 @@

{{ poolStats.pool.name }}

-
+
@@ -173,7 +173,119 @@
+ + +

Next block

+
+
+
+ + + + + + + + + + + + +
+ + + + + + + + + + + + + + + + + +
HeightExpectedRewardTimestamp
+ {{ job.height }} + + + + + ~ + + + + +
+
+ + + + + + + + + + + + + + + + + +
Coinbase tagCleanPrevhashJob Received
+ {{ job.scriptsig | hex2ascii }} + + @if (job.cleanJobs) { + + } @else { + + } + + + + + + +
+
+ + + + + + + + + @for (branch of job.merkleBranches; track $index) { + + } + @for (_ of [].constructor(Math.max(0, 12 - job.merkleBranches.length)); track $index) { + + } + + +
+ + Merkle Branches +   + + +
+
+
+
+
+
+ +

Blocks

diff --git a/frontend/src/app/components/pool/pool.component.scss b/frontend/src/app/components/pool/pool.component.scss index 5c2fedd26..31d12474f 100644 --- a/frontend/src/app/components/pool/pool.component.scss +++ b/frontend/src/app/components/pool/pool.component.scss @@ -49,111 +49,110 @@ div.scrollable { max-height: 75px; } -.box { - padding-bottom: 5px; +.pool-details { @media (min-width: 767.98px) { min-height: 187px; } -} -.label { - width: 25%; - @media (min-width: 767.98px) { - vertical-align: middle; + .label { + width: 25%; + @media (min-width: 767.98px) { + vertical-align: middle; + } + @media (max-width: 767.98px) { + font-weight: bold; + } } - @media (max-width: 767.98px) { - font-weight: bold; + .label.addresses { + vertical-align: top; + padding-top: 25px; + } + .addresses-data { + vertical-align: top; + font-family: monospace; + font-size: 14px; } -} -.label.addresses { - vertical-align: top; - padding-top: 25px; -} -.addresses-data { - vertical-align: top; - font-family: monospace; - font-size: 14px; -} -.data { - text-align: right; - padding-left: 5%; - @media (max-width: 992px) { - text-align: left; - padding-left: 12px; - } - @media (max-width: 450px) { + .data { text-align: right; + padding-left: 5%; + @media (max-width: 992px) { + text-align: left; + padding-left: 12px; + } + @media (max-width: 450px) { + text-align: right; + } } -} -.progress { - background-color: var(--secondary); -} + .progress { + background-color: var(--secondary); + } -.coinbase { - width: 20%; - @media (max-width: 875px) { - display: none; - } -} - -.height { - width: 10%; -} - -.timestamp { - @media (max-width: 875px) { - padding-left: 50px; - } - @media (max-width: 685px) { - display: none; - } -} - -.mined { - width: 13%; - @media (max-width: 1100px) { - display: none; - } -} - -.txs { - padding-right: 40px; - @media (max-width: 1100px) { - padding-right: 10px; - } - @media (max-width: 875px) { - padding-right: 20px; - } - @media (max-width: 567px) { - padding-right: 10px; - } -} - -.size { - width: 12%; - @media (max-width: 1000px) { - width: 15%; - } - @media (max-width: 875px) { + .coinbase { width: 20%; + @media (max-width: 875px) { + display: none; + } } - @media (max-width: 650px) { - width: 20%; - } - @media (max-width: 450px) { - display: none; - } -} -.scriptmessage { - overflow: hidden; - display: inline-block; - text-overflow: ellipsis; - vertical-align: middle; - width: auto; - text-align: left; + .height { + width: 10%; + } + + .timestamp { + @media (max-width: 875px) { + padding-left: 50px; + } + @media (max-width: 685px) { + display: none; + } + } + + .mined { + width: 13%; + @media (max-width: 1100px) { + display: none; + } + } + + .txs { + padding-right: 40px; + @media (max-width: 1100px) { + padding-right: 10px; + } + @media (max-width: 875px) { + padding-right: 20px; + } + @media (max-width: 567px) { + padding-right: 10px; + } + } + + .size { + width: 12%; + @media (max-width: 1000px) { + width: 15%; + } + @media (max-width: 875px) { + width: 20%; + } + @media (max-width: 650px) { + width: 20%; + } + @media (max-width: 450px) { + display: none; + } + } + + .scriptmessage { + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + vertical-align: middle; + width: auto; + text-align: left; + } } .skeleton-loader { @@ -214,4 +213,55 @@ div.scrollable { .taller-row { height: 75px; +} + +.stratum-table { + width: 100%; + + .merkle { + width: 100px; + } + + .empty-branch { + outline: solid 1px white; + outline-offset: -1px; + + &::after { + content: ""; + position: absolute; + left: 0; + top: 0; + height: 100%; + width: 100%; + background: linear-gradient(to top left, transparent, transparent 48%, white 49%, white 51%, transparent 52%, transparent); + } + } + + td { + position: relative; + height: 2em; + } +} + +.job-table { + td, th { + width: 25%; + max-width: 25%; + min-width: 25%; + overflow: hidden; + text-overflow: ellipsis; + padding: 0.1rem 0.2rem; + } + + @media (max-width: 767.98px) { + .expected, .timestamp, .clean, .job-received { + display: none; + } + } +} + +.title-link, .title-link:hover, .title-link:focus, .title-link:active { + display: block; + text-decoration: none; + color: inherit; } \ No newline at end of file diff --git a/frontend/src/app/components/pool/pool.component.ts b/frontend/src/app/components/pool/pool.component.ts index 1893f0a48..23b795613 100644 --- a/frontend/src/app/components/pool/pool.component.ts +++ b/frontend/src/app/components/pool/pool.component.ts @@ -10,6 +10,9 @@ import { selectPowerOfTen } from '@app/bitcoin.utils'; import { formatNumber } from '@angular/common'; import { SeoService } from '@app/services/seo.service'; import { HttpErrorResponse } from '@angular/common/http'; +import { StratumJob } from '../../interfaces/websocket.interface'; +import { WebsocketService } from '../../services/websocket.service'; +import { MiningService } from '../../services/mining.service'; interface AccelerationTotal { cost: number, @@ -27,12 +30,16 @@ export class PoolComponent implements OnInit { @Input() left: number | string = 75; gfg = true; + stratumEnabled = this.stateService.env.STRATUM_ENABLED; formatNumber = formatNumber; + Math = Math; slugSubscription: Subscription; poolStats$: Observable; blocks$: Observable; oobFees$: Observable; + job$: Observable; + expectedBlockTime$: Observable; isLoading = true; error: HttpErrorResponse | null = null; @@ -53,6 +60,8 @@ export class PoolComponent implements OnInit { private apiService: ApiService, private route: ActivatedRoute, public stateService: StateService, + private websocketService: WebsocketService, + private miningService: MiningService, private seoService: SeoService, ) { this.auditAvailable = this.stateService.env.AUDIT; @@ -62,7 +71,7 @@ export class PoolComponent implements OnInit { this.slugSubscription = this.route.params.pipe(map((params) => params.slug)).subscribe((slug) => { this.isLoading = true; this.blocks = []; - this.chartOptions = {}; + this.chartOptions = {}; this.slug = slug; this.initializeObservables(); }); @@ -129,6 +138,31 @@ export class PoolComponent implements OnInit { }), filter(oob => oob.length === 3 && oob[2].count > 0) ); + + if (this.stratumEnabled) { + this.job$ = combineLatest([ + this.poolStats$.pipe( + tap((poolStats) => { + this.websocketService.startTrackStratum(poolStats.pool.unique_id); + }) + ), + this.stateService.stratumJobs$ + ]).pipe( + map(([poolStats, jobs]) => { + return jobs[poolStats.pool.unique_id]; + }) + ); + + this.expectedBlockTime$ = combineLatest([ + this.miningService.getMiningStats('1w'), + this.poolStats$, + this.stateService.difficultyAdjustment$ + ]).pipe( + map(([miningStats, poolStat, da]) => { + return (da.timeAvg / ((poolStat.estimatedHashrate || 0) / (miningStats.lastEstimatedHashrate * 1_000_000_000_000_000_000))) + Date.now() + da.timeOffset; + }) + ); + } } prepareChartOptions(hashrate, share) { diff --git a/frontend/src/app/components/stratum/stratum-list/stratum-list.component.ts b/frontend/src/app/components/stratum/stratum-list/stratum-list.component.ts index 1ab1a1c94..0af9f0976 100644 --- a/frontend/src/app/components/stratum/stratum-list/stratum-list.component.ts +++ b/frontend/src/app/components/stratum/stratum-list/stratum-list.component.ts @@ -36,13 +36,14 @@ function parseTag(scriptSig: string): string { for (let i = 0; i < hex.length; i += 2) { bytes.push(parseInt(hex.substr(i, 2), 16)); } - const ascii = new TextDecoder('utf8').decode(Uint8Array.from(bytes)).replace(/\uFFFD/g, '').replace(/\\0/g, ''); + // eslint-disable-next-line no-control-regex + const ascii = new TextDecoder('utf8').decode(Uint8Array.from(bytes)).replace(/\uFFFD/g, '').replace(/\\0/g, '').replace(/[\x00-\x1F\x7F-\x9F]/g, ''); if (ascii.includes('/ViaBTC/')) { return '/ViaBTC/'; } else if (ascii.includes('SpiderPool/')) { return 'SpiderPool/'; } - return ascii.match(/\/.*\//)?.[0] || ascii; + return (ascii.match(/\/.*\//)?.[0] || ascii).trim(); } @Component({