2022-01-18 09:37:04 +01:00
|
|
|
import { BlockExtended, PoolTag } from '../mempool.interfaces';
|
|
|
|
import { DB } from '../database';
|
|
|
|
import logger from '../logger';
|
2022-01-06 11:59:33 +01:00
|
|
|
|
|
|
|
export interface EmptyBlocks {
|
2022-01-18 09:37:04 +01:00
|
|
|
emptyBlocks: number;
|
|
|
|
poolId: number;
|
2022-01-06 11:59:33 +01:00
|
|
|
}
|
2022-01-05 07:41:14 +01:00
|
|
|
|
|
|
|
class BlocksRepository {
|
|
|
|
/**
|
|
|
|
* Save indexed block data in the database
|
|
|
|
*/
|
|
|
|
public async $saveBlockInDatabase(
|
|
|
|
block: BlockExtended,
|
|
|
|
blockHash: string,
|
|
|
|
coinbaseHex: string | undefined,
|
|
|
|
poolTag: PoolTag
|
|
|
|
) {
|
|
|
|
const connection = await DB.pool.getConnection();
|
|
|
|
|
|
|
|
try {
|
|
|
|
const query = `INSERT INTO blocks(
|
2022-01-18 09:37:04 +01:00
|
|
|
height, hash, blockTimestamp, size,
|
|
|
|
weight, tx_count, coinbase_raw, difficulty,
|
|
|
|
pool_id, fees, fee_span, median_fee
|
2022-01-05 07:41:14 +01:00
|
|
|
) VALUE (
|
2022-01-06 11:59:33 +01:00
|
|
|
?, ?, FROM_UNIXTIME(?), ?,
|
2022-01-05 07:41:14 +01:00
|
|
|
?, ?, ?, ?,
|
|
|
|
?, ?, ?, ?
|
|
|
|
)`;
|
|
|
|
|
|
|
|
const params: any[] = [
|
2022-02-04 04:51:45 +01:00
|
|
|
block.height,
|
|
|
|
blockHash,
|
|
|
|
block.timestamp,
|
|
|
|
block.size,
|
|
|
|
block.weight,
|
|
|
|
block.tx_count,
|
|
|
|
coinbaseHex ? coinbaseHex : '',
|
|
|
|
block.difficulty,
|
|
|
|
poolTag.id,
|
|
|
|
0,
|
|
|
|
'[]',
|
2022-02-04 11:28:00 +01:00
|
|
|
block.extras ? block.extras.medianFee : 0,
|
2022-01-05 07:41:14 +01:00
|
|
|
];
|
|
|
|
|
|
|
|
await connection.query(query, params);
|
|
|
|
} catch (e) {
|
2022-01-20 09:20:02 +01:00
|
|
|
logger.err('$saveBlockInDatabase() error' + (e instanceof Error ? e.message : e));
|
2022-01-05 07:41:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
connection.release();
|
|
|
|
}
|
|
|
|
|
2022-01-18 09:37:04 +01:00
|
|
|
/**
|
|
|
|
* Get all block height that have not been indexed between [startHeight, endHeight]
|
|
|
|
*/
|
|
|
|
public async $getMissingBlocksBetweenHeights(startHeight: number, endHeight: number): Promise<number[]> {
|
2022-01-24 09:43:11 +01:00
|
|
|
if (startHeight < endHeight) {
|
|
|
|
return [];
|
|
|
|
}
|
|
|
|
|
2022-01-18 09:37:04 +01:00
|
|
|
const connection = await DB.pool.getConnection();
|
|
|
|
const [rows] : any[] = await connection.query(`
|
|
|
|
SELECT height
|
|
|
|
FROM blocks
|
|
|
|
WHERE height <= ${startHeight} AND height >= ${endHeight}
|
|
|
|
ORDER BY height DESC;
|
|
|
|
`);
|
|
|
|
connection.release();
|
|
|
|
|
|
|
|
const indexedBlockHeights: number[] = [];
|
|
|
|
rows.forEach((row: any) => { indexedBlockHeights.push(row.height); });
|
|
|
|
const seekedBlocks: number[] = Array.from(Array(startHeight - endHeight + 1).keys(), n => n + endHeight).reverse();
|
|
|
|
const missingBlocksHeights = seekedBlocks.filter(x => indexedBlockHeights.indexOf(x) === -1);
|
|
|
|
|
|
|
|
return missingBlocksHeights;
|
|
|
|
}
|
|
|
|
|
2022-01-06 11:59:33 +01:00
|
|
|
/**
|
|
|
|
* Count empty blocks for all pools
|
|
|
|
*/
|
2022-01-25 10:33:46 +01:00
|
|
|
public async $countEmptyBlocks(interval: string | null): Promise<EmptyBlocks[]> {
|
|
|
|
const query = `
|
2022-01-06 11:59:33 +01:00
|
|
|
SELECT pool_id as poolId
|
|
|
|
FROM blocks
|
2022-01-25 10:33:46 +01:00
|
|
|
WHERE tx_count = 1` +
|
|
|
|
(interval != null ? ` AND blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()` : ``)
|
|
|
|
;
|
|
|
|
|
|
|
|
const connection = await DB.pool.getConnection();
|
|
|
|
const [rows] = await connection.query(query);
|
2022-01-06 11:59:33 +01:00
|
|
|
connection.release();
|
|
|
|
|
|
|
|
return <EmptyBlocks[]>rows;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get blocks count for a period
|
|
|
|
*/
|
2022-01-25 10:33:46 +01:00
|
|
|
public async $blockCount(interval: string | null): Promise<number> {
|
|
|
|
const query = `
|
2022-01-06 11:59:33 +01:00
|
|
|
SELECT count(height) as blockCount
|
2022-01-25 10:33:46 +01:00
|
|
|
FROM blocks` +
|
|
|
|
(interval != null ? ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()` : ``)
|
|
|
|
;
|
|
|
|
|
|
|
|
const connection = await DB.pool.getConnection();
|
|
|
|
const [rows] = await connection.query(query);
|
|
|
|
connection.release();
|
|
|
|
|
|
|
|
return <number>rows[0].blockCount;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the oldest indexed block
|
|
|
|
*/
|
|
|
|
public async $oldestBlockTimestamp(): Promise<number> {
|
|
|
|
const connection = await DB.pool.getConnection();
|
|
|
|
const [rows]: any[] = await connection.query(`
|
|
|
|
SELECT blockTimestamp
|
2022-01-06 11:59:33 +01:00
|
|
|
FROM blocks
|
2022-01-25 10:33:46 +01:00
|
|
|
ORDER BY height
|
|
|
|
LIMIT 1;
|
2022-01-06 11:59:33 +01:00
|
|
|
`);
|
|
|
|
connection.release();
|
|
|
|
|
2022-01-25 10:33:46 +01:00
|
|
|
if (rows.length <= 0) {
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
return <number>rows[0].blockTimestamp;
|
2022-01-06 11:59:33 +01:00
|
|
|
}
|
2022-01-05 07:41:14 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
export default new BlocksRepository();
|