mirror of
https://github.com/aljazceru/lightning.git
synced 2025-12-19 15:14:23 +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:
@@ -48,6 +48,7 @@ struct peer {
|
|||||||
struct pubkey old_per_commit[NUM_SIDES];
|
struct pubkey old_per_commit[NUM_SIDES];
|
||||||
struct pubkey current_per_commit[NUM_SIDES];
|
struct pubkey current_per_commit[NUM_SIDES];
|
||||||
bool funding_locked[NUM_SIDES];
|
bool funding_locked[NUM_SIDES];
|
||||||
|
u64 commit_index[NUM_SIDES];
|
||||||
|
|
||||||
/* Their sig for current commit. */
|
/* Their sig for current commit. */
|
||||||
secp256k1_ecdsa_signature their_commit_sig;
|
secp256k1_ecdsa_signature their_commit_sig;
|
||||||
@@ -58,6 +59,9 @@ struct peer {
|
|||||||
/* Our shaseed for generating per-commitment-secrets. */
|
/* Our shaseed for generating per-commitment-secrets. */
|
||||||
struct sha256 shaseed;
|
struct sha256 shaseed;
|
||||||
|
|
||||||
|
/* Their shachain. */
|
||||||
|
struct shachain their_shachain;
|
||||||
|
|
||||||
/* BOLT #2:
|
/* BOLT #2:
|
||||||
*
|
*
|
||||||
* A sending node MUST set `id` to 0 for the first HTLC it offers, and
|
* 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! */
|
/* FIXME: Document this requirement in BOLT 2! */
|
||||||
/* We can't send two commits in a row. */
|
/* We can't send two commits in a row. */
|
||||||
if (channel_awaiting_revoke_and_ack(peer->channel)) {
|
if (channel_awaiting_revoke_and_ack(peer->channel)) {
|
||||||
|
status_trace("Can't send commit: waiting for revoke_and_ack");
|
||||||
tal_free(tmpctx);
|
tal_free(tmpctx);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -289,6 +294,7 @@ static void send_commit(struct peer *peer)
|
|||||||
* include any updates.
|
* include any updates.
|
||||||
*/
|
*/
|
||||||
if (!channel_sending_commit(peer->channel)) {
|
if (!channel_sending_commit(peer->channel)) {
|
||||||
|
status_trace("Can't send commit: nothing to send");
|
||||||
tal_free(tmpctx);
|
tal_free(tmpctx);
|
||||||
return;
|
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)
|
static void handle_peer_commit_sig(struct peer *peer, const u8 *msg)
|
||||||
{
|
{
|
||||||
tal_t *tmpctx = tal_tmpctx(peer);
|
tal_t *tmpctx = tal_tmpctx(peer);
|
||||||
|
struct sha256 old_commit_secret;
|
||||||
struct channel_id channel_id;
|
struct channel_id channel_id;
|
||||||
secp256k1_ecdsa_signature commit_sig, *htlc_sigs;
|
secp256k1_ecdsa_signature commit_sig, *htlc_sigs;
|
||||||
struct pubkey remotekey;
|
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",
|
status_trace("Received commit_sig with %zu htlc sigs",
|
||||||
tal_count(htlc_sigs));
|
tal_count(htlc_sigs));
|
||||||
|
|
||||||
/* This may have triggered changes, so restart timer. */
|
struct pubkey oldpoint = peer->old_per_commit[LOCAL], test;
|
||||||
start_commit_timer(peer);
|
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);
|
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)
|
static struct io_plan *peer_in(struct io_conn *conn, struct peer *peer, u8 *msg)
|
||||||
{
|
{
|
||||||
enum wire_type type = fromwire_peektype(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:
|
case WIRE_COMMITMENT_SIGNED:
|
||||||
handle_peer_commit_sig(peer, msg);
|
handle_peer_commit_sig(peer, msg);
|
||||||
goto done;
|
goto done;
|
||||||
|
case WIRE_REVOKE_AND_ACK:
|
||||||
|
handle_peer_revoke_and_ack(peer, msg);
|
||||||
|
goto done;
|
||||||
case WIRE_INIT:
|
case WIRE_INIT:
|
||||||
case WIRE_ERROR:
|
case WIRE_ERROR:
|
||||||
case WIRE_OPEN_CHANNEL:
|
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_FULFILL_HTLC:
|
||||||
case WIRE_UPDATE_FAIL_HTLC:
|
case WIRE_UPDATE_FAIL_HTLC:
|
||||||
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
|
case WIRE_UPDATE_FAIL_MALFORMED_HTLC:
|
||||||
case WIRE_REVOKE_AND_ACK:
|
|
||||||
case WIRE_UPDATE_FEE:
|
case WIRE_UPDATE_FEE:
|
||||||
peer_failed(io_conn_fd(peer->peer_conn),
|
peer_failed(io_conn_fd(peer->peer_conn),
|
||||||
&peer->pcs.cs,
|
&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. */
|
/* We derive everything from the one secret seed. */
|
||||||
derive_basepoints(&seed, &funding_pubkey[LOCAL], &points[LOCAL],
|
derive_basepoints(&seed, &funding_pubkey[LOCAL], &points[LOCAL],
|
||||||
&peer->our_secrets, &peer->shaseed,
|
&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,
|
peer->channel = new_channel(peer, &funding_txid, funding_txout,
|
||||||
funding_satoshi, push_msat, feerate,
|
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,
|
next_per_commit_point(&peer->shaseed, NULL,
|
||||||
&peer->current_per_commit[LOCAL],
|
&peer->current_per_commit[LOCAL],
|
||||||
0);
|
peer->commit_index[LOCAL]++);
|
||||||
|
|
||||||
msg = towire_funding_locked(peer,
|
msg = towire_funding_locked(peer,
|
||||||
&peer->channel_id,
|
&peer->channel_id,
|
||||||
@@ -849,6 +975,8 @@ int main(int argc, char *argv[])
|
|||||||
peer->htlc_id = 0;
|
peer->htlc_id = 0;
|
||||||
timers_init(&peer->timers, time_mono());
|
timers_init(&peer->timers, time_mono());
|
||||||
peer->commit_timer = NULL;
|
peer->commit_timer = NULL;
|
||||||
|
peer->commit_index[LOCAL] = peer->commit_index[REMOTE] = 0;
|
||||||
|
shachain_init(&peer->their_shachain);
|
||||||
|
|
||||||
status_setup_async(&peer->master);
|
status_setup_async(&peer->master);
|
||||||
msg_queue_init(&peer->peer_out, peer);
|
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
|
lcli1 dev-newhtlc $ID2 100000 $(( $(blockheight) + 10 )) $RHASH
|
||||||
|
|
||||||
sleep 1
|
check "lcli2 getlog debug | $FGREP 'their htlc 0 locked'"
|
||||||
check "lcli2 getpeers | tr -s '\012\011\" ' ' ' | $FGREP 'condition : Normal operation'"
|
|
||||||
|
|
||||||
lcli1 stop
|
lcli1 stop
|
||||||
lcli2 stop
|
lcli2 stop
|
||||||
|
|||||||
Reference in New Issue
Block a user