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