2022-04-13 17:38:42 +04:00
import DB from '../database' ;
2022-01-19 18:50:52 +09:00
import logger from '../logger' ;
2022-01-20 22:59:10 +09:00
import config from '../config' ;
2023-01-02 13:25:40 +01:00
import PoolsRepository from '../repositories/PoolsRepository' ;
import { PoolTag } from '../mempool.interfaces' ;
2022-01-19 18:50:52 +09:00
class PoolsParser {
2022-06-07 11:28:39 +02:00
miningPools : any [ ] = [ ] ;
unknownPool : any = {
2022-11-09 06:43:46 +01:00
'name' : 'Unknown' ,
'link' : 'https://learnmeabitcoin.com/technical/coinbase-transaction' ,
'regexes' : '[]' ,
'addresses' : '[]' ,
2022-06-07 11:28:39 +02:00
'slug' : 'unknown'
} ;
2023-02-24 21:35:13 +09:00
private uniqueLogs : string [ ] = [ ] ;
private uniqueLog ( loggerFunction : any , msg : string ) : void {
if ( this . uniqueLogs . includes ( msg ) ) {
return ;
}
this . uniqueLogs . push ( msg ) ;
loggerFunction ( msg ) ;
}
2023-01-02 13:25:40 +01:00
public setMiningPools ( pools ) : void {
2023-02-24 21:35:13 +09:00
for ( const pool of pools ) {
pool . regexes = pool . tags ;
delete ( pool . tags ) ;
2023-02-16 09:09:14 +09:00
}
2023-02-24 21:35:13 +09:00
this . miningPools = pools ;
2023-01-02 13:25:40 +01:00
}
2022-03-25 12:31:09 +09:00
2022-01-19 18:50:52 +09:00
/ * *
2023-01-02 13:25:40 +01:00
* Populate our db with updated mining pool definition
* @param pools
2022-01-19 18:50:52 +09:00
* /
2023-02-24 21:35:13 +09:00
public async migratePoolsJson ( ) : Promise < void > {
2023-01-02 13:25:40 +01:00
await this . $insertUnknownPool ( ) ;
2022-01-19 18:50:52 +09:00
2023-02-24 21:35:13 +09:00
for ( const pool of this . miningPools ) {
2023-01-02 13:25:40 +01:00
if ( ! pool . id ) {
logger . info ( ` Mining pool ${ pool . name } has no unique 'id' defined. Skipping. ` ) ;
continue ;
2022-01-19 18:50:52 +09:00
}
2022-01-20 22:59:10 +09:00
2023-01-02 13:25:40 +01:00
const poolDB = await PoolsRepository . $getPoolByUniqueId ( pool . id , false ) ;
if ( ! poolDB ) {
// New mining pool
const slug = pool . name . replace ( /[^a-z0-9]/gi , '' ) . toLowerCase ( ) ;
logger . debug ( ` Inserting new mining pool ${ pool . name } ` ) ;
await PoolsRepository . $insertNewMiningPool ( pool , slug ) ;
2023-02-12 22:44:04 +09:00
await this . $deleteUnknownBlocks ( ) ;
2022-06-07 11:28:39 +02:00
} else {
2023-01-02 13:25:40 +01:00
if ( poolDB . name !== pool . name ) {
// Pool has been renamed
const newSlug = pool . name . replace ( /[^a-z0-9]/gi , '' ) . toLowerCase ( ) ;
logger . warn ( ` Renaming ${ poolDB . name } mining pool to ${ pool . name } . Slug has been updated. Maybe you want to make a redirection from 'https://mempool.space/mining/pool/ ${ poolDB . slug } ' to 'https://mempool.space/mining/pool/ ${ newSlug } ` ) ;
await PoolsRepository . $renameMiningPool ( poolDB . id , newSlug , pool . name ) ;
2022-03-25 12:31:09 +09:00
}
2023-01-02 13:25:40 +01:00
if ( poolDB . link !== pool . link ) {
// Pool link has changed
logger . debug ( ` Updating link for ${ pool . name } mining pool ` ) ;
await PoolsRepository . $updateMiningPoolLink ( poolDB . id , pool . link ) ;
2022-07-07 13:41:09 +02:00
}
2023-01-02 13:25:40 +01:00
if ( JSON . stringify ( pool . addresses ) !== poolDB . addresses ||
2023-02-24 21:35:13 +09:00
JSON . stringify ( pool . regexes ) !== poolDB . regexes ) {
2023-01-02 13:25:40 +01:00
// Pool addresses changed or coinbase tags changed
logger . notice ( ` Updating addresses and/or coinbase tags for ${ pool . name } mining pool. If 'AUTOMATIC_BLOCK_REINDEXING' is enabled, we will re-index its blocks and 'unknown' blocks ` ) ;
2023-02-24 21:35:13 +09:00
await PoolsRepository . $updateMiningPoolTags ( poolDB . id , pool . addresses , pool . regexes ) ;
2023-01-02 13:25:40 +01:00
await this . $deleteBlocksForPool ( poolDB ) ;
2022-11-09 06:43:46 +01:00
}
2022-01-20 13:53:08 +09:00
}
2022-06-07 11:28:39 +02:00
}
2023-01-02 13:25:40 +01:00
logger . info ( 'Mining pools.json import completed' ) ;
2022-01-19 18:50:52 +09:00
}
2022-01-20 22:59:10 +09:00
/ * *
* Manually add the 'unknown pool'
* /
2023-01-02 13:25:40 +01:00
public async $insertUnknownPool ( ) : Promise < void > {
if ( ! config . DATABASE . ENABLED ) {
return ;
}
2022-01-20 22:59:10 +09:00
try {
2022-04-12 15:15:57 +09:00
const [ rows ] : any [ ] = await DB . query ( { sql : 'SELECT name from pools where name="Unknown"' , timeout : 120000 } ) ;
2022-01-20 22:59:10 +09:00
if ( rows . length === 0 ) {
2022-04-12 15:15:57 +09:00
await DB . query ( {
2023-01-02 13:25:40 +01:00
sql : ` INSERT INTO pools(name, link, regexes, addresses, slug, unique_id)
VALUES ( "${this.unknownPool.name}" , "${this.unknownPool.link}" , "[]" , "[]" , "${this.unknownPool.slug}" , 0 ) ;
2022-01-20 22:59:10 +09:00
` });
2022-03-24 19:44:22 +09:00
} else {
2022-04-12 15:15:57 +09:00
await DB . query ( ` UPDATE pools
2023-01-02 13:25:40 +01:00
SET name = '${this.unknownPool.name}' , link = '${this.unknownPool.link}' ,
2022-03-24 19:44:22 +09:00
regexes = '[]' , addresses = '[]' ,
2023-01-02 13:25:40 +01:00
slug = '${this.unknownPool.slug}' ,
unique_id = 0
WHERE slug = '${this.unknownPool.slug}'
2022-03-29 14:37:17 +09:00
` );
2022-01-20 22:59:10 +09:00
}
} catch ( e ) {
2023-01-02 13:25:40 +01:00
logger . err ( ` Unable to insert or update "Unknown" mining pool. Reason: ${ e instanceof Error ? e.message : e } ` ) ;
2022-01-20 22:59:10 +09:00
}
}
2022-07-07 13:41:09 +02:00
/ * *
2023-01-02 13:25:40 +01:00
* Delete indexed blocks for an updated mining pool
*
* @param pool
2022-07-07 13:41:09 +02:00
* /
2023-01-02 13:25:40 +01:00
private async $deleteBlocksForPool ( pool : PoolTag ) : Promise < void > {
2022-07-09 19:04:35 +02:00
if ( config . MEMPOOL . AUTOMATIC_BLOCK_REINDEXING === false ) {
return ;
}
2023-01-02 13:25:40 +01:00
// Get oldest blocks mined by the pool and assume pools.json updates only concern most recent years
// Ignore early days of Bitcoin as there were no mining pool yet
const [ oldestPoolBlock ] : any [ ] = await DB . query ( `
SELECT height
FROM blocks
WHERE pool_id = ?
ORDER BY height
LIMIT 1 ` ,
[ pool . id ]
) ;
const oldestBlockHeight = oldestPoolBlock . length ? ? 0 > 0 ? oldestPoolBlock [ 0 ] . height : 130635 ;
2022-07-07 13:41:09 +02:00
const [ unknownPool ] = await DB . query ( ` SELECT id from pools where slug = "unknown" ` ) ;
2023-02-24 21:35:13 +09:00
this . uniqueLog ( logger . notice , ` Deleting blocks with unknown mining pool from height ${ oldestBlockHeight } for re-indexing ` ) ;
2023-01-02 13:25:40 +01:00
await DB . query ( `
DELETE FROM blocks
WHERE pool_id = ? AND height >= $ { oldestBlockHeight } ` ,
[ unknownPool [ 0 ] . id ]
) ;
logger . notice ( ` Deleting blocks from ${ pool . name } mining pool for re-indexing ` ) ;
await DB . query ( `
DELETE FROM blocks
WHERE pool_id = ? ` ,
[ pool . id ]
) ;
2022-07-07 13:41:09 +02:00
}
2023-02-12 22:44:04 +09:00
private async $deleteUnknownBlocks ( ) : Promise < void > {
const [ unknownPool ] = await DB . query ( ` SELECT id from pools where slug = "unknown" ` ) ;
2023-02-24 21:35:13 +09:00
this . uniqueLog ( logger . notice , ` Deleting blocks with unknown mining pool from height 130635 for re-indexing ` ) ;
2023-02-12 22:44:04 +09:00
await DB . query ( `
DELETE FROM blocks
WHERE pool_id = ? AND height >= 130635 ` ,
[ unknownPool [ 0 ] . id ]
) ;
}
2022-01-19 18:50:52 +09:00
}
2022-01-20 16:34:14 +09:00
export default new PoolsParser ( ) ;