Skip to content

Commit 07669a0

Browse files
rustyrussellendothermicdev
authored andcommitted
lightningd: rescan for missing p2wkph for closed channels.
This can happen with 24.11 and later. We scan back to exposed channel opens, or that release. The BROKEN log messages cause some tests to fail, so we fix those. Fixes: #8169 Changelog-Fixed: wallet: rescan for missing close outputs (can happen if peer doesn't support option_shutdown_anysegwit)
1 parent 8c2d537 commit 07669a0

File tree

7 files changed

+212
-8
lines changed

7 files changed

+212
-8
lines changed

Diff for: lightningd/lightningd.c

+6
Original file line numberDiff line numberDiff line change
@@ -1471,6 +1471,12 @@ int main(int argc, char *argv[])
14711471
if (ld->daemon_parent_fd != -1)
14721472
complete_daemonize(ld);
14731473

1474+
/*~ At one stage, we didn't catch mutual closes with old node to p2wkph
1475+
* so now we start a scan if the db doesn't say we completed it. */
1476+
db_begin_transaction(ld->wallet->db);
1477+
wallet_begin_old_close_rescan(ld);
1478+
db_commit_transaction(ld->wallet->db);
1479+
14741480
/*~ Setting this (global) activates the crash log: we don't usually need
14751481
* a backtrace if we fail during startup. */
14761482
crashlog = ld->log;

Diff for: lightningd/test/run-find_my_abspath.c

+3
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,9 @@ const char *version(void)
286286
void waitblockheight_notify_new_block(struct lightningd *ld UNNEEDED,
287287
u32 block_height UNNEEDED)
288288
{ fprintf(stderr, "waitblockheight_notify_new_block called!\n"); abort(); }
289+
/* Generated stub for wallet_begin_old_close_rescan */
290+
void wallet_begin_old_close_rescan(struct lightningd *ld UNNEEDED)
291+
{ fprintf(stderr, "wallet_begin_old_close_rescan called!\n"); abort(); }
289292
/* Generated stub for wallet_new */
290293
struct wallet *wallet_new(struct lightningd *ld UNNEEDED, struct timers *timers UNNEEDED)
291294
{ fprintf(stderr, "wallet_new called!\n"); abort(); }

Diff for: wallet/db.c

+2
Original file line numberDiff line numberDiff line change
@@ -1033,6 +1033,8 @@ static struct migration dbmigrations[] = {
10331033
{SQL("ALTER TABLE peers ADD last_known_address BLOB DEFAULT NULL;"), NULL},
10341034
{SQL("ALTER TABLE channels ADD close_attempt_height INTEGER DEFAULT 0;"), NULL},
10351035
{NULL, migrate_convert_old_channel_keyidx},
1036+
{SQL("INSERT INTO vars(name, intval)"
1037+
" VALUES('needs_p2wpkh_close_rescan', 1)"), NULL},
10361038
};
10371039

10381040
/**

Diff for: wallet/test/run-db.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,17 @@ static void db_log_(struct logger *log UNUSED, enum log_level level UNUSED, cons
2525
/* Generated stub for bip32_pubkey */
2626
void bip32_pubkey(struct lightningd *ld UNNEEDED, struct pubkey *pubkey UNNEEDED, u32 index UNNEEDED)
2727
{ fprintf(stderr, "bip32_pubkey called!\n"); abort(); }
28+
/* Generated stub for bitcoind_getrawblockbyheight_ */
29+
void bitcoind_getrawblockbyheight_(const tal_t *ctx UNNEEDED,
30+
struct bitcoind *bitcoind UNNEEDED,
31+
u32 height UNNEEDED,
32+
void (*cb)(struct bitcoind *bitcoind_ UNNEEDED,
33+
u32 height_ UNNEEDED,
34+
struct bitcoin_blkid *blkid UNNEEDED,
35+
struct bitcoin_block *blk UNNEEDED,
36+
void *arg) UNNEEDED,
37+
void *arg UNNEEDED)
38+
{ fprintf(stderr, "bitcoind_getrawblockbyheight_ called!\n"); abort(); }
2839
/* Generated stub for channel_gossip_get_remote_update */
2940
const struct peer_update *channel_gossip_get_remote_update(const struct channel *channel UNNEEDED)
3041
{ fprintf(stderr, "channel_gossip_get_remote_update called!\n"); abort(); }
@@ -296,9 +307,6 @@ struct htlc_in *remove_htlc_in_by_dbid(struct htlc_in_map *remaining_htlcs_in UN
296307
/* Generated stub for rune_unique_id */
297308
u64 rune_unique_id(const struct rune *rune UNNEEDED)
298309
{ fprintf(stderr, "rune_unique_id called!\n"); abort(); }
299-
/* Generated stub for scriptpubkey_hash */
300-
size_t scriptpubkey_hash(const u8 *out UNNEEDED)
301-
{ fprintf(stderr, "scriptpubkey_hash called!\n"); abort(); }
302310
/* Generated stub for sendpay_index_created */
303311
u64 sendpay_index_created(struct lightningd *ld UNNEEDED,
304312
const struct sha256 *payment_hash UNNEEDED,

Diff for: wallet/test/run-wallet.c

+11-3
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,17 @@ void add_node_announcement_sig(u8 *nannounce UNNEEDED,
4949
/* Generated stub for bigsize_put */
5050
size_t bigsize_put(u8 buf[BIGSIZE_MAX_LEN] UNNEEDED, bigsize_t v UNNEEDED)
5151
{ fprintf(stderr, "bigsize_put called!\n"); abort(); }
52+
/* Generated stub for bitcoind_getrawblockbyheight_ */
53+
void bitcoind_getrawblockbyheight_(const tal_t *ctx UNNEEDED,
54+
struct bitcoind *bitcoind UNNEEDED,
55+
u32 height UNNEEDED,
56+
void (*cb)(struct bitcoind *bitcoind_ UNNEEDED,
57+
u32 height_ UNNEEDED,
58+
struct bitcoin_blkid *blkid UNNEEDED,
59+
struct bitcoin_block *blk UNNEEDED,
60+
void *arg) UNNEEDED,
61+
void *arg UNNEEDED)
62+
{ fprintf(stderr, "bitcoind_getrawblockbyheight_ called!\n"); abort(); }
5263
/* Generated stub for bitcoind_getutxout_ */
5364
void bitcoind_getutxout_(const tal_t *ctx UNNEEDED,
5465
struct bitcoind *bitcoind UNNEEDED,
@@ -967,9 +978,6 @@ void resolve_close_command(struct lightningd *ld UNNEEDED, struct channel *chann
967978
/* Generated stub for rune_unique_id */
968979
u64 rune_unique_id(const struct rune *rune UNNEEDED)
969980
{ fprintf(stderr, "rune_unique_id called!\n"); abort(); }
970-
/* Generated stub for scriptpubkey_hash */
971-
size_t scriptpubkey_hash(const u8 *out UNNEEDED)
972-
{ fprintf(stderr, "scriptpubkey_hash called!\n"); abort(); }
973981
/* Generated stub for serialize_onionpacket */
974982
u8 *serialize_onionpacket(
975983
const tal_t *ctx UNNEEDED,

Diff for: wallet/wallet.c

+172-2
Original file line numberDiff line numberDiff line change
@@ -2917,7 +2917,8 @@ static void got_utxo(struct wallet *w,
29172917
const struct wally_tx *wtx,
29182918
size_t outnum,
29192919
bool is_coinbase,
2920-
const u32 *blockheight)
2920+
const u32 *blockheight,
2921+
struct bitcoin_outpoint *outpoint)
29212922
{
29222923
struct utxo *utxo = tal(tmpctx, struct utxo);
29232924
const struct wally_tx_output *txout = &wtx->outputs[outnum];
@@ -2972,6 +2973,8 @@ static void got_utxo(struct wallet *w,
29722973
outpointfilter_add(w->owned_outpoints, &utxo->outpoint);
29732974

29742975
wallet_annotate_txout(w, &utxo->outpoint, TX_WALLET_DEPOSIT, 0);
2976+
if (outpoint)
2977+
*outpoint = utxo->outpoint;
29752978
}
29762979

29772980
int wallet_extract_owned_outputs(struct wallet *w, const struct wally_tx *wtx,
@@ -2991,7 +2994,7 @@ int wallet_extract_owned_outputs(struct wallet *w, const struct wally_tx *wtx,
29912994
if (!wallet_can_spend(w, txout->script, txout->script_len, &keyindex))
29922995
continue;
29932996

2994-
got_utxo(w, keyindex, wtx, i, is_coinbase, blockheight);
2997+
got_utxo(w, keyindex, wtx, i, is_coinbase, blockheight, NULL);
29952998
num_utxos++;
29962999
}
29973000
return num_utxos;
@@ -6512,3 +6515,170 @@ struct issued_address_type *wallet_list_addresses(const tal_t *ctx, struct walle
65126515
tal_free(stmt);
65136516
return addresseslist;
65146517
}
6518+
6519+
struct missing {
6520+
size_t num_found;
6521+
struct missing_addr *addrs;
6522+
};
6523+
6524+
struct missing_addr {
6525+
u64 keyidx;
6526+
const u8 *scriptpubkey;
6527+
};
6528+
6529+
static void mutual_close_p2pkh_catch(struct bitcoind *bitcoind,
6530+
u32 height,
6531+
struct bitcoin_blkid *blkid,
6532+
struct bitcoin_block *blk,
6533+
struct missing *missing)
6534+
{
6535+
struct wallet *w = bitcoind->ld->wallet;
6536+
6537+
/* Are we finished? */
6538+
if (!blkid) {
6539+
log_broken(bitcoind->ld->log,
6540+
"Rescan finished! %zu outputs recovered. Let's never do that again.",
6541+
missing->num_found);
6542+
db_set_intvar(w->db, "needs_p2wpkh_close_rescan", 0);
6543+
/* Call is allocated off of this, so we can't free just yet */
6544+
tal_steal(tmpctx, missing);
6545+
return;
6546+
}
6547+
6548+
log_debug(bitcoind->ld->log, "Mutual close p2wpkh recovery block %u", height);
6549+
for (size_t i = 0; i < tal_count(blk->tx); i++) {
6550+
const struct wally_tx *wtx = blk->tx[i]->wtx;
6551+
for (size_t outnum = 0; outnum < wtx->num_outputs; outnum++) {
6552+
const struct wally_tx_output *txout = &wtx->outputs[outnum];
6553+
for (size_t n = 0; n < tal_count(missing->addrs); n++) {
6554+
struct bitcoin_outpoint outp;
6555+
log_debug(bitcoind->ld->log, "%zu out %zu: %s (seeking %s)",
6556+
i, outnum,
6557+
tal_hexstr(tmpctx, txout->script, txout->script_len),
6558+
tal_hex(tmpctx, missing->addrs[n].scriptpubkey));
6559+
if (!memeq(txout->script, txout->script_len,
6560+
missing->addrs[n].scriptpubkey,
6561+
tal_bytelen(missing->addrs[n].scriptpubkey)))
6562+
continue;
6563+
got_utxo(w, missing->addrs[n].keyidx,
6564+
wtx, outnum, i == 0, &height, &outp);
6565+
log_broken(bitcoind->ld->log, "Rescan found %s!",
6566+
fmt_bitcoin_outpoint(tmpctx, &outp));
6567+
missing->num_found++;
6568+
}
6569+
}
6570+
}
6571+
6572+
/* Next block! */
6573+
bitcoind_getrawblockbyheight(missing, bitcoind, height + 1,
6574+
mutual_close_p2pkh_catch, missing);
6575+
}
6576+
6577+
void wallet_begin_old_close_rescan(struct lightningd *ld)
6578+
{
6579+
struct db_stmt *stmt;
6580+
u32 earliest_block = UINT32_MAX;
6581+
struct missing *missing;
6582+
int v = db_get_intvar(ld->wallet->db, "needs_p2wpkh_close_rescan", -1);
6583+
if (v == 0)
6584+
return;
6585+
assert(v == 1);
6586+
6587+
/* Channels where we might have already seen a mutual close,
6588+
* which said their key was only taproot, but we didn't see an
6589+
* output, may actually have closed to the p2wpkh address.
6590+
* Some debugging help with ChatGPT here!
6591+
*/
6592+
stmt = db_prepare_v2(ld->wallet->db,
6593+
SQL("SELECT "
6594+
" full_channel_id"
6595+
", state"
6596+
", scid"
6597+
", shutdown_keyidx_local"
6598+
" FROM channels"
6599+
" JOIN addresses"
6600+
" ON channels.shutdown_keyidx_local = addresses.keyidx"
6601+
" WHERE addresses.addrtype = ?"
6602+
" AND NOT EXISTS ("
6603+
" SELECT 1"
6604+
" FROM outputs"
6605+
" WHERE outputs.keyindex = addresses.keyidx"
6606+
");"));
6607+
db_bind_int(stmt, wallet_addrtype_in_db(ADDR_P2TR));
6608+
db_query_prepared(stmt);
6609+
6610+
missing = tal(tmpctx, struct missing);
6611+
missing->num_found = 0;
6612+
missing->addrs = tal_arr(missing, struct missing_addr, 0);
6613+
while (db_step(stmt)) {
6614+
enum channel_state state;
6615+
struct short_channel_id scid;
6616+
struct channel_id cid;
6617+
struct missing_addr maddr;
6618+
struct ext_key ext;
6619+
6620+
state = channel_state_in_db(db_col_int(stmt, "state"));
6621+
switch (state) {
6622+
case DUALOPEND_OPEN_INIT:
6623+
case CHANNELD_AWAITING_LOCKIN:
6624+
case CHANNELD_NORMAL:
6625+
case CHANNELD_SHUTTING_DOWN:
6626+
case CLOSINGD_SIGEXCHANGE:
6627+
case DUALOPEND_OPEN_COMMITTED:
6628+
case DUALOPEND_AWAITING_LOCKIN:
6629+
case CHANNELD_AWAITING_SPLICE:
6630+
case DUALOPEND_OPEN_COMMIT_READY:
6631+
db_col_ignore(stmt, "full_channel_id");
6632+
db_col_ignore(stmt, "scid");
6633+
db_col_ignore(stmt, "shutdown_keyidx_local");
6634+
continue;
6635+
/* States where we may have already seen close */
6636+
case CLOSINGD_COMPLETE:
6637+
case AWAITING_UNILATERAL:
6638+
case FUNDING_SPEND_SEEN:
6639+
case ONCHAIN:
6640+
case CLOSED:
6641+
db_col_channel_id(stmt, "full_channel_id", &cid);
6642+
maddr.keyidx = db_col_u64(stmt, "shutdown_keyidx_local");
6643+
6644+
/* This can happen with zeroconf, but it's unusual. In that case
6645+
* we haven't even seen the open, let alone the close.*/
6646+
if (db_col_is_null(stmt, "scid"))
6647+
continue;
6648+
6649+
/* Don't search for close before open */
6650+
scid = db_col_short_channel_id(stmt, "scid");
6651+
if (short_channel_id_blocknum(scid) < earliest_block)
6652+
earliest_block = short_channel_id_blocknum(scid);
6653+
6654+
if (bip32_key_from_parent(ld->bip32_base, maddr.keyidx,
6655+
BIP32_FLAG_KEY_PUBLIC | BIP32_FLAG_SKIP_HASH,
6656+
&ext) != WALLY_OK) {
6657+
abort();
6658+
}
6659+
maddr.scriptpubkey = scriptpubkey_p2wpkh_derkey(missing, ext.pub_key);
6660+
tal_arr_expand(&missing->addrs, maddr);
6661+
}
6662+
}
6663+
tal_free(stmt);
6664+
6665+
/* No results? We didn't have a problem, never test again. */
6666+
if (tal_count(missing->addrs) == 0) {
6667+
db_set_intvar(ld->wallet->db, "needs_p2wpkh_close_rescan", 0);
6668+
return;
6669+
}
6670+
6671+
/* We only released 24.11 in December, so don't go back before
6672+
* block 870000 which was mid-November */
6673+
if (streq(chainparams->network_name, "bitcoin") && earliest_block < 870000)
6674+
earliest_block = 870000;
6675+
6676+
log_broken(ld->log,
6677+
"Potentially missing %zu outputs from previous closes: scanning from block %u",
6678+
tal_count(missing->addrs), earliest_block);
6679+
6680+
/* This is not a leak, though it may take a while! */
6681+
tal_steal(ld, notleak(missing));
6682+
bitcoind_getrawblockbyheight(missing, ld->topology->bitcoind, earliest_block,
6683+
mutual_close_p2pkh_catch, missing);
6684+
}

Diff for: wallet/wallet.h

+7
Original file line numberDiff line numberDiff line change
@@ -1825,6 +1825,13 @@ struct issued_address_type *wallet_list_addresses(const tal_t *ctx, struct walle
18251825
u64 liststart, const u32 *listlimit);
18261826

18271827

1828+
/**
1829+
* wallet_begin_old_close_rescan: rescan for missing mutual close p2wpkh outputs.
1830+
*
1831+
* Once complete, we set a db var so we never do this again.
1832+
*/
1833+
void wallet_begin_old_close_rescan(struct lightningd *ld);
1834+
18281835
/**
18291836
* wallet_memleak_scan - Check for memleaks in wallet.
18301837
*/

0 commit comments

Comments
 (0)