[nodejs backend] added /api/v1/health

This commit is contained in:
nymkappa 2023-09-26 16:36:29 +02:00
parent 5e95d8d6ce
commit 8a51f32e63
No known key found for this signature in database
GPG Key ID: E155910B16E8BD04
2 changed files with 104 additions and 7 deletions

View File

@ -6,7 +6,7 @@ import websocketHandler from '../websocket-handler';
import mempool from '../mempool';
import feeApi from '../fee-api';
import mempoolBlocks from '../mempool-blocks';
import bitcoinApi from './bitcoin-api-factory';
import bitcoinApi, { bitcoinCoreApi } from './bitcoin-api-factory';
import { Common } from '../common';
import backendInfo from '../backend-info';
import transactionUtils from '../transaction-utils';
@ -19,6 +19,7 @@ import bitcoinClient from './bitcoin-client';
import difficultyAdjustment from '../difficulty-adjustment';
import transactionRepository from '../../repositories/TransactionRepository';
import rbfCache from '../rbf-cache';
import BlocksRepository from '../../repositories/BlocksRepository';
class BitcoinRoutes {
public initRoutes(app: Application) {
@ -126,8 +127,53 @@ class BitcoinRoutes {
.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) {
try {

View File

@ -385,7 +385,7 @@ class BlocksRepository {
/**
* 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[] = [];
let query = `SELECT count(height) as blockCount
FROM blocks
@ -721,7 +721,7 @@ class BlocksRepository {
/**
* 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 {
let query = `SELECT
CAST(AVG(height) as INT) as avgHeight,
@ -752,7 +752,7 @@ class BlocksRepository {
/**
* 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 {
let query = `SELECT
CAST(AVG(height) as INT) as avgHeight,
@ -777,7 +777,7 @@ class BlocksRepository {
/**
* 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 {
let query = `SELECT
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
*/
public async $getCPFPUnindexedBlocks(): Promise<any[]> {
public async $getCPFPUnindexedBlocks(): Promise<any[]> {
try {
const blockchainInfo = await bitcoinClient.getBlockchainInfo();
const currentBlockHeight = blockchainInfo.blocks;
@ -885,7 +885,7 @@ class BlocksRepository {
/**
* Save block price by batch
*/
public async $saveBlockPrices(blockPrices: BlockPrice[]): Promise<void> {
public async $saveBlockPrices(blockPrices: BlockPrice[]): Promise<void> {
try {
let query = `INSERT INTO blocks_prices(height, price_id) VALUES`;
for (const price of blockPrices) {
@ -1061,6 +1061,57 @@ class BlocksRepository {
blk.extras = <BlockExtension>extras;
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();