diff --git a/wallet/db.c b/wallet/db.c index c0ec46e67..0b2e2fd12 100644 --- a/wallet/db.c +++ b/wallet/db.c @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -15,6 +16,7 @@ #include #include #include +#include #include #include #include @@ -62,6 +64,9 @@ static void migrate_invalid_last_tx_psbts(struct lightningd *ld, static void migrate_fill_in_channel_type(struct lightningd *ld, struct db *db); +static void migrate_normalize_invstr(struct lightningd *ld, + struct db *db); + /* Do not reorder or remove elements from this array, it is used to * migrate existing databases from a previous state, based on the * string indices */ @@ -950,6 +955,7 @@ static struct migration dbmigrations[] = { {SQL("ALTER TABLE channels ADD channel_type BLOB DEFAULT NULL;"), NULL}, {NULL, migrate_fill_in_channel_type}, {SQL("ALTER TABLE peers ADD feature_bits BLOB DEFAULT NULL;"), NULL}, + {NULL, migrate_normalize_invstr}, }; /** @@ -1698,3 +1704,62 @@ static void migrate_invalid_last_tx_psbts(struct lightningd *ld, } tal_free(stmt); } +/** + * 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. + */ +static void migrate_normalize_invstr(struct lightningd *ld, struct db *db) +{ + 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 = ?;")); + db_bind_text(update_stmt, 0, invstr); + db_bind_u64(update_stmt, 1, id); + 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 = ?;")); + db_bind_text(update_stmt, 0, invstr); + db_bind_u64(update_stmt, 1, id); + db_exec_prepared_v2(update_stmt); + + tal_free(update_stmt); + } + tal_free(stmt); +} diff --git a/wallet/test/run-db.c b/wallet/test/run-db.c index 80cf0f19a..f8f9adcfa 100644 --- a/wallet/test/run-db.c +++ b/wallet/test/run-db.c @@ -65,6 +65,9 @@ u8 *wire_sync_read(const tal_t *ctx UNNEEDED, int fd UNNEEDED) /* Generated stub for wire_sync_write */ bool wire_sync_write(int fd UNNEEDED, const void *msg TAKES UNNEEDED) { fprintf(stderr, "wire_sync_write called!\n"); abort(); } +/* Generated stub for strip_lightning_prefix */ +const char *to_canonical_invstr(const tal_t *ctx, const char *invstring UNNEEDED) +{ fprintf(stderr, "strip_lightning_prefix called!\n"); abort(); } /* AUTOGENERATED MOCKS END */ void plugin_hook_db_sync(struct db *db UNNEEDED) diff --git a/wallet/test/run-wallet.c b/wallet/test/run-wallet.c index 1792a2c85..5b4e64612 100644 --- a/wallet/test/run-wallet.c +++ b/wallet/test/run-wallet.c @@ -38,6 +38,9 @@ static void test_error(struct lightningd *ld, bool fatal, const char *fmt, va_li #include /* AUTOGENERATED MOCKS START */ +/* Generated stub for strip_lightning_prefix */ +const char *to_canonical_invstr(const tal_t *ctx, const char *invstring UNNEEDED) +{ fprintf(stderr, "strip_lightning_prefix called!\n"); abort(); } /* Generated stub for bigsize_put */ size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED) { fprintf(stderr, "bigsize_put called!\n"); abort(); }