Index new hashrates once every 24 hours
This commit is contained in:
		
							parent
							
								
									358604ad85
								
							
						
					
					
						commit
						e61df324ea
					
				@ -261,6 +261,10 @@ class DatabaseMigration {
 | 
			
		||||
      }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    if (version < 7) {
 | 
			
		||||
      queries.push(`INSERT INTO state(name, number, string) VALUES ('last_hashrates_indexing', 0, NULL)`);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    return queries;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -14,7 +14,7 @@ class Mining {
 | 
			
		||||
  /**
 | 
			
		||||
   * Generate high level overview of the pool ranks and general stats
 | 
			
		||||
   */
 | 
			
		||||
  public async $getPoolsStats(interval: string | null) : Promise<object> {
 | 
			
		||||
  public async $getPoolsStats(interval: string | null): Promise<object> {
 | 
			
		||||
    const poolsStatistics = {};
 | 
			
		||||
 | 
			
		||||
    const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(interval);
 | 
			
		||||
@ -30,8 +30,8 @@ class Mining {
 | 
			
		||||
        link: poolInfo.link,
 | 
			
		||||
        blockCount: poolInfo.blockCount,
 | 
			
		||||
        rank: rank++,
 | 
			
		||||
        emptyBlocks: 0, 
 | 
			
		||||
      }
 | 
			
		||||
        emptyBlocks: 0
 | 
			
		||||
      };
 | 
			
		||||
      for (let i = 0; i < emptyBlocks.length; ++i) {
 | 
			
		||||
        if (emptyBlocks[i].poolId === poolInfo.poolId) {
 | 
			
		||||
          poolStat.emptyBlocks++;
 | 
			
		||||
@ -84,32 +84,41 @@ class Mining {
 | 
			
		||||
    return {
 | 
			
		||||
      adjustments: difficultyAdjustments,
 | 
			
		||||
      oldestIndexedBlockTimestamp: oldestBlock.getTime(),
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * Return the historical hashrates and oldest indexed block timestamp
 | 
			
		||||
   */
 | 
			
		||||
   public async $getHistoricalHashrates(interval: string | null): Promise<object> {
 | 
			
		||||
  public async $getHistoricalHashrates(interval: string | null): Promise<object> {
 | 
			
		||||
    const hashrates = await HashratesRepository.$get(interval);
 | 
			
		||||
    const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
 | 
			
		||||
 | 
			
		||||
    return {
 | 
			
		||||
      hashrates: hashrates,
 | 
			
		||||
      oldestIndexedBlockTimestamp: oldestBlock.getTime(),
 | 
			
		||||
    }
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  /**
 | 
			
		||||
   * 
 | 
			
		||||
   * Generate daily hashrate data
 | 
			
		||||
   */
 | 
			
		||||
  public async $generateNetworkHashrateHistory() : Promise<void> {
 | 
			
		||||
  public async $generateNetworkHashrateHistory(): Promise<void> {
 | 
			
		||||
    // We only run this once a day
 | 
			
		||||
    const latestTimestamp = await HashratesRepository.$getLatestRunTimestamp();
 | 
			
		||||
    const now = new Date().getTime() / 1000;
 | 
			
		||||
    if (now - latestTimestamp < 86400) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    logger.info(`Indexing hashrates`);
 | 
			
		||||
 | 
			
		||||
    if (this.hashrateIndexingStarted) {
 | 
			
		||||
      return;
 | 
			
		||||
    }
 | 
			
		||||
    this.hashrateIndexingStarted = true;
 | 
			
		||||
 | 
			
		||||
    const totalIndexed = await BlocksRepository.$blockCount(null, null);
 | 
			
		||||
    const oldestIndexedBlockHeight = await BlocksRepository.$getOldestIndexedBlockHeight();
 | 
			
		||||
    const indexedTimestamp = (await HashratesRepository.$get(null)).map(hashrate => hashrate.timestamp);
 | 
			
		||||
 | 
			
		||||
    const genesisTimestamp = 1231006505; // bitcoin-cli getblock 000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f
 | 
			
		||||
@ -128,16 +137,18 @@ class Mining {
 | 
			
		||||
        null, fromTimestamp, toTimestamp
 | 
			
		||||
      );
 | 
			
		||||
 | 
			
		||||
      let lastBlockHashrate = 0;
 | 
			
		||||
      if (blockStats.blockCount > 0) {
 | 
			
		||||
        lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount,
 | 
			
		||||
          blockStats.lastBlockHeight);
 | 
			
		||||
      if (blockStats.blockCount === 0) { // We are done indexing, no blocks left
 | 
			
		||||
        break;
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      if (toTimestamp % 864000 === 0) {
 | 
			
		||||
        const progress = Math.round((totalIndexed - blockStats.lastBlockHeight) / totalIndexed * 100);
 | 
			
		||||
      let lastBlockHashrate = 0;
 | 
			
		||||
      lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount,
 | 
			
		||||
        blockStats.lastBlockHeight);
 | 
			
		||||
 | 
			
		||||
      if (toTimestamp % 864000 === 0) { // Log every 10 days during initial indexing
 | 
			
		||||
        const formattedDate = new Date(fromTimestamp * 1000).toUTCString();
 | 
			
		||||
        logger.debug(`Counting blocks and hashrate for ${formattedDate}. Progress: ${progress}%`);
 | 
			
		||||
        const blocksLeft = blockStats.lastBlockHeight - oldestIndexedBlockHeight;
 | 
			
		||||
        logger.debug(`Counting blocks and hashrate for ${formattedDate}. ${blocksLeft} blocks left`);
 | 
			
		||||
      }
 | 
			
		||||
 | 
			
		||||
      await HashratesRepository.$saveDailyStat({
 | 
			
		||||
@ -149,6 +160,9 @@ class Mining {
 | 
			
		||||
      toTimestamp -= 86400;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    await HashratesRepository.$setLatestRunTimestamp();
 | 
			
		||||
    this.hashrateIndexingStarted = false;
 | 
			
		||||
 | 
			
		||||
    logger.info(`Hashrates indexing completed`);
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -281,6 +281,13 @@ class BlocksRepository {
 | 
			
		||||
 | 
			
		||||
    return rows;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getOldestIndexedBlockHeight(): Promise<number> {
 | 
			
		||||
    const connection = await DB.pool.getConnection();
 | 
			
		||||
    const [rows]: any[] = await connection.query(`SELECT MIN(height) as minHeight FROM blocks`);
 | 
			
		||||
    connection.release();
 | 
			
		||||
    return rows[0].minHeight;
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new BlocksRepository();
 | 
			
		||||
 | 
			
		||||
@ -43,11 +43,28 @@ class HashratesRepository {
 | 
			
		||||
      query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    query += ` ORDER by hashrate_timestamp DESC`;
 | 
			
		||||
 | 
			
		||||
    const [rows]: any[] = await connection.query(query);
 | 
			
		||||
    connection.release();
 | 
			
		||||
 | 
			
		||||
    return rows;
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $setLatestRunTimestamp() {
 | 
			
		||||
    const connection = await DB.pool.getConnection();
 | 
			
		||||
    const query = `UPDATE state SET number = ? WHERE name = 'last_hashrates_indexing'`;
 | 
			
		||||
    await connection.query<any>(query, [Math.round(new Date().getTime() / 1000)]);
 | 
			
		||||
    connection.release();
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  public async $getLatestRunTimestamp(): Promise<number> {
 | 
			
		||||
    const connection = await DB.pool.getConnection();
 | 
			
		||||
    const query = `SELECT number FROM state WHERE name = 'last_hashrates_indexing'`;
 | 
			
		||||
    const [rows] = await connection.query<any>(query);
 | 
			
		||||
    connection.release();
 | 
			
		||||
    return rows[0]['number'];
 | 
			
		||||
  }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
export default new HashratesRepository();
 | 
			
		||||
 | 
			
		||||
@ -134,17 +134,18 @@ export class DifficultyChartComponent implements OnInit {
 | 
			
		||||
          }
 | 
			
		||||
        }
 | 
			
		||||
      },
 | 
			
		||||
      series: [
 | 
			
		||||
        {
 | 
			
		||||
          data: data,
 | 
			
		||||
          type: 'line',
 | 
			
		||||
          smooth: false,
 | 
			
		||||
          lineStyle: {
 | 
			
		||||
            width: 3,
 | 
			
		||||
          },
 | 
			
		||||
          areaStyle: {}
 | 
			
		||||
      series: {
 | 
			
		||||
        showSymbol: false,
 | 
			
		||||
        data: data,
 | 
			
		||||
        type: 'line',
 | 
			
		||||
        smooth: false,
 | 
			
		||||
        lineStyle: {
 | 
			
		||||
          width: 2,
 | 
			
		||||
        },
 | 
			
		||||
      ],
 | 
			
		||||
        areaStyle: {
 | 
			
		||||
          opacity: 0.25
 | 
			
		||||
        },
 | 
			
		||||
      },
 | 
			
		||||
    };
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -4,50 +4,29 @@
 | 
			
		||||
  <div class="text-center loadingGraphs" *ngIf="isLoading">
 | 
			
		||||
    <div class="spinner-border text-light"></div>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <div class="card-header mb-0 mb-lg-4" [style]="widget ? 'display:none' : ''">
 | 
			
		||||
    <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as diffChanges">
 | 
			
		||||
  
 | 
			
		||||
  <div class="card-header mb-0 mb-lg-4 mt-3" [style]="widget ? 'display:none' : ''">
 | 
			
		||||
    <form [formGroup]="radioGroupForm" class="formRadioGroup" *ngIf="(hashrateObservable$ | async) as hashrates">
 | 
			
		||||
      <div class="btn-group btn-group-toggle" ngbRadioGroup name="radioBasic" formControlName="dateSpan">
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 90">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3m'" fragment="3m"> 3M
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 90">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3m'"> 3M
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 180">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'6m'" fragment="6m"> 6M
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 180">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'6m'"> 6M
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 365">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1y'" fragment="1y"> 1Y
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 365">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'1y'"> 1Y
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 730">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'2y'" fragment="2y"> 2Y
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 730">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'2y'"> 2Y
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" [routerLink]="['/mining/hashrate' | relativeUrl]" *ngIf="diffChanges.availableTimespanDay >= 1095">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3y'" fragment="3y"> 3Y
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm" *ngIf="hashrates.availableTimespanDay >= 1095">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'3y'"> 3Y
 | 
			
		||||
        </label>
 | 
			
		||||
        <label ngbButtonLabel class="btn-primary btn-sm">
 | 
			
		||||
          <input ngbButton type="radio" [value]="'all'" [routerLink]="['/mining/hashrate' | relativeUrl]" fragment="all"> ALL
 | 
			
		||||
          <input ngbButton type="radio" [value]="'all'"> ALL
 | 
			
		||||
        </label>
 | 
			
		||||
      </div>
 | 
			
		||||
    </form>
 | 
			
		||||
  </div>
 | 
			
		||||
 | 
			
		||||
  <!-- <table class="table table-borderless table-sm text-center" *ngIf="!widget">
 | 
			
		||||
    <thead>
 | 
			
		||||
      <tr>
 | 
			
		||||
        <th i18n="mining.rank">Block</th>
 | 
			
		||||
        <th i18n="block.timestamp">Timestamp</th>
 | 
			
		||||
        <th i18n="mining.hashrate">Difficulty</th>
 | 
			
		||||
        <th i18n="mining.change">Change</th>
 | 
			
		||||
      </tr>
 | 
			
		||||
    </thead>
 | 
			
		||||
    <tbody *ngIf="(hashrateObservable$ | async) as diffChanges">
 | 
			
		||||
      <tr *ngFor="let diffChange of diffChanges.data">
 | 
			
		||||
        <td><a [routerLink]="['/block' | relativeUrl, diffChange.height]">{{ diffChange.height }}</a></td>
 | 
			
		||||
        <td>‎{{ diffChange.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }}</td>
 | 
			
		||||
        <td class="d-none d-md-block">{{ formatNumber(diffChange.hashrate, 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>
 | 
			
		||||
 | 
			
		||||
@ -66,15 +66,15 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
                };
 | 
			
		||||
              }),
 | 
			
		||||
            );
 | 
			
		||||
          }),
 | 
			
		||||
          share()
 | 
			
		||||
        );
 | 
			
		||||
        }),
 | 
			
		||||
        share()
 | 
			
		||||
      );
 | 
			
		||||
  }
 | 
			
		||||
 | 
			
		||||
  prepareChartOptions(data) {
 | 
			
		||||
    this.chartOptions = {
 | 
			
		||||
      title: {
 | 
			
		||||
        text: this.widget? '' : $localize`:@@mining.hashrate:Hashrate`,
 | 
			
		||||
        text: this.widget ? '' : $localize`:@@mining.hashrate:Hashrate`,
 | 
			
		||||
        left: 'center',
 | 
			
		||||
        textStyle: {
 | 
			
		||||
          color: '#FFF',
 | 
			
		||||
@ -102,7 +102,7 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
              giga: Math.pow(10, 9),
 | 
			
		||||
              mega: Math.pow(10, 6),
 | 
			
		||||
              kilo: Math.pow(10, 3),
 | 
			
		||||
            }
 | 
			
		||||
            };
 | 
			
		||||
 | 
			
		||||
            let selectedPowerOfTen = { divider: powerOfTen.exa, unit: 'E' };
 | 
			
		||||
            if (val < powerOfTen.mega) {
 | 
			
		||||
@ -135,9 +135,11 @@ export class HashrateChartComponent implements OnInit {
 | 
			
		||||
        type: 'line',
 | 
			
		||||
        smooth: false,
 | 
			
		||||
        lineStyle: {
 | 
			
		||||
          width: 3,
 | 
			
		||||
          width: 2,
 | 
			
		||||
        },
 | 
			
		||||
        areaStyle: {
 | 
			
		||||
          opacity: 0.25
 | 
			
		||||
        },
 | 
			
		||||
        areaStyle: {},
 | 
			
		||||
      },
 | 
			
		||||
      dataZoom: this.widget ? null : [{
 | 
			
		||||
        type: 'inside',
 | 
			
		||||
 | 
			
		||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user