Skip to content

Commit fb973fe

Browse files
committed
wallet: find and remove any duplicates from the bug we just fixed.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 7631ce6 commit fb973fe

File tree

3 files changed

+84
-0
lines changed

3 files changed

+84
-0
lines changed

wallet/db.c

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1093,6 +1093,8 @@ static struct migration dbmigrations[] = {
10931093
/* We do a lookup before each append, to avoid duplicates */
10941094
{SQL("CREATE INDEX chain_moves_utxo_idx ON chain_moves (utxo)"), NULL},
10951095
{NULL, migrate_from_account_db},
1096+
/* We accidentally allowed duplicate entries */
1097+
{NULL, migrate_remove_chain_moves_duplicates}
10961098
};
10971099

10981100
/**

wallet/wallet.c

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7723,3 +7723,84 @@ void migrate_setup_coinmoves(struct lightningd *ld, struct db *db)
77237723
tal_free(stmt);
77247724
}
77257725

7726+
/* When we imported from accounts.db, we always used a reference into
7727+
* the move_accounts table (via account_nonchannel_id). But (on
7728+
* replay) if a channel was live, we used the reference into the
7729+
* channels table (via account_channel_id) and our duplicate detection
7730+
* didn't trigger. Now we need to get rid of such duplicates.
7731+
*
7732+
* Note that if the channel is now CLOSED, the references to account_channel_id
7733+
* will have been converted to references using account_nonchannel_id. */
7734+
void migrate_remove_chain_moves_duplicates(struct lightningd *ld, struct db *db)
7735+
{
7736+
/* This is O(n^2) but there just aren't that many! */
7737+
u64 *to_delete = tal_arr(tmpctx, u64, 0);
7738+
struct db_stmt *stmt;
7739+
7740+
/* Gather */
7741+
stmt = db_prepare_v2(db, SQL("SELECT"
7742+
" chain_moves.id,"
7743+
" utxo,"
7744+
" spending_txid,"
7745+
" tag_bitmap,"
7746+
" account_channel_id,"
7747+
" channels.full_channel_id,"
7748+
" move_accounts.name"
7749+
" FROM chain_moves "
7750+
" LEFT JOIN move_accounts "
7751+
" ON move_accounts.id = chain_moves.account_nonchannel_id "
7752+
" LEFT JOIN channels "
7753+
" ON channels.id = chain_moves.account_channel_id "
7754+
" ORDER BY move_accounts.id;"));
7755+
db_query_prepared(stmt);
7756+
while (db_step(stmt)) {
7757+
struct bitcoin_outpoint outpoint;
7758+
u64 id, channel_dbid;
7759+
struct bitcoin_txid *spending_txid;
7760+
struct mvt_tags tags;
7761+
const char *nonchannel_acctname;
7762+
7763+
id = db_col_u64(stmt, "chain_moves.id");
7764+
db_col_outpoint(stmt, "utxo", &outpoint);
7765+
if (db_col_is_null(stmt, "spending_txid"))
7766+
spending_txid = NULL;
7767+
else {
7768+
spending_txid = tal(tmpctx, struct bitcoin_txid);
7769+
db_col_txid(stmt, "spending_txid", spending_txid);
7770+
}
7771+
tags = db_col_mvt_tags(stmt, "tag_bitmap");
7772+
if (db_col_is_null(stmt, "account_channel_id")) {
7773+
channel_dbid = 0;
7774+
nonchannel_acctname = db_col_strdup(tmpctx, stmt, "move_accounts.name");
7775+
db_col_ignore(stmt, "channels.full_channel_id");
7776+
} else {
7777+
struct channel_id cid;
7778+
channel_dbid = db_col_u64(stmt, "account_channel_id");
7779+
db_col_channel_id(stmt, "channels.full_channel_id", &cid);
7780+
nonchannel_acctname = fmt_channel_id(tmpctx, &cid);
7781+
}
7782+
7783+
if (find_duplicate_chain_move(db, nonchannel_acctname,
7784+
channel_dbid,
7785+
&outpoint,
7786+
spending_txid,
7787+
tags,
7788+
id)) {
7789+
log_unusual(ld->log,
7790+
"Deleting redundant chain_moves %"PRIu64" for account %s",
7791+
id, nonchannel_acctname);
7792+
tal_arr_expand(&to_delete, id);
7793+
}
7794+
}
7795+
tal_free(stmt);
7796+
7797+
/* Do the delete. We do it separately to avoid any db issues
7798+
* while iterating */
7799+
for (size_t i = 0; i < tal_count(to_delete); i++) {
7800+
stmt = db_prepare_v2(db,
7801+
SQL("DELETE FROM chain_moves "
7802+
"WHERE id = ?;"));
7803+
db_bind_u64(stmt, to_delete[i]);
7804+
db_exec_prepared_v2(take(stmt));
7805+
}
7806+
}

wallet/wallet.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1926,6 +1926,7 @@ void wallet_datastore_save_payment_description(struct db *db,
19261926
const struct sha256 *payment_hash,
19271927
const char *desc);
19281928
void migrate_setup_coinmoves(struct lightningd *ld, struct db *db);
1929+
void migrate_remove_chain_moves_duplicates(struct lightningd *ld, struct db *db);
19291930

19301931
/**
19311932
* wallet_memleak_scan - Check for memleaks in wallet.

0 commit comments

Comments
 (0)