Merge branch 'master' into regtest-1
for cla bot
This commit is contained in:
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { HttpClient, HttpParams } from '@angular/common/http';
|
||||
import { CpfpInfo, OptimizedMempoolStats, DifficultyAdjustment, AddressInformation, LiquidPegs, ITranslators } from '../interfaces/node-api.interface';
|
||||
import { CpfpInfo, OptimizedMempoolStats, DifficultyAdjustment, AddressInformation, LiquidPegs, ITranslators, PoolsStats } from '../interfaces/node-api.interface';
|
||||
import { Observable } from 'rxjs';
|
||||
import { StateService } from './state.service';
|
||||
import { WebsocketResponse } from '../interfaces/websocket.interface';
|
||||
@@ -120,4 +120,8 @@ export class ApiService {
|
||||
postTransaction$(hexPayload: string): Observable<any> {
|
||||
return this.httpClient.post<any>(this.apiBaseUrl + this.apiBasePath + '/api/tx', hexPayload, { responseType: 'text' as 'json'});
|
||||
}
|
||||
|
||||
listPools$(interval: string | null) : Observable<PoolsStats> {
|
||||
return this.httpClient.get<PoolsStats>(this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pools/${interval}`);
|
||||
}
|
||||
}
|
||||
|
||||
98
frontend/src/app/services/mining.service.ts
Normal file
98
frontend/src/app/services/mining.service.ts
Normal file
@@ -0,0 +1,98 @@
|
||||
import { Injectable } from '@angular/core';
|
||||
import { Observable } from 'rxjs';
|
||||
import { map } from 'rxjs/operators';
|
||||
import { PoolsStats, SinglePoolStats } from '../interfaces/node-api.interface';
|
||||
import { ApiService } from '../services/api.service';
|
||||
import { StateService } from './state.service';
|
||||
|
||||
export interface MiningUnits {
|
||||
hashrateDivider: number;
|
||||
hashrateUnit: string;
|
||||
}
|
||||
|
||||
export interface MiningStats {
|
||||
lastEstimatedHashrate: string;
|
||||
blockCount: number;
|
||||
totalEmptyBlock: number;
|
||||
totalEmptyBlockRatio: string;
|
||||
pools: SinglePoolStats[];
|
||||
miningUnits: MiningUnits;
|
||||
availableTimespanDay: number;
|
||||
}
|
||||
|
||||
@Injectable({
|
||||
providedIn: 'root'
|
||||
})
|
||||
export class MiningService {
|
||||
|
||||
constructor(
|
||||
private stateService: StateService,
|
||||
private apiService: ApiService,
|
||||
) { }
|
||||
|
||||
public getMiningStats(interval: string): Observable<MiningStats> {
|
||||
return this.apiService.listPools$(interval).pipe(
|
||||
map(pools => this.generateMiningStats(pools))
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the hashrate power of ten we want to display
|
||||
*/
|
||||
public getMiningUnits(): MiningUnits {
|
||||
const powerTable = {
|
||||
0: 'H/s',
|
||||
3: 'kH/s',
|
||||
6: 'MH/s',
|
||||
9: 'GH/s',
|
||||
12: 'TH/s',
|
||||
15: 'PH/s',
|
||||
18: 'EH/s',
|
||||
};
|
||||
|
||||
// I think it's fine to hardcode this since we don't have x1000 hashrate jump everyday
|
||||
// If we want to support the mining dashboard for testnet, we can hardcode it too
|
||||
let selectedPower = 15;
|
||||
if (this.stateService.network === 'testnet') {
|
||||
selectedPower = 12;
|
||||
}
|
||||
|
||||
return {
|
||||
hashrateDivider: Math.pow(10, selectedPower),
|
||||
hashrateUnit: powerTable[selectedPower],
|
||||
};
|
||||
}
|
||||
|
||||
private generateMiningStats(stats: PoolsStats): MiningStats {
|
||||
const miningUnits = this.getMiningUnits();
|
||||
const hashrateDivider = miningUnits.hashrateDivider;
|
||||
|
||||
const totalEmptyBlock = Object.values(stats.pools).reduce((prev, cur) => {
|
||||
return prev + cur.emptyBlocks;
|
||||
}, 0);
|
||||
const totalEmptyBlockRatio = (totalEmptyBlock / stats.blockCount * 100).toFixed(2);
|
||||
const poolsStats = stats.pools.map((poolStat) => {
|
||||
return {
|
||||
share: (poolStat.blockCount / stats.blockCount * 100).toFixed(2),
|
||||
lastEstimatedHashrate: (poolStat.blockCount / stats.blockCount * stats.lastEstimatedHashrate / hashrateDivider).toFixed(2),
|
||||
emptyBlockRatio: (poolStat.emptyBlocks / poolStat.blockCount * 100).toFixed(2),
|
||||
logo: `./resources/mining-pools/` + poolStat.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg',
|
||||
...poolStat
|
||||
};
|
||||
});
|
||||
|
||||
const availableTimespanDay = (
|
||||
(new Date().getTime() / 1000) - (stats.oldestIndexedBlockTimestamp / 1000)
|
||||
) / 3600 / 24;
|
||||
|
||||
return {
|
||||
lastEstimatedHashrate: (stats.lastEstimatedHashrate / hashrateDivider).toFixed(2),
|
||||
blockCount: stats.blockCount,
|
||||
totalEmptyBlock: totalEmptyBlock,
|
||||
totalEmptyBlockRatio: totalEmptyBlockRatio,
|
||||
pools: poolsStats,
|
||||
miningUnits: miningUnits,
|
||||
availableTimespanDay: availableTimespanDay,
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -6,18 +6,28 @@ import { Router, ActivatedRoute } from '@angular/router';
|
||||
})
|
||||
export class StorageService {
|
||||
constructor(private router: Router, private route: ActivatedRoute) {
|
||||
let graphWindowPreference: string = this.getValue('graphWindowPreference');
|
||||
this.setDefaultValueIfNeeded('graphWindowPreference', '2h');
|
||||
this.setDefaultValueIfNeeded('poolsWindowPreference', '1w');
|
||||
}
|
||||
|
||||
setDefaultValueIfNeeded(key: string, defaultValue: string) {
|
||||
let graphWindowPreference: string = this.getValue(key);
|
||||
if (graphWindowPreference === null) { // First visit to mempool.space
|
||||
if (this.router.url.includes("graphs")) {
|
||||
this.setValue('graphWindowPreference', this.route.snapshot.fragment ? this.route.snapshot.fragment : "2h");
|
||||
if (this.router.url.includes('graphs') && key === 'graphWindowPreference' ||
|
||||
this.router.url.includes('pools') && key === 'poolsWindowPreference'
|
||||
) {
|
||||
this.setValue(key, this.route.snapshot.fragment ? this.route.snapshot.fragment : defaultValue);
|
||||
} else {
|
||||
this.setValue('graphWindowPreference', "2h");
|
||||
this.setValue(key, defaultValue);
|
||||
}
|
||||
} else if (this.router.url.includes("graphs")) { // Visit a different graphs#fragment from last visit
|
||||
if (this.route.snapshot.fragment !== null && graphWindowPreference !== this.route.snapshot.fragment) {
|
||||
this.setValue('graphWindowPreference', this.route.snapshot.fragment);
|
||||
}
|
||||
} else if (this.router.url.includes('graphs') && key === 'graphWindowPreference' ||
|
||||
this.router.url.includes('pools') && key === 'poolsWindowPreference'
|
||||
) {
|
||||
// Visit a different graphs#fragment from last visit
|
||||
if (this.route.snapshot.fragment !== null && graphWindowPreference !== this.route.snapshot.fragment) {
|
||||
this.setValue(key, this.route.snapshot.fragment);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
getValue(key: string): string {
|
||||
|
||||
Reference in New Issue
Block a user