[nodejs backend] added /api/v1/health
This commit is contained in:
		
							parent
							
								
									5e95d8d6ce
								
							
						
					
					
						commit
						8a51f32e63
					
				| @ -6,7 +6,7 @@ import websocketHandler from '../websocket-handler'; | |||||||
| import mempool from '../mempool'; | import mempool from '../mempool'; | ||||||
| import feeApi from '../fee-api'; | import feeApi from '../fee-api'; | ||||||
| import mempoolBlocks from '../mempool-blocks'; | import mempoolBlocks from '../mempool-blocks'; | ||||||
| import bitcoinApi from './bitcoin-api-factory'; | import bitcoinApi, { bitcoinCoreApi } from './bitcoin-api-factory'; | ||||||
| import { Common } from '../common'; | import { Common } from '../common'; | ||||||
| import backendInfo from '../backend-info'; | import backendInfo from '../backend-info'; | ||||||
| import transactionUtils from '../transaction-utils'; | import transactionUtils from '../transaction-utils'; | ||||||
| @ -19,6 +19,7 @@ import bitcoinClient from './bitcoin-client'; | |||||||
| import difficultyAdjustment from '../difficulty-adjustment'; | import difficultyAdjustment from '../difficulty-adjustment'; | ||||||
| import transactionRepository from '../../repositories/TransactionRepository'; | import transactionRepository from '../../repositories/TransactionRepository'; | ||||||
| import rbfCache from '../rbf-cache'; | import rbfCache from '../rbf-cache'; | ||||||
|  | import BlocksRepository from '../../repositories/BlocksRepository'; | ||||||
| 
 | 
 | ||||||
| class BitcoinRoutes { | class BitcoinRoutes { | ||||||
|   public initRoutes(app: Application) { |   public initRoutes(app: Application) { | ||||||
| @ -126,8 +127,53 @@ class BitcoinRoutes { | |||||||
|           .get(config.MEMPOOL.API_URL_PREFIX + 'address-prefix/:prefix', this.getAddressPrefix) |           .get(config.MEMPOOL.API_URL_PREFIX + 'address-prefix/:prefix', this.getAddressPrefix) | ||||||
|           ; |           ; | ||||||
|       } |       } | ||||||
|  | 
 | ||||||
|  |       app.get(config.MEMPOOL.API_URL_PREFIX + 'health', this.generateHealthReport) | ||||||
|   } |   } | ||||||
| 
 | 
 | ||||||
|  |   private async generateHealthReport(req: Request, res: Response) { | ||||||
|  |     try { | ||||||
|  |       // Bitcoin Core
 | ||||||
|  |       const bitcoinCoreBlockHeight = await bitcoinCoreApi.$getBlockHeightTip(); | ||||||
|  |       const bitcoinCoreIndexes = await bitcoinClient.getIndexInfo(); | ||||||
|  |       // Esplora
 | ||||||
|  |       const esploraBlockHeight = await bitcoinApi.$getBlockHeightTip(); | ||||||
|  |       // Mempool
 | ||||||
|  |       const mempoolBlockHeight = blocks.getCurrentBlockHeight(); | ||||||
|  |       const indexedBlockCount = await BlocksRepository.$getIndexedBlockCount(); | ||||||
|  |       const indexedBlockWithCpfpCount = await BlocksRepository.$getIndexedCpfpBlockCount(); | ||||||
|  |       const indexedBlockWithCoinStatsCount = await BlocksRepository.$getIndexedCoinStatsBlockCount(); | ||||||
|  | 
 | ||||||
|  |       const response = { | ||||||
|  |         core: { | ||||||
|  |           height: bitcoinCoreBlockHeight, | ||||||
|  |         }, | ||||||
|  |         esplora: { | ||||||
|  |           height: esploraBlockHeight | ||||||
|  |         }, | ||||||
|  |         mempool: { | ||||||
|  |           height: mempoolBlockHeight, | ||||||
|  |           indexing: { | ||||||
|  |             indexedBlockCount: indexedBlockCount, | ||||||
|  |             indexedBlockCountWithCPFP: indexedBlockWithCpfpCount, | ||||||
|  |             indexedBlockCountWithCoinStats: indexedBlockWithCoinStatsCount, | ||||||
|  |           } | ||||||
|  |         } | ||||||
|  |       }; | ||||||
|  | 
 | ||||||
|  |       // Bitcoin Core indexes
 | ||||||
|  |       for (const indexName in bitcoinCoreIndexes) { | ||||||
|  |         response.core[indexName] = bitcoinCoreIndexes[indexName]; | ||||||
|  |       } | ||||||
|  | 
 | ||||||
|  |       res.json(response); | ||||||
|  | 
 | ||||||
|  |     } catch (e: any) { | ||||||
|  |       logger.err(`Unable to generate health report. Exception: ${JSON.stringify(e)}`); | ||||||
|  |       logger.err(e.stack); | ||||||
|  |       res.status(500).send(e instanceof Error ? e.message : e); | ||||||
|  |     } | ||||||
|  |   } | ||||||
| 
 | 
 | ||||||
|   private getInitData(req: Request, res: Response) { |   private getInitData(req: Request, res: Response) { | ||||||
|     try { |     try { | ||||||
|  | |||||||
| @ -385,7 +385,7 @@ class BlocksRepository { | |||||||
|   /** |   /** | ||||||
|    * Get blocks count for a period |    * Get blocks count for a period | ||||||
|    */ |    */ | ||||||
|    public async $blockCountBetweenHeight(startHeight: number, endHeight: number): Promise<number> { |   public async $blockCountBetweenHeight(startHeight: number, endHeight: number): Promise<number> { | ||||||
|     const params: any[] = []; |     const params: any[] = []; | ||||||
|     let query = `SELECT count(height) as blockCount
 |     let query = `SELECT count(height) as blockCount
 | ||||||
|       FROM blocks |       FROM blocks | ||||||
| @ -721,7 +721,7 @@ class BlocksRepository { | |||||||
|   /** |   /** | ||||||
|    * Get the historical averaged block fee rate percentiles |    * Get the historical averaged block fee rate percentiles | ||||||
|    */ |    */ | ||||||
|    public async $getHistoricalBlockFeeRates(div: number, interval: string | null): Promise<any> { |   public async $getHistoricalBlockFeeRates(div: number, interval: string | null): Promise<any> { | ||||||
|     try { |     try { | ||||||
|       let query = `SELECT
 |       let query = `SELECT
 | ||||||
|         CAST(AVG(height) as INT) as avgHeight, |         CAST(AVG(height) as INT) as avgHeight, | ||||||
| @ -752,7 +752,7 @@ class BlocksRepository { | |||||||
|   /** |   /** | ||||||
|    * Get the historical averaged block sizes |    * Get the historical averaged block sizes | ||||||
|    */ |    */ | ||||||
|    public async $getHistoricalBlockSizes(div: number, interval: string | null): Promise<any> { |   public async $getHistoricalBlockSizes(div: number, interval: string | null): Promise<any> { | ||||||
|     try { |     try { | ||||||
|       let query = `SELECT
 |       let query = `SELECT
 | ||||||
|         CAST(AVG(height) as INT) as avgHeight, |         CAST(AVG(height) as INT) as avgHeight, | ||||||
| @ -777,7 +777,7 @@ class BlocksRepository { | |||||||
|   /** |   /** | ||||||
|    * Get the historical averaged block weights |    * Get the historical averaged block weights | ||||||
|    */ |    */ | ||||||
|    public async $getHistoricalBlockWeights(div: number, interval: string | null): Promise<any> { |   public async $getHistoricalBlockWeights(div: number, interval: string | null): Promise<any> { | ||||||
|     try { |     try { | ||||||
|       let query = `SELECT
 |       let query = `SELECT
 | ||||||
|         CAST(AVG(height) as INT) as avgHeight, |         CAST(AVG(height) as INT) as avgHeight, | ||||||
| @ -815,7 +815,7 @@ class BlocksRepository { | |||||||
|   /** |   /** | ||||||
|    * Get a list of blocks that have not had CPFP data indexed |    * Get a list of blocks that have not had CPFP data indexed | ||||||
|    */ |    */ | ||||||
|    public async $getCPFPUnindexedBlocks(): Promise<any[]> { |   public async $getCPFPUnindexedBlocks(): Promise<any[]> { | ||||||
|     try { |     try { | ||||||
|       const blockchainInfo = await bitcoinClient.getBlockchainInfo(); |       const blockchainInfo = await bitcoinClient.getBlockchainInfo(); | ||||||
|       const currentBlockHeight = blockchainInfo.blocks; |       const currentBlockHeight = blockchainInfo.blocks; | ||||||
| @ -885,7 +885,7 @@ class BlocksRepository { | |||||||
|   /** |   /** | ||||||
|    * Save block price by batch |    * Save block price by batch | ||||||
|    */ |    */ | ||||||
|    public async $saveBlockPrices(blockPrices: BlockPrice[]): Promise<void> { |   public async $saveBlockPrices(blockPrices: BlockPrice[]): Promise<void> { | ||||||
|     try { |     try { | ||||||
|       let query = `INSERT INTO blocks_prices(height, price_id) VALUES`; |       let query = `INSERT INTO blocks_prices(height, price_id) VALUES`; | ||||||
|       for (const price of blockPrices) { |       for (const price of blockPrices) { | ||||||
| @ -1061,6 +1061,57 @@ class BlocksRepository { | |||||||
|     blk.extras = <BlockExtension>extras; |     blk.extras = <BlockExtension>extras; | ||||||
|     return <BlockExtended>blk; |     return <BlockExtended>blk; | ||||||
|   } |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Count how many blocks are indexed | ||||||
|  |    */ | ||||||
|  |   public async $getIndexedBlockCount(): Promise<number> { | ||||||
|  |     try { | ||||||
|  |       const [res]: any[] = await DB.query(`SELECT COUNT(hash) as count FROM blocks`); | ||||||
|  |       if (!res || !res.length) { | ||||||
|  |         logger.err(`Unable to count indexed blocks in our db`); | ||||||
|  |         return -1; | ||||||
|  |       } | ||||||
|  |       return res[0].count; | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.err(`Unable to count indexed blocks in our db. Exception: ${JSON.stringify(e)}`); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Count how many blocks are indexed with CPFP data | ||||||
|  |    */ | ||||||
|  |   public async $getIndexedCpfpBlockCount(): Promise<number> { | ||||||
|  |     try { | ||||||
|  |       const [res]: any[] = await DB.query(`SELECT COUNT(DISTINCT height) as count FROM compact_cpfp_clusters`); | ||||||
|  |       if (!res || !res.length) { | ||||||
|  |         logger.err(`Unable to count indexed blocks with CPFP data in our db`); | ||||||
|  |         return -1; | ||||||
|  |       } | ||||||
|  |       return res[0].count; | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.err(`Unable to count indexed blocks with CPFP data in our db. Exception: ${JSON.stringify(e)}`); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |   } | ||||||
|  | 
 | ||||||
|  |   /** | ||||||
|  |    * Count how many blocks are indexed with coin stats data | ||||||
|  |    */ | ||||||
|  |   public async $getIndexedCoinStatsBlockCount(): Promise<number> { | ||||||
|  |     try { | ||||||
|  |       const [res]: any[] = await DB.query(`SELECT COUNT(hash) as count FROM blocks WHERE utxoset_size IS NOT NULL && total_input_amt IS NOT NULL`); | ||||||
|  |       if (!res || !res.length) { | ||||||
|  |         logger.err(`Unable to count indexed blocks with coin stats data in our db`); | ||||||
|  |         return -1; | ||||||
|  |       } | ||||||
|  |       return res[0].count; | ||||||
|  |     } catch (e) { | ||||||
|  |       logger.err(`Unable to count indexed blocks with coin stats data in our db. Exception: ${JSON.stringify(e)}`); | ||||||
|  |       return -1; | ||||||
|  |     } | ||||||
|  |   } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| export default new BlocksRepository(); | export default new BlocksRepository(); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user