From 60c50fc47e86917a2205abb588d79011f567b1a1 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 11 Jul 2023 14:18:05 +0900 Subject: [PATCH] Add regtest network support --- backend/src/api/bitcoin/bitcoin.routes.ts | 4 +- backend/src/api/blocks.ts | 6 +- backend/src/api/common.ts | 2 +- backend/src/api/database-migration.ts | 6 +- backend/src/api/pools-parser.ts | 4 +- backend/src/config.ts | 2 +- backend/src/repositories/PoolsRepository.ts | 4 +- backend/src/tasks/pools-updater.ts | 2 +- backend/src/tasks/price-updater.ts | 2 +- docker/frontend/entrypoint.sh | 2 + frontend/mempool-frontend-config.sample.json | 1 + frontend/src/app/app-routing.module.ts | 109 ++++++++++++++++++ frontend/src/app/bitcoin.utils.ts | 5 + .../bisq-master-page.component.html | 3 +- .../bisq-master-page.component.scss | 4 + .../app/components/block/block.component.ts | 1 + .../blockchain-blocks.component.ts | 3 +- .../app/components/clock/clock.component.ts | 1 + .../liquid-master-page.component.html | 3 +- .../liquid-master-page.component.scss | 4 + .../master-page-preview.component.html | 1 + .../master-page/master-page.component.html | 5 +- .../master-page/master-page.component.scss | 4 + .../mempool-blocks.component.ts | 2 +- .../svg-images/svg-images.component.html | 3 + .../tx-bowtie-graph.component.ts | 1 + .../src/app/services/enterprise.service.ts | 1 + .../src/app/services/navigation.service.ts | 3 +- frontend/src/app/services/seo.service.ts | 2 + frontend/src/app/services/state.service.ts | 12 +- .../global-footer/global-footer.component.ts | 2 +- frontend/src/styles.scss | 4 + 32 files changed, 182 insertions(+), 26 deletions(-) diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts index ffdb2e629..6b3b0611b 100644 --- a/backend/src/api/bitcoin/bitcoin.routes.ts +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -414,7 +414,7 @@ class BitcoinRoutes { private async getBlocks(req: Request, res: Response) { try { - if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { // Bitcoin + if (['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { // Bitcoin const height = req.params.height === undefined ? undefined : parseInt(req.params.height, 10); res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); res.json(await blocks.$getBlocks(height, 15)); @@ -428,7 +428,7 @@ class BitcoinRoutes { private async getBlocksByBulk(req: Request, res: Response) { try { - if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) { // Liquid, Bisq - Not implemented + if (['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK) === false) { // Liquid, Bisq - Not implemented return res.status(404).send(`This API is only available for Bitcoin networks`); } if (config.MEMPOOL.MAX_BLOCKS_BULK_QUERY <= 0) { diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 7cd37f637..752b61fae 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -263,7 +263,7 @@ class Blocks { extras.totalInputAmt = null; } - if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + if (['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { let pool: PoolTag; if (coinbaseTx !== undefined) { pool = await this.$findBlockMiner(coinbaseTx); @@ -845,7 +845,7 @@ class Blocks { } // Not Bitcoin network, return the block as it from the bitcoin backend - if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) { + if (['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK) === false) { return await bitcoinCoreApi.$getBlock(hash); } @@ -1061,7 +1061,7 @@ class Blocks { } public async $getBlockAuditSummary(hash: string): Promise { - if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + if (['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { return BlocksAuditsRepository.$getBlockAudit(hash); } else { return null; diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index cd9da3d2a..028bd8044 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -239,7 +239,7 @@ export class Common { static indexingEnabled(): boolean { return ( - ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) && + ['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK) && config.DATABASE.ENABLED === true && config.MEMPOOL.INDEXING_BLOCKS_AMOUNT !== 0 ); diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 7c7608aff..376ead035 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -104,7 +104,7 @@ class DatabaseMigration { private async $createMissingTablesAndIndexes(databaseSchemaVersion: number) { await this.$setStatisticsAddedIndexedFlag(databaseSchemaVersion); - const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK); + const isBitcoin = ['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK); await this.$executeQuery(this.getCreateElementsTableQuery(), await this.$checkIfTableExists('elements_pegs')); await this.$executeQuery(this.getCreateStatisticsQuery(), await this.$checkIfTableExists('statistics')); @@ -512,7 +512,7 @@ class DatabaseMigration { await this.updateToSchemaVersion(58); } - if (databaseSchemaVersion < 59 && (config.MEMPOOL.NETWORK === 'signet' || config.MEMPOOL.NETWORK === 'testnet')) { + if (databaseSchemaVersion < 59 && ['testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { // https://github.com/mempool/mempool/issues/3360 await this.$executeQuery(`TRUNCATE prices`); } @@ -656,7 +656,7 @@ class DatabaseMigration { */ private getMigrationQueriesFromVersion(version: number): string[] { const queries: string[] = []; - const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK); + const isBitcoin = ['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK); if (version < 1) { if (config.MEMPOOL.NETWORK !== 'liquid' && config.MEMPOOL.NETWORK !== 'liquidtestnet') { diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts index 66f09a9f7..cd8351fcd 100644 --- a/backend/src/api/pools-parser.ts +++ b/backend/src/api/pools-parser.ts @@ -131,7 +131,7 @@ class PoolsParser { let firstKnownBlockPool = 130635; // https://mempool.space/block/0000000000000a067d94ff753eec72830f1205ad3a4c216a08a80c832e551a52 if (config.MEMPOOL.NETWORK === 'testnet') { firstKnownBlockPool = 21106; // https://mempool.space/testnet/block/0000000070b701a5b6a1b965f6a38e0472e70b2bb31b973e4638dec400877581 - } else if (config.MEMPOOL.NETWORK === 'signet') { + } else if (config.MEMPOOL.NETWORK === 'signet' || config.MEMPOOL.NETWORK === 'regtest') { firstKnownBlockPool = 0; } @@ -159,7 +159,7 @@ class PoolsParser { let firstKnownBlockPool = 130635; // https://mempool.space/block/0000000000000a067d94ff753eec72830f1205ad3a4c216a08a80c832e551a52 if (config.MEMPOOL.NETWORK === 'testnet') { firstKnownBlockPool = 21106; // https://mempool.space/testnet/block/0000000070b701a5b6a1b965f6a38e0472e70b2bb31b973e4638dec400877581 - } else if (config.MEMPOOL.NETWORK === 'signet') { + } else if (config.MEMPOOL.NETWORK === 'signet' || config.MEMPOOL.NETWORK === 'regtest') { firstKnownBlockPool = 0; } diff --git a/backend/src/config.ts b/backend/src/config.ts index 09d279537..05274344b 100644 --- a/backend/src/config.ts +++ b/backend/src/config.ts @@ -5,7 +5,7 @@ const configFromFile = require( interface IConfig { MEMPOOL: { ENABLED: boolean; - NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid' | 'liquidtestnet'; + NETWORK: 'mainnet' | 'testnet' | 'signet' | 'regtest' | 'liquid' | 'liquidtestnet'; BACKEND: 'esplora' | 'electrum' | 'none'; HTTP_PORT: number; SPAWN_CLUSTER_PROCS: number; diff --git a/backend/src/repositories/PoolsRepository.ts b/backend/src/repositories/PoolsRepository.ts index 899712266..b2a4fd886 100644 --- a/backend/src/repositories/PoolsRepository.ts +++ b/backend/src/repositories/PoolsRepository.ts @@ -99,7 +99,7 @@ class PoolsRepository { if (parse) { rows[0].regexes = JSON.parse(rows[0].regexes); } - if (['testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + if (['testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { rows[0].addresses = []; // pools-v2.json only contains mainnet addresses } else if (parse) { rows[0].addresses = JSON.parse(rows[0].addresses); @@ -131,7 +131,7 @@ class PoolsRepository { if (parse) { rows[0].regexes = JSON.parse(rows[0].regexes); } - if (['testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + if (['testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { rows[0].addresses = []; // pools.json only contains mainnet addresses } else if (parse) { rows[0].addresses = JSON.parse(rows[0].addresses); diff --git a/backend/src/tasks/pools-updater.ts b/backend/src/tasks/pools-updater.ts index 6e8173c21..cde2126e2 100644 --- a/backend/src/tasks/pools-updater.ts +++ b/backend/src/tasks/pools-updater.ts @@ -17,7 +17,7 @@ class PoolsUpdater { treeUrl: string = config.MEMPOOL.POOLS_JSON_TREE_URL; public async updatePoolsJson(): Promise { - if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false || + if (['mainnet', 'testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK) === false || config.MEMPOOL.ENABLED === false ) { return; diff --git a/backend/src/tasks/price-updater.ts b/backend/src/tasks/price-updater.ts index fafe2b913..2585a4e04 100644 --- a/backend/src/tasks/price-updater.ts +++ b/backend/src/tasks/price-updater.ts @@ -73,7 +73,7 @@ class PriceUpdater { } public async $run(): Promise { - if (config.MEMPOOL.NETWORK === 'signet' || config.MEMPOOL.NETWORK === 'testnet') { + if (['testnet', 'signet', 'regtest'].includes(config.MEMPOOL.NETWORK)) { // Coins have no value on testnet/signet, so we want to always show 0 return; } diff --git a/docker/frontend/entrypoint.sh b/docker/frontend/entrypoint.sh index b6946578b..2d20617f8 100644 --- a/docker/frontend/entrypoint.sh +++ b/docker/frontend/entrypoint.sh @@ -18,6 +18,7 @@ fi __TESTNET_ENABLED__=${TESTNET_ENABLED:=false} __SIGNET_ENABLED__=${SIGNET_ENABLED:=false} +__REGTEST_ENABLED__=${REGTEST_ENABLED:=false} __LIQUID_ENABLED__=${LIQUID_EANBLED:=false} __LIQUID_TESTNET_ENABLED__=${LIQUID_TESTNET_ENABLED:=false} __BISQ_ENABLED__=${BISQ_ENABLED:=false} @@ -44,6 +45,7 @@ __HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true} # Export as environment variables to be used by envsubst export __TESTNET_ENABLED__ export __SIGNET_ENABLED__ +export __REGTEST_ENABLED__ export __LIQUID_ENABLED__ export __LIQUID_TESTNET_ENABLED__ export __BISQ_ENABLED__ diff --git a/frontend/mempool-frontend-config.sample.json b/frontend/mempool-frontend-config.sample.json index 084cbd0ef..ceb9dd729 100644 --- a/frontend/mempool-frontend-config.sample.json +++ b/frontend/mempool-frontend-config.sample.json @@ -1,6 +1,7 @@ { "TESTNET_ENABLED": false, "SIGNET_ENABLED": false, + "REGTEST_ENABLED": false, "LIQUID_ENABLED": false, "LIQUID_TESTNET_ENABLED": false, "BISQ_ENABLED": false, diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index 79a8e1c02..f1d4ff4ba 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -249,6 +249,115 @@ let routes: Routes = [ }, ] }, + { + path: 'regtest', + children: [ + { + path: 'mining/blocks', + redirectTo: 'blocks', + pathMatch: 'full' + }, + { + path: '', + pathMatch: 'full', + loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule) + }, + { + path: '', + component: MasterPageComponent, + children: [ + { + path: 'tx/push', + component: PushTransactionComponent, + }, + { + path: 'about', + component: AboutComponent, + }, + { + path: 'blocks', + component: BlocksList, + }, + { + path: 'rbf', + component: RbfList, + }, + { + path: 'terms-of-service', + component: TermsOfServiceComponent + }, + { + path: 'privacy-policy', + component: PrivacyPolicyComponent + }, + { + path: 'trademark-policy', + component: TrademarkPolicyComponent + }, + { + path: 'address/:id', + children: [], + component: AddressComponent, + data: { + ogImage: true, + networkSpecific: true, + } + }, + { + path: 'tx', + data: { networkSpecific: true }, + component: StartComponent, + children: [ + { + path: ':id', + component: TransactionComponent + }, + ], + }, + { + path: 'block', + data: { networkSpecific: true }, + component: StartComponent, + children: [ + { + path: ':id', + component: BlockComponent, + data: { + ogImage: true + } + }, + ], + }, + { + path: 'docs', + loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule) + }, + { + path: 'api', + loadChildren: () => import('./docs/docs.module').then(m => m.DocsModule) + }, + { + path: 'lightning', + data: { networks: ['bitcoin'] }, + loadChildren: () => import('./lightning/lightning.module').then(m => m.LightningModule) + }, + ], + }, + { + path: 'status', + data: { networks: ['bitcoin', 'liquid'] }, + component: StatusViewComponent + }, + { + path: '', + loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule) + }, + { + path: '**', + redirectTo: '/signet' + }, + ] + }, { path: '', pathMatch: 'full', diff --git a/frontend/src/app/bitcoin.utils.ts b/frontend/src/app/bitcoin.utils.ts index c4af730f6..361702f08 100644 --- a/frontend/src/app/bitcoin.utils.ts +++ b/frontend/src/app/bitcoin.utils.ts @@ -271,6 +271,11 @@ const featureActivation = { segwit: 0, taproot: 0, }, + regtest: { + rbf: 0, + segwit: 0, + taproot: 0, + }, }; export function isFeatureActive(network: string, height: number, feature: 'rbf' | 'segwit' | 'taproot'): boolean { diff --git a/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html b/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html index 61597a2ed..7176ac1e3 100644 --- a/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html +++ b/frontend/src/app/components/bisq-master-page/bisq-master-page.component.html @@ -39,7 +39,7 @@ -