diff --git a/README.md b/README.md
index d2f9f9382..b7a455cd5 100644
--- a/README.md
+++ b/README.md
@@ -1,13 +1,13 @@
# The Mempool Open Source Projectâ„¢ [](https://dashboard.cypress.io/projects/ry4br7/runs)
-https://user-images.githubusercontent.com/232186/222445818-234aa6c9-c233-4c52-b3f0-e32b8232893b.mp4
+https://user-images.githubusercontent.com/93150691/226236121-375ea64f-b4a1-4cc0-8fad-a6fb33226840.mp4
+
+
Mempool is the fully-featured mempool visualizer, explorer, and API service running at [mempool.space](https://mempool.space/).
It is an open-source project developed and operated for the benefit of the Bitcoin community, with a focus on the emerging transaction fee market that is evolving Bitcoin into a multi-layer ecosystem.
-
-
# Installation Methods
Mempool can be self-hosted on a wide variety of your own hardware, ranging from a simple one-click installation on a Raspberry Pi full-node distro all the way to a robust production instance on a powerful FreeBSD server.
diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json
index 9e941636e..48b79a175 100644
--- a/backend/mempool-config.sample.json
+++ b/backend/mempool-config.sample.json
@@ -27,7 +27,8 @@
"AUDIT": false,
"ADVANCED_GBT_AUDIT": false,
"ADVANCED_GBT_MEMPOOL": false,
- "CPFP_INDEXING": false
+ "CPFP_INDEXING": false,
+ "DISK_CACHE_BLOCK_INTERVAL": 6
},
"CORE_RPC": {
"HOST": "127.0.0.1",
diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json
index 239c30547..276cddbfb 100644
--- a/backend/src/__fixtures__/mempool-config.template.json
+++ b/backend/src/__fixtures__/mempool-config.template.json
@@ -28,7 +28,8 @@
"ADVANCED_GBT_AUDIT": "__MEMPOOL_ADVANCED_GBT_AUDIT__",
"ADVANCED_GBT_MEMPOOL": "__MEMPOOL_ADVANCED_GBT_MEMPOOL__",
"CPFP_INDEXING": "__MEMPOOL_CPFP_INDEXING__",
- "MAX_BLOCKS_BULK_QUERY": "__MEMPOOL_MAX_BLOCKS_BULK_QUERY__"
+ "MAX_BLOCKS_BULK_QUERY": "__MEMPOOL_MAX_BLOCKS_BULK_QUERY__",
+ "DISK_CACHE_BLOCK_INTERVAL": "__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__"
},
"CORE_RPC": {
"HOST": "__CORE_RPC_HOST__",
diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts
index 04c97f961..487fb4e78 100644
--- a/backend/src/__tests__/config.test.ts
+++ b/backend/src/__tests__/config.test.ts
@@ -42,6 +42,7 @@ describe('Mempool Backend Config', () => {
ADVANCED_GBT_MEMPOOL: false,
CPFP_INDEXING: false,
MAX_BLOCKS_BULK_QUERY: 0,
+ DISK_CACHE_BLOCK_INTERVAL: 6,
});
expect(config.ELECTRUM).toStrictEqual({ HOST: '127.0.0.1', PORT: 3306, TLS_ENABLED: true });
diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts
index 8ed81016b..f9b14d637 100644
--- a/backend/src/api/blocks.ts
+++ b/backend/src/api/blocks.ts
@@ -651,7 +651,7 @@ class Blocks {
if (this.newBlockCallbacks.length) {
this.newBlockCallbacks.forEach((cb) => cb(blockExtended, txIds, transactions));
}
- if (!memPool.hasPriority() && (block.height % 6 === 0)) {
+ if (!memPool.hasPriority() && (block.height % config.MEMPOOL.DISK_CACHE_BLOCK_INTERVAL === 0)) {
diskCache.$saveCacheToDisk();
}
diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts
index 74b68b6be..7180c6f51 100644
--- a/backend/src/api/disk-cache.ts
+++ b/backend/src/api/disk-cache.ts
@@ -19,20 +19,16 @@ class DiskCache {
private isWritingCache = false;
constructor() {
- if (!cluster.isMaster) {
+ if (!cluster.isPrimary) {
return;
}
process.on('SIGINT', (e) => {
- this.saveCacheToDiskSync();
- process.exit(2);
- });
- process.on('SIGTERM', (e) => {
- this.saveCacheToDiskSync();
- process.exit(2);
+ this.$saveCacheToDisk(true);
+ process.exit(0);
});
}
- async $saveCacheToDisk(): Promise {
+ async $saveCacheToDisk(sync: boolean = false): Promise {
if (!cluster.isPrimary) {
return;
}
@@ -41,7 +37,7 @@ class DiskCache {
return;
}
try {
- logger.debug('Writing mempool and blocks data to disk cache (async)...');
+ logger.debug(`Writing mempool and blocks data to disk cache (${ sync ? 'sync' : 'async' })...`);
this.isWritingCache = true;
const mempool = memPool.getMempool();
@@ -54,68 +50,46 @@ class DiskCache {
const chunkSize = Math.floor(mempoolArray.length / DiskCache.CHUNK_FILES);
- await fsPromises.writeFile(DiskCache.FILE_NAME, JSON.stringify({
- network: config.MEMPOOL.NETWORK,
- cacheSchemaVersion: this.cacheSchemaVersion,
- blocks: blocks.getBlocks(),
- blockSummaries: blocks.getBlockSummaries(),
- mempool: {},
- mempoolArray: mempoolArray.splice(0, chunkSize),
- }), { flag: 'w' });
- for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
- await fsPromises.writeFile(DiskCache.FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({
+ if (sync) {
+ fs.writeFileSync(DiskCache.TMP_FILE_NAME, JSON.stringify({
+ network: config.MEMPOOL.NETWORK,
+ cacheSchemaVersion: this.cacheSchemaVersion,
+ blocks: blocks.getBlocks(),
+ blockSummaries: blocks.getBlockSummaries(),
mempool: {},
mempoolArray: mempoolArray.splice(0, chunkSize),
}), { flag: 'w' });
- }
- logger.debug('Mempool and blocks data saved to disk cache');
- this.isWritingCache = false;
- } catch (e) {
- logger.warn('Error writing to cache file: ' + (e instanceof Error ? e.message : e));
- this.isWritingCache = false;
- }
- }
+ for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
+ fs.writeFileSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({
+ mempool: {},
+ mempoolArray: mempoolArray.splice(0, chunkSize),
+ }), { flag: 'w' });
+ }
- saveCacheToDiskSync(): void {
- if (!cluster.isPrimary) {
- return;
- }
- if (this.isWritingCache) {
- logger.debug('Saving cache already in progress. Skipping.');
- return;
- }
- try {
- logger.debug('Writing mempool and blocks data to disk cache (sync)...');
- this.isWritingCache = true;
-
- const mempool = memPool.getMempool();
- const mempoolArray: TransactionExtended[] = [];
- for (const tx in mempool) {
- mempoolArray.push(mempool[tx]);
- }
-
- Common.shuffleArray(mempoolArray);
-
- const chunkSize = Math.floor(mempoolArray.length / DiskCache.CHUNK_FILES);
-
- fs.writeFileSync(DiskCache.TMP_FILE_NAME, JSON.stringify({
- network: config.MEMPOOL.NETWORK,
- cacheSchemaVersion: this.cacheSchemaVersion,
- blocks: blocks.getBlocks(),
- blockSummaries: blocks.getBlockSummaries(),
- mempool: {},
- mempoolArray: mempoolArray.splice(0, chunkSize),
- }), { flag: 'w' });
- for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
- fs.writeFileSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({
+ fs.renameSync(DiskCache.TMP_FILE_NAME, DiskCache.FILE_NAME);
+ for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
+ fs.renameSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString()));
+ }
+ } else {
+ await fsPromises.writeFile(DiskCache.TMP_FILE_NAME, JSON.stringify({
+ network: config.MEMPOOL.NETWORK,
+ cacheSchemaVersion: this.cacheSchemaVersion,
+ blocks: blocks.getBlocks(),
+ blockSummaries: blocks.getBlockSummaries(),
mempool: {},
mempoolArray: mempoolArray.splice(0, chunkSize),
}), { flag: 'w' });
- }
+ for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
+ await fsPromises.writeFile(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({
+ mempool: {},
+ mempoolArray: mempoolArray.splice(0, chunkSize),
+ }), { flag: 'w' });
+ }
- fs.renameSync(DiskCache.TMP_FILE_NAME, DiskCache.FILE_NAME);
- for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
- fs.renameSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString()));
+ await fsPromises.rename(DiskCache.TMP_FILE_NAME, DiskCache.FILE_NAME);
+ for (let i = 1; i < DiskCache.CHUNK_FILES; i++) {
+ await fsPromises.rename(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString()));
+ }
}
logger.debug('Mempool and blocks data saved to disk cache');
diff --git a/backend/src/config.ts b/backend/src/config.ts
index a16b38af9..ca5ad5487 100644
--- a/backend/src/config.ts
+++ b/backend/src/config.ts
@@ -33,6 +33,7 @@ interface IConfig {
ADVANCED_GBT_MEMPOOL: boolean;
CPFP_INDEXING: boolean;
MAX_BLOCKS_BULK_QUERY: number;
+ DISK_CACHE_BLOCK_INTERVAL: number;
};
ESPLORA: {
REST_API_URL: string;
@@ -158,6 +159,7 @@ const defaults: IConfig = {
'ADVANCED_GBT_MEMPOOL': false,
'CPFP_INDEXING': false,
'MAX_BLOCKS_BULK_QUERY': 0,
+ 'DISK_CACHE_BLOCK_INTERVAL': 6,
},
'ESPLORA': {
'REST_API_URL': 'http://127.0.0.1:3000',
diff --git a/docker/README.md b/docker/README.md
index 1b9787842..3c08d9c3a 100644
--- a/docker/README.md
+++ b/docker/README.md
@@ -113,6 +113,7 @@ Below we list all settings from `mempool-config.json` and the corresponding over
"ADVANCED_GBT_MEMPOOL": false,
"CPFP_INDEXING": false,
"MAX_BLOCKS_BULK_QUERY": 0,
+ "DISK_CACHE_BLOCK_INTERVAL": 6
},
```
@@ -144,6 +145,7 @@ Corresponding `docker-compose.yml` overrides:
MEMPOOL_ADVANCED_GBT_MEMPOOL: ""
MEMPOOL_CPFP_INDEXING: ""
MAX_BLOCKS_BULK_QUERY: ""
+ DISK_CACHE_BLOCK_INTERVAL: ""
...
```
diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json
index c1165a93a..e78a370f0 100644
--- a/docker/backend/mempool-config.json
+++ b/docker/backend/mempool-config.json
@@ -26,7 +26,8 @@
"ADVANCED_GBT_AUDIT": __MEMPOOL_ADVANCED_GBT_AUDIT__,
"ADVANCED_GBT_MEMPOOL": __MEMPOOL_ADVANCED_GBT_MEMPOOL__,
"CPFP_INDEXING": __MEMPOOL_CPFP_INDEXING__,
- "MAX_BLOCKS_BULK_QUERY": __MEMPOOL_MAX_BLOCKS_BULK_QUERY__
+ "MAX_BLOCKS_BULK_QUERY": __MEMPOOL_MAX_BLOCKS_BULK_QUERY__,
+ "DISK_CACHE_BLOCK_INTERVAL": __MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__
},
"CORE_RPC": {
"HOST": "__CORE_RPC_HOST__",
diff --git a/docker/backend/start.sh b/docker/backend/start.sh
index 3c963815c..61f16098c 100755
--- a/docker/backend/start.sh
+++ b/docker/backend/start.sh
@@ -30,6 +30,7 @@ __MEMPOOL_ADVANCED_GBT_AUDIT__=${MEMPOOL_ADVANCED_GBT_AUDIT:=false}
__MEMPOOL_ADVANCED_GBT_MEMPOOL__=${MEMPOOL_ADVANCED_GBT_MEMPOOL:=false}
__MEMPOOL_CPFP_INDEXING__=${MEMPOOL_CPFP_INDEXING:=false}
__MEMPOOL_MAX_BLOCKS_BULK_QUERY__=${MEMPOOL_MAX_BLOCKS_BULK_QUERY:=0}
+__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__=${MEMPOOL_DISK_CACHE_BLOCK_INTERVAL:=6}
# CORE_RPC
__CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1}
@@ -152,6 +153,7 @@ sed -i "s!__MEMPOOL_ADVANCED_GBT_MEMPOOL__!${__MEMPOOL_ADVANCED_GBT_MEMPOOL__}!g
sed -i "s!__MEMPOOL_ADVANCED_GBT_AUDIT__!${__MEMPOOL_ADVANCED_GBT_AUDIT__}!g" mempool-config.json
sed -i "s!__MEMPOOL_CPFP_INDEXING__!${__MEMPOOL_CPFP_INDEXING__}!g" mempool-config.json
sed -i "s!__MEMPOOL_MAX_BLOCKS_BULK_QUERY__!${__MEMPOOL_MAX_BLOCKS_BULK_QUERY__}!g" mempool-config.json
+sed -i "s!__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__!${__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__}!g" mempool-config.json
sed -i "s/__CORE_RPC_HOST__/${__CORE_RPC_HOST__}/g" mempool-config.json
sed -i "s/__CORE_RPC_PORT__/${__CORE_RPC_PORT__}/g" mempool-config.json
diff --git a/production/mempool-config.liquid.json b/production/mempool-config.liquid.json
index 11ad8ffcd..d6513f9e2 100644
--- a/production/mempool-config.liquid.json
+++ b/production/mempool-config.liquid.json
@@ -6,7 +6,8 @@
"MINED_BLOCKS_CACHE": 144,
"SPAWN_CLUSTER_PROCS": 0,
"API_URL_PREFIX": "/api/v1/",
- "POLL_RATE_MS": 1000
+ "POLL_RATE_MS": 1000,
+ "DISK_CACHE_BLOCK_INTERVAL": 1
},
"SYSLOG" : {
"MIN_PRIORITY": "debug"
diff --git a/production/mempool-config.liquidtestnet.json b/production/mempool-config.liquidtestnet.json
index 7769bfb53..f85f041d2 100644
--- a/production/mempool-config.liquidtestnet.json
+++ b/production/mempool-config.liquidtestnet.json
@@ -6,7 +6,8 @@
"MINED_BLOCKS_CACHE": 144,
"SPAWN_CLUSTER_PROCS": 0,
"API_URL_PREFIX": "/api/v1/",
- "POLL_RATE_MS": 1000
+ "POLL_RATE_MS": 1000,
+ "DISK_CACHE_BLOCK_INTERVAL": 1
},
"SYSLOG" : {
"MIN_PRIORITY": "debug"
diff --git a/production/mempool-config.mainnet.json b/production/mempool-config.mainnet.json
index cca43d7e3..fc08ae930 100644
--- a/production/mempool-config.mainnet.json
+++ b/production/mempool-config.mainnet.json
@@ -14,7 +14,8 @@
"CPFP_INDEXING": true,
"ADVANCED_GBT_AUDIT": true,
"ADVANCED_GBT_MEMPOOL": true,
- "USE_SECOND_NODE_FOR_MINFEE": true
+ "USE_SECOND_NODE_FOR_MINFEE": true,
+ "DISK_CACHE_BLOCK_INTERVAL": 1
},
"SYSLOG" : {
"MIN_PRIORITY": "debug"
diff --git a/production/mempool-config.signet.json b/production/mempool-config.signet.json
index 87f8e2650..c4d43e040 100644
--- a/production/mempool-config.signet.json
+++ b/production/mempool-config.signet.json
@@ -10,7 +10,8 @@
"AUDIT": true,
"ADVANCED_GBT_AUDIT": true,
"ADVANCED_GBT_MEMPOOL": true,
- "POLL_RATE_MS": 1000
+ "POLL_RATE_MS": 1000,
+ "DISK_CACHE_BLOCK_INTERVAL": 1
},
"SYSLOG" : {
"MIN_PRIORITY": "debug"
diff --git a/production/mempool-config.testnet.json b/production/mempool-config.testnet.json
index 5c1695e62..f5ff4fba1 100644
--- a/production/mempool-config.testnet.json
+++ b/production/mempool-config.testnet.json
@@ -10,7 +10,8 @@
"AUDIT": true,
"ADVANCED_GBT_AUDIT": true,
"ADVANCED_GBT_MEMPOOL": true,
- "POLL_RATE_MS": 1000
+ "POLL_RATE_MS": 1000,
+ "DISK_CACHE_BLOCK_INTERVAL": 1
},
"SYSLOG" : {
"MIN_PRIORITY": "debug"