Wrap esplora call into try/catch when scanning channel forensics

This commit is contained in:
nymkappa 2022-08-23 15:53:15 +02:00
parent 7fe9029a4e
commit 7d5ed66db1
No known key found for this signature in database
GPG Key ID: E155910B16E8BD04

View File

@ -285,44 +285,66 @@ class NetworkSyncService {
for (const channel of channels) { for (const channel of channels) {
let reason = 0; let reason = 0;
// Only Esplora backend can retrieve spent transaction outputs // Only Esplora backend can retrieve spent transaction outputs
const outspends = await bitcoinApi.$getOutspends(channel.closing_transaction_id); try {
const lightningScriptReasons: number[] = []; let outspends: IEsploraApi.Outspend[] | undefined;
for (const outspend of outspends) { try {
if (outspend.spent && outspend.txid) { outspends = await bitcoinApi.$getOutspends(channel.closing_transaction_id);
const spendingTx = await bitcoinApi.$getRawTransaction(outspend.txid); } catch (e) {
const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]); logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + channel.closing_transaction_id + '/outspends'}. Reason ${e instanceof Error ? e.message : e}`);
lightningScriptReasons.push(lightningScript); continue;
} }
} const lightningScriptReasons: number[] = [];
if (lightningScriptReasons.length === outspends.length for (const outspend of outspends) {
&& lightningScriptReasons.filter((r) => r === 1).length === outspends.length) { if (outspend.spent && outspend.txid) {
reason = 1; let spendingTx: IEsploraApi.Transaction | undefined;
} else { try {
const filteredReasons = lightningScriptReasons.filter((r) => r !== 1); spendingTx = await bitcoinApi.$getRawTransaction(outspend.txid);
if (filteredReasons.length) { } catch (e) {
if (filteredReasons.some((r) => r === 2 || r === 4)) { logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + outspend.txid}. Reason ${e instanceof Error ? e.message : e}`);
reason = 3; continue;
} else { }
reason = 2; const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]);
lightningScriptReasons.push(lightningScript);
} }
}
if (lightningScriptReasons.length === outspends.length
&& lightningScriptReasons.filter((r) => r === 1).length === outspends.length) {
reason = 1;
} else { } else {
/* const filteredReasons = lightningScriptReasons.filter((r) => r !== 1);
We can detect a commitment transaction (force close) by reading Sequence and Locktime if (filteredReasons.length) {
https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction if (filteredReasons.some((r) => r === 2 || r === 4)) {
*/ reason = 3;
const closingTx = await bitcoinApi.$getRawTransaction(channel.closing_transaction_id); } else {
const sequenceHex: string = closingTx.vin[0].sequence.toString(16); reason = 2;
const locktimeHex: string = closingTx.locktime.toString(16); }
if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') {
reason = 2; // Here we can't be sure if it's a penalty or not
} else { } else {
reason = 1; /*
We can detect a commitment transaction (force close) by reading Sequence and Locktime
https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction
*/
let closingTx: IEsploraApi.Transaction | undefined;
try {
closingTx = await bitcoinApi.$getRawTransaction(channel.closing_transaction_id);
} catch (e) {
logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + channel.closing_transaction_id}. Reason ${e instanceof Error ? e.message : e}`);
continue;
}
const sequenceHex: string = closingTx.vin[0].sequence.toString(16);
const locktimeHex: string = closingTx.locktime.toString(16);
if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') {
reason = 2; // Here we can't be sure if it's a penalty or not
} else {
reason = 1;
}
} }
} }
} if (reason) {
if (reason) { logger.debug('Setting closing reason ' + reason + ' for channel: ' + channel.id + '.');
logger.debug('Setting closing reason ' + reason + ' for channel: ' + channel.id + '.'); await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]);
await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]); }
} catch (e) {
logger.err(`$runClosedChannelsForensics() failed for channel ${channel.short_id}. Reason: ${e instanceof Error ? e.message : e}`);
} }
++progress; ++progress;