lightningd: start onchaind when we see funding spent.

We're very simple about it: if there's a reorganization, we restart.  Otherwise
we tell it about everything.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-08-23 11:25:16 +09:30 committed by Christian Decker
parent 1b2fb18944
commit d7db0be5da
5 changed files with 342 additions and 27 deletions

View File

@ -148,7 +148,7 @@ check-makefile: check-lightningd-makefile
check-lightningd-makefile:
@for f in lightningd/*.h lightningd/*/*.h; do if ! echo $(LIGHTNINGD_HEADERS_NOGEN) $(LIGHTNINGD_HEADERS_GEN) "" | grep -q "$$f "; then echo $$f not mentioned in LIGHTNINGD_HEADERS_NOGEN or LIGHTNINGD_HEADERS_GEN >&2; exit 1; fi; done
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(CCAN_OBJS) $(CCAN_SHACHAIN48_OBJ) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) $(LIGHTNINGD_CLOSING_CONTROL_OBJS) $(WALLET_LIB_OBJS) libsecp256k1.a libsodium.a libwallycore.a
lightningd/lightningd: $(LIGHTNINGD_OBJS) $(LIGHTNINGD_OLD_OBJS) $(LIGHTNINGD_OLD_LIB_OBJS) $(LIGHTNINGD_LIB_OBJS) $(LIGHTNINGD_JSMN_OBJS) $(CORE_OBJS) $(CORE_TX_OBJS) $(BITCOIN_OBJS) $(WIRE_OBJS) $(WIRE_ONION_OBJS) $(CCAN_OBJS) $(CCAN_SHACHAIN48_OBJ) $(LIGHTNINGD_HSM_CONTROL_OBJS) $(LIGHTNINGD_HANDSHAKE_CONTROL_OBJS) $(LIGHTNINGD_GOSSIP_CONTROL_OBJS) $(LIBBASE58_OBJS) $(LIGHTNINGD_OPENING_CONTROL_OBJS) $(LIGHTNINGD_CHANNEL_CONTROL_OBJS) $(LIGHTNINGD_CLOSING_CONTROL_OBJS) $(LIGHTNINGD_ONCHAIN_CONTROL_OBJS) $(WALLET_LIB_OBJS) libsecp256k1.a libsodium.a libwallycore.a
clean: lightningd-clean

View File

@ -30,6 +30,7 @@
#include <lightningd/hsm_control.h>
#include <lightningd/key_derive.h>
#include <lightningd/new_connection.h>
#include <lightningd/onchain/gen_onchain_wire.h>
#include <lightningd/onchain/onchain_wire.h>
#include <lightningd/opening/gen_opening_wire.h>
#include <lightningd/peer_htlcs.h>
@ -213,8 +214,8 @@ void peer_fail_transient(struct peer *peer, const char *fmt, ...)
return;
}
/* Reconnect unless we've dropped to chain. */
if (!peer_on_chain(peer)) {
/* Reconnect unless we've dropped/are dropping to chain. */
if (!peer_on_chain(peer) && peer->state != CLOSINGD_COMPLETE) {
peer_reconnect(peer);
return;
}
@ -1013,6 +1014,283 @@ static enum watch_result funding_announce_cb(struct peer *peer,
return DELETE_WATCH;
}
static void peer_onchain_finished(struct subd *subd, int status)
{
/* Moved on? Eg. reorg, and it has a new onchaind. */
if (subd->peer->owner != subd)
return;
if (status != 0) {
log_broken(subd->peer->log, "onchaind died status %i", status);
subd->peer->owner = NULL;
return;
}
/* FIXME: Remove peer from db. */
log_info(subd->peer->log, "onchaind complete, forgetting peer");
/* Peer is gone. */
tal_free(subd->peer);
}
static int handle_onchain_init_reply(struct peer *peer, const u8 *msg)
{
u8 state;
if (!fromwire_onchain_init_reply(msg, NULL, &state)) {
log_broken(peer->log, "Invalid onchain_init_reply");
return -1;
}
if (!peer_state_on_chain(state)) {
log_broken(peer->log, "Invalid onchain_init_reply state %u (%s)",
state, peer_state_name(state));
return -1;
}
/* We could come from almost any state. */
peer_set_condition(peer, peer->state, state);
return 0;
}
static enum watch_result onchain_tx_watched(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
void *unused)
{
u8 *msg;
struct sha256_double txid;
if (depth == 0) {
struct subd *old_onchaind = peer->owner;
log_unusual(peer->log, "Chain reorganization!");
peer->owner = NULL;
tal_free(old_onchaind);
/* FIXME!
topology_rescan(peer->ld->topology, peer->funding_txid);
*/
/* We will most likely be freed, so this is a noop */
return KEEP_WATCHING;
}
bitcoin_txid(tx, &txid);
msg = towire_onchain_depth(peer, &txid, depth);
subd_send_msg(peer->owner, take(msg));
return KEEP_WATCHING;
}
static void watch_tx_and_outputs(struct peer *peer,
const struct bitcoin_tx *tx);
static enum watch_result onchain_txo_watched(struct peer *peer,
const struct bitcoin_tx *tx,
size_t input_num,
const struct block *block,
void *unused)
{
u8 *msg;
watch_tx_and_outputs(peer, tx);
msg = towire_onchain_spent(peer, tx, input_num, block->height);
subd_send_msg(peer->owner, take(msg));
/* We don't need to keep watching: If this output is double-spent
* (reorg), we'll get a zero depth cb to onchain_tx_watched, and
* restart onchaind. */
return DELETE_WATCH;
}
/* To avoid races, we watch the tx and all outputs. */
static void watch_tx_and_outputs(struct peer *peer,
const struct bitcoin_tx *tx)
{
struct sha256_double txid;
struct txwatch *txw;
bitcoin_txid(tx, &txid);
/* Make txwatch a parent of txo watches, so we can unwatch together. */
txw = watch_tx(peer->owner, peer->ld->topology, peer, tx,
onchain_tx_watched, NULL);
for (size_t i = 0; i < tal_count(tx->output); i++)
watch_txo(txw, peer->ld->topology, peer, &txid, i,
onchain_txo_watched, NULL);
}
static int handle_onchain_broadcast_tx(struct peer *peer, const u8 *msg)
{
struct bitcoin_tx *tx;
tx = tal(msg, struct bitcoin_tx);
if (!fromwire_onchain_broadcast_tx(msg, NULL, tx)) {
log_broken(peer->log, "Invalid onchain_broadcast_tx");
return -1;
}
/* We don't really care if it fails, we'll respond via watch. */
broadcast_tx(peer->ld->topology, peer, tx, NULL);
return 0;
}
static int handle_onchain_unwatch_tx(struct peer *peer, const u8 *msg)
{
/* FIXME: unwatch tx and children here. */
return 0;
}
static int handle_extracted_preimage(struct peer *peer, const u8 *msg)
{
struct preimage preimage;
if (!fromwire_onchain_extracted_preimage(msg, NULL, &preimage)) {
log_broken(peer->log, "Invalid extracted_preimage");
return -1;
}
onchain_fulfilled_htlc(peer, &preimage);
return 0;
}
static int onchain_msg(struct subd *sd, const u8 *msg, const int *fds)
{
enum onchain_wire_type t = fromwire_peektype(msg);
switch (t) {
/* We let peer_onchain_finished handle these. */
case WIRE_ONCHAIN_BAD_COMMAND:
case WIRE_ONCHAIN_INTERNAL_ERROR:
case WIRE_ONCHAIN_CRYPTO_FAILED:
break;
case WIRE_ONCHAIN_INIT_REPLY:
return handle_onchain_init_reply(sd->peer, msg);
case WIRE_ONCHAIN_BROADCAST_TX:
return handle_onchain_broadcast_tx(sd->peer, msg);
case WIRE_ONCHAIN_UNWATCH_TX:
return handle_onchain_unwatch_tx(sd->peer, msg);
case WIRE_ONCHAIN_EXTRACTED_PREIMAGE:
return handle_extracted_preimage(sd->peer, msg);
/* We send these, not receive them */
case WIRE_ONCHAIN_INIT:
case WIRE_ONCHAIN_SPENT:
case WIRE_ONCHAIN_DEPTH:
case WIRE_ONCHAIN_HTLC:
case WIRE_ONCHAIN_KNOWN_PREIMAGE:
break;
}
return 0;
}
static u8 *p2wpkh_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx)
{
struct pubkey shutdownkey;
if (!bip32_pubkey(ld->bip32_base, &shutdownkey, keyidx))
return NULL;
return scriptpubkey_p2wpkh(ctx, &shutdownkey);
}
/* With a reorg, this can get called multiple times; each time we'll kill
* onchaind (like any other owner), and restart */
static enum watch_result funding_spent(struct peer *peer,
const struct bitcoin_tx *tx,
size_t input_num,
const struct block *block,
void *unused)
{
u8 *msg, *scriptpubkey;
struct sha256_double our_last_txid;
s64 keyindex;
struct pubkey ourkey;
peer_fail_permanent_str(peer, "Funding transaction spent");
peer->owner = new_subd(peer->ld, peer->ld,
"lightningd_onchain", peer,
onchain_wire_type_name,
onchain_msg,
peer_onchain_finished,
NULL, NULL);
if (!peer->owner) {
log_broken(peer->log, "Could not subdaemon onchain: %s",
strerror(errno));
return KEEP_WATCHING;
}
/* We re-use this key to send other outputs to. */
if (peer->local_shutdown_idx >= 0)
keyindex = peer->local_shutdown_idx;
else {
/* FIXME: Save to db */
keyindex = wallet_get_newindex(peer->ld);
if (keyindex < 0) {
log_broken(peer->log, "Could not get keyindex");
return KEEP_WATCHING;
}
}
scriptpubkey = p2wpkh_for_keyidx(peer, peer->ld, keyindex);
if (!scriptpubkey) {
peer_internal_error(peer,
"Can't get shutdown script %"PRIu64,
keyindex);
return DELETE_WATCH;
}
if (!bip32_pubkey(peer->ld->bip32_base, &ourkey, keyindex)) {
peer_internal_error(peer,
"Can't get shutdown key %"PRIu64,
keyindex);
return DELETE_WATCH;
}
/* This could be a mutual close, but it doesn't matter. */
bitcoin_txid(peer->last_tx, &our_last_txid);
msg = towire_onchain_init(peer, peer->seed, &peer->their_shachain.chain,
peer->funding_satoshi,
&peer->channel_info->old_remote_per_commit,
&peer->channel_info->remote_per_commit,
peer->our_config.to_self_delay,
peer->channel_info->their_config.to_self_delay,
peer->channel_info->feerate_per_kw,
peer->our_config.dust_limit_satoshis,
&peer->channel_info->theirbase.revocation,
&our_last_txid,
scriptpubkey,
peer->remote_shutdown_scriptpubkey,
&ourkey,
peer->funder,
&peer->channel_info->theirbase.payment,
&peer->channel_info->theirbase.delayed_payment,
tx,
block->height,
peer->last_htlc_sigs,
tal_count(peer->htlcs));
subd_send_msg(peer->owner, take(msg));
/* FIXME: Don't queue all at once, use an empty cb... */
for (size_t i = 0; i < tal_count(peer->htlcs); i++) {
msg = towire_onchain_htlc(peer, peer->htlcs+i);
subd_send_msg(peer->owner, take(msg));
}
/* FIXME: Send any known HTLC preimage for live HTLCs! */
watch_tx_and_outputs(peer, tx);
/* We keep watching until peer finally deleted, for reorgs. */
return KEEP_WATCHING;
}
static enum watch_result funding_lockin_cb(struct peer *peer,
const struct bitcoin_tx *tx,
unsigned int depth,
@ -1116,6 +1394,11 @@ static void opening_got_hsm_funding_sig(struct funding_channel *fc,
watch_tx(fc->peer, fc->peer->ld->topology, fc->peer, tx,
funding_lockin_cb, NULL);
/* FIXME: Remove arg from cb? */
watch_txo(fc->peer, fc->peer->ld->topology, fc->peer,
fc->peer->funding_txid, fc->peer->funding_outnum,
funding_spent, NULL);
/* We could defer until after funding locked, but makes testing
* harder. */
tal_del_destructor(fc, fail_fundchannel_command);
@ -1215,16 +1498,6 @@ static int peer_got_funding_locked(struct peer *peer, const u8 *msg)
return 0;
}
static u8 *p2wpkh_for_keyidx(const tal_t *ctx, struct lightningd *ld, u64 keyidx)
{
struct pubkey shutdownkey;
if (!bip32_pubkey(ld->bip32_base, &shutdownkey, keyidx))
return NULL;
return scriptpubkey_p2wpkh(ctx, &shutdownkey);
}
static int peer_got_shutdown(struct peer *peer, const u8 *msg)
{
u8 *scriptpubkey;
@ -1945,6 +2218,10 @@ static bool opening_fundee_finished(struct subd *opening,
watch_txid(peer, peer->ld->topology, peer, peer->funding_txid,
funding_lockin_cb, NULL);
/* FIXME: Remove arg from cb? */
watch_txo(peer, peer->ld->topology, peer, peer->funding_txid,
peer->funding_outnum, funding_spent, NULL);
/* Unowned. */
peer->owner = NULL;

View File

@ -117,12 +117,17 @@ static inline bool peer_can_remove_htlc(const struct peer *peer)
|| peer->state == ONCHAIND_OUR_UNILATERAL;
}
static inline bool peer_state_on_chain(enum peer_state state)
{
return state == ONCHAIND_CHEATED
|| state == ONCHAIND_THEIR_UNILATERAL
|| state == ONCHAIND_OUR_UNILATERAL
|| state == ONCHAIND_MUTUAL;
}
static inline bool peer_on_chain(const struct peer *peer)
{
return peer->state == ONCHAIND_CHEATED
|| peer->state == ONCHAIND_THEIR_UNILATERAL
|| peer->state == ONCHAIND_OUR_UNILATERAL
|| peer->state == ONCHAIND_MUTUAL;
return peer_state_on_chain(peer->state);
}
/* BOLT #2:

View File

@ -687,6 +687,20 @@ out:
return true;
}
static void fulfill_our_htlc_out(struct peer *peer, struct htlc_out *hout,
const struct preimage *preimage)
{
hout->preimage = tal_dup(hout, struct preimage, preimage);
htlc_out_check(hout, __func__);
/* FIXME: Save to db */
if (hout->in)
fulfill_htlc(hout->in, preimage);
else
payment_succeeded(peer->ld, hout, preimage);
}
static bool peer_fulfilled_our_htlc(struct peer *peer,
const struct fulfilled_htlc *fulfilled)
{
@ -703,19 +717,34 @@ static bool peer_fulfilled_our_htlc(struct peer *peer,
if (!htlc_out_update_state(peer, hout, RCVD_REMOVE_COMMIT))
return false;
hout->preimage = tal_dup(hout, struct preimage,
&fulfilled->payment_preimage);
htlc_out_check(hout, __func__);
/* FIXME: Save to db */
if (hout->in)
fulfill_htlc(hout->in, &fulfilled->payment_preimage);
else
payment_succeeded(peer->ld, hout, &fulfilled->payment_preimage);
fulfill_our_htlc_out(peer, hout, &fulfilled->payment_preimage);
return true;
}
void onchain_fulfilled_htlc(struct peer *peer, const struct preimage *preimage)
{
struct htlc_out_map_iter outi;
struct htlc_out *hout;
struct sha256 payment_hash;
sha256(&payment_hash, preimage, sizeof(*preimage));
/* FIXME: use db to look this up! */
for (hout = htlc_out_map_first(&peer->ld->htlcs_out, &outi);
hout;
hout = htlc_out_map_next(&peer->ld->htlcs_out, &outi)) {
if (hout->key.peer != peer)
continue;
if (!structeq(&hout->payment_hash, &payment_hash))
continue;
fulfill_our_htlc_out(peer, hout, preimage);
/* We keep going: this is something of a leak, but onchain
* we have no real way of distinguishing HTLCs anyway */
}
}
static bool peer_failed_our_htlc(struct peer *peer,
const struct failed_htlc *failed)
{

View File

@ -11,6 +11,8 @@ struct channel_info {
struct channel_config their_config;
struct pubkey remote_fundingkey;
struct basepoints theirbase;
/* The old_remote_per_commit is for the locked-in remote commit_tx,
* and the remote_per_commit is for the commit_tx we're modifying now. */
struct pubkey remote_per_commit, old_remote_per_commit;
u32 feerate_per_kw;
};
@ -38,4 +40,6 @@ enum onion_type send_htlc_out(struct peer *out, u64 amount, u32 cltv,
struct htlc_in *in,
struct pay_command *pc,
struct htlc_out **houtp);
void onchain_fulfilled_htlc(struct peer *peer, const struct preimage *preimage);
#endif /* LIGHTNING_LIGHTNINGD_PEER_HTLCS_H */