From 3f234431fbd991dd459cb1f7ae53d2aad3b675ba Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 9 Mar 2023 19:31:53 -0600 Subject: [PATCH 1/8] fix missing fee rating on mobile --- .../src/app/components/transaction/transaction.component.html | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/frontend/src/app/components/transaction/transaction.component.html b/frontend/src/app/components/transaction/transaction.component.html index 0cd4a86c2..ec08c9303 100644 --- a/frontend/src/app/components/transaction/transaction.component.html +++ b/frontend/src/app/components/transaction/transaction.component.html @@ -488,7 +488,7 @@
{{ tx.effectiveFeePerVsize | feeRounding }} sat/vB - +
From 796566e7aedcc926b872d7feef291554c4b8ce29 Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 9 Mar 2023 19:47:54 -0600 Subject: [PATCH 2/8] Save cache to disk on SIGTERM/SIGINT --- backend/src/api/disk-cache.ts | 63 ++++++++++++++++++++++++++++++++--- 1 file changed, 59 insertions(+), 4 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 01bbb4d3f..584916563 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -16,14 +16,26 @@ class DiskCache { private static CHUNK_FILES = 25; private isWritingCache = false; - constructor() { } + constructor() { + if (!cluster.isMaster) { + return; + } + process.on('SIGINT', (e) => { + this.saveCacheToDiskSync(); + process.exit(2); + }); + process.on('SIGTERM', (e) => { + this.saveCacheToDiskSync(); + process.exit(2); + }); + } async $saveCacheToDisk(): Promise { if (!cluster.isPrimary) { return; } if (this.isWritingCache) { - logger.debug('Saving cache already in progress. Skipping.') + logger.debug('Saving cache already in progress. Skipping.'); return; } try { @@ -61,7 +73,50 @@ class DiskCache { } } - wipeCache() { + 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.FILE_NAME, JSON.stringify({ + 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.FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({ + 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; + } + } + + wipeCache(): void { logger.notice(`Wiping nodejs backend cache/cache*.json files`); try { fs.unlinkSync(DiskCache.FILE_NAME); @@ -83,7 +138,7 @@ class DiskCache { } } - loadMempoolCache() { + loadMempoolCache(): void { if (!fs.existsSync(DiskCache.FILE_NAME)) { return; } From 46d89ac8379c04ceaa1c0988bab62211b4cf86de Mon Sep 17 00:00:00 2001 From: Mononaut Date: Thu, 9 Mar 2023 20:19:22 -0600 Subject: [PATCH 3/8] prevent disk cache file write corruption --- backend/src/api/disk-cache.ts | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 584916563..af04d5acb 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -11,6 +11,8 @@ import { Common } from './common'; class DiskCache { private cacheSchemaVersion = 3; + private static TMP_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/tmp-cache.json'; + private static TMP_FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/tmp-cache{number}.json'; private static FILE_NAME = config.MEMPOOL.CACHE_DIR + '/cache.json'; private static FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/cache{number}.json'; private static CHUNK_FILES = 25; @@ -95,7 +97,7 @@ class DiskCache { const chunkSize = Math.floor(mempoolArray.length / DiskCache.CHUNK_FILES); - fs.writeFileSync(DiskCache.FILE_NAME, JSON.stringify({ + fs.writeFileSync(DiskCache.TMP_FILE_NAME, JSON.stringify({ cacheSchemaVersion: this.cacheSchemaVersion, blocks: blocks.getBlocks(), blockSummaries: blocks.getBlockSummaries(), @@ -103,11 +105,17 @@ class DiskCache { mempoolArray: mempoolArray.splice(0, chunkSize), }), { flag: 'w' }); for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { - fs.writeFileSync(DiskCache.FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({ + fs.writeFileSync(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())); + } + logger.debug('Mempool and blocks data saved to disk cache'); this.isWritingCache = false; } catch (e) { From dd01371b61a3b5b8c998585b4423c0b25a91fe7e Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 10 Mar 2023 12:37:55 +0900 Subject: [PATCH 4/8] Fixes changed after checked error in transaction page --- .../src/app/components/transaction/transaction.component.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 673743344..e254d131a 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -496,7 +496,9 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { @HostListener('window:resize', ['$event']) setGraphSize(): void { if (this.graphContainer) { - this.graphWidth = this.graphContainer.nativeElement.clientWidth; + setTimeout(() => { + this.graphWidth = this.graphContainer.nativeElement.clientWidth; + }, 1); } } From a22a62836e8cc55a0793349a7fcd88c1a80d8e6e Mon Sep 17 00:00:00 2001 From: Mononaut Date: Tue, 21 Feb 2023 21:59:31 -0600 Subject: [PATCH 5/8] pixel-perfect flow diagrams --- .../tx-bowtie-graph/tx-bowtie-graph.component.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts index 1c5ee5391..b402ddea8 100644 --- a/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts +++ b/frontend/src/app/components/tx-bowtie-graph/tx-bowtie-graph.component.ts @@ -208,8 +208,8 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { this.outputs = this.initLines('out', voutWithFee, totalValue, this.maxStrands); this.middle = { - path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.5} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.5}`, - style: `stroke-width: ${this.combinedWeight + 1}; stroke: ${this.gradient[1]}` + path: `M ${(this.width / 2) - this.midWidth} ${(this.height / 2) + 0.25} L ${(this.width / 2) + this.midWidth} ${(this.height / 2) + 0.25}`, + style: `stroke-width: ${this.combinedWeight + 0.5}; stroke: ${this.gradient[1]}` }; this.hasLine = this.inputs.reduce((line, put) => line || !put.zeroValue, false) @@ -266,7 +266,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { const lineParams = weights.map((w, i) => { return { weight: w, - thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.max(this.minWeight - 1, w) + 1, + thickness: xputs[i].value === 0 ? this.zeroValueThickness : Math.min(this.combinedWeight + 0.5, Math.max(this.minWeight - 1, w) + 1), offset: 0, innerY: 0, outerY: 0, @@ -278,7 +278,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { // bounds of the middle segment const innerTop = (this.height / 2) - (this.combinedWeight / 2); - const innerBottom = innerTop + this.combinedWeight; + const innerBottom = innerTop + this.combinedWeight + 0.5; // tracks the visual bottom of the endpoints of the previous line let lastOuter = 0; let lastInner = innerTop; @@ -303,7 +303,7 @@ export class TxBowtieGraphComponent implements OnInit, OnChanges { // set the vertical position of the (center of the) outer side of the line line.outerY = lastOuter + (line.thickness / 2); - line.innerY = Math.min(innerBottom + (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2))); + line.innerY = Math.min(innerBottom - (line.thickness / 2), Math.max(innerTop + (line.thickness / 2), lastInner + (line.weight / 2))); // special case to center single input/outputs if (xputs.length === 1) { From 4a0d9cb66f7a18d789e08c15ace3b414b95320ca Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 10 Mar 2023 18:35:26 +0900 Subject: [PATCH 6/8] Fixes arrow position on confirmed blocks fixes #3294 --- .../components/blockchain-blocks/blockchain-blocks.component.ts | 2 +- .../src/app/components/transaction/transaction.component.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 3feaf6c2d..e3547a569 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -107,7 +107,7 @@ export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { this.blocks.unshift(block); this.blocks = this.blocks.slice(0, this.dynamicBlocksAmount); - if (txConfirmed) { + if (txConfirmed && this.height === block.height) { this.markHeight = block.height; this.moveArrowToPosition(true, true); } else { diff --git a/frontend/src/app/components/transaction/transaction.component.ts b/frontend/src/app/components/transaction/transaction.component.ts index 673743344..c28525159 100644 --- a/frontend/src/app/components/transaction/transaction.component.ts +++ b/frontend/src/app/components/transaction/transaction.component.ts @@ -347,7 +347,7 @@ export class TransactionComponent implements OnInit, AfterViewInit, OnDestroy { this.blocksSubscription = this.stateService.blocks$.subscribe(([block, txConfirmed]) => { this.latestBlock = block; - if (txConfirmed && this.tx) { + if (txConfirmed && this.tx && !this.tx.status.confirmed) { this.tx.status = { confirmed: true, block_height: block.height, From d3d67627f3090a36dff30a145befb3384fb803f3 Mon Sep 17 00:00:00 2001 From: softsimon Date: Fri, 10 Mar 2023 20:19:37 +0900 Subject: [PATCH 7/8] Remove search bar focus border --- .../app/components/search-form/search-form.component.scss | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/frontend/src/app/components/search-form/search-form.component.scss b/frontend/src/app/components/search-form/search-form.component.scss index d59acadb9..f3d2ee234 100644 --- a/frontend/src/app/components/search-form/search-form.component.scss +++ b/frontend/src/app/components/search-form/search-form.component.scss @@ -53,3 +53,8 @@ form { margin-top: 1px; margin-right: 2px; } + +input:focus { + box-shadow: none; + border-color: #1b1f2c; +} From 4263977d99a6d16abb86c2a7c7a963f1cb0b4543 Mon Sep 17 00:00:00 2001 From: nymkappa <1612910616@pm.me> Date: Sat, 11 Mar 2023 10:52:15 +0900 Subject: [PATCH 8/8] Updated regtest example --- backend/README.md | 28 +++++++++++++++++----------- 1 file changed, 17 insertions(+), 11 deletions(-) diff --git a/backend/README.md b/backend/README.md index be85d25af..256dcaa43 100644 --- a/backend/README.md +++ b/backend/README.md @@ -171,52 +171,58 @@ Helpful link: https://gist.github.com/System-Glitch/cb4e87bf1ae3fec9925725bb3ebe Run bitcoind on regtest: ``` - bitcoind -regtest -rpcport=8332 + bitcoind -regtest ``` Create a new wallet, if needed: ``` - bitcoin-cli -regtest -rpcport=8332 createwallet test + bitcoin-cli -regtest createwallet test ``` Load wallet (this command may take a while if you have lot of UTXOs): ``` - bitcoin-cli -regtest -rpcport=8332 loadwallet test + bitcoin-cli -regtest loadwallet test ``` Get a new address: ``` - address=$(./src/bitcoin-cli -regtest -rpcport=8332 getnewaddress) + address=$(bitcoin-cli -regtest getnewaddress) ``` Mine blocks to the previously generated address. You need at least 101 blocks before you can spend. This will take some time to execute (~1 min): ``` - bitcoin-cli -regtest -rpcport=8332 generatetoaddress 101 $address + bitcoin-cli -regtest generatetoaddress 101 $address ``` Send 0.1 BTC at 5 sat/vB to another address: ``` - ./src/bitcoin-cli -named -regtest -rpcport=8332 sendtoaddress address=$(./src/bitcoin-cli -regtest -rpcport=8332 getnewaddress) amount=0.1 fee_rate=5 + bitcoin-cli -named -regtest sendtoaddress address=$(bitcoin-cli -regtest getnewaddress) amount=0.1 fee_rate=5 ``` See more example of `sendtoaddress`: ``` - ./src/bitcoin-cli sendtoaddress # will print the help + bitcoin-cli sendtoaddress # will print the help ``` -Mini script to generate transactions with random TX fee-rate (between 1 to 100 sat/vB). It's slow so don't expect to use this to test mempool spam, except if you let it run for a long time, or maybe with multiple regtest nodes connected to each other. +Mini script to generate random network activity (random TX count with random tx fee-rate). It's slow so don't expect to use this to test mempool spam, except if you let it run for a long time, or maybe with multiple regtest nodes connected to each other. ``` #!/bin/bash - address=$(./src/bitcoin-cli -regtest -rpcport=8332 getnewaddress) + address=$(bitcoin-cli -regtest getnewaddress) + bitcoin-cli -regtest generatetoaddress 101 $address for i in {1..1000000} do - ./src/bitcoin-cli -regtest -rpcport=8332 -named sendtoaddress address=$address amount=0.01 fee_rate=$(jot -r 1 1 100) + for y in $(seq 1 "$(jot -r 1 1 1000)") + do + bitcoin-cli -regtest -named sendtoaddress address=$address amount=0.01 fee_rate=$(jot -r 1 1 100) + done + bitcoin-cli -regtest generatetoaddress 1 $address + sleep 5 done ``` Generate block at regular interval (every 10 seconds in this example): ``` - watch -n 10 "./src/bitcoin-cli -regtest -rpcport=8332 generatetoaddress 1 $address" + watch -n 10 "bitcoin-cli -regtest generatetoaddress 1 $address" ``` ### Mining pools update