Add hashrate & difficulty chart resolution scaling
This commit is contained in:
parent
81c68620a1
commit
9ed7b2aad3
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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);
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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() {
|
||||
|
@ -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 »</a></div>
|
||||
<div class="mt-1"><a [routerLink]="['/graphs/mining/hashrate-difficulty' | relativeUrl]" fragment="1y" i18n="dashboard.view-more">View more »</a></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
Loading…
x
Reference in New Issue
Block a user