diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts index d3fadbcce..ebf8fd40d 100644 --- a/backend/src/api/mining/mining.ts +++ b/backend/src/api/mining/mining.ts @@ -114,31 +114,29 @@ class Mining { const poolsStatistics = {}; const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(interval); - const emptyBlocks: any[] = await BlocksRepository.$countEmptyBlocks(null, interval); const poolsStats: PoolStats[] = []; let rank = 1; + let blockCount = 0; poolsInfo.forEach((poolInfo: PoolInfo) => { - const emptyBlocksCount = emptyBlocks.filter((emptyCount) => emptyCount.poolId === poolInfo.poolId); const poolStat: PoolStats = { poolId: poolInfo.poolId, // mysql row id name: poolInfo.name, link: poolInfo.link, blockCount: poolInfo.blockCount, rank: rank++, - emptyBlocks: emptyBlocksCount.length > 0 ? emptyBlocksCount[0]['count'] : 0, + emptyBlocks: poolInfo.emptyBlocks, slug: poolInfo.slug, avgMatchRate: poolInfo.avgMatchRate !== null ? Math.round(100 * poolInfo.avgMatchRate) / 100 : null, avgFeeDelta: poolInfo.avgFeeDelta, poolUniqueId: poolInfo.poolUniqueId }; poolsStats.push(poolStat); + blockCount += poolInfo.blockCount; }); poolsStatistics['pools'] = poolsStats; - - const blockCount: number = await BlocksRepository.$blockCount(null, interval); poolsStatistics['blockCount'] = blockCount; const totalBlock24h: number = await BlocksRepository.$blockCount(null, '24h'); @@ -151,6 +149,8 @@ class Mining { poolsStatistics['lastEstimatedHashrate1w'] = await bitcoinClient.getNetworkHashPs(totalBlock1w); } catch (e) { poolsStatistics['lastEstimatedHashrate'] = 0; + poolsStatistics['lastEstimatedHashrate3d'] = 0; + poolsStatistics['lastEstimatedHashrate1w'] = 0; logger.debug('Bitcoin Core is not available, using zeroed value for current hashrate', logger.tags.mining); } diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts index 24e01d4dd..3f1403518 100644 --- a/backend/src/mempool.interfaces.ts +++ b/backend/src/mempool.interfaces.ts @@ -17,6 +17,7 @@ export interface PoolInfo { name: string; link: string; blockCount: number; + emptyBlocks: number; slug: string; avgMatchRate: number | null; avgFeeDelta: number | null; @@ -25,7 +26,6 @@ export interface PoolInfo { export interface PoolStats extends PoolInfo { rank: number; - emptyBlocks: number; } export enum TemplateAlgorithm { diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts index faa8fce74..20d0a6e46 100644 --- a/backend/src/repositories/BlocksRepository.ts +++ b/backend/src/repositories/BlocksRepository.ts @@ -305,39 +305,6 @@ class BlocksRepository { } } - /** - * Get empty blocks for one or all pools - * @asyncSafe - */ - public async $countEmptyBlocks(poolId: number | null, interval: string | null = null): Promise { - interval = Common.getSqlInterval(interval); - - const params: any[] = []; - let query = `SELECT count(height) as count, pools.id as poolId - FROM blocks - JOIN pools on pools.id = blocks.pool_id - WHERE tx_count = 1 AND stale = 0`; - - if (poolId) { - query += ` AND pool_id = ?`; - params.push(poolId); - } - - if (interval) { - query += ` AND blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; - } - - query += ` GROUP by pools.id`; - - try { - const [rows] = await DB.query(query, params); - return rows; - } catch (e) { - logger.err('Cannot count empty blocks. Reason: ' + (e instanceof Error ? e.message : e)); - throw e; - } - } - /** * Return most recent block height * @asyncSafe @@ -360,17 +327,26 @@ class BlocksRepository { interval = Common.getSqlInterval(interval); const params: any[] = []; - let query = `SELECT count(height) as blockCount - FROM blocks - WHERE stale = 0`; - - if (poolId) { - query += ` AND pool_id = ?`; + let query; + if (!poolId && !interval) { + // optimized query to get full indexed block count + query = `SELECT CAST(COALESCE(MAX(height) - MIN(height) + 1, 0) AS SIGNED) as blockCount FROM blocks`; + } else if (!poolId) { + // optimized query for indexed count within an interval + query = `SELECT GREATEST(0, COALESCE( + CAST((SELECT height FROM blocks WHERE stale = 0 AND blockTimestamp <= NOW() ORDER BY blockTimestamp DESC LIMIT 1) AS SIGNED) - + CAST((SELECT height FROM blocks WHERE stale = 0 AND blockTimestamp >= DATE_SUB(NOW(), INTERVAL ${interval}) ORDER BY blockTimestamp ASC LIMIT 1) AS SIGNED) + 1 + , 0)) as blockCount`; + } else { + // for specific pools, we do still have to actually count the blocks + query = `SELECT count(*) as blockCount + FROM blocks + WHERE stale = 0 AND pool_id = ?`; params.push(poolId); - } - if (interval) { - query += ` AND blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + if (interval) { + query += ` AND blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } } try { diff --git a/backend/src/repositories/PoolsRepository.ts b/backend/src/repositories/PoolsRepository.ts index fcc218f7b..4fc3742fd 100644 --- a/backend/src/repositories/PoolsRepository.ts +++ b/backend/src/repositories/PoolsRepository.ts @@ -38,6 +38,7 @@ class PoolsRepository { let query = ` SELECT COUNT(blocks.height) As blockCount, + COUNT(CASE WHEN blocks.tx_count = 1 THEN 1 END) AS emptyBlocks, pool_id AS poolId, pools.name AS name, pools.link AS link, @@ -47,7 +48,7 @@ class PoolsRepository { unique_id as poolUniqueId FROM blocks JOIN pools on pools.id = pool_id - LEFT JOIN blocks_audits ON blocks_audits.height = blocks.height + LEFT JOIN blocks_audits ON blocks_audits.hash = blocks.hash WHERE blocks.stale = 0 `;