Skip to content

Commit 1e66414

Browse files
committed
wallet: make sure we re-watch outpoints after blocks are rolled back.
At startup, we load the outpoints to watch, *then* roll back 15 blocks. If there were things in those blocks we wanted to watch, we no longer do! 1. We load the utxoset into memory: everything in the utxoset table which has spendheight null. 2. We roll back 15 blocks to re-read. Deleting a block from the database causes the utxo spentheights referring to it to be set to null. 3. We roll forward, but we didn't update the in-memory utxoset, so we're not watching those utxos which are spent. The main symptom of this is that we spam peers with obsolete gossip (if we get sent a channel announcement for a closed channel, we can think it isn't spent yet). But it could *also* mean we don't notice onchain txs, if we restart at the wrong time! Changelog-Fixed: lightningd: we could miss tx spends which happened in the past blocks when we restarted. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
1 parent 8caffde commit 1e66414

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

tests/test_wallet.py

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2538,7 +2538,6 @@ def test_hsm_wrong_passphrase_crash(node_factory):
25382538
os.close(slave_fd2)
25392539

25402540

2541-
@pytest.mark.xfail(strict=True)
25422541
def test_unspend_during_reorg(node_factory, bitcoind):
25432542
l1, l2 = node_factory.line_graph(2)
25442543
scid = first_scid(l1, l2)

wallet/wallet.c

Lines changed: 21 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -180,32 +180,39 @@ static void our_addresses_init(struct wallet *w)
180180
w->our_addresses_maxindex = w->keyscan_gap;
181181
}
182182

183-
static void outpointfilters_init(struct wallet *w)
183+
/* Idempotent: outpointfilter_add is a noop if it already exists. */
184+
static void refill_outpointfilters(struct wallet *w)
184185
{
185186
struct db_stmt *stmt;
186-
struct utxo **utxos = wallet_get_all_utxos(NULL, w);
187-
struct bitcoin_outpoint outpoint;
188-
189-
w->owned_outpoints = outpointfilter_new(w);
190-
for (size_t i = 0; i < tal_count(utxos); i++)
191-
outpointfilter_add(w->owned_outpoints, &utxos[i]->outpoint);
192187

193-
tal_free(utxos);
194-
195-
w->utxoset_outpoints = outpointfilter_new(w);
196188
stmt = db_prepare_v2(
197189
w->db,
198190
SQL("SELECT txid, outnum FROM utxoset WHERE spendheight is NULL"));
199191
db_query_prepared(stmt);
200192

201193
while (db_step(stmt)) {
194+
struct bitcoin_outpoint outpoint;
202195
db_col_txid(stmt, "txid", &outpoint.txid);
203196
outpoint.n = db_col_int(stmt, "outnum");
204197
outpointfilter_add(w->utxoset_outpoints, &outpoint);
205198
}
206199
tal_free(stmt);
207200
}
208201

202+
static void outpointfilters_init(struct wallet *w)
203+
{
204+
struct utxo **utxos = wallet_get_all_utxos(NULL, w);
205+
206+
w->owned_outpoints = outpointfilter_new(w);
207+
for (size_t i = 0; i < tal_count(utxos); i++)
208+
outpointfilter_add(w->owned_outpoints, &utxos[i]->outpoint);
209+
210+
tal_free(utxos);
211+
212+
w->utxoset_outpoints = outpointfilter_new(w);
213+
refill_outpointfilters(w);
214+
}
215+
209216
struct wallet *wallet_new(struct lightningd *ld, struct timers *timers)
210217
{
211218
struct wallet *wallet = tal(ld, struct wallet);
@@ -4867,6 +4874,9 @@ void wallet_block_remove(struct wallet *w, struct block *b)
48674874
db_query_prepared(stmt);
48684875
assert(!db_step(stmt));
48694876
tal_free(stmt);
4877+
4878+
/* We might need to watch more now-unspent UTXOs */
4879+
refill_outpointfilters(w);
48704880
}
48714881

48724882
void wallet_blocks_rollback(struct wallet *w, u32 height)
@@ -4875,6 +4885,7 @@ void wallet_blocks_rollback(struct wallet *w, u32 height)
48754885
"WHERE height > ?"));
48764886
db_bind_int(stmt, height);
48774887
db_exec_prepared_v2(take(stmt));
4888+
refill_outpointfilters(w);
48784889
}
48794890

48804891
bool wallet_outpoint_spend(const tal_t *ctx, struct wallet *w, const u32 blockheight,

0 commit comments

Comments
 (0)