Browse Source
This uses the functions in bitcoind to provide callbacks when various things happen. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>ppa-0.6.1
7 changed files with 347 additions and 2 deletions
@ -0,0 +1,230 @@ |
|||||
|
/* Code to talk to bitcoind to watch for various events.
|
||||
|
* |
||||
|
* Here's what we want to know: |
||||
|
* |
||||
|
* - An anchor tx: |
||||
|
* - Reached given depth |
||||
|
* - Times out. |
||||
|
* - Is unspent after reaching given depth. |
||||
|
* |
||||
|
* - Our own commitment tx: |
||||
|
* - Reached a given depth. |
||||
|
* |
||||
|
* - HTLC spend tx: |
||||
|
* - Reached a given depth. |
||||
|
* |
||||
|
* - Anchor tx output: |
||||
|
* - Is spent by their current tx. |
||||
|
* - Is spent by a revoked tx. |
||||
|
* |
||||
|
* - Commitment tx HTLC outputs: |
||||
|
* - HTLC timed out |
||||
|
* - HTLC spent |
||||
|
* |
||||
|
* We do this by adding the P2SH address to the wallet, and then querying |
||||
|
* that using listtransactions. |
||||
|
* |
||||
|
* WE ASSUME NO MALLEABILITY! This requires segregated witness. |
||||
|
*/ |
||||
|
#include "bitcoin/script.h" |
||||
|
#include "bitcoin/tx.h" |
||||
|
#include "bitcoind.h" |
||||
|
#include "lightningd.h" |
||||
|
#include "log.h" |
||||
|
#include "peer.h" |
||||
|
#include "timeout.h" |
||||
|
#include "watch.h" |
||||
|
#include <ccan/hash/hash.h> |
||||
|
#include <ccan/structeq/structeq.h> |
||||
|
|
||||
|
const struct txwatch_output *txowatch_keyof(const struct txowatch *w) |
||||
|
{ |
||||
|
return &w->out; |
||||
|
} |
||||
|
|
||||
|
size_t txo_hash(const struct txwatch_output *out) |
||||
|
{ |
||||
|
return hash(&out->txid, 1, out->index); |
||||
|
} |
||||
|
|
||||
|
bool txowatch_eq(const struct txowatch *w, const struct txwatch_output *out) |
||||
|
{ |
||||
|
return structeq(&w->out.txid, &out->txid) |
||||
|
&& w->out.index == out->index; |
||||
|
} |
||||
|
|
||||
|
static void destroy_txowatch(struct txowatch *w) |
||||
|
{ |
||||
|
txowatch_hash_del(&w->peer->state->txowatches, w); |
||||
|
} |
||||
|
|
||||
|
/* Watch a txo. */ |
||||
|
static void insert_txo_watch(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(peer, struct txowatch); |
||||
|
|
||||
|
w->out.txid = *txid; |
||||
|
w->out.index = txout; |
||||
|
w->peer = peer; |
||||
|
w->cb = cb; |
||||
|
w->cbdata = cbdata; |
||||
|
|
||||
|
txowatch_hash_add(&w->peer->state->txowatches, w); |
||||
|
tal_add_destructor(w, destroy_txowatch); |
||||
|
} |
||||
|
|
||||
|
const struct sha256_double *txwatch_keyof(const struct txwatch *w) |
||||
|
{ |
||||
|
return &w->txid; |
||||
|
} |
||||
|
|
||||
|
size_t txid_hash(const struct sha256_double *txid) |
||||
|
{ |
||||
|
return hash(txid->sha.u.u8, sizeof(txid->sha.u.u8), 0); |
||||
|
} |
||||
|
|
||||
|
bool txwatch_eq(const struct txwatch *w, const struct sha256_double *txid) |
||||
|
{ |
||||
|
return structeq(&w->txid, txid); |
||||
|
} |
||||
|
|
||||
|
static void destroy_txwatch(struct txwatch *w) |
||||
|
{ |
||||
|
txwatch_hash_del(&w->state->txwatches, w); |
||||
|
} |
||||
|
|
||||
|
static struct txwatch *insert_txwatch(const tal_t *ctx, |
||||
|
struct lightningd_state *state, |
||||
|
struct peer *peer, |
||||
|
const struct sha256_double *txid, |
||||
|
void (*cb)(struct peer *, int, void *), |
||||
|
void *cbdata) |
||||
|
{ |
||||
|
struct txwatch *w; |
||||
|
|
||||
|
/* We could have a null-watch on it because we saw it spend a TXO */ |
||||
|
w = txwatch_hash_get(&state->txwatches, txid); |
||||
|
if (w) { |
||||
|
assert(!w->cb); |
||||
|
tal_free(w); |
||||
|
} |
||||
|
|
||||
|
w = tal(ctx, struct txwatch); |
||||
|
w->depth = 0; |
||||
|
w->txid = *txid; |
||||
|
w->state = state; |
||||
|
w->peer = peer; |
||||
|
w->cb = cb; |
||||
|
w->cbdata = cbdata; |
||||
|
|
||||
|
txwatch_hash_add(&w->state->txwatches, w); |
||||
|
tal_add_destructor(w, destroy_txwatch); |
||||
|
|
||||
|
return w; |
||||
|
} |
||||
|
|
||||
|
void add_anchor_watch_(struct peer *peer, |
||||
|
const struct sha256_double *txid, |
||||
|
unsigned int out, |
||||
|
void (*anchor_cb)(struct peer *peer, int depth, void *), |
||||
|
void (*spend_cb)(struct peer *peer, |
||||
|
const struct bitcoin_tx *, void *), |
||||
|
void *cbdata) |
||||
|
{ |
||||
|
struct sha256 h; |
||||
|
struct ripemd160 redeemhash; |
||||
|
u8 *redeemscript; |
||||
|
|
||||
|
insert_txwatch(peer, peer->state, peer, txid, anchor_cb, cbdata); |
||||
|
insert_txo_watch(peer, txid, out, spend_cb, cbdata); |
||||
|
|
||||
|
redeemscript = bitcoin_redeem_2of2(peer, &peer->their_commitkey, |
||||
|
&peer->our_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->state, &redeemhash); |
||||
|
} |
||||
|
|
||||
|
void add_commit_tx_watch_(struct peer *peer, |
||||
|
const struct sha256_double *txid, |
||||
|
void (*cb)(struct peer *peer, int depth, void *), |
||||
|
void *cbdata) |
||||
|
{ |
||||
|
insert_txwatch(peer, peer->state, peer, txid, cb, cbdata); |
||||
|
|
||||
|
/* We are already watching the anchor txo, so we don't need to
|
||||
|
* watch anything else. */ |
||||
|
} |
||||
|
|
||||
|
static void tx_watched_inputs(struct lightningd_state *state, |
||||
|
const struct bitcoin_tx *tx, void *unused) |
||||
|
{ |
||||
|
size_t in; |
||||
|
|
||||
|
for (in = 0; in < tx->input_count; in++) { |
||||
|
struct txwatch_output out; |
||||
|
struct txowatch *txow; |
||||
|
|
||||
|
out.txid = tx->input[in].txid; |
||||
|
out.index = tx->input[in].index; |
||||
|
|
||||
|
txow = txowatch_hash_get(&state->txowatches, &out); |
||||
|
if (txow) |
||||
|
txow->cb(txow->peer, tx, txow->cbdata); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static void watched_transaction(struct lightningd_state *state, |
||||
|
const struct sha256_double *txid, |
||||
|
int confirmations) |
||||
|
{ |
||||
|
struct txwatch *txw; |
||||
|
|
||||
|
/* Are we watching this txid directly (or already reported)? */ |
||||
|
txw = txwatch_hash_get(&state->txwatches, txid); |
||||
|
if (txw) { |
||||
|
if (confirmations != txw->depth) { |
||||
|
txw->depth = confirmations; |
||||
|
if (txw->cb) |
||||
|
txw->cb(txw->peer, txw->depth, txw->cbdata); |
||||
|
} |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
/* Don't report about this txid twice. */ |
||||
|
insert_txwatch(state, state, NULL, txid, NULL, NULL); |
||||
|
|
||||
|
/* Maybe it spent an output we're watching? */ |
||||
|
bitcoind_txid_lookup(state, txid, tx_watched_inputs, NULL); |
||||
|
} |
||||
|
|
||||
|
static struct timeout watch_timeout; |
||||
|
|
||||
|
static void start_poll_transactions(struct lightningd_state *state) |
||||
|
{ |
||||
|
if (state->bitcoind_in_progress != 0) { |
||||
|
log_unusual(state->base_log, |
||||
|
"Delaying start poll: %u commands in progress", |
||||
|
state->bitcoind_in_progress); |
||||
|
} else |
||||
|
bitcoind_poll_transactions(state, watched_transaction); |
||||
|
refresh_timeout(state, &watch_timeout); |
||||
|
} |
||||
|
|
||||
|
void setup_watch_timer(struct lightningd_state *state) |
||||
|
{ |
||||
|
init_timeout(&watch_timeout, 30, start_poll_transactions, state); |
||||
|
/* Run once immediately, in case there are issues. */ |
||||
|
start_poll_transactions(state); |
||||
|
} |
@ -0,0 +1,98 @@ |
|||||
|
#ifndef LIGHTNING_DAEMON_WATCH_H |
||||
|
#define LIGHTNING_DAEMON_WATCH_H |
||||
|
#include "config.h" |
||||
|
#include "bitcoin/shadouble.h" |
||||
|
#include <ccan/crypto/ripemd160/ripemd160.h> |
||||
|
#include <ccan/htable/htable_type.h> |
||||
|
#include <ccan/list/list.h> |
||||
|
#include <ccan/short_types/short_types.h> |
||||
|
#include <ccan/typesafe_cb/typesafe_cb.h> |
||||
|
|
||||
|
struct bitcoin_tx; |
||||
|
struct lightningd_state; |
||||
|
|
||||
|
struct txwatch_output { |
||||
|
struct sha256_double txid; |
||||
|
unsigned int index; |
||||
|
}; |
||||
|
|
||||
|
/* Watching an output */ |
||||
|
struct txowatch { |
||||
|
/* Peer who owns us. */ |
||||
|
struct peer *peer; |
||||
|
|
||||
|
/* Output to watch. */ |
||||
|
struct txwatch_output out; |
||||
|
|
||||
|
/* A new tx. */ |
||||
|
void (*cb)(struct peer *peer, |
||||
|
const struct bitcoin_tx *tx, |
||||
|
void *cbdata); |
||||
|
|
||||
|
void *cbdata; |
||||
|
}; |
||||
|
|
||||
|
const struct txwatch_output *txowatch_keyof(const struct txowatch *w); |
||||
|
size_t txo_hash(const struct txwatch_output *out); |
||||
|
bool txowatch_eq(const struct txowatch *w, const struct txwatch_output *out); |
||||
|
|
||||
|
HTABLE_DEFINE_TYPE(struct txowatch, txowatch_keyof, txo_hash, txowatch_eq, |
||||
|
txowatch_hash); |
||||
|
|
||||
|
struct txwatch { |
||||
|
struct lightningd_state *state; |
||||
|
|
||||
|
/* Peer who owns us. */ |
||||
|
struct peer *peer; |
||||
|
|
||||
|
/* Transaction to watch. */ |
||||
|
struct sha256_double txid; |
||||
|
int depth; |
||||
|
|
||||
|
/* A new depth (-1 if conflicted) */ |
||||
|
void (*cb)(struct peer *peer, int depth, void *cbdata); |
||||
|
void *cbdata; |
||||
|
}; |
||||
|
|
||||
|
const struct sha256_double *txwatch_keyof(const struct txwatch *w); |
||||
|
size_t txid_hash(const struct sha256_double *txid); |
||||
|
bool txwatch_eq(const struct txwatch *w, const struct sha256_double *txid); |
||||
|
HTABLE_DEFINE_TYPE(struct txwatch, txwatch_keyof, txid_hash, txwatch_eq, |
||||
|
txwatch_hash); |
||||
|
|
||||
|
|
||||
|
void add_anchor_watch_(struct peer *peer, |
||||
|
const struct sha256_double *txid, |
||||
|
unsigned int out, |
||||
|
void (*anchor_cb)(struct peer *peer, int depth, void *), |
||||
|
void (*spend_cb)(struct peer *peer, |
||||
|
const struct bitcoin_tx *, void *), |
||||
|
void *cbdata); |
||||
|
|
||||
|
#define add_anchor_watch(peer, txid, out, anchor_cb, spend_cb, cbdata) \ |
||||
|
add_anchor_watch_((peer), (txid), (out), \ |
||||
|
typesafe_cb_preargs(void, void *, \ |
||||
|
(anchor_cb), (cbdata), \ |
||||
|
struct peer *, \ |
||||
|
int depth), \ |
||||
|
typesafe_cb_preargs(void, void *, \ |
||||
|
(spend_cb), (cbdata), \ |
||||
|
struct peer *, \ |
||||
|
const struct bitcoin_tx *), \ |
||||
|
(cbdata)) |
||||
|
|
||||
|
void add_commit_tx_watch_(struct peer *peer, |
||||
|
const struct sha256_double *txid, |
||||
|
void (*cb)(struct peer *peer, int depth, void *), |
||||
|
void *cbdata); |
||||
|
|
||||
|
#define add_commit_tx_watch(peer, txid, cb, cbdata) \ |
||||
|
add_commit_tx_watch_((peer), (txid), \ |
||||
|
typesafe_cb_preargs(void, void *, \ |
||||
|
(cb), (cbdata), \ |
||||
|
struct peer *, \ |
||||
|
int depth), \ |
||||
|
(cbdata)) |
||||
|
|
||||
|
void setup_watch_timer(struct lightningd_state *state); |
||||
|
#endif /* LIGHTNING_DAEMON_WATCH_H */ |
Loading…
Reference in new issue