Small improvements on the mining page UX
- INDEXING_BLOCKS_AMOUNT = 0 disable indexing, INDEXING_BLOCKS_AMOUNT = -1 indexes everything - Show only available timespan in the mining page according to available datas - Change default INDEXING_BLOCKS_AMOUNT to 1100 Don't use unfiltered mysql user input Enable http cache header for mining pools (1 min)
This commit is contained in:
@@ -114,7 +114,7 @@ class Blocks {
|
||||
* @returns
|
||||
*/
|
||||
private async $findBlockMiner(txMinerInfo: TransactionMinerInfo | undefined): Promise<PoolTag> {
|
||||
if (txMinerInfo === undefined) {
|
||||
if (txMinerInfo === undefined || txMinerInfo.vout.length < 1) {
|
||||
return await poolsRepository.$getUnknownPool();
|
||||
}
|
||||
|
||||
@@ -147,9 +147,9 @@ class Blocks {
|
||||
*/
|
||||
public async $generateBlockDatabase() {
|
||||
if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false || // Bitcoin only
|
||||
config.MEMPOOL.INDEXING_BLOCKS_AMOUNT <= 0 || // Indexing must be enabled
|
||||
this.blockIndexingStarted === true || // Indexing must not already be in progress
|
||||
!memPool.isInSync() // We sync the mempool first
|
||||
config.MEMPOOL.INDEXING_BLOCKS_AMOUNT === 0 || // Indexing must be enabled
|
||||
!memPool.isInSync() || // We sync the mempool first
|
||||
this.blockIndexingStarted === true // Indexing must not already be in progress
|
||||
) {
|
||||
return;
|
||||
}
|
||||
@@ -163,7 +163,13 @@ class Blocks {
|
||||
|
||||
try {
|
||||
let currentBlockHeight = blockchainInfo.blocks;
|
||||
const lastBlockToIndex = Math.max(0, currentBlockHeight - config.MEMPOOL.INDEXING_BLOCKS_AMOUNT + 1);
|
||||
|
||||
let indexingBlockAmount = config.MEMPOOL.INDEXING_BLOCKS_AMOUNT;
|
||||
if (indexingBlockAmount <= -1) {
|
||||
indexingBlockAmount = currentBlockHeight + 1;
|
||||
}
|
||||
|
||||
const lastBlockToIndex = Math.max(0, currentBlockHeight - indexingBlockAmount + 1);
|
||||
|
||||
logger.info(`Indexing blocks from #${currentBlockHeight} to #${lastBlockToIndex}`);
|
||||
|
||||
|
||||
@@ -118,11 +118,11 @@ class Mempool {
|
||||
});
|
||||
}
|
||||
hasChange = true;
|
||||
// if (diff > 0) {
|
||||
// logger.debug('Fetched transaction ' + txCount + ' / ' + diff);
|
||||
// } else {
|
||||
// logger.debug('Fetched transaction ' + txCount);
|
||||
// }
|
||||
if (diff > 0) {
|
||||
logger.debug('Fetched transaction ' + txCount + ' / ' + diff);
|
||||
} else {
|
||||
logger.debug('Fetched transaction ' + txCount);
|
||||
}
|
||||
newTransactions.push(transaction);
|
||||
} catch (e) {
|
||||
logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e));
|
||||
|
||||
@@ -2,7 +2,6 @@ import { PoolInfo, PoolStats } from '../mempool.interfaces';
|
||||
import BlocksRepository, { EmptyBlocks } from '../repositories/BlocksRepository';
|
||||
import PoolsRepository from '../repositories/PoolsRepository';
|
||||
import bitcoinClient from './bitcoin/bitcoin-client';
|
||||
import BitcoinApi from './bitcoin/bitcoin-api';
|
||||
|
||||
class Mining {
|
||||
constructor() {
|
||||
@@ -11,14 +10,25 @@ class Mining {
|
||||
/**
|
||||
* Generate high level overview of the pool ranks and general stats
|
||||
*/
|
||||
public async $getPoolsStats(interval: string = '100 YEAR') : Promise<object> {
|
||||
public async $getPoolsStats(interval: string | null) : Promise<object> {
|
||||
let sqlInterval: string | null = null;
|
||||
switch (interval) {
|
||||
case '24h': sqlInterval = '1 DAY'; break;
|
||||
case '3d': sqlInterval = '3 DAY'; break;
|
||||
case '1w': sqlInterval = '1 WEEK'; break;
|
||||
case '1m': sqlInterval = '1 MONTH'; break;
|
||||
case '3m': sqlInterval = '3 MONTH'; break;
|
||||
case '6m': sqlInterval = '6 MONTH'; break;
|
||||
case '1y': sqlInterval = '1 YEAR'; break;
|
||||
case '2y': sqlInterval = '2 YEAR'; break;
|
||||
case '3y': sqlInterval = '3 YEAR'; break;
|
||||
default: sqlInterval = null; break;
|
||||
}
|
||||
|
||||
const poolsStatistics = {};
|
||||
|
||||
const blockHeightTip = await bitcoinClient.getBlockCount();
|
||||
const lastBlockHashrate = await bitcoinClient.getNetworkHashPs(120, blockHeightTip);
|
||||
const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(interval);
|
||||
const blockCount: number = await BlocksRepository.$blockCount(interval);
|
||||
const emptyBlocks: EmptyBlocks[] = await BlocksRepository.$countEmptyBlocks(interval);
|
||||
const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(sqlInterval);
|
||||
const emptyBlocks: EmptyBlocks[] = await BlocksRepository.$countEmptyBlocks(sqlInterval);
|
||||
|
||||
const poolsStats: PoolStats[] = [];
|
||||
let rank = 1;
|
||||
@@ -40,12 +50,20 @@ class Mining {
|
||||
poolsStats.push(poolStat);
|
||||
});
|
||||
|
||||
poolsStatistics['blockCount'] = blockCount;
|
||||
poolsStatistics['lastEstimatedHashrate'] = lastBlockHashrate;
|
||||
poolsStatistics['pools'] = poolsStats;
|
||||
|
||||
const oldestBlock = new Date(await BlocksRepository.$oldestBlockTimestamp());
|
||||
poolsStatistics['oldestIndexedBlockTimestamp'] = oldestBlock.getTime();
|
||||
|
||||
const blockCount: number = await BlocksRepository.$blockCount(sqlInterval);
|
||||
poolsStatistics['blockCount'] = blockCount;
|
||||
|
||||
const blockHeightTip = await bitcoinClient.getBlockCount();
|
||||
const lastBlockHashrate = await bitcoinClient.getNetworkHashPs(120, blockHeightTip);
|
||||
poolsStatistics['lastEstimatedHashrate'] = lastBlockHashrate;
|
||||
|
||||
return poolsStatistics;
|
||||
}
|
||||
}
|
||||
|
||||
export default new Mining();
|
||||
export default new Mining();
|
||||
|
||||
@@ -78,7 +78,7 @@ const defaults: IConfig = {
|
||||
'BLOCK_WEIGHT_UNITS': 4000000,
|
||||
'INITIAL_BLOCKS_AMOUNT': 8,
|
||||
'MEMPOOL_BLOCKS_AMOUNT': 8,
|
||||
'INDEXING_BLOCKS_AMOUNT': 432, // ~3 days at 10 minutes / block. Set to 0 to disable indexing
|
||||
'INDEXING_BLOCKS_AMOUNT': 1100, // 0 = disable indexing, -1 = index all blocks
|
||||
'PRICE_FEED_UPDATE_INTERVAL': 3600,
|
||||
'USE_SECOND_NODE_FOR_MINFEE': false,
|
||||
'EXTERNAL_ASSETS': [
|
||||
|
||||
@@ -255,7 +255,7 @@ class Server {
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1y', routes.$getStatisticsByTime.bind(routes, '1y'))
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2y', routes.$getStatisticsByTime.bind(routes, '2y'))
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3y', routes.$getStatisticsByTime.bind(routes, '3y'))
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'pools', routes.$getPools)
|
||||
.get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools', routes.$getPools)
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
@@ -72,14 +72,16 @@ class BlocksRepository {
|
||||
/**
|
||||
* Count empty blocks for all pools
|
||||
*/
|
||||
public async $countEmptyBlocks(interval: string = '100 YEAR'): Promise<EmptyBlocks[]> {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const [rows] = await connection.query(`
|
||||
public async $countEmptyBlocks(interval: string | null): Promise<EmptyBlocks[]> {
|
||||
const query = `
|
||||
SELECT pool_id as poolId
|
||||
FROM blocks
|
||||
WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()
|
||||
AND tx_count = 1;
|
||||
`);
|
||||
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);
|
||||
connection.release();
|
||||
|
||||
return <EmptyBlocks[]>rows;
|
||||
@@ -88,17 +90,39 @@ class BlocksRepository {
|
||||
/**
|
||||
* Get blocks count for a period
|
||||
*/
|
||||
public async $blockCount(interval: string = '100 YEAR'): Promise<number> {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const [rows] = await connection.query(`
|
||||
public async $blockCount(interval: string | null): Promise<number> {
|
||||
const query = `
|
||||
SELECT count(height) as blockCount
|
||||
FROM blocks
|
||||
WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW();
|
||||
`);
|
||||
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
|
||||
FROM blocks
|
||||
ORDER BY height
|
||||
LIMIT 1;
|
||||
`);
|
||||
connection.release();
|
||||
|
||||
if (rows.length <= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
return <number>rows[0].blockTimestamp;
|
||||
}
|
||||
}
|
||||
|
||||
export default new BlocksRepository();
|
||||
@@ -25,17 +25,20 @@ class PoolsRepository {
|
||||
/**
|
||||
* Get basic pool info and block count
|
||||
*/
|
||||
public async $getPoolsInfo(interval: string = '100 YEARS'): Promise<PoolInfo[]> {
|
||||
const connection = await DB.pool.getConnection();
|
||||
const [rows] = await connection.query(`
|
||||
public async $getPoolsInfo(interval: string | null): Promise<PoolInfo[]> {
|
||||
const query = `
|
||||
SELECT COUNT(height) as blockCount, pool_id as poolId, pools.name as name, pools.link as link
|
||||
FROM blocks
|
||||
JOIN pools on pools.id = pool_id
|
||||
WHERE blocks.blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()
|
||||
GROUP BY pool_id
|
||||
ORDER BY COUNT(height) DESC;
|
||||
`);
|
||||
JOIN pools on pools.id = pool_id` +
|
||||
(interval != null ? ` WHERE blocks.blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()` : ``) +
|
||||
` GROUP BY pool_id
|
||||
ORDER BY COUNT(height) DESC
|
||||
`;
|
||||
|
||||
const connection = await DB.pool.getConnection();
|
||||
const [rows] = await connection.query(query);
|
||||
connection.release();
|
||||
|
||||
return <PoolInfo[]>rows;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -535,9 +535,9 @@ class Routes {
|
||||
public async $getPools(req: Request, res: Response) {
|
||||
try {
|
||||
let stats = await miningStats.$getPoolsStats(req.query.interval as string);
|
||||
// res.header('Pragma', 'public');
|
||||
// res.header('Cache-control', 'public');
|
||||
// res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString());
|
||||
res.header('Pragma', 'public');
|
||||
res.header('Cache-control', 'public');
|
||||
res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString());
|
||||
res.json(stats);
|
||||
} catch (e) {
|
||||
res.status(500).send(e instanceof Error ? e.message : e);
|
||||
|
||||
Reference in New Issue
Block a user