misc JS-side gbt performance optimizations

This commit is contained in:
Mononaut 2023-06-28 19:51:52 -04:00
parent 0886e850f9
commit db8c34ae61
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
3 changed files with 23 additions and 22 deletions

View File

@ -371,7 +371,7 @@ class MempoolBlocks {
return this.$rustMakeBlockTemplates(newMempool, false); return this.$rustMakeBlockTemplates(newMempool, false);
} }
public async $rustUpdateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[]): Promise<void> { public async $rustUpdateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[]): Promise<void> {
// sanity check to avoid approaching uint32 uid overflow // sanity check to avoid approaching uint32 uid overflow
if (this.nextUid + added.length > MAX_UINT32) { if (this.nextUid + added.length > MAX_UINT32) {
this.resetRustGbt(); this.resetRustGbt();
@ -401,13 +401,13 @@ class MempoolBlocks {
removedUids, removedUids,
), ),
); );
const expectedMempoolSize = Object.keys(newMempool).length; const resultMempoolSize = blocks.reduce((total, block) => total + block.length, 0);
const actualMempoolSize = blocks.reduce((total, block) => total + block.length, 0); if (mempoolSize !== resultMempoolSize) {
if (expectedMempoolSize !== actualMempoolSize) {
throw new Error('GBT returned wrong number of transactions, cache is probably out of sync'); throw new Error('GBT returned wrong number of transactions, cache is probably out of sync');
} else { } else {
this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, true); this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, true);
} }
this.removeUids(removedUids);
logger.debug(`RUST updateBlockTemplates completed in ${(Date.now() - start)/1000} seconds`); logger.debug(`RUST updateBlockTemplates completed in ${(Date.now() - start)/1000} seconds`);
} catch (e) { } catch (e) {
logger.err('RUST updateBlockTemplates failed. ' + (e instanceof Error ? e.message : 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 hasBlockStack = blocks.length >= 8;
let stackWeight; let stackWeight;
let feeStatsCalculator: OnlineFeeStatsCalculator | void; let feeStatsCalculator: OnlineFeeStatsCalculator | void;
@ -430,7 +431,7 @@ class MempoolBlocks {
if (blockWeights && blockWeights[7] !== null) { if (blockWeights && blockWeights[7] !== null) {
stackWeight = blockWeights[7]; stackWeight = blockWeights[7];
} else { } 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; hasBlockStack = stackWeight > config.MEMPOOL.BLOCK_WEIGHT_UNITS;
feeStatsCalculator = new OnlineFeeStatsCalculator(stackWeight, 0.5, [10, 20, 30, 40, 50, 60, 70, 80, 90]); 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 cluster of Object.values(clusters)) {
for (const memberTxid of cluster) { for (const memberTxid of cluster) {
if (memberTxid in mempool) { const mempoolTx = mempool[memberTxid];
const mempoolTx = mempool[memberTxid]; if (mempoolTx) {
const ancestors: Ancestor[] = []; const ancestors: Ancestor[] = [];
const descendants: Ancestor[] = []; const descendants: Ancestor[] = [];
let matched = false; let matched = false;
@ -459,10 +460,7 @@ class MempoolBlocks {
} }
} }
}); });
mempoolTx.ancestors = ancestors; Object.assign(mempoolTx, {ancestors, descendants, bestDescendant: null, cpfpChecked: true});
mempoolTx.descendants = descendants;
mempoolTx.bestDescendant = null;
mempoolTx.cpfpChecked = true;
} }
} }
} }
@ -498,7 +496,7 @@ class MempoolBlocks {
} }
// online calculation of stack-of-blocks fee stats // online calculation of stack-of-blocks fee stats
if (hasBlockStack && blockIndex === blocks.length - 1 && feeStatsCalculator) { if (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) {
feeStatsCalculator.processNext(mempoolTx); feeStatsCalculator.processNext(mempoolTx);
} }
@ -518,7 +516,7 @@ class MempoolBlocks {
totalSize, totalSize,
totalWeight, totalWeight,
totalFees, totalFees,
feeStats: (hasBlockStack && blockIndex === blocks.length - 1 && feeStatsCalculator) ? feeStatsCalculator.getRawFeeStats() : undefined, feeStats: (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) ? feeStatsCalculator.getRawFeeStats() : undefined,
}); });
} }

View File

@ -19,7 +19,7 @@ class Mempool {
maxmempool: 300000000, mempoolminfee: 0.00001000, minrelaytxfee: 0.00001000 }; maxmempool: 300000000, mempoolminfee: 0.00001000, minrelaytxfee: 0.00001000 };
private mempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[], private mempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[],
deletedTransactions: MempoolTransactionExtended[]) => void) | undefined; 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<void>) | undefined; deletedTransactions: MempoolTransactionExtended[]) => Promise<void>) | undefined;
private txPerSecondArray: number[] = []; private txPerSecondArray: number[] = [];
@ -69,7 +69,7 @@ class Mempool {
this.mempoolChangedCallback = fn; 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>): void { newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => Promise<void>): void {
this.$asyncMempoolChangedCallback = fn; this.$asyncMempoolChangedCallback = fn;
} }
@ -84,16 +84,18 @@ class Mempool {
public async $setMempool(mempoolData: { [txId: string]: MempoolTransactionExtended }) { public async $setMempool(mempoolData: { [txId: string]: MempoolTransactionExtended }) {
this.mempoolCache = mempoolData; this.mempoolCache = mempoolData;
let count = 0;
for (const txid of Object.keys(this.mempoolCache)) { for (const txid of Object.keys(this.mempoolCache)) {
if (this.mempoolCache[txid].sigops == null || this.mempoolCache[txid].effectiveFeePerVsize == null) { if (this.mempoolCache[txid].sigops == null || this.mempoolCache[txid].effectiveFeePerVsize == null) {
this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]); this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]);
} }
count++;
} }
if (this.mempoolChangedCallback) { if (this.mempoolChangedCallback) {
this.mempoolChangedCallback(this.mempoolCache, [], []); this.mempoolChangedCallback(this.mempoolCache, [], []);
} }
if (this.$asyncMempoolChangedCallback) { if (this.$asyncMempoolChangedCallback) {
await this.$asyncMempoolChangedCallback(this.mempoolCache, [], []); await this.$asyncMempoolChangedCallback(this.mempoolCache, count, [], []);
} }
this.addToSpendMap(Object.values(this.mempoolCache)); 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)); const newTransactionsStripped = newTransactions.map((tx) => Common.stripTransaction(tx));
this.latestTransactions = newTransactionsStripped.concat(this.latestTransactions).slice(0, 6); 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; this.inSync = true;
logger.notice('The mempool is now in sync!'); logger.notice('The mempool is now in sync!');
loadingIndicators.setProgress('mempool', 100); 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)) { if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) {
this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions);
} }
if (this.$asyncMempoolChangedCallback && (hasChange || deletedTransactions.length)) { if (this.$asyncMempoolChangedCallback && (hasChange || deletedTransactions.length)) {
this.updateTimerProgress(timer, 'running async mempool callback'); 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'); this.updateTimerProgress(timer, 'completed async mempool callback');
} }

View File

@ -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<void> { newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]): Promise<void> {
if (!this.wss) { if (!this.wss) {
throw new Error('WebSocket.Server is not set'); throw new Error('WebSocket.Server is not set');
@ -343,7 +343,7 @@ class WebsocketHandler {
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
if (config.MEMPOOL.RUST_GBT) { if (config.MEMPOOL.RUST_GBT) {
await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, newTransactions, deletedTransactions); await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, mempoolSize, newTransactions, deletedTransactions);
} else { } else {
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, true); await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, true);
} }
@ -664,7 +664,7 @@ class WebsocketHandler {
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) { if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
if (config.MEMPOOL.RUST_GBT) { if (config.MEMPOOL.RUST_GBT) {
await mempoolBlocks.$rustUpdateBlockTemplates(_memPool, [], transactions); await mempoolBlocks.$rustUpdateBlockTemplates(_memPool, Object.keys(_memPool).length, [], transactions);
} else { } else {
await mempoolBlocks.$makeBlockTemplates(_memPool, true); await mempoolBlocks.$makeBlockTemplates(_memPool, true);
} }