optimize cpfp indexing

This commit is contained in:
Mononaut 2022-11-28 17:56:50 +09:00
parent ab5308e1c8
commit f2ad184d1f
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E

View File

@ -27,6 +27,7 @@ import mining from './mining/mining';
import DifficultyAdjustmentsRepository from '../repositories/DifficultyAdjustmentsRepository'; import DifficultyAdjustmentsRepository from '../repositories/DifficultyAdjustmentsRepository';
import PricesRepository from '../repositories/PricesRepository'; import PricesRepository from '../repositories/PricesRepository';
import priceUpdater from '../tasks/price-updater'; import priceUpdater from '../tasks/price-updater';
import { Block } from 'bitcoinjs-lib';
class Blocks { class Blocks {
private blocks: BlockExtended[] = []; private blocks: BlockExtended[] = [];
@ -342,7 +343,7 @@ class Blocks {
for (const block of unindexedBlocks) { for (const block of unindexedBlocks) {
// Logging // Logging
const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); const elapsedSeconds = Math.max(1, new Date().getTime() / 1000 - timer);
if (elapsedSeconds > 5) { if (elapsedSeconds > 5) {
const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt));
const blockPerSeconds = Math.max(1, countThisRun / elapsedSeconds); const blockPerSeconds = Math.max(1, countThisRun / elapsedSeconds);
@ -352,10 +353,11 @@ class Blocks {
countThisRun = 0; countThisRun = 0;
} }
await this.$indexCPFP(block.hash); // Calculate and save CPFP data for transactions in this block await this.$indexCPFP(block.hash, block.height); // Calculate and save CPFP data for transactions in this block
// Logging // Logging
count++; count++;
countThisRun++;
} }
if (count > 0) { if (count > 0) {
logger.notice(`CPFP indexing completed: indexed ${count} blocks`); logger.notice(`CPFP indexing completed: indexed ${count} blocks`);
@ -411,7 +413,7 @@ class Blocks {
} }
++indexedThisRun; ++indexedThisRun;
++totalIndexed; ++totalIndexed;
const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); const elapsedSeconds = Math.max(1, new Date().getTime() / 1000 - timer);
if (elapsedSeconds > 5 || blockHeight === lastBlockToIndex) { if (elapsedSeconds > 5 || blockHeight === lastBlockToIndex) {
const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt));
const blockPerSeconds = Math.max(1, indexedThisRun / elapsedSeconds); const blockPerSeconds = Math.max(1, indexedThisRun / elapsedSeconds);
@ -518,7 +520,7 @@ class Blocks {
const newBlock = await this.$indexBlock(lastBlock['height'] - i); const newBlock = await this.$indexBlock(lastBlock['height'] - i);
await this.$getStrippedBlockTransactions(newBlock.id, true, true); await this.$getStrippedBlockTransactions(newBlock.id, true, true);
if (config.MEMPOOL.TRANSACTION_INDEXING) { if (config.MEMPOOL.TRANSACTION_INDEXING) {
await this.$indexCPFP(newBlock.id); await this.$indexCPFP(newBlock.id, lastBlock['height'] - i);
} }
} }
await mining.$indexDifficultyAdjustments(); await mining.$indexDifficultyAdjustments();
@ -546,7 +548,7 @@ class Blocks {
await this.$getStrippedBlockTransactions(blockExtended.id, true); await this.$getStrippedBlockTransactions(blockExtended.id, true);
} }
if (config.MEMPOOL.TRANSACTION_INDEXING) { if (config.MEMPOOL.TRANSACTION_INDEXING) {
this.$indexCPFP(blockExtended.id); this.$indexCPFP(blockExtended.id, this.currentBlockHeight);
} }
} }
} }
@ -738,23 +740,47 @@ class Blocks {
return this.currentBlockHeight; return this.currentBlockHeight;
} }
public async $indexCPFP(hash: string): Promise<void> { public async $indexCPFP(hash: string, height: number): Promise<void> {
const block = await bitcoinClient.getBlock(hash, 2); let transactions;
const transactions = block.tx; if (Common.blocksSummariesIndexingEnabled()) {
let cluster: IBitcoinApi.VerboseTransaction[] = []; transactions = await this.$getStrippedBlockTransactions(hash);
const rawBlock = await bitcoinClient.getBlock(hash, 0);
const block = Block.fromHex(rawBlock);
const txMap = {};
for (const tx of block.transactions || []) {
txMap[tx.getId()] = tx;
}
for (const tx of transactions) {
if (txMap[tx.txid]?.ins) {
tx.vin = txMap[tx.txid].ins.map(vin => {
return {
txid: vin.hash
};
});
}
}
} else {
const block = await bitcoinClient.getBlock(hash, 2);
transactions = block.tx.map(tx => {
tx.vsize = tx.weight / 4;
return tx;
});
}
let cluster: TransactionStripped[] = [];
let ancestors: { [txid: string]: boolean } = {}; let ancestors: { [txid: string]: boolean } = {};
for (let i = transactions.length - 1; i >= 0; i--) { for (let i = transactions.length - 1; i >= 0; i--) {
const tx = transactions[i]; const tx = transactions[i];
if (!ancestors[tx.txid]) { if (!ancestors[tx.txid]) {
let totalFee = 0; let totalFee = 0;
let totalWeight = 0; let totalVSize = 0;
cluster.forEach(tx => { cluster.forEach(tx => {
totalFee += tx?.fee || 0; totalFee += tx?.fee || 0;
totalWeight += tx.weight; totalVSize += tx.vsize;
}); });
const effectiveFeePerVsize = (totalFee * 100_000_000) / (totalWeight / 4); const effectiveFeePerVsize = (totalFee * 100_000_000) / totalVSize;
if (cluster.length > 1) { if (cluster.length > 1) {
await cpfpRepository.$saveCluster(block.height, cluster.map(tx => { return { txid: tx.txid, weight: tx.weight, fee: (tx.fee || 0) * 100_000_000 }; }), effectiveFeePerVsize); await cpfpRepository.$saveCluster(height, cluster.map(tx => { return { txid: tx.txid, weight: tx.vsize * 4, fee: (tx.fee || 0) * 100_000_000 }; }), effectiveFeePerVsize);
for (const tx of cluster) { for (const tx of cluster) {
await transactionRepository.$setCluster(tx.txid, cluster[0].txid); await transactionRepository.$setCluster(tx.txid, cluster[0].txid);
} }