lightningd/channel: send and receive revoke_and_ack packets.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell 2017-04-01 21:28:30 +10:30
parent 2ddc0b696c
commit d3cbde4b46
2 changed files with 134 additions and 7 deletions

View File

@ -48,6 +48,7 @@ struct peer {
struct pubkey old_per_commit[NUM_SIDES];
struct pubkey current_per_commit[NUM_SIDES];
bool funding_locked[NUM_SIDES];
u64 commit_index[NUM_SIDES];
/* Their sig for current commit. */
secp256k1_ecdsa_signature their_commit_sig;
@ -58,6 +59,9 @@ struct peer {
/* Our shaseed for generating per-commitment-secrets. */
struct sha256 shaseed;
/* Their shachain. */
struct shachain their_shachain;
/* BOLT #2:
*
* A sending node MUST set `id` to 0 for the first HTLC it offers, and
@ -279,6 +283,7 @@ static void send_commit(struct peer *peer)
/* FIXME: Document this requirement in BOLT 2! */
/* We can't send two commits in a row. */
if (channel_awaiting_revoke_and_ack(peer->channel)) {
status_trace("Can't send commit: waiting for revoke_and_ack");
tal_free(tmpctx);
return;
}
@ -289,6 +294,7 @@ static void send_commit(struct peer *peer)
* include any updates.
*/
if (!channel_sending_commit(peer->channel)) {
status_trace("Can't send commit: nothing to send");
tal_free(tmpctx);
return;
}
@ -369,6 +375,7 @@ static void start_commit_timer(struct peer *peer)
static void handle_peer_commit_sig(struct peer *peer, const u8 *msg)
{
tal_t *tmpctx = tal_tmpctx(peer);
struct sha256 old_commit_secret;
struct channel_id channel_id;
secp256k1_ecdsa_signature commit_sig, *htlc_sigs;
struct pubkey remotekey;
@ -466,11 +473,124 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg)
status_trace("Received commit_sig with %zu htlc sigs",
tal_count(htlc_sigs));
/* This may have triggered changes, so restart timer. */
struct pubkey oldpoint = peer->old_per_commit[LOCAL], test;
status_trace("Sending secret for point %"PRIu64" %s",
peer->commit_index[LOCAL]-1,
type_to_string(trc, struct pubkey,
&peer->old_per_commit[LOCAL]));
peer->old_per_commit[LOCAL] = peer->current_per_commit[LOCAL];
if (!next_per_commit_point(&peer->shaseed, &old_commit_secret,
&peer->current_per_commit[LOCAL],
peer->commit_index[LOCAL]))
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
"Deriving next commit_point");
pubkey_from_privkey((struct privkey *)&old_commit_secret, &test);
if (!pubkey_eq(&test, &oldpoint))
status_failed(WIRE_CHANNEL_CRYPTO_FAILED,
"Invalid secret %s for commit_point",
tal_hexstr(msg, &old_commit_secret,
sizeof(old_commit_secret)));
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(msg, &channel_id, &old_commit_secret,
&peer->current_per_commit[LOCAL]);
msg_enqueue(&peer->peer_out, take(msg));
tal_free(tmpctx);
}
static void our_htlc_failed(const struct htlc *htlc, struct peer *peer)
{
status_trace("FIXME: our htlc %"PRIu64" failed", htlc->id);
}
static void their_htlc_locked(const struct htlc *htlc, struct peer *peer)
{
status_trace("FIXME: their htlc %"PRIu64" locked", htlc->id);
}
static void handle_peer_revoke_and_ack(struct peer *peer, const u8 *msg)
{
struct sha256 old_commit_secret;
struct privkey privkey;
struct channel_id channel_id;
struct pubkey per_commit_point, next_per_commit;
if (!fromwire_revoke_and_ack(msg, NULL, &channel_id, &old_commit_secret,
&next_per_commit)) {
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Bad revoke_and_ack %s", tal_hex(msg, msg));
}
/* BOLT #2:
*
* A receiving node MUST check that `per-commitment-secret` generates
* the previous `per-commitment-point`, and MUST fail if it does
* not.
*/
memcpy(&privkey, &old_commit_secret, sizeof(privkey));
if (!pubkey_from_privkey(&privkey, &per_commit_point)) {
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Bad privkey %s",
type_to_string(msg, struct privkey, &privkey));
}
if (!pubkey_eq(&per_commit_point, &peer->old_per_commit[REMOTE])) {
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Wrong privkey %s for %s",
type_to_string(msg, struct privkey, &privkey),
type_to_string(msg, struct pubkey,
&peer->old_per_commit[REMOTE]));
}
/* BOLT #2:
*
* A receiving node MAY fail if the `per-commitment-secret` was not
* generated by the protocol in [BOLT #3]
*/
if (!shachain_add_hash(&peer->their_shachain,
281474976710655ULL - peer->commit_index[REMOTE],
&old_commit_secret)) {
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
&peer->channel_id,
WIRE_CHANNEL_PEER_BAD_MESSAGE,
"Bad shachain for privkey %"PRIu64" %s ",
peer->commit_index[REMOTE],
type_to_string(msg, struct privkey, &privkey));
}
peer->commit_index[REMOTE]++;
peer->old_per_commit[REMOTE] = peer->current_per_commit[REMOTE];
peer->current_per_commit[REMOTE] = next_per_commit;
/* We start timer even if this returns false: we might have delayed
* commit because we were waiting for this! */
if (channel_rcvd_revoke_and_ack(peer->channel,
our_htlc_failed, their_htlc_locked,
peer))
status_trace("Commits outstanding after recv revoke_and_ack");
else
status_trace("No commits outstanding after recv revoke_and_ack");
start_commit_timer(peer);
}
static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
{
enum wire_type type = fromwire_peektype(msg);
@ -510,6 +630,9 @@ static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
case WIRE_COMMITMENT_SIGNED:
handle_peer_commit_sig(peer, msg);
goto done;
case WIRE_REVOKE_AND_ACK:
handle_peer_revoke_and_ack(peer, msg);
goto done;
case WIRE_INIT:
case WIRE_ERROR:
case WIRE_OPEN_CHANNEL:
@ -523,7 +646,6 @@ static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
case WIRE_UPDATE_FULFILL_HTLC:
case WIRE_UPDATE_FAIL_HTLC:
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
case WIRE_REVOKE_AND_ACK:
case WIRE_UPDATE_FEE:
peer_failed(io_conn_fd(peer->peer_conn),
&peer->pcs.cs,
@ -593,7 +715,11 @@ static void init_channel(struct peer *peer, const u8 *msg)
/* We derive everything from the one secret seed. */
derive_basepoints(&seed, &funding_pubkey[LOCAL], &points[LOCAL],
&peer->our_secrets, &peer->shaseed,
&peer->old_per_commit[LOCAL], 0);
&peer->old_per_commit[LOCAL],
peer->commit_index[LOCAL]);
status_trace("First per_commit_point = %s",
type_to_string(trc, struct pubkey,
&peer->old_per_commit[LOCAL]));
peer->channel = new_channel(peer, &funding_txid, funding_txout,
funding_satoshi, push_msat, feerate,
@ -619,7 +745,7 @@ static void handle_funding_locked(struct peer *peer, const u8 *msg)
next_per_commit_point(&peer->shaseed, NULL,
&peer->current_per_commit[LOCAL],
0);
peer->commit_index[LOCAL]++);
msg = towire_funding_locked(peer,
&peer->channel_id,
@ -849,6 +975,8 @@ int main(int argc, char *argv[])
peer->htlc_id = 0;
timers_init(&peer->timers, time_mono());
peer->commit_timer = NULL;
peer->commit_index[LOCAL] = peer->commit_index[REMOTE] = 0;
shachain_init(&peer->their_shachain);
status_setup_async(&peer->master);
msg_queue_init(&peer->peer_out, peer);

View File

@ -55,8 +55,7 @@ RHASH=`lcli1 dev-rhash $SECRET | sed 's/.*"\([0-9a-f]*\)".*/\1/'`
lcli1 dev-newhtlc $ID2 100000 $(( $(blockheight) + 10 )) $RHASH
sleep 1
check "lcli2 getpeers | tr -s '\012\011\" ' ' ' | $FGREP 'condition : Normal operation'"
check "lcli2 getlog debug | $FGREP 'their htlc 0 locked'"
lcli1 stop
lcli2 stop