Merge pull request #3091 from mempool/nymkappa/feature/avg-block-health-pool
Show average block health in pool ranking
This commit is contained in:
commit
994b31527b
@ -100,6 +100,7 @@ class Mining {
|
|||||||
rank: rank++,
|
rank: rank++,
|
||||||
emptyBlocks: emptyBlocksCount.length > 0 ? emptyBlocksCount[0]['count'] : 0,
|
emptyBlocks: emptyBlocksCount.length > 0 ? emptyBlocksCount[0]['count'] : 0,
|
||||||
slug: poolInfo.slug,
|
slug: poolInfo.slug,
|
||||||
|
avgMatchRate: poolInfo.avgMatchRate !== null ? Math.round(100 * poolInfo.avgMatchRate) / 100 : null,
|
||||||
};
|
};
|
||||||
poolsStats.push(poolStat);
|
poolsStats.push(poolStat);
|
||||||
});
|
});
|
||||||
|
@ -16,6 +16,7 @@ export interface PoolInfo {
|
|||||||
link: string;
|
link: string;
|
||||||
blockCount: number;
|
blockCount: number;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
avgMatchRate: number | null;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface PoolStats extends PoolInfo {
|
export interface PoolStats extends PoolInfo {
|
||||||
|
@ -27,16 +27,25 @@ class PoolsRepository {
|
|||||||
public async $getPoolsInfo(interval: string | null = null): Promise<PoolInfo[]> {
|
public async $getPoolsInfo(interval: string | null = null): Promise<PoolInfo[]> {
|
||||||
interval = Common.getSqlInterval(interval);
|
interval = Common.getSqlInterval(interval);
|
||||||
|
|
||||||
let query = `SELECT COUNT(height) as blockCount, pool_id as poolId, pools.name as name, pools.link as link, slug
|
let query = `
|
||||||
|
SELECT
|
||||||
|
COUNT(blocks.height) As blockCount,
|
||||||
|
pool_id AS poolId,
|
||||||
|
pools.name AS name,
|
||||||
|
pools.link AS link,
|
||||||
|
slug,
|
||||||
|
AVG(blocks_audits.match_rate) AS avgMatchRate
|
||||||
FROM blocks
|
FROM blocks
|
||||||
JOIN pools on pools.id = pool_id`;
|
JOIN pools on pools.id = pool_id
|
||||||
|
LEFT JOIN blocks_audits ON blocks_audits.height = blocks.height
|
||||||
|
`;
|
||||||
|
|
||||||
if (interval) {
|
if (interval) {
|
||||||
query += ` WHERE blocks.blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
|
query += ` WHERE blocks.blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
|
||||||
}
|
}
|
||||||
|
|
||||||
query += ` GROUP BY pool_id
|
query += ` GROUP BY pool_id
|
||||||
ORDER BY COUNT(height) DESC`;
|
ORDER BY COUNT(blocks.height) DESC`;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const [rows] = await DB.query(query);
|
const [rows] = await DB.query(query);
|
||||||
|
@ -92,6 +92,8 @@
|
|||||||
<th class="" i18n="mining.pool-name">Pool</th>
|
<th class="" i18n="mining.pool-name">Pool</th>
|
||||||
<th class="" *ngIf="this.miningWindowPreference === '24h'" i18n="mining.hashrate">Hashrate</th>
|
<th class="" *ngIf="this.miningWindowPreference === '24h'" i18n="mining.hashrate">Hashrate</th>
|
||||||
<th class="" i18n="master-page.blocks">Blocks</th>
|
<th class="" i18n="master-page.blocks">Blocks</th>
|
||||||
|
<th *ngIf="auditAvailable" class="health text-right widget" i18n="latest-blocks.avg_health"
|
||||||
|
i18n-ngbTooltip="latest-blocks.avg_health" ngbTooltip="Avg Health" placement="bottom" #health [disableTooltip]="!isEllipsisActive(health)">Avg Health</th>
|
||||||
<th class="d-none d-md-block" i18n="mining.empty-blocks">Empty blocks</th>
|
<th class="d-none d-md-block" i18n="mining.empty-blocks">Empty blocks</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
@ -104,7 +106,21 @@
|
|||||||
<td class=""><a [routerLink]="[('/mining/pool/' + pool.slug) | relativeUrl]">{{ pool.name }}</a></td>
|
<td class=""><a [routerLink]="[('/mining/pool/' + pool.slug) | relativeUrl]">{{ pool.name }}</a></td>
|
||||||
<td class="" *ngIf="this.miningWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{
|
<td class="" *ngIf="this.miningWindowPreference === '24h' && !isLoading">{{ pool.lastEstimatedHashrate }} {{
|
||||||
miningStats.miningUnits.hashrateUnit }}</td>
|
miningStats.miningUnits.hashrateUnit }}</td>
|
||||||
<td class="">{{ pool['blockText'] }}</td>
|
<td class="d-flex justify-content-center">
|
||||||
|
{{ pool.blockCount }}<span class="d-none d-md-block"> ({{ pool.share }}%)</span>
|
||||||
|
</td>
|
||||||
|
<td *ngIf="auditAvailable" class="health text-right" [ngClass]="{'widget': widget, 'legacy': !indexingAvailable}">
|
||||||
|
<a
|
||||||
|
class="health-badge badge"
|
||||||
|
[class.badge-success]="pool.avgMatchRate >= 99"
|
||||||
|
[class.badge-warning]="pool.avgMatchRate >= 75 && pool.avgMatchRate < 99"
|
||||||
|
[class.badge-danger]="pool.avgMatchRate < 75"
|
||||||
|
*ngIf="pool.avgMatchRate != null; else nullHealth"
|
||||||
|
>{{ pool.avgMatchRate }}%</a>
|
||||||
|
<ng-template #nullHealth>
|
||||||
|
<span class="health-badge badge badge-secondary" i18n="unknown">Unknown</span>
|
||||||
|
</ng-template>
|
||||||
|
</td>
|
||||||
<td class="d-none d-md-block">{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%)</td>
|
<td class="d-none d-md-block">{{ pool.emptyBlocks }} ({{ pool.emptyBlockRatio }}%)</td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr style="border-top: 1px solid #555">
|
<tr style="border-top: 1px solid #555">
|
||||||
|
@ -26,6 +26,8 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
miningWindowPreference: string;
|
miningWindowPreference: string;
|
||||||
radioGroupForm: UntypedFormGroup;
|
radioGroupForm: UntypedFormGroup;
|
||||||
|
|
||||||
|
auditAvailable = false;
|
||||||
|
indexingAvailable = false;
|
||||||
isLoading = true;
|
isLoading = true;
|
||||||
chartOptions: EChartsOption = {};
|
chartOptions: EChartsOption = {};
|
||||||
chartInitOptions = {
|
chartInitOptions = {
|
||||||
@ -60,6 +62,10 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference });
|
||||||
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference);
|
||||||
|
|
||||||
|
this.indexingAvailable = (this.stateService.env.BASE_MODULE === 'mempool' &&
|
||||||
|
this.stateService.env.MINING_DASHBOARD === true);
|
||||||
|
this.auditAvailable = this.indexingAvailable && this.stateService.env.AUDIT;
|
||||||
|
|
||||||
this.route
|
this.route
|
||||||
.fragment
|
.fragment
|
||||||
.subscribe((fragment) => {
|
.subscribe((fragment) => {
|
||||||
@ -92,7 +98,6 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
)
|
)
|
||||||
.pipe(
|
.pipe(
|
||||||
map(data => {
|
map(data => {
|
||||||
data.pools = data.pools.map((pool: SinglePoolStats) => this.formatPoolUI(pool));
|
|
||||||
data['minersLuck'] = (100 * (data.blockCount / 1008)).toFixed(2); // luck 1w
|
data['minersLuck'] = (100 * (data.blockCount / 1008)).toFixed(2); // luck 1w
|
||||||
return data;
|
return data;
|
||||||
}),
|
}),
|
||||||
@ -104,11 +109,6 @@ export class PoolRankingComponent implements OnInit {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
formatPoolUI(pool: SinglePoolStats) {
|
|
||||||
pool['blockText'] = pool.blockCount.toString() + ` (${pool.share}%)`;
|
|
||||||
return pool;
|
|
||||||
}
|
|
||||||
|
|
||||||
generatePoolsChartSerieData(miningStats) {
|
generatePoolsChartSerieData(miningStats) {
|
||||||
let poolShareThreshold = 0.5;
|
let poolShareThreshold = 0.5;
|
||||||
if (isMobile()) {
|
if (isMobile()) {
|
||||||
|
@ -73,6 +73,7 @@ export interface SinglePoolStats {
|
|||||||
emptyBlockRatio: string;
|
emptyBlockRatio: string;
|
||||||
logo: string;
|
logo: string;
|
||||||
slug: string;
|
slug: string;
|
||||||
|
avgMatchRate: number;
|
||||||
}
|
}
|
||||||
export interface PoolsStats {
|
export interface PoolsStats {
|
||||||
blockCount: number;
|
blockCount: number;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user