From ded11892f5faea6628ab6ec94d4e5097339447cf Mon Sep 17 00:00:00 2001 From: Mononaut Date: Fri, 25 Nov 2022 15:54:44 +0900 Subject: [PATCH] merge forensics columns into main channels table --- backend/src/api/database-migration.ts | 29 ++---- backend/src/api/explorer/channels.api.ts | 89 ++++++------------- .../src/tasks/lightning/forensics.service.ts | 10 +-- 3 files changed, 39 insertions(+), 89 deletions(-) diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts index 0f43580f6..a2977d3ba 100644 --- a/backend/src/api/database-migration.ts +++ b/backend/src/api/database-migration.ts @@ -382,7 +382,15 @@ class DatabaseMigration { if (databaseSchemaVersion < 48 && isBitcoin === true) { await this.$executeQuery('ALTER TABLE `channels` ADD source_checked tinyint(1) DEFAULT 0'); - await this.$executeQuery(this.getCreateChannelsForensicsTableQuery(), await this.$checkIfTableExists('channels_forensics')); + await this.$executeQuery('ALTER TABLE `channels` ADD closing_fee bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node1_funding_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node2_funding_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node1_closing_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node2_closing_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD funding_ratio float unsigned DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `channels` ADD closed_by varchar(66) DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `channels` ADD single_funded tinyint(1) DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD outputs JSON DEFAULT "[]"'); } } @@ -764,25 +772,6 @@ class DatabaseMigration { ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; } - private getCreateChannelsForensicsTableQuery(): string { - return `CREATE TABLE IF NOT EXISTS channels_forensics ( - channel_id bigint(11) unsigned NOT NULL, - closing_fee bigint(20) unsigned DEFAULT 0, - node1_funding_balance bigint(20) unsigned DEFAULT 0, - node2_funding_balance bigint(20) unsigned DEFAULT 0, - node1_closing_balance bigint(20) unsigned DEFAULT 0, - node2_closing_balance bigint(20) unsigned DEFAULT 0, - funding_ratio float unsigned DEFAULT NULL, - closed_by varchar(66) DEFAULT NULL, - single_funded tinyint(1) default 0, - outputs JSON NOT NULL, - PRIMARY KEY (channel_id), - FOREIGN KEY (channel_id) - REFERENCES channels (id) - ON DELETE CASCADE - ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; - } - private getCreateNodesStatsQuery(): string { return `CREATE TABLE IF NOT EXISTS node_stats ( id int(11) unsigned NOT NULL AUTO_INCREMENT, diff --git a/backend/src/api/explorer/channels.api.ts b/backend/src/api/explorer/channels.api.ts index 7f76a2971..e761288a3 100644 --- a/backend/src/api/explorer/channels.api.ts +++ b/backend/src/api/explorer/channels.api.ts @@ -131,9 +131,8 @@ class ChannelsApi { public async $getChannelsWithoutSourceChecked(): Promise { try { const query = ` - SELECT channels.*, forensics.* + SELECT channels.* FROM channels - LEFT JOIN channels_forensics AS forensics ON forensics.channel_id = channels.id WHERE channels.source_checked != 1 `; const [rows]: any = await DB.query(query); @@ -161,16 +160,12 @@ class ChannelsApi { SELECT n1.alias AS alias_left, n1.longitude as node1_longitude, n1.latitude as node1_latitude, n2.alias AS alias_right, n2.longitude as node2_longitude, n2.latitude as node2_latitude, channels.*, - ns1.channels AS channels_left, ns1.capacity AS capacity_left, ns2.channels AS channels_right, ns2.capacity AS capacity_right, - forensics.closing_fee as closing_fee, forensics.node1_funding_balance as node1_funding_balance, forensics.node2_funding_balance as node2_funding_balance, - forensics.funding_ratio as funding_ratio, forensics.node1_closing_balance as node1_closing_balance, forensics.node2_closing_balance as node2_closing_balance, - forensics.closed_by as closed_by, forensics.single_funded as single_funded + ns1.channels AS channels_left, ns1.capacity AS capacity_left, ns2.channels AS channels_right, ns2.capacity AS capacity_right FROM channels LEFT JOIN nodes AS n1 ON n1.public_key = channels.node1_public_key LEFT JOIN nodes AS n2 ON n2.public_key = channels.node2_public_key LEFT JOIN node_stats AS ns1 ON ns1.public_key = channels.node1_public_key LEFT JOIN node_stats AS ns2 ON ns2.public_key = channels.node2_public_key - LEFT JOIN channels_forensics AS forensics ON forensics.channel_id = channels.id WHERE ( ns1.id = ( SELECT MAX(id) @@ -277,15 +272,12 @@ class ChannelsApi { } } - public async $getChannelForensicsByClosingId(transactionId: string): Promise { + public async $getChannelByClosingId(transactionId: string): Promise { try { const query = ` SELECT - channels.id, channels.node1_public_key, channels.node2_public_key, - channels.closing_reason, channels.closing_transaction_id, channels.capacity, - forensics.* + channels.* FROM channels - LEFT JOIN channels_forensics as forensics ON forensics.channel_id = channels.id WHERE channels.closing_transaction_id = ? `; const [rows]: any = await DB.query(query, [transactionId]); @@ -294,20 +286,17 @@ class ChannelsApi { return rows[0]; } } catch (e) { - logger.err('$getChannelForensicsByClosingId error: ' + (e instanceof Error ? e.message : e)); + logger.err('$getChannelByClosingId error: ' + (e instanceof Error ? e.message : e)); // don't throw - this data isn't essential } } - public async $getChannelForensicsByOpeningId(transactionId: string): Promise { + public async $getChannelsByOpeningId(transactionId: string): Promise { try { const query = ` SELECT - channels.id, channels.node1_public_key, channels.node2_public_key, - channels.status, channels.transaction_id, channels.capacity, - forensics.* + channels.* FROM channels - LEFT JOIN channels_forensics as forensics ON forensics.channel_id = channels.id WHERE channels.transaction_id = ? `; const [rows]: any = await DB.query(query, [transactionId]); @@ -318,7 +307,7 @@ class ChannelsApi { }); } } catch (e) { - logger.err('$getChannelForensicsByOpeningId error: ' + (e instanceof Error ? e.message : e)); + logger.err('$getChannelsByOpeningId error: ' + (e instanceof Error ? e.message : e)); // don't throw - this data isn't essential } } @@ -326,36 +315,21 @@ class ChannelsApi { public async $updateClosingInfo(channelInfo: { id: string, node1_closing_balance: number, node2_closing_balance: number, closed_by: string | null, closing_fee: number, outputs: ILightningApi.ForensicOutput[]}): Promise { try { const query = ` - INSERT INTO channels_forensics - ( - channel_id, - node1_closing_balance, - node2_closing_balance, - closed_by, - closing_fee, - outputs - ) - VALUES (?, ?, ?, ?, ?, ?) - ON DUPLICATE KEY UPDATE + UPDATE channels SET node1_closing_balance = ?, node2_closing_balance = ?, closed_by = ?, closing_fee = ?, outputs = ? + WHERE channels.id = ? `; - const jsonOutputs = JSON.stringify(channelInfo.outputs); await DB.query(query, [ + channelInfo.node1_closing_balance || 0, + channelInfo.node2_closing_balance || 0, + channelInfo.closed_by, + channelInfo.closing_fee || 0, + JSON.stringify(channelInfo.outputs), channelInfo.id, - channelInfo.node1_closing_balance || 0, - channelInfo.node2_closing_balance || 0, - channelInfo.closed_by, - channelInfo.closing_fee || 0, - jsonOutputs, - channelInfo.node1_closing_balance || 0, - channelInfo.node2_closing_balance || 0, - channelInfo.closed_by, - channelInfo.closing_fee || 0, - jsonOutputs ]); } catch (e) { logger.err('$updateClosingInfo error: ' + (e instanceof Error ? e.message : e)); @@ -366,32 +340,19 @@ class ChannelsApi { public async $updateOpeningInfo(channelInfo: { id: string, node1_funding_balance: number, node2_funding_balance: number, funding_ratio: number, single_funded: boolean | void }): Promise { try { const query = ` - INSERT INTO channels_forensics - ( - channel_id, - node1_funding_balance, - node2_funding_balance, - funding_ratio, - single_funded, - outputs - ) - VALUES (?, ?, ?, ?, ?, 'null') - ON DUPLICATE KEY UPDATE - node1_funding_balance = ?, - node2_funding_balance = ?, - funding_ratio = ?, - single_funded = ? + UPDATE channels SET + node1_funding_balance = ?, + node2_funding_balance = ?, + funding_ratio = ?, + single_funded = ? + WHERE channels.id = ? `; await DB.query(query, [ + channelInfo.node1_funding_balance || 0, + channelInfo.node2_funding_balance || 0, + channelInfo.funding_ratio, + channelInfo.single_funded ? 1 : 0, channelInfo.id, - channelInfo.node1_funding_balance || 0, - channelInfo.node2_funding_balance || 0, - channelInfo.funding_ratio, - channelInfo.single_funded ? 1 : 0, - channelInfo.node1_funding_balance || 0, - channelInfo.node2_funding_balance || 0, - channelInfo.funding_ratio, - channelInfo.single_funded ? 1 : 0, ]); } catch (e) { logger.err('$updateOpeningInfo error: ' + (e instanceof Error ? e.message : e)); diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts index af79a270a..7083ad072 100644 --- a/backend/src/tasks/lightning/forensics.service.ts +++ b/backend/src/tasks/lightning/forensics.service.ts @@ -227,12 +227,12 @@ class ForensicsService { continue; } for (const input of openTx.vin) { - const closeChannel = await channelsApi.$getChannelForensicsByClosingId(input.txid); + const closeChannel = await channelsApi.$getChannelByClosingId(input.txid); if (closeChannel) { // this input directly spends a channel close output await this.$attributeChannelBalances(closeChannel, openChannel, input); } else { - const prevOpenChannels = await channelsApi.$getChannelForensicsByOpeningId(input.txid); + const prevOpenChannels = await channelsApi.$getChannelsByOpeningId(input.txid); if (prevOpenChannels?.length) { // this input spends a channel open change output for (const prevOpenChannel of prevOpenChannels) { @@ -286,7 +286,7 @@ class ForensicsService { for (const sweepInput of sweepTx.vin) { const lnScriptType = this.findLightningScript(sweepInput); if (lnScriptType > 1) { - const closeChannel = await channelsApi.$getChannelForensicsByClosingId(sweepInput.txid); + const closeChannel = await channelsApi.$getChannelByClosingId(sweepInput.txid); if (closeChannel) { const initiator = (lnScriptType === 2 || lnScriptType === 4) ? 'remote' : (lnScriptType === 3 ? 'local' : null); await this.$attributeChannelBalances(closeChannel, openChannel, sweepInput, openContribution, initiator); @@ -348,8 +348,8 @@ class ForensicsService { return; } if (!linkedOpenings) { - if (!prevChannel.outputs) { - prevChannel.outputs = prevChannel.outputs || prevChannelTx.vout.map(vout => { + if (!prevChannel.outputs || !prevChannel.outputs.length) { + prevChannel.outputs = prevChannelTx.vout.map(vout => { return { type: 0, value: vout.value,