Implement CPFP reindexing using mini-miner method (not activated)
This commit is contained in:
parent
9aac0ddce7
commit
398593828f
@ -32,6 +32,7 @@ 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';
|
import mempool from './mempool';
|
||||||
|
import CpfpRepository from '../repositories/CpfpRepository';
|
||||||
|
|
||||||
class Blocks {
|
class Blocks {
|
||||||
private blocks: BlockExtended[] = [];
|
private blocks: BlockExtended[] = [];
|
||||||
@ -569,8 +570,11 @@ class Blocks {
|
|||||||
const blockchainInfo = await bitcoinClient.getBlockchainInfo();
|
const blockchainInfo = await bitcoinClient.getBlockchainInfo();
|
||||||
const currentBlockHeight = blockchainInfo.blocks;
|
const currentBlockHeight = blockchainInfo.blocks;
|
||||||
|
|
||||||
const unclassifiedBlocksList = await BlocksSummariesRepository.$getSummariesWithVersion(0);
|
const targetSummaryVersion: number = 1;
|
||||||
const unclassifiedTemplatesList = await BlocksSummariesRepository.$getTemplatesWithVersion(0);
|
const targetTemplateVersion: number = 1;
|
||||||
|
|
||||||
|
const unclassifiedBlocksList = await BlocksSummariesRepository.$getSummariesBelowVersion(targetSummaryVersion);
|
||||||
|
const unclassifiedTemplatesList = await BlocksSummariesRepository.$getTemplatesBelowVersion(targetTemplateVersion);
|
||||||
|
|
||||||
// nothing to do
|
// nothing to do
|
||||||
if (!unclassifiedBlocksList?.length && !unclassifiedTemplatesList?.length) {
|
if (!unclassifiedBlocksList?.length && !unclassifiedTemplatesList?.length) {
|
||||||
@ -612,7 +616,15 @@ class Blocks {
|
|||||||
const cpfpSummary = calculateGoodBlockCpfp(height, txs, []);
|
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, 2);
|
||||||
|
if (unclassifiedBlocks[height].version < 2 && targetSummaryVersion === 2) {
|
||||||
|
const cpfpClusters = await CpfpRepository.$getClustersAt(height);
|
||||||
|
if (!cpfpRepository.compareClusters(cpfpClusters, cpfpSummary.clusters)) {
|
||||||
|
// CPFP clusters changed - update the compact_cpfp tables
|
||||||
|
await CpfpRepository.$deleteClustersAt(height);
|
||||||
|
await this.$saveCpfp(blockHash, height, cpfpSummary);
|
||||||
|
}
|
||||||
|
}
|
||||||
await Common.sleep$(250);
|
await Common.sleep$(250);
|
||||||
}
|
}
|
||||||
if (unclassifiedTemplates[height]) {
|
if (unclassifiedTemplates[height]) {
|
||||||
|
@ -114,6 +114,43 @@ class BlocksSummariesRepository {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $getSummariesBelowVersion(version: number): Promise<{ height: number, id: string, version: number }[]> {
|
||||||
|
try {
|
||||||
|
const [rows]: any[] = await DB.query(`
|
||||||
|
SELECT
|
||||||
|
height,
|
||||||
|
id,
|
||||||
|
version
|
||||||
|
FROM blocks_summaries
|
||||||
|
WHERE version < ?
|
||||||
|
ORDER BY height DESC;`, [version]);
|
||||||
|
return rows;
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Cannot get block summaries below version. Reason: ` + (e instanceof Error ? e.message : e));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
public async $getTemplatesBelowVersion(version: number): Promise<{ height: number, id: string, version: number }[]> {
|
||||||
|
try {
|
||||||
|
const [rows]: any[] = await DB.query(`
|
||||||
|
SELECT
|
||||||
|
blocks_summaries.height as height,
|
||||||
|
blocks_templates.id as id,
|
||||||
|
blocks_templates.version as version
|
||||||
|
FROM blocks_templates
|
||||||
|
JOIN blocks_summaries ON blocks_templates.id = blocks_summaries.id
|
||||||
|
WHERE blocks_templates.version < ?
|
||||||
|
ORDER BY height DESC;`, [version]);
|
||||||
|
return rows;
|
||||||
|
} catch (e) {
|
||||||
|
logger.err(`Cannot get block summaries below version. Reason: ` + (e instanceof Error ? e.message : e));
|
||||||
|
}
|
||||||
|
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the fee percentiles if the block has already been indexed, [] otherwise
|
* Get the fee percentiles if the block has already been indexed, [] otherwise
|
||||||
*
|
*
|
||||||
|
@ -91,6 +91,26 @@ class CpfpRepository {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $getClustersAt(height: number): Promise<CpfpCluster[]> {
|
||||||
|
const [clusterRows]: any = await DB.query(
|
||||||
|
`
|
||||||
|
SELECT *
|
||||||
|
FROM compact_cpfp_clusters
|
||||||
|
WHERE height = ?
|
||||||
|
`,
|
||||||
|
[height]
|
||||||
|
);
|
||||||
|
return clusterRows.map(cluster => {
|
||||||
|
if (cluster?.txs) {
|
||||||
|
cluster.effectiveFeePerVsize = cluster.fee_rate;
|
||||||
|
cluster.txs = this.unpack(cluster.txs);
|
||||||
|
return cluster;
|
||||||
|
} else {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}).filter(cluster => cluster !== null);
|
||||||
|
}
|
||||||
|
|
||||||
public async $deleteClustersFrom(height: number): Promise<void> {
|
public async $deleteClustersFrom(height: number): Promise<void> {
|
||||||
logger.info(`Delete newer cpfp clusters from height ${height} from the database`);
|
logger.info(`Delete newer cpfp clusters from height ${height} from the database`);
|
||||||
try {
|
try {
|
||||||
@ -122,6 +142,37 @@ class CpfpRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async $deleteClustersAt(height: number): Promise<void> {
|
||||||
|
logger.info(`Delete cpfp clusters at height ${height} from the database`);
|
||||||
|
try {
|
||||||
|
const [rows] = await DB.query(
|
||||||
|
`
|
||||||
|
SELECT txs, height, root from compact_cpfp_clusters
|
||||||
|
WHERE height = ?
|
||||||
|
`,
|
||||||
|
[height]
|
||||||
|
) as RowDataPacket[][];
|
||||||
|
if (rows?.length) {
|
||||||
|
for (const clusterToDelete of rows) {
|
||||||
|
const txs = this.unpack(clusterToDelete?.txs);
|
||||||
|
for (const tx of txs) {
|
||||||
|
await transactionRepository.$removeTransaction(tx.txid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await DB.query(
|
||||||
|
`
|
||||||
|
DELETE from compact_cpfp_clusters
|
||||||
|
WHERE height = ?
|
||||||
|
`,
|
||||||
|
[height]
|
||||||
|
);
|
||||||
|
} catch (e: any) {
|
||||||
|
logger.err(`Cannot delete cpfp clusters from db. Reason: ` + (e instanceof Error ? e.message : e));
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// insert a dummy row to mark that we've indexed as far as this block
|
// insert a dummy row to mark that we've indexed as far as this block
|
||||||
public async $insertProgressMarker(height: number): Promise<void> {
|
public async $insertProgressMarker(height: number): Promise<void> {
|
||||||
try {
|
try {
|
||||||
@ -190,6 +241,32 @@ class CpfpRepository {
|
|||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns `true` if two sets of CPFP clusters are deeply identical
|
||||||
|
public compareClusters(clustersA: CpfpCluster[], clustersB: CpfpCluster[]): boolean {
|
||||||
|
if (clustersA.length !== clustersB.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
clustersA = clustersA.sort((a,b) => a.root.localeCompare(b.root));
|
||||||
|
clustersB = clustersB.sort((a,b) => a.root.localeCompare(b.root));
|
||||||
|
|
||||||
|
for (let i = 0; i < clustersA.length; i++) {
|
||||||
|
if (clustersA[i].root !== clustersB[i].root) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (clustersA[i].txs.length !== clustersB[i].txs.length) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (let j = 0; j < clustersA[i].txs.length; j++) {
|
||||||
|
if (clustersA[i].txs[j].txid !== clustersB[i].txs[j].txid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export default new CpfpRepository();
|
export default new CpfpRepository();
|
Loading…
x
Reference in New Issue
Block a user