Merge pull request #3010 from mempool/mononaut/cpfp-error-handling

More robust error checking & handling in CPFP repositories
This commit is contained in:
softsimon 2023-02-04 09:18:10 +07:00 committed by GitHub
commit 241850beca
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
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(
`
SELECT *
@ -121,8 +121,11 @@ class CpfpRepository {
[clusterRoot]
);
const cluster = clusterRows[0];
cluster.txs = this.unpack(cluster.txs);
return cluster;
if (cluster?.txs) {
cluster.txs = this.unpack(cluster.txs);
return cluster;
}
return;
}
public async $deleteClustersFrom(height: number): Promise<void> {
@ -136,9 +139,9 @@ class CpfpRepository {
[height]
) as RowDataPacket[][];
if (rows?.length) {
for (let clusterToDelete of rows) {
const txs = this.unpack(clusterToDelete.txs);
for (let tx of txs) {
for (const clusterToDelete of rows) {
const txs = this.unpack(clusterToDelete?.txs);
for (const tx of txs) {
await transactionRepository.$removeTransaction(tx.txid);
}
}
@ -204,20 +207,25 @@ class CpfpRepository {
return [];
}
const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
const txs: Ancestor[] = [];
const view = new DataView(arrayBuffer);
for (let offset = 0; offset < arrayBuffer.byteLength; offset += 44) {
const txid = Array.from(new Uint8Array(arrayBuffer, offset, 32)).reverse().map(b => b.toString(16).padStart(2, '0')).join('');
const weight = view.getUint32(offset + 32);
const fee = Number(view.getBigUint64(offset + 36));
txs.push({
txid,
weight,
fee
});
try {
const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength);
const txs: Ancestor[] = [];
const view = new DataView(arrayBuffer);
for (let offset = 0; offset < arrayBuffer.byteLength; offset += 44) {
const txid = Array.from(new Uint8Array(arrayBuffer, offset, 32)).reverse().map(b => b.toString(16).padStart(2, '0')).join('');
const weight = view.getUint32(offset + 32);
const fee = Number(view.getBigUint64(offset + 36));
txs.push({
txid,
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 cpfpRepository from './CpfpRepository';
interface CpfpSummary {
txid: string;
cluster: string;
root: string;
txs: Ancestor[];
height: number;
fee_rate: number;
}
class TransactionRepository {
public async $setCluster(txid: string, clusterRoot: string): Promise<void> {
try {
@ -72,7 +63,9 @@ class TransactionRepository {
const txid = txRows[0].id.toLowerCase();
const clusterId = txRows[0].root.toLowerCase();
const cluster = await cpfpRepository.$getCluster(clusterId);
return this.convertCpfp(txid, cluster);
if (cluster) {
return this.convertCpfp(txid, cluster);
}
}
} catch (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> {
await DB.query(
`
DELETE FROM compact_transactions
WHERE txid = UNHEX(?)
`,
[txid]
);
try {
await DB.query(
`
DELETE FROM compact_transactions
WHERE txid = UNHEX(?)
`,
[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 {
@ -95,7 +93,7 @@ class TransactionRepository {
const ancestors: Ancestor[] = [];
let matched = false;
for (const tx of cluster.txs) {
for (const tx of (cluster?.txs || [])) {
if (tx.txid === txid) {
matched = true;
} else if (!matched) {