From 7270b1ccacdcbdfbbdaebff914d6d15331b2c965 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Wed, 16 Feb 2022 21:20:28 +0900 Subject: [PATCH 1/4] Create difficulty chart component --- backend/src/api/blocks.ts | 10 +- backend/src/index.ts | 9 +- backend/src/repositories/BlocksRepository.ts | 24 +++++ backend/src/routes.ts | 12 +++ frontend/src/app/app-routing.module.ts | 13 +++ frontend/src/app/app.module.ts | 2 + .../difficulty-chart.component.html | 8 ++ .../difficulty-chart.component.scss | 0 .../difficulty-chart.component.ts | 102 ++++++++++++++++++ .../pool-ranking/pool-ranking.component.ts | 7 +- frontend/src/app/services/api.service.ts | 21 +++- 11 files changed, 192 insertions(+), 16 deletions(-) create mode 100644 frontend/src/app/components/difficulty-chart/difficulty-chart.component.html create mode 100644 frontend/src/app/components/difficulty-chart/difficulty-chart.component.scss create mode 100644 frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 7513f259e..c406ae803 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -199,6 +199,7 @@ class Blocks { const chunkSize = 10000; let totaIndexed = 0; + let indexedThisRun = 0; while (currentBlockHeight >= lastBlockToIndex) { const endBlock = Math.max(0, lastBlockToIndex, currentBlockHeight - chunkSize + 1); @@ -207,9 +208,11 @@ class Blocks { if (missingBlockHeights.length <= 0) { logger.debug(`No missing blocks between #${currentBlockHeight} to #${endBlock}`); currentBlockHeight -= chunkSize; + totaIndexed += chunkSize; continue; } + totaIndexed += chunkSize - missingBlockHeights.length; logger.debug(`Indexing ${missingBlockHeights.length} blocks from #${currentBlockHeight} to #${endBlock}`); for (const blockHeight of missingBlockHeights) { @@ -219,8 +222,10 @@ class Blocks { try { if (totaIndexed % 100 === 0 || blockHeight === lastBlockToIndex) { const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); - const blockPerSeconds = Math.round(totaIndexed / elapsedSeconds); - logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds} blocks/sec | total: ${totaIndexed} | elapsed: ${elapsedSeconds} seconds`); + const blockPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); + const progress = Math.round(totaIndexed / indexingBlockAmount * 100); + const timeLeft = Math.round((indexingBlockAmount - totaIndexed) / blockPerSeconds); + logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds} blocks/sec | total: ${totaIndexed}/${indexingBlockAmount} (${progress}%) | elapsed: ${elapsedSeconds} seconds | left: ~${timeLeft} seconds`); } const blockHash = await bitcoinApi.$getBlockHash(blockHeight); const block = await bitcoinApi.$getBlock(blockHash); @@ -228,6 +233,7 @@ class Blocks { const blockExtended = await this.$getBlockExtended(block, transactions); await blocksRepository.$saveBlockInDatabase(blockExtended); ++totaIndexed; + ++indexedThisRun; } catch (e) { logger.err(`Something went wrong while indexing blocks.` + e); } diff --git a/backend/src/index.ts b/backend/src/index.ts index 1f8575294..23c70f59d 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -259,10 +259,7 @@ class Server { ; } - const indexingAvailable = - ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) && - config.DATABASE.ENABLED === true; - if (indexingAvailable) { + if (Common.indexingEnabled()) { this.app .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/24h', routes.$getPools.bind(routes, '24h')) .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/3d', routes.$getPools.bind(routes, '3d')) @@ -277,7 +274,9 @@ class Server { .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) - .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId/:interval', routes.$getPool); + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:poolId/:interval', routes.$getPool) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty', routes.$getHistoricalDifficulty) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty/:interval', routes.$getHistoricalDifficulty); } if (config.BISQ.ENABLED) { diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index adc3a1f31..d57bc8eb0 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -223,6 +223,30 @@ class BlocksRepository { return rows[0]; } + + /** + * Return blocks difficulty + */ + public async $getBlocksDifficulty(interval: string | null): Promise { + interval = Common.getSqlInterval(interval); + + const connection = await DB.pool.getConnection(); + + let query = `SELECT MIN(blockTimestamp) as timestamp, difficulty + FROM blocks`; + + if (interval) { + query += ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY difficulty + ORDER BY blockTimestamp DESC`; + + const [rows]: any[] = await connection.query(query); + connection.release(); + + return rows; + } } export default new BlocksRepository(); diff --git a/backend/src/routes.ts b/backend/src/routes.ts index 66ecebd31..2159c0721 100644 --- a/backend/src/routes.ts +++ b/backend/src/routes.ts @@ -575,6 +575,18 @@ class Routes { } } + public async $getHistoricalDifficulty(req: Request, res: Response) { + try { + const stats = await BlocksRepository.$getBlocksDifficulty(req.params.interval ?? null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json(stats); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + public async getBlock(req: Request, res: Response) { try { const result = await bitcoinApi.$getBlock(req.params.hash); diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 4018ed64e..6ce39b1d2 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -27,6 +27,7 @@ import { AssetGroupComponent } from './components/assets/asset-group/asset-group import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; import { AssetsComponent } from './components/assets/assets.component'; import { PoolComponent } from './components/pool/pool.component'; +import { DifficultyChartComponent } from './components/difficulty-chart/difficulty-chart.component'; let routes: Routes = [ { @@ -63,6 +64,10 @@ let routes: Routes = [ path: 'blocks', component: LatestBlocksComponent, }, + { + path: 'mining/difficulty', + component: DifficultyChartComponent, + }, { path: 'mining/pools', component: PoolRankingComponent, @@ -155,6 +160,10 @@ let routes: Routes = [ path: 'blocks', component: LatestBlocksComponent, }, + { + path: 'mining/difficulty', + component: DifficultyChartComponent, + }, { path: 'mining/pools', component: PoolRankingComponent, @@ -241,6 +250,10 @@ let routes: Routes = [ path: 'blocks', component: LatestBlocksComponent, }, + { + path: 'mining/difficulty', + component: DifficultyChartComponent, + }, { path: 'mining/pools', component: PoolRankingComponent, diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 20eb2ea03..15bebd033 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -68,6 +68,7 @@ import { PushTransactionComponent } from './components/push-transaction/push-tra import { NgbModule } from '@ng-bootstrap/ng-bootstrap'; import { AssetsFeaturedComponent } from './components/assets/assets-featured/assets-featured.component'; import { AssetGroupComponent } from './components/assets/asset-group/asset-group.component'; +import { DifficultyChartComponent } from './components/difficulty-chart/difficulty-chart.component'; @NgModule({ declarations: [ @@ -118,6 +119,7 @@ import { AssetGroupComponent } from './components/assets/asset-group/asset-group AssetsNavComponent, AssetsFeaturedComponent, AssetGroupComponent, + DifficultyChartComponent, ], imports: [ BrowserModule.withServerTransition({ appId: 'serverApp' }), diff --git a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html new file mode 100644 index 000000000..0a9a60620 --- /dev/null +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html @@ -0,0 +1,8 @@ +
+ +
+
+
+
+ +
diff --git a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.scss b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.scss new file mode 100644 index 000000000..e69de29bb diff --git a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts new file mode 100644 index 000000000..635a8a6d9 --- /dev/null +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts @@ -0,0 +1,102 @@ +import { Component, OnInit } from '@angular/core'; +import { EChartsOption } from 'echarts'; +import { Observable } from 'rxjs'; +import { map, tap } from 'rxjs/operators'; +import { ApiService } from 'src/app/services/api.service'; +import { SeoService } from 'src/app/services/seo.service'; + +@Component({ + selector: 'app-difficulty-chart', + templateUrl: './difficulty-chart.component.html', + styleUrls: ['./difficulty-chart.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 38%; + left: calc(50% - 15px); + z-index: 100; + } + `], +}) +export class DifficultyChartComponent implements OnInit { + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg' + }; + + difficultyObservable$: Observable; + isLoading = true; + + constructor( + private seoService: SeoService, + private apiService: ApiService, + ) { + this.seoService.setTitle($localize`:@@mining.difficulty:Difficulty`); + } + + ngOnInit(): void { + this.difficultyObservable$ = this.apiService.getHistoricalDifficulty$(undefined) + .pipe( + map(data => { + return data.map(val => [val.timestamp, val.difficulty]) + }), + tap(data => { + this.prepareChartOptions(data); + this.isLoading = false; + }) + ) + } + + prepareChartOptions(data) { + this.chartOptions = { + title: { + text: $localize`:@@mining.difficulty:Difficulty`, + left: 'center', + textStyle: { + color: '#FFF', + }, + }, + tooltip: { + show: true, + trigger: 'axis', + }, + axisPointer: { + type: 'line', + }, + xAxis: [ + { + type: 'time', + } + ], + yAxis: { + type: 'value', + axisLabel: { + fontSize: 11, + formatter: function(val) { + const diff = val / Math.pow(10, 12); // terra + return diff.toString() + 'T'; + } + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: '#ffffff66', + opacity: 0.25, + } + } + }, + series: [ + { + data: data, + type: 'line', + smooth: false, + lineStyle: { + width: 3, + }, + areaStyle: {} + }, + ], + }; + } + +} 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 d1b64f190..9a7a33fc0 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.ts +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.ts @@ -1,4 +1,4 @@ -import { Component, OnDestroy, OnInit } from '@angular/core'; +import { Component, OnInit } from '@angular/core'; import { FormBuilder, FormGroup } from '@angular/forms'; import { Router } from '@angular/router'; import { EChartsOption, PieSeriesOption } from 'echarts'; @@ -23,7 +23,7 @@ import { StateService } from '../../services/state.service'; } `], }) -export class PoolRankingComponent implements OnInit, OnDestroy { +export class PoolRankingComponent implements OnInit { poolsWindowPreference: string; radioGroupForm: FormGroup; @@ -90,9 +90,6 @@ export class PoolRankingComponent implements OnInit, OnDestroy { ); } - ngOnDestroy(): void { - } - formatPoolUI(pool: SinglePoolStats) { pool['blockText'] = pool.blockCount.toString() + ` (${pool.share}%)`; return pool; diff --git a/frontend/src/app/services/api.service.ts b/frontend/src/app/services/api.service.ts index bf468c467..950a99fa7 100644 --- a/frontend/src/app/services/api.service.ts +++ b/frontend/src/app/services/api.service.ts @@ -129,12 +129,18 @@ export class ApiService { return this.httpClient.post(this.apiBaseUrl + this.apiBasePath + '/api/tx', hexPayload, { responseType: 'text' as 'json'}); } - listPools$(interval: string | null) : Observable { - return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pools/${interval}`); + listPools$(interval: string | undefined) : Observable { + return this.httpClient.get( + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pools` + + (interval !== undefined ? `/${interval}` : '') + ); } - getPoolStats$(poolId: number, interval: string | null): Observable { - return this.httpClient.get(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${poolId}/${interval}`); + getPoolStats$(poolId: number, interval: string | undefined): Observable { + return this.httpClient.get( + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pool/${poolId}` + + (interval !== undefined ? `/${interval}` : '') + ); } getPoolBlocks$(poolId: number, fromHeight: number): Observable { @@ -143,4 +149,11 @@ export class ApiService { (fromHeight !== undefined ? `/${fromHeight}` : '') ); } + + getHistoricalDifficulty$(interval: string | undefined): Observable { + return this.httpClient.get( + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/difficulty` + + (interval !== undefined ? `/${interval}` : '') + ); + } } From 9fa7e58d827e3a6bee2a3c87794428924030c11d Mon Sep 17 00:00:00 2001 From: nymkappa Date: Wed, 16 Feb 2022 22:56:06 +0900 Subject: [PATCH 2/4] Show all difficulty adjustment in a table - Need pagination --- backend/src/repositories/BlocksRepository.ts | 2 +- .../difficulty-chart.component.html | 19 +++++++++++++++ .../difficulty-chart.component.ts | 24 +++++++++++++++---- .../pool-ranking/pool-ranking.component.html | 2 +- 4 files changed, 41 insertions(+), 6 deletions(-) diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index d57bc8eb0..5d2cdbe36 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 + let query = `SELECT MIN(blockTimestamp) as timestamp, difficulty, height FROM blocks`; if (interval) { 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 0a9a60620..b63ba29f5 100644 --- a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html @@ -5,4 +5,23 @@
+ + + + + + + + + + + + + + + + + +
BlockTimestampDifficultyChange
{{ change[2] }}‎{{ change[0] | date:'yyyy-MM-dd HH:mm' }}{{ formatNumber(change[1], locale, '1.2-2') }}{{ formatNumber(change[3], 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 635a8a6d9..0e343843d 100644 --- a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts @@ -1,9 +1,10 @@ -import { Component, OnInit } from '@angular/core'; +import { Component, Inject, LOCALE_ID, OnInit } from '@angular/core'; import { EChartsOption } from 'echarts'; import { Observable } from 'rxjs'; -import { map, tap } from 'rxjs/operators'; +import { map, share, 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"; @Component({ selector: 'app-difficulty-chart', @@ -26,8 +27,10 @@ export class DifficultyChartComponent implements OnInit { difficultyObservable$: Observable; isLoading = true; + formatNumber = formatNumber; constructor( + @Inject(LOCALE_ID) public locale: string, private seoService: SeoService, private apiService: ApiService, ) { @@ -38,12 +41,25 @@ export class DifficultyChartComponent implements OnInit { this.difficultyObservable$ = this.apiService.getHistoricalDifficulty$(undefined) .pipe( map(data => { - return data.map(val => [val.timestamp, val.difficulty]) + 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() ) } diff --git a/frontend/src/app/components/pool-ranking/pool-ranking.component.html b/frontend/src/app/components/pool-ranking/pool-ranking.component.html index 1f6fdbc0e..ac59ab2d2 100644 --- a/frontend/src/app/components/pool-ranking/pool-ranking.component.html +++ b/frontend/src/app/components/pool-ranking/pool-ranking.component.html @@ -43,7 +43,7 @@ - +
From f45103e7e34ca562a1f0e8129060c87456815ef1 Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 17 Feb 2022 09:41:05 +0900 Subject: [PATCH 3/4] Add difficulty chart timespan selection --- backend/src/api/mining.ts | 13 ++++ backend/src/repositories/BlocksRepository.ts | 2 +- backend/src/routes.ts | 2 +- .../difficulty-chart.component.html | 37 +++++++++-- .../difficulty-chart.component.ts | 64 +++++++++++-------- .../pool-ranking/pool-ranking.component.ts | 14 ++-- frontend/src/app/services/api.service.ts | 2 +- 7 files changed, 93 insertions(+), 41 deletions(-) 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 @@
+
+
+
+ + + + + + +
+ +
+
Rank
@@ -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}` : '') From 1630ff717efa85b82076d234c49889cbbc27cbad Mon Sep 17 00:00:00 2001 From: nymkappa Date: Thu, 17 Feb 2022 10:15:41 +0900 Subject: [PATCH 4/4] On mobile, show power of ten difficulty instead of full number --- .../difficulty-chart.component.html | 3 ++- .../difficulty-chart.component.ts | 21 ++++++++++++++++++- 2 files changed, 22 insertions(+), 2 deletions(-) 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 78350d5d5..1cdd90576 100644 --- a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.html @@ -43,7 +43,8 @@ {{ diffChange.height }} ‎{{ diffChange.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} - {{ formatNumber(diffChange.difficulty, locale, '1.2-2') }} + {{ formatNumber(diffChange.difficulty, locale, '1.2-2') }} + {{ diffChange.difficultyShorten }} {{ 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 97be13f78..47e0d9ea4 100644 --- a/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts +++ b/frontend/src/app/components/difficulty-chart/difficulty-chart.component.ts @@ -44,6 +44,13 @@ export class DifficultyChartComponent implements OnInit { } ngOnInit(): void { + const powerOfTen = { + terra: Math.pow(10, 12), + giga: Math.pow(10, 9), + mega: Math.pow(10, 6), + kilo: Math.pow(10, 3), + } + this.difficultyObservable$ = this.radioGroupForm.get('dateSpan').valueChanges .pipe( startWith('1y'), @@ -62,8 +69,20 @@ export class DifficultyChartComponent implements OnInit { 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; + let selectedPowerOfTen = { divider: powerOfTen.terra, unit: 'T' }; + if (data.adjustments[i].difficulty < powerOfTen.mega) { + selectedPowerOfTen = { divider: 1, unit: '' }; // no scaling + } else if (data.adjustments[i].difficulty < powerOfTen.giga) { + selectedPowerOfTen = { divider: powerOfTen.mega, unit: 'M' }; + } else if (data.adjustments[i].difficulty < powerOfTen.terra) { + selectedPowerOfTen = { divider: powerOfTen.giga, unit: 'G' }; + } + tableData.push(Object.assign(data.adjustments[i], { - change: change + change: change, + difficultyShorten: formatNumber( + data.adjustments[i].difficulty / selectedPowerOfTen.divider, + this.locale, '1.2-2') + selectedPowerOfTen.unit })); } return {