More robust error checking & handling in CPFP repositories

This commit is contained in:
Mononaut 2023-02-02 17:37:32 -06:00
parent 69f5d483ee
commit 900e66aef7
No known key found for this signature in database
GPG Key ID: A3F058E41374C04E
2 changed files with 43 additions and 37 deletions

View File

@ -111,7 +111,7 @@ class CpfpRepository {
} }
} }
public async $getCluster(clusterRoot: string): Promise<Cluster> { public async $getCluster(clusterRoot: string): Promise<Cluster | void> {
const [clusterRows]: any = await DB.query( const [clusterRows]: any = await DB.query(
` `
SELECT * SELECT *
@ -121,8 +121,11 @@ class CpfpRepository {
[clusterRoot] [clusterRoot]
); );
const cluster = clusterRows[0]; const cluster = clusterRows[0];
cluster.txs = this.unpack(cluster.txs); if (cluster?.txs) {
return cluster; cluster.txs = this.unpack(cluster.txs);
return cluster;
}
return;
} }
public async $deleteClustersFrom(height: number): Promise<void> { public async $deleteClustersFrom(height: number): Promise<void> {
@ -136,9 +139,9 @@ class CpfpRepository {
[height] [height]
) as RowDataPacket[][]; ) as RowDataPacket[][];
if (rows?.length) { if (rows?.length) {
for (let clusterToDelete of rows) { for (const clusterToDelete of rows) {
const txs = this.unpack(clusterToDelete.txs); const txs = this.unpack(clusterToDelete?.txs);
for (let tx of txs) { for (const tx of txs) {
await transactionRepository.$removeTransaction(tx.txid); await transactionRepository.$removeTransaction(tx.txid);
} }
} }
@ -204,20 +207,25 @@ class CpfpRepository {
return []; return [];
} }
const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); try {
const txs: Ancestor[] = []; const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
const view = new DataView(arrayBuffer); const txs: Ancestor[] = [];
for (let offset = 0; offset < arrayBuffer.byteLength; offset += 44) { const view = new DataView(arrayBuffer);
const txid = Array.from(new Uint8Array(arrayBuffer, offset, 32)).reverse().map(b => b.toString(16).padStart(2, '0')).join(''); for (let offset = 0; offset < arrayBuffer.byteLength; offset += 44) {
const weight = view.getUint32(offset + 32); const txid = Array.from(new Uint8Array(arrayBuffer, offset, 32)).reverse().map(b => b.toString(16).padStart(2, '0')).join('');
const fee = Number(view.getBigUint64(offset + 36)); const weight = view.getUint32(offset + 32);
txs.push({ const fee = Number(view.getBigUint64(offset + 36));
txid, txs.push({
weight, txid,
fee weight,
}); fee
});
}
return txs;
} catch (e) {
logger.warn(`Failed to unpack CPFP cluster. Reason: ` + (e instanceof Error ? e.message : e));
return [];
} }
return txs;
} }
} }

View File

@ -3,15 +3,6 @@ import logger from '../logger';
import { Ancestor, CpfpInfo } from '../mempool.interfaces'; import { Ancestor, CpfpInfo } from '../mempool.interfaces';
import cpfpRepository from './CpfpRepository'; import cpfpRepository from './CpfpRepository';
interface CpfpSummary {
txid: string;
cluster: string;
root: string;
txs: Ancestor[];
height: number;
fee_rate: number;
}
class TransactionRepository { class TransactionRepository {
public async $setCluster(txid: string, clusterRoot: string): Promise<void> { public async $setCluster(txid: string, clusterRoot: string): Promise<void> {
try { try {
@ -72,7 +63,9 @@ class TransactionRepository {
const txid = txRows[0].id.toLowerCase(); const txid = txRows[0].id.toLowerCase();
const clusterId = txRows[0].root.toLowerCase(); const clusterId = txRows[0].root.toLowerCase();
const cluster = await cpfpRepository.$getCluster(clusterId); const cluster = await cpfpRepository.$getCluster(clusterId);
return this.convertCpfp(txid, cluster); if (cluster) {
return this.convertCpfp(txid, cluster);
}
} }
} catch (e) { } catch (e) {
logger.err('Cannot get transaction cpfp info from db. Reason: ' + (e instanceof Error ? e.message : e)); logger.err('Cannot get transaction cpfp info from db. Reason: ' + (e instanceof Error ? e.message : e));
@ -81,13 +74,18 @@ class TransactionRepository {
} }
public async $removeTransaction(txid: string): Promise<void> { public async $removeTransaction(txid: string): Promise<void> {
await DB.query( try {
` await DB.query(
DELETE FROM compact_transactions `
WHERE txid = UNHEX(?) DELETE FROM compact_transactions
`, WHERE txid = UNHEX(?)
[txid] `,
); [txid]
);
} catch (e) {
logger.warn('Cannot delete transaction cpfp info from db. Reason: ' + (e instanceof Error ? e.message : e));
throw e;
}
} }
private convertCpfp(txid, cluster): CpfpInfo { private convertCpfp(txid, cluster): CpfpInfo {
@ -95,7 +93,7 @@ class TransactionRepository {
const ancestors: Ancestor[] = []; const ancestors: Ancestor[] = [];
let matched = false; let matched = false;
for (const tx of cluster.txs) { for (const tx of (cluster?.txs || [])) {
if (tx.txid === txid) { if (tx.txid === txid) {
matched = true; matched = true;
} else if (!matched) { } else if (!matched) {