diff --git a/daemon/chaintopology.c b/daemon/chaintopology.c index 65932c233..e64fac2f3 100644 --- a/daemon/chaintopology.c +++ b/daemon/chaintopology.c @@ -39,6 +39,9 @@ struct block { /* Transactions in this block we care about */ struct list_head txs; + + /* Full copy of txs (trimmed to txs list in connect_blocks) */ + struct bitcoin_tx **full_txs; }; /* Hash blocks by sha */ @@ -77,7 +80,7 @@ static int cmp_times(const u32 *a, const u32 *b, void *unused) return 0; } -/* Mediantime is median of previous 11 blocks. */ +/* Mediantime is median of this and previous 10 blocks. */ static u32 get_mediantime(const struct topology *topo, const struct block *b) { unsigned int i; @@ -93,24 +96,76 @@ static u32 get_mediantime(const struct topology *topo, const struct block *b) return times[ARRAY_SIZE(times) / 2]; } -/* Fills in prev, height, mediantime. */ -static void connect_blocks(struct topology *topo, struct block *b) +static void remove_tx(struct tx_in_block *t) { - size_t n; + list_del_from(&t->block->txs, &t->list); +} + +static void add_tx_to_block(struct block *b, struct txwatch *w) +{ + /* We attach this to watch, so removed when that is */ + struct tx_in_block *t = tal(w, struct tx_in_block); + + t->block = b; + t->w = w; + list_add_tail(&b->txs, &t->list); + tal_add_destructor(t, remove_tx); +} + +/* Fills in prev, height, mediantime. */ +static void connect_blocks(struct lightningd_state *dstate, struct block *b) +{ + const struct topology *topo = dstate->topology; + size_t n, i; /* Hooked in already? */ if (b->height != -1) return; b->prev = block_map_get(&topo->block_map, &b->hdr.prev_hash); - connect_blocks(topo, b->prev); + connect_blocks(dstate, b->prev); b->height = b->prev->height + 1; n = tal_count(b->prev->nexts); tal_resize(&b->prev->nexts, n+1); b->prev->nexts[n] = b; - b->mediantime = get_mediantime(topo, b->prev); + b->mediantime = get_mediantime(topo, b); + + /* Now we see if any of those txs are interesting. */ + for (i = 0; i < tal_count(b->full_txs); i++) { + struct bitcoin_tx *tx = b->full_txs[i]; + struct txwatch *w; + struct sha256_double txid; + size_t j; + + /* Tell them if it spends a txo we care about. */ + for (j = 0; j < tx->input_count; j++) { + struct txwatch_output out; + struct txowatch *txo; + out.txid = tx->input[j].txid; + out.index = tx->input[j].index; + + txo = txowatch_hash_get(&dstate->txowatches, &out); + if (txo) + txowatch_fire(dstate, txo, tx); + } + + /* We do spends first, in case that tells us to watch tx. */ + normalized_txid(tx, &txid); + w = txwatch_hash_get(&dstate->txwatches, &txid); + if (!w) { + bitcoin_txid(tx, &txid); + w = txwatch_hash_get(&dstate->txwatches, &txid); + } + if (w) { + add_tx_to_block(b, w); + /* Fire if it's the first we've seen it: this might + * set up txo watches, which could fire in this block */ + txwatch_fire(dstate, w, 0, &b->blkid); + } + } + b->full_txs = tal_free(b->full_txs); } /* This is expensive, but reorgs are usually short and txs are few. @@ -279,32 +334,16 @@ static void topology_changed(struct lightningd_state *dstate) for (i = 0; i < tal_count(topo->newtips); i++) { topo->tips[i] = block_map_get(&topo->block_map, &topo->newtips[i]); - connect_blocks(topo, topo->tips[i]); + connect_blocks(dstate, topo->tips[i]); } - /* FIXME: Tell watch code to re-evaluate all txs. */ -} - -static void remove_tx(struct tx_in_block *t) -{ - list_del_from(&t->block->txs, &t->list); -} - -static void add_tx_to_block(struct block *b, struct txwatch *w) -{ - /* We attach this to watch, so removed when that is */ - struct tx_in_block *t = tal(w, struct tx_in_block); - - t->block = b; - t->w = w; - list_add_tail(&b->txs, &t->list); - tal_add_destructor(t, remove_tx); + /* Tell watch code to re-evaluate all txs. */ + watch_topology_changed(dstate); } static struct block *add_block(struct lightningd_state *dstate, struct bitcoin_block *blk) { - size_t i; struct topology *topo = dstate->topology; struct block *b = tal(topo, struct block); @@ -324,17 +363,8 @@ static struct block *add_block(struct lightningd_state *dstate, b->hdr = blk->hdr; - /* See if any of those txs are interesting. */ list_head_init(&b->txs); - for (i = 0; i < tal_count(blk->tx); i++) { - struct txwatch *w; - struct sha256_double txid; - - bitcoin_txid(blk->tx[i], &txid); - w = txwatch_hash_get(&dstate->txwatches, &txid); - if (w) - add_tx_to_block(b, w); - } + b->full_txs = tal_steal(b, blk->tx); block_map_add(&topo->block_map, b); return b; diff --git a/daemon/lightningd.c b/daemon/lightningd.c index 1448fb50e..c7d88f583 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -274,9 +274,6 @@ int main(int argc, char *argv[]) /* Set up node ID and private key. */ secrets_init(dstate); - /* Create timer to do watches. */ - setup_watch_timer(dstate); - /* Initialize block topology. */ setup_topology(dstate); diff --git a/daemon/peer.c b/daemon/peer.c index 8880a2ccc..2aea897e6 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -795,7 +795,6 @@ void peer_watch_anchor(struct peer *peer, w->theyspent = theyspent; w->otherspent = otherspent; - peer_watch_setup(peer); watch_txid(w, peer, &peer->anchor.txid, anchor_depthchange, NULL); watch_txo(w, peer, &peer->anchor.txid, 0, anchor_spent, NULL); diff --git a/daemon/test/test.sh b/daemon/test/test.sh index c964ec96a..da7af5059 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -259,9 +259,6 @@ if [ -n "$TIMEOUT_ANCHOR" ]; then lcli1 dev-mocktime $TIME sleep 2 - # Now we need to trigger it again (first time it gets the mediantime). - $CLI generate 1 - # Sometimes it skips poll because it's busy. Do it again. TIME=$(($TIME + 1)) lcli1 dev-mocktime $TIME diff --git a/daemon/watch.c b/daemon/watch.c index 001f7bd75..22d1a93e9 100644 --- a/daemon/watch.c +++ b/daemon/watch.c @@ -29,6 +29,7 @@ #include "bitcoin/script.h" #include "bitcoin/tx.h" #include "bitcoind.h" +#include "chaintopology.h" #include "lightningd.h" #include "log.h" #include "peer.h" @@ -78,22 +79,6 @@ static void destroy_txwatch(struct txwatch *w) txwatch_hash_del(&w->dstate->txwatches, w); } -/* FIXME: This is a hack! */ -void peer_watch_setup(struct peer *peer) -{ - struct sha256 h; - struct ripemd160 redeemhash; - - /* Telling bitcoind to watch the redeemhash address means - * it'll tell is about the anchor itself (spend to that - * address), and any commit txs (spend from that address).*/ - sha256(&h, peer->anchor.redeemscript, - tal_count(peer->anchor.redeemscript)); - ripemd160(&redeemhash, h.u.u8, sizeof(h)); - - bitcoind_watch_addr(peer->dstate, &redeemhash); -} - struct txwatch *watch_txid_(const tal_t *ctx, struct peer *peer, const struct sha256_double *txid, @@ -159,138 +144,71 @@ struct txowatch *watch_txo_(const tal_t *ctx, return w; } -struct tx_info { - struct sha256_double blkhash; - int conf; -}; -static void insert_null_txwatch(struct lightningd_state *dstate, - const struct sha256_double *txid) +void txwatch_fire(struct lightningd_state *dstate, + struct txwatch *txw, + unsigned int depth, + const struct sha256_double *blkhash) { - struct txwatch *w = tal(dstate, struct txwatch); - w->depth = 0; - w->txid = *txid; - w->dstate = dstate; - w->peer = NULL; - w->cb = NULL; - w->cbdata = NULL; - - txwatch_hash_add(&w->dstate->txwatches, w); - tal_add_destructor(w, destroy_txwatch); + if (depth != txw->depth) { + log_debug(txw->peer->log, + "Got depth change %u for %02x%02x%02x...\n", + txw->depth, + txw->txid.sha.u.u8[0], + txw->txid.sha.u.u8[1], + txw->txid.sha.u.u8[2]); + txw->depth = depth; + txw->cb(txw->peer, txw->depth, blkhash, &txw->txid, + txw->cbdata); + } } -static void watched_normalized_txid(struct lightningd_state *dstate, - const struct bitcoin_tx *tx, - struct tx_info *txinfo) +void txowatch_fire(struct lightningd_state *dstate, + const struct txowatch *txow, + const struct bitcoin_tx *tx) { - struct txwatch *txw; struct sha256_double txid; - size_t i; - - normalized_txid(tx, &txid); - txw = txwatch_hash_get(&dstate->txwatches, &txid); - /* Reset to real txid for logging. */ bitcoin_txid(tx, &txid); - - if (txw) { - if (txinfo->conf != txw->depth) { - log_debug(txw->peer->log, - "Got depth change %u for %02x%02x%02x...\n", - txinfo->conf, - txid.sha.u.u8[0], - txid.sha.u.u8[1], - txid.sha.u.u8[2]); - txw->depth = txinfo->conf; - txw->cb(txw->peer, txw->depth, &txinfo->blkhash, &txid, - txw->cbdata); - } - return; - } - - /* Hmm, otherwise it may be new */ - for (i = 0; i < tx->input_count; i++) { - struct txowatch *txo; - struct txwatch_output out; - - out.txid = tx->input[i].txid; - out.index = tx->input[i].index; - txo = txowatch_hash_get(&dstate->txowatches, &out); - - /* Presumably, this sets a watch on it. */ - if (txo) { - log_debug(txo->peer->log, - "New tx spending %02x%02x%02x output %u:" - " %02x%02x%02x...\n", - out.txid.sha.u.u8[0], - out.txid.sha.u.u8[1], - out.txid.sha.u.u8[2], - out.index, - txid.sha.u.u8[0], - txid.sha.u.u8[1], - txid.sha.u.u8[2]); - txo->cb(txo->peer, tx, txo->cbdata); - return; - } - } - - /* OK, not interesting. Put in fake (on original txid). */ - log_debug(dstate->base_log, "Ignoring tx %02x%02x%02x...\n", + log_debug(txow->peer->log, + "Got UTXO spend for %02x%02x%02x:%u: %02x%02x%02x%02x...\n", + txow->out.txid.sha.u.u8[0], + txow->out.txid.sha.u.u8[1], + txow->out.txid.sha.u.u8[2], + txow->out.index, txid.sha.u.u8[0], txid.sha.u.u8[1], - txid.sha.u.u8[2]); - insert_null_txwatch(dstate, &txid); + txid.sha.u.u8[2], + txid.sha.u.u8[3]); + txow->cb(txow->peer, tx, txow->cbdata); } -static void watched_txid(struct lightningd_state *dstate, - const struct sha256_double *txid, - int confirmations, - bool is_coinbase, - const struct sha256_double *blkhash) - +void watch_topology_changed(struct lightningd_state *dstate) { - struct txwatch *txw; - struct tx_info *txinfo; + struct txwatch_hash_iter i; + struct txwatch *w; + bool needs_rerun; - /* Maybe it spent an output we're watching? */ - if (is_coinbase) - return; +again: + /* Iterating a htable during deletes is safe, but might skip entries. */ + needs_rerun = false; + for (w = txwatch_hash_first(&dstate->txwatches, &i); + w; + w = txwatch_hash_next(&dstate->txwatches, &i)) { + struct sha256_double blkid; + size_t depth; - /* Are we watching this txid directly (or already reported)? */ - txw = txwatch_hash_get(&dstate->txwatches, txid); - if (txw) { - if (txw->cb && confirmations != txw->depth) { - txw->depth = confirmations; - txw->cb(txw->peer, txw->depth, blkhash, txid, - txw->cbdata); + /* Don't fire if we haven't seen it at all. */ + if (w->depth == -1) + continue; + + depth = get_tx_depth(dstate, w, &blkid); + if (depth != w->depth) { + w->depth = depth; + w->cb(w->peer, w->depth, &blkid, &w->txid, w->cbdata); + needs_rerun = true; } - return; } - - txinfo = tal(dstate, struct tx_info); - txinfo->conf = confirmations; - if (blkhash) - txinfo->blkhash = *blkhash; - /* FIXME: Since we don't use segwit, we need to normalize txids. */ - bitcoind_txid_lookup(dstate, txid, watched_normalized_txid, txinfo); -} - -static struct timeout watch_timeout; - -static void start_poll_transactions(struct lightningd_state *dstate) -{ - if (!list_empty(&dstate->bitcoin_req)) { - log_unusual(dstate->base_log, - "Delaying start poll: commands in progress"); - } else - bitcoind_poll_transactions(dstate, watched_txid); - refresh_timeout(dstate, &watch_timeout); -} - -void setup_watch_timer(struct lightningd_state *dstate) -{ - init_timeout(&watch_timeout, dstate->config.poll_seconds, - start_poll_transactions, dstate); - /* Run once immediately, in case there are issues. */ - start_poll_transactions(dstate); + if (needs_rerun) + goto again; } diff --git a/daemon/watch.h b/daemon/watch.h index dbd829467..6a636c128 100644 --- a/daemon/watch.h +++ b/daemon/watch.h @@ -119,10 +119,17 @@ struct txowatch *watch_txo_(const tal_t *ctx, const struct bitcoin_tx *), \ (cbdata)) -void peer_watch_setup(struct peer *peer); - /* FIXME: Seg witness removes need for this! */ void normalized_txid(const struct bitcoin_tx *tx, struct sha256_double *txid); -void setup_watch_timer(struct lightningd_state *dstate); +void txwatch_fire(struct lightningd_state *dstate, + struct txwatch *txw, + unsigned int depth, + const struct sha256_double *blkhash); + +void txowatch_fire(struct lightningd_state *dstate, + const struct txowatch *txow, + const struct bitcoin_tx *tx); + +void watch_topology_changed(struct lightningd_state *dstate); #endif /* LIGHTNING_DAEMON_WATCH_H */