Refactor acceleration tracking
This commit is contained in:
parent
aa24f6a84d
commit
c246db1cf9
@ -5,6 +5,7 @@ import { Common, OnlineFeeStatsCalculator } from './common';
|
|||||||
import config from '../config';
|
import config from '../config';
|
||||||
import { Worker } from 'worker_threads';
|
import { Worker } from 'worker_threads';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
|
import mempool from './mempool';
|
||||||
|
|
||||||
const MAX_UINT32 = Math.pow(2, 32) - 1;
|
const MAX_UINT32 = Math.pow(2, 32) - 1;
|
||||||
|
|
||||||
@ -212,9 +213,11 @@ class MempoolBlocks {
|
|||||||
// reset mempool short ids
|
// reset mempool short ids
|
||||||
this.resetUids();
|
this.resetUids();
|
||||||
for (const tx of Object.values(newMempool)) {
|
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
|
// 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
|
// to reduce the overhead of passing this data to the worker thread
|
||||||
const strippedMempool: Map<number, CompactThreadTransaction> = new Map();
|
const strippedMempool: Map<number, CompactThreadTransaction> = new Map();
|
||||||
@ -222,7 +225,7 @@ class MempoolBlocks {
|
|||||||
if (entry.uid !== null && entry.uid !== undefined) {
|
if (entry.uid !== null && entry.uid !== undefined) {
|
||||||
const stripped = {
|
const stripped = {
|
||||||
uid: entry.uid,
|
uid: entry.uid,
|
||||||
fee: entry.fee + (entry.acceleration || 0),
|
fee: entry.fee + (accelerations[entry.txid] || 0),
|
||||||
weight: (entry.adjustedVsize * 4),
|
weight: (entry.adjustedVsize * 4),
|
||||||
sigops: entry.sigops,
|
sigops: entry.sigops,
|
||||||
feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize,
|
feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize,
|
||||||
@ -273,7 +276,7 @@ class MempoolBlocks {
|
|||||||
return this.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) {
|
if (!this.txSelectionWorker) {
|
||||||
// need to reset the worker
|
// need to reset the worker
|
||||||
await this.$makeBlockTemplates(newMempool, saveResults);
|
await this.$makeBlockTemplates(newMempool, saveResults);
|
||||||
@ -282,17 +285,20 @@ class MempoolBlocks {
|
|||||||
|
|
||||||
const start = Date.now();
|
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, true);
|
this.setUid(tx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const removedUids = removed.map(tx => this.getUid(tx)).filter(uid => uid != null) as number[];
|
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
|
// 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
|
// to reduce the overhead of passing this data to the worker thread
|
||||||
const addedStripped: CompactThreadTransaction[] = added.filter(entry => (entry.uid !== null && entry.uid !== undefined)).map(entry => {
|
const addedStripped: CompactThreadTransaction[] = addedAndChanged.filter(entry => entry.uid != null).map(entry => {
|
||||||
return {
|
return {
|
||||||
uid: entry.uid || 0,
|
uid: entry.uid || 0,
|
||||||
fee: entry.fee + (entry.acceleration || 0),
|
fee: entry.fee + (accelerations[entry.txid] || 0),
|
||||||
weight: (entry.adjustedVsize * 4),
|
weight: (entry.adjustedVsize * 4),
|
||||||
sigops: entry.sigops,
|
sigops: entry.sigops,
|
||||||
feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize,
|
feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize,
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
import config from '../config';
|
import config from '../config';
|
||||||
import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory';
|
import bitcoinApi from './bitcoin/bitcoin-api-factory';
|
||||||
import { MempoolTransactionExtended, TransactionExtended, VbytesPerSecond } from '../mempool.interfaces';
|
import { MempoolTransactionExtended, TransactionExtended, VbytesPerSecond } from '../mempool.interfaces';
|
||||||
import logger from '../logger';
|
import logger from '../logger';
|
||||||
import { Common } from './common';
|
import { Common } from './common';
|
||||||
@ -9,7 +9,7 @@ import loadingIndicators from './loading-indicators';
|
|||||||
import bitcoinClient from './bitcoin/bitcoin-client';
|
import bitcoinClient from './bitcoin/bitcoin-client';
|
||||||
import bitcoinSecondClient from './bitcoin/bitcoin-second-client';
|
import bitcoinSecondClient from './bitcoin/bitcoin-second-client';
|
||||||
import rbfCache from './rbf-cache';
|
import rbfCache from './rbf-cache';
|
||||||
import { IEsploraApi } from './bitcoin/esplora-api.interface';
|
import accelerationApi from './services/acceleration';
|
||||||
|
|
||||||
class Mempool {
|
class Mempool {
|
||||||
private inSync: boolean = false;
|
private inSync: boolean = false;
|
||||||
@ -19,9 +19,9 @@ class Mempool {
|
|||||||
private mempoolInfo: IBitcoinApi.MempoolInfo = { loaded: false, size: 0, bytes: 0, usage: 0, total_fee: 0,
|
private mempoolInfo: IBitcoinApi.MempoolInfo = { loaded: false, size: 0, bytes: 0, usage: 0, total_fee: 0,
|
||||||
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[], accelerationDelta: string[]) => void) | undefined;
|
||||||
private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, mempoolSize: number, newTransactions: MempoolTransactionExtended[],
|
private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, mempoolSize: number, newTransactions: MempoolTransactionExtended[],
|
||||||
deletedTransactions: MempoolTransactionExtended[]) => Promise<void>) | undefined;
|
deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => Promise<void>) | undefined;
|
||||||
|
|
||||||
private accelerations: { [txId: string]: number } = {};
|
private accelerations: { [txId: string]: number } = {};
|
||||||
|
|
||||||
@ -68,12 +68,12 @@ class Mempool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public setMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; },
|
public setMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; },
|
||||||
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => void): void {
|
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => void): void {
|
||||||
this.mempoolChangedCallback = fn;
|
this.mempoolChangedCallback = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; }, mempoolSize: number,
|
public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; }, mempoolSize: number,
|
||||||
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]) => Promise<void>): void {
|
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => Promise<void>): void {
|
||||||
this.$asyncMempoolChangedCallback = fn;
|
this.$asyncMempoolChangedCallback = fn;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -98,10 +98,10 @@ class Mempool {
|
|||||||
count++;
|
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, count, [], []);
|
await this.$asyncMempoolChangedCallback(this.mempoolCache, count, [], [], []);
|
||||||
}
|
}
|
||||||
this.addToSpendMap(Object.values(this.mempoolCache));
|
this.addToSpendMap(Object.values(this.mempoolCache));
|
||||||
}
|
}
|
||||||
@ -303,25 +303,19 @@ class Mempool {
|
|||||||
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);
|
||||||
|
|
||||||
const newAccelerations: { txid: string, delta: number }[] = [];
|
const accelerationDelta = await this.$updateAccelerations();
|
||||||
newTransactions.forEach(tx => {
|
if (accelerationDelta.length) {
|
||||||
if (tx.txid.startsWith('00')) {
|
hasChange = true;
|
||||||
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));
|
|
||||||
|
|
||||||
this.mempoolCacheDelta = Math.abs(transactions.length - newMempoolSize);
|
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, accelerationDelta);
|
||||||
}
|
}
|
||||||
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, newMempoolSize, newTransactions, deletedTransactions);
|
await this.$asyncMempoolChangedCallback(this.mempoolCache, newMempoolSize, newTransactions, deletedTransactions, accelerationDelta);
|
||||||
this.updateTimerProgress(timer, 'completed async mempool callback');
|
this.updateTimerProgress(timer, 'completed async mempool callback');
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -342,15 +336,37 @@ class Mempool {
|
|||||||
return this.accelerations;
|
return this.accelerations;
|
||||||
}
|
}
|
||||||
|
|
||||||
public addAccelerations(newAccelerations: { txid: string, delta: number }[]): void {
|
public async $updateAccelerations(): Promise<string[]> {
|
||||||
|
try {
|
||||||
|
const newAccelerations = await accelerationApi.fetchAccelerations$();
|
||||||
|
|
||||||
|
const changed: string[] = [];
|
||||||
|
|
||||||
|
const newAccelerationMap: { [txid: string]: number } = {};
|
||||||
for (const acceleration of newAccelerations) {
|
for (const acceleration of newAccelerations) {
|
||||||
this.accelerations[acceleration.txid] = acceleration.delta;
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public removeAccelerations(txids: string[]): void {
|
for (const oldTxid of Object.keys(this.accelerations)) {
|
||||||
for (const txid of txids) {
|
if (!newAccelerationMap[oldTxid]) {
|
||||||
delete this.accelerations[txid];
|
// 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 [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
20
backend/src/api/services/acceleration.ts
Normal file
20
backend/src/api/services/acceleration.ts
Normal 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();
|
@ -381,7 +381,7 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
async $handleMempoolChange(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number,
|
async $handleMempoolChange(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number,
|
||||||
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[]): Promise<void> {
|
newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]): Promise<void> {
|
||||||
if (!this.wss) {
|
if (!this.wss) {
|
||||||
throw new Error('WebSocket.Server is not set');
|
throw new Error('WebSocket.Server is not set');
|
||||||
}
|
}
|
||||||
@ -392,7 +392,7 @@ class WebsocketHandler {
|
|||||||
if (config.MEMPOOL.RUST_GBT) {
|
if (config.MEMPOOL.RUST_GBT) {
|
||||||
await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, mempoolSize, newTransactions, deletedTransactions);
|
await mempoolBlocks.$rustUpdateBlockTemplates(newMempool, mempoolSize, newTransactions, deletedTransactions);
|
||||||
} else {
|
} else {
|
||||||
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, true);
|
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, accelerationDelta, true);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mempoolBlocks.updateMempoolBlocks(newMempool, true);
|
mempoolBlocks.updateMempoolBlocks(newMempool, true);
|
||||||
@ -738,8 +738,6 @@ class WebsocketHandler {
|
|||||||
const fees = feeApi.getRecommendedFee();
|
const fees = feeApi.getRecommendedFee();
|
||||||
const mempoolInfo = memPool.getMempoolInfo();
|
const mempoolInfo = memPool.getMempoolInfo();
|
||||||
|
|
||||||
memPool.removeAccelerations(txIds);
|
|
||||||
|
|
||||||
// update init data
|
// update init data
|
||||||
this.updateSocketDataFields({
|
this.updateSocketDataFields({
|
||||||
'mempoolInfo': mempoolInfo,
|
'mempoolInfo': mempoolInfo,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user