diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index c676cb1bb..de8d6f51a 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -371,7 +371,7 @@ class MempoolBlocks { return this.$rustMakeBlockTemplates(newMempool, false); } - public async $rustUpdateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[]): Promise { + public async $rustUpdateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[]): Promise { // sanity check to avoid approaching uint32 uid overflow if (this.nextUid + added.length > MAX_UINT32) { this.resetRustGbt(); @@ -401,13 +401,13 @@ class MempoolBlocks { removedUids, ), ); - const expectedMempoolSize = Object.keys(newMempool).length; - const actualMempoolSize = blocks.reduce((total, block) => total + block.length, 0); - if (expectedMempoolSize !== actualMempoolSize) { + const resultMempoolSize = blocks.reduce((total, block) => total + block.length, 0); + if (mempoolSize !== resultMempoolSize) { throw new Error('GBT returned wrong number of transactions, cache is probably out of sync'); } else { this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, true); } + this.removeUids(removedUids); logger.debug(`RUST updateBlockTemplates completed in ${(Date.now() - start)/1000} seconds`); } catch (e) { logger.err('RUST updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); @@ -423,6 +423,7 @@ class MempoolBlocks { } } + const lastBlockIndex = blocks.length - 1; let hasBlockStack = blocks.length >= 8; let stackWeight; let feeStatsCalculator: OnlineFeeStatsCalculator | void; @@ -430,7 +431,7 @@ class MempoolBlocks { if (blockWeights && blockWeights[7] !== null) { stackWeight = blockWeights[7]; } else { - stackWeight = blocks[blocks.length - 1].reduce((total, tx) => total + (mempool[tx]?.weight || 0), 0); + stackWeight = blocks[lastBlockIndex].reduce((total, tx) => total + (mempool[tx]?.weight || 0), 0); } hasBlockStack = stackWeight > config.MEMPOOL.BLOCK_WEIGHT_UNITS; feeStatsCalculator = new OnlineFeeStatsCalculator(stackWeight, 0.5, [10, 20, 30, 40, 50, 60, 70, 80, 90]); @@ -438,8 +439,8 @@ class MempoolBlocks { for (const cluster of Object.values(clusters)) { for (const memberTxid of cluster) { - if (memberTxid in mempool) { - const mempoolTx = mempool[memberTxid]; + const mempoolTx = mempool[memberTxid]; + if (mempoolTx) { const ancestors: Ancestor[] = []; const descendants: Ancestor[] = []; let matched = false; @@ -459,10 +460,7 @@ class MempoolBlocks { } } }); - mempoolTx.ancestors = ancestors; - mempoolTx.descendants = descendants; - mempoolTx.bestDescendant = null; - mempoolTx.cpfpChecked = true; + Object.assign(mempoolTx, {ancestors, descendants, bestDescendant: null, cpfpChecked: true}); } } } @@ -498,7 +496,7 @@ class MempoolBlocks { } // online calculation of stack-of-blocks fee stats - if (hasBlockStack && blockIndex === blocks.length - 1 && feeStatsCalculator) { + if (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) { feeStatsCalculator.processNext(mempoolTx); } @@ -518,7 +516,7 @@ class MempoolBlocks { totalSize, totalWeight, totalFees, - feeStats: (hasBlockStack && blockIndex === blocks.length - 1 && feeStatsCalculator) ? feeStatsCalculator.getRawFeeStats() : undefined, + feeStats: (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) ? feeStatsCalculator.getRawFeeStats() : undefined, }); } diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index d237818b2..c7d7b8b27 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -19,7 +19,7 @@ class Mempool { maxmempool: 300000000, mempoolminfee: 0.00001000, minrelaytxfee: 0.00001000 }; private mempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => void) | undefined; - private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[], + private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, mempoolSize: number, newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => Promise) | undefined; private txPerSecondArray: number[] = []; @@ -69,7 +69,7 @@ class Mempool { this.mempoolChangedCallback = fn; } - public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; }, + public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; }, mempoolSize: number, newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => Promise): void { this.$asyncMempoolChangedCallback = fn; } @@ -84,16 +84,18 @@ class Mempool { public async $setMempool(mempoolData: { [txId: string]: MempoolTransactionExtended }) { this.mempoolCache = mempoolData; + let count = 0; for (const txid of Object.keys(this.mempoolCache)) { if (this.mempoolCache[txid].sigops == null || this.mempoolCache[txid].effectiveFeePerVsize == null) { this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]); } + count++; } if (this.mempoolChangedCallback) { this.mempoolChangedCallback(this.mempoolCache, [], []); } if (this.$asyncMempoolChangedCallback) { - await this.$asyncMempoolChangedCallback(this.mempoolCache, [], []); + await this.$asyncMempoolChangedCallback(this.mempoolCache, count, [], []); } this.addToSpendMap(Object.values(this.mempoolCache)); } @@ -237,23 +239,24 @@ class Mempool { } } + const newMempoolSize = currentMempoolSize + newTransactions.length - deletedTransactions.length; const newTransactionsStripped = newTransactions.map((tx) => Common.stripTransaction(tx)); this.latestTransactions = newTransactionsStripped.concat(this.latestTransactions).slice(0, 6); - if (!this.inSync && transactions.length === Object.keys(this.mempoolCache).length) { + if (!this.inSync && transactions.length === newMempoolSize) { this.inSync = true; logger.notice('The mempool is now in sync!'); loadingIndicators.setProgress('mempool', 100); } - this.mempoolCacheDelta = Math.abs(transactions.length - Object.keys(this.mempoolCache).length); + this.mempoolCacheDelta = Math.abs(transactions.length - newMempoolSize); if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) { this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); } if (this.$asyncMempoolChangedCallback && (hasChange || deletedTransactions.length)) { this.updateTimerProgress(timer, 'running async mempool callback'); - await this.$asyncMempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); + await this.$asyncMempoolChangedCallback(this.mempoolCache, newMempoolSize, newTransactions, deletedTransactions); this.updateTimerProgress(timer, 'completed async mempool callback'); } diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index 00d5a6026..97092d2b1 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -333,7 +333,7 @@ class WebsocketHandler { }); } - async $handleMempoolChange(newMempool: { [txid: string]: MempoolTransactionExtended }, + async $handleMempoolChange(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number, newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]): Promise { if (!this.wss) { throw new Error('WebSocket.Server is not set'); @@ -343,7 +343,7 @@ class WebsocketHandler { if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { if (config.MEMPOOL.RUST_GBT) { - await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, newTransactions, deletedTransactions); + await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, mempoolSize, newTransactions, deletedTransactions); } else { await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, true); } @@ -664,7 +664,7 @@ class WebsocketHandler { if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { if (config.MEMPOOL.RUST_GBT) { - await mempoolBlocks.$rustUpdateBlockTemplates(_memPool, [], transactions); + await mempoolBlocks.$rustUpdateBlockTemplates(_memPool, Object.keys(_memPool).length, [], transactions); } else { await mempoolBlocks.$makeBlockTemplates(_memPool, true); }