mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 18:11:28 +01:00
lightningd/channel: send and receive revoke_and_ack packets.
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
2ddc0b696c
commit
d3cbde4b46
@ -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. */
|
||||
start_commit_timer(peer);
|
||||
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);
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user