Merge branch 'master' into add-schildbach
This commit is contained in:
		
						commit
						fae54797e8
					
				| @ -15,6 +15,7 @@ import BitcoinApi from './bitcoin/bitcoin-api'; | |||||||
| import { prepareBlock } from '../utils/blocks-utils'; | import { prepareBlock } from '../utils/blocks-utils'; | ||||||
| import BlocksRepository from '../repositories/BlocksRepository'; | import BlocksRepository from '../repositories/BlocksRepository'; | ||||||
| import HashratesRepository from '../repositories/HashratesRepository'; | import HashratesRepository from '../repositories/HashratesRepository'; | ||||||
|  | import indexer from '../indexer'; | ||||||
| 
 | 
 | ||||||
| class Blocks { | class Blocks { | ||||||
|   private blocks: BlockExtended[] = []; |   private blocks: BlockExtended[] = []; | ||||||
| @ -23,9 +24,6 @@ class Blocks { | |||||||
|   private lastDifficultyAdjustmentTime = 0; |   private lastDifficultyAdjustmentTime = 0; | ||||||
|   private previousDifficultyRetarget = 0; |   private previousDifficultyRetarget = 0; | ||||||
|   private newBlockCallbacks: ((block: BlockExtended, txIds: string[], transactions: TransactionExtended[]) => void)[] = []; |   private newBlockCallbacks: ((block: BlockExtended, txIds: string[], transactions: TransactionExtended[]) => void)[] = []; | ||||||
|   private blockIndexingStarted = false; |  | ||||||
|   public blockIndexingCompleted = false; |  | ||||||
|   public reindexFlag = false; |  | ||||||
| 
 | 
 | ||||||
|   constructor() { } |   constructor() { } | ||||||
| 
 | 
 | ||||||
| @ -197,24 +195,15 @@ class Blocks { | |||||||
|    * [INDEXING] Index all blocks metadata for the mining dashboard |    * [INDEXING] Index all blocks metadata for the mining dashboard | ||||||
|    */ |    */ | ||||||
|   public async $generateBlockDatabase() { |   public async $generateBlockDatabase() { | ||||||
|     if (this.blockIndexingStarted && !this.reindexFlag) { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     this.reindexFlag = false; |  | ||||||
| 
 |  | ||||||
|     const blockchainInfo = await bitcoinClient.getBlockchainInfo(); |     const blockchainInfo = await bitcoinClient.getBlockchainInfo(); | ||||||
|     if (blockchainInfo.blocks !== blockchainInfo.headers) { // Wait for node to sync
 |     if (blockchainInfo.blocks !== blockchainInfo.headers) { // Wait for node to sync
 | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     this.blockIndexingStarted = true; |  | ||||||
|     this.blockIndexingCompleted = false; |  | ||||||
| 
 |  | ||||||
|     try { |     try { | ||||||
|       let currentBlockHeight = blockchainInfo.blocks; |       let currentBlockHeight = blockchainInfo.blocks; | ||||||
| 
 | 
 | ||||||
|       let indexingBlockAmount = config.MEMPOOL.INDEXING_BLOCKS_AMOUNT; |       let indexingBlockAmount = Math.min(config.MEMPOOL.INDEXING_BLOCKS_AMOUNT, blockchainInfo.blocks); | ||||||
|       if (indexingBlockAmount <= -1) { |       if (indexingBlockAmount <= -1) { | ||||||
|         indexingBlockAmount = currentBlockHeight + 1; |         indexingBlockAmount = currentBlockHeight + 1; | ||||||
|       } |       } | ||||||
| @ -275,14 +264,14 @@ class Blocks { | |||||||
|       loadingIndicators.setProgress('block-indexing', 100); |       loadingIndicators.setProgress('block-indexing', 100); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       logger.err('Block indexing failed. Trying again later. Reason: ' + (e instanceof Error ? e.message : e)); |       logger.err('Block indexing failed. Trying again later. Reason: ' + (e instanceof Error ? e.message : e)); | ||||||
|       this.blockIndexingStarted = false; |  | ||||||
|       loadingIndicators.setProgress('block-indexing', 100); |       loadingIndicators.setProgress('block-indexing', 100); | ||||||
|       return; |       return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const chainValid = await BlocksRepository.$validateChain(); |     const chainValid = await BlocksRepository.$validateChain(); | ||||||
|     this.reindexFlag = !chainValid; |     if (!chainValid) { | ||||||
|     this.blockIndexingCompleted = chainValid; |       indexer.reindex(); | ||||||
|  |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   public async $updateBlocks() { |   public async $updateBlocks() { | ||||||
| @ -299,6 +288,8 @@ class Blocks { | |||||||
|       logger.info(`${blockHeightTip - this.currentBlockHeight} blocks since tip. Fast forwarding to the ${config.MEMPOOL.INITIAL_BLOCKS_AMOUNT} recent blocks`); |       logger.info(`${blockHeightTip - this.currentBlockHeight} blocks since tip. Fast forwarding to the ${config.MEMPOOL.INITIAL_BLOCKS_AMOUNT} recent blocks`); | ||||||
|       this.currentBlockHeight = blockHeightTip - config.MEMPOOL.INITIAL_BLOCKS_AMOUNT; |       this.currentBlockHeight = blockHeightTip - config.MEMPOOL.INITIAL_BLOCKS_AMOUNT; | ||||||
|       fastForwarded = true; |       fastForwarded = true; | ||||||
|  |       logger.info(`Re-indexing skipped blocks and corresponding hashrates data`); | ||||||
|  |       indexer.reindex(); // Make sure to index the skipped blocks #1619
 | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (!this.lastDifficultyAdjustmentTime) { |     if (!this.lastDifficultyAdjustmentTime) { | ||||||
|  | |||||||
| @ -4,15 +4,11 @@ import PoolsRepository from '../repositories/PoolsRepository'; | |||||||
| import HashratesRepository from '../repositories/HashratesRepository'; | import HashratesRepository from '../repositories/HashratesRepository'; | ||||||
| import bitcoinClient from './bitcoin/bitcoin-client'; | import bitcoinClient from './bitcoin/bitcoin-client'; | ||||||
| import logger from '../logger'; | import logger from '../logger'; | ||||||
| import blocks from './blocks'; |  | ||||||
| import { Common } from './common'; | import { Common } from './common'; | ||||||
| import loadingIndicators from './loading-indicators'; | import loadingIndicators from './loading-indicators'; | ||||||
| import { escape } from 'mysql2'; | import { escape } from 'mysql2'; | ||||||
| 
 | 
 | ||||||
| class Mining { | class Mining { | ||||||
|   hashrateIndexingStarted = false; |  | ||||||
|   weeklyHashrateIndexingStarted = false; |  | ||||||
| 
 |  | ||||||
|   constructor() { |   constructor() { | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
| @ -153,14 +149,9 @@ class Mining { | |||||||
|    * [INDEXING] Generate weekly mining pool hashrate history |    * [INDEXING] Generate weekly mining pool hashrate history | ||||||
|    */ |    */ | ||||||
|   public async $generatePoolHashrateHistory(): Promise<void> { |   public async $generatePoolHashrateHistory(): Promise<void> { | ||||||
|     if (!blocks.blockIndexingCompleted || this.hashrateIndexingStarted || this.weeklyHashrateIndexingStarted) { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const now = new Date(); |     const now = new Date(); | ||||||
| 
 | 
 | ||||||
|     try { |     try { | ||||||
|       this.weeklyHashrateIndexingStarted = true; |  | ||||||
|       const lastestRunDate = await HashratesRepository.$getLatestRun('last_weekly_hashrates_indexing'); |       const lastestRunDate = await HashratesRepository.$getLatestRun('last_weekly_hashrates_indexing'); | ||||||
| 
 | 
 | ||||||
|       // Run only if:
 |       // Run only if:
 | ||||||
| @ -168,11 +159,9 @@ class Mining { | |||||||
|       // * we started a new week (around Monday midnight)
 |       // * we started a new week (around Monday midnight)
 | ||||||
|       const runIndexing = lastestRunDate === 0 || now.getUTCDay() === 1 && lastestRunDate !== now.getUTCDate(); |       const runIndexing = lastestRunDate === 0 || now.getUTCDay() === 1 && lastestRunDate !== now.getUTCDate(); | ||||||
|       if (!runIndexing) { |       if (!runIndexing) { | ||||||
|         this.weeklyHashrateIndexingStarted = false; |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       this.weeklyHashrateIndexingStarted = false; |  | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -192,6 +181,7 @@ class Mining { | |||||||
|       const startedAt = new Date().getTime() / 1000; |       const startedAt = new Date().getTime() / 1000; | ||||||
|       let timer = new Date().getTime() / 1000; |       let timer = new Date().getTime() / 1000; | ||||||
| 
 | 
 | ||||||
|  |       logger.debug(`Indexing weekly mining pool hashrate`); | ||||||
|       loadingIndicators.setProgress('weekly-hashrate-indexing', 0); |       loadingIndicators.setProgress('weekly-hashrate-indexing', 0); | ||||||
| 
 | 
 | ||||||
|       while (toTimestamp > genesisTimestamp) { |       while (toTimestamp > genesisTimestamp) { | ||||||
| @ -256,7 +246,6 @@ class Mining { | |||||||
|         ++indexedThisRun; |         ++indexedThisRun; | ||||||
|         ++totalIndexed; |         ++totalIndexed; | ||||||
|       } |       } | ||||||
|       this.weeklyHashrateIndexingStarted = false; |  | ||||||
|       await HashratesRepository.$setLatestRun('last_weekly_hashrates_indexing', new Date().getUTCDate()); |       await HashratesRepository.$setLatestRun('last_weekly_hashrates_indexing', new Date().getUTCDate()); | ||||||
|       if (newlyIndexed > 0) { |       if (newlyIndexed > 0) { | ||||||
|         logger.info(`Indexed ${newlyIndexed} pools weekly hashrate`); |         logger.info(`Indexed ${newlyIndexed} pools weekly hashrate`); | ||||||
| @ -264,7 +253,6 @@ class Mining { | |||||||
|       loadingIndicators.setProgress('weekly-hashrate-indexing', 100); |       loadingIndicators.setProgress('weekly-hashrate-indexing', 100); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       loadingIndicators.setProgress('weekly-hashrate-indexing', 100); |       loadingIndicators.setProgress('weekly-hashrate-indexing', 100); | ||||||
|       this.weeklyHashrateIndexingStarted = false; |  | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
| @ -273,22 +261,14 @@ class Mining { | |||||||
|    * [INDEXING] Generate daily hashrate data |    * [INDEXING] Generate daily hashrate data | ||||||
|    */ |    */ | ||||||
|   public async $generateNetworkHashrateHistory(): Promise<void> { |   public async $generateNetworkHashrateHistory(): Promise<void> { | ||||||
|     if (!blocks.blockIndexingCompleted || this.hashrateIndexingStarted) { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     try { |     try { | ||||||
|       this.hashrateIndexingStarted = true; |  | ||||||
| 
 |  | ||||||
|       // We only run this once a day around midnight
 |       // We only run this once a day around midnight
 | ||||||
|       const latestRunDate = await HashratesRepository.$getLatestRun('last_hashrates_indexing'); |       const latestRunDate = await HashratesRepository.$getLatestRun('last_hashrates_indexing'); | ||||||
|       const now = new Date().getUTCDate(); |       const now = new Date().getUTCDate(); | ||||||
|       if (now === latestRunDate) { |       if (now === latestRunDate) { | ||||||
|         this.hashrateIndexingStarted = false; |  | ||||||
|         return; |         return; | ||||||
|       } |       } | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       this.hashrateIndexingStarted = false; |  | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| @ -306,6 +286,7 @@ class Mining { | |||||||
|       const startedAt = new Date().getTime() / 1000; |       const startedAt = new Date().getTime() / 1000; | ||||||
|       let timer = new Date().getTime() / 1000; |       let timer = new Date().getTime() / 1000; | ||||||
| 
 | 
 | ||||||
|  |       logger.debug(`Indexing daily network hashrate`); | ||||||
|       loadingIndicators.setProgress('daily-hashrate-indexing', 0); |       loadingIndicators.setProgress('daily-hashrate-indexing', 0); | ||||||
| 
 | 
 | ||||||
|       while (toTimestamp > genesisTimestamp) { |       while (toTimestamp > genesisTimestamp) { | ||||||
| @ -377,14 +358,12 @@ class Mining { | |||||||
|       await HashratesRepository.$saveHashrates(hashrates); |       await HashratesRepository.$saveHashrates(hashrates); | ||||||
| 
 | 
 | ||||||
|       await HashratesRepository.$setLatestRun('last_hashrates_indexing', new Date().getUTCDate()); |       await HashratesRepository.$setLatestRun('last_hashrates_indexing', new Date().getUTCDate()); | ||||||
|       this.hashrateIndexingStarted = false; |  | ||||||
|       if (newlyIndexed > 0) { |       if (newlyIndexed > 0) { | ||||||
|         logger.info(`Indexed ${newlyIndexed} day of network hashrate`); |         logger.info(`Indexed ${newlyIndexed} day of network hashrate`); | ||||||
|       } |       } | ||||||
|       loadingIndicators.setProgress('daily-hashrate-indexing', 100); |       loadingIndicators.setProgress('daily-hashrate-indexing', 100); | ||||||
|     } catch (e) { |     } catch (e) { | ||||||
|       loadingIndicators.setProgress('daily-hashrate-indexing', 100); |       loadingIndicators.setProgress('daily-hashrate-indexing', 100); | ||||||
|       this.hashrateIndexingStarted = false; |  | ||||||
|       throw e; |       throw e; | ||||||
|     } |     } | ||||||
|   } |   } | ||||||
|  | |||||||
| @ -29,6 +29,7 @@ import mining from './api/mining'; | |||||||
| import HashratesRepository from './repositories/HashratesRepository'; | import HashratesRepository from './repositories/HashratesRepository'; | ||||||
| import BlocksRepository from './repositories/BlocksRepository'; | import BlocksRepository from './repositories/BlocksRepository'; | ||||||
| import poolsUpdater from './tasks/pools-updater'; | import poolsUpdater from './tasks/pools-updater'; | ||||||
|  | import indexer from './indexer'; | ||||||
| 
 | 
 | ||||||
| class Server { | class Server { | ||||||
|   private wss: WebSocket.Server | undefined; |   private wss: WebSocket.Server | undefined; | ||||||
| @ -99,7 +100,7 @@ class Server { | |||||||
|         } |         } | ||||||
|         await databaseMigration.$initializeOrMigrateDatabase(); |         await databaseMigration.$initializeOrMigrateDatabase(); | ||||||
|         if (Common.indexingEnabled()) { |         if (Common.indexingEnabled()) { | ||||||
|           await this.$resetHashratesIndexingState(); |           await indexer.$resetHashratesIndexingState(); | ||||||
|         } |         } | ||||||
|       } catch (e) { |       } catch (e) { | ||||||
|         throw new Error(e instanceof Error ? e.message : 'Error'); |         throw new Error(e instanceof Error ? e.message : 'Error'); | ||||||
| @ -154,7 +155,7 @@ class Server { | |||||||
|       await poolsUpdater.updatePoolsJson(); |       await poolsUpdater.updatePoolsJson(); | ||||||
|       await blocks.$updateBlocks(); |       await blocks.$updateBlocks(); | ||||||
|       await memPool.$updateMempool(); |       await memPool.$updateMempool(); | ||||||
|       this.$runIndexingWhenReady(); |       indexer.$run(); | ||||||
| 
 | 
 | ||||||
|       setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); |       setTimeout(this.runMainUpdateLoop.bind(this), config.MEMPOOL.POLL_RATE_MS); | ||||||
|       this.currentBackendRetryInterval = 5; |       this.currentBackendRetryInterval = 5; | ||||||
| @ -173,29 +174,6 @@ class Server { | |||||||
|     } |     } | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|   async $resetHashratesIndexingState() { |  | ||||||
|     try { |  | ||||||
|       await HashratesRepository.$setLatestRun('last_hashrates_indexing', 0); |  | ||||||
|       await HashratesRepository.$setLatestRun('last_weekly_hashrates_indexing', 0); |  | ||||||
|     } catch (e) { |  | ||||||
|       logger.err(`Cannot reset hashrate indexing timestamps. Reason: ` + (e instanceof Error ? e.message : e)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   async $runIndexingWhenReady() { |  | ||||||
|     if (!Common.indexingEnabled() || mempool.hasPriority()) { |  | ||||||
|       return; |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     try { |  | ||||||
|       await blocks.$generateBlockDatabase(); |  | ||||||
|       await mining.$generateNetworkHashrateHistory(); |  | ||||||
|       await mining.$generatePoolHashrateHistory(); |  | ||||||
|     } catch (e) { |  | ||||||
|       logger.err(`Indexing failed, trying again later. Reason: ` + (e instanceof Error ? e.message : e)); |  | ||||||
|     } |  | ||||||
|   } |  | ||||||
| 
 |  | ||||||
|   setUpWebsocketHandling() { |   setUpWebsocketHandling() { | ||||||
|     if (this.wss) { |     if (this.wss) { | ||||||
|       websocketHandler.setWebsocketServer(this.wss); |       websocketHandler.setWebsocketServer(this.wss); | ||||||
|  | |||||||
							
								
								
									
										52
									
								
								backend/src/indexer.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										52
									
								
								backend/src/indexer.ts
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,52 @@ | |||||||
|  | import { Common } from './api/common'; | ||||||
|  | import blocks from './api/blocks'; | ||||||
|  | import mempool from './api/mempool'; | ||||||
|  | import mining from './api/mining'; | ||||||
|  | import logger from './logger'; | ||||||
|  | import HashratesRepository from './repositories/HashratesRepository'; | ||||||
|  | 
 | ||||||
|  | class Indexer { | ||||||
|  |   runIndexer = true; | ||||||
|  |   indexerRunning = false; | ||||||
|  | 
 | ||||||
|  |   constructor() { | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public reindex() { | ||||||
|  |     this.runIndexer = true; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   public async $run() { | ||||||
|  |     if (!Common.indexingEnabled() || this.runIndexer === false || | ||||||
|  |       this.indexerRunning === true || mempool.hasPriority() | ||||||
|  |     ) { | ||||||
|  |       return; | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.runIndexer = false; | ||||||
|  |     this.indexerRunning = true; | ||||||
|  | 
 | ||||||
|  |     try { | ||||||
|  |       await blocks.$generateBlockDatabase(); | ||||||
|  |       await this.$resetHashratesIndexingState(); | ||||||
|  |       await mining.$generateNetworkHashrateHistory(); | ||||||
|  |       await mining.$generatePoolHashrateHistory(); | ||||||
|  |     } catch (e) { | ||||||
|  |       this.reindex(); | ||||||
|  |       logger.err(`Indexer failed, trying again later. Reason: ` + (e instanceof Error ? e.message : e)); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     this.indexerRunning = false; | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   async $resetHashratesIndexingState() { | ||||||
|  |     try { | ||||||
|  |       await HashratesRepository.$setLatestRun('last_hashrates_indexing', 0); | ||||||
|  |       await HashratesRepository.$setLatestRun('last_weekly_hashrates_indexing', 0); | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.err(`Cannot reset hashrate indexing timestamps. Reason: ` + (e instanceof Error ? e.message : e)); | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | export default new Indexer(); | ||||||
| @ -1,7 +1,7 @@ | |||||||
| <div class="mb-3 d-flex menu" style="padding: 0px 35px;"> | <div *ngIf="stateService.env.MINING_DASHBOARD" class="mb-3 d-flex menu" style="padding: 0px 35px;"> | ||||||
|   <a routerLinkActive="active" class="btn btn-primary w-50 mr-1" |   <a routerLinkActive="active" class="btn btn-primary w-50 mr-1" | ||||||
|     [routerLink]="['/graphs/mempool' | relativeUrl]">Mempool</a> |     [routerLink]="['/graphs/mempool' | relativeUrl]">Mempool</a> | ||||||
|   <div ngbDropdown *ngIf="stateService.env.MINING_DASHBOARD" class="w-50"> |   <div ngbDropdown class="w-50"> | ||||||
|     <button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="mining">Mining</button> |     <button class="btn btn-primary w-100" id="dropdownBasic1" ngbDropdownToggle i18n="mining">Mining</button> | ||||||
|     <div ngbDropdownMenu aria-labelledby="dropdownBasic1"> |     <div ngbDropdownMenu aria-labelledby="dropdownBasic1"> | ||||||
|       <a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools' | relativeUrl]" |       <a class="dropdown-item" routerLinkActive="active" [routerLink]="['/graphs/mining/pools' | relativeUrl]" | ||||||
|  | |||||||
| @ -198,9 +198,7 @@ | |||||||
|     display: none; |     display: none; | ||||||
|     text-align: right; |     text-align: right; | ||||||
|     width: 20%; |     width: 20%; | ||||||
|     @media (min-width: 376px) { |     display: table-cell; | ||||||
|       display: table-cell; |  | ||||||
|     } |  | ||||||
|   } |   } | ||||||
|   .table-cell-size { |   .table-cell-size { | ||||||
|     display: none; |     display: none; | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user