warn on re-index - fix hash indexing state issue - cleanup ui mining
This commit is contained in:
parent
54ccfe070e
commit
ec40231f93
@ -92,11 +92,13 @@ class DatabaseMigration {
|
|||||||
await this.$executeQuery(connection, this.getCreateBlocksTableQuery(), await this.$checkIfTableExists('blocks'));
|
await this.$executeQuery(connection, this.getCreateBlocksTableQuery(), await this.$checkIfTableExists('blocks'));
|
||||||
}
|
}
|
||||||
if (databaseSchemaVersion < 5 && isBitcoin === true) {
|
if (databaseSchemaVersion < 5 && isBitcoin === true) {
|
||||||
|
logger.warn(`'blocks' table has been truncated. Re-indexing from scratch.'`);
|
||||||
await this.$executeQuery(connection, 'TRUNCATE blocks;'); // Need to re-index
|
await this.$executeQuery(connection, 'TRUNCATE blocks;'); // Need to re-index
|
||||||
await this.$executeQuery(connection, 'ALTER TABLE blocks ADD `reward` double unsigned NOT NULL DEFAULT "0"');
|
await this.$executeQuery(connection, 'ALTER TABLE blocks ADD `reward` double unsigned NOT NULL DEFAULT "0"');
|
||||||
}
|
}
|
||||||
|
|
||||||
if (databaseSchemaVersion < 6 && isBitcoin === true) {
|
if (databaseSchemaVersion < 6 && isBitcoin === true) {
|
||||||
|
logger.warn(`'blocks' table has been truncated. Re-indexing from scratch.'`);
|
||||||
await this.$executeQuery(connection, 'TRUNCATE blocks;'); // Need to re-index
|
await this.$executeQuery(connection, 'TRUNCATE blocks;'); // Need to re-index
|
||||||
// Cleanup original blocks fields type
|
// Cleanup original blocks fields type
|
||||||
await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `height` integer unsigned NOT NULL DEFAULT "0"');
|
await this.$executeQuery(connection, 'ALTER TABLE blocks MODIFY `height` integer unsigned NOT NULL DEFAULT "0"');
|
||||||
@ -123,7 +125,8 @@ class DatabaseMigration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (databaseSchemaVersion < 8 && isBitcoin === true) {
|
if (databaseSchemaVersion < 8 && isBitcoin === true) {
|
||||||
await this.$executeQuery(connection, 'TRUNCATE hashrates;');
|
logger.warn(`'hashrates' table has been truncated. Re-indexing from scratch.'`);
|
||||||
|
await this.$executeQuery(connection, 'TRUNCATE hashrates;'); // Need to re-index
|
||||||
await this.$executeQuery(connection, 'ALTER TABLE `hashrates` DROP INDEX `PRIMARY`');
|
await this.$executeQuery(connection, 'ALTER TABLE `hashrates` DROP INDEX `PRIMARY`');
|
||||||
await this.$executeQuery(connection, 'ALTER TABLE `hashrates` ADD `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST');
|
await this.$executeQuery(connection, 'ALTER TABLE `hashrates` ADD `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST');
|
||||||
await this.$executeQuery(connection, 'ALTER TABLE `hashrates` ADD `share` float NOT NULL DEFAULT "0"');
|
await this.$executeQuery(connection, 'ALTER TABLE `hashrates` ADD `share` float NOT NULL DEFAULT "0"');
|
||||||
|
@ -27,6 +27,7 @@ import syncAssets from './sync-assets';
|
|||||||
import icons from './api/liquid/icons';
|
import icons from './api/liquid/icons';
|
||||||
import { Common } from './api/common';
|
import { Common } from './api/common';
|
||||||
import mining from './api/mining';
|
import mining from './api/mining';
|
||||||
|
import HashratesRepository from './repositories/HashratesRepository';
|
||||||
|
|
||||||
class Server {
|
class Server {
|
||||||
private wss: WebSocket.Server | undefined;
|
private wss: WebSocket.Server | undefined;
|
||||||
@ -95,6 +96,7 @@ class Server {
|
|||||||
await Common.sleep(5000);
|
await Common.sleep(5000);
|
||||||
await databaseMigration.$truncateIndexedData(tables);
|
await databaseMigration.$truncateIndexedData(tables);
|
||||||
}
|
}
|
||||||
|
await this.$resetHashratesIndexingState();
|
||||||
await databaseMigration.$initializeOrMigrateDatabase();
|
await databaseMigration.$initializeOrMigrateDatabase();
|
||||||
await poolsParser.migratePoolsJson();
|
await poolsParser.migratePoolsJson();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -145,7 +147,7 @@ class Server {
|
|||||||
}
|
}
|
||||||
await blocks.$updateBlocks();
|
await blocks.$updateBlocks();
|
||||||
await memPool.$updateMempool();
|
await memPool.$updateMempool();
|
||||||
this.runIndexingWhenReady();
|
this.$runIndexingWhenReady();
|
||||||
|
|
||||||
setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS);
|
setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS);
|
||||||
this.currentBackendRetryInterval = 5;
|
this.currentBackendRetryInterval = 5;
|
||||||
@ -164,7 +166,11 @@ class Server {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async runIndexingWhenReady() {
|
async $resetHashratesIndexingState() {
|
||||||
|
return await HashratesRepository.$setLatestRunTimestamp(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
async $runIndexingWhenReady() {
|
||||||
if (!Common.indexingEnabled() || mempool.hasPriority()) {
|
if (!Common.indexingEnabled() || mempool.hasPriority()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,10 +84,11 @@ class HashratesRepository {
|
|||||||
return rows;
|
return rows;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $setLatestRunTimestamp() {
|
public async $setLatestRunTimestamp(val: any = null) {
|
||||||
const connection = await DB.pool.getConnection();
|
const connection = await DB.pool.getConnection();
|
||||||
const query = `UPDATE state SET number = ? WHERE name = 'last_hashrates_indexing'`;
|
const query = `UPDATE state SET number = ? WHERE name = 'last_hashrates_indexing'`;
|
||||||
await connection.query<any>(query, [Math.round(new Date().getTime() / 1000)]);
|
|
||||||
|
await connection.query<any>(query, (val === null) ? [Math.round(new Date().getTime() / 1000)] : [val]);
|
||||||
connection.release();
|
connection.release();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -45,12 +45,15 @@ export class HashrateChartComponent implements OnInit {
|
|||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
) {
|
) {
|
||||||
this.seoService.setTitle($localize`:@@mining.hashrate-difficulty:Hashrate and Difficulty`);
|
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
if (!this.widget) {
|
||||||
|
this.seoService.setTitle($localize`:@@mining.hashrate-difficulty:Hashrate and Difficulty`);
|
||||||
|
}
|
||||||
|
|
||||||
this.hashrateObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
|
this.hashrateObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
startWith('1y'),
|
startWith('1y'),
|
||||||
|
@ -31,28 +31,4 @@
|
|||||||
<div class="spinner-border text-light"></div>
|
<div class="spinner-border text-light"></div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- <div class="mt-3" *ngIf="!widget">
|
|
||||||
<table class="table table-borderless table-sm text-center">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th i18n="mining.rank">Block</th>
|
|
||||||
<th class="d-none d-md-block" i18n="block.timestamp">Timestamp</th>
|
|
||||||
<th i18n="mining.adjusted">Adjusted</th>
|
|
||||||
<th i18n="mining.difficulty">Difficulty</th>
|
|
||||||
<th i18n="mining.change">Change</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody *ngIf="(hashrateObservable$ | async) as data">
|
|
||||||
<tr *ngFor="let diffChange of data.difficulty">
|
|
||||||
<td><a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height }}</a></td>
|
|
||||||
<td class="d-none d-md-block">‎{{ diffChange.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}</td>
|
|
||||||
<td><app-time-since [time]="diffChange.timestamp" [fastRender]="true"></app-time-since></td>
|
|
||||||
<td class="d-none d-md-block">{{ formatNumber(diffChange.difficulty, 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>
|
</div>
|
||||||
|
@ -11,12 +11,12 @@
|
|||||||
|
|
||||||
.full-container {
|
.full-container {
|
||||||
width: 100%;
|
width: 100%;
|
||||||
height: calc(100% - 50px);
|
height: calc(100% - 100px);
|
||||||
@media (max-width: 992px) {
|
@media (max-width: 992px) {
|
||||||
height: calc(100% - 110px);
|
height: calc(100% - 140px);
|
||||||
};
|
};
|
||||||
@media (max-width: 576px) {
|
@media (max-width: 576px) {
|
||||||
height: calc(100% - 130px);
|
height: calc(100% - 180px);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,10 +1,9 @@
|
|||||||
import { Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core';
|
||||||
import { EChartsOption } from 'echarts';
|
import { EChartsOption } from 'echarts';
|
||||||
import { Observable } from 'rxjs';
|
import { Observable } from 'rxjs';
|
||||||
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
|
import { map, share, startWith, switchMap, tap } from 'rxjs/operators';
|
||||||
import { ApiService } from 'src/app/services/api.service';
|
import { ApiService } from 'src/app/services/api.service';
|
||||||
import { SeoService } from 'src/app/services/seo.service';
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
import { formatNumber } from '@angular/common';
|
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { poolsColor } from 'src/app/app.constants';
|
import { poolsColor } from 'src/app/app.constants';
|
||||||
|
|
||||||
@ -15,11 +14,12 @@ import { poolsColor } from 'src/app/app.constants';
|
|||||||
styles: [`
|
styles: [`
|
||||||
.loadingGraphs {
|
.loadingGraphs {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 38%;
|
top: 50%;
|
||||||
left: calc(50% - 15px);
|
left: calc(50% - 15px);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
`],
|
`],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class HashrateChartPoolsComponent implements OnInit {
|
export class HashrateChartPoolsComponent implements OnInit {
|
||||||
@Input() widget: boolean = false;
|
@Input() widget: boolean = false;
|
||||||
@ -37,7 +37,6 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
|
|
||||||
hashrateObservable$: Observable<any>;
|
hashrateObservable$: Observable<any>;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
formatNumber = formatNumber;
|
|
||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(LOCALE_ID) public locale: string,
|
@Inject(LOCALE_ID) public locale: string,
|
||||||
@ -45,19 +44,24 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
private apiService: ApiService,
|
private apiService: ApiService,
|
||||||
private formBuilder: FormBuilder,
|
private formBuilder: FormBuilder,
|
||||||
) {
|
) {
|
||||||
this.seoService.setTitle($localize`:@@mining.hashrate-difficulty:Hashrate and Difficulty`);
|
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
this.radioGroupForm.controls.dateSpan.setValue('1y');
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
|
if (!this.widget) {
|
||||||
|
this.seoService.setTitle($localize`:@@mining.pools-historical-dominance:Pools Historical Dominance`);
|
||||||
|
}
|
||||||
|
|
||||||
this.hashrateObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
|
this.hashrateObservable$ = this.radioGroupForm.get('dateSpan').valueChanges
|
||||||
.pipe(
|
.pipe(
|
||||||
startWith('1y'),
|
startWith('1y'),
|
||||||
switchMap((timespan) => {
|
switchMap((timespan) => {
|
||||||
|
this.isLoading = true;
|
||||||
return this.apiService.getHistoricalPoolsHashrate$(timespan)
|
return this.apiService.getHistoricalPoolsHashrate$(timespan)
|
||||||
.pipe(
|
.pipe(
|
||||||
tap((data: any) => {
|
tap((data: any) => {
|
||||||
|
// Prepare series (group all hashrates data point by pool)
|
||||||
const grouped = {};
|
const grouped = {};
|
||||||
for (const hashrate of data.hashrates) {
|
for (const hashrate of data.hashrates) {
|
||||||
if (!grouped.hasOwnProperty(hashrate.poolName)) {
|
if (!grouped.hasOwnProperty(hashrate.poolName)) {
|
||||||
@ -68,7 +72,6 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
|
|
||||||
const series = [];
|
const series = [];
|
||||||
const legends = [];
|
const legends = [];
|
||||||
|
|
||||||
for (const name in grouped) {
|
for (const name in grouped) {
|
||||||
series.push({
|
series.push({
|
||||||
stack: 'Total',
|
stack: 'Total',
|
||||||
@ -76,12 +79,8 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
showSymbol: false,
|
showSymbol: false,
|
||||||
data: grouped[name].map((val) => [val.timestamp * 1000, (val.share * 100).toFixed(2)]),
|
data: grouped[name].map((val) => [val.timestamp * 1000, (val.share * 100).toFixed(2)]),
|
||||||
type: 'line',
|
type: 'line',
|
||||||
lineStyle: {
|
lineStyle: { width: 0 },
|
||||||
width: 0,
|
areaStyle: { opacity: 1 },
|
||||||
},
|
|
||||||
areaStyle: {
|
|
||||||
opacity: 1,
|
|
||||||
},
|
|
||||||
smooth: true,
|
smooth: true,
|
||||||
color: poolsColor[name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()],
|
color: poolsColor[name.replace(/[^a-zA-Z0-9]/g, "").toLowerCase()],
|
||||||
emphasis: {
|
emphasis: {
|
||||||
@ -115,7 +114,6 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
) / 3600 / 24;
|
) / 3600 / 24;
|
||||||
return {
|
return {
|
||||||
availableTimespanDay: availableTimespanDay,
|
availableTimespanDay: availableTimespanDay,
|
||||||
hashrates: data
|
|
||||||
};
|
};
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
@ -129,7 +127,7 @@ export class HashrateChartPoolsComponent implements OnInit {
|
|||||||
grid: {
|
grid: {
|
||||||
right: this.right,
|
right: this.right,
|
||||||
left: this.left,
|
left: this.left,
|
||||||
bottom: this.widget ? 30 : 60,
|
bottom: this.widget ? 30 : 20,
|
||||||
top: this.widget ? 10 : 40,
|
top: this.widget ? 10 : 40,
|
||||||
},
|
},
|
||||||
tooltip: {
|
tooltip: {
|
||||||
|
@ -8,7 +8,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<h5 class="card-title">
|
<h5 class="card-title">
|
||||||
<a class="link" href="" [routerLink]="['/mining/hashrate/pools' | relativeUrl]" i18n="mining.pools-hashrate">
|
<a class="link" href="" [routerLink]="['/mining/hashrate/pools' | relativeUrl]" i18n="mining.pools-hashrate">
|
||||||
Pools Hashrate Share (1y)
|
Mining Pools Dominance (1y)
|
||||||
</a>
|
</a>
|
||||||
</h5>
|
</h5>
|
||||||
<app-hashrate-chart-pools [widget]=true></app-hashrate-chart-pools>
|
<app-hashrate-chart-pools [widget]=true></app-hashrate-chart-pools>
|
||||||
|
@ -12,7 +12,7 @@
|
|||||||
|
|
||||||
.card {
|
.card {
|
||||||
background-color: #1d1f31;
|
background-color: #1d1f31;
|
||||||
height: 100%;
|
height: 340px;
|
||||||
}
|
}
|
||||||
|
|
||||||
.card-title {
|
.card-title {
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
||||||
|
import { SeoService } from 'src/app/services/seo.service';
|
||||||
|
|
||||||
@Component({
|
@Component({
|
||||||
selector: 'app-mining-dashboard',
|
selector: 'app-mining-dashboard',
|
||||||
@ -8,7 +9,9 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
|
|||||||
})
|
})
|
||||||
export class MiningDashboardComponent implements OnInit {
|
export class MiningDashboardComponent implements OnInit {
|
||||||
|
|
||||||
constructor() { }
|
constructor(private seoService: SeoService) {
|
||||||
|
this.seoService.setTitle($localize`:@@mining.mining-dashboard:Mining Dashboard`);
|
||||||
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Component, Input, OnInit } from '@angular/core';
|
import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core';
|
||||||
import { FormBuilder, FormGroup } from '@angular/forms';
|
import { FormBuilder, FormGroup } from '@angular/forms';
|
||||||
import { Router } from '@angular/router';
|
import { Router } from '@angular/router';
|
||||||
import { EChartsOption, PieSeriesOption } from 'echarts';
|
import { EChartsOption, PieSeriesOption } from 'echarts';
|
||||||
@ -18,11 +18,12 @@ import { chartColors, poolsColor } from 'src/app/app.constants';
|
|||||||
styles: [`
|
styles: [`
|
||||||
.loadingGraphs {
|
.loadingGraphs {
|
||||||
position: absolute;
|
position: absolute;
|
||||||
top: 38%;
|
top: 50%;
|
||||||
left: calc(50% - 15px);
|
left: calc(50% - 15px);
|
||||||
z-index: 100;
|
z-index: 100;
|
||||||
}
|
}
|
||||||
`],
|
`],
|
||||||
|
changeDetection: ChangeDetectionStrategy.OnPush,
|
||||||
})
|
})
|
||||||
export class PoolRankingComponent implements OnInit {
|
export class PoolRankingComponent implements OnInit {
|
||||||
@Input() widget: boolean = false;
|
@Input() widget: boolean = false;
|
||||||
@ -49,13 +50,13 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
private seoService: SeoService,
|
private seoService: SeoService,
|
||||||
private router: Router,
|
private router: Router,
|
||||||
) {
|
) {
|
||||||
this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ngOnInit(): void {
|
ngOnInit(): void {
|
||||||
if (this.widget) {
|
if (this.widget) {
|
||||||
this.poolsWindowPreference = '1w';
|
this.poolsWindowPreference = '1w';
|
||||||
} else {
|
} else {
|
||||||
|
this.seoService.setTitle($localize`:@@mining.mining-pools:Mining Pools`);
|
||||||
this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';
|
this.poolsWindowPreference = this.storageService.getValue('poolsWindowPreference') ? this.storageService.getValue('poolsWindowPreference') : '1w';
|
||||||
}
|
}
|
||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.poolsWindowPreference });
|
||||||
@ -167,6 +168,7 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.chartOptions = {
|
this.chartOptions = {
|
||||||
|
color: chartColors,
|
||||||
title: {
|
title: {
|
||||||
text: this.widget ? '' : $localize`:@@mining.pool-chart-title:${network}:NETWORK: mining pools share`,
|
text: this.widget ? '' : $localize`:@@mining.pool-chart-title:${network}:NETWORK: mining pools share`,
|
||||||
left: 'center',
|
left: 'center',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user