Browse Source

watch: express everything in terms of watch_tx and watch_txo.

With segregated witness, we can (in advance!) specify the txid or tx
output we want to watch, so convert to that now.  For the moment it's
done by pretending we have normalized txids; that goes away after the
conversion.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
ppa-0.6.1
Rusty Russell 9 years ago
parent
commit
3d9cb81215
  1. 38
      daemon/peer.c
  2. 2
      daemon/test/test.sh
  3. 270
      daemon/watch.c
  4. 105
      daemon/watch.h

38
daemon/peer.c

@ -644,8 +644,10 @@ struct anchor_watch {
static void anchor_depthchange(struct peer *peer, int depth,
const struct sha256_double *blkhash,
struct anchor_watch *w)
const struct sha256_double *txid,
void *unused)
{
struct anchor_watch *w = peer->anchor.watches;
/* Still waiting for it to reach depth? */
if (w->depthok != INPUT_NONE) {
/* Beware sign! */
@ -737,7 +739,10 @@ static bool is_mutual_close(const struct peer *peer,
return matches;
}
static void close_depth_cb(struct peer *peer, int depth)
static void close_depth_cb(struct peer *peer, int depth,
const struct sha256_double *txid,
const struct sha256_double *blkhash,
void *unused)
{
if (depth >= peer->dstate->config.forever_confirms) {
state_event(peer, BITCOIN_CLOSE_DONE, NULL);
@ -748,8 +753,9 @@ static void close_depth_cb(struct peer *peer, int depth)
* invalid transactions! */
static void anchor_spent(struct peer *peer,
const struct bitcoin_tx *tx,
struct anchor_watch *w)
void *unused)
{
struct anchor_watch *w = peer->anchor.watches;
union input idata;
/* FIXME: change type in idata? */
@ -757,7 +763,7 @@ static void anchor_spent(struct peer *peer,
if (is_unrevoked_commit(peer->them.commit, tx))
state_event(peer, w->theyspent, &idata);
else if (is_mutual_close(peer, tx))
add_close_tx_watch(peer, peer, tx, close_depth_cb);
watch_tx(peer, peer, tx, close_depth_cb, NULL);
else
state_event(peer, w->otherspent, &idata);
}
@ -789,10 +795,9 @@ void peer_watch_anchor(struct peer *peer,
w->theyspent = theyspent;
w->otherspent = otherspent;
add_anchor_watch(w, peer, &peer->anchor.txid, peer->anchor.index,
anchor_depthchange,
anchor_spent,
w);
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);
/* For anchor timeout, expect 20 minutes per block, +2 hours.
*
@ -833,6 +838,7 @@ void peer_unwatch_anchor_depth(struct peer *peer,
static void commit_tx_depth(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txid,
ptrint_t *canspend)
{
log_debug(peer->log, "Commit tx reached depth %i", depth);
@ -899,14 +905,15 @@ void peer_watch_delayed(struct peer *peer,
memset(&peer->cur_commit.blockid, 0xFF,
sizeof(peer->cur_commit.blockid));
peer->cur_commit.watch
= add_commit_tx_watch(tx, peer, &txid, commit_tx_depth,
int2ptr(canspend));
= watch_txid(tx, peer, &txid, commit_tx_depth,
int2ptr(canspend));
watch_tx_outputs(peer, tx);
}
static void spend_tx_done(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txid,
ptrint_t *done)
{
log_debug(peer->log, "tx reached depth %i", depth);
@ -930,16 +937,7 @@ void peer_watch_tx(struct peer *peer,
const struct bitcoin_tx *tx,
enum state_input done)
{
struct sha256_double txid;
bitcoin_txid(tx, &txid);
log_debug(peer->log, "Watching tx %02x%02x%02x%02x...",
txid.sha.u.u8[0],
txid.sha.u.u8[1],
txid.sha.u.u8[2],
txid.sha.u.u8[3]);
add_commit_tx_watch(tx, peer, &txid, spend_tx_done, int2ptr(done));
watch_tx(tx, peer, tx, spend_tx_done, int2ptr(done));
}
struct bitcoin_tx *peer_create_close_tx(struct peer *peer, u64 fee)

2
daemon/test/test.sh

@ -408,7 +408,7 @@ $CLI generate 1
TIME=$(($EXPIRY + 33))
lcli1 dev-mocktime $TIME
lcli2 dev-mocktime $TIME
sleep 1
sleep 2
check_no_peers lcli1
check_no_peers lcli2

270
daemon/watch.c

@ -58,28 +58,6 @@ static void destroy_txowatch(struct txowatch *w)
txowatch_hash_del(&w->peer->dstate->txowatches, w);
}
/* Watch a txo. */
static void insert_txo_watch(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
unsigned int txout,
void (*cb)(struct peer *peer,
const struct bitcoin_tx *tx,
void *cbdata),
void *cbdata)
{
struct txowatch *w = tal(ctx, struct txowatch);
w->out.txid = *txid;
w->out.index = txout;
w->peer = peer;
w->cb = cb;
w->cbdata = cbdata;
txowatch_hash_add(&w->peer->dstate->txowatches, w);
tal_add_destructor(w, destroy_txowatch);
}
const struct sha256_double *txwatch_keyof(const struct txwatch *w)
{
return &w->txid;
@ -100,30 +78,42 @@ static void destroy_txwatch(struct txwatch *w)
txwatch_hash_del(&w->dstate->txwatches, w);
}
static struct txwatch *insert_txwatch(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
void (*cb)(struct peer *, int,
const struct sha256_double *,
void *),
void *cbdata)
/* 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,
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txid,
void *arg),
void *cb_arg)
{
struct txwatch *w;
/* We could have a null-watch on it because we saw it spend a TXO */
w = txwatch_hash_get(&peer->dstate->txwatches, txid);
if (w) {
assert(!w->cb);
tal_free(w);
}
assert(!txwatch_hash_get(&peer->dstate->txwatches, txid));
w = tal(ctx, struct txwatch);
w->depth = 0;
w->depth = -1;
w->txid = *txid;
w->dstate = peer->dstate;
w->peer = peer;
w->cb = cb;
w->cbdata = cbdata;
w->cbdata = cb_arg;
txwatch_hash_add(&w->dstate->txwatches, w);
tal_add_destructor(w, destroy_txwatch);
@ -131,8 +121,49 @@ static struct txwatch *insert_txwatch(const tal_t *ctx,
return w;
}
/* This just serves to avoid us doing bitcoind_txid_lookup repeatedly
* on unknown txs. */
struct txwatch *watch_tx_(const tal_t *ctx,
struct peer *peer,
const struct bitcoin_tx *tx,
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txid,
void *arg),
void *cb_arg)
{
struct sha256_double txid;
normalized_txid(tx, &txid);
return watch_txid(ctx, peer, &txid, cb, cb_arg);
}
struct txowatch *watch_txo_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
unsigned int output,
void (*cb)(struct peer *peer,
const struct bitcoin_tx *tx,
void *),
void *cbdata)
{
struct txowatch *w = tal(ctx, struct txowatch);
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);
tal_add_destructor(w, destroy_txowatch);
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)
{
@ -148,115 +179,100 @@ static void insert_null_txwatch(struct lightningd_state *dstate,
tal_add_destructor(w, destroy_txwatch);
}
void add_anchor_watch_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
unsigned int out,
void (*anchor_cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
void *),
void (*spend_cb)(struct peer *peer,
const struct bitcoin_tx *, void *),
void *cbdata)
{
struct sha256 h;
struct ripemd160 redeemhash;
u8 *redeemscript;
insert_txwatch(ctx, peer, txid, anchor_cb, cbdata);
insert_txo_watch(ctx, peer, txid, out, spend_cb, cbdata);
redeemscript = bitcoin_redeem_2of2(ctx, &peer->them.commitkey,
&peer->us.commitkey);
sha256(&h, redeemscript, tal_count(redeemscript));
ripemd160(&redeemhash, h.u.u8, sizeof(h));
tal_free(redeemscript);
/* 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).*/
bitcoind_watch_addr(peer->dstate, &redeemhash);
}
struct txwatch *add_commit_tx_watch_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
void *),
void *cbdata)
{
return insert_txwatch(ctx, peer, txid, cb, cbdata);
/* We are already watching the anchor txo, so we don't need to
* watch anything else. */
}
static void cb_no_arg(struct peer *peer, int depth,
const struct sha256_double *blkhash, void *vcb)
{
void (*cb)(struct peer *peer, int depth) = vcb;
cb(peer, depth);
}
void add_close_tx_watch(const tal_t *ctx,
struct peer *peer,
const struct bitcoin_tx *tx,
void (*cb)(struct peer *peer, int depth))
static void watched_normalized_txid(struct lightningd_state *dstate,
const struct bitcoin_tx *tx,
struct tx_info *txinfo)
{
struct txwatch *txw;
struct sha256_double txid;
bitcoin_txid(tx, &txid);
insert_txwatch(ctx, peer, &txid, cb_no_arg, cb);
size_t i;
normalized_txid(tx, &txid);
txw = txwatch_hash_get(&dstate->txwatches, &txid);
/* We are already watching the anchor txo, so we don't need to
* watch anything else. */
}
/* Reset to real txid for logging. */
bitcoin_txid(tx, &txid);
static void tx_watched_inputs(struct lightningd_state *dstate,
const struct bitcoin_tx *tx, void *unused)
{
size_t in;
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;
}
for (in = 0; in < tx->input_count; in++) {
/* Hmm, otherwise it may be new */
for (i = 0; i < tx->input_count; i++) {
struct txowatch *txo;
struct txwatch_output out;
struct txowatch *txow;
out.txid = tx->input[in].txid;
out.index = tx->input[in].index;
txow = txowatch_hash_get(&dstate->txowatches, &out);
if (txow)
txow->cb(txow->peer, tx, txow->cbdata);
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",
txid.sha.u.u8[0],
txid.sha.u.u8[1],
txid.sha.u.u8[2]);
insert_null_txwatch(dstate, &txid);
}
static void watched_transaction(struct lightningd_state *dstate,
const struct sha256_double *txid,
int confirmations,
bool is_coinbase,
const struct sha256_double *blkhash)
static void watched_txid(struct lightningd_state *dstate,
const struct sha256_double *txid,
int confirmations,
bool is_coinbase,
const struct sha256_double *blkhash)
{
struct txwatch *txw;
struct tx_info *txinfo;
/* Maybe it spent an output we're watching? */
if (is_coinbase)
return;
/* Are we watching this txid directly (or already reported)? */
txw = txwatch_hash_get(&dstate->txwatches, txid);
if (txw) {
if (confirmations != txw->depth) {
if (txw->cb && confirmations != txw->depth) {
txw->depth = confirmations;
if (txw->cb)
txw->cb(txw->peer, txw->depth, blkhash,
txw->cbdata);
txw->cb(txw->peer, txw->depth, blkhash, txid,
txw->cbdata);
}
return;
}
/* Don't report about this txid twice. */
insert_null_txwatch(dstate, txid);
/* Maybe it spent an output we're watching? */
if (!is_coinbase)
bitcoind_txid_lookup(dstate, txid, tx_watched_inputs, NULL);
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;
@ -267,7 +283,7 @@ static void start_poll_transactions(struct lightningd_state *dstate)
log_unusual(dstate->base_log,
"Delaying start poll: commands in progress");
} else
bitcoind_poll_transactions(dstate, watched_transaction);
bitcoind_poll_transactions(dstate, watched_txid);
refresh_timeout(dstate, &watch_timeout);
}

105
daemon/watch.h

@ -52,6 +52,7 @@ struct txwatch {
/* A new depth (-1 if conflicted), blkhash valid if > 0 */
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txid,
void *cbdata);
void *cbdata;
};
@ -63,51 +64,65 @@ HTABLE_DEFINE_TYPE(struct txwatch, txwatch_keyof, txid_hash, txwatch_eq,
txwatch_hash);
void add_anchor_watch_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
unsigned int out,
void (*anchor_cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
void *),
void (*spend_cb)(struct peer *peer,
const struct bitcoin_tx *, void *),
void *cbdata);
#define add_anchor_watch(ctx, peer, txid, out, anchor_cb, spend_cb, cbdata) \
add_anchor_watch_((ctx), (peer), (txid), (out), \
typesafe_cb_preargs(void, void *, \
(anchor_cb), (cbdata), \
struct peer *, \
int depth, \
const struct sha256_double *), \
typesafe_cb_preargs(void, void *, \
(spend_cb), (cbdata), \
struct peer *, \
const struct bitcoin_tx *), \
(cbdata))
struct txwatch *add_commit_tx_watch_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
void *),
void *cbdata);
#define add_commit_tx_watch(ctx, peer, txid, cb, cbdata) \
add_commit_tx_watch_((ctx), (peer), (txid), \
typesafe_cb_preargs(void, void *, \
(cb), (cbdata), \
struct peer *, \
int, \
const struct sha256_double *), \
(cbdata))
void add_close_tx_watch(const tal_t *ctx,
struct peer *peer,
const struct bitcoin_tx *tx,
void (*cb)(struct peer *peer, int depth));
struct txwatch *watch_txid_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txidx,
void *),
void *cbdata);
#define watch_txid(ctx, peer, txid, cb, cbdata) \
watch_txid_((ctx), (peer), (txid), \
typesafe_cb_preargs(void, void *, \
(cb), (cbdata), \
struct peer *, \
int depth, \
const struct sha256_double *, \
const struct sha256_double *txidx), \
(cbdata))
struct txwatch *watch_tx_(const tal_t *ctx,
struct peer *peer,
const struct bitcoin_tx *tx,
void (*cb)(struct peer *peer, int depth,
const struct sha256_double *blkhash,
const struct sha256_double *txidx,
void *),
void *cbdata);
#define watch_tx(ctx, peer, tx, cb, cbdata) \
watch_tx_((ctx), (peer), (tx), \
typesafe_cb_preargs(void, void *, \
(cb), (cbdata), \
struct peer *, \
int depth, \
const struct sha256_double *, \
const struct sha256_double *), \
(cbdata))
struct txowatch *watch_txo_(const tal_t *ctx,
struct peer *peer,
const struct sha256_double *txid,
unsigned int output,
void (*cb)(struct peer *peer,
const struct bitcoin_tx *tx,
void *),
void *cbdata);
#define watch_txo(ctx, peer, txid, outnum, cb, cbdata) \
watch_txo_((ctx), (peer), (txid), (outnum), \
typesafe_cb_preargs(void, void *, \
(cb), (cbdata), \
struct peer *, \
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);
#endif /* LIGHTNING_DAEMON_WATCH_H */

Loading…
Cancel
Save