diff --git a/daemon/jsonrpc.c b/daemon/jsonrpc.c index d0944b8f3..11c61aebf 100644 --- a/daemon/jsonrpc.c +++ b/daemon/jsonrpc.c @@ -254,6 +254,7 @@ static const struct json_command *cmdlist[] = { &newhtlc_command, &fulfillhtlc_command, &failhtlc_command, + &close_command, /* Developer/debugging options. */ &echo_command, &rhash_command, diff --git a/daemon/jsonrpc.h b/daemon/jsonrpc.h index d1518ddba..a0edd9e1a 100644 --- a/daemon/jsonrpc.h +++ b/daemon/jsonrpc.h @@ -62,4 +62,5 @@ extern const struct json_command newhtlc_command; extern const struct json_command fulfillhtlc_command; extern const struct json_command failhtlc_command; extern const struct json_command mocktime_command; +extern const struct json_command close_command; #endif /* LIGHTNING_DAEMON_JSONRPC_H */ diff --git a/daemon/lightningd.c b/daemon/lightningd.c index d4baa0def..6b5034f9d 100644 --- a/daemon/lightningd.c +++ b/daemon/lightningd.c @@ -79,6 +79,9 @@ static void config_register_opts(struct lightningd_state *dstate) opt_register_arg("--max-anchor-confirms", opt_set_u32, opt_show_u32, &dstate->config.anchor_confirms_max, "Maximum confirmations other side can wait for anchor transaction"); + opt_register_arg("--forever-confirms", opt_set_u32, opt_show_u32, + &dstate->config.forever_confirms, + "Confirmations after which we consider a reorg impossible"); opt_register_arg("--commit-fee", opt_set_u64, opt_show_u64, &dstate->config.commitment_fee, "Satoshis to offer for commitment transaction fee"); @@ -120,6 +123,9 @@ static void default_config(struct config *config) /* More than 10 confirms seems overkill. */ config->anchor_confirms_max = 10; + /* At some point, you've got to let it go... */ + config->forever_confirms = 100; + /* FIXME: These should float with bitcoind's recommendations! */ /* Pay hefty fee (10x current suggested minimum). */ diff --git a/daemon/lightningd.h b/daemon/lightningd.h index 6f56acfec..39e462abe 100644 --- a/daemon/lightningd.h +++ b/daemon/lightningd.h @@ -26,6 +26,9 @@ struct config { /* How long will we accept them waiting? */ u32 anchor_confirms_max; + /* How many blocks until we stop watching a close commit? */ + u32 forever_confirms; + /* What are we prepared to pay in commitment fee (satoshis). */ u64 commitment_fee; diff --git a/daemon/packets.c b/daemon/packets.c index f4e8afb1d..06566125e 100644 --- a/daemon/packets.c +++ b/daemon/packets.c @@ -1,5 +1,6 @@ #include "bitcoin/script.h" #include "bitcoin/tx.h" +#include "close_tx.h" #include "controlled_time.h" #include "find_p2sh_out.h" #include "lightningd.h" @@ -242,32 +243,32 @@ Pkt *pkt_err(const tal_t *ctx, const char *msg, ...) Pkt *pkt_close(const tal_t *ctx, const struct peer *peer) { CloseChannel *c = tal(ctx, CloseChannel); - struct signature sig; close_channel__init(c); - /* FIXME: If we're not connected, we don't create close tx. */ - if (!peer->close_tx) { - c->close_fee = 0; - memset(&sig, 0, sizeof(sig)); - c->sig = signature_to_proto(c, &sig); - } else { - c->close_fee = peer->close_tx->fee; - peer_sign_mutual_close(peer, peer->close_tx, &sig); - c->sig = signature_to_proto(c, &sig); - } + c->close_fee = peer->close_tx->fee; + c->sig = signature_to_proto(c, &peer->our_close_sig.sig); return make_pkt(ctx, PKT__PKT_CLOSE, c); } Pkt *pkt_close_complete(const tal_t *ctx, const struct peer *peer) { - FIXME_STUB(peer); + CloseChannelComplete *c = tal(ctx, CloseChannelComplete); + + close_channel_complete__init(c); + assert(peer->close_tx); + c->sig = signature_to_proto(c, &peer->our_close_sig.sig); + + return make_pkt(ctx, PKT__PKT_CLOSE_COMPLETE, c); } Pkt *pkt_close_ack(const tal_t *ctx, const struct peer *peer) { - FIXME_STUB(peer); + CloseChannelAck *a = tal(ctx, CloseChannelAck); + + close_channel_ack__init(a); + return make_pkt(ctx, PKT__PKT_CLOSE_ACK, a); } Pkt *pkt_err_unexpected(const tal_t *ctx, const Pkt *pkt) @@ -758,15 +759,57 @@ Pkt *accept_pkt_update_signature(const tal_t *ctx, return NULL; } +static bool peer_sign_close_tx(struct peer *peer, const Signature *theirs) +{ + struct bitcoin_signature theirsig; + + /* We never sign twice! */ + assert(peer->close_tx->input[0].script_length == 0); + + theirsig.stype = SIGHASH_ALL; + if (!proto_to_signature(theirs, &theirsig.sig)) + return false; + + /* Their sig + ours should sign the close tx. */ + if (!check_2of2_sig(peer->dstate->secpctx, + peer->close_tx, 0, + peer->anchor.redeemscript, + tal_count(peer->anchor.redeemscript), + &peer->them.commitkey, &peer->us.commitkey, + &theirsig, &peer->our_close_sig)) + return false; + + /* Complete the close_tx, using signatures. */ + peer->close_tx->input[0].script + = scriptsig_p2sh_2of2(peer->close_tx, + &theirsig, &peer->our_close_sig, + &peer->them.commitkey, + &peer->us.commitkey); + peer->close_tx->input[0].script_length + = tal_count(peer->close_tx->input[0].script); + return true; +} + Pkt *accept_pkt_close(const tal_t *ctx, struct peer *peer, const Pkt *pkt) { - FIXME_STUB(peer); + const CloseChannel *c = pkt->close; + + /* FIXME: Don't accept tiny close fee! */ + if (!peer_create_close_tx(peer, c->close_fee)) + return pkt_err(ctx, "Invalid close fee"); + + if (!peer_sign_close_tx(peer, c->sig)) + return pkt_err(ctx, "Invalid signature"); + return NULL; } Pkt *accept_pkt_close_complete(const tal_t *ctx, struct peer *peer, const Pkt *pkt) { - FIXME_STUB(peer); + const CloseChannelComplete *c = pkt->close_complete; + if (!peer_sign_close_tx(peer, c->sig)) + return pkt_err(ctx, "Invalid signature"); + return NULL; } Pkt *accept_pkt_simultaneous_close(const tal_t *ctx, @@ -776,7 +819,8 @@ Pkt *accept_pkt_simultaneous_close(const tal_t *ctx, FIXME_STUB(peer); } +/* FIXME: Since this packet is empty, is it worth having? */ Pkt *accept_pkt_close_ack(const tal_t *ctx, struct peer *peer, const Pkt *pkt) { - FIXME_STUB(peer); + return NULL; } diff --git a/daemon/peer.c b/daemon/peer.c index cb94c6c1f..013c5814d 100644 --- a/daemon/peer.c +++ b/daemon/peer.c @@ -293,6 +293,9 @@ static void peer_disconnect(struct io_conn *conn, struct peer *peer) } /* FIXME: Try to reconnect. */ + if (peer->cond == PEER_CLOSING + || peer->cond == PEER_CLOSED) + return; state(peer, peer, CMD_CLOSE, NULL, &outpkt, &broadcast); /* Can't send packet, so ignore it. */ @@ -339,6 +342,7 @@ static struct peer *new_peer(struct lightningd_state *dstate, peer->num_htlcs = 0; peer->close_tx = NULL; peer->cstate = NULL; + peer->close_watch_timeout = NULL; /* If we free peer, conn should be closed, but can't be freed * immediately so don't make peer a parent. */ @@ -597,6 +601,38 @@ static bool txmatch(const struct bitcoin_tx *txa, const struct bitcoin_tx *txb) return true; } +static bool is_mutual_close(const struct bitcoin_tx *tx, + const struct bitcoin_tx *close_tx) +{ + varint_t i; + + /* Haven't created mutual close yet? This isn't one then. */ + if (!close_tx) + return false; + + /* We know it spends anchor, but do txouts match? */ + if (tx->output_count != close_tx->output_count) + return false; + for (i = 0; i < tx->output_count; i++) { + if (tx->output[i].amount != close_tx->output[i].amount) + return false; + if (tx->output[i].script_length + != close_tx->output[i].script_length) + return false; + if (memcmp(tx->output[i].script, close_tx->output[i].script, + tx->output[i].script_length) != 0) + return false; + } + return true; +} + +static void close_depth_cb(struct peer *peer, int depth) +{ + if (depth >= peer->dstate->config.forever_confirms) { + state_event(peer, BITCOIN_CLOSE_DONE, NULL); + } +} + /* We assume the tx is valid! Don't do a blockchain.info and feed this * invalid transactions! */ static void anchor_spent(struct peer *peer, @@ -609,6 +645,8 @@ static void anchor_spent(struct peer *peer, idata.btc = (struct bitcoin_event *)tx; if (txmatch(tx, peer->them.commit)) state_event(peer, w->theyspent, &idata); + else if (is_mutual_close(tx, peer->close_tx)) + add_close_tx_watch(peer, tx, close_depth_cb); else state_event(peer, w->otherspent, &idata); } @@ -656,29 +694,82 @@ void peer_watch_tx(struct peer *peer, FIXME_STUB(peer); } +bool peer_create_close_tx(struct peer *peer, u64 fee_satoshis) +{ + struct channel_state cstate; + + assert(!peer->close_tx); + + /* We don't need a deep copy here, just fee levels. */ + cstate = *peer->cstate; + if (!adjust_fee(peer->us.offer_anchor == CMD_OPEN_WITH_ANCHOR, + peer->anchor.satoshis, + fee_satoshis, + &cstate.a, &cstate.b)) + return false; + + log_debug(peer->log, + "creating close-tx: to %02x%02x%02x%02x/%02x%02x%02x%02x, amounts %u/%u", + peer->us.finalkey.der[0], peer->us.finalkey.der[1], + peer->us.finalkey.der[2], peer->us.finalkey.der[3], + peer->them.finalkey.der[0], peer->them.finalkey.der[1], + peer->them.finalkey.der[2], peer->them.finalkey.der[3], + cstate.a.pay_msat / 1000, + cstate.b.pay_msat / 1000); + + peer->close_tx = create_close_tx(peer->dstate->secpctx, peer, + &peer->us.finalkey, + &peer->them.finalkey, + &peer->anchor.txid, + peer->anchor.index, + peer->anchor.satoshis, + cstate.a.pay_msat / 1000, + cstate.b.pay_msat / 1000); + + peer->our_close_sig.stype = SIGHASH_ALL; + peer_sign_mutual_close(peer, peer->close_tx, &peer->our_close_sig.sig); + return true; +} + static void send_close_timeout(struct peer *peer) { + /* FIXME: Remove any close_tx watches! */ state_event(peer, INPUT_CLOSE_COMPLETE_TIMEOUT, NULL); } void peer_watch_close(struct peer *peer, enum state_input done, enum state_input timedout) { - /* We save some work by assuming this. */ - assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT); + /* We save some work by assuming these. */ + assert(done == BITCOIN_CLOSE_DONE); + + /* FIXME: Dynamic closing fee! */ + if (!peer->close_tx) + peer_create_close_tx(peer, peer->dstate->config.closing_fee); - /* FIXME: We didn't send CLOSE, so timeout immediately */ + /* FIXME: We can't send CLOSE, so timeout immediately */ if (!peer->conn) { - (void)send_close_timeout; - /* FIXME: oneshot_timeout(peer->dstate, peer, 0, send_close_timeout, peer); */ + assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT); + oneshot_timeout(peer->dstate, peer, 0, + send_close_timeout, peer); return; } - FIXME_STUB(peer); + /* Give them a reasonable time to respond. */ + /* FIXME: config? */ + if (timedout != INPUT_NONE) { + assert(timedout == INPUT_CLOSE_COMPLETE_TIMEOUT); + peer->close_watch_timeout + = oneshot_timeout(peer->dstate, peer, 120, + send_close_timeout, peer); + } + + /* anchor_spent will get called, we match against close_tx there. */ } void peer_unwatch_close_timeout(struct peer *peer, enum state_input timedout) { - FIXME_STUB(peer); + assert(peer->close_watch_timeout); + peer->close_watch_timeout = tal_free(peer->close_watch_timeout); } bool peer_watch_our_htlc_outputs(struct peer *peer, const struct bitcoin_tx *tx, @@ -767,36 +858,9 @@ bool committed_to_htlcs(const struct peer *peer) const struct bitcoin_tx *bitcoin_close(const tal_t *ctx, const struct peer *peer) { -#if 0 - struct bitcoin_tx *close_tx; - u8 *redeemscript; - - close_tx = create_close_tx(ctx, peer->us.openpkt, peer->them.openpkt, - peer->anchorpkt, - peer->cstate.a.pay_msat / 1000, - peer->cstate.b.pay_msat / 1000); - - /* This is what the anchor pays to. */ - redeemscript = bitcoin_redeem_2of2(close_tx, &peer->us.commitkey, - &peer->them.commitkey); - - /* Combined signatures must validate correctly. */ - if (!check_2of2_sig(close_tx, 0, redeemscript, tal_count(redeemscript), - &peer->us.finalkey, &peer->them.finalkey, - &peer->us.closesig, &peer->them.closesig)) - fatal("bitcoin_close signature failed"); - - /* Create p2sh input for close_tx */ - close_tx->input[0].script = scriptsig_p2sh_2of2(close_tx, - &peer->us.closesig, - &peer->them.closesig, - &peer->us.finalkey, - &peer->them.finalkey); - close_tx->input[0].script_length = tal_count(close_tx->input[0].script); - - return close_tx; -#endif - FIXME_STUB(peer); + /* Must be signed! */ + assert(peer->close_tx->input[0].script_length != 0); + return peer->close_tx; } /* Create a bitcoin spend tx (to spend our commit's outputs) */ @@ -1448,3 +1512,48 @@ const struct json_command failhtlc_command = { "Fail htlc proposed by {id} which has redeem hash {rhash}", "Returns an empty result on success" }; + +static void json_close(struct command *cmd, + const char *buffer, const jsmntok_t *params) +{ + struct peer *peer; + jsmntok_t *idtok; + struct pubkey id; + + json_get_params(buffer, params, + "id", &idtok, + NULL); + + if (!idtok) { + command_fail(cmd, "Need id"); + return; + } + + if (!pubkey_from_hexstr(cmd->dstate->secpctx, + buffer + idtok->start, + idtok->end - idtok->start, &id)) { + command_fail(cmd, "Not a valid id"); + return; + } + peer = find_peer(cmd->dstate, &id); + if (!peer) { + command_fail(cmd, "Could not find peer with that id"); + return; + } + if (peer->cond == PEER_CLOSING) { + command_fail(cmd, "Peer is already closing"); + return; + } + + /* Unlike other things, CMD_CLOSE is always valid. */ + log_debug(peer->log, "Sending CMD_CLOSE"); + state_event(peer, CMD_CLOSE, NULL); + command_success(cmd, null_response(cmd)); +} + +const struct json_command close_command = { + "close", + json_close, + "Close the channel with peer {id}", + "Returns an empty result on success" +}; diff --git a/daemon/peer.h b/daemon/peer.h index 904cd5708..c81414ef4 100644 --- a/daemon/peer.h +++ b/daemon/peer.h @@ -104,8 +104,9 @@ struct peer { /* Number of HTLC updates (== number of previous commit txs) */ u64 num_htlcs; - /* Closing tx, once we've generated it */ + /* Closing tx and signature once we've generated it */ struct bitcoin_tx *close_tx; + struct bitcoin_signature our_close_sig; /* Current ongoing packetflow */ struct io_data *io_data; @@ -116,6 +117,9 @@ struct peer { /* Things we're watching for (see watches.c) */ struct list_head watches; + /* Timeout for close_watch. */ + struct oneshot *close_watch_timeout; + /* Private keys for dealing with this peer. */ struct peer_secrets *secrets; @@ -135,4 +139,6 @@ void make_commit_txs(const tal_t *ctx, void peer_add_htlc_expiry(struct peer *peer, const struct abs_locktime *expiry); +bool peer_create_close_tx(struct peer *peer, u64 fee_satoshis); + #endif /* LIGHTNING_DAEMON_PEER_H */ diff --git a/daemon/test/test.sh b/daemon/test/test.sh index 66e574ae8..69aecf1c0 100755 --- a/daemon/test/test.sh +++ b/daemon/test/test.sh @@ -1,4 +1,4 @@ -#! /bin/sh -e +#! /bin/sh -ex # We steal the test-cli scripts. cd test-cli @@ -138,8 +138,33 @@ sleep 1 # Back to how we were before. check_status 949999000 49000000 "" 0 1000000 "" +$LCLI1 close $ID2 + +sleep 1 + +# They should be waiting for close. +$LCLI1 getpeers | tr -s '\012\011 ' ' ' | fgrep '"STATE_CLOSE_WAIT_CLOSE"' +$LCLI2 getpeers | tr -s '\012\011 ' ' ' | fgrep '"STATE_CLOSE_WAIT_CLOSE"' + +# Give it 99 blocks. +$CLI generate 99 + +# Make sure they saw it! +$LCLI1 dev-mocktime $(($EXPIRY + 32)) +$LCLI2 dev-mocktime $(($EXPIRY + 32)) +sleep 1 +$LCLI1 getpeers | tr -s '\012\011 ' ' ' | fgrep '"STATE_CLOSE_WAIT_CLOSE"' +$LCLI2 getpeers | tr -s '\012\011 ' ' ' | fgrep '"STATE_CLOSE_WAIT_CLOSE"' + +# Now the final one. +$CLI generate 1 +$LCLI1 dev-mocktime $(($EXPIRY + 33)) +$LCLI2 dev-mocktime $(($EXPIRY + 33)) sleep 1 +$LCLI1 getpeers | tr -s '\012\011 ' ' ' | fgrep '"peers" : [ ]' +$LCLI2 getpeers | tr -s '\012\011 ' ' ' | fgrep '"peers" : [ ]' + $LCLI1 stop $LCLI2 stop scripts/shutdown.sh diff --git a/daemon/watch.c b/daemon/watch.c index dc56467cc..7bdc30912 100644 --- a/daemon/watch.c +++ b/daemon/watch.c @@ -167,6 +167,24 @@ void add_commit_tx_watch_(struct peer *peer, * watch anything else. */ } +static void cb_no_arg(struct peer *peer, int depth, void *vcb) +{ + void (*cb)(struct peer *peer, int depth) = vcb; + cb(peer, depth); +} + +void add_close_tx_watch(struct peer *peer, + const struct bitcoin_tx *tx, + void (*cb)(struct peer *peer, int depth)) +{ + struct sha256_double txid; + bitcoin_txid(tx, &txid); + insert_txwatch(peer, peer->dstate, peer, &txid, cb_no_arg, cb); + + /* We are already watching the anchor txo, so we don't need to + * watch anything else. */ +} + static void tx_watched_inputs(struct lightningd_state *dstate, const struct bitcoin_tx *tx, void *unused) { diff --git a/daemon/watch.h b/daemon/watch.h index d7ed44daa..d616480d0 100644 --- a/daemon/watch.h +++ b/daemon/watch.h @@ -94,5 +94,9 @@ void add_commit_tx_watch_(struct peer *peer, int depth), \ (cbdata)) +void add_close_tx_watch(struct peer *peer, + const struct bitcoin_tx *tx, + void (*cb)(struct peer *peer, int depth)); + void setup_watch_timer(struct lightningd_state *dstate); #endif /* LIGHTNING_DAEMON_WATCH_H */