mirror of
https://github.com/mempool/mempool.git
synced 2024-11-19 09:52:14 +01:00
Mini-miner based block cpfp calculations
This commit is contained in:
parent
27374bd131
commit
41c373c39d
@ -31,6 +31,7 @@ import rbfCache from './rbf-cache';
|
|||||||
import { calcBitsDifference } from './difficulty-adjustment';
|
import { calcBitsDifference } from './difficulty-adjustment';
|
||||||
import AccelerationRepository from '../repositories/AccelerationRepository';
|
import AccelerationRepository from '../repositories/AccelerationRepository';
|
||||||
import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp';
|
import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp';
|
||||||
|
import mempool from './mempool';
|
||||||
|
|
||||||
class Blocks {
|
class Blocks {
|
||||||
private blocks: BlockExtended[] = [];
|
private blocks: BlockExtended[] = [];
|
||||||
@ -602,13 +603,13 @@ class Blocks {
|
|||||||
|
|
||||||
for (let height = currentBlockHeight; height >= 0; height--) {
|
for (let height = currentBlockHeight; height >= 0; height--) {
|
||||||
try {
|
try {
|
||||||
let txs: TransactionExtended[] | null = null;
|
let txs: MempoolTransactionExtended[] | null = null;
|
||||||
if (unclassifiedBlocks[height]) {
|
if (unclassifiedBlocks[height]) {
|
||||||
const blockHash = unclassifiedBlocks[height];
|
const blockHash = unclassifiedBlocks[height];
|
||||||
// fetch transactions
|
// fetch transactions
|
||||||
txs = (await bitcoinApi.$getTxsForBlock(blockHash)).map(tx => transactionUtils.extendTransaction(tx)) || [];
|
txs = (await bitcoinApi.$getTxsForBlock(blockHash)).map(tx => transactionUtils.extendMempoolTransaction(tx)) || [];
|
||||||
// add CPFP
|
// add CPFP
|
||||||
const cpfpSummary = calculateFastBlockCpfp(height, txs, true);
|
const cpfpSummary = calculateGoodBlockCpfp(height, txs, []);
|
||||||
// classify
|
// classify
|
||||||
const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions);
|
const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions);
|
||||||
await BlocksSummariesRepository.$saveTransactions(height, blockHash, classifiedTxs, 1);
|
await BlocksSummariesRepository.$saveTransactions(height, blockHash, classifiedTxs, 1);
|
||||||
@ -637,7 +638,7 @@ class Blocks {
|
|||||||
}
|
}
|
||||||
templateTxs.push(tx || templateTx);
|
templateTxs.push(tx || templateTx);
|
||||||
}
|
}
|
||||||
const cpfpSummary = calculateFastBlockCpfp(height, templateTxs?.filter(tx => tx['effectiveFeePerVsize'] != null) as TransactionExtended[], true);
|
const cpfpSummary = calculateGoodBlockCpfp(height, templateTxs?.filter(tx => tx['effectiveFeePerVsize'] != null) as MempoolTransactionExtended[], []);
|
||||||
// classify
|
// classify
|
||||||
const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions);
|
const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions);
|
||||||
const classifiedTxMap: { [txid: string]: TransactionClassified } = {};
|
const classifiedTxMap: { [txid: string]: TransactionClassified } = {};
|
||||||
@ -891,7 +892,7 @@ class Blocks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const cpfpSummary: CpfpSummary = calculateGoodBlockCpfp(block.height, transactions);
|
const cpfpSummary: CpfpSummary = calculateGoodBlockCpfp(block.height, transactions, Object.values(mempool.getAccelerations()).map(a => ({ txid: a.txid, max_bid: a.feeDelta })));
|
||||||
const blockExtended: BlockExtended = await this.$getBlockExtended(block, cpfpSummary.transactions);
|
const blockExtended: BlockExtended = await this.$getBlockExtended(block, cpfpSummary.transactions);
|
||||||
const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, cpfpSummary.transactions);
|
const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, cpfpSummary.transactions);
|
||||||
this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`);
|
this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`);
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
import { CpfpCluster, CpfpInfo, CpfpSummary, MempoolTransactionExtended, TransactionExtended } from '../mempool.interfaces';
|
import { Ancestor, CpfpCluster, CpfpInfo, CpfpSummary, MempoolTransactionExtended, TransactionExtended } from '../mempool.interfaces';
|
||||||
import { GraphTx, convertToGraphTx, expandRelativesGraph, initializeRelatives, mempoolComparator, removeAncestors, setAncestorScores } from './mini-miner';
|
import { GraphTx, convertToGraphTx, expandRelativesGraph, initializeRelatives, makeBlockTemplate, mempoolComparator, removeAncestors, setAncestorScores } from './mini-miner';
|
||||||
import memPool from './mempool';
|
import memPool from './mempool';
|
||||||
|
import { Acceleration } from './acceleration';
|
||||||
|
|
||||||
const CPFP_UPDATE_INTERVAL = 60_000; // update CPFP info at most once per 60s per transaction
|
const CPFP_UPDATE_INTERVAL = 60_000; // update CPFP info at most once per 60s per transaction
|
||||||
const MAX_CLUSTER_ITERATIONS = 100;
|
const MAX_CLUSTER_ITERATIONS = 100;
|
||||||
@ -95,8 +96,70 @@ export function calculateFastBlockCpfp(height: number, transactions: Transaction
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
export function calculateGoodBlockCpfp(height: number, transactions: TransactionExtended[]): CpfpSummary {
|
export function calculateGoodBlockCpfp(height: number, transactions: MempoolTransactionExtended[], accelerations: Acceleration[]): CpfpSummary {
|
||||||
return calculateFastBlockCpfp(height, transactions, true);
|
const txMap: { [txid: string]: MempoolTransactionExtended } = {};
|
||||||
|
for (const tx of transactions) {
|
||||||
|
txMap[tx.txid] = tx;
|
||||||
|
}
|
||||||
|
const template = makeBlockTemplate(transactions, accelerations, 1, Infinity, Infinity);
|
||||||
|
const clusters = new Map<string, string[]>();
|
||||||
|
for (const tx of template) {
|
||||||
|
const cluster = tx.cluster || [];
|
||||||
|
const root = cluster.length ? cluster[cluster.length - 1] : null;
|
||||||
|
if (cluster.length > 1 && root && !clusters.has(root)) {
|
||||||
|
clusters.set(root, cluster);
|
||||||
|
}
|
||||||
|
txMap[tx.txid].effectiveFeePerVsize = tx.effectiveFeePerVsize;
|
||||||
|
}
|
||||||
|
|
||||||
|
const clusterArray: CpfpCluster[] = [];
|
||||||
|
|
||||||
|
for (const cluster of clusters.values()) {
|
||||||
|
for (const txid of cluster) {
|
||||||
|
const mempoolTx = txMap[txid];
|
||||||
|
if (mempoolTx) {
|
||||||
|
const ancestors: Ancestor[] = [];
|
||||||
|
const descendants: Ancestor[] = [];
|
||||||
|
let matched = false;
|
||||||
|
cluster.forEach(relativeTxid => {
|
||||||
|
if (relativeTxid === txid) {
|
||||||
|
matched = true;
|
||||||
|
} else {
|
||||||
|
const relative = {
|
||||||
|
txid: relativeTxid,
|
||||||
|
fee: txMap[relativeTxid].fee,
|
||||||
|
weight: (txMap[relativeTxid].adjustedVsize * 4) || txMap[relativeTxid].weight,
|
||||||
|
};
|
||||||
|
if (matched) {
|
||||||
|
descendants.push(relative);
|
||||||
|
} else {
|
||||||
|
ancestors.push(relative);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
if (mempoolTx.ancestors?.length !== ancestors.length || mempoolTx.descendants?.length !== descendants.length) {
|
||||||
|
mempoolTx.cpfpDirty = true;
|
||||||
|
}
|
||||||
|
Object.assign(mempoolTx, { ancestors, descendants, bestDescendant: null, cpfpChecked: true });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const root = cluster[cluster.length - 1];
|
||||||
|
clusterArray.push({
|
||||||
|
root: root,
|
||||||
|
height,
|
||||||
|
txs: cluster.reverse().map(txid => ({
|
||||||
|
txid,
|
||||||
|
fee: txMap[txid].fee,
|
||||||
|
weight: (txMap[txid].adjustedVsize * 4) || txMap[txid].weight,
|
||||||
|
})),
|
||||||
|
effectiveFeePerVsize: txMap[root].effectiveFeePerVsize,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
transactions: transactions.map(tx => txMap[tx.txid]),
|
||||||
|
clusters: clusterArray,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
Loading…
Reference in New Issue
Block a user