daemon/chaintopology: hand full txs to watch_tx()

This is required for onchaind: we want to watch all descendents by default,
as to do otherwise would be racy, which means we need to traverse the outputs
when a tx appears.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-08-18 14:13:53 +09:30
parent 04db39558d
commit 8ffdeea522
7 changed files with 129 additions and 98 deletions

View File

@ -54,13 +54,14 @@ static u32 get_mediantime(const struct chain_topology *topo, const struct block
}
/* FIXME: Remove tx from block when peer done. */
static void add_tx_to_block(struct block *b, const struct sha256_double *txid, const u32 txnum)
static void add_tx_to_block(struct block *b,
const struct bitcoin_tx *tx, const u32 txnum)
{
size_t n = tal_count(b->txids);
size_t n = tal_count(b->txs);
tal_resize(&b->txids, n+1);
tal_resize(&b->txs, n+1);
tal_resize(&b->txnums, n+1);
b->txids[n] = *txid;
b->txs[n] = tal_steal(b->txs, tx);
b->txnums[n] = txnum;
}
@ -96,7 +97,7 @@ static void connect_block(struct chain_topology *topo,
/* 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];
const struct bitcoin_tx *tx = b->full_txs[i];
struct sha256_double txid;
size_t j;
@ -115,7 +116,7 @@ static void connect_block(struct chain_topology *topo,
/* We did spends first, in case that tells us to watch tx. */
bitcoin_txid(tx, &txid);
if (watching_txid(topo, &txid) || we_broadcast(topo, &txid))
add_tx_to_block(b, &txid, i);
add_tx_to_block(b, tx, i);
}
b->full_txs = tal_free(b->full_txs);
@ -123,37 +124,46 @@ static void connect_block(struct chain_topology *topo,
notify_new_block(topo, b->height);
}
static bool tx_in_block(const struct block *b,
const struct sha256_double *txid)
static const struct bitcoin_tx *tx_in_block(const struct block *b,
const struct sha256_double *txid)
{
size_t i, n = tal_count(b->txids);
size_t i, n = tal_count(b->txs);
for (i = 0; i < n; i++) {
if (structeq(&b->txids[i], txid))
return true;
struct sha256_double this_txid;
bitcoin_txid(b->txs[i], &this_txid);
if (structeq(&this_txid, txid))
return b->txs[i];
}
return false;
return NULL;
}
/* FIXME: Use hash table. */
static struct block *block_for_tx(const struct chain_topology *topo,
const struct sha256_double *txid)
const struct sha256_double *txid,
const struct bitcoin_tx **tx)
{
struct block *b;
const struct bitcoin_tx *dummy_tx;
if (!tx)
tx = &dummy_tx;
for (b = topo->tip; b; b = b->prev) {
if (tx_in_block(b, txid))
*tx = tx_in_block(b, txid);
if (*tx)
return b;
}
return NULL;
}
size_t get_tx_depth(const struct chain_topology *topo,
const struct sha256_double *txid)
const struct sha256_double *txid,
const struct bitcoin_tx **tx)
{
const struct block *b;
b = block_for_tx(topo, txid);
b = block_for_tx(topo, txid, tx);
if (!b)
return 0;
return topo->tip->height - b->height + 1;
@ -215,7 +225,7 @@ static void rebroadcast_txs(struct chain_topology *topo, struct command *cmd)
/* Put any txs we want to broadcast in ->txs. */
txs->txs = tal_arr(txs, const char *, 0);
list_for_each(&topo->outgoing_txs, otx, list) {
if (block_for_tx(topo, &otx->txid))
if (block_for_tx(topo, &otx->txid, NULL))
continue;
tal_resize(&txs->txs, num_txs+1);
@ -293,11 +303,11 @@ static void free_blocks(struct chain_topology *topo, struct block *b)
struct block *next;
while (b) {
size_t i, n = tal_count(b->txids);
size_t i, n = tal_count(b->txs);
/* Notify that txs are kicked out. */
for (i = 0; i < n; i++)
txwatch_fire(topo, &b->txids[i], 0);
txwatch_fire(topo, b->txs[i], 0);
next = b->next;
tal_free(b);
@ -359,7 +369,7 @@ static struct block *new_block(struct chain_topology *topo,
b->hdr = blk->hdr;
b->txids = tal_arr(b, struct sha256_double, 0);
b->txs = tal_arr(b, const struct bitcoin_tx *, 0);
b->txnums = tal_arr(b, u32, 0);
b->full_txs = tal_steal(b, blk->tx);
@ -468,7 +478,7 @@ u32 get_tx_mediantime(const struct chain_topology *topo,
{
struct block *b;
b = block_for_tx(topo, txid);
b = block_for_tx(topo, txid, NULL);
if (b)
return b->mediantime;
@ -502,16 +512,18 @@ u64 get_feerate(const struct chain_topology *topo)
struct txlocator *locate_tx(const void *ctx, const struct chain_topology *topo,
const struct sha256_double *txid)
{
struct block *block = block_for_tx(topo, txid);
struct block *block = block_for_tx(topo, txid, NULL);
if (block == NULL) {
return NULL;
}
struct txlocator *loc = talz(ctx, struct txlocator);
loc->blkheight = block->height;
size_t i, n = tal_count(block->txids);
size_t i, n = tal_count(block->txs);
for (i = 0; i < n; i++) {
if (structeq(&block->txids[i], txid)){
struct sha256_double this_txid;
bitcoin_txid(block->txs[i], &this_txid);
if (structeq(&this_txid, txid)){
loc->index = block->txnums[i];
return loc;
}

View File

@ -49,7 +49,7 @@ struct block {
u32 mediantime;
/* Transactions in this block we care about */
struct sha256_double *txids;
const struct bitcoin_tx **txs;
/* And their associated index in the block */
u32 *txnums;
@ -131,9 +131,10 @@ struct txlocator {
};
/* This is the number of blocks which would have to be mined to invalidate
* the tx. */
* the tx (optional tx is filled in if return is non-zero). */
size_t get_tx_depth(const struct chain_topology *topo,
const struct sha256_double *txid);
const struct sha256_double *txid,
const struct bitcoin_tx **tx);
/* Get the mediantime of the block including this tx (must be one!) */
u32 get_tx_mediantime(const struct chain_topology *topo,

View File

@ -3360,8 +3360,8 @@ static void peer_depth_ok(struct peer *peer)
}
static enum watch_result anchor_depthchange(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
void *unused)
{
log_debug(peer->log, "Anchor at depth %u", depth);
@ -3620,8 +3620,8 @@ static void fail_own_htlc(struct peer *peer, struct htlc *htlc)
* than the HTLC timeout difference.
*/
static enum watch_result our_htlc_timeout_depth(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
struct htlc *htlc)
{
if (depth == 0)
@ -3683,24 +3683,28 @@ static enum watch_result our_htlc_depth(struct peer *peer,
}
static enum watch_result our_htlc_depth_theircommit(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
ptrint_t *out_num)
{
return our_htlc_depth(peer, depth, txid, REMOTE, ptr2int(out_num));
struct sha256_double txid;
bitcoin_txid(tx, &txid);
return our_htlc_depth(peer, depth, &txid, REMOTE, ptr2int(out_num));
}
static enum watch_result our_htlc_depth_ourcommit(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
ptrint_t *out_num)
{
return our_htlc_depth(peer, depth, txid, LOCAL, ptr2int(out_num));
struct sha256_double txid;
bitcoin_txid(tx, &txid);
return our_htlc_depth(peer, depth, &txid, LOCAL, ptr2int(out_num));
}
static enum watch_result their_htlc_depth(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
ptrint_t *out_num)
{
u32 height;
@ -3725,8 +3729,8 @@ static enum watch_result their_htlc_depth(struct peer *peer,
}
static enum watch_result our_main_output_depth(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
void *unused)
{
/* Not past CSV timeout? */
@ -3755,8 +3759,8 @@ static enum watch_result our_main_output_depth(struct peer *peer,
/* Any of our HTLCs we didn't have in our commitment tx, but they did,
* we can't fail until we're sure our commitment tx will win. */
static enum watch_result our_unilateral_depth(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
void *unused)
{
struct htlc_map_iter it;
@ -3837,8 +3841,8 @@ static enum watch_result our_htlc_spent(struct peer *peer,
static void resolve_our_htlc(struct peer *peer,
unsigned int out_num,
enum watch_result (*cb)(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double*,
ptrint_t *out_num))
{
/* FIXME-OLD #onchain:
@ -3998,8 +4002,8 @@ static void resolve_mutual_close(struct peer *peer)
/* Called every time the tx spending the funding tx changes depth. */
static enum watch_result check_for_resolution(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
void *unused)
{
size_t i, n = tal_count(peer->onchain.resolved);
@ -4028,7 +4032,7 @@ static enum watch_result check_for_resolution(struct peer *peer,
struct sha256_double txid;
bitcoin_txid(peer->onchain.resolved[i], &txid);
if (get_tx_depth(peer->dstate->topology, &txid) < forever)
if (get_tx_depth(peer->dstate->topology, &txid, NULL) < forever)
return KEEP_WATCHING;
}

View File

@ -90,8 +90,8 @@ struct txwatch *watch_txid_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
enum watch_result (*cb)(struct peer *peer,
const struct bitcoin_tx *,
unsigned int depth,
const struct sha256_double *,
void *arg),
void *cb_arg)
{
@ -122,8 +122,8 @@ struct txwatch *watch_tx_(const tal_t *ctx,
struct peer *peer,
const struct bitcoin_tx *tx,
enum watch_result (*cb)(struct peer *peer,
const struct bitcoin_tx *,
unsigned int depth,
const struct sha256_double *,
void *arg),
void *cb_arg)
{
@ -159,31 +159,46 @@ struct txowatch *watch_txo_(const tal_t *ctx,
return w;
}
/* Returns true if we fired a callback */
static bool txw_fire(struct chain_topology *topo,
struct txwatch *txw,
const struct bitcoin_tx *tx,
unsigned int depth)
{
enum watch_result r;
if (depth == txw->depth)
return false;
peer_debug(txw->peer,
"Got depth change %u->%u for %02x%02x%02x...\n",
txw->depth, depth,
txw->txid.sha.u.u8[0],
txw->txid.sha.u.u8[1],
txw->txid.sha.u.u8[2]);
txw->depth = depth;
r = txw->cb(txw->peer, tx, txw->depth, txw->cbdata);
switch (r) {
case DELETE_WATCH:
tal_free(txw);
return true;
case KEEP_WATCHING:
return true;
}
fatal("txwatch callback %p returned %i\n", txw->cb, r);
}
void txwatch_fire(struct chain_topology *topo,
const struct sha256_double *txid,
const struct bitcoin_tx *tx,
unsigned int depth)
{
struct txwatch *txw = txwatch_hash_get(&topo->txwatches, txid);
struct sha256_double txid;
struct txwatch *txw;
if (txw && depth != txw->depth) {
enum watch_result r;
peer_debug(txw->peer,
"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;
r = txw->cb(txw->peer, txw->depth, &txw->txid, txw->cbdata);
switch (r) {
case DELETE_WATCH:
tal_free(txw);
return;
case KEEP_WATCHING:
return;
}
fatal("txwatch callback %p returned %i\n", txw->cb, r);
}
bitcoin_txid(tx, &txid);
txw = txwatch_hash_get(&topo->txwatches, &txid);
if (txw)
txw_fire(topo, txw, tx, depth);
}
void txowatch_fire(struct chain_topology *topo,
@ -228,23 +243,12 @@ again:
for (w = txwatch_hash_first(&topo->txwatches, &i);
w;
w = txwatch_hash_next(&topo->txwatches, &i)) {
size_t depth;
u32 depth;
const struct bitcoin_tx *tx;
depth = get_tx_depth(topo, &w->txid);
if (depth != w->depth) {
enum watch_result r;
w->depth = depth;
needs_rerun = true;
r = w->cb(w->peer, w->depth, &w->txid, w->cbdata);
switch (r) {
case DELETE_WATCH:
tal_free(w);
continue;
case KEEP_WATCHING:
continue;
}
fatal("txwatch callback %p returned %i\n", w->cb, r);
}
depth = get_tx_depth(topo, &w->txid, &tx);
if (depth)
needs_rerun |= txw_fire(topo, w, tx, depth);
}
if (needs_rerun)
goto again;

View File

@ -58,9 +58,11 @@ struct txwatch {
unsigned int depth;
/* A new depth (0 if kicked out, otherwise 1 = tip, etc.) */
enum watch_result (*cb)(struct peer *peer, unsigned int depth,
const struct sha256_double *txid,
enum watch_result (*cb)(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
void *cbdata);
void *cbdata;
};
@ -76,8 +78,8 @@ struct txwatch *watch_txid_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
enum watch_result (*cb)(struct peer *peer,
const struct bitcoin_tx *,
unsigned int depth,
const struct sha256_double*,
void *),
void *cbdata);
@ -86,8 +88,8 @@ struct txwatch *watch_txid_(const tal_t *ctx,
typesafe_cb_preargs(enum watch_result, void *, \
(cb), (cbdata), \
struct peer *, \
unsigned int depth, \
const struct sha256_double *), \
const struct bitcoin_tx *, \
unsigned int depth), \
(cbdata))
struct txwatch *watch_tx_(const tal_t *ctx,
@ -95,8 +97,8 @@ struct txwatch *watch_tx_(const tal_t *ctx,
struct peer *peer,
const struct bitcoin_tx *tx,
enum watch_result (*cb)(struct peer *peer,
const struct bitcoin_tx *,
unsigned int depth,
const struct sha256_double *,
void *),
void *cbdata);
@ -105,8 +107,8 @@ struct txwatch *watch_tx_(const tal_t *ctx,
typesafe_cb_preargs(enum watch_result, void *, \
(cb), (cbdata), \
struct peer *, \
unsigned int depth, \
const struct sha256_double *), \
const struct bitcoin_tx *, \
unsigned int depth), \
(cbdata))
struct txowatch *watch_txo_(const tal_t *ctx,
@ -130,7 +132,7 @@ struct txowatch *watch_txo_(const tal_t *ctx,
(cbdata))
void txwatch_fire(struct chain_topology *topo,
const struct sha256_double *txid,
const struct bitcoin_tx *tx,
unsigned int depth);
void txowatch_fire(struct chain_topology *topo,

View File

@ -46,12 +46,6 @@ struct peer *find_peer_by_unique_id(struct lightningd *ld, u64 unique_id)
return NULL;
}
void peer_debug(struct peer *peer, const char *fmt, ...);
void peer_debug(struct peer *peer, const char *fmt, ...)
{
FIXME_IMPLEMENT();
}
void debug_dump_peers(struct lightningd_state *dstate);
void debug_dump_peers(struct lightningd_state *dstate)
{

View File

@ -49,6 +49,17 @@ static void destroy_peer(struct peer *peer)
list_del_from(&peer->ld->peers, &peer->list);
}
/* FIXME: Remove this with legacy daemon! */
void peer_debug(struct peer *peer, const char *fmt, ...);
void peer_debug(struct peer *peer, const char *fmt, ...)
{
va_list ap;
va_start(ap, fmt);
logv(peer->log, LOG_DBG, fmt, ap);
va_end(ap);
}
/* Mutual recursion, sets timer. */
static void peer_reconnect(struct peer *peer);
@ -918,8 +929,8 @@ static void funding_broadcast_failed(struct peer *peer,
}
static enum watch_result funding_announce_cb(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
void *unused)
{
if (depth < ANNOUNCE_MIN_DEPTH) {
@ -938,14 +949,17 @@ static enum watch_result funding_announce_cb(struct peer *peer,
}
static enum watch_result funding_lockin_cb(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
const struct sha256_double *txid,
void *unused)
{
const char *txidstr = type_to_string(peer, struct sha256_double, txid);
struct sha256_double txid;
const char *txidstr;
struct txlocator *loc;
bool peer_ready;
bitcoin_txid(tx, &txid);
txidstr = type_to_string(peer, struct sha256_double, &txid);
log_debug(peer->log, "Funding tx %s depth %u of %u",
txidstr, depth, peer->minimum_depth);
tal_free(txidstr);
@ -953,7 +967,7 @@ static enum watch_result funding_lockin_cb(struct peer *peer,
if (depth < peer->minimum_depth)
return KEEP_WATCHING;
loc = locate_tx(peer, peer->ld->topology, txid);
loc = locate_tx(peer, peer->ld->topology, &txid);
peer->scid = tal(peer, struct short_channel_id);
peer->scid->blocknum = loc->blkheight;
@ -995,7 +1009,7 @@ static enum watch_result funding_lockin_cb(struct peer *peer,
take(towire_channel_funding_announce_depth(peer)));
} else {
/* Worst case, we'll send next block. */
watch_txid(peer, peer->ld->topology, peer, txid,
watch_txid(peer, peer->ld->topology, peer, &txid,
funding_announce_cb, NULL);
}
return DELETE_WATCH;