[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 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 {
|
||||
|
@ -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();
|
||||
|
Loading…
x
Reference in New Issue
Block a user