2021-12-04 21:53:56 +10:30
|
|
|
#include "config.h"
|
2020-05-21 22:45:14 -05:00
|
|
|
#include <bitcoin/script.h>
|
2019-02-24 15:40:37 +10:30
|
|
|
#include <ccan/array_size/array_size.h>
|
2017-05-12 20:24:18 +02:00
|
|
|
#include <ccan/tal/str/str.h>
|
2018-02-17 15:11:08 +10:30
|
|
|
#include <common/version.h>
|
2022-01-03 12:45:35 -06:00
|
|
|
#include <db/bindings.h>
|
|
|
|
|
#include <db/common.h>
|
|
|
|
|
#include <db/exec.h>
|
|
|
|
|
#include <db/utils.h>
|
2021-09-16 14:30:42 +09:30
|
|
|
#include <errno.h>
|
2020-08-25 11:25:38 +09:30
|
|
|
#include <hsmd/hsmd_wiregen.h>
|
2020-05-21 22:45:14 -05:00
|
|
|
#include <lightningd/channel.h>
|
2023-03-21 14:28:15 +10:30
|
|
|
#include <lightningd/hsm_control.h>
|
2019-03-18 13:10:32 +10:30
|
|
|
#include <lightningd/plugin_hook.h>
|
2025-08-19 10:30:52 +09:30
|
|
|
#include <wallet/account_migration.h>
|
2021-12-04 21:53:56 +10:30
|
|
|
#include <wallet/db.h>
|
2025-11-27 15:15:36 +10:30
|
|
|
#include <wallet/migrations.h>
|
2023-03-30 15:55:21 +10:30
|
|
|
#include <wallet/psbt_fixup.h>
|
2020-07-28 21:03:03 -05:00
|
|
|
#include <wire/wire_sync.h>
|
2017-05-12 20:24:18 +02:00
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* db_migrate - Apply all remaining migrations from the current version
|
|
|
|
|
*/
|
2021-10-13 14:15:36 +10:30
|
|
|
static bool db_migrate(struct lightningd *ld, struct db *db,
|
2020-07-28 20:20:30 -05:00
|
|
|
const struct ext_key *bip32_base)
|
2017-05-12 20:24:18 +02:00
|
|
|
{
|
|
|
|
|
/* Attempt to read the version from the database */
|
2018-02-17 15:11:08 +10:30
|
|
|
int current, orig, available;
|
2025-11-27 15:15:36 +10:30
|
|
|
size_t num_migrations;
|
2023-02-08 20:17:23 +01:00
|
|
|
char *err_msg;
|
2019-08-13 16:00:46 +02:00
|
|
|
struct db_stmt *stmt;
|
2025-11-27 15:15:36 +10:30
|
|
|
const struct db_migration *dbmigrations = get_db_migrations(&num_migrations);
|
2017-05-12 20:24:18 +02:00
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
/* This is the final number, not the count! */
|
|
|
|
|
available = num_migrations - 1;
|
2018-02-17 15:11:08 +10:30
|
|
|
orig = current = db_get_version(db);
|
2017-11-01 11:40:48 +10:30
|
|
|
|
2018-01-02 14:33:42 +10:30
|
|
|
if (current == -1)
|
2022-01-03 12:45:35 -06:00
|
|
|
log_info(ld->log, "Creating database");
|
2023-02-08 20:17:23 +01:00
|
|
|
else if (available < current) {
|
|
|
|
|
err_msg = tal_fmt(tmpctx, "Refusing to migrate down from version %u to %u",
|
2018-08-09 11:57:20 +09:30
|
|
|
current, available);
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db, "%s", err_msg);
|
2023-02-08 20:17:23 +01:00
|
|
|
} else if (current != available) {
|
2022-08-24 19:35:42 +09:30
|
|
|
if (ld->db_upgrade_ok && *ld->db_upgrade_ok == false) {
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db,
|
|
|
|
|
"Refusing to upgrade db from version %u to %u (database-upgrade=false)",
|
2022-08-24 19:35:42 +09:30
|
|
|
current, available);
|
|
|
|
|
} else if (!ld->db_upgrade_ok && !is_released_version()) {
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db, "Refusing to irreversibly upgrade db from version %u to %u in non-final version %s (use --database-upgrade=true to override)",
|
|
|
|
|
current, available, version());
|
2022-08-24 19:35:42 +09:30
|
|
|
}
|
2022-01-03 12:45:35 -06:00
|
|
|
log_info(ld->log, "Updating database from version %u to %u",
|
2018-01-02 14:33:42 +10:30
|
|
|
current, available);
|
2022-08-24 19:35:42 +09:30
|
|
|
}
|
2018-01-02 14:33:42 +10:30
|
|
|
|
2019-02-24 15:42:09 +10:30
|
|
|
while (current < available) {
|
|
|
|
|
current++;
|
2019-07-25 22:47:44 +02:00
|
|
|
if (dbmigrations[current].sql) {
|
2022-07-25 16:30:09 +09:30
|
|
|
stmt = db_prepare_v2(db, dbmigrations[current].sql);
|
2019-07-25 22:47:44 +02:00
|
|
|
db_exec_prepared_v2(stmt);
|
2019-08-03 14:48:38 +02:00
|
|
|
tal_free(stmt);
|
2019-07-25 22:47:44 +02:00
|
|
|
}
|
2019-02-24 15:42:09 +10:30
|
|
|
if (dbmigrations[current].func)
|
2023-03-21 14:28:15 +10:30
|
|
|
dbmigrations[current].func(ld, db);
|
2019-02-24 15:42:09 +10:30
|
|
|
}
|
2017-05-12 20:24:18 +02:00
|
|
|
|
|
|
|
|
/* Finally update the version number in the version table */
|
2019-08-13 16:00:46 +02:00
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE version SET version=?;"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_int(stmt, available);
|
2019-08-13 16:00:46 +02:00
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
2017-05-12 20:24:18 +02:00
|
|
|
|
2018-02-17 15:11:08 +10:30
|
|
|
/* Annotate that we did upgrade, if any. */
|
2019-08-13 16:00:46 +02:00
|
|
|
if (current != orig) {
|
|
|
|
|
stmt = db_prepare_v2(
|
|
|
|
|
db, SQL("INSERT INTO db_upgrades VALUES (?, ?);"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_int(stmt, orig);
|
|
|
|
|
db_bind_text(stmt, version());
|
2019-08-13 16:00:46 +02:00
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
2021-10-13 14:15:36 +10:30
|
|
|
|
|
|
|
|
return current != orig;
|
2019-12-18 19:45:24 +01:00
|
|
|
}
|
2018-02-17 15:11:08 +10:30
|
|
|
|
2023-06-30 04:53:08 +09:30
|
|
|
static void db_error(struct lightningd *ld, bool fatal, const char *fmt, va_list ap)
|
|
|
|
|
{
|
|
|
|
|
va_list ap2;
|
|
|
|
|
|
|
|
|
|
va_copy(ap2, ap);
|
|
|
|
|
logv(ld->log, LOG_BROKEN, NULL, true, fmt, ap);
|
|
|
|
|
|
|
|
|
|
if (fatal)
|
|
|
|
|
fatal_vfmt(fmt, ap2);
|
|
|
|
|
va_end(ap2);
|
|
|
|
|
}
|
|
|
|
|
|
2020-07-28 20:20:30 -05:00
|
|
|
struct db *db_setup(const tal_t *ctx, struct lightningd *ld,
|
|
|
|
|
const struct ext_key *bip32_base)
|
2017-05-12 20:24:18 +02:00
|
|
|
{
|
2025-08-19 10:30:52 +09:30
|
|
|
struct db *db = db_open(ctx, ld->wallet_dsn, ld->developer, true,
|
2023-09-21 15:06:27 +09:30
|
|
|
db_error, ld);
|
2021-10-13 14:15:36 +10:30
|
|
|
bool migrated;
|
2022-01-03 12:45:35 -06:00
|
|
|
|
|
|
|
|
db->report_changes_fn = plugin_hook_db_sync;
|
2019-12-18 18:57:37 +01:00
|
|
|
|
|
|
|
|
db_begin_transaction(db);
|
2022-09-09 17:02:15 +09:30
|
|
|
db->data_version = db_data_version_get(db);
|
2019-12-18 18:57:37 +01:00
|
|
|
|
2021-10-13 14:15:36 +10:30
|
|
|
migrated = db_migrate(ld, db, bip32_base);
|
2019-12-18 18:57:37 +01:00
|
|
|
|
|
|
|
|
db_commit_transaction(db);
|
2021-10-13 14:15:36 +10:30
|
|
|
|
|
|
|
|
/* This needs to be done outside a transaction, apparently.
|
|
|
|
|
* It's a good idea to do this every so often, and on db
|
|
|
|
|
* upgrade is a reasonable time. */
|
|
|
|
|
if (migrated && !db->config->vacuum_fn(db))
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db, "Error vacuuming db: %s", db->error);
|
2021-10-13 14:15:36 +10:30
|
|
|
|
2017-05-12 20:24:18 +02:00
|
|
|
return db;
|
|
|
|
|
}
|
2017-06-01 16:10:40 +02:00
|
|
|
|
2019-02-21 01:01:33 +01:00
|
|
|
/* Will apply the current config fee settings to all channels */
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_pr2342_feerate_per_channel(struct lightningd *ld, struct db *db)
|
2019-02-21 01:01:33 +01:00
|
|
|
{
|
2019-07-25 22:47:44 +02:00
|
|
|
struct db_stmt *stmt = db_prepare_v2(
|
|
|
|
|
db, SQL("UPDATE channels SET feerate_base = ?, feerate_ppm = ?;"));
|
|
|
|
|
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_int(stmt, ld->config.fee_base);
|
|
|
|
|
db_bind_int(stmt, ld->config.fee_per_satoshi);
|
2019-07-25 22:47:44 +02:00
|
|
|
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
2019-08-03 14:48:38 +02:00
|
|
|
tal_free(stmt);
|
2019-02-21 01:01:33 +01:00
|
|
|
}
|
2019-04-10 17:08:57 +02:00
|
|
|
|
2019-09-30 16:47:16 -05:00
|
|
|
/* We've added a column `our_funding_satoshis`, since channels can now
|
|
|
|
|
* have funding for either channel participant. We need to 'backfill' this
|
|
|
|
|
* data, however. We can do this using the fact that our_funding_satoshi
|
|
|
|
|
* is the same as the funding_satoshi for every channel where we are
|
|
|
|
|
* the `funder`
|
|
|
|
|
*/
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_our_funding(struct lightningd *ld, struct db *db)
|
2019-09-30 16:47:16 -05:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
/* Statement to update record */
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET our_funding_satoshi = funding_satoshi"
|
|
|
|
|
" WHERE funder = 0;")); /* 0 == LOCAL */
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
if (stmt->error)
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(stmt->db,
|
|
|
|
|
"Error migrating funding satoshis to our_funding (%s)",
|
2019-09-30 16:47:16 -05:00
|
|
|
stmt->error);
|
|
|
|
|
|
2020-07-28 21:03:03 -05:00
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-21 14:28:15 +10:30
|
|
|
void fillin_missing_scriptpubkeys(struct lightningd *ld, struct db *db)
|
2020-07-28 21:03:03 -05:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT"
|
|
|
|
|
" type"
|
|
|
|
|
", keyindex"
|
|
|
|
|
", prev_out_tx"
|
|
|
|
|
", prev_out_index"
|
|
|
|
|
", channel_id"
|
|
|
|
|
", peer_id"
|
|
|
|
|
", commitment_point"
|
|
|
|
|
" FROM outputs"
|
|
|
|
|
" WHERE scriptpubkey IS NULL;"));
|
|
|
|
|
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
int type;
|
|
|
|
|
u8 *scriptPubkey;
|
|
|
|
|
struct bitcoin_txid txid;
|
|
|
|
|
u32 outnum, keyindex;
|
|
|
|
|
struct pubkey key;
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
type = db_col_int(stmt, "type");
|
|
|
|
|
keyindex = db_col_int(stmt, "keyindex");
|
|
|
|
|
db_col_txid(stmt, "prev_out_tx", &txid);
|
|
|
|
|
outnum = db_col_int(stmt, "prev_out_index");
|
2020-07-28 21:03:03 -05:00
|
|
|
|
|
|
|
|
/* This indiciates whether or not we have 'close_info' */
|
2021-11-15 04:28:46 +10:30
|
|
|
if (!db_col_is_null(stmt, "channel_id")) {
|
2020-07-28 21:03:03 -05:00
|
|
|
struct pubkey *commitment_point;
|
|
|
|
|
struct node_id peer_id;
|
|
|
|
|
u64 channel_id;
|
|
|
|
|
u8 *msg;
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
channel_id = db_col_u64(stmt, "channel_id");
|
|
|
|
|
db_col_node_id(stmt, "peer_id", &peer_id);
|
2023-03-20 10:48:59 +10:30
|
|
|
commitment_point = db_col_optional(stmt, stmt, "commitment_point", pubkey);
|
2020-07-28 21:03:03 -05:00
|
|
|
|
|
|
|
|
/* Have to go ask the HSM to derive the pubkey for us */
|
2020-08-25 11:25:38 +09:30
|
|
|
msg = towire_hsmd_get_output_scriptpubkey(NULL,
|
2020-07-28 21:03:03 -05:00
|
|
|
channel_id,
|
|
|
|
|
&peer_id,
|
|
|
|
|
commitment_point);
|
|
|
|
|
if (!wire_sync_write(ld->hsm_fd, take(msg)))
|
|
|
|
|
fatal("Could not write to HSM: %s", strerror(errno));
|
|
|
|
|
msg = wire_sync_read(stmt, ld->hsm_fd);
|
2020-08-25 11:25:38 +09:30
|
|
|
if (!fromwire_hsmd_get_output_scriptpubkey_reply(stmt, msg,
|
2020-07-28 21:03:03 -05:00
|
|
|
&scriptPubkey))
|
|
|
|
|
fatal("HSM gave bad hsm_get_output_scriptpubkey_reply %s",
|
|
|
|
|
tal_hex(msg, msg));
|
|
|
|
|
} else {
|
2021-11-15 04:30:46 +10:30
|
|
|
db_col_ignore(stmt, "peer_id");
|
|
|
|
|
db_col_ignore(stmt, "commitment_point");
|
2023-03-21 14:28:15 +10:30
|
|
|
bip32_pubkey(ld, &key, keyindex);
|
2025-05-06 05:22:46 +09:30
|
|
|
if (type == WALLET_OUTPUT_P2SH_WPKH) {
|
2020-07-28 21:03:03 -05:00
|
|
|
u8 *redeemscript = bitcoin_redeem_p2sh_p2wpkh(stmt, &key);
|
|
|
|
|
scriptPubkey = scriptpubkey_p2sh(tmpctx, redeemscript);
|
|
|
|
|
} else
|
|
|
|
|
scriptPubkey = scriptpubkey_p2wpkh(stmt, &key);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE outputs"
|
|
|
|
|
" SET scriptpubkey = ?"
|
|
|
|
|
" WHERE prev_out_tx = ? "
|
|
|
|
|
" AND prev_out_index = ?"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_blob(update_stmt, scriptPubkey, tal_bytelen(scriptPubkey));
|
|
|
|
|
db_bind_txid(update_stmt, &txid);
|
|
|
|
|
db_bind_int(update_stmt, outnum);
|
2020-07-28 21:03:03 -05:00
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2019-09-30 16:47:16 -05:00
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2020-09-09 16:50:53 +09:30
|
|
|
/*
|
|
|
|
|
* V2 channel open has a different channel_id format than v1. prior to this, we
|
|
|
|
|
* could simply derive the channel_id whenever it was required, but since there
|
|
|
|
|
* are now two ways to do it, we save the derived channel id.
|
|
|
|
|
*/
|
2025-11-27 15:15:36 +10:30
|
|
|
void fillin_missing_channel_id(struct lightningd *ld, struct db *db)
|
2020-09-09 16:50:53 +09:30
|
|
|
{
|
|
|
|
|
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT"
|
|
|
|
|
" id"
|
|
|
|
|
", funding_tx_id"
|
|
|
|
|
", funding_tx_outnum"
|
|
|
|
|
" FROM channels;"));
|
|
|
|
|
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
size_t id;
|
2021-10-13 14:15:36 +10:30
|
|
|
struct bitcoin_outpoint funding;
|
2020-09-09 16:50:53 +09:30
|
|
|
struct channel_id cid;
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
id = db_col_u64(stmt, "id");
|
|
|
|
|
db_col_txid(stmt, "funding_tx_id", &funding.txid);
|
|
|
|
|
funding.n = db_col_int(stmt, "funding_tx_outnum");
|
2021-10-13 14:15:36 +10:30
|
|
|
derive_channel_id(&cid, &funding);
|
2020-09-09 16:50:53 +09:30
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET full_channel_id = ?"
|
|
|
|
|
" WHERE id = ?;"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_channel_id(update_stmt, &cid);
|
|
|
|
|
db_bind_u64(update_stmt, id);
|
2020-09-09 16:50:53 +09:30
|
|
|
|
|
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void fillin_missing_local_basepoints(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2021-03-01 15:47:55 +01:00
|
|
|
{
|
|
|
|
|
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
stmt = db_prepare_v2(
|
|
|
|
|
db,
|
|
|
|
|
SQL("SELECT"
|
|
|
|
|
" channels.id"
|
|
|
|
|
", peers.node_id "
|
|
|
|
|
"FROM"
|
|
|
|
|
" channels JOIN"
|
|
|
|
|
" peers "
|
|
|
|
|
"ON (peers.id = channels.peer_id)"));
|
|
|
|
|
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct node_id peer_id;
|
|
|
|
|
u64 dbid;
|
|
|
|
|
u8 *msg;
|
|
|
|
|
struct db_stmt *upstmt;
|
|
|
|
|
struct basepoints base;
|
|
|
|
|
struct pubkey funding_pubkey;
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
dbid = db_col_u64(stmt, "channels.id");
|
|
|
|
|
db_col_node_id(stmt, "peers.node_id", &peer_id);
|
2021-03-01 15:47:55 +01:00
|
|
|
|
2023-03-21 14:28:15 +10:30
|
|
|
if (!wire_sync_write(ld->hsm_fd,
|
2021-03-01 15:47:55 +01:00
|
|
|
towire_hsmd_get_channel_basepoints(
|
|
|
|
|
tmpctx, &peer_id, dbid)))
|
|
|
|
|
fatal("could not retrieve basepoint from hsmd");
|
|
|
|
|
|
2023-03-21 14:28:15 +10:30
|
|
|
msg = wire_sync_read(tmpctx, ld->hsm_fd);
|
2021-03-01 15:47:55 +01:00
|
|
|
if (!fromwire_hsmd_get_channel_basepoints_reply(
|
|
|
|
|
msg, &base, &funding_pubkey))
|
|
|
|
|
fatal("malformed hsmd_get_channel_basepoints_reply "
|
|
|
|
|
"from hsmd");
|
|
|
|
|
|
|
|
|
|
upstmt = db_prepare_v2(
|
|
|
|
|
db,
|
|
|
|
|
SQL("UPDATE channels SET"
|
|
|
|
|
" revocation_basepoint_local = ?"
|
|
|
|
|
", payment_basepoint_local = ?"
|
|
|
|
|
", htlc_basepoint_local = ?"
|
|
|
|
|
", delayed_payment_basepoint_local = ?"
|
|
|
|
|
", funding_pubkey_local = ? "
|
|
|
|
|
"WHERE id = ?;"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_pubkey(upstmt, &base.revocation);
|
|
|
|
|
db_bind_pubkey(upstmt, &base.payment);
|
|
|
|
|
db_bind_pubkey(upstmt, &base.htlc);
|
|
|
|
|
db_bind_pubkey(upstmt, &base.delayed_payment);
|
|
|
|
|
db_bind_pubkey(upstmt, &funding_pubkey);
|
2021-03-01 15:47:55 +01:00
|
|
|
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_u64(upstmt, dbid);
|
2021-03-01 15:47:55 +01:00
|
|
|
|
|
|
|
|
db_exec_prepared_v2(take(upstmt));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2021-06-22 13:25:59 -05:00
|
|
|
/* New 'channel_blockheights' table, every existing channel gets a
|
|
|
|
|
* 'initial blockheight' of 0 */
|
2025-11-27 15:15:36 +10:30
|
|
|
void fillin_missing_channel_blockheights(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2021-06-22 13:25:59 -05:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
/* Set all existing channels to 0 */
|
|
|
|
|
/* If we're funder (LOCAL=0):
|
|
|
|
|
* Then our blockheight is set last (SENT_ADD_ACK_REVOCATION = 4) */
|
|
|
|
|
stmt = db_prepare_v2(db,
|
|
|
|
|
SQL("INSERT INTO channel_blockheights"
|
|
|
|
|
" (channel_id, hstate, blockheight)"
|
|
|
|
|
" SELECT id, 4, 0 FROM channels"
|
|
|
|
|
" WHERE funder = 0;"));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
/* If they're funder (REMOTE=1):
|
|
|
|
|
* Then their blockheight is last (RCVD_ADD_ACK_REVOCATION = 14) */
|
|
|
|
|
stmt = db_prepare_v2(db,
|
|
|
|
|
SQL("INSERT INTO channel_blockheights"
|
|
|
|
|
" (channel_id, hstate, blockheight)"
|
|
|
|
|
" SELECT id, 14, 0 FROM channels"
|
|
|
|
|
" WHERE funder = 1;"));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
}
|
|
|
|
|
|
2021-05-19 19:15:12 -05:00
|
|
|
void
|
2023-03-21 14:28:15 +10:30
|
|
|
migrate_inflight_last_tx_to_psbt(struct lightningd *ld, struct db *db)
|
2021-05-19 19:15:12 -05:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt, *update_stmt;
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT "
|
|
|
|
|
" c.id"
|
|
|
|
|
", p.node_id"
|
|
|
|
|
", c.fundingkey_remote"
|
|
|
|
|
", inflight.last_tx"
|
|
|
|
|
", inflight.last_sig"
|
|
|
|
|
", inflight.funding_satoshi"
|
|
|
|
|
", inflight.funding_tx_id"
|
|
|
|
|
" FROM channels c"
|
|
|
|
|
" LEFT OUTER JOIN peers p"
|
|
|
|
|
" ON p.id = c.peer_id"
|
|
|
|
|
" LEFT OUTER JOIN"
|
|
|
|
|
" channel_funding_inflights inflight"
|
|
|
|
|
" ON c.id = inflight.channel_id"
|
|
|
|
|
" WHERE inflight.last_tx IS NOT NULL;"));
|
|
|
|
|
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct bitcoin_tx *last_tx;
|
|
|
|
|
struct bitcoin_txid funding_txid;
|
|
|
|
|
struct amount_sat funding_sat;
|
|
|
|
|
struct node_id peer_id;
|
|
|
|
|
struct pubkey local_funding_pubkey, remote_funding_pubkey;
|
|
|
|
|
struct basepoints local_basepoints UNUSED;
|
|
|
|
|
struct bitcoin_signature last_sig;
|
|
|
|
|
u64 cdb_id;
|
|
|
|
|
u8 *funding_wscript;
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
cdb_id = db_col_u64(stmt, "c.id");
|
|
|
|
|
last_tx = db_col_tx(stmt, stmt, "inflight.last_tx");
|
2021-05-19 19:15:12 -05:00
|
|
|
assert(last_tx != NULL);
|
|
|
|
|
|
2021-11-15 04:30:46 +10:30
|
|
|
/* FIXME: This is only needed inside the select? */
|
|
|
|
|
db_col_ignore(stmt, "inflight.last_tx");
|
|
|
|
|
|
2021-05-19 19:15:12 -05:00
|
|
|
/* If we've forgotten about the peer_id
|
|
|
|
|
* because we closed / forgot the channel,
|
|
|
|
|
* we can skip this. */
|
2021-11-15 04:30:46 +10:30
|
|
|
if (db_col_is_null(stmt, "p.node_id")) {
|
|
|
|
|
db_col_ignore(stmt, "inflight.last_sig");
|
|
|
|
|
db_col_ignore(stmt, "inflight.funding_satoshi");
|
|
|
|
|
db_col_ignore(stmt, "inflight.funding_tx_id");
|
2021-05-19 19:15:12 -05:00
|
|
|
continue;
|
2021-11-15 04:30:46 +10:30
|
|
|
}
|
2021-11-15 04:28:46 +10:30
|
|
|
db_col_node_id(stmt, "p.node_id", &peer_id);
|
2023-07-22 16:42:57 +09:30
|
|
|
funding_sat = db_col_amount_sat(stmt, "inflight.funding_satoshi");
|
2021-11-15 04:28:46 +10:30
|
|
|
db_col_pubkey(stmt, "c.fundingkey_remote", &remote_funding_pubkey);
|
|
|
|
|
db_col_txid(stmt, "inflight.funding_tx_id", &funding_txid);
|
2021-05-19 19:15:12 -05:00
|
|
|
|
|
|
|
|
get_channel_basepoints(ld, &peer_id, cdb_id,
|
|
|
|
|
&local_basepoints, &local_funding_pubkey);
|
|
|
|
|
|
|
|
|
|
funding_wscript = bitcoin_redeem_2of2(stmt, &local_funding_pubkey,
|
|
|
|
|
&remote_funding_pubkey);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
psbt_input_set_wit_utxo(last_tx->psbt, 0,
|
|
|
|
|
scriptpubkey_p2wsh(last_tx->psbt, funding_wscript),
|
|
|
|
|
funding_sat);
|
|
|
|
|
psbt_input_set_witscript(last_tx->psbt, 0, funding_wscript);
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
if (!db_col_signature(stmt, "inflight.last_sig", &last_sig.s))
|
2021-05-19 19:15:12 -05:00
|
|
|
abort();
|
|
|
|
|
|
|
|
|
|
last_sig.sighash_type = SIGHASH_ALL;
|
|
|
|
|
if (!psbt_input_set_signature(last_tx->psbt, 0,
|
|
|
|
|
&remote_funding_pubkey, &last_sig))
|
|
|
|
|
abort();
|
|
|
|
|
psbt_input_add_pubkey(last_tx->psbt, 0,
|
2023-07-11 05:29:41 +09:30
|
|
|
&local_funding_pubkey, false /* is_taproot */);
|
2021-05-19 19:15:12 -05:00
|
|
|
psbt_input_add_pubkey(last_tx->psbt, 0,
|
2023-07-11 05:29:41 +09:30
|
|
|
&remote_funding_pubkey, false /* is_taproot */);
|
2021-05-19 19:15:12 -05:00
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db,
|
|
|
|
|
SQL("UPDATE channel_funding_inflights"
|
|
|
|
|
" SET last_tx = ?"
|
|
|
|
|
" WHERE channel_id = ?"
|
|
|
|
|
" AND funding_tx_id = ?;"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_psbt(update_stmt, last_tx->psbt);
|
|
|
|
|
db_bind_int(update_stmt, cdb_id);
|
|
|
|
|
db_bind_txid(update_stmt, &funding_txid);
|
2021-05-19 19:15:12 -05:00
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2023-07-22 17:15:49 +09:30
|
|
|
void load_indexes(struct db *db, struct indexes *indexes)
|
|
|
|
|
{
|
|
|
|
|
for (size_t s = 0; s < NUM_WAIT_SUBSYSTEM; s++) {
|
|
|
|
|
for (size_t i = 0; i < NUM_WAIT_INDEX; i++) {
|
|
|
|
|
const char *fname = tal_fmt(tmpctx, "last_%s_%s_index",
|
|
|
|
|
wait_subsystem_name(s),
|
|
|
|
|
wait_index_name(i));
|
|
|
|
|
indexes[s].i[i] = db_get_intvar(db, fname, 0);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 22:45:14 -05:00
|
|
|
/* We're moving everything over to PSBTs from tx's, particularly our last_tx's
|
|
|
|
|
* which are commitment transactions for channels.
|
|
|
|
|
* This migration loads all of the last_tx's and 're-formats' them into psbts,
|
|
|
|
|
* adds the required input witness utxo information, and then saves it back to disk
|
|
|
|
|
* */
|
2023-03-21 14:28:15 +10:30
|
|
|
void migrate_last_tx_to_psbt(struct lightningd *ld, struct db *db)
|
2020-05-21 22:45:14 -05:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt, *update_stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT "
|
|
|
|
|
" c.id"
|
|
|
|
|
", p.node_id"
|
|
|
|
|
", c.last_tx"
|
|
|
|
|
", c.funding_satoshi"
|
|
|
|
|
", c.fundingkey_remote"
|
|
|
|
|
", c.last_sig"
|
|
|
|
|
" FROM channels c"
|
|
|
|
|
" LEFT OUTER JOIN peers p"
|
|
|
|
|
" ON p.id = c.peer_id;"));
|
|
|
|
|
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct bitcoin_tx *last_tx;
|
|
|
|
|
struct amount_sat funding_sat;
|
|
|
|
|
struct node_id peer_id;
|
|
|
|
|
struct pubkey local_funding_pubkey, remote_funding_pubkey;
|
|
|
|
|
struct basepoints local_basepoints UNUSED;
|
|
|
|
|
struct bitcoin_signature last_sig;
|
|
|
|
|
u64 cdb_id;
|
|
|
|
|
u8 *funding_wscript;
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
cdb_id = db_col_u64(stmt, "c.id");
|
|
|
|
|
last_tx = db_col_tx(stmt, stmt, "c.last_tx");
|
2020-05-21 22:45:14 -05:00
|
|
|
assert(last_tx != NULL);
|
|
|
|
|
|
2020-06-16 18:25:32 -05:00
|
|
|
/* If we've forgotten about the peer_id
|
|
|
|
|
* because we closed / forgot the channel,
|
|
|
|
|
* we can skip this. */
|
2021-11-15 04:30:46 +10:30
|
|
|
if (db_col_is_null(stmt, "p.node_id")) {
|
|
|
|
|
db_col_ignore(stmt, "c.funding_satoshi");
|
|
|
|
|
db_col_ignore(stmt, "c.fundingkey_remote");
|
|
|
|
|
db_col_ignore(stmt, "c.last_sig");
|
2020-06-16 18:25:32 -05:00
|
|
|
continue;
|
2021-11-15 04:30:46 +10:30
|
|
|
}
|
|
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
db_col_node_id(stmt, "p.node_id", &peer_id);
|
2023-07-22 16:42:57 +09:30
|
|
|
funding_sat = db_col_amount_sat(stmt, "c.funding_satoshi");
|
2021-11-15 04:28:46 +10:30
|
|
|
db_col_pubkey(stmt, "c.fundingkey_remote", &remote_funding_pubkey);
|
2020-05-21 22:45:14 -05:00
|
|
|
|
|
|
|
|
get_channel_basepoints(ld, &peer_id, cdb_id,
|
|
|
|
|
&local_basepoints, &local_funding_pubkey);
|
|
|
|
|
|
|
|
|
|
funding_wscript = bitcoin_redeem_2of2(stmt, &local_funding_pubkey,
|
|
|
|
|
&remote_funding_pubkey);
|
|
|
|
|
|
2020-09-09 19:40:29 +09:30
|
|
|
|
|
|
|
|
psbt_input_set_wit_utxo(last_tx->psbt, 0,
|
|
|
|
|
scriptpubkey_p2wsh(last_tx->psbt, funding_wscript),
|
|
|
|
|
funding_sat);
|
|
|
|
|
psbt_input_set_witscript(last_tx->psbt, 0, funding_wscript);
|
2020-07-10 16:09:46 -05:00
|
|
|
if (is_elements(chainparams)) {
|
|
|
|
|
/*FIXME: persist asset tags */
|
|
|
|
|
struct amount_asset asset;
|
|
|
|
|
asset = amount_sat_to_asset(&funding_sat,
|
|
|
|
|
chainparams->fee_asset_tag);
|
2020-09-09 19:40:29 +09:30
|
|
|
psbt_elements_input_set_asset(last_tx->psbt, 0, &asset);
|
|
|
|
|
}
|
|
|
|
|
|
2020-05-21 22:45:14 -05:00
|
|
|
|
2021-11-15 04:28:46 +10:30
|
|
|
if (!db_col_signature(stmt, "c.last_sig", &last_sig.s))
|
2020-05-21 22:45:14 -05:00
|
|
|
abort();
|
|
|
|
|
|
|
|
|
|
last_sig.sighash_type = SIGHASH_ALL;
|
2020-07-15 14:00:58 +12:00
|
|
|
if (!psbt_input_set_signature(last_tx->psbt, 0,
|
|
|
|
|
&remote_funding_pubkey, &last_sig))
|
2020-06-06 14:38:59 -05:00
|
|
|
abort();
|
2020-05-21 22:45:14 -05:00
|
|
|
psbt_input_add_pubkey(last_tx->psbt, 0,
|
2023-07-11 05:29:41 +09:30
|
|
|
&local_funding_pubkey, false /* is_taproot */);
|
2020-05-21 22:45:14 -05:00
|
|
|
psbt_input_add_pubkey(last_tx->psbt, 0,
|
2023-07-11 05:29:41 +09:30
|
|
|
&remote_funding_pubkey, false /* is_taproot */);
|
2020-05-21 22:45:14 -05:00
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET last_tx = ?"
|
|
|
|
|
" WHERE id = ?;"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_psbt(update_stmt, last_tx->psbt);
|
|
|
|
|
db_bind_int(update_stmt, cdb_id);
|
2020-05-21 22:45:14 -05:00
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
2022-09-19 10:19:53 +09:30
|
|
|
|
|
|
|
|
/* We used to store scids as strings... */
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_channels_scids_as_integers(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2022-09-19 10:19:53 +09:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
char **scids = tal_arr(tmpctx, char *, 0);
|
2022-12-06 11:19:16 +10:30
|
|
|
size_t changes;
|
2022-09-19 10:19:53 +09:30
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT short_channel_id FROM channels"));
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
if (db_col_is_null(stmt, "short_channel_id"))
|
|
|
|
|
continue;
|
|
|
|
|
tal_arr_expand(&scids,
|
|
|
|
|
db_col_strdup(scids, stmt, "short_channel_id"));
|
|
|
|
|
}
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
|
2022-12-06 11:19:16 +10:30
|
|
|
changes = 0;
|
2022-09-19 10:19:53 +09:30
|
|
|
for (size_t i = 0; i < tal_count(scids); i++) {
|
|
|
|
|
struct short_channel_id scid;
|
|
|
|
|
if (!short_channel_id_from_str(scids[i], strlen(scids[i]), &scid))
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db, "Cannot convert invalid channels.short_channel_id '%s'",
|
2022-09-19 10:19:53 +09:30
|
|
|
scids[i]);
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET scid = ?"
|
|
|
|
|
" WHERE short_channel_id = ?"));
|
2024-03-20 12:29:51 +10:30
|
|
|
db_bind_short_channel_id(stmt, scid);
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_text(stmt, scids[i]);
|
2022-09-19 10:19:53 +09:30
|
|
|
db_exec_prepared_v2(stmt);
|
2022-12-06 11:19:16 +10:30
|
|
|
|
|
|
|
|
/* This was reported to happen with an (old, closed) channel: that we'd have
|
|
|
|
|
* more than one change here! That's weird, but just log about it. */
|
2022-09-19 10:19:53 +09:30
|
|
|
if (db_count_changes(stmt) != 1)
|
2022-12-06 11:19:16 +10:30
|
|
|
log_broken(ld->log,
|
|
|
|
|
"migrate_channels_scids_as_integers: converting channels.short_channel_id '%s' gave %zu changes != 1!",
|
|
|
|
|
scids[i], db_count_changes(stmt));
|
|
|
|
|
changes += db_count_changes(stmt);
|
2022-09-19 10:19:53 +09:30
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2022-12-06 11:19:16 +10:30
|
|
|
if (changes != tal_count(scids))
|
2023-03-07 08:50:17 +10:30
|
|
|
log_broken(ld->log, "migrate_channels_scids_as_integers: only converted %zu of %zu scids!",
|
|
|
|
|
changes, tal_count(scids));
|
2022-12-06 11:19:16 +10:30
|
|
|
|
2022-09-19 10:19:53 +09:30
|
|
|
/* FIXME: We cannot use ->delete_columns to remove
|
|
|
|
|
* short_channel_id, as other tables reference the channels
|
|
|
|
|
* (and sqlite3 has them referencing a now-deleted table!).
|
2025-07-17 13:18:34 +09:30
|
|
|
* When we can assume sqlite3 version 3.35.5 (2021-04-19),
|
|
|
|
|
* we can simply use DROP COLUMN (yay!) */
|
2022-09-19 10:24:26 +09:30
|
|
|
|
|
|
|
|
/* So null-out the unused column, at least! */
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET short_channel_id = NULL;"));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
2022-09-19 10:19:53 +09:30
|
|
|
}
|
2022-09-19 10:19:53 +09:30
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_payments_scids_as_integers(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2022-09-19 10:19:53 +09:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
const char *colnames[] = {"failchannel"};
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT id, failchannel FROM payments"));
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
struct short_channel_id scid;
|
|
|
|
|
const char *str;
|
|
|
|
|
|
|
|
|
|
if (db_col_is_null(stmt, "failchannel")) {
|
|
|
|
|
db_col_ignore(stmt, "id");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
str = db_col_strdup(tmpctx, stmt, "failchannel");
|
|
|
|
|
if (!short_channel_id_from_str(str, strlen(str), &scid))
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db, "Cannot convert invalid payments.failchannel '%s'",
|
2022-09-19 10:19:53 +09:30
|
|
|
str);
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE payments SET"
|
|
|
|
|
" failscid = ?"
|
|
|
|
|
" WHERE id = ?"));
|
2024-03-20 12:29:51 +10:30
|
|
|
db_bind_short_channel_id(update_stmt, scid);
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_u64(update_stmt, db_col_u64(stmt, "id"));
|
2022-09-19 10:19:53 +09:30
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
|
|
|
|
|
if (!db->config->delete_columns(db, "payments", colnames, ARRAY_SIZE(colnames)))
|
2023-06-30 04:53:08 +09:30
|
|
|
db_fatal(db, "Could not delete payments.failchannel");
|
2022-09-19 10:19:53 +09:30
|
|
|
}
|
db-fix: update NULL lease_satoshi fields to zero
Missed a DEFAULT in the db clause.
Feb 15 16:02:12 citrine lightningd[902093]: Accessing a null column lease_satoshi/15 in query SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start, lease_fee, lease_satoshi FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate
Fixes #6016
2023-02-15 16:21:44 -06:00
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void fillin_missing_lease_satoshi(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
db-fix: update NULL lease_satoshi fields to zero
Missed a DEFAULT in the db clause.
Feb 15 16:02:12 citrine lightningd[902093]: Accessing a null column lease_satoshi/15 in query SELECT funding_tx_id, funding_tx_outnum, funding_feerate, funding_satoshi, our_funding_satoshi, funding_psbt, last_tx, last_sig, funding_tx_remote_sigs_received, lease_expiry, lease_commit_sig, lease_chan_max_msat, lease_chan_max_ppt, lease_blockheight_start, lease_fee, lease_satoshi FROM channel_funding_inflights WHERE channel_id = ? ORDER BY funding_feerate
Fixes #6016
2023-02-15 16:21:44 -06:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE channel_funding_inflights"
|
|
|
|
|
" SET lease_satoshi = 0"
|
|
|
|
|
" WHERE lease_satoshi IS NULL;"));
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
2023-03-30 15:55:21 +10:30
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_fill_in_channel_type(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2023-04-10 09:52:56 +09:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT id, local_static_remotekey_start, option_anchor_outputs, channel_flags, alias_remote, minimum_depth FROM channels"));
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
struct channel_type *type;
|
|
|
|
|
u64 id = db_col_u64(stmt, "id");
|
|
|
|
|
int channel_flags = db_col_int(stmt, "channel_flags");
|
|
|
|
|
|
|
|
|
|
if (db_col_int(stmt, "option_anchor_outputs")) {
|
|
|
|
|
db_col_ignore(stmt, "local_static_remotekey_start");
|
2024-06-19 09:31:01 +09:30
|
|
|
type = channel_type_anchor_outputs_obsolete(tmpctx);
|
2023-04-10 09:52:56 +09:30
|
|
|
} else if (db_col_u64(stmt, "local_static_remotekey_start") != 0x7FFFFFFFFFFFFFFFULL)
|
|
|
|
|
type = channel_type_static_remotekey(tmpctx);
|
|
|
|
|
else
|
2024-06-19 09:30:01 +09:30
|
|
|
type = channel_type_none_obsolete(tmpctx);
|
2023-04-10 09:52:56 +09:30
|
|
|
|
|
|
|
|
/* We didn't keep type in db, so assume all private
|
|
|
|
|
* channels which support aliases don't want us to fwd
|
|
|
|
|
* unless using alias, which is how we behaved
|
|
|
|
|
* before. */
|
|
|
|
|
if (!db_col_is_null(stmt, "alias_remote")
|
|
|
|
|
&& !(channel_flags & CHANNEL_FLAGS_ANNOUNCE_CHANNEL))
|
|
|
|
|
channel_type_set_scid_alias(type);
|
|
|
|
|
|
|
|
|
|
if (db_col_int(stmt, "minimum_depth") == 0)
|
|
|
|
|
channel_type_set_zeroconf(type);
|
|
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE channels SET"
|
|
|
|
|
" channel_type = ?"
|
|
|
|
|
" WHERE id = ?"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_channel_type(update_stmt, type);
|
|
|
|
|
db_bind_u64(update_stmt, id);
|
2023-04-10 09:52:56 +09:30
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_initialize_invoice_wait_indexes(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2023-07-22 17:15:49 +09:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
|
|
/* "invoices.id" serves as the created_index. It's never 0. */
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT MAX(id) FROM invoices;"));
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
res = db_step(stmt);
|
|
|
|
|
assert(res);
|
|
|
|
|
|
|
|
|
|
if (!db_col_is_null(stmt, "MAX(id)"))
|
|
|
|
|
db_set_intvar(db, "last_invoice_created_index",
|
|
|
|
|
db_col_u64(stmt, "MAX(id)"));
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_invoice_created_index_var(struct lightningd *ld, struct db *db)
|
2023-07-27 09:45:25 +09:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
2023-07-31 11:26:17 +09:30
|
|
|
s64 badindex, realindex;
|
|
|
|
|
|
|
|
|
|
/* Prior migration had a typo! But we might have run since
|
|
|
|
|
* then and created an invoice, so we have to set the real one
|
|
|
|
|
* to the max of the two... */
|
|
|
|
|
badindex = db_get_intvar(db, "last_invoice_created_index", -1);
|
|
|
|
|
realindex = db_get_intvar(db, "last_invoices_created_index", -1);
|
|
|
|
|
|
|
|
|
|
/* Bad index does not exist? Fine */
|
|
|
|
|
if (badindex < 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
/* Bad index exists, real index doesn't? Rename */
|
|
|
|
|
if (badindex >= 0 && realindex < 0) {
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE vars"
|
|
|
|
|
" SET name = 'last_invoices_created_index'"
|
|
|
|
|
" WHERE name = 'last_invoice_created_index'"));
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Both exist. Correct value is the higher one. */
|
|
|
|
|
if (badindex > realindex)
|
|
|
|
|
realindex = badindex;
|
2023-07-27 09:45:25 +09:30
|
|
|
|
2023-07-31 11:26:17 +09:30
|
|
|
/* Update correct one, remove bad one. */
|
|
|
|
|
db_set_intvar(db, "last_invoices_created_index", realindex);
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("DELETE FROM vars"
|
2023-07-27 09:45:25 +09:30
|
|
|
" WHERE name = 'last_invoice_created_index'"));
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2023-10-27 16:07:28 +10:30
|
|
|
/* We expect to have a few of these... */
|
|
|
|
|
static void migrate_initialize_wait_indexes(struct db *db,
|
|
|
|
|
enum wait_subsystem subsystem,
|
|
|
|
|
enum wait_index index,
|
|
|
|
|
const char *query,
|
|
|
|
|
const char *colname)
|
|
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
bool res;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, query);
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
res = db_step(stmt);
|
|
|
|
|
assert(res);
|
|
|
|
|
|
|
|
|
|
if (!db_col_is_null(stmt, colname))
|
|
|
|
|
db_set_intvar(db,
|
|
|
|
|
tal_fmt(tmpctx, "last_%s_%s_index",
|
|
|
|
|
wait_subsystem_name(subsystem),
|
|
|
|
|
wait_index_name(index)),
|
|
|
|
|
db_col_u64(stmt, colname));
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_initialize_payment_wait_indexes(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2023-10-27 16:07:28 +10:30
|
|
|
{
|
|
|
|
|
migrate_initialize_wait_indexes(db,
|
|
|
|
|
WAIT_SUBSYSTEM_SENDPAY,
|
|
|
|
|
WAIT_INDEX_CREATED,
|
|
|
|
|
SQL("SELECT MAX(id) FROM payments;"),
|
|
|
|
|
"MAX(id)");
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_forwards_add_rowid(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2023-10-28 13:41:01 +10:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
/* sqlite3 has implicit "rowid" column already */
|
|
|
|
|
if (streq(db->config->name, "sqlite3"))
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("ALTER TABLE forwards ADD rowid BIGINT"));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
|
|
|
|
|
/* Yes, I got ChatGPT to write this for me! */
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("WITH numbered_rows AS ("
|
|
|
|
|
" SELECT in_channel_scid, in_htlc_id, row_number() OVER () AS rn"
|
|
|
|
|
" FROM forwards)"
|
|
|
|
|
" UPDATE forwards"
|
|
|
|
|
" SET rowid = numbered_rows.rn"
|
|
|
|
|
" FROM numbered_rows"
|
|
|
|
|
" WHERE forwards.in_channel_scid = numbered_rows.in_channel_scid"
|
|
|
|
|
" AND forwards.in_htlc_id = numbered_rows.in_htlc_id;"));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("CREATE INDEX forwards_created_idx ON forwards (rowid)"));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_initialize_forwards_wait_indexes(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2023-10-28 13:41:01 +10:30
|
|
|
{
|
|
|
|
|
migrate_initialize_wait_indexes(db,
|
|
|
|
|
WAIT_SUBSYSTEM_FORWARD,
|
|
|
|
|
WAIT_INDEX_CREATED,
|
|
|
|
|
SQL("SELECT MAX(rowid) FROM forwards;"),
|
|
|
|
|
"MAX(rowid)");
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_initialize_channel_htlcs_wait_indexes_and_fixup_forwards(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2025-04-28 14:15:23 +09:30
|
|
|
{
|
2025-05-17 22:37:11 +09:30
|
|
|
/* A previous badly-written migration (now NULL-ed out) set
|
|
|
|
|
* the forwards, not htlc index! Set the htlcs migration, and fixup forwards. */
|
2025-04-28 14:15:23 +09:30
|
|
|
migrate_initialize_wait_indexes(db,
|
2025-05-17 22:37:11 +09:30
|
|
|
WAIT_SUBSYSTEM_HTLCS,
|
2025-04-28 14:15:23 +09:30
|
|
|
WAIT_INDEX_CREATED,
|
|
|
|
|
SQL("SELECT MAX(id) FROM channel_htlcs;"),
|
|
|
|
|
"MAX(id)");
|
2025-05-17 22:37:11 +09:30
|
|
|
migrate_initialize_forwards_wait_indexes(ld, db);
|
2025-04-28 14:15:23 +09:30
|
|
|
}
|
|
|
|
|
|
2023-03-30 15:55:21 +10:30
|
|
|
static void complain_unfixed(struct lightningd *ld,
|
|
|
|
|
enum channel_state state,
|
|
|
|
|
u64 id,
|
|
|
|
|
const u8 *bytes,
|
|
|
|
|
const char *why)
|
|
|
|
|
{
|
|
|
|
|
/* This is OK on closed channels */
|
|
|
|
|
if (state != CLOSED) {
|
|
|
|
|
log_broken(ld->log,
|
|
|
|
|
"%s channel id %"PRIu64" PSBT hex '%s'",
|
|
|
|
|
why, id, tal_hex(tmpctx, bytes));
|
|
|
|
|
} else {
|
|
|
|
|
log_debug(ld->log,
|
|
|
|
|
"%s on closed channel id %"PRIu64" PSBT hex '%s'",
|
|
|
|
|
why, id, tal_hex(tmpctx, bytes));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_invalid_last_tx_psbts(struct lightningd *ld, struct db *db)
|
2023-03-30 15:55:21 +10:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
/* We try all of them, but note that last_tx used to be a tx,
|
|
|
|
|
* and migrate_last_tx_to_psbt didn't convert channels which had
|
|
|
|
|
* already been closed, so we expect some failures. */
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT "
|
|
|
|
|
" id"
|
|
|
|
|
", state"
|
|
|
|
|
", last_tx"
|
|
|
|
|
" FROM channels"));
|
|
|
|
|
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
const u8 *bytes, *fixed;
|
|
|
|
|
enum channel_state state;
|
|
|
|
|
u64 id;
|
|
|
|
|
struct wally_psbt *psbt;
|
|
|
|
|
|
|
|
|
|
state = db_col_int(stmt, "state");
|
|
|
|
|
id = db_col_u64(stmt, "id");
|
|
|
|
|
|
|
|
|
|
/* Parses fine? */
|
|
|
|
|
if (db_col_psbt(tmpctx, stmt, "last_tx"))
|
|
|
|
|
continue;
|
|
|
|
|
|
|
|
|
|
/* Can we fix it? */
|
|
|
|
|
bytes = db_col_arr(tmpctx, stmt, "last_tx", u8);
|
|
|
|
|
fixed = psbt_fixup(tmpctx, bytes);
|
|
|
|
|
if (!fixed) {
|
|
|
|
|
complain_unfixed(ld, state, id, bytes, "Could not fix");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
psbt = psbt_from_bytes(tmpctx, fixed, tal_bytelen(fixed));
|
|
|
|
|
if (!psbt) {
|
|
|
|
|
complain_unfixed(ld, state, id, fixed, "Fix made invalid psbt");
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
log_broken(ld->log, "Forced database repair of psbt %s -> %s",
|
|
|
|
|
tal_hex(tmpctx, bytes), tal_hex(tmpctx, fixed));
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET last_tx = ?"
|
|
|
|
|
" WHERE id = ?;"));
|
2023-07-14 09:58:46 +09:30
|
|
|
db_bind_psbt(update_stmt, psbt);
|
|
|
|
|
db_bind_u64(update_stmt, id);
|
2023-03-30 15:55:21 +10:30
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
2023-06-13 12:36:16 +02:00
|
|
|
/**
|
|
|
|
|
* We store the bolt11 string in several places with the `lightning:` prefix, so
|
|
|
|
|
* we update one by one by lowering and normalize the string in a canonical one.
|
|
|
|
|
*
|
|
|
|
|
* See also `to_canonical_invstr` in `common/bolt11.c` the definition of
|
|
|
|
|
* canonical invoice.
|
|
|
|
|
*/
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_normalize_invstr(struct lightningd *ld, struct db *db)
|
2023-06-13 12:36:16 +02:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT bolt11, id"
|
|
|
|
|
" FROM invoices"
|
|
|
|
|
" WHERE bolt11 IS NOT NULL;"));
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
u64 id;
|
|
|
|
|
const char *invstr;
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
|
|
|
|
|
id = db_col_u64(stmt, "id");
|
|
|
|
|
invstr = db_col_strdup(tmpctx, stmt, "bolt11");
|
|
|
|
|
invstr = to_canonical_invstr(tmpctx, invstr);
|
|
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE invoices"
|
|
|
|
|
" SET bolt11 = ?"
|
|
|
|
|
" WHERE id = ?;"));
|
wallet: Fixes the compilation error due the db_binindings change
Currently our CI is not able to complete the compilation because
there is the following compilation error introduced in `0bcff1e76d`
```
cc wallet/db.c
wallet/db.c: In function 'migrate_normalize_invstr':
wallet/db.c:1734:3: error: too many arguments to function 'db_bind_text'
1734 | db_bind_text(update_stmt, 0, invstr);
| ^~~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:25:6: note: declared here
25 | void db_bind_text(struct db_stmt *stmt, const char *val);
| ^~~~~~~~~~~~
wallet/db.c:1735:3: error: too many arguments to function 'db_bind_u64'
1735 | db_bind_u64(update_stmt, 1, id);
| ^~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:23:6: note: declared here
23 | void db_bind_u64(struct db_stmt *stmt, u64 val);
| ^~~~~~~~~~~
wallet/db.c:1758:3: error: too many arguments to function 'db_bind_text'
1758 | db_bind_text(update_stmt, 0, invstr);
| ^~~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:25:6: note: declared here
25 | void db_bind_text(struct db_stmt *stmt, const char *val);
| ^~~~~~~~~~~~
wallet/db.c:1759:3: error: too many arguments to function 'db_bind_u64'
1759 | db_bind_u64(update_stmt, 1, id);
| ^~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:23:6: note: declared here
23 | void db_bind_u64(struct db_stmt *stmt, u64 val);
| ^~~~~~~~~~~
make: *** [Makefile:299: wallet/db.o] Error 1
make: *** Waiting for unfinished jobs....
rm external/build-x86_64-linux-gnu/libwally-core-build/src/secp256k1/libsecp256k1.la
```
Fixes: 0bcff1e76d
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
2023-07-18 16:00:56 +02:00
|
|
|
db_bind_text(update_stmt, invstr);
|
|
|
|
|
db_bind_u64(update_stmt, id);
|
2023-06-13 12:36:16 +02:00
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT bolt11, id"
|
|
|
|
|
" FROM payments"
|
|
|
|
|
" WHERE bolt11 IS NOT NULL;"));
|
|
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt)) {
|
|
|
|
|
u64 id;
|
|
|
|
|
const char *invstr;
|
|
|
|
|
struct db_stmt *update_stmt;
|
|
|
|
|
|
|
|
|
|
id = db_col_u64(stmt, "id");
|
|
|
|
|
invstr = db_col_strdup(tmpctx, stmt, "bolt11");
|
|
|
|
|
invstr = to_canonical_invstr(tmpctx, invstr);
|
|
|
|
|
|
|
|
|
|
update_stmt = db_prepare_v2(db, SQL("UPDATE payments"
|
|
|
|
|
" SET bolt11 = ?"
|
|
|
|
|
" WHERE id = ?;"));
|
wallet: Fixes the compilation error due the db_binindings change
Currently our CI is not able to complete the compilation because
there is the following compilation error introduced in `0bcff1e76d`
```
cc wallet/db.c
wallet/db.c: In function 'migrate_normalize_invstr':
wallet/db.c:1734:3: error: too many arguments to function 'db_bind_text'
1734 | db_bind_text(update_stmt, 0, invstr);
| ^~~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:25:6: note: declared here
25 | void db_bind_text(struct db_stmt *stmt, const char *val);
| ^~~~~~~~~~~~
wallet/db.c:1735:3: error: too many arguments to function 'db_bind_u64'
1735 | db_bind_u64(update_stmt, 1, id);
| ^~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:23:6: note: declared here
23 | void db_bind_u64(struct db_stmt *stmt, u64 val);
| ^~~~~~~~~~~
wallet/db.c:1758:3: error: too many arguments to function 'db_bind_text'
1758 | db_bind_text(update_stmt, 0, invstr);
| ^~~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:25:6: note: declared here
25 | void db_bind_text(struct db_stmt *stmt, const char *val);
| ^~~~~~~~~~~~
wallet/db.c:1759:3: error: too many arguments to function 'db_bind_u64'
1759 | db_bind_u64(update_stmt, 1, id);
| ^~~~~~~~~~~
In file included from wallet/db.c:10:
./db/bindings.h:23:6: note: declared here
23 | void db_bind_u64(struct db_stmt *stmt, u64 val);
| ^~~~~~~~~~~
make: *** [Makefile:299: wallet/db.o] Error 1
make: *** Waiting for unfinished jobs....
rm external/build-x86_64-linux-gnu/libwally-core-build/src/secp256k1/libsecp256k1.la
```
Fixes: 0bcff1e76d
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
2023-07-18 16:00:56 +02:00
|
|
|
db_bind_text(update_stmt, invstr);
|
|
|
|
|
db_bind_u64(update_stmt, id);
|
2023-06-13 12:36:16 +02:00
|
|
|
db_exec_prepared_v2(update_stmt);
|
|
|
|
|
|
|
|
|
|
tal_free(update_stmt);
|
|
|
|
|
}
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
2024-02-08 09:56:17 +10:30
|
|
|
|
|
|
|
|
/* We required local aliases to be set on established channels,
|
|
|
|
|
* but we forgot about already-existing ones in the db! */
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_initialize_alias_local(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2024-02-08 09:56:17 +10:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
u64 *ids = tal_arr(tmpctx, u64, 0);
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("SELECT id FROM channels"
|
2025-08-14 12:40:11 +09:30
|
|
|
" WHERE alias_local IS NULL;"));
|
2024-02-08 09:56:17 +10:30
|
|
|
db_query_prepared(stmt);
|
|
|
|
|
while (db_step(stmt))
|
|
|
|
|
tal_arr_expand(&ids, db_col_u64(stmt, "id"));
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
|
|
|
|
|
for (size_t i = 0; i < tal_count(ids); i++) {
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE channels"
|
|
|
|
|
" SET alias_local = ?"
|
|
|
|
|
" WHERE id = ?;"));
|
|
|
|
|
/* We don't even check for clashes! */
|
2025-08-14 12:40:11 +09:30
|
|
|
db_bind_short_channel_id(stmt, random_scid());
|
2024-02-08 09:56:17 +10:30
|
|
|
db_bind_u64(stmt, ids[i]);
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
}
|
2024-11-13 17:24:26 -08:00
|
|
|
|
|
|
|
|
/* Insert address type as `ADDR_ALL` for issued addresses */
|
2025-11-27 15:15:36 +10:30
|
|
|
void insert_addrtype_to_addresses(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2024-11-13 17:24:26 -08:00
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
u64 bip32_max_index = db_get_intvar(db, "bip32_max_index", 0);
|
|
|
|
|
for (u64 newidx = 1; newidx <= bip32_max_index; newidx++) {
|
|
|
|
|
stmt = db_prepare_v2(db,
|
|
|
|
|
SQL("INSERT INTO addresses ("
|
|
|
|
|
" keyidx"
|
|
|
|
|
", addrtype"
|
|
|
|
|
") VALUES (?, ?);"));
|
|
|
|
|
db_bind_u64(stmt, newidx);
|
|
|
|
|
db_bind_int(stmt, wallet_addrtype_in_db(ADDR_ALL));
|
|
|
|
|
db_exec_prepared_v2(stmt);
|
|
|
|
|
tal_free(stmt);
|
|
|
|
|
}
|
|
|
|
|
}
|
2025-03-31 11:26:19 +10:30
|
|
|
|
|
|
|
|
/* If we said a channel final key was taproot-only, but actually the peer
|
|
|
|
|
* didn't support `option_shutdown_anysegwit`, we used the p2wpkh instead. We
|
|
|
|
|
* don't have access to the peers' features in the db, so instead convert all
|
|
|
|
|
* the keys to ADDR_ALL. Users with closed channels may still need to
|
|
|
|
|
* rescan! */
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_convert_old_channel_keyidx(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2025-03-31 11:26:19 +10:30
|
|
|
{
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE addresses"
|
|
|
|
|
" SET addrtype = ?"
|
2025-04-22 23:32:57 +02:00
|
|
|
" WHERE keyidx IN (SELECT shutdown_keyidx_local FROM channels"
|
|
|
|
|
" WHERE state != ?"
|
|
|
|
|
" AND state != ?"
|
|
|
|
|
" AND state != ?)"));
|
2025-03-31 11:26:19 +10:30
|
|
|
db_bind_int(stmt, wallet_addrtype_in_db(ADDR_ALL));
|
|
|
|
|
/* If we might have already seen onchain funds, we need to rescan */
|
|
|
|
|
db_bind_int(stmt, channel_state_in_db(FUNDING_SPEND_SEEN));
|
|
|
|
|
db_bind_int(stmt, channel_state_in_db(ONCHAIN));
|
|
|
|
|
db_bind_int(stmt, channel_state_in_db(CLOSED));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
}
|
2025-11-13 15:21:10 +10:30
|
|
|
|
2025-11-27 15:15:36 +10:30
|
|
|
void migrate_fail_pending_payments_without_htlcs(struct lightningd *ld,
|
|
|
|
|
struct db *db)
|
2025-11-13 15:21:10 +10:30
|
|
|
{
|
|
|
|
|
/* If channeld died or was offline at the right moment, we
|
|
|
|
|
* could register a payment as pending, but then not create an
|
|
|
|
|
* HTLC. Clean those up. */
|
|
|
|
|
struct db_stmt *stmt;
|
|
|
|
|
|
|
|
|
|
stmt = db_prepare_v2(db, SQL("UPDATE payments AS p"
|
|
|
|
|
" SET status = ?"
|
|
|
|
|
" WHERE p.status = ?"
|
|
|
|
|
" AND NOT EXISTS ("
|
|
|
|
|
" SELECT 1"
|
|
|
|
|
" FROM channel_htlcs AS h"
|
|
|
|
|
" WHERE h.payment_hash = p.payment_hash"
|
|
|
|
|
" AND h.groupid = p.groupid"
|
|
|
|
|
" AND h.partid = p.partid);"));
|
|
|
|
|
db_bind_int(stmt, payment_status_in_db(PAYMENT_FAILED));
|
|
|
|
|
db_bind_int(stmt, payment_status_in_db(PAYMENT_PENDING));
|
|
|
|
|
db_exec_prepared_v2(take(stmt));
|
|
|
|
|
}
|