Index new hashrates once every 24 hours
This commit is contained in:
parent
358604ad85
commit
e61df324ea
@ -261,6 +261,10 @@ class DatabaseMigration {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (version < 7) {
|
||||||
|
queries.push(`INSERT INTO state(name, number, string) VALUES ('last_hashrates_indexing', 0, NULL)`);
|
||||||
|
}
|
||||||
|
|
||||||
return queries;
|
return queries;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -14,7 +14,7 @@ class Mining {
|
|||||||
/**
|
/**
|
||||||
* Generate high level overview of the pool ranks and general stats
|
* Generate high level overview of the pool ranks and general stats
|
||||||
*/
|
*/
|
||||||
public async $getPoolsStats(interval: string | null) : Promise<object> {
|
public async $getPoolsStats(interval: string | null): Promise<object> {
|
||||||
const poolsStatistics = {};
|
const poolsStatistics = {};
|
||||||
|
|
||||||
const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(interval);
|
const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(interval);
|
||||||
@ -30,8 +30,8 @@ class Mining {
|
|||||||
link: poolInfo.link,
|
link: poolInfo.link,
|
||||||
blockCount: poolInfo.blockCount,
|
blockCount: poolInfo.blockCount,
|
||||||
rank: rank++,
|
rank: rank++,
|
||||||
emptyBlocks: 0,
|
emptyBlocks: 0
|
||||||
}
|
};
|
||||||
for (let i = 0; i < emptyBlocks.length; ++i) {
|
for (let i = 0; i < emptyBlocks.length; ++i) {
|
||||||
if (emptyBlocks[i].poolId === poolInfo.poolId) {
|
if (emptyBlocks[i].poolId === poolInfo.poolId) {
|
||||||
poolStat.emptyBlocks++;
|
poolStat.emptyBlocks++;
|
||||||
@ -84,32 +84,41 @@ class Mining {
|
|||||||
return {
|
return {
|
||||||
adjustments: difficultyAdjustments,
|
adjustments: difficultyAdjustments,
|
||||||
oldestIndexedBlockTimestamp: oldestBlock.getTime(),
|
oldestIndexedBlockTimestamp: oldestBlock.getTime(),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return the historical hashrates and oldest indexed block timestamp
|
* Return the historical hashrates and oldest indexed block timestamp
|
||||||
*/
|
*/
|
||||||
public async $getHistoricalHashrates(interval: string | null): Promise<object> {
|
public async $getHistoricalHashrates(interval: string | null): Promise<object> {
|
||||||
const hashrates = await HashratesRepository.$get(interval);
|
const hashrates = await HashratesRepository.$get(interval);
|
||||||
const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
|
const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
|
||||||
|
|
||||||
return {
|
return {
|
||||||
hashrates: hashrates,
|
hashrates: hashrates,
|
||||||
oldestIndexedBlockTimestamp: oldestBlock.getTime(),
|
oldestIndexedBlockTimestamp: oldestBlock.getTime(),
|
||||||
}
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Generate daily hashrate data
|
||||||
*/
|
*/
|
||||||
public async $generateNetworkHashrateHistory() : Promise<void> {
|
public async $generateNetworkHashrateHistory(): Promise<void> {
|
||||||
|
// We only run this once a day
|
||||||
|
const latestTimestamp = await HashratesRepository.$getLatestRunTimestamp();
|
||||||
|
const now = new Date().getTime() / 1000;
|
||||||
|
if (now - latestTimestamp < 86400) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.info(`Indexing hashrates`);
|
||||||
|
|
||||||
if (this.hashrateIndexingStarted) {
|
if (this.hashrateIndexingStarted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
this.hashrateIndexingStarted = true;
|
this.hashrateIndexingStarted = true;
|
||||||
|
|
||||||
const totalIndexed = await BlocksRepository.$blockCount(null, null);
|
const oldestIndexedBlockHeight = await BlocksRepository.$getOldestIndexedBlockHeight();
|
||||||
const indexedTimestamp = (await HashratesRepository.$get(null)).map(hashrate => hashrate.timestamp);
|
const indexedTimestamp = (await HashratesRepository.$get(null)).map(hashrate => hashrate.timestamp);
|
||||||
|
|
||||||
const genesisTimestamp = 1231006505; // bitcoin-cli getblock 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
const genesisTimestamp = 1231006505; // bitcoin-cli getblock 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
|
||||||
@ -128,16 +137,18 @@ class Mining {
|
|||||||
null, fromTimestamp, toTimestamp
|
null, fromTimestamp, toTimestamp
|
||||||
);
|
);
|
||||||
|
|
||||||
let lastBlockHashrate = 0;
|
if (blockStats.blockCount === 0) { // We are done indexing, no blocks left
|
||||||
if (blockStats.blockCount > 0) {
|
break;
|
||||||
lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount,
|
|
||||||
blockStats.lastBlockHeight);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (toTimestamp % 864000 === 0) {
|
let lastBlockHashrate = 0;
|
||||||
const progress = Math.round((totalIndexed - blockStats.lastBlockHeight) / totalIndexed * 100);
|
lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount,
|
||||||
|
blockStats.lastBlockHeight);
|
||||||
|
|
||||||
|
if (toTimestamp % 864000 === 0) { // Log every 10 days during initial indexing
|
||||||
const formattedDate = new Date(fromTimestamp * 1000).toUTCString();
|
const formattedDate = new Date(fromTimestamp * 1000).toUTCString();
|
||||||
logger.debug(`Counting blocks and hashrate for ${formattedDate}. Progress: ${progress}%`);
|
const blocksLeft = blockStats.lastBlockHeight - oldestIndexedBlockHeight;
|
||||||
|
logger.debug(`Counting blocks and hashrate for ${formattedDate}. ${blocksLeft} blocks left`);
|
||||||
}
|
}
|
||||||
|
|
||||||
await HashratesRepository.$saveDailyStat({
|
await HashratesRepository.$saveDailyStat({
|
||||||
@ -149,6 +160,9 @@ class Mining {
|
|||||||
toTimestamp -= 86400;
|
toTimestamp -= 86400;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await HashratesRepository.$setLatestRunTimestamp();
|
||||||
|
this.hashrateIndexingStarted = false;
|
||||||
|
|
||||||
logger.info(`Hashrates indexing completed`);
|
logger.info(`Hashrates indexing completed`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -281,6 +281,13 @@ class BlocksRepository {
|
|||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $getOldestIndexedBlockHeight(): Promise<number> {
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
const [rows]: any[] = await connection.query(`SELECT MIN(height) as minHeight FROM blocks`);
|
||||||
|
connection.release();
|
||||||
|
return rows[0].minHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new BlocksRepository();
|
export default new BlocksRepository();
|
||||||
|
@ -43,11 +43,28 @@ class HashratesRepository {
|
|||||||
query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
|
query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
query += ` ORDER by hashrate_timestamp DESC`;
|
||||||
|
|
||||||
const [rows]: any[] = await connection.query(query);
|
const [rows]: any[] = await connection.query(query);
|
||||||
connection.release();
|
connection.release();
|
||||||
|
|
||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $setLatestRunTimestamp() {
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
const query = `UPDATE state SET number = ? WHERE name = 'last_hashrates_indexing'`;
|
||||||
|
await connection.query<any>(query, [Math.round(new Date().getTime() / 1000)]);
|
||||||
|
connection.release();
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $getLatestRunTimestamp(): Promise<number> {
|
||||||
|
const connection = await DB.pool.getConnection();
|
||||||
|
const query = `SELECT number FROM state WHERE name = 'last_hashrates_indexing'`;
|
||||||
|
const [rows] = await connection.query<any>(query);
|
||||||
|
connection.release();
|
||||||
|
return rows[0]['number'];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new HashratesRepository();
|
export default new HashratesRepository();
|
||||||
|
@ -134,17 +134,18 @@ export class DifficultyChartComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
series: [
|
series: {
|
||||||
{
|
showSymbol: false,
|
||||||
data: data,
|
data: data,
|
||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: false,
|
smooth: false,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 3,
|
width: 2,
|
||||||
},
|
|
||||||
areaStyle: {}
|
|
||||||
},
|
},
|
||||||
],
|
areaStyle: {
|
||||||
|
opacity: 0.25
|
||||||
|
},
|
||||||
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,50 +4,29 @@
|
|||||||
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
<div class="text-center loadingGraphs" *ngIf="isLoading">
|
||||||
<div class="spinner-border text-light"></div>
|
<div class="spinner-border text-light"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="card-header mb-0 mb-lg-4" [style]="widget ? 'display:none' : ''">
|
<div class="card-header mb-0 mb-lg-4 mt-3" [style]="widget ? 'display:none' : ''">
|
||||||
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as diffChanges">
|
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
|
||||||
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
|
<div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 90">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
|
||||||
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
|
<input ngbButton type="radio" [value]="'3m'"> 3M
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 180">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 180">
|
||||||
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
|
<input ngbButton type="radio" [value]="'6m'"> 6M
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 365">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 365">
|
||||||
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
|
<input ngbButton type="radio" [value]="'1y'"> 1Y
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 730">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 730">
|
||||||
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
|
<input ngbButton type="radio" [value]="'2y'"> 2Y
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 1095">
|
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 1095">
|
||||||
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
|
<input ngbButton type="radio" [value]="'3y'"> 3Y
|
||||||
</label>
|
</label>
|
||||||
<label ngbButtonLabel class="btn-primary btn-sm">
|
<label ngbButtonLabel class="btn-primary btn-sm">
|
||||||
<input ngbButton type="radio" [value]="'all'" [routerLink]="['/mining/hashrate' | relativeUrl]" fragment="all"> ALL
|
<input ngbButton type="radio" [value]="'all'"> ALL
|
||||||
</label>
|
</label>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <table class="table table-borderless table-sm text-center" *ngIf="!widget">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th i18n="mining.rank">Block</th>
|
|
||||||
<th i18n="block.timestamp">Timestamp</th>
|
|
||||||
<th i18n="mining.hashrate">Difficulty</th>
|
|
||||||
<th i18n="mining.change">Change</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody *ngIf="(hashrateObservable$ | async) as diffChanges">
|
|
||||||
<tr *ngFor="let diffChange of diffChanges.data">
|
|
||||||
<td><a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height }}</a></td>
|
|
||||||
<td>‎{{ diffChange.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}</td>
|
|
||||||
<td class="d-none d-md-block">{{ formatNumber(diffChange.hashrate, locale, '1.2-2') }}</td>
|
|
||||||
<td class="d-block d-md-none">{{ diffChange.difficultyShorten }}</td>
|
|
||||||
<td [style]="diffChange.change >= 0 ? 'color: #42B747' : 'color: #B74242'">{{ formatNumber(diffChange.change, locale, '1.2-2') }}%</td>
|
|
||||||
</tr>
|
|
||||||
</tbody>
|
|
||||||
</table> -->
|
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
@ -66,15 +66,15 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}),
|
}),
|
||||||
share()
|
share()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
prepareChartOptions(data) {
|
prepareChartOptions(data) {
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
title: {
|
title: {
|
||||||
text: this.widget? '' : $localize`:@@mining.hashrate:Hashrate`,
|
text: this.widget ? '' : $localize`:@@mining.hashrate:Hashrate`,
|
||||||
left: 'center',
|
left: 'center',
|
||||||
textStyle: {
|
textStyle: {
|
||||||
color: '#FFF',
|
color: '#FFF',
|
||||||
@ -102,7 +102,7 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
giga: Math.pow(10, 9),
|
giga: Math.pow(10, 9),
|
||||||
mega: Math.pow(10, 6),
|
mega: Math.pow(10, 6),
|
||||||
kilo: Math.pow(10, 3),
|
kilo: Math.pow(10, 3),
|
||||||
}
|
};
|
||||||
|
|
||||||
let selectedPowerOfTen = { divider: powerOfTen.exa, unit: 'E' };
|
let selectedPowerOfTen = { divider: powerOfTen.exa, unit: 'E' };
|
||||||
if (val < powerOfTen.mega) {
|
if (val < powerOfTen.mega) {
|
||||||
@ -135,9 +135,11 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
type: 'line',
|
type: 'line',
|
||||||
smooth: false,
|
smooth: false,
|
||||||
lineStyle: {
|
lineStyle: {
|
||||||
width: 3,
|
width: 2,
|
||||||
|
},
|
||||||
|
areaStyle: {
|
||||||
|
opacity: 0.25
|
||||||
},
|
},
|
||||||
areaStyle: {},
|
|
||||||
},
|
},
|
||||||
dataZoom: this.widget ? null : [{
|
dataZoom: this.widget ? null : [{
|
||||||
type: 'inside',
|
type: 'inside',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user