Skip to content

Commit a2b0212

Browse files
rustyrussellShahanaFarooqui
authored andcommitted
lightningd: handle duplicate watches on the same thing correctly.
Our hash tables allow duplicate keys, and we use that in a few places. However, the get() function only returns the first, so it's not a good idea with such hash tables. Another patch fixes this at a deeper level (using different hash table types depending on whether this table can have duplicates), but this is the minimal fix for existing code. This may be the cause behind us occasionally missing onchain events: Fixes: #7460 Fixes: #7377 Fixes: #7118 Fixes: #6951 This fixes them in future: fixing them now will require something else. Signed-off-by: Rusty Russell <[email protected]> Changelog-Fixed: lightningd: occasionally we could miss transaction outputs (not telling gossipd, or even onchaind)
1 parent 9afc10b commit a2b0212

File tree

3 files changed

+30
-17
lines changed

3 files changed

+30
-17
lines changed

lightningd/chaintopology.c

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -55,20 +55,22 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b)
5555
/* Now we see if any of those txs are interesting. */
5656
const size_t num_txs = tal_count(b->full_txs);
5757
for (i = 0; i < num_txs; i++) {
58-
const struct bitcoin_tx *tx = b->full_txs[i];
58+
struct bitcoin_tx *tx = b->full_txs[i];
5959
struct bitcoin_txid txid;
6060
size_t j;
6161
bool is_coinbase = i == 0;
6262

6363
/* Tell them if it spends a txo we care about. */
6464
for (j = 0; j < tx->wtx->num_inputs; j++) {
6565
struct bitcoin_outpoint out;
66-
struct txowatch *txo;
66+
struct txowatch_hash_iter it;
67+
6768
bitcoin_tx_input_get_txid(tx, j, &out.txid);
6869
out.n = tx->wtx->inputs[j].index;
6970

70-
txo = txowatch_hash_get(topo->txowatches, &out);
71-
if (txo) {
71+
for (struct txowatch *txo = txowatch_hash_getfirst(topo->txowatches, &out, &it);
72+
txo;
73+
txo = txowatch_hash_getnext(topo->txowatches, &out, &it)) {
7274
wallet_transaction_add(topo->ld->wallet,
7375
tx->wtx, b->height, i);
7476
txowatch_fire(txo, tx, j, b);
@@ -104,7 +106,7 @@ static void filter_block_txs(struct chain_topology *topo, struct block *b)
104106
tx->wtx, b->height, i);
105107
}
106108

107-
txwatch_inform(topo, &txid, tx);
109+
txwatch_inform(topo, &txid, take(tx));
108110
}
109111
b->full_txs = tal_free(b->full_txs);
110112
b->txids = tal_free(b->txids);

lightningd/watch.c

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@
3030
* WE ASSUME NO MALLEABILITY! This requires segregated witness.
3131
*/
3232
#include "config.h"
33+
#include <bitcoin/psbt.h>
3334
#include <lightningd/chaintopology.h>
3435
#include <lightningd/channel.h>
3536
#include <lightningd/lightningd.h>
@@ -235,12 +236,13 @@ void txwatch_fire(struct chain_topology *topo,
235236
const struct bitcoin_txid *txid,
236237
unsigned int depth)
237238
{
238-
struct txwatch *txw;
239+
struct txwatch_hash_iter it;
239240

240-
txw = txwatch_hash_get(topo->txwatches, txid);
241-
242-
if (txw)
241+
for (struct txwatch *txw = txwatch_hash_getfirst(topo->txwatches, txid, &it);
242+
txw;
243+
txw = txwatch_hash_getnext(topo->txwatches, txid, &it)) {
243244
txw_fire(txw, txid, depth);
245+
}
244246
}
245247

246248
void txowatch_fire(const struct txowatch *txow,
@@ -295,12 +297,22 @@ void watch_topology_changed(struct chain_topology *topo)
295297

296298
void txwatch_inform(const struct chain_topology *topo,
297299
const struct bitcoin_txid *txid,
298-
const struct bitcoin_tx *tx_may_steal)
300+
struct bitcoin_tx *tx TAKES)
299301
{
300-
struct txwatch *txw;
301-
302-
txw = txwatch_hash_get(topo->txwatches, txid);
302+
struct txwatch_hash_iter it;
303+
304+
for (struct txwatch *txw = txwatch_hash_getfirst(topo->txwatches, txid, &it);
305+
txw;
306+
txw = txwatch_hash_getnext(topo->txwatches, txid, &it)) {
307+
if (txw->tx)
308+
continue;
309+
/* FIXME: YUCK! These don't have PSBTs attached */
310+
if (!tx->psbt)
311+
tx->psbt = new_psbt(tx, tx->wtx);
312+
txw->tx = clone_bitcoin_tx(txw, tx);
313+
}
303314

304-
if (txw && !txw->tx)
305-
txw->tx = tal_steal(txw, tx_may_steal);
315+
/* If we don't clone above, handle take() now */
316+
if (taken(tx))
317+
tal_free(tx);
306318
}

lightningd/watch.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -89,10 +89,9 @@ void txowatch_fire(const struct txowatch *txow,
8989
bool watching_txid(const struct chain_topology *topo,
9090
const struct bitcoin_txid *txid);
9191

92-
/* FIXME: Implement bitcoin_tx_dup() so we tx arg can be TAKEN */
9392
void txwatch_inform(const struct chain_topology *topo,
9493
const struct bitcoin_txid *txid,
95-
const struct bitcoin_tx *tx_may_steal);
94+
struct bitcoin_tx *tx TAKES);
9695

9796
void watch_topology_changed(struct chain_topology *topo);
9897
#endif /* LIGHTNING_LIGHTNINGD_WATCH_H */

0 commit comments

Comments
 (0)