Refactor accelerated audits
This commit is contained in:
parent
6af6274f43
commit
77b0a8eccc
@ -5,7 +5,7 @@ import { TransactionExtended, MempoolBlockWithTransactions } from '../mempool.in
|
|||||||
const PROPAGATION_MARGIN = 180; // in seconds, time since a transaction is first seen after which it is assumed to have propagated to all miners
|
const PROPAGATION_MARGIN = 180; // in seconds, time since a transaction is first seen after which it is assumed to have propagated to all miners
|
||||||
|
|
||||||
class Audit {
|
class Audit {
|
||||||
auditBlock(transactions: TransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: TransactionExtended })
|
auditBlock(transactions: TransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: TransactionExtended }, useAccelerations: boolean = false)
|
||||||
: { censored: string[], added: string[], fresh: string[], sigop: string[], accelerated: string[], score: number, similarity: number } {
|
: { censored: string[], added: string[], fresh: string[], sigop: string[], accelerated: string[], score: number, similarity: number } {
|
||||||
if (!projectedBlocks?.[0]?.transactionIds || !mempool) {
|
if (!projectedBlocks?.[0]?.transactionIds || !mempool) {
|
||||||
return { censored: [], added: [], fresh: [], sigop: [], accelerated: [], score: 0, similarity: 1 };
|
return { censored: [], added: [], fresh: [], sigop: [], accelerated: [], score: 0, similarity: 1 };
|
||||||
@ -27,7 +27,7 @@ class Audit {
|
|||||||
const now = Math.round((Date.now() / 1000));
|
const now = Math.round((Date.now() / 1000));
|
||||||
for (const tx of transactions) {
|
for (const tx of transactions) {
|
||||||
inBlock[tx.txid] = tx;
|
inBlock[tx.txid] = tx;
|
||||||
if (tx.acceleration) {
|
if (mempool[tx.txid] && mempool[tx.txid].acceleration) {
|
||||||
accelerated.push(tx.txid);
|
accelerated.push(tx.txid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -206,7 +206,7 @@ class MempoolBlocks {
|
|||||||
return mempoolBlockDeltas;
|
return mempoolBlockDeltas;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $makeBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, saveResults: boolean = false): Promise<MempoolBlockWithTransactions[]> {
|
public async $makeBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, saveResults: boolean = false, useAccelerations: boolean = false): Promise<MempoolBlockWithTransactions[]> {
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
|
|
||||||
// reset mempool short ids
|
// reset mempool short ids
|
||||||
@ -215,7 +215,7 @@ class MempoolBlocks {
|
|||||||
this.setUid(tx, true);
|
this.setUid(tx, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
const accelerations = mempool.getAccelerations();
|
const accelerations = useAccelerations ? 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
|
||||||
@ -224,7 +224,7 @@ class MempoolBlocks {
|
|||||||
if (entry.uid != null) {
|
if (entry.uid != null) {
|
||||||
strippedMempool.set(entry.uid, {
|
strippedMempool.set(entry.uid, {
|
||||||
uid: entry.uid,
|
uid: entry.uid,
|
||||||
fee: entry.fee + (accelerations[entry.txid] || 0),
|
fee: entry.fee + (useAccelerations ? (accelerations[entry.txid] || 0) : 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,
|
||||||
@ -263,7 +263,7 @@ class MempoolBlocks {
|
|||||||
// clean up thread error listener
|
// clean up thread error listener
|
||||||
this.txSelectionWorker?.removeListener('error', threadErrorListener);
|
this.txSelectionWorker?.removeListener('error', threadErrorListener);
|
||||||
|
|
||||||
const processed = this.processBlockTemplates(newMempool, blocks, rates, clusters, saveResults);
|
const processed = this.processBlockTemplates(newMempool, blocks, rates, clusters, accelerations, saveResults);
|
||||||
logger.debug(`makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`);
|
logger.debug(`makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`);
|
||||||
return processed;
|
return processed;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@ -272,17 +272,17 @@ class MempoolBlocks {
|
|||||||
return this.mempoolBlocks;
|
return this.mempoolBlocks;
|
||||||
}
|
}
|
||||||
|
|
||||||
public async $updateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], accelerationDelta: string[] = [], saveResults: boolean = false): Promise<void> {
|
public async $updateBlockTemplates(newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], accelerationDelta: string[] = [], saveResults: boolean = false, useAccelerations: 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, useAccelerations);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const start = Date.now();
|
const start = Date.now();
|
||||||
|
|
||||||
const accelerations = mempool.getAccelerations();
|
const accelerations = useAccelerations ? mempool.getAccelerations() : {};
|
||||||
const addedAndChanged: MempoolTransactionExtended[] = accelerationDelta.map(txid => newMempool[txid]).filter(tx => tx != null).concat(added);
|
const addedAndChanged: MempoolTransactionExtended[] = useAccelerations ? accelerationDelta.map(txid => newMempool[txid]).filter(tx => tx != null).concat(added) : added;
|
||||||
|
|
||||||
for (const tx of addedAndChanged) {
|
for (const tx of addedAndChanged) {
|
||||||
this.setUid(tx);
|
this.setUid(tx);
|
||||||
@ -294,7 +294,7 @@ class MempoolBlocks {
|
|||||||
const addedStripped: CompactThreadTransaction[] = addedAndChanged.filter(entry => entry.uid != null).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 + (accelerations[entry.txid] || 0),
|
fee: entry.fee + (useAccelerations ? (accelerations[entry.txid] || 0) : 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,
|
||||||
@ -321,14 +321,14 @@ class MempoolBlocks {
|
|||||||
// clean up thread error listener
|
// clean up thread error listener
|
||||||
this.txSelectionWorker?.removeListener('error', threadErrorListener);
|
this.txSelectionWorker?.removeListener('error', threadErrorListener);
|
||||||
|
|
||||||
this.processBlockTemplates(newMempool, blocks, rates, clusters, saveResults);
|
this.processBlockTemplates(newMempool, blocks, rates, clusters, accelerations, saveResults);
|
||||||
logger.debug(`updateBlockTemplates completed in ${(Date.now() - start) / 1000} seconds`);
|
logger.debug(`updateBlockTemplates completed in ${(Date.now() - start) / 1000} seconds`);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.err('updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e));
|
logger.err('updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private processBlockTemplates(mempool, blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }, saveResults): MempoolBlockWithTransactions[] {
|
private processBlockTemplates(mempool, blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }, accelerations, saveResults): MempoolBlockWithTransactions[] {
|
||||||
for (const txid of Object.keys(rates)) {
|
for (const txid of Object.keys(rates)) {
|
||||||
if (txid in mempool) {
|
if (txid in mempool) {
|
||||||
mempool[txid].effectiveFeePerVsize = rates[txid];
|
mempool[txid].effectiveFeePerVsize = rates[txid];
|
||||||
@ -367,6 +367,8 @@ class MempoolBlocks {
|
|||||||
};
|
};
|
||||||
mempoolTx.cpfpChecked = true;
|
mempoolTx.cpfpChecked = true;
|
||||||
|
|
||||||
|
mempoolTx.acceleration = accelerations[txid];
|
||||||
|
|
||||||
// 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 === blocks.length - 1 && feeStatsCalculator) {
|
||||||
feeStatsCalculator.processNext(mempoolTx);
|
feeStatsCalculator.processNext(mempoolTx);
|
||||||
|
@ -274,7 +274,7 @@ class Mempool {
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const newAccelerations = await accelerationApi.fetchAccelerations$();
|
const newAccelerations = await accelerationApi.$fetchAccelerations();
|
||||||
|
|
||||||
const changed: string[] = [];
|
const changed: string[] = [];
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { query } from '../../utils/axios-query';
|
import { query } from '../../utils/axios-query';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
import { BlockExtended, PoolTag } from '../../mempool.interfaces';
|
||||||
|
|
||||||
export interface Acceleration {
|
export interface Acceleration {
|
||||||
txid: string,
|
txid: string,
|
||||||
@ -7,7 +8,7 @@ export interface Acceleration {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class AccelerationApi {
|
class AccelerationApi {
|
||||||
public async fetchAccelerations$(): Promise<Acceleration[]> {
|
public async $fetchAccelerations(): Promise<Acceleration[]> {
|
||||||
if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
|
if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
|
||||||
const response = await query(`${config.MEMPOOL_SERVICES.API}/accelerations`);
|
const response = await query(`${config.MEMPOOL_SERVICES.API}/accelerations`);
|
||||||
return (response as Acceleration[]) || [];
|
return (response as Acceleration[]) || [];
|
||||||
@ -15,6 +16,23 @@ class AccelerationApi {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $fetchPools(): Promise<PoolTag[]> {
|
||||||
|
if (config.MEMPOOL_SERVICES.ACCELERATIONS) {
|
||||||
|
const response = await query(`${config.MEMPOOL_SERVICES.API}/partners`);
|
||||||
|
return (response as PoolTag[]) || [];
|
||||||
|
} else {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $isAcceleratedBlock(block: BlockExtended): Promise<boolean> {
|
||||||
|
const pools = await this.$fetchPools();
|
||||||
|
if (block?.extras?.pool?.id == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return pools.reduce((match, tag) => match || tag.uniqueId === block.extras.pool.id, false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new AccelerationApi();
|
export default new AccelerationApi();
|
@ -21,7 +21,7 @@ import Audit from './audit';
|
|||||||
import { deepClone } from '../utils/clone';
|
import { deepClone } from '../utils/clone';
|
||||||
import priceUpdater from '../tasks/price-updater';
|
import priceUpdater from '../tasks/price-updater';
|
||||||
import { ApiPrice } from '../repositories/PricesRepository';
|
import { ApiPrice } from '../repositories/PricesRepository';
|
||||||
import mempool from './mempool';
|
import accelerationApi from './services/acceleration';
|
||||||
|
|
||||||
class WebsocketHandler {
|
class WebsocketHandler {
|
||||||
private wss: WebSocket.Server | undefined;
|
private wss: WebSocket.Server | undefined;
|
||||||
@ -311,7 +311,7 @@ class WebsocketHandler {
|
|||||||
this.printLogs();
|
this.printLogs();
|
||||||
|
|
||||||
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
|
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
|
||||||
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, accelerationDelta, true);
|
await mempoolBlocks.$updateBlockTemplates(newMempool, newTransactions, deletedTransactions, accelerationDelta, true, config.MEMPOOL_SERVICES.ACCELERATIONS);
|
||||||
} else {
|
} else {
|
||||||
mempoolBlocks.updateMempoolBlocks(newMempool, true);
|
mempoolBlocks.updateMempoolBlocks(newMempool, true);
|
||||||
}
|
}
|
||||||
@ -545,18 +545,23 @@ class WebsocketHandler {
|
|||||||
if (config.MEMPOOL.AUDIT) {
|
if (config.MEMPOOL.AUDIT) {
|
||||||
let projectedBlocks;
|
let projectedBlocks;
|
||||||
let auditMempool = _memPool;
|
let auditMempool = _memPool;
|
||||||
|
const isAccelerated = config.MEMPOOL_SERVICES.ACCELERATIONS && await accelerationApi.$isAcceleratedBlock(block);
|
||||||
// template calculation functions have mempool side effects, so calculate audits using
|
// template calculation functions have mempool side effects, so calculate audits using
|
||||||
// a cloned copy of the mempool if we're running a different algorithm for mempool updates
|
// a cloned copy of the mempool if we're running a different algorithm for mempool updates
|
||||||
const separateAudit = config.MEMPOOL.ADVANCED_GBT_AUDIT !== config.MEMPOOL.ADVANCED_GBT_MEMPOOL;
|
const separateAudit = config.MEMPOOL.ADVANCED_GBT_AUDIT !== config.MEMPOOL.ADVANCED_GBT_MEMPOOL;
|
||||||
if (separateAudit) {
|
if (separateAudit) {
|
||||||
auditMempool = deepClone(_memPool);
|
auditMempool = deepClone(_memPool);
|
||||||
if (config.MEMPOOL.ADVANCED_GBT_AUDIT) {
|
if (config.MEMPOOL.ADVANCED_GBT_AUDIT) {
|
||||||
projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false);
|
projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false, isAccelerated);
|
||||||
} else {
|
} else {
|
||||||
projectedBlocks = mempoolBlocks.updateMempoolBlocks(auditMempool, false);
|
projectedBlocks = mempoolBlocks.updateMempoolBlocks(auditMempool, false);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
projectedBlocks = mempoolBlocks.getMempoolBlocksWithTransactions();
|
if ((config.MEMPOOL_SERVICES.ACCELERATIONS && !isAccelerated)) {
|
||||||
|
projectedBlocks = await mempoolBlocks.$makeBlockTemplates(auditMempool, false, isAccelerated);
|
||||||
|
} else {
|
||||||
|
projectedBlocks = mempoolBlocks.getMempoolBlocksWithTransactions();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Common.indexingEnabled() && memPool.isInSync()) {
|
if (Common.indexingEnabled() && memPool.isInSync()) {
|
||||||
@ -615,7 +620,7 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
|
if (config.MEMPOOL.ADVANCED_GBT_MEMPOOL) {
|
||||||
await mempoolBlocks.$makeBlockTemplates(_memPool, true);
|
await mempoolBlocks.$makeBlockTemplates(_memPool, true, config.MEMPOOL_SERVICES.ACCELERATIONS);
|
||||||
} else {
|
} else {
|
||||||
mempoolBlocks.updateMempoolBlocks(_memPool, true);
|
mempoolBlocks.updateMempoolBlocks(_memPool, true);
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user