Estimate accelerated positions in partner mempools
This commit is contained in:
parent
e4d92c8fe0
commit
ccc127c84a
@ -6,6 +6,7 @@ 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';
|
import mempool from './mempool';
|
||||||
|
import { Acceleration } from './services/acceleration';
|
||||||
|
|
||||||
const MAX_UINT32 = Math.pow(2, 32) - 1;
|
const MAX_UINT32 = Math.pow(2, 32) - 1;
|
||||||
|
|
||||||
@ -452,7 +453,7 @@ class MempoolBlocks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private processBlockTemplates(mempool: { [txid: string]: MempoolTransactionExtended }, blocks: string[][], blockWeights: number[] | null, rates: [string, number][], clusters: string[][], accelerations, accelerationPool, saveResults): MempoolBlockWithTransactions[] {
|
private processBlockTemplates(mempool: { [txid: string]: MempoolTransactionExtended }, blocks: string[][], blockWeights: number[] | null, rates: [string, number][], clusters: string[][], accelerations: { [txid: string]: Acceleration }, accelerationPool, saveResults): MempoolBlockWithTransactions[] {
|
||||||
for (const [txid, rate] of rates) {
|
for (const [txid, rate] of rates) {
|
||||||
if (txid in mempool) {
|
if (txid in mempool) {
|
||||||
mempool[txid].cpfpDirty = (rate !== mempool[txid].effectiveFeePerVsize);
|
mempool[txid].cpfpDirty = (rate !== mempool[txid].effectiveFeePerVsize);
|
||||||
@ -586,7 +587,7 @@ class MempoolBlocks {
|
|||||||
const deltas = this.calculateMempoolDeltas(this.mempoolBlocks, mempoolBlocks);
|
const deltas = this.calculateMempoolDeltas(this.mempoolBlocks, mempoolBlocks);
|
||||||
this.mempoolBlocks = mempoolBlocks;
|
this.mempoolBlocks = mempoolBlocks;
|
||||||
this.mempoolBlockDeltas = deltas;
|
this.mempoolBlockDeltas = deltas;
|
||||||
|
this.updateAccelerationPositions(mempool, accelerations, mempoolBlocks);
|
||||||
}
|
}
|
||||||
|
|
||||||
return mempoolBlocks;
|
return mempoolBlocks;
|
||||||
@ -691,6 +692,94 @@ class MempoolBlocks {
|
|||||||
});
|
});
|
||||||
return { blocks: convertedBlocks, blockWeights, rates: convertedRates, clusters: convertedClusters, overflow: convertedOverflow };
|
return { blocks: convertedBlocks, blockWeights, rates: convertedRates, clusters: convertedClusters, overflow: convertedOverflow };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// estimates and saves positions of accelerations in mining partner mempools
|
||||||
|
private updateAccelerationPositions(mempoolCache: { [txid: string]: MempoolTransactionExtended }, accelerations: { [txid: string]: Acceleration }, mempoolBlocks: MempoolBlockWithTransactions[]): void {
|
||||||
|
const accelerationPositions: { [txid: string]: { [pool: string]: { block: number, vbytes: number } } } = {};
|
||||||
|
// keep track of simulated mempool blocks for each active pool
|
||||||
|
const pools: {
|
||||||
|
[pool: string]: { block: number, vsize: number, accelerations: string[] };
|
||||||
|
} = {};
|
||||||
|
// prepare a list of accelerations in ascending order (we'll pop items off the end of the list)
|
||||||
|
const accQueue: { acceleration: Acceleration, rate: number, vsize: number }[] = Object.values(accelerations).map(acc => {
|
||||||
|
let vsize = mempoolCache[acc.txid].vsize;
|
||||||
|
for (const ancestor of mempoolCache[acc.txid].ancestors || []) {
|
||||||
|
vsize += (ancestor.weight / 4);
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
acceleration: acc,
|
||||||
|
rate: mempoolCache[acc.txid].effectiveFeePerVsize,
|
||||||
|
vsize
|
||||||
|
};
|
||||||
|
}).sort((a, b) => a.rate - b.rate);
|
||||||
|
// initialize the pool tracker
|
||||||
|
for (const { acceleration } of accQueue) {
|
||||||
|
accelerationPositions[acceleration.txid] = {};
|
||||||
|
for (const pool of acceleration.pools) {
|
||||||
|
if (!pools[pool]) {
|
||||||
|
pools[pool] = {
|
||||||
|
block: 0,
|
||||||
|
vsize: 0,
|
||||||
|
accelerations: [],
|
||||||
|
};
|
||||||
|
}
|
||||||
|
pools[pool].accelerations.push(acceleration.txid);
|
||||||
|
}
|
||||||
|
for (const ancestor of mempoolCache[acceleration.txid].ancestors || []) {
|
||||||
|
accelerationPositions[ancestor.txid] = {};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let block = 0;
|
||||||
|
let index = 0;
|
||||||
|
let next = accQueue.pop();
|
||||||
|
// build simulated blocks for each pool by taking the best option from
|
||||||
|
// either the mempool or the list of accelerations.
|
||||||
|
while (next && block < mempoolBlocks.length) {
|
||||||
|
while (next && index < mempoolBlocks[block].transactions.length) {
|
||||||
|
const nextTx = mempoolBlocks[block].transactions[index];
|
||||||
|
if (next.rate >= (nextTx.rate || (nextTx.fee / nextTx.vsize))) {
|
||||||
|
for (const pool of next.acceleration.pools) {
|
||||||
|
if (pools[pool].vsize + next.vsize <= 999_000) {
|
||||||
|
pools[pool].vsize += next.vsize;
|
||||||
|
} else {
|
||||||
|
pools[pool].block++;
|
||||||
|
pools[pool].vsize = next.vsize;
|
||||||
|
}
|
||||||
|
// insert the acceleration into matching pool's blocks
|
||||||
|
accelerationPositions[next.acceleration.txid][pool] = {
|
||||||
|
block: pools[pool].block,
|
||||||
|
vbytes: pools[pool].vsize - (next.vsize / 2),
|
||||||
|
};
|
||||||
|
// and any accelerated ancestors
|
||||||
|
for (const ancestor of mempoolCache[next.acceleration.txid].ancestors || []) {
|
||||||
|
accelerationPositions[ancestor.txid][pool] = {
|
||||||
|
block: pools[pool].block,
|
||||||
|
vbytes: pools[pool].vsize - (next.vsize / 2),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
next = accQueue.pop();
|
||||||
|
} else {
|
||||||
|
// skip accelerated transactions and their CPFP ancestors
|
||||||
|
if (accelerationPositions[nextTx.txid] == null) {
|
||||||
|
// insert into all pools' blocks
|
||||||
|
for (const pool of Object.keys(pools)) {
|
||||||
|
if (pools[pool].vsize + nextTx.vsize <= 999_000) {
|
||||||
|
pools[pool].vsize += nextTx.vsize;
|
||||||
|
} else {
|
||||||
|
pools[pool].block++;
|
||||||
|
pools[pool].vsize = nextTx.vsize;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
index++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
block++;
|
||||||
|
index = 0;
|
||||||
|
}
|
||||||
|
mempool.setAccelerationPositions(accelerationPositions);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new MempoolBlocks();
|
export default new MempoolBlocks();
|
||||||
|
@ -25,6 +25,7 @@ class Mempool {
|
|||||||
deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => Promise<void>) | undefined;
|
deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => Promise<void>) | undefined;
|
||||||
|
|
||||||
private accelerations: { [txId: string]: Acceleration } = {};
|
private accelerations: { [txId: string]: Acceleration } = {};
|
||||||
|
private accelerationPositions: { [txid: string]: { [pool: number]: { block: number, vbytes: number } } } = {};
|
||||||
|
|
||||||
private txPerSecondArray: number[] = [];
|
private txPerSecondArray: number[] = [];
|
||||||
private txPerSecond: number = 0;
|
private txPerSecond: number = 0;
|
||||||
@ -431,6 +432,14 @@ class Mempool {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
setAccelerationPositions(positions: { [txid: string]: { [pool: number]: { block: number, vbytes: number } } }): void {
|
||||||
|
this.accelerationPositions = positions;
|
||||||
|
}
|
||||||
|
|
||||||
|
getAccelerationPositions(txid: string): { [pool: number]: { block: number, vbytes: number } } | undefined {
|
||||||
|
return this.accelerationPositions[txid];
|
||||||
|
}
|
||||||
|
|
||||||
private startTimer() {
|
private startTimer() {
|
||||||
const state: any = {
|
const state: any = {
|
||||||
start: Date.now(),
|
start: Date.now(),
|
||||||
|
@ -7,6 +7,14 @@ export interface Acceleration {
|
|||||||
txid: string,
|
txid: string,
|
||||||
feeDelta: number,
|
feeDelta: number,
|
||||||
pools: number[],
|
pools: number[],
|
||||||
|
effectiveFee: number;
|
||||||
|
effectiveVsize: number;
|
||||||
|
positions?: {
|
||||||
|
[pool: number]: {
|
||||||
|
block: number,
|
||||||
|
vbytes: number,
|
||||||
|
},
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
class AccelerationApi {
|
class AccelerationApi {
|
||||||
|
@ -192,7 +192,8 @@ class WebsocketHandler {
|
|||||||
}
|
}
|
||||||
response['txPosition'] = JSON.stringify({
|
response['txPosition'] = JSON.stringify({
|
||||||
txid: trackTxid,
|
txid: trackTxid,
|
||||||
position
|
position,
|
||||||
|
accelerationPositions: memPool.getAccelerationPositions(tx.txid),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
@ -674,7 +675,8 @@ class WebsocketHandler {
|
|||||||
position: {
|
position: {
|
||||||
...mempoolTx.position,
|
...mempoolTx.position,
|
||||||
accelerated: mempoolTx.acceleration || undefined,
|
accelerated: mempoolTx.acceleration || undefined,
|
||||||
}
|
},
|
||||||
|
accelerationPositions: memPool.getAccelerationPositions(mempoolTx.txid),
|
||||||
};
|
};
|
||||||
if (mempoolTx.cpfpDirty) {
|
if (mempoolTx.cpfpDirty) {
|
||||||
positionData['cpfp'] = {
|
positionData['cpfp'] = {
|
||||||
@ -684,7 +686,7 @@ class WebsocketHandler {
|
|||||||
effectiveFeePerVsize: mempoolTx.effectiveFeePerVsize || null,
|
effectiveFeePerVsize: mempoolTx.effectiveFeePerVsize || null,
|
||||||
sigops: mempoolTx.sigops,
|
sigops: mempoolTx.sigops,
|
||||||
adjustedVsize: mempoolTx.adjustedVsize,
|
adjustedVsize: mempoolTx.adjustedVsize,
|
||||||
acceleration: mempoolTx.acceleration
|
acceleration: mempoolTx.acceleration,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
response['txPosition'] = JSON.stringify(positionData);
|
response['txPosition'] = JSON.stringify(positionData);
|
||||||
@ -896,7 +898,8 @@ class WebsocketHandler {
|
|||||||
position: {
|
position: {
|
||||||
...mempoolTx.position,
|
...mempoolTx.position,
|
||||||
accelerated: mempoolTx.acceleration || undefined,
|
accelerated: mempoolTx.acceleration || undefined,
|
||||||
}
|
},
|
||||||
|
accelerationPositions: memPool.getAccelerationPositions(mempoolTx.txid),
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user