Merge pull request #1548 from mempool/nymkappa/feature/timespan-selector-update

Use block count instead of oldest block for timespan selection
This commit is contained in:
wiz 2022-04-24 03:51:47 +00:00 committed by GitHub
commit 71334516e2
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
16 changed files with 98 additions and 120 deletions

View file

@ -102,7 +102,7 @@ class HashratesRepository {
/** /**
* Returns a pool hashrate history * Returns a pool hashrate history
*/ */
public async $getPoolWeeklyHashrate(slug: string): Promise<any[]> { public async $getPoolWeeklyHashrate(slug: string): Promise<any[]> {
const pool = await PoolsRepository.$getPool(slug); const pool = await PoolsRepository.$getPool(slug);
if (!pool) { if (!pool) {
throw new Error(`This mining pool does not exist`); throw new Error(`This mining pool does not exist`);

View file

@ -575,8 +575,10 @@ class Routes {
public async $getPools(interval: string, req: Request, res: Response) { public async $getPools(interval: string, req: Request, res: Response) {
try { try {
const stats = await miningStats.$getPoolsStats(interval); const stats = await miningStats.$getPoolsStats(interval);
const blockCount = await BlocksRepository.$blockCount(null, null);
res.header('Pragma', 'public'); res.header('Pragma', 'public');
res.header('Cache-control', 'public'); res.header('Cache-control', 'public');
res.header('X-total-count', blockCount.toString());
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
res.json(stats); res.json(stats);
} catch (e) { } catch (e) {
@ -587,14 +589,12 @@ class Routes {
public async $getPoolsHistoricalHashrate(req: Request, res: Response) { public async $getPoolsHistoricalHashrate(req: Request, res: Response) {
try { try {
const hashrates = await HashratesRepository.$getPoolsWeeklyHashrate(req.params.interval ?? null); const hashrates = await HashratesRepository.$getPoolsWeeklyHashrate(req.params.interval ?? null);
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp(); const blockCount = await BlocksRepository.$blockCount(null, null);
res.header('Pragma', 'public'); res.header('Pragma', 'public');
res.header('Cache-control', 'public'); res.header('Cache-control', 'public');
res.header('X-total-count', blockCount.toString());
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
res.json({ res.json(hashrates);
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
hashrates: hashrates,
});
} catch (e) { } catch (e) {
res.status(500).send(e instanceof Error ? e.message : e); res.status(500).send(e instanceof Error ? e.message : e);
} }
@ -603,14 +603,12 @@ class Routes {
public async $getPoolHistoricalHashrate(req: Request, res: Response) { public async $getPoolHistoricalHashrate(req: Request, res: Response) {
try { try {
const hashrates = await HashratesRepository.$getPoolWeeklyHashrate(req.params.slug); const hashrates = await HashratesRepository.$getPoolWeeklyHashrate(req.params.slug);
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp(); const blockCount = await BlocksRepository.$blockCount(null, null);
res.header('Pragma', 'public'); res.header('Pragma', 'public');
res.header('Cache-control', 'public'); res.header('Cache-control', 'public');
res.header('X-total-count', blockCount.toString());
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
res.json({ res.json(hashrates);
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
hashrates: hashrates,
});
} catch (e) { } catch (e) {
if (e instanceof Error && e.message.indexOf('This mining pool does not exist') > -1) { if (e instanceof Error && e.message.indexOf('This mining pool does not exist') > -1) {
res.status(404).send(e.message); res.status(404).send(e.message);
@ -624,12 +622,12 @@ class Routes {
try { try {
const hashrates = await HashratesRepository.$getNetworkDailyHashrate(req.params.interval ?? null); const hashrates = await HashratesRepository.$getNetworkDailyHashrate(req.params.interval ?? null);
const difficulty = await BlocksRepository.$getBlocksDifficulty(req.params.interval ?? null); const difficulty = await BlocksRepository.$getBlocksDifficulty(req.params.interval ?? null);
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp(); const blockCount = await BlocksRepository.$blockCount(null, null);
res.header('Pragma', 'public'); res.header('Pragma', 'public');
res.header('Cache-control', 'public'); res.header('Cache-control', 'public');
res.header('X-total-count', blockCount.toString());
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
res.json({ res.json({
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
hashrates: hashrates, hashrates: hashrates,
difficulty: difficulty, difficulty: difficulty,
}); });
@ -641,14 +639,12 @@ class Routes {
public async $getHistoricalBlockFees(req: Request, res: Response) { public async $getHistoricalBlockFees(req: Request, res: Response) {
try { try {
const blockFees = await mining.$getHistoricalBlockFees(req.params.interval ?? null); const blockFees = await mining.$getHistoricalBlockFees(req.params.interval ?? null);
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp(); const blockCount = await BlocksRepository.$blockCount(null, null);
res.header('Pragma', 'public'); res.header('Pragma', 'public');
res.header('Cache-control', 'public'); res.header('Cache-control', 'public');
res.header('X-total-count', blockCount.toString());
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
res.json({ res.json(blockFees);
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
blockFees: blockFees,
});
} catch (e) { } catch (e) {
res.status(500).send(e instanceof Error ? e.message : e); res.status(500).send(e instanceof Error ? e.message : e);
} }
@ -657,14 +653,12 @@ class Routes {
public async $getHistoricalBlockRewards(req: Request, res: Response) { public async $getHistoricalBlockRewards(req: Request, res: Response) {
try { try {
const blockRewards = await mining.$getHistoricalBlockRewards(req.params.interval ?? null); const blockRewards = await mining.$getHistoricalBlockRewards(req.params.interval ?? null);
const oldestIndexedBlockTimestamp = await BlocksRepository.$oldestBlockTimestamp(); const blockCount = await BlocksRepository.$blockCount(null, null);
res.header('Pragma', 'public'); res.header('Pragma', 'public');
res.header('Cache-control', 'public'); res.header('Cache-control', 'public');
res.header('X-total-count', blockCount.toString());
res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
res.json({ res.json(blockRewards);
oldestIndexedBlockTimestamp: oldestIndexedBlockTimestamp,
blockRewards: blockRewards,
});
} catch (e) { } catch (e) {
res.status(500).send(e instanceof Error ? e.message : e); res.status(500).send(e instanceof Error ? e.message : e);
} }
@ -986,7 +980,7 @@ class Routes {
public async $getRewardStats(req: Request, res: Response) { public async $getRewardStats(req: Request, res: Response) {
try { try {
const response = await mining.$getRewardStats(parseInt(req.params.blockCount)) const response = await mining.$getRewardStats(parseInt(req.params.blockCount, 10));
res.json(response); res.json(response);
} catch (e) { } catch (e) {
res.status(500).end(); res.status(500).end();

View file

@ -3,34 +3,34 @@
<span i18n="mining.block-fees">Block fees</span> <span i18n="mining.block-fees">Block fees</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as stats"> <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as stats">
<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" *ngIf="stats.availableTimespanDay >= 1"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 144">
<input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h <input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 3"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 432">
<input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D <input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 7"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 1008">
<input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W <input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 30"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 4320">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M <input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 12960">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 25920">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 52560">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 105120">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 157680">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount > 157680">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL <input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label> </label>
</div> </div>

View file

@ -68,19 +68,15 @@ export class BlockFeesGraphComponent implements OnInit {
this.isLoading = true; this.isLoading = true;
return this.apiService.getHistoricalBlockFees$(timespan) return this.apiService.getHistoricalBlockFees$(timespan)
.pipe( .pipe(
tap((data: any) => { tap((response) => {
this.prepareChartOptions({ this.prepareChartOptions({
blockFees: data.blockFees.map(val => [val.timestamp * 1000, val.avg_fees / 100000000]), blockFees: response.body.map(val => [val.timestamp * 1000, val.avg_fees / 100000000]),
}); });
this.isLoading = false; this.isLoading = false;
}), }),
map((data: any) => { map((response) => {
const availableTimespanDay = (
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
) / 3600 / 24;
return { return {
availableTimespanDay: availableTimespanDay, blockCount: parseInt(response.headers.get('x-total-count'), 10),
}; };
}), }),
); );

View file

@ -4,34 +4,34 @@
<span i18n="mining.block-rewards">Block rewards</span> <span i18n="mining.block-rewards">Block rewards</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as stats"> <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(statsObservable$ | async) as stats">
<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" *ngIf="stats.availableTimespanDay >= 1"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 144">
<input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h <input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 3"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 432">
<input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D <input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 7"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 1008">
<input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W <input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 30"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 4320">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M <input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 12960">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 25920">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 52560">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 105120">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 157680">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount > 157680">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL <input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label> </label>
</div> </div>

View file

@ -66,19 +66,15 @@ export class BlockRewardsGraphComponent implements OnInit {
this.isLoading = true; this.isLoading = true;
return this.apiService.getHistoricalBlockRewards$(timespan) return this.apiService.getHistoricalBlockRewards$(timespan)
.pipe( .pipe(
tap((data: any) => { tap((response) => {
this.prepareChartOptions({ this.prepareChartOptions({
blockRewards: data.blockRewards.map(val => [val.timestamp * 1000, val.avg_rewards / 100000000]), blockRewards: response.body.map(val => [val.timestamp * 1000, val.avg_rewards / 100000000]),
}); });
this.isLoading = false; this.isLoading = false;
}), }),
map((data: any) => { map((response) => {
const availableTimespanDay = (
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
) / 3600 / 24;
return { return {
availableTimespanDay: availableTimespanDay, blockCount: parseInt(response.headers.get('x-total-count'), 10),
}; };
}), }),
); );

View file

@ -32,7 +32,8 @@ export class DifficultyAdjustmentsTable implements OnInit {
ngOnInit(): void { ngOnInit(): void {
this.hashrateObservable$ = this.apiService.getHistoricalHashrate$('1y') this.hashrateObservable$ = this.apiService.getHistoricalHashrate$('1y')
.pipe( .pipe(
map((data: any) => { map((response) => {
const data = response.body;
const availableTimespanDay = ( const availableTimespanDay = (
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp) (new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
) / 3600 / 24; ) / 3600 / 24;

View file

@ -22,25 +22,25 @@
<span i18n="mining.hashrate-difficulty">Hashrate & Difficulty</span> <span i18n="mining.hashrate-difficulty">Hashrate & Difficulty</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats"> <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats">
<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" *ngIf="stats.availableTimespanDay >= 30"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 4320">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M <input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 12960">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 25920">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 52560">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 105120">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 157680">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount > 157680">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL <input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label> </label>
</div> </div>

View file

@ -79,7 +79,8 @@ export class HashrateChartComponent implements OnInit {
this.isLoading = true; this.isLoading = true;
return this.apiService.getHistoricalHashrate$(timespan) return this.apiService.getHistoricalHashrate$(timespan)
.pipe( .pipe(
tap((data: any) => { tap((response) => {
const data = response.body;
// We generate duplicated data point so the tooltip works nicely // We generate duplicated data point so the tooltip works nicely
const diffFixed = []; const diffFixed = [];
let diffIndex = 1; let diffIndex = 1;
@ -111,7 +112,6 @@ export class HashrateChartComponent implements OnInit {
this.prepareChartOptions({ this.prepareChartOptions({
hashrates: data.hashrates.map(val => [val.timestamp * 1000, val.avgHashrate]), hashrates: data.hashrates.map(val => [val.timestamp * 1000, val.avgHashrate]),
difficulty: diffFixed.map(val => [val.timestamp * 1000, val.difficulty]), difficulty: diffFixed.map(val => [val.timestamp * 1000, val.difficulty]),
timestamp: data.oldestIndexedBlockTimestamp,
}); });
this.isLoading = false; this.isLoading = false;
@ -120,13 +120,10 @@ export class HashrateChartComponent implements OnInit {
throw new Error(); throw new Error();
} }
}), }),
map((data: any) => { map((response) => {
const availableTimespanDay = ( const data = response.body;
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
) / 3600 / 24;
return { return {
availableTimespanDay: availableTimespanDay, blockCount: parseInt(response.headers.get('x-total-count'), 10),
currentDifficulty: Math.round(data.difficulty[data.difficulty.length - 1].difficulty * 100) / 100, currentDifficulty: Math.round(data.difficulty[data.difficulty.length - 1].difficulty * 100) / 100,
currentHashrate: data.hashrates[data.hashrates.length - 1].avgHashrate, currentHashrate: data.hashrates[data.hashrates.length - 1].avgHashrate,
}; };

View file

@ -4,25 +4,25 @@
<span i18n="mining.pools-dominance">Mining pools dominance</span> <span i18n="mining.pools-dominance">Mining pools dominance</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats"> <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as stats">
<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" *ngIf="stats.availableTimespanDay >= 30"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 4320">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M <input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 90"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 12960">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 180"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 25920">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 365"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 52560">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 730"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 105120">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay >= 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount >= 157680">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.availableTimespanDay > 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.blockCount > 157680">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL <input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label> </label>
</div> </div>

View file

@ -72,10 +72,11 @@ export class HashrateChartPoolsComponent implements OnInit {
this.isLoading = true; this.isLoading = true;
return this.apiService.getHistoricalPoolsHashrate$(timespan) return this.apiService.getHistoricalPoolsHashrate$(timespan)
.pipe( .pipe(
tap((data: any) => { tap((response) => {
const hashrates = response.body;
// Prepare series (group all hashrates data point by pool) // Prepare series (group all hashrates data point by pool)
const grouped = {}; const grouped = {};
for (const hashrate of data.hashrates) { for (const hashrate of hashrates) {
if (!grouped.hasOwnProperty(hashrate.poolName)) { if (!grouped.hasOwnProperty(hashrate.poolName)) {
grouped[hashrate.poolName] = []; grouped[hashrate.poolName] = [];
} }
@ -119,7 +120,6 @@ export class HashrateChartPoolsComponent implements OnInit {
this.prepareChartOptions({ this.prepareChartOptions({
legends: legends, legends: legends,
series: series, series: series,
timestamp: data.oldestIndexedBlockTimestamp,
}); });
this.isLoading = false; this.isLoading = false;
@ -128,13 +128,10 @@ export class HashrateChartPoolsComponent implements OnInit {
throw new Error(); throw new Error();
} }
}), }),
map((data: any) => { map((response) => {
const availableTimespanDay = (
(new Date().getTime() / 1000) - (data.oldestIndexedBlockTimestamp)
) / 3600 / 24;
return { return {
availableTimespanDay: availableTimespanDay, blockCount: parseInt(response.headers.get('x-total-count'), 10),
}; }
}), }),
retryWhen((errors) => errors.pipe( retryWhen((errors) => errors.pipe(
delay(60000) delay(60000)

View file

@ -26,36 +26,36 @@
<div class="card-header" *ngIf="!widget"> <div class="card-header" *ngIf="!widget">
<span i18n="mining.mining-pool-share">Mining pools share</span> <span i18n="mining.mining-pool-share">Mining pools share</span>
<form [formGroup]="radioGroupForm" class="formRadioGroup" <form [formGroup]="radioGroupForm" class="formRadioGroup"
*ngIf="!widget && (miningStatsObservable$ | async) as miningStats"> *ngIf="!widget && (miningStatsObservable$ | async) as stats">
<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" *ngIf="miningStats.availableTimespanDay >= 1"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 144">
<input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h <input ngbButton type="radio" [value]="'24h'" fragment="24h"> 24h
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 3"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 432">
<input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D <input ngbButton type="radio" [value]="'3d'" fragment="3d"> 3D
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 7"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 1008">
<input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W <input ngbButton type="radio" [value]="'1w'" fragment="1w"> 1W
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 30"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 4320">
<input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M <input ngbButton type="radio" [value]="'1m'" fragment="1m"> 1M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 90"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 12960">
<input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 180"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 25920">
<input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 365"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 52560">
<input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 730"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 105120">
<input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay >= 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount >= 157680">
<input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
</label> </label>
<label ngbButtonLabel class="btn-primary btn-sm" *ngIf="miningStats.availableTimespanDay > 1095"> <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="stats.totalBlockCount > 157680">
<input ngbButton type="radio" [value]="'all'" fragment="all"> ALL <input ngbButton type="radio" [value]="'all'" fragment="all"> ALL
</label> </label>
</div> </div>

View file

@ -276,7 +276,7 @@ export class PoolRankingComponent implements OnInit {
totalEmptyBlock: 0, totalEmptyBlock: 0,
totalEmptyBlockRatio: '', totalEmptyBlockRatio: '',
pools: [], pools: [],
availableTimespanDay: 0, totalBlockCount: 0,
miningUnits: { miningUnits: {
hashrateDivider: 1, hashrateDivider: 1,
hashrateUnit: '', hashrateUnit: '',

View file

@ -56,7 +56,7 @@ export class PoolComponent implements OnInit {
.pipe( .pipe(
switchMap((data) => { switchMap((data) => {
this.isLoading = false; this.isLoading = false;
this.prepareChartOptions(data.hashrates.map(val => [val.timestamp * 1000, val.avgHashrate])); this.prepareChartOptions(data.map(val => [val.timestamp * 1000, val.avgHashrate]));
return [slug]; return [slug];
}), }),
); );

View file

@ -125,10 +125,10 @@ export class ApiService {
return this.httpClient.post<any>(this.apiBaseUrl + this.apiBasePath + '/api/tx', hexPayload, { responseType: 'text' as 'json'}); return this.httpClient.post<any>(this.apiBaseUrl + this.apiBasePath + '/api/tx', hexPayload, { responseType: 'text' as 'json'});
} }
listPools$(interval: string | undefined) : Observable<PoolsStats> { listPools$(interval: string | undefined) : Observable<any> {
return this.httpClient.get<PoolsStats>( return this.httpClient.get<any>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pools` + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/pools` +
(interval !== undefined ? `/${interval}` : '') (interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
); );
} }
@ -157,28 +157,28 @@ export class ApiService {
getHistoricalHashrate$(interval: string | undefined): Observable<any> { getHistoricalHashrate$(interval: string | undefined): Observable<any> {
return this.httpClient.get<any[]>( return this.httpClient.get<any[]>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/hashrate` + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/hashrate` +
(interval !== undefined ? `/${interval}` : '') (interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
); );
} }
getHistoricalPoolsHashrate$(interval: string | undefined): Observable<any> { getHistoricalPoolsHashrate$(interval: string | undefined): Observable<any> {
return this.httpClient.get<any[]>( return this.httpClient.get<any[]>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/hashrate/pools` + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/hashrate/pools` +
(interval !== undefined ? `/${interval}` : '') (interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
); );
} }
getHistoricalBlockFees$(interval: string | undefined) : Observable<any> { getHistoricalBlockFees$(interval: string | undefined) : Observable<any> {
return this.httpClient.get<any[]>( return this.httpClient.get<any[]>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/fees` + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/fees` +
(interval !== undefined ? `/${interval}` : '') (interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
); );
} }
getHistoricalBlockRewards$(interval: string | undefined) : Observable<any> { getHistoricalBlockRewards$(interval: string | undefined) : Observable<any> {
return this.httpClient.get<any[]>( return this.httpClient.get<any[]>(
this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/rewards` + this.apiBaseUrl + this.apiBasePath + `/api/v1/mining/blocks/rewards` +
(interval !== undefined ? `/${interval}` : '') (interval !== undefined ? `/${interval}` : ''), { observe: 'response' }
); );
} }

View file

@ -18,7 +18,7 @@ export interface MiningStats {
totalEmptyBlockRatio: string; totalEmptyBlockRatio: string;
pools: SinglePoolStats[]; pools: SinglePoolStats[];
miningUnits: MiningUnits; miningUnits: MiningUnits;
availableTimespanDay: number; totalBlockCount: number;
} }
@Injectable({ @Injectable({
@ -37,7 +37,7 @@ export class MiningService {
*/ */
public getMiningStats(interval: string): Observable<MiningStats> { public getMiningStats(interval: string): Observable<MiningStats> {
return this.apiService.listPools$(interval).pipe( return this.apiService.listPools$(interval).pipe(
map(pools => this.generateMiningStats(pools)) map(response => this.generateMiningStats(response))
); );
} }
@ -82,7 +82,8 @@ export class MiningService {
return preference; return preference;
} }
private generateMiningStats(stats: PoolsStats): MiningStats { private generateMiningStats(response): MiningStats {
const stats: PoolsStats = response.body;
const miningUnits = this.getMiningUnits(); const miningUnits = this.getMiningUnits();
const hashrateDivider = miningUnits.hashrateDivider; const hashrateDivider = miningUnits.hashrateDivider;
@ -100,10 +101,6 @@ export class MiningService {
}; };
}); });
const availableTimespanDay = (
(new Date().getTime() / 1000) - (stats.oldestIndexedBlockTimestamp)
) / 3600 / 24;
return { return {
lastEstimatedHashrate: (stats.lastEstimatedHashrate / hashrateDivider).toFixed(2), lastEstimatedHashrate: (stats.lastEstimatedHashrate / hashrateDivider).toFixed(2),
blockCount: stats.blockCount, blockCount: stats.blockCount,
@ -111,7 +108,7 @@ export class MiningService {
totalEmptyBlockRatio: totalEmptyBlockRatio, totalEmptyBlockRatio: totalEmptyBlockRatio,
pools: poolsStats, pools: poolsStats,
miningUnits: miningUnits, miningUnits: miningUnits,
availableTimespanDay: availableTimespanDay, totalBlockCount: parseInt(response.headers.get('x-total-count'), 10),
}; };
} }
} }