daemon/watch.c: move list of watched txs/txouts into struct topology.

This weans daemon/watch.c off relying on struct lightningd_state.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-03-02 22:51:49 +10:30
parent d34dade8bb
commit 923526baf3
8 changed files with 151 additions and 119 deletions

View File

@ -16,65 +16,6 @@
#include <ccan/tal/str/str.h>
#include <inttypes.h>
struct block {
int height;
/* Actual header. */
struct bitcoin_block_hdr hdr;
/* Previous block (if any). */
struct block *prev;
/* Next block (if any). */
struct block *next;
/* Key for hash table */
struct sha256_double blkid;
/* 0 if not enough predecessors. */
u32 mediantime;
/* Transactions in this block we care about */
struct sha256_double *txids;
/* And their associated index in the block */
u32 *txnums;
/* Full copy of txs (trimmed to txs list in connect_block) */
struct bitcoin_tx **full_txs;
};
/* Hash blocks by sha */
static const struct sha256_double *keyof_block_map(const struct block *b)
{
return &b->blkid;
}
static size_t hash_sha(const struct sha256_double *key)
{
size_t ret;
memcpy(&ret, key, sizeof(ret));
return ret;
}
static bool block_eq(const struct block *b, const struct sha256_double *key)
{
return structeq(&b->blkid, key);
}
HTABLE_DEFINE_TYPE(struct block, keyof_block_map, hash_sha, block_eq, block_map);
struct topology {
struct block *root;
struct block *tip;
struct block_map block_map;
u64 feerate;
bool startup;
/* Bitcoin transctions we're broadcasting */
struct list_head outgoing_txs;
};
static void start_poll_chaintip(struct lightningd_state *dstate);
static void next_topology_timer(struct lightningd_state *dstate)
@ -168,14 +109,14 @@ static void connect_block(struct lightningd_state *dstate,
out.txid = tx->input[j].txid;
out.index = tx->input[j].index;
txo = txowatch_hash_get(&dstate->txowatches, &out);
txo = txowatch_hash_get(&topo->txowatches, &out);
if (txo)
txowatch_fire(dstate, txo, tx, j);
txowatch_fire(topo, txo, tx, j);
}
/* We did spends first, in case that tells us to watch tx. */
bitcoin_txid(tx, &txid);
if (watching_txid(dstate, &txid) || we_broadcast(dstate, &txid))
if (watching_txid(topo, &txid) || we_broadcast(dstate, &txid))
add_tx_to_block(b, &txid, i);
}
b->full_txs = tal_free(b->full_txs);
@ -340,7 +281,7 @@ void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx,
broadcast_done, otx);
}
static void free_blocks(struct lightningd_state *dstate, struct block *b)
static void free_blocks(struct topology *topo, struct block *b)
{
struct block *next;
@ -349,7 +290,7 @@ static void free_blocks(struct lightningd_state *dstate, struct block *b)
/* Notify that txs are kicked out. */
for (i = 0; i < n; i++)
txwatch_fire(dstate, &b->txids[i], 0);
txwatch_fire(topo, &b->txids[i], 0);
next = b->next;
tal_free(b);
@ -371,7 +312,7 @@ static void topology_changed(struct lightningd_state *dstate,
{
/* Eliminate any old chain. */
if (prev->next)
free_blocks(dstate, prev->next);
free_blocks(dstate->topology, prev->next);
prev->next = b;
do {
@ -381,7 +322,7 @@ static void topology_changed(struct lightningd_state *dstate,
} while (b);
/* Tell watch code to re-evaluate all txs. */
watch_topology_changed(dstate);
watch_topology_changed(dstate->topology);
/* Maybe need to rebroadcast. */
rebroadcast_txs(dstate, NULL);
@ -618,19 +559,27 @@ static void destroy_outgoing_txs(struct topology *topo)
tal_free(otx);
}
void setup_topology(struct lightningd_state *dstate)
struct topology *new_topology(const tal_t *ctx)
{
dstate->topology = tal(dstate, struct topology);
block_map_init(&dstate->topology->block_map);
list_head_init(&dstate->topology->outgoing_txs);
struct topology *topo = tal(ctx, struct topology);
dstate->topology->startup = true;
dstate->topology->feerate = 0;
bitcoind_getblockcount(dstate->bitcoind, get_init_blockhash, NULL);
block_map_init(&topo->block_map);
list_head_init(&topo->outgoing_txs);
txwatch_hash_init(&topo->txwatches);
txowatch_hash_init(&topo->txowatches);
tal_add_destructor(dstate->topology, destroy_outgoing_txs);
return topo;
}
void setup_topology(struct topology *topo, struct bitcoind *bitcoind)
{
topo->startup = true;
topo->feerate = 0;
bitcoind_getblockcount(bitcoind, get_init_blockhash, NULL);
tal_add_destructor(topo, destroy_outgoing_txs);
/* Once it gets topology, it calls io_break() and we return. */
io_loop(NULL, NULL);
assert(!dstate->topology->startup);
assert(!topo->startup);
}

View File

@ -1,12 +1,16 @@
#ifndef LIGHTNING_DAEMON_CHAINTOPOLOGY_H
#define LIGHTNING_DAEMON_CHAINTOPOLOGY_H
#include "config.h"
#include <bitcoin/block.h>
#include <bitcoin/shadouble.h>
#include <ccan/list/list.h>
#include <ccan/short_types/short_types.h>
#include <ccan/structeq/structeq.h>
#include <daemon/watch.h>
#include <stddef.h>
struct bitcoin_tx;
struct bitcoind;
struct lightningd_state;
struct peer;
struct sha256_double;
@ -21,6 +25,69 @@ struct outgoing_tx {
void (*failed)(struct peer *peer, int exitstatus, const char *err);
};
struct block {
int height;
/* Actual header. */
struct bitcoin_block_hdr hdr;
/* Previous block (if any). */
struct block *prev;
/* Next block (if any). */
struct block *next;
/* Key for hash table */
struct sha256_double blkid;
/* 0 if not enough predecessors. */
u32 mediantime;
/* Transactions in this block we care about */
struct sha256_double *txids;
/* And their associated index in the block */
u32 *txnums;
/* Full copy of txs (trimmed to txs list in connect_block) */
struct bitcoin_tx **full_txs;
};
/* Hash blocks by sha */
static inline const struct sha256_double *keyof_block_map(const struct block *b)
{
return &b->blkid;
}
static inline size_t hash_sha(const struct sha256_double *key)
{
size_t ret;
memcpy(&ret, key, sizeof(ret));
return ret;
}
static inline bool block_eq(const struct block *b, const struct sha256_double *key)
{
return structeq(&b->blkid, key);
}
HTABLE_DEFINE_TYPE(struct block, keyof_block_map, hash_sha, block_eq, block_map);
struct topology {
struct block *root;
struct block *tip;
struct block_map block_map;
u64 feerate;
bool startup;
/* Bitcoin transctions we're broadcasting */
struct list_head outgoing_txs;
/* Transactions/txos we are watching. */
struct txwatch_hash txwatches;
struct txowatch_hash txowatches;
};
/* Information relevant to locating a TX in a blockchain. */
struct txlocator {
@ -56,7 +123,8 @@ void broadcast_tx(struct peer *peer, const struct bitcoin_tx *tx,
int exitstatus,
const char *err));
void setup_topology(struct lightningd_state *dstate);
struct topology *new_topology(const tal_t *ctx);
void setup_topology(struct topology *topology, struct bitcoind *bitcoind);
struct txlocator *locate_tx(const void *ctx, struct lightningd_state *dstate, const struct sha256_double *txid);

View File

@ -41,8 +41,6 @@ static struct lightningd_state *lightningd_state(void)
dstate->portnum = 0;
dstate->testnet = true;
timers_init(&dstate->timers, time_mono());
txwatch_hash_init(&dstate->txwatches);
txowatch_hash_init(&dstate->txowatches);
list_head_init(&dstate->wallet);
list_head_init(&dstate->addresses);
dstate->dev_never_routefail = false;
@ -69,6 +67,7 @@ int main(int argc, char *argv[])
| SECP256K1_CONTEXT_SIGN);
dstate->bitcoind = new_bitcoind(dstate, dstate->base_log);
dstate->topology = new_topology(dstate);
/* Handle options and config; move to .lightningd */
register_opts(dstate);
@ -88,7 +87,7 @@ int main(int argc, char *argv[])
db_init(dstate);
/* Initialize block topology. */
setup_topology(dstate);
setup_topology(dstate->topology, dstate->bitcoind);
/* Create RPC socket (if any) */
setup_jsonrpc(dstate, dstate->rpc_filename);

View File

@ -110,10 +110,6 @@ struct lightningd_state {
/* This is us. */
struct pubkey id;
/* Transactions/txos we are watching. */
struct txwatch_hash txwatches;
struct txowatch_hash txowatches;
/* Our tame bitcoind. */
struct bitcoind *bitcoind;

View File

@ -3659,6 +3659,7 @@ static enum watch_result our_htlc_depth(struct peer *peer,
if (!peer->onchain.resolved[out_num]) {
peer->onchain.resolved[out_num] = htlc_timeout_tx(peer, out_num);
watch_tx(peer->onchain.resolved[out_num],
peer->dstate->topology,
peer,
peer->onchain.resolved[out_num],
our_htlc_timeout_depth, h);
@ -3832,10 +3833,13 @@ static void resolve_our_htlc(struct peer *peer,
* (the node pays back to itself) or redemption transaction (the other
* node provides the redemption preimage).
*/
watch_txo(peer->onchain.tx, peer, &peer->onchain.txid, out_num,
watch_txo(peer->onchain.tx,
peer->dstate->topology,
peer, &peer->onchain.txid, out_num,
our_htlc_spent, peer->onchain.htlcs[out_num]);
watch_txid(peer->onchain.tx, peer,
&peer->onchain.txid, cb, int2ptr(out_num));
watch_txid(peer->onchain.tx,
peer->dstate->topology,
peer, &peer->onchain.txid, cb, int2ptr(out_num));
}
static void resolve_their_htlc(struct peer *peer, unsigned int out_num)
@ -3855,7 +3859,9 @@ static void resolve_their_htlc(struct peer *peer, unsigned int out_num)
* Otherwise, if the output HTLC has expired, it is considered
* *irrevocably resolved*.
*/
watch_tx(peer->onchain.tx, peer, peer->onchain.tx,
watch_tx(peer->onchain.tx,
peer->dstate->topology,
peer, peer->onchain.tx,
their_htlc_depth, int2ptr(out_num));
}
}
@ -3867,12 +3873,13 @@ static void resolve_their_htlc(struct peer *peer, unsigned int out_num)
static void resolve_our_unilateral(struct peer *peer)
{
unsigned int i;
struct topology *topo = peer->dstate->topology;
const struct bitcoin_tx *tx = peer->onchain.tx;
/* This only works because we always watch for a long time before
* freeing peer, by which time this has resolved. We could create
* resolved[] entries for these uncommitted HTLCs, too. */
watch_tx(tx, peer, tx, our_unilateral_depth, NULL);
watch_tx(tx, topo, peer, tx, our_unilateral_depth, NULL);
for (i = 0; i < tal_count(tx->output); i++) {
/* FIXME-OLD #onchain:
@ -3884,7 +3891,8 @@ static void resolve_our_unilateral(struct peer *peer)
* spending the output.
*/
if (i == peer->onchain.to_us_idx)
watch_tx(tx, peer, tx, our_main_output_depth, NULL);
watch_tx(tx, topo,
peer, tx, our_main_output_depth, NULL);
/* FIXME-OLD #onchain:
*
@ -4278,7 +4286,8 @@ static enum watch_result anchor_spent(struct peer *peer,
assert(!state_can_io(peer->state));
assert(peer->onchain.resolved != NULL);
watch_tx(tx, peer, tx, check_for_resolution, NULL);
watch_tx(tx, peer->dstate->topology,
peer, tx, check_for_resolution, NULL);
return KEEP_WATCHING;
@ -4299,13 +4308,16 @@ unknown_spend:
void peer_watch_anchor(struct peer *peer, int depth)
{
struct topology *topo = peer->dstate->topology;
log_debug_struct(peer->log, "watching for anchor %s",
struct sha256_double, &peer->anchor.txid);
log_add(peer->log, " to hit depth %i", depth);
peer->anchor.ok_depth = depth;
watch_txid(peer, peer, &peer->anchor.txid, anchor_depthchange, NULL);
watch_txo(peer, peer, &peer->anchor.txid, 0, anchor_spent, NULL);
watch_txid(peer, topo, peer,
&peer->anchor.txid, anchor_depthchange, NULL);
watch_txo(peer, topo, peer, &peer->anchor.txid, 0, anchor_spent, NULL);
}
struct bitcoin_tx *peer_create_close_tx(const tal_t *ctx,

View File

@ -62,7 +62,7 @@ bool txowatch_eq(const struct txowatch *w, const struct txwatch_output *out)
static void destroy_txowatch(struct txowatch *w)
{
txowatch_hash_del(&w->peer->dstate->txowatches, w);
txowatch_hash_del(&w->topo->txowatches, w);
}
const struct sha256_double *txwatch_keyof(const struct txwatch *w)
@ -82,10 +82,11 @@ bool txwatch_eq(const struct txwatch *w, const struct sha256_double *txid)
static void destroy_txwatch(struct txwatch *w)
{
txwatch_hash_del(&w->dstate->txwatches, w);
txwatch_hash_del(&w->topo->txwatches, w);
}
struct txwatch *watch_txid_(const tal_t *ctx,
struct topology *topo,
struct peer *peer,
const struct sha256_double *txid,
enum watch_result (*cb)(struct peer *peer,
@ -97,26 +98,27 @@ struct txwatch *watch_txid_(const tal_t *ctx,
struct txwatch *w;
w = tal(ctx, struct txwatch);
w->topo = topo;
w->depth = 0;
w->txid = *txid;
w->dstate = peer->dstate;
w->peer = peer;
w->cb = cb;
w->cbdata = cb_arg;
txwatch_hash_add(&w->dstate->txwatches, w);
txwatch_hash_add(&w->topo->txwatches, w);
tal_add_destructor(w, destroy_txwatch);
return w;
}
bool watching_txid(struct lightningd_state *dstate,
bool watching_txid(const struct topology *topo,
const struct sha256_double *txid)
{
return txwatch_hash_get(&dstate->txwatches, txid) != NULL;
return txwatch_hash_get(&topo->txwatches, txid) != NULL;
}
struct txwatch *watch_tx_(const tal_t *ctx,
struct topology *topo,
struct peer *peer,
const struct bitcoin_tx *tx,
enum watch_result (*cb)(struct peer *peer,
@ -128,10 +130,11 @@ struct txwatch *watch_tx_(const tal_t *ctx,
struct sha256_double txid;
bitcoin_txid(tx, &txid);
return watch_txid(ctx, peer, &txid, cb, cb_arg);
return watch_txid(ctx, topo, peer, &txid, cb, cb_arg);
}
struct txowatch *watch_txo_(const tal_t *ctx,
struct topology *topo,
struct peer *peer,
const struct sha256_double *txid,
unsigned int output,
@ -143,23 +146,24 @@ struct txowatch *watch_txo_(const tal_t *ctx,
{
struct txowatch *w = tal(ctx, struct txowatch);
w->topo = topo;
w->out.txid = *txid;
w->out.index = output;
w->peer = peer;
w->cb = cb;
w->cbdata = cbdata;
txowatch_hash_add(&w->peer->dstate->txowatches, w);
txowatch_hash_add(&w->topo->txowatches, w);
tal_add_destructor(w, destroy_txowatch);
return w;
}
void txwatch_fire(struct lightningd_state *dstate,
void txwatch_fire(struct topology *topo,
const struct sha256_double *txid,
unsigned int depth)
{
struct txwatch *txw = txwatch_hash_get(&dstate->txwatches, txid);
struct txwatch *txw = txwatch_hash_get(&topo->txwatches, txid);
if (txw && depth != txw->depth) {
enum watch_result r;
@ -182,7 +186,7 @@ void txwatch_fire(struct lightningd_state *dstate,
}
}
void txowatch_fire(struct lightningd_state *dstate,
void txowatch_fire(struct topology *topo,
const struct txowatch *txow,
const struct bitcoin_tx *tx,
size_t input_num)
@ -212,18 +216,19 @@ void txowatch_fire(struct lightningd_state *dstate,
fatal("txowatch callback %p returned %i\n", txow->cb, r);
}
void watch_topology_changed(struct lightningd_state *dstate)
void watch_topology_changed(struct topology *topo)
{
struct txwatch_hash_iter i;
struct txwatch *w;
bool needs_rerun;
struct lightningd_state *dstate = tal_parent(topo);
again:
/* Iterating a htable during deletes is safe, but might skip entries. */
needs_rerun = false;
for (w = txwatch_hash_first(&dstate->txwatches, &i);
for (w = txwatch_hash_first(&topo->txwatches, &i);
w;
w = txwatch_hash_next(&dstate->txwatches, &i)) {
w = txwatch_hash_next(&topo->txwatches, &i)) {
size_t depth;
depth = get_tx_depth(dstate, &w->txid);

View File

@ -23,6 +23,8 @@ struct txwatch_output {
/* Watching an output */
struct txowatch {
struct topology *topo;
/* Peer who owns us. */
struct peer *peer;
@ -46,7 +48,7 @@ HTABLE_DEFINE_TYPE(struct txowatch, txowatch_keyof, txo_hash, txowatch_eq,
txowatch_hash);
struct txwatch {
struct lightningd_state *dstate;
struct topology *topo;
/* Peer who owns us. */
struct peer *peer;
@ -70,6 +72,7 @@ HTABLE_DEFINE_TYPE(struct txwatch, txwatch_keyof, txid_hash, txwatch_eq,
struct txwatch *watch_txid_(const tal_t *ctx,
struct topology *topo,
struct peer *peer,
const struct sha256_double *txid,
enum watch_result (*cb)(struct peer *peer,
@ -78,8 +81,8 @@ struct txwatch *watch_txid_(const tal_t *ctx,
void *),
void *cbdata);
#define watch_txid(ctx, peer, txid, cb, cbdata) \
watch_txid_((ctx), (peer), (txid), \
#define watch_txid(ctx, topo, peer, txid, cb, cbdata) \
watch_txid_((ctx), (topo), (peer), (txid), \
typesafe_cb_preargs(enum watch_result, void *, \
(cb), (cbdata), \
struct peer *, \
@ -88,6 +91,7 @@ struct txwatch *watch_txid_(const tal_t *ctx,
(cbdata))
struct txwatch *watch_tx_(const tal_t *ctx,
struct topology *topo,
struct peer *peer,
const struct bitcoin_tx *tx,
enum watch_result (*cb)(struct peer *peer,
@ -96,8 +100,8 @@ struct txwatch *watch_tx_(const tal_t *ctx,
void *),
void *cbdata);
#define watch_tx(ctx, peer, tx, cb, cbdata) \
watch_tx_((ctx), (peer), (tx), \
#define watch_tx(ctx, topo, peer, tx, cb, cbdata) \
watch_tx_((ctx), (topo), (peer), (tx), \
typesafe_cb_preargs(enum watch_result, void *, \
(cb), (cbdata), \
struct peer *, \
@ -106,6 +110,7 @@ struct txwatch *watch_tx_(const tal_t *ctx,
(cbdata))
struct txowatch *watch_txo_(const tal_t *ctx,
struct topology *topo,
struct peer *peer,
const struct sha256_double *txid,
unsigned int output,
@ -115,8 +120,8 @@ struct txowatch *watch_txo_(const tal_t *ctx,
void *),
void *cbdata);
#define watch_txo(ctx, peer, txid, outnum, cb, cbdata) \
watch_txo_((ctx), (peer), (txid), (outnum), \
#define watch_txo(ctx, topo, peer, txid, outnum, cb, cbdata) \
watch_txo_((ctx), (topo), (peer), (txid), (outnum), \
typesafe_cb_preargs(enum watch_result, void *, \
(cb), (cbdata), \
struct peer *, \
@ -124,16 +129,16 @@ struct txowatch *watch_txo_(const tal_t *ctx,
size_t), \
(cbdata))
void txwatch_fire(struct lightningd_state *dstate,
void txwatch_fire(struct topology *topo,
const struct sha256_double *txid,
unsigned int depth);
void txowatch_fire(struct lightningd_state *dstate,
void txowatch_fire(struct topology *topo,
const struct txowatch *txow,
const struct bitcoin_tx *tx, size_t input_num);
bool watching_txid(struct lightningd_state *dstate,
bool watching_txid(const struct topology *topo,
const struct sha256_double *txid);
void watch_topology_changed(struct lightningd_state *dstate);
void watch_topology_changed(struct topology *topo);
#endif /* LIGHTNING_DAEMON_WATCH_H */

View File

@ -88,8 +88,6 @@ static struct lightningd *new_lightningd(const tal_t *ctx)
ld->dstate.portnum = DEFAULT_PORT;
ld->dstate.testnet = true;
timers_init(&ld->dstate.timers, time_mono());
txwatch_hash_init(&ld->dstate.txwatches);
txowatch_hash_init(&ld->dstate.txowatches);
list_head_init(&ld->dstate.wallet);
list_head_init(&ld->dstate.addresses);
ld->dstate.dev_never_routefail = false;