From 6b61e9ab0aceb18b37c38b94ae3a0232ec772161 Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Tue, 20 Jun 2017 15:41:03 +0930 Subject: [PATCH] channeld: exchange channel_reestablish. Signed-off-by: Rusty Russell --- lightningd/channel/channel.c | 336 +++++++++++++++++++++++++--- lightningd/channel/channel_wire.csv | 4 + lightningd/peer_control.c | 58 +++-- lightningd/peer_control.h | 2 + tests/test_lightningd.py | 13 +- 5 files changed, 362 insertions(+), 51 deletions(-) diff --git a/lightningd/channel/channel.c b/lightningd/channel/channel.c index 1a58dd33a..e97bf78ca 100644 --- a/lightningd/channel/channel.c +++ b/lightningd/channel/channel.c @@ -3,6 +3,7 @@ #include #include #include +#include #include #include #include @@ -36,7 +37,7 @@ #include #include #include -#include +#include #include #include #include @@ -120,6 +121,11 @@ struct peer { /* We save calculated commit sigs while waiting for master approval */ struct commit_sigs *next_commit_sigs; + + /* Information used for reestablishment. */ + bool last_was_revoke; + struct changed_htlc *last_sent_commit; + u64 revocations_received; }; static u8 *create_channel_announcement(const tal_t *ctx, struct peer *peer); @@ -287,6 +293,14 @@ static struct io_plan *handle_peer_funding_locked(struct io_conn *conn, { struct channel_id chanid; + /* BOLT #2: + * + * On reconnection, a node MUST ignore a redundant `funding_locked` if + * it receives one. + */ + if (peer->funding_locked[REMOTE]) + return peer_read_message(conn, &peer->pcs, peer_in); + peer->old_remote_per_commit = peer->remote_per_commit; if (!fromwire_funding_locked(msg, NULL, &chanid, &peer->remote_per_commit)) @@ -296,9 +310,6 @@ static struct io_plan *handle_peer_funding_locked(struct io_conn *conn, if (!structeq(&chanid, &peer->channel_id)) status_failed(WIRE_CHANNEL_PEER_BAD_MESSAGE, "Wrong channel id in %s", tal_hex(trc, msg)); - if (peer->funding_locked[REMOTE]) - status_failed(WIRE_CHANNEL_PEER_BAD_MESSAGE, - "Funding locked twice"); peer->funding_locked[REMOTE] = true; daemon_conn_send(&peer->master, @@ -450,7 +461,8 @@ static void master_sync_reply(struct peer *peer, const u8 *msg, } static struct commit_sigs *calc_commitsigs(const tal_t *ctx, - const struct peer *peer) + const struct peer *peer, + u64 commit_index) { const tal_t *tmpctx = tal_tmpctx(ctx); size_t i; @@ -483,7 +495,7 @@ static struct commit_sigs *calc_commitsigs(const tal_t *ctx, txs = channel_txs(tmpctx, &htlc_map, &wscripts, peer->channel, &peer->remote_per_commit, - peer->commit_index[REMOTE], + commit_index, REMOTE); sign_tx_input(txs[0], 0, NULL, @@ -493,7 +505,7 @@ static struct commit_sigs *calc_commitsigs(const tal_t *ctx, &commit_sigs->commit_sig); status_trace("Creating commit_sig signature %"PRIu64" %s for tx %s wscript %s key %s", - peer->commit_index[REMOTE], + commit_index, type_to_string(trc, secp256k1_ecdsa_signature, &commit_sigs->commit_sig), type_to_string(trc, struct bitcoin_tx, txs[0]), @@ -564,7 +576,8 @@ static void send_commit(struct peer *peer) return; } - peer->next_commit_sigs = calc_commitsigs(peer, peer); + peer->next_commit_sigs = calc_commitsigs(peer, peer, + peer->commit_index[REMOTE]); status_trace("Telling master we're about to commit..."); /* Tell master to save this next commit to database, then wait. */ @@ -591,24 +604,24 @@ static void start_commit_timer(struct peer *peer) send_commit, peer); } -/* We come back here once master has acked the commit_sig we received */ -static struct io_plan *send_revocation(struct io_conn *conn, struct peer *peer) +static u8 *make_revocation_msg(const struct peer *peer, u64 commit_index) { struct pubkey oldpoint, point; struct sha256 old_commit_secret; - u8 *msg; /* Get N-1th secret. */ - per_commit_secret(&peer->shaseed, &old_commit_secret, - peer->commit_index[LOCAL] - 1); + per_commit_secret(&peer->shaseed, &old_commit_secret, commit_index-1); /* Sanity check that it corresponds to the point we sent. */ pubkey_from_privkey((struct privkey *)&old_commit_secret, &point); - if (!per_commit_point(&peer->shaseed, &oldpoint, - peer->commit_index[LOCAL]-1)) + if (!per_commit_point(&peer->shaseed, &oldpoint, commit_index-1)) status_failed(WIRE_CHANNEL_CRYPTO_FAILED, "Invalid point %"PRIu64" for commit_point", - peer->commit_index[LOCAL]-1); + commit_index-1); + + status_trace("Sending revocation #%"PRIu64" for %s", + commit_index-1, + type_to_string(trc, struct pubkey, &oldpoint)); if (!pubkey_eq(&point, &oldpoint)) status_failed(WIRE_CHANNEL_CRYPTO_FAILED, @@ -617,19 +630,28 @@ static struct io_plan *send_revocation(struct io_conn *conn, struct peer *peer) sizeof(old_commit_secret))); /* Send N+1th point. */ - if (!per_commit_point(&peer->shaseed, &point, - ++peer->commit_index[LOCAL])) + if (!per_commit_point(&peer->shaseed, &point, commit_index+1)) status_failed(WIRE_CHANNEL_CRYPTO_FAILED, "Deriving next commit_point"); + return towire_revoke_and_ack(peer, &peer->channel_id, &old_commit_secret, + &point); +} + +/* We come back here once master has acked the commit_sig we received */ +static struct io_plan *send_revocation(struct io_conn *conn, struct peer *peer) +{ + u8 *msg = make_revocation_msg(peer, peer->commit_index[LOCAL]); + + /* From now on we apply to the next commitment */ + peer->commit_index[LOCAL]++; + /* If this queues more changes on the other end, send commit. */ if (channel_sending_revoke_and_ack(peer->channel)) { status_trace("revoke_and_ack made pending: commit timer"); start_commit_timer(peer); } - msg = towire_revoke_and_ack(peer, &peer->channel_id, &old_commit_secret, - &point); msg_enqueue(&peer->peer_out, take(msg)); return peer_read_message(conn, &peer->pcs, peer_in); @@ -940,8 +962,9 @@ static struct io_plan *handle_peer_revoke_and_ack(struct io_conn *conn, &peer->pcs.cs, &peer->channel_id, WIRE_CHANNEL_PEER_BAD_MESSAGE, - "Wrong privkey %s for %s", + "Wrong privkey %s for %"PRIu64" %s", type_to_string(msg, struct privkey, &privkey), + peer->commit_index[LOCAL]-2, type_to_string(msg, struct pubkey, &peer->old_remote_per_commit)); } @@ -964,6 +987,12 @@ static struct io_plan *handle_peer_revoke_and_ack(struct io_conn *conn, peer->commit_index[REMOTE]++; peer->old_remote_per_commit = peer->remote_per_commit; peer->remote_per_commit = next_per_commit; + status_trace("revoke_and_ack %s: remote_per_commit = %s, old_remote_per_commit = %s", + side_to_str(peer->channel->funder), + type_to_string(trc, struct pubkey, + &peer->remote_per_commit), + type_to_string(trc, struct pubkey, + &peer->old_remote_per_commit)); /* And peer waits for reply. */ return io_wait(conn, peer, accepted_revocation, peer); @@ -1267,6 +1296,244 @@ static void peer_conn_broken(struct io_conn *conn, struct peer *peer) "peer connection broken: %s", strerror(errno)); } +static void resend_revoke(struct peer *peer) +{ + u8 *msg = make_revocation_msg(peer, peer->commit_index[LOCAL]-1); + msg_enqueue(&peer->peer_out, take(msg)); +} + +static void resend_commitment(struct peer *peer, const struct changed_htlc *last) +{ + size_t i; + struct commit_sigs *commit_sigs; + u8 *msg; + + /* BOLT #2: + * + * If `commitments_received` is one less than the commitment number of + * the last `commitment_signed` message the receiving node has sent, + * it MUST reuse the same commitment number for its next + * `commitment_signed` + */ + /* In our case, we consider ourselves already committed to this, so + * retransmission is simplest. */ + for (i = 0; i < tal_count(last); i++) { + const struct htlc *h; + + h = channel_get_htlc(peer->channel, + htlc_state_owner(last[i].newstate), + last[i].id); + + /* I think this can happen if we actually received revoke_and_ack + * then they asked for a retransmit */ + if (!h) + peer_failed(io_conn_fd(peer->peer_conn), + &peer->pcs.cs, + &peer->channel_id, + WIRE_CHANNEL_PEER_BAD_MESSAGE, + "Can't find HTLC %"PRIu64" to resend", + last[i].id); + + if (h->state == SENT_ADD_COMMIT) { + u8 *msg = towire_update_add_htlc(peer, &peer->channel_id, + h->id, h->msatoshi, + &h->rhash, + abs_locktime_to_blocks( + &h->expiry), + h->routing); + msg_enqueue(&peer->peer_out, take(msg)); + } else if (h->state == SENT_REMOVE_COMMIT) { + u8 *msg; + if (h->malformed) { + struct sha256 sha256_of_onion; + sha256(&sha256_of_onion, h->routing, + tal_len(h->routing)); + + msg = towire_update_fail_malformed_htlc + (peer, &peer->channel_id, h->id, + &sha256_of_onion, h->malformed); + } else if (h->fail) { + msg = towire_update_fail_htlc + (peer, &peer->channel_id, h->id, + h->fail); + } else if (h->r) { + msg = towire_update_fulfill_htlc + (peer, &peer->channel_id, h->id, + h->r); + } else + peer_failed(io_conn_fd(peer->peer_conn), + &peer->pcs.cs, + &peer->channel_id, + WIRE_CHANNEL_PEER_BAD_MESSAGE, + "HTLC %"PRIu64" state %s not failed/fulfilled", + h->id, htlc_state_name(h->state)); + msg_enqueue(&peer->peer_out, take(msg)); + } + } + + /* Re-send the commitment_signed itself. */ + commit_sigs = calc_commitsigs(peer, peer, peer->commit_index[REMOTE]-1); + msg = towire_commitment_signed(peer, &peer->channel_id, + &commit_sigs->commit_sig, + commit_sigs->htlc_sigs); + msg_enqueue(&peer->peer_out, take(msg)); + tal_free(commit_sigs); +} + +static struct io_plan *handle_peer_reestablish(struct io_conn *conn, + struct peer *peer, + u8 *msg) +{ + struct channel_id channel_id; + u64 last_commitidx_sent, last_revokeidx_sent; + u64 commitments_received, revocations_received; + bool retransmit_revoke_and_ack; + + if (gossip_msg(msg)) { + /* Forward to gossip daemon */ + daemon_conn_send(&peer->gossip_client, msg); + return peer_read_message(conn, &peer->pcs, + handle_peer_reestablish); + } + + if (!fromwire_channel_reestablish(msg, NULL, &channel_id, + &commitments_received, + &revocations_received)) { + status_failed(WIRE_CHANNEL_PEER_READ_FAILED, + "bad reestablish msg: %s %s", + wire_type_name(fromwire_peektype(msg)), + tal_hex(msg, msg)); + } + + /* BOLT #2: + * + * On reconnection, a node MUST retransmit `funding_locked` unless it + * has received an `update_` or `revoke_and_ack` for that channel, + * otherwise it MAY retransmit `funding_locked`. + */ + if (peer->funding_locked[LOCAL]) { + u8 *msg; + struct pubkey next_per_commit_point; + + /* Contains per commit point #1, for first post-opening commit */ + per_commit_point(&peer->shaseed, &next_per_commit_point, 1); + msg = towire_funding_locked(peer, + &peer->channel_id, + &next_per_commit_point); + msg_enqueue(&peer->peer_out, take(msg)); + } + + /* If we're working on commit #1 now, we sent #0. */ + last_commitidx_sent = peer->commit_index[REMOTE] - 1; + assert(peer->commit_index[REMOTE] > 0); + + /* Can be -1, but in that case nothing to re-transmit. */ + last_revokeidx_sent = peer->commit_index[LOCAL] - 2; + assert(peer->commit_index[LOCAL] > 0); + + /* BOLT #2: + * + * If `revocations_received` is equal to the commitment number of the + * last `revoke_and_ack` the receiving node has sent, it MUST re-send + * the final `revoke_and_ack`, otherwise if `revocations_received` is + * not equal to one greater than the commitment number of the last + * `revoke_and_ack`, the receiving node has sent, it SHOULD fail the + * channel. + */ + /* If we're working on commit #2 now, we've send a revocation for commit + * #0, but beware commit #1 case, where no revoke has been sent! */ + if (revocations_received == last_revokeidx_sent) { + if (last_revokeidx_sent == (u64)-1) { + status_failed(WIRE_CHANNEL_PEER_READ_FAILED, + "bad reestablish revocations_received: %" + PRIu64, + revocations_received); + } + retransmit_revoke_and_ack = true; + } else if (revocations_received != last_revokeidx_sent + 1) { + status_failed(WIRE_CHANNEL_PEER_READ_FAILED, + "bad reestablish revocations_received: %"PRIu64 + " vs %"PRIu64, + revocations_received, last_revokeidx_sent); + } else + retransmit_revoke_and_ack = false; + + /* We have to re-send in the same order we sent originally: + * revoke_and_ack (usually) alters our next commitment. */ + if (retransmit_revoke_and_ack && !peer->last_was_revoke) + resend_revoke(peer); + + /* BOLT #2: + * + * If `commitments_received` is one less than the commitment number of + * the last `commitment_signed` message the receiving node has sent, + * it MUST reuse the same commitment number for its next + * `commitment_signed`, otherwise if `commitments_received` is not + * equal to the commitment number of the last `commitment_signed` + * message the receiving node has sent, it SHOULD fail the channel. + */ + if (commitments_received == last_commitidx_sent - 1) { + /* We completed opening, we don't re-transmit that one! */ + if (last_commitidx_sent == 0) + status_failed(WIRE_CHANNEL_PEER_READ_FAILED, + "bad reestablish commitments_received: %" + PRIu64, + commitments_received); + + resend_commitment(peer, peer->last_sent_commit); + } else if (commitments_received != last_commitidx_sent) + peer_failed(io_conn_fd(conn), + &peer->pcs.cs, + &peer->channel_id, + WIRE_CHANNEL_PEER_BAD_MESSAGE, + "Peer sent invalid commitments_received %"PRIu64 + " vs %"PRIu64, + commitments_received, last_commitidx_sent); + + /* This covers the case where we sent revoke after commit. */ + if (retransmit_revoke_and_ack && peer->last_was_revoke) + resend_revoke(peer); + + /* Start commit timer: if we sent revoke we might need it. */ + start_commit_timer(peer); + + /* Now into normal mode. */ + return setup_peer_conn(conn, peer); +} + + +static struct io_plan *peer_read_reestablish(struct io_conn *conn, + struct peer *peer) +{ + return peer_read_message(conn, &peer->pcs, handle_peer_reestablish); +} + +static struct io_plan *peer_write_reestablish(struct io_conn *conn, + struct peer *peer) +{ + u8 *msg; + + /* BOLT #2: + * + * On reconnection, a node MUST transmit `channel_reestablish` for + * each channel, and MUST wait for to receive the other node's + * `channel_reestablish` message before sending any other messages for + * that channel. + * + * The sending node MUST set `commitments_received` to the commitment + * number of the last `commitment_signed` it received, and MUST set + * `revocations_received` to one greater than the commitment number of + * the last `revoke_and_ack` message received, or 0 if none have been + * received. + */ + /* Note: if we're working on commit #7, we've seen commitsig for #6 */ + msg = towire_channel_reestablish(peer, &peer->channel_id, + peer->commit_index[LOCAL] - 1, + peer->revocations_received); + return peer_write_message(conn, &peer->pcs, take(msg), + peer_read_reestablish); +} + /* We do this synchronously. */ static void init_channel(struct peer *peer) { @@ -1274,23 +1541,23 @@ static void init_channel(struct peer *peer) struct basepoints points[NUM_SIDES]; u64 funding_satoshi; u16 funding_txout; - u64 commits_sent, commits_received, revocations_received; + u64 commits_sent, commits_received; u64 local_msatoshi; struct pubkey funding_pubkey[NUM_SIDES]; struct sha256_double funding_txid; - bool am_funder, last_was_revoke; + bool am_funder; enum htlc_state *hstates; struct fulfilled_htlc *fulfilled; enum side *fulfilled_sides; struct failed_htlc *failed; enum side *failed_sides; - struct changed_htlc *last_sent_commit; struct added_htlc *htlcs; + bool reconnected; u8 *funding_signed; u8 *msg; msg = wire_sync_read(peer, REQ_FD); - if (!fromwire_channel_init(msg, msg, NULL, + if (!fromwire_channel_init(peer, msg, NULL, &funding_txid, &funding_txout, &funding_satoshi, &peer->conf[LOCAL], &peer->conf[REMOTE], @@ -1310,11 +1577,11 @@ static void init_channel(struct peer *peer) &peer->node_ids[REMOTE], &peer->commit_msec, &peer->cltv_delta, - &last_was_revoke, - &last_sent_commit, + &peer->last_was_revoke, + &peer->last_sent_commit, &commits_sent, &commits_received, - &revocations_received, + &peer->revocations_received, &peer->htlc_id, &htlcs, &hstates, @@ -1322,6 +1589,10 @@ static void init_channel(struct peer *peer) &fulfilled_sides, &failed, &failed_sides, + &peer->funding_locked[LOCAL], + &peer->funding_locked[REMOTE], + &peer->short_channel_ids[LOCAL], + &reconnected, &funding_signed)) status_failed(WIRE_CHANNEL_BAD_COMMAND, "Init: %s", tal_hex(msg, msg)); @@ -1330,6 +1601,7 @@ static void init_channel(struct peer *peer) assert(commits_sent > 0); assert(commits_received > 0); + /* If we've sent 1, we're on index 1. */ peer->commit_index[LOCAL] = commits_sent; peer->commit_index[REMOTE] = commits_received; @@ -1360,7 +1632,13 @@ static void init_channel(struct peer *peer) &peer->node_ids[LOCAL], &peer->node_ids[REMOTE]); /* OK, now we can process peer messages. */ - peer->peer_conn = io_new_conn(peer, PEER_FD, setup_peer_conn, peer); + if (reconnected) { + peer->peer_conn = io_new_conn(peer, PEER_FD, + peer_write_reestablish, peer); + } else { + peer->peer_conn = io_new_conn(peer, PEER_FD, setup_peer_conn, + peer); + } io_set_finish(peer->peer_conn, peer_conn_broken, peer); /* If we have a funding_signed message, we send that immediately */ diff --git a/lightningd/channel/channel_wire.csv b/lightningd/channel/channel_wire.csv index 3bf0b03db..a9bb99e9b 100644 --- a/lightningd/channel/channel_wire.csv +++ b/lightningd/channel/channel_wire.csv @@ -56,6 +56,10 @@ channel_init,,fulfilled_sides,num_fulfilled*enum side channel_init,,num_failed,u16 channel_init,,failed,num_failed*struct failed_htlc channel_init,,failed_sides,num_failed*enum side +channel_init,,local_funding_locked,bool +channel_init,,remote_funding_locked,bool +channel_init,,funding_short_id,struct short_channel_id +channel_init,,reestablish,bool channel_init,,init_peer_pkt_len,u16 channel_init,,init_peer_pkt,init_peer_pkt_len*u8 diff --git a/lightningd/peer_control.c b/lightningd/peer_control.c index 3725a9f35..cddb2ffc5 100644 --- a/lightningd/peer_control.c +++ b/lightningd/peer_control.c @@ -101,11 +101,6 @@ void peer_fail(struct peer *peer, const char *fmt, ...) goto dont_talk; } - /* FIXME: Implement reconnect here! */ - if (peer->state == CHANNELD_NORMAL) { - fatal("Peer fail in CHANNELD_NORMAL"); - } - /* Reconnect unless we've dropped to chain. */ if (!peer_on_chain(peer)) { peer_reconnect(peer); @@ -155,6 +150,9 @@ static bool peer_reconnected(struct lightningd *ld, tal_free(peer->cs); peer->cs = tal_dup(peer, struct crypto_state, cs); + /* We need this for init */ + peer->reconnected = true; + /* FIXME: We should close peer->gossip_client_fd when we're not * connected, and get a new one from gossipd when we reconnect. */ @@ -289,6 +287,7 @@ void add_peer(struct lightningd *ld, u64 unique_id, peer->scid = NULL; peer->id = *id; peer->fd = fd; + peer->reconnected = false; peer->gossip_client_fd = -1; peer->cs = tal_dup(peer, struct crypto_state, cs); peer->funding_txid = NULL; @@ -686,6 +685,7 @@ static enum watch_result funding_lockin_cb(struct peer *peer, { const char *txidstr = type_to_string(peer, struct sha256_double, txid); struct txlocator *loc; + bool peer_ready; log_debug(peer->log, "Funding tx %s depth %u of %u", txidstr, depth, peer->minimum_depth); @@ -694,16 +694,6 @@ static enum watch_result funding_lockin_cb(struct peer *peer, if (depth < peer->minimum_depth) return KEEP_WATCHING; - /* In theory, it could have been buried before we got back - * from accepting openingd or disconnected: just wait for next one. */ - if (!peer->owner || peer->state != CHANNELD_AWAITING_LOCKIN) { - log_unusual(peer->log, - "Funding tx confirmed, but peer state %s %s", - peer_state_name(peer->state), - peer->owner ? peer->owner->name : "unowned"); - return KEEP_WATCHING; - } - loc = locate_tx(peer, peer->ld->topology, txid); peer->scid = tal(peer, struct short_channel_id); @@ -712,8 +702,19 @@ static enum watch_result funding_lockin_cb(struct peer *peer, peer->scid->outnum = peer->funding_outnum; tal_free(loc); - subd_send_msg(peer->owner, - take(towire_channel_funding_locked(peer, peer->scid))); + /* In theory, it could have been buried before we got back + * from accepting openingd or disconnected: just wait for next one. */ + peer_ready = (peer->owner && peer->state == CHANNELD_AWAITING_LOCKIN); + if (!peer_ready) { + log_unusual(peer->log, + "Funding tx confirmed, but peer state %s %s", + peer_state_name(peer->state), + peer->owner ? peer->owner->name : "unowned"); + } else { + subd_send_msg(peer->owner, + take(towire_channel_funding_locked(peer, + peer->scid))); + } /* BOLT #7: * @@ -721,10 +722,11 @@ static enum watch_result funding_lockin_cb(struct peer *peer, * `funding_locked` has been sent, and the funding transaction is has * at least 6 confirmations. */ - if (depth >= ANNOUNCE_MIN_DEPTH) { + if (depth >= ANNOUNCE_MIN_DEPTH && peer_ready) { subd_send_msg(peer->owner, take(towire_channel_funding_announce_depth(peer))); } else { + /* Worst case, we'll send next block. */ watch_txid(peer, peer->ld->topology, peer, txid, funding_announce_cb, NULL); } @@ -862,6 +864,7 @@ static int peer_got_funding_locked(struct peer *peer, const u8 *msg) = tal_free(peer->next_per_commitment_point); peer->next_per_commitment_point = tal_dup(peer, struct pubkey, &next_per_commitment_point); + log_debug(peer->log, "Got funding_locked"); return 0; } @@ -928,6 +931,7 @@ static bool peer_start_channeld_hsmfd(struct subd *hsm, const u8 *resp, enum side *fulfilled_sides; struct failed_htlc *failed_htlcs; enum side *failed_sides; + struct short_channel_id funding_channel_id; peer->owner = new_subd(peer->ld, peer->ld, "lightningd_channel", peer, @@ -944,12 +948,20 @@ static bool peer_start_channeld_hsmfd(struct subd *hsm, const u8 *resp, return true; } - log_debug(peer->log, "Waiting for funding confirmations"); - peer_set_condition(peer, GETTING_HSMFD, CHANNELD_AWAITING_LOCKIN); - peer_htlcs(resp, peer, &htlcs, &htlc_states, &fulfilled_htlcs, &fulfilled_sides, &failed_htlcs, &failed_sides); + if (peer->scid) { + funding_channel_id = *peer->scid; + log_debug(peer->log, "Got funding confirmations"); + peer_set_condition(peer, GETTING_HSMFD, CHANNELD_NORMAL); + } else { + log_debug(peer->log, "Waiting for funding confirmations"); + peer_set_condition(peer, GETTING_HSMFD, + CHANNELD_AWAITING_LOCKIN); + memset(&funding_channel_id, 0, sizeof(funding_channel_id)); + } + initmsg = towire_channel_init(peer, peer->funding_txid, peer->funding_outnum, @@ -981,6 +993,10 @@ static bool peer_start_channeld_hsmfd(struct subd *hsm, const u8 *resp, htlcs, htlc_states, fulfilled_htlcs, fulfilled_sides, failed_htlcs, failed_sides, + peer->scid != NULL, + peer->next_per_commitment_point != NULL, + &funding_channel_id, + peer->reconnected, peer->funding_signed); /* Don't need this any more (we never re-transmit it) */ diff --git a/lightningd/peer_control.h b/lightningd/peer_control.h index 72133044a..d68aa25b8 100644 --- a/lightningd/peer_control.h +++ b/lightningd/peer_control.h @@ -45,6 +45,8 @@ struct peer { /* Our fd to the peer (-1 when we don't have it). */ int fd; + /* If we've disconnected, this is set. */ + bool reconnected; /* Crypto state (NULL if it's in daemon) */ struct crypto_state *cs; diff --git a/tests/test_lightningd.py b/tests/test_lightningd.py index 8d44dfa93..9ba52ef74 100644 --- a/tests/test_lightningd.py +++ b/tests/test_lightningd.py @@ -526,7 +526,7 @@ class LightningDTests(BaseLightningDTests): assert l1.rpc.getpeer(l2.info['id']) == None assert l2.rpc.getpeer(l1.info['id'])['peerid'] == l1.info['id'] - def test_reconnect(self): + def test_reconnect_signed(self): # This will fail *after* both sides consider channel opening. disconnects = ['+WIRE_FUNDING_SIGNED'] l1 = self.node_factory.get_node(legacy=False) @@ -557,6 +557,17 @@ class LightningDTests(BaseLightningDTests): l1.daemon.wait_for_log('-> CHANNELD_NORMAL') l2.daemon.wait_for_log('-> CHANNELD_NORMAL') + def test_reconnect_normal(self): + # Should reconnect fine even if locked message gets lost. + disconnects = ['-WIRE_FUNDING_LOCKED', + '@WIRE_FUNDING_LOCKED', + '+WIRE_FUNDING_LOCKED'] + l1 = self.node_factory.get_node(legacy=False, disconnect=disconnects) + l2 = self.node_factory.get_node(legacy=False) + ret = l1.rpc.connect('localhost', l2.info['port'], l2.info['id']) + + self.fund_channel(l1, l2, 10**6) + def test_json_addfunds(self): """ Attempt to add funds """