Add hashrate & difficulty chart resolution scaling

This commit is contained in:
nymkappa 2022-07-06 21:03:55 +02:00
parent 81c68620a1
commit 9ed7b2aad3
No known key found for this signature in database
GPG Key ID: E155910B16E8BD04
7 changed files with 58 additions and 22 deletions

View File

@ -8,6 +8,7 @@ import { Common } from './common';
import loadingIndicators from './loading-indicators';
import { escape } from 'mysql2';
import DifficultyAdjustmentsRepository from '../repositories/DifficultyAdjustmentsRepository';
import config from '../config';
class Mining {
constructor() {
@ -302,7 +303,7 @@ class Mining {
while (toTimestamp > genesisTimestamp) {
const fromTimestamp = toTimestamp - 86400000;
// Skip already indexed weeks
// Skip already indexed days
if (indexedTimestamp.includes(toTimestamp / 1000)) {
toTimestamp -= 86400000;
++totalIndexed;
@ -313,7 +314,7 @@ class Mining {
// we are currently indexing has complete data)
const blockStatsPreviousDay: any = await BlocksRepository.$blockCountBetweenTimestamp(
null, (fromTimestamp - 86400000) / 1000, (toTimestamp - 86400000) / 1000);
if (blockStatsPreviousDay.blockCount === 0) { // We are done indexing
if (blockStatsPreviousDay.blockCount === 0 && config.MEMPOOL.NETWORK === 'mainnet') { // We are done indexing
break;
}
@ -357,9 +358,10 @@ class Mining {
// Add genesis block manually
if (toTimestamp <= genesisTimestamp && !indexedTimestamp.includes(genesisTimestamp)) {
hashrates.push({
hashrateTimestamp: genesisTimestamp,
hashrateTimestamp: genesisTimestamp / 1000,
avgHashrate: await bitcoinClient.getNetworkHashPs(1, 1),
poolId: null,
poolId: 0,
share: 1,
type: 'daily',
});
}
@ -393,6 +395,15 @@ class Mining {
let currentDifficulty = 0;
let totalIndexed = 0;
if (indexedHeights[0] === false) {
await DifficultyAdjustmentsRepository.$saveAdjustments({
time: 1231006505,
height: 0,
difficulty: 1.0,
adjustment: 0.0,
});
}
for (const block of blocks) {
if (block.difficulty !== currentDifficulty) {
if (block.height === 0 || indexedHeights[block.height] === true) { // Already indexed

View File

@ -285,6 +285,7 @@ class Server {
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug', routes.$getPool)
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/pools/:interval', routes.$getPoolsHistoricalHashrate)
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/:interval', routes.$getHistoricalHashrate)
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments', routes.$getDifficultyAdjustments)
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/reward-stats/:blockCount', routes.$getRewardStats)
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fees/:interval', routes.$getHistoricalBlockFees)
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/rewards/:interval', routes.$getHistoricalBlockRewards)

View File

@ -436,7 +436,7 @@ class BlocksRepository {
}
if (blocks[idx].previous_block_hash !== blocks[idx - 1].hash) {
logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}, re-indexing newer blocks and hashrates`);
logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}`);
await this.$deleteBlocksFrom(blocks[idx - 1].height);
await BlocksSummariesRepository.$deleteBlocksFrom(blocks[idx - 1].height);
await HashratesRepository.$deleteHashratesFromTimestamp(blocks[idx - 1].timestamp - 604800);

View File

@ -1,4 +1,5 @@
import { Common } from '../api/common';
import config from '../config';
import DB from '../database';
import logger from '../logger';
import { IndexedDifficultyAdjustment } from '../mempool.interfaces';
@ -31,13 +32,19 @@ class DifficultyAdjustmentsRepository {
public async $getAdjustments(interval: string | null, descOrder: boolean = false): Promise<IndexedDifficultyAdjustment[]> {
interval = Common.getSqlInterval(interval);
let query = `SELECT UNIX_TIMESTAMP(time) as time, height, difficulty, adjustment
let query = `SELECT
CAST(AVG(UNIX_TIMESTAMP(time)) as INT) as time,
CAST(AVG(height) AS INT) as height,
CAST(AVG(difficulty) as DOUBLE) as difficulty,
CAST(AVG(adjustment) as DOUBLE) as adjustment
FROM difficulty_adjustments`;
if (interval) {
query += ` WHERE time BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
}
query += ` GROUP BY UNIX_TIMESTAMP(time) DIV ${86400}`;
if (descOrder === true) {
query += ` ORDER BY time DESC`;
} else {

View File

@ -1,5 +1,6 @@
import { escape } from 'mysql2';
import { Common } from '../api/common';
import config from '../config';
import DB from '../database';
import logger from '../logger';
import PoolsRepository from './PoolsRepository';
@ -32,7 +33,9 @@ class HashratesRepository {
public async $getNetworkDailyHashrate(interval: string | null): Promise<any[]> {
interval = Common.getSqlInterval(interval);
let query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate
let query = `SELECT
CAST(AVG(UNIX_TIMESTAMP(hashrate_timestamp)) as INT) as timestamp,
CAST(AVG(avg_hashrate) as DOUBLE) as avgHashrate
FROM hashrates`;
if (interval) {
@ -42,6 +45,7 @@ class HashratesRepository {
query += ` WHERE hashrates.type = 'daily'`;
}
query += ` GROUP BY UNIX_TIMESTAMP(hashrate_timestamp) DIV ${86400}`;
query += ` ORDER by hashrate_timestamp`;
try {

View File

@ -11,6 +11,7 @@ import { StorageService } from 'src/app/services/storage.service';
import { MiningService } from 'src/app/services/mining.service';
import { download } from 'src/app/shared/graphs.utils';
import { ActivatedRoute } from '@angular/router';
import { StateService } from 'src/app/services/state.service';
@Component({
selector: 'app-hashrate-chart',
@ -47,7 +48,7 @@ export class HashrateChartComponent implements OnInit {
formatNumber = formatNumber;
timespan = '';
chartInstance: any = undefined;
maResolution: number = 30;
network = '';
constructor(
@Inject(LOCALE_ID) public locale: string,
@ -57,10 +58,13 @@ export class HashrateChartComponent implements OnInit {
private storageService: StorageService,
private miningService: MiningService,
private route: ActivatedRoute,
private stateService: StateService
) {
}
ngOnInit(): void {
this.stateService.networkChanged$.subscribe((network) => this.network = network);
let firstRun = true;
if (this.widget) {
@ -124,17 +128,14 @@ export class HashrateChartComponent implements OnInit {
++diffIndex;
}
this.maResolution = 30;
if (["3m", "6m"].includes(this.timespan)) {
this.maResolution = 7;
}
let maResolution = 15;
const hashrateMa = [];
for (let i = this.maResolution - 1; i < data.hashrates.length; ++i) {
for (let i = maResolution - 1; i < data.hashrates.length; ++i) {
let avg = 0;
for (let y = this.maResolution - 1; y >= 0; --y) {
for (let y = maResolution - 1; y >= 0; --y) {
avg += data.hashrates[i - y].avgHashrate;
}
avg /= this.maResolution;
avg /= maResolution;
hashrateMa.push([data.hashrates[i].timestamp * 1000, avg]);
}
@ -276,17 +277,17 @@ export class HashrateChartComponent implements OnInit {
},
},
{
name: $localize`::Difficulty`,
name: $localize`:@@25148835d92465353fc5fe8897c27d5369978e5a:Difficulty`,
inactiveColor: 'rgb(110, 112, 121)',
textStyle: {
textStyle: {
color: 'white',
},
icon: 'roundRect',
},
{
name: $localize`Hashrate` + ` (MA${this.maResolution})`,
name: $localize`Hashrate (MA)`,
inactiveColor: 'rgb(110, 112, 121)',
textStyle: {
textStyle: {
color: 'white',
},
icon: 'roundRect',
@ -295,11 +296,19 @@ export class HashrateChartComponent implements OnInit {
},
},
],
selected: JSON.parse(this.storageService.getValue('hashrate_difficulty_legend')) ?? {
'$localize`:@@79a9dc5b1caca3cbeb1733a19515edacc5fc7920:Hashrate`': true,
'$localize`::Difficulty`': this.network === '',
'$localize`Hashrate (MA)`': true,
},
},
yAxis: data.hashrates.length === 0 ? undefined : [
{
min: (value) => {
return value.min * 0.9;
const selectedPowerOfTen: any = selectPowerOfTen(value.min);
const newMin = Math.floor(value.min / selectedPowerOfTen.divider / 10);
console.log(newMin);
return newMin * selectedPowerOfTen.divider * 10;
},
type: 'value',
axisLabel: {
@ -363,7 +372,7 @@ export class HashrateChartComponent implements OnInit {
},
{
zlevel: 2,
name: $localize`Hashrate` + ` (MA${this.maResolution})`,
name: $localize`Hashrate (MA)`,
showSymbol: false,
symbol: 'none',
data: data.hashrateMa,
@ -404,6 +413,10 @@ export class HashrateChartComponent implements OnInit {
onChartInit(ec) {
this.chartInstance = ec;
this.chartInstance.on('legendselectchanged', (e) => {
this.storageService.setValue('hashrate_difficulty_legend', JSON.stringify(e.selected));
});
}
isMobile() {

View File

@ -40,7 +40,7 @@
<div class="card">
<div class="card-body pl-lg-3 pr-lg-3 pl-2 pr-2">
<app-hashrate-chart [widget]="true"></app-hashrate-chart>
<div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" i18n="dashboard.view-more">View more &raquo;</a></div>
<div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" fragment="1y" i18n="dashboard.view-more">View more &raquo;</a></div>
</div>
</div>
</div>