Refactor acceleration tracking

This commit is contained in:
Mononaut 2023-05-30 19:35:39 -04:00
parent fe76a0fd08
commit 379fa3fe49
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
4 changed files with 91 additions and 44 deletions

View File

@ -4,6 +4,7 @@ import { Common, OnlineFeeStatsCalculator } from './common';
import config from '../config';
import { Worker } from 'worker_threads';
import path from 'path';
import mempool from './mempool';
class MempoolBlocks {
private mempoolBlocks: MempoolBlockWithTransactions[] = [];
@ -211,9 +212,11 @@ class MempoolBlocks {
// reset mempool short ids
this.resetUids();
for (const tx of Object.values(newMempool)) {
this.setUid(tx);
this.setUid(tx, true);
}
const accelerations = mempool.getAccelerations();
// prepare a stripped down version of the mempool with only the minimum necessary data
// to reduce the overhead of passing this data to the worker thread
const strippedMempool: Map<number, CompactThreadTransaction> = new Map();
@ -221,7 +224,7 @@ class MempoolBlocks {
if (entry.uid != null) {
strippedMempool.set(entry.uid, {
uid: entry.uid,
fee: entry.fee + (entry.acceleration || 0),
fee: entry.fee + (accelerations[entry.txid] || 0),
weight: (entry.adjustedVsize * 4),
sigops: entry.sigops,
feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize,
@ -269,7 +272,7 @@ class MempoolBlocks {
return this.mempoolBlocks;
}
public async $updateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], saveResults: boolean = false): Promise<void> {
public async $updateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], accelerationDelta: string[] = [], saveResults: boolean = false): Promise<void> {
if (!this.txSelectionWorker) {
// need to reset the worker
await this.$makeBlockTemplates(newMempool, saveResults);
@ -278,17 +281,20 @@ class MempoolBlocks {
const start = Date.now();
for (const tx of Object.values(added)) {
const accelerations = mempool.getAccelerations();
const addedAndChanged: MempoolTransactionExtended[] = accelerationDelta.map(txid => newMempool[txid]).filter(tx => tx != null).concat(added);
for (const tx of addedAndChanged) {
this.setUid(tx);
}
const removedUids = removed.map(tx => this.getUid(tx)).filter(uid => uid != null) as number[];
// prepare a stripped down version of the mempool with only the minimum necessary data
// to reduce the overhead of passing this data to the worker thread
const addedStripped: CompactThreadTransaction[] = added.filter(entry => entry.uid != null).map(entry => {
const addedStripped: CompactThreadTransaction[] = addedAndChanged.filter(entry => entry.uid != null).map(entry => {
return {
uid: entry.uid || 0,
fee: entry.fee + (entry.acceleration || 0),
fee: entry.fee + (accelerations[entry.txid] || 0),
weight: (entry.adjustedVsize * 4),
sigops: entry.sigops,
feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize,
@ -450,12 +456,18 @@ class MempoolBlocks {
this.nextUid = 1;
}
private setUid(tx: MempoolTransactionExtended): number {
const uid = this.nextUid;
this.nextUid++;
this.uidMap.set(uid, tx.txid);
tx.uid = uid;
return uid;
// use reset=true to overwrite existing uids held by tx objects (required after resetUids)
private setUid(tx: MempoolTransactionExtended, reset = false): number {
let uid = reset ? null : this.getUid(tx);
if (uid == null) {
uid = this.nextUid;
this.nextUid++;
this.uidMap.set(uid, tx.txid);
tx.uid = uid;
return uid;
} else {
return uid;
}
}
private getUid(tx: MempoolTransactionExtended): number | void {

View File

@ -9,6 +9,7 @@ import loadingIndicators from './loading-indicators';
import bitcoinClient from './bitcoin/bitcoin-client';
import bitcoinSecondClient from './bitcoin/bitcoin-second-client';
import rbfCache from './rbf-cache';
import accelerationApi, { Acceleration } from './services/acceleration';
class Mempool {
private inSync: boolean = false;
@ -18,9 +19,9 @@ class Mempool {
private mempoolInfo: IBitcoinApi.MempoolInfo = { loaded: false, size: 0, bytes: 0, usage: 0, total_fee: 0,
maxmempool: 300000000, mempoolminfee: 0.00001000, minrelaytxfee: 0.00001000 };
private mempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[],
deletedTransactions: MempoolTransactionExtended[]) => void) | undefined;
deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => void) | undefined;
private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[],
deletedTransactions: MempoolTransactionExtended[]) => Promise<void>) | undefined;
deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => Promise<void>) | undefined;
private accelerations: { [txId: string]: number } = {};
@ -67,12 +68,12 @@ class Mempool {
}
public setMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; },
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => void): void {
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => void): void {
this.mempoolChangedCallback = fn;
}
public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; },
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => Promise<void>): void {
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => Promise<void>): void {
this.$asyncMempoolChangedCallback = fn;
}
@ -92,10 +93,10 @@ class Mempool {
}
}
if (this.mempoolChangedCallback) {
this.mempoolChangedCallback(this.mempoolCache, [], []);
this.mempoolChangedCallback(this.mempoolCache, [], [], []);
}
if (this.$asyncMempoolChangedCallback) {
await this.$asyncMempoolChangedCallback(this.mempoolCache, [], []);
await this.$asyncMempoolChangedCallback(this.mempoolCache, [], [], []);
}
this.addToSpendMap(Object.values(this.mempoolCache));
}
@ -231,20 +232,14 @@ class Mempool {
}
}
const accelerationDelta = await this.$updateAccelerations();
if (accelerationDelta.length) {
hasChange = true;
}
const newTransactionsStripped = newTransactions.map((tx) => Common.stripTransaction(tx));
this.latestTransactions = newTransactionsStripped.concat(this.latestTransactions).slice(0, 6);
const newAccelerations: { txid: string, delta: number }[] = [];
newTransactions.forEach(tx => {
if (tx.txid.startsWith('00')) {
const delta = Math.floor(Math.random() * 100000) + 100000;
newAccelerations.push({ txid: tx.txid, delta });
tx.acceleration = delta;
}
});
this.addAccelerations(newAccelerations);
this.removeAccelerations(deletedTransactions.map(tx => tx.txid));
if (!this.inSync && transactions.length === Object.keys(this.mempoolCache).length) {
this.inSync = true;
logger.notice('The mempool is now in sync!');
@ -254,11 +249,11 @@ class Mempool {
this.mempoolCacheDelta = Math.abs(transactions.length - Object.keys(this.mempoolCache).length);
if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) {
this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions);
this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions, accelerationDelta);
}
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, newTransactions, deletedTransactions, accelerationDelta);
this.updateTimerProgress(timer, 'completed async mempool callback');
}
@ -273,15 +268,37 @@ class Mempool {
return this.accelerations;
}
public addAccelerations(newAccelerations: { txid: string, delta: number }[]): void {
for (const acceleration of newAccelerations) {
this.accelerations[acceleration.txid] = acceleration.delta;
}
}
public async $updateAccelerations(): Promise<string[]> {
try {
const newAccelerations = await accelerationApi.fetchAccelerations$();
public removeAccelerations(txids: string[]): void {
for (const txid of txids) {
delete this.accelerations[txid];
const changed: string[] = [];
const newAccelerationMap: { [txid: string]: number } = {};
for (const acceleration of newAccelerations) {
newAccelerationMap[acceleration.txid] = acceleration.feeDelta;
if (this.accelerations[acceleration.txid] == null) {
// new acceleration
changed.push(acceleration.txid);
} else if (this.accelerations[acceleration.txid] !== acceleration.feeDelta) {
// feeDelta changed
changed.push(acceleration.txid);
}
}
for (const oldTxid of Object.keys(this.accelerations)) {
if (!newAccelerationMap[oldTxid]) {
// removed
changed.push(oldTxid);
}
}
this.accelerations = newAccelerationMap;
return changed;
} catch (e: any) {
logger.debug(`Failed to update accelerations: ` + (e instanceof Error ? e.message : e));
return [];
}
}

View File

@ -0,0 +1,20 @@
import { query } from '../../utils/axios-query';
import config from '../../config';
export interface Acceleration {
txid: string,
feeDelta: number,
}
class AccelerationApi {
public async fetchAccelerations$(): Promise<Acceleration[]> {
if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
const response = await query(`${config.MEMPOOL_SERVICES.API}/accelerations`);
return (response as Acceleration[]) || [];
} else {
return [];
}
}
}
export default new AccelerationApi();

View File

@ -303,7 +303,7 @@ class WebsocketHandler {
}
async $handleMempoolChange(newMempool: { [txid: string]: MempoolTransactionExtended },
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]): Promise<void> {
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]): Promise<void> {
if (!this.wss) {
throw new Error('WebSocket.Server is not set');
}
@ -311,7 +311,7 @@ class WebsocketHandler {
this.printLogs();
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, true);
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, accelerationDelta, true);
} else {
mempoolBlocks.updateMempoolBlocks(newMempool, true);
}
@ -625,8 +625,6 @@ class WebsocketHandler {
const da = difficultyAdjustment.getDifficultyAdjustment();
const fees = feeApi.getRecommendedFee();
memPool.removeAccelerations(txIds);
// update init data
this.updateInitData();