channeld: exchange channel_reestablish.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
b600e6118c
commit
6b61e9ab0a
|
@ -3,6 +3,7 @@
|
||||||
#include <ccan/cast/cast.h>
|
#include <ccan/cast/cast.h>
|
||||||
#include <ccan/container_of/container_of.h>
|
#include <ccan/container_of/container_of.h>
|
||||||
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
#include <ccan/crypto/hkdf_sha256/hkdf_sha256.h>
|
||||||
|
#include <ccan/crypto/shachain/shachain.h>
|
||||||
#include <ccan/fdpass/fdpass.h>
|
#include <ccan/fdpass/fdpass.h>
|
||||||
#include <ccan/io/io.h>
|
#include <ccan/io/io.h>
|
||||||
#include <ccan/mem/mem.h>
|
#include <ccan/mem/mem.h>
|
||||||
|
@ -36,7 +37,7 @@
|
||||||
#include <type_to_string.h>
|
#include <type_to_string.h>
|
||||||
#include <version.h>
|
#include <version.h>
|
||||||
#include <wire/gen_onion_wire.h>
|
#include <wire/gen_onion_wire.h>
|
||||||
#include <wire/gen_peer_wire.h>
|
#include <wire/peer_wire.h>
|
||||||
#include <wire/wire.h>
|
#include <wire/wire.h>
|
||||||
#include <wire/wire_io.h>
|
#include <wire/wire_io.h>
|
||||||
#include <wire/wire_sync.h>
|
#include <wire/wire_sync.h>
|
||||||
|
@ -120,6 +121,11 @@ struct peer {
|
||||||
|
|
||||||
/* We save calculated commit sigs while waiting for master approval */
|
/* We save calculated commit sigs while waiting for master approval */
|
||||||
struct commit_sigs *next_commit_sigs;
|
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);
|
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;
|
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;
|
peer->old_remote_per_commit = peer->remote_per_commit;
|
||||||
if (!fromwire_funding_locked(msg, NULL, &chanid,
|
if (!fromwire_funding_locked(msg, NULL, &chanid,
|
||||||
&peer->remote_per_commit))
|
&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))
|
if (!structeq(&chanid, &peer->channel_id))
|
||||||
status_failed(WIRE_CHANNEL_PEER_BAD_MESSAGE,
|
status_failed(WIRE_CHANNEL_PEER_BAD_MESSAGE,
|
||||||
"Wrong channel id in %s", tal_hex(trc, msg));
|
"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;
|
peer->funding_locked[REMOTE] = true;
|
||||||
daemon_conn_send(&peer->master,
|
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,
|
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);
|
const tal_t *tmpctx = tal_tmpctx(ctx);
|
||||||
size_t i;
|
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,
|
txs = channel_txs(tmpctx, &htlc_map, &wscripts, peer->channel,
|
||||||
&peer->remote_per_commit,
|
&peer->remote_per_commit,
|
||||||
peer->commit_index[REMOTE],
|
commit_index,
|
||||||
REMOTE);
|
REMOTE);
|
||||||
|
|
||||||
sign_tx_input(txs[0], 0, NULL,
|
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);
|
&commit_sigs->commit_sig);
|
||||||
|
|
||||||
status_trace("Creating commit_sig signature %"PRIu64" %s for tx %s wscript %s key %s",
|
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,
|
type_to_string(trc, secp256k1_ecdsa_signature,
|
||||||
&commit_sigs->commit_sig),
|
&commit_sigs->commit_sig),
|
||||||
type_to_string(trc, struct bitcoin_tx, txs[0]),
|
type_to_string(trc, struct bitcoin_tx, txs[0]),
|
||||||
|
@ -564,7 +576,8 @@ static void send_commit(struct peer *peer)
|
||||||
return;
|
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...");
|
status_trace("Telling master we're about to commit...");
|
||||||
/* Tell master to save this next commit to database, then wait. */
|
/* 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);
|
send_commit, peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* We come back here once master has acked the commit_sig we received */
|
static u8 *make_revocation_msg(const struct peer *peer, u64 commit_index)
|
||||||
static struct io_plan *send_revocation(struct io_conn *conn, struct peer *peer)
|
|
||||||
{
|
{
|
||||||
struct pubkey oldpoint, point;
|
struct pubkey oldpoint, point;
|
||||||
struct sha256 old_commit_secret;
|
struct sha256 old_commit_secret;
|
||||||
u8 *msg;
|
|
||||||
|
|
||||||
/* Get N-1th secret. */
|
/* Get N-1th secret. */
|
||||||
per_commit_secret(&peer->shaseed, &old_commit_secret,
|
per_commit_secret(&peer->shaseed, &old_commit_secret, commit_index-1);
|
||||||
peer->commit_index[LOCAL] - 1);
|
|
||||||
|
|
||||||
/* Sanity check that it corresponds to the point we sent. */
|
/* Sanity check that it corresponds to the point we sent. */
|
||||||
pubkey_from_privkey((struct privkey *)&old_commit_secret, &point);
|
pubkey_from_privkey((struct privkey *)&old_commit_secret, &point);
|
||||||
if (!per_commit_point(&peer->shaseed, &oldpoint,
|
if (!per_commit_point(&peer->shaseed, &oldpoint, commit_index-1))
|
||||||
peer->commit_index[LOCAL]-1))
|
|
||||||
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
|
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
|
||||||
"Invalid point %"PRIu64" for commit_point",
|
"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))
|
if (!pubkey_eq(&point, &oldpoint))
|
||||||
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
|
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)));
|
sizeof(old_commit_secret)));
|
||||||
|
|
||||||
/* Send N+1th point. */
|
/* Send N+1th point. */
|
||||||
if (!per_commit_point(&peer->shaseed, &point,
|
if (!per_commit_point(&peer->shaseed, &point, commit_index+1))
|
||||||
++peer->commit_index[LOCAL]))
|
|
||||||
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
|
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
|
||||||
"Deriving next commit_point");
|
"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 this queues more changes on the other end, send commit. */
|
||||||
if (channel_sending_revoke_and_ack(peer->channel)) {
|
if (channel_sending_revoke_and_ack(peer->channel)) {
|
||||||
status_trace("revoke_and_ack made pending: commit timer");
|
status_trace("revoke_and_ack made pending: commit timer");
|
||||||
start_commit_timer(peer);
|
start_commit_timer(peer);
|
||||||
}
|
}
|
||||||
|
|
||||||
msg = towire_revoke_and_ack(peer, &peer->channel_id, &old_commit_secret,
|
|
||||||
&point);
|
|
||||||
msg_enqueue(&peer->peer_out, take(msg));
|
msg_enqueue(&peer->peer_out, take(msg));
|
||||||
|
|
||||||
return peer_read_message(conn, &peer->pcs, peer_in);
|
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->pcs.cs,
|
||||||
&peer->channel_id,
|
&peer->channel_id,
|
||||||
WIRE_CHANNEL_PEER_BAD_MESSAGE,
|
WIRE_CHANNEL_PEER_BAD_MESSAGE,
|
||||||
"Wrong privkey %s for %s",
|
"Wrong privkey %s for %"PRIu64" %s",
|
||||||
type_to_string(msg, struct privkey, &privkey),
|
type_to_string(msg, struct privkey, &privkey),
|
||||||
|
peer->commit_index[LOCAL]-2,
|
||||||
type_to_string(msg, struct pubkey,
|
type_to_string(msg, struct pubkey,
|
||||||
&peer->old_remote_per_commit));
|
&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->commit_index[REMOTE]++;
|
||||||
peer->old_remote_per_commit = peer->remote_per_commit;
|
peer->old_remote_per_commit = peer->remote_per_commit;
|
||||||
peer->remote_per_commit = next_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. */
|
/* And peer waits for reply. */
|
||||||
return io_wait(conn, peer, accepted_revocation, peer);
|
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));
|
"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. */
|
/* We do this synchronously. */
|
||||||
static void init_channel(struct peer *peer)
|
static void init_channel(struct peer *peer)
|
||||||
{
|
{
|
||||||
|
@ -1274,23 +1541,23 @@ static void init_channel(struct peer *peer)
|
||||||
struct basepoints points[NUM_SIDES];
|
struct basepoints points[NUM_SIDES];
|
||||||
u64 funding_satoshi;
|
u64 funding_satoshi;
|
||||||
u16 funding_txout;
|
u16 funding_txout;
|
||||||
u64 commits_sent, commits_received, revocations_received;
|
u64 commits_sent, commits_received;
|
||||||
u64 local_msatoshi;
|
u64 local_msatoshi;
|
||||||
struct pubkey funding_pubkey[NUM_SIDES];
|
struct pubkey funding_pubkey[NUM_SIDES];
|
||||||
struct sha256_double funding_txid;
|
struct sha256_double funding_txid;
|
||||||
bool am_funder, last_was_revoke;
|
bool am_funder;
|
||||||
enum htlc_state *hstates;
|
enum htlc_state *hstates;
|
||||||
struct fulfilled_htlc *fulfilled;
|
struct fulfilled_htlc *fulfilled;
|
||||||
enum side *fulfilled_sides;
|
enum side *fulfilled_sides;
|
||||||
struct failed_htlc *failed;
|
struct failed_htlc *failed;
|
||||||
enum side *failed_sides;
|
enum side *failed_sides;
|
||||||
struct changed_htlc *last_sent_commit;
|
|
||||||
struct added_htlc *htlcs;
|
struct added_htlc *htlcs;
|
||||||
|
bool reconnected;
|
||||||
u8 *funding_signed;
|
u8 *funding_signed;
|
||||||
u8 *msg;
|
u8 *msg;
|
||||||
|
|
||||||
msg = wire_sync_read(peer, REQ_FD);
|
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_txid, &funding_txout,
|
||||||
&funding_satoshi,
|
&funding_satoshi,
|
||||||
&peer->conf[LOCAL], &peer->conf[REMOTE],
|
&peer->conf[LOCAL], &peer->conf[REMOTE],
|
||||||
|
@ -1310,11 +1577,11 @@ static void init_channel(struct peer *peer)
|
||||||
&peer->node_ids[REMOTE],
|
&peer->node_ids[REMOTE],
|
||||||
&peer->commit_msec,
|
&peer->commit_msec,
|
||||||
&peer->cltv_delta,
|
&peer->cltv_delta,
|
||||||
&last_was_revoke,
|
&peer->last_was_revoke,
|
||||||
&last_sent_commit,
|
&peer->last_sent_commit,
|
||||||
&commits_sent,
|
&commits_sent,
|
||||||
&commits_received,
|
&commits_received,
|
||||||
&revocations_received,
|
&peer->revocations_received,
|
||||||
&peer->htlc_id,
|
&peer->htlc_id,
|
||||||
&htlcs,
|
&htlcs,
|
||||||
&hstates,
|
&hstates,
|
||||||
|
@ -1322,6 +1589,10 @@ static void init_channel(struct peer *peer)
|
||||||
&fulfilled_sides,
|
&fulfilled_sides,
|
||||||
&failed,
|
&failed,
|
||||||
&failed_sides,
|
&failed_sides,
|
||||||
|
&peer->funding_locked[LOCAL],
|
||||||
|
&peer->funding_locked[REMOTE],
|
||||||
|
&peer->short_channel_ids[LOCAL],
|
||||||
|
&reconnected,
|
||||||
&funding_signed))
|
&funding_signed))
|
||||||
status_failed(WIRE_CHANNEL_BAD_COMMAND, "Init: %s",
|
status_failed(WIRE_CHANNEL_BAD_COMMAND, "Init: %s",
|
||||||
tal_hex(msg, msg));
|
tal_hex(msg, msg));
|
||||||
|
@ -1330,6 +1601,7 @@ static void init_channel(struct peer *peer)
|
||||||
assert(commits_sent > 0);
|
assert(commits_sent > 0);
|
||||||
assert(commits_received > 0);
|
assert(commits_received > 0);
|
||||||
|
|
||||||
|
/* If we've sent 1, we're on index 1. */
|
||||||
peer->commit_index[LOCAL] = commits_sent;
|
peer->commit_index[LOCAL] = commits_sent;
|
||||||
peer->commit_index[REMOTE] = commits_received;
|
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]);
|
&peer->node_ids[LOCAL], &peer->node_ids[REMOTE]);
|
||||||
|
|
||||||
/* OK, now we can process peer messages. */
|
/* 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);
|
io_set_finish(peer->peer_conn, peer_conn_broken, peer);
|
||||||
|
|
||||||
/* If we have a funding_signed message, we send that immediately */
|
/* If we have a funding_signed message, we send that immediately */
|
||||||
|
|
|
@ -56,6 +56,10 @@ channel_init,,fulfilled_sides,num_fulfilled*enum side
|
||||||
channel_init,,num_failed,u16
|
channel_init,,num_failed,u16
|
||||||
channel_init,,failed,num_failed*struct failed_htlc
|
channel_init,,failed,num_failed*struct failed_htlc
|
||||||
channel_init,,failed_sides,num_failed*enum side
|
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_len,u16
|
||||||
channel_init,,init_peer_pkt,init_peer_pkt_len*u8
|
channel_init,,init_peer_pkt,init_peer_pkt_len*u8
|
||||||
|
|
||||||
|
|
|
|
@ -101,11 +101,6 @@ void peer_fail(struct peer *peer, const char *fmt, ...)
|
||||||
goto dont_talk;
|
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. */
|
/* Reconnect unless we've dropped to chain. */
|
||||||
if (!peer_on_chain(peer)) {
|
if (!peer_on_chain(peer)) {
|
||||||
peer_reconnect(peer);
|
peer_reconnect(peer);
|
||||||
|
@ -155,6 +150,9 @@ static bool peer_reconnected(struct lightningd *ld,
|
||||||
tal_free(peer->cs);
|
tal_free(peer->cs);
|
||||||
peer->cs = tal_dup(peer, struct crypto_state, 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
|
/* FIXME: We should close peer->gossip_client_fd when we're not
|
||||||
* connected, and get a new one from gossipd when we reconnect. */
|
* 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->scid = NULL;
|
||||||
peer->id = *id;
|
peer->id = *id;
|
||||||
peer->fd = fd;
|
peer->fd = fd;
|
||||||
|
peer->reconnected = false;
|
||||||
peer->gossip_client_fd = -1;
|
peer->gossip_client_fd = -1;
|
||||||
peer->cs = tal_dup(peer, struct crypto_state, cs);
|
peer->cs = tal_dup(peer, struct crypto_state, cs);
|
||||||
peer->funding_txid = NULL;
|
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);
|
const char *txidstr = type_to_string(peer, struct sha256_double, txid);
|
||||||
struct txlocator *loc;
|
struct txlocator *loc;
|
||||||
|
bool peer_ready;
|
||||||
|
|
||||||
log_debug(peer->log, "Funding tx %s depth %u of %u",
|
log_debug(peer->log, "Funding tx %s depth %u of %u",
|
||||||
txidstr, depth, peer->minimum_depth);
|
txidstr, depth, peer->minimum_depth);
|
||||||
|
@ -694,16 +694,6 @@ static enum watch_result funding_lockin_cb(struct peer *peer,
|
||||||
if (depth < peer->minimum_depth)
|
if (depth < peer->minimum_depth)
|
||||||
return KEEP_WATCHING;
|
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);
|
loc = locate_tx(peer, peer->ld->topology, txid);
|
||||||
|
|
||||||
peer->scid = tal(peer, struct short_channel_id);
|
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;
|
peer->scid->outnum = peer->funding_outnum;
|
||||||
tal_free(loc);
|
tal_free(loc);
|
||||||
|
|
||||||
subd_send_msg(peer->owner,
|
/* In theory, it could have been buried before we got back
|
||||||
take(towire_channel_funding_locked(peer, peer->scid)));
|
* 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:
|
/* 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
|
* `funding_locked` has been sent, and the funding transaction is has
|
||||||
* at least 6 confirmations.
|
* at least 6 confirmations.
|
||||||
*/
|
*/
|
||||||
if (depth >= ANNOUNCE_MIN_DEPTH) {
|
if (depth >= ANNOUNCE_MIN_DEPTH && peer_ready) {
|
||||||
subd_send_msg(peer->owner,
|
subd_send_msg(peer->owner,
|
||||||
take(towire_channel_funding_announce_depth(peer)));
|
take(towire_channel_funding_announce_depth(peer)));
|
||||||
} else {
|
} else {
|
||||||
|
/* Worst case, we'll send next block. */
|
||||||
watch_txid(peer, peer->ld->topology, peer, txid,
|
watch_txid(peer, peer->ld->topology, peer, txid,
|
||||||
funding_announce_cb, NULL);
|
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);
|
= tal_free(peer->next_per_commitment_point);
|
||||||
peer->next_per_commitment_point
|
peer->next_per_commitment_point
|
||||||
= tal_dup(peer, struct pubkey, &next_per_commitment_point);
|
= tal_dup(peer, struct pubkey, &next_per_commitment_point);
|
||||||
|
log_debug(peer->log, "Got funding_locked");
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -928,6 +931,7 @@ static bool peer_start_channeld_hsmfd(struct subd *hsm, const u8 *resp,
|
||||||
enum side *fulfilled_sides;
|
enum side *fulfilled_sides;
|
||||||
struct failed_htlc *failed_htlcs;
|
struct failed_htlc *failed_htlcs;
|
||||||
enum side *failed_sides;
|
enum side *failed_sides;
|
||||||
|
struct short_channel_id funding_channel_id;
|
||||||
|
|
||||||
peer->owner = new_subd(peer->ld, peer->ld,
|
peer->owner = new_subd(peer->ld, peer->ld,
|
||||||
"lightningd_channel", peer,
|
"lightningd_channel", peer,
|
||||||
|
@ -944,12 +948,20 @@ static bool peer_start_channeld_hsmfd(struct subd *hsm, const u8 *resp,
|
||||||
return true;
|
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,
|
peer_htlcs(resp, peer, &htlcs, &htlc_states, &fulfilled_htlcs,
|
||||||
&fulfilled_sides, &failed_htlcs, &failed_sides);
|
&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,
|
initmsg = towire_channel_init(peer,
|
||||||
peer->funding_txid,
|
peer->funding_txid,
|
||||||
peer->funding_outnum,
|
peer->funding_outnum,
|
||||||
|
@ -981,6 +993,10 @@ static bool peer_start_channeld_hsmfd(struct subd *hsm, const u8 *resp,
|
||||||
htlcs, htlc_states,
|
htlcs, htlc_states,
|
||||||
fulfilled_htlcs, fulfilled_sides,
|
fulfilled_htlcs, fulfilled_sides,
|
||||||
failed_htlcs, failed_sides,
|
failed_htlcs, failed_sides,
|
||||||
|
peer->scid != NULL,
|
||||||
|
peer->next_per_commitment_point != NULL,
|
||||||
|
&funding_channel_id,
|
||||||
|
peer->reconnected,
|
||||||
peer->funding_signed);
|
peer->funding_signed);
|
||||||
|
|
||||||
/* Don't need this any more (we never re-transmit it) */
|
/* Don't need this any more (we never re-transmit it) */
|
||||||
|
|
|
@ -45,6 +45,8 @@ struct peer {
|
||||||
|
|
||||||
/* Our fd to the peer (-1 when we don't have it). */
|
/* Our fd to the peer (-1 when we don't have it). */
|
||||||
int fd;
|
int fd;
|
||||||
|
/* If we've disconnected, this is set. */
|
||||||
|
bool reconnected;
|
||||||
|
|
||||||
/* Crypto state (NULL if it's in daemon) */
|
/* Crypto state (NULL if it's in daemon) */
|
||||||
struct crypto_state *cs;
|
struct crypto_state *cs;
|
||||||
|
|
|
@ -526,7 +526,7 @@ class LightningDTests(BaseLightningDTests):
|
||||||
assert l1.rpc.getpeer(l2.info['id']) == None
|
assert l1.rpc.getpeer(l2.info['id']) == None
|
||||||
assert l2.rpc.getpeer(l1.info['id'])['peerid'] == l1.info['id']
|
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.
|
# This will fail *after* both sides consider channel opening.
|
||||||
disconnects = ['+WIRE_FUNDING_SIGNED']
|
disconnects = ['+WIRE_FUNDING_SIGNED']
|
||||||
l1 = self.node_factory.get_node(legacy=False)
|
l1 = self.node_factory.get_node(legacy=False)
|
||||||
|
@ -557,6 +557,17 @@ class LightningDTests(BaseLightningDTests):
|
||||||
l1.daemon.wait_for_log('-> CHANNELD_NORMAL')
|
l1.daemon.wait_for_log('-> CHANNELD_NORMAL')
|
||||||
l2.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):
|
def test_json_addfunds(self):
|
||||||
""" Attempt to add funds
|
""" Attempt to add funds
|
||||||
"""
|
"""
|
||||||
|
|
Loading…
Reference in New Issue