diff --git a/backend/src/api/mining.ts b/backend/src/api/mining.ts index 4423e5f16..0724a6612 100644 --- a/backend/src/api/mining.ts +++ b/backend/src/api/mining.ts @@ -58,14 +58,14 @@ class Mining { /** * Get all mining pool stats for a pool */ - public async $getPoolStat(interval: string | null, poolId: number): Promise { + public async $getPoolStat(poolId: number): Promise { const pool = await PoolsRepository.$getPool(poolId); if (!pool) { throw new Error(`This mining pool does not exist`); } - const blockCount: number = await BlocksRepository.$blockCount(poolId, interval); - const emptyBlocks: EmptyBlocks[] = await BlocksRepository.$getEmptyBlocks(poolId, interval); + const blockCount: number = await BlocksRepository.$blockCount(poolId); + const emptyBlocks: EmptyBlocks[] = await BlocksRepository.$getEmptyBlocks(poolId); return { pool: pool, diff --git a/backend/src/index.ts b/backend/src/index.ts index fb358b1f3..c2de54521 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -299,7 +299,7 @@ class Server { .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/2y', routes.$getPools.bind(routes, '2y')) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/3y', routes.$getPools.bind(routes, '3y')) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/all', routes.$getPools.bind(routes, 'all')) - .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId/hashrate/:interval', routes.$getPoolHistoricalHashrate) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId/hashrate', routes.$getPoolHistoricalHashrate) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId/blocks', routes.$getPoolBlocks) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId/blocks/:height', routes.$getPoolBlocks) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId', routes.$getPool) diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 844f62bad..33f7a2d97 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -134,7 +134,7 @@ class BlocksRepository { /** * Get blocks count for a period */ - public async $blockCount(poolId: number | null, interval: string | null): Promise { + public async $blockCount(poolId: number | null, interval: string | null = null): Promise { interval = Common.getSqlInterval(interval); const params: any[] = []; diff --git a/backend/src/repositories/HashratesRepository.ts b/backend/src/repositories/HashratesRepository.ts index a217dcc16..4371b9e0a 100644 --- a/backend/src/repositories/HashratesRepository.ts +++ b/backend/src/repositories/HashratesRepository.ts @@ -119,28 +119,39 @@ class HashratesRepository { /** * Returns a pool hashrate history */ - public async $getPoolWeeklyHashrate(interval: string | null, poolId: number): Promise { - interval = Common.getSqlInterval(interval); - + public async $getPoolWeeklyHashrate(poolId: number): Promise { const connection = await DB.pool.getConnection(); - let query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate, share, pools.name as poolName - FROM hashrates - JOIN pools on pools.id = pool_id`; - - if (interval) { - query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() - AND hashrates.type = 'weekly' - AND pool_id = ${poolId}`; - } else { - query += ` WHERE hashrates.type = 'weekly' - AND pool_id = ${poolId}`; - } - - query += ` ORDER by hashrate_timestamp`; + // Find hashrate boundaries + let query = `SELECT MIN(hashrate_timestamp) as firstTimestamp, MAX(hashrate_timestamp) as lastTimestamp + FROM hashrates + JOIN pools on pools.id = pool_id + WHERE hashrates.type = 'weekly' AND pool_id = ${poolId} AND avg_hashrate != 0 + ORDER by hashrate_timestamp LIMIT 1` + let boundaries = { + firstTimestamp: '1970-01-01', + lastTimestamp: '9999-01-01' + }; try { const [rows]: any[] = await connection.query(query); + boundaries = rows[0]; + connection.release(); + } catch (e) { + connection.release(); + logger.err('$getPoolWeeklyHashrate() error' + (e instanceof Error ? e.message : e)); + } + + // Get hashrates entries between boundaries + query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate, share, pools.name as poolName + FROM hashrates + JOIN pools on pools.id = pool_id + WHERE hashrates.type = 'weekly' AND hashrate_timestamp BETWEEN ? AND ? + AND pool_id = ${poolId} + ORDER by hashrate_timestamp`; + + try { + const [rows]: any[] = await connection.query(query, [boundaries.firstTimestamp, boundaries.lastTimestamp]); connection.release(); return rows; diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 69dde1a59..8ccc9c2e1 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -538,7 +538,7 @@ class Routes { public async $getPool(req: Request, res: Response) { try { - const stats = await mining.$getPoolStat(req.params.interval ?? null, parseInt(req.params.poolId, 10)); + const stats = await mining.$getPoolStat(parseInt(req.params.poolId, 10)); res.header('Pragma', 'public'); res.header('Cache-control', 'public'); res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); @@ -605,7 +605,7 @@ class Routes { public async $getPoolHistoricalHashrate(req: Request, res: Response) { try { - const hashrates = await HashratesRepository.$getPoolWeeklyHashrate(req.params.interval ?? null, parseInt(req.params.poolId, 10)); + const hashrates = await HashratesRepository.$getPoolWeeklyHashrate(parseInt(req.params.poolId, 10)); const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp(); res.header('Pragma', 'public'); res.header('Cache-control', 'public'); diff --git a/frontend/src/app/components/pool/pool.component.html b/frontend/src/app/components/pool/pool.component.html index 8478aa566..4e6d78d2b 100644 --- a/frontend/src/app/components/pool/pool.component.html +++ b/frontend/src/app/components/pool/pool.component.html @@ -1,36 +1,11 @@
-
-

- - {{ poolStats.pool.name }} -

-
-
-
-
- - - - - -
-
-
-
-
+

+ + {{ poolStats.pool.name }} +

diff --git a/frontend/src/app/components/pool/pool.component.ts b/frontend/src/app/components/pool/pool.component.ts index 7cc909abd..282febf2f 100644 --- a/frontend/src/app/components/pool/pool.component.ts +++ b/frontend/src/app/components/pool/pool.component.ts @@ -1,9 +1,8 @@ import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; -import { FormBuilder, FormGroup } from '@angular/forms'; import { ActivatedRoute } from '@angular/router'; import { EChartsOption, graphic } from 'echarts'; -import { BehaviorSubject, combineLatest, Observable } from 'rxjs'; -import { distinctUntilChanged, map, startWith, switchMap, tap, toArray } from 'rxjs/operators'; +import { BehaviorSubject, Observable } from 'rxjs'; +import { distinctUntilChanged, map, switchMap, tap, toArray } from 'rxjs/operators'; import { BlockExtended, PoolStat } from 'src/app/interfaces/node-api.interface'; import { ApiService } from 'src/app/services/api.service'; import { StateService } from 'src/app/services/state.service'; @@ -24,8 +23,6 @@ export class PoolComponent implements OnInit { blocks$: Observable; isLoading = true; - radioGroupForm: FormGroup; - chartOptions: EChartsOption = {}; chartInitOptions = { renderer: 'svg', @@ -44,34 +41,27 @@ export class PoolComponent implements OnInit { private apiService: ApiService, private route: ActivatedRoute, public stateService: StateService, - private formBuilder: FormBuilder, ) { - this.radioGroupForm = this.formBuilder.group({ dateSpan: 'all' }); - this.radioGroupForm.controls.dateSpan.setValue('all'); } ngOnInit(): void { - this.poolStats$ = combineLatest([ - this.route.params.pipe(map((params) => params.poolId)), - this.radioGroupForm.get('dateSpan').valueChanges.pipe(startWith('all')), - ]) + this.poolStats$ = this.route.params.pipe(map((params) => params.poolId)) .pipe( - switchMap((params: any) => { - this.poolId = params[0]; - return this.apiService.getPoolHashrate$(this.poolId, params[1] ?? 'all') + switchMap((poolId: any) => { + this.poolId = poolId; + return this.apiService.getPoolHashrate$(this.poolId) .pipe( switchMap((data) => { this.prepareChartOptions(data.hashrates.map(val => [val.timestamp * 1000, val.avgHashrate])); - return params; + return poolId; }), - toArray(), ) }), - switchMap((params: any) => { + switchMap(() => { if (this.blocks.length === 0) { this.fromHeightSubject.next(undefined); } - return this.apiService.getPoolStats$(this.poolId, params[1] ?? '1w'); + return this.apiService.getPoolStats$(this.poolId); }), map((poolStats) => { let regexes = '"'; diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index fcac428a9..858da3273 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -136,15 +136,12 @@ export class ApiService { ); } - getPoolStats$(poolId: number, interval: string | undefined): Observable { - return this.httpClient.get( - this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${poolId}` + - (interval !== undefined ? `/${interval}` : '') - ); + getPoolStats$(poolId: number): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${poolId}`); } - getPoolHashrate$(poolId: number, interval: string | undefined): Observable { - return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${poolId}/hashrate/${interval}`); + getPoolHashrate$(poolId: number): Observable { + return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${poolId}/hashrate`); } getPoolBlocks$(poolId: number, fromHeight: number): Observable {