diff --git a/backend/src/api/mining.ts b/backend/src/api/mining.ts index 2a978868f..beca52893 100644 --- a/backend/src/api/mining.ts +++ b/backend/src/api/mining.ts @@ -69,6 +69,19 @@ class Mining { emptyBlocks: emptyBlocks, }; } + + /** + * Return the historical difficulty adjustments and oldest indexed block timestamp + */ + public async $getHistoricalDifficulty(interval: string | null): Promise { + const difficultyAdjustments = await BlocksRepository.$getBlocksDifficulty(interval); + const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp()); + + return { + adjustments: difficultyAdjustments, + oldestIndexedBlockTimestamp: oldestBlock.getTime(), + } + } } export default new Mining(); diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index 5d2cdbe36..ac0ea25bc 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -232,7 +232,7 @@ class BlocksRepository { const connection = await DB.pool.getConnection(); - let query = `SELECT MIN(blockTimestamp) as timestamp, difficulty, height + let query = `SELECT MIN(UNIX_TIMESTAMP(blockTimestamp)) as timestamp, difficulty, height FROM blocks`; if (interval) { diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 2159c0721..4a9cb1f8f 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -577,7 +577,7 @@ class Routes { public async $getHistoricalDifficulty(req: Request, res: Response) { try { - const stats = await BlocksRepository.$getBlocksDifficulty(req.params.interval ?? null); + const stats = await mining.$getHistoricalDifficulty(req.params.interval ?? null); res.header('Pragma', 'public'); res.header('Cache-control', 'public'); res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); diff --git a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html index b63ba29f5..78350d5d5 100644 --- a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html @@ -5,6 +5,31 @@
+
+
+
+ + + + + + +
+
+
+ @@ -14,12 +39,12 @@ - - - - - - + + + + + +
Change
{{ change[2] }}‎{{ change[0] | date:'yyyy-MM-dd HH:mm' }}{{ formatNumber(change[1], locale, '1.2-2') }}{{ formatNumber(change[3], locale, '1.2-2') }}%
{{ diffChange.height }}‎{{ diffChange.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}{{ formatNumber(diffChange.difficulty, locale, '1.2-2') }}{{ formatNumber(diffChange.change, locale, '1.2-2') }}%
diff --git a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts index 0e343843d..97be13f78 100644 --- a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts @@ -1,10 +1,11 @@ import { Component, Inject, LOCALE_ID, OnInit } from '@angular/core'; import { EChartsOption } from 'echarts'; import { Observable } from 'rxjs'; -import { map, share, tap } from 'rxjs/operators'; +import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; import { ApiService } from 'src/app/services/api.service'; import { SeoService } from 'src/app/services/seo.service'; -import { formatNumber } from "@angular/common"; +import { formatNumber } from '@angular/common'; +import { FormBuilder, FormGroup } from '@angular/forms'; @Component({ selector: 'app-difficulty-chart', @@ -20,6 +21,8 @@ import { formatNumber } from "@angular/common"; `], }) export class DifficultyChartComponent implements OnInit { + radioGroupForm: FormGroup; + chartOptions: EChartsOption = {}; chartInitOptions = { renderer: 'svg' @@ -33,34 +36,45 @@ export class DifficultyChartComponent implements OnInit { @Inject(LOCALE_ID) public locale: string, private seoService: SeoService, private apiService: ApiService, + private formBuilder: FormBuilder, ) { this.seoService.setTitle($localize`:@@mining.difficulty:Difficulty`); + this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); + this.radioGroupForm.controls.dateSpan.setValue('1y'); } ngOnInit(): void { - this.difficultyObservable$ = this.apiService.getHistoricalDifficulty$(undefined) + this.difficultyObservable$ = this.radioGroupForm.get('dateSpan').valueChanges .pipe( - map(data => { - let formatted = []; - for (let i = 0; i < data.length - 1; ++i) { - const change = (data[i].difficulty / data[i + 1].difficulty - 1) * 100; - formatted.push([ - data[i].timestamp, - data[i].difficulty, - data[i].height, - formatNumber(change, this.locale, '1.2-2'), - change, - formatNumber(data[i].difficulty, this.locale, '1.2-2'), - ]); - } - return formatted; - }), - tap(data => { - this.prepareChartOptions(data); - this.isLoading = false; - }), - share() - ) + startWith('1y'), + switchMap((timespan) => { + return this.apiService.getHistoricalDifficulty$(timespan) + .pipe( + tap(data => { + this.prepareChartOptions(data.adjustments.map(val => [val.timestamp * 1000, val.difficulty])); + this.isLoading = false; + }), + map(data => { + const availableTimespanDay = ( + (new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp / 1000) + ) / 3600 / 24; + + const tableData = []; + for (let i = 0; i < data.adjustments.length - 1; ++i) { + const change = (data.adjustments[i].difficulty / data.adjustments[i + 1].difficulty - 1) * 100; + tableData.push(Object.assign(data.adjustments[i], { + change: change + })); + } + return { + availableTimespanDay: availableTimespanDay, + data: tableData + }; + }), + ); + }), + share() + ); } prepareChartOptions(data) { @@ -88,7 +102,7 @@ export class DifficultyChartComponent implements OnInit { type: 'value', axisLabel: { fontSize: 11, - formatter: function(val) { + formatter: (val) => { const diff = val / Math.pow(10, 12); // terra return diff.toString() + 'T'; } diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts index 9a7a33fc0..fc5a8da60 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts @@ -107,7 +107,7 @@ export class PoolRankingComponent implements OnInit { if (parseFloat(pool.share) < poolShareThreshold) { return; } - data.push({ + data.push({ value: pool.share, name: pool.name + (this.isMobile() ? `` : ` (${pool.share}%)`), label: { @@ -115,9 +115,9 @@ export class PoolRankingComponent implements OnInit { overflow: 'break', }, tooltip: { - backgroundColor: "#282d47", + backgroundColor: '#282d47', textStyle: { - color: "#FFFFFF", + color: '#FFFFFF', }, formatter: () => { if (this.poolsWindowPreference === '24h') { @@ -131,7 +131,7 @@ export class PoolRankingComponent implements OnInit { } }, data: pool.poolId, - }); + } as PieSeriesOption); }); return data; } @@ -205,10 +205,10 @@ export class PoolRankingComponent implements OnInit { this.chartInstance = ec; this.chartInstance.on('click', (e) => { - this.router.navigate(['/mining/pool/', e.data.data]); - }) + this.router.navigate(['/mining/pool/', e.data.data]); + }); } - + /** * Default mining stats if something goes wrong */ diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index 950a99fa7..9a6bbc0b8 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -150,7 +150,7 @@ export class ApiService { ); } - getHistoricalDifficulty$(interval: string | undefined): Observable { + getHistoricalDifficulty$(interval: string | undefined): Observable { return this.httpClient.get( this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/difficulty` + (interval !== undefined ? `/${interval}` : '')