Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 15 additions & 3 deletions lightningd/lightningd.c
Original file line number Diff line number Diff line change
Expand Up @@ -1367,17 +1367,29 @@ int main(int argc, char *argv[])
trace_span_end(ld->topology);

/*~ Stand up the watchman: it queues bwatch RPC requests until the
* bwatch plugin reports ready, then replays them. Must come after
* setup_topology so start_block reflects the last-processed height.
* bwatch plugin reports ready, then replays them. Must come before
* init_wallet_scriptpubkey_watches so the watches have somewhere to
* enqueue, and after setup_topology so start_block reflects the
* last-processed height.
*
* bwatch is opt-in for now: the --experimental-bwatch flag is
* registered by the bwatch plugin, so peek at the configvar to gate
* the lightningd side too. Without it, ld->watchman stays NULL and
* the watchman_* entry points are no-ops, leaving chain_topology as
* the only chain watcher. */
if (bwatch_enabled(ld))
if (bwatch_enabled(ld)) {
ld->watchman = watchman_new(ld, ld);

/*~ Reads intvars and the addresses table, so needs a
* transaction (the datastore writes it triggers self-wrap
* when necessary). */
db_begin_transaction(ld->wallet->db);
trace_span_start("init_wallet_scriptpubkey_watches", ld->wallet);
init_wallet_scriptpubkey_watches(ld->wallet);
trace_span_end(ld->wallet);
db_commit_transaction(ld->wallet->db);
}

db_begin_transaction(ld->wallet->db);
trace_span_start("delete_old_htlcs", ld->wallet);
wallet_delete_old_htlcs(ld->wallet);
Expand Down
3 changes: 3 additions & 0 deletions lightningd/test/run-find_my_abspath.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,9 @@ void htlcs_notify_new_block(struct lightningd *ld UNNEEDED)
void htlcs_resubmit(struct lightningd *ld UNNEEDED,
struct htlc_in_map *unconnected_htlcs_in STEALS UNNEEDED)
{ fprintf(stderr, "htlcs_resubmit called!\n"); abort(); }
/* Generated stub for init_wallet_scriptpubkey_watches */
void init_wallet_scriptpubkey_watches(struct wallet *w UNNEEDED)
{ fprintf(stderr, "init_wallet_scriptpubkey_watches called!\n"); abort(); }
/* Generated stub for invoices_start_expiration */
void invoices_start_expiration(struct lightningd *ld UNNEEDED)
{ fprintf(stderr, "invoices_start_expiration called!\n"); abort(); }
Expand Down
74 changes: 66 additions & 8 deletions wallet/wallet.c
Original file line number Diff line number Diff line change
Expand Up @@ -994,6 +994,43 @@ bool wallet_can_spend(struct wallet *w, const u8 *script, size_t script_len,
return true;
}

static void watch_newindex_scripts(struct lightningd *ld,
u64 keyidx,
enum addrtype addrtype)
{
struct pubkey pubkey;
const u8 *scriptpubkey;
bool legacy = (ld->bip86_base == NULL);
u32 start_block = UINT32_MAX;

if (ld->bip86_base)
bip86_pubkey(ld, &pubkey, keyidx);
else
bip32_pubkey(ld, &pubkey, keyidx);

if (addrtype & ADDR_BECH32) {
scriptpubkey = scriptpubkey_p2wpkh(tmpctx, &pubkey);
wallet_add_bwatch_scriptpubkey(ld, keyidx, start_block,
scriptpubkey,
tal_bytelen(scriptpubkey));

/* Pre-24.11 ADDR_ALL can include legacy wrapped form. */
if (addrtype == ADDR_ALL && legacy) {
const u8 *p2sh = scriptpubkey_p2sh(tmpctx, scriptpubkey);
wallet_add_bwatch_scriptpubkey(ld, keyidx, start_block,
p2sh,
tal_bytelen(p2sh));
}
}

if (addrtype & ADDR_P2TR) {
scriptpubkey = scriptpubkey_p2tr(tmpctx, &pubkey);
wallet_add_bwatch_scriptpubkey(ld, keyidx, start_block,
scriptpubkey,
tal_bytelen(scriptpubkey));
}
}

s64 wallet_get_newindex(struct lightningd *ld, enum addrtype addrtype)
{
struct db_stmt *stmt;
Expand Down Expand Up @@ -1022,6 +1059,8 @@ s64 wallet_get_newindex(struct lightningd *ld, enum addrtype addrtype)
db_bind_int(stmt, wallet_addrtype_in_db(addrtype));
db_exec_prepared_v2(take(stmt));

watch_newindex_scripts(ld, newidx, addrtype);

return newidx;
}

Expand Down Expand Up @@ -8010,6 +8049,33 @@ void wallet_add_bwatch_scriptpubkey(struct lightningd *ld,
script, script_len, start_block);
}

/* Register perennial bwatch watches for every scriptpubkey wallet_can_spend()
* recognizes, including keyscan_gap lookahead. UINT32_MAX avoids a per-key
* startup rescan; existing outputs come from migration and catch-up comes from
* bwatch polling. */
void init_wallet_scriptpubkey_watches(struct wallet *w)
{
struct wallet_address_htable_iter it;
u64 bip32_max_index = db_get_intvar(w->db, "bip32_max_index", 0);
u64 bip86_max_index = db_get_intvar(w->db, "bip86_max_index", 0);
u64 max_index = bip32_max_index > bip86_max_index
? bip32_max_index : bip86_max_index;
u32 start_block = UINT32_MAX;

/* Extend the table to cover every key we've derived plus lookahead;
* same rule wallet_can_spend applies. */
while (w->our_addresses_maxindex < max_index + w->keyscan_gap)
our_addresses_add_for_index(w, ++w->our_addresses_maxindex);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ++ prefix skips index=0 if I'm not mistaken, is that intentional? Also the iteration stops one after maxindex.


for (struct wallet_address *waddr
= wallet_address_htable_first(w->our_addresses, &it);
waddr;
waddr = wallet_address_htable_next(w->our_addresses, &it)) {
wallet_add_bwatch_scriptpubkey(w->ld, waddr->index, start_block,
waddr->swl.script, waddr->swl.len);
}
}

/* Insert a wallet-owned UTXO row into our_outputs. If the outpoint was
* previously inserted unconfirmed (blockheight=0) and we now have a real
* blockheight, promote the row so coin selection can treat it as
Expand Down Expand Up @@ -8200,14 +8266,6 @@ static void bwatch_got_utxo(struct wallet *w,
watchman_watch_outpoint(w->ld,
owner_wallet_utxo(tmpctx, &output->outpoint),
&output->outpoint, start_block);

/* Unconfirmed: keep watching the scriptpubkey so bwatch tells us when
* the output confirms. UINT32_MAX = perennial watch: never skip on
* reorg, never rescan. */
if (!blockheight)
wallet_add_bwatch_scriptpubkey(w->ld, keyindex, UINT32_MAX,
output->txout->script,
output->txout->script_len);
}

/* A wallet/spk watch owner suffix is "<keyindex>/<form>", as written by
Expand Down
5 changes: 5 additions & 0 deletions wallet/wallet.h
Original file line number Diff line number Diff line change
Expand Up @@ -2092,4 +2092,9 @@ void wallet_add_bwatch_scriptpubkey(struct lightningd *ld,
const u8 *script,
size_t script_len);

/* Register a bwatch watch for every scriptpubkey wallet_can_spend
* recognizes: every HD key up through {bip32,bip86}_max_index plus the
* keyscan_gap lookahead, in the address forms actually issued. */
void init_wallet_scriptpubkey_watches(struct wallet *w);

#endif /* LIGHTNING_WALLET_WALLET_H */