mirror of
https://github.com/ElementsProject/lightning.git
synced 2024-11-19 09:54:16 +01:00
lightningd/channel.c: add callbacks for when HTLCs fully committed/removed.
The three cases we care about only happen on specific transitions: 1. They can no longer spend our failed HTLC: we can fail the source now. 2. They are fully committed to their new HTLC htlc: we can forward now. 3. They can no longer timeout their fulfilled HTLC: the funds are ours. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
82a467f131
commit
ada1eb5106
@ -619,11 +619,36 @@ static void htlc_incstate(struct channel *channel,
|
||||
}
|
||||
}
|
||||
|
||||
static void check_lockedin(const struct htlc *h,
|
||||
struct peer *peer,
|
||||
void (*oursfail)(struct peer *peer,
|
||||
const struct htlc *htlc),
|
||||
void (*theirslocked)(struct peer *peer,
|
||||
const struct htlc *htlc),
|
||||
void (*theirsfulfilled)(struct peer *peer,
|
||||
const struct htlc *htlc))
|
||||
{
|
||||
/* If it was fulfilled, we handled it immediately. */
|
||||
if (h->state == RCVD_REMOVE_ACK_REVOCATION && !h->r)
|
||||
oursfail(peer, h);
|
||||
else if (h->state == RCVD_ADD_ACK_REVOCATION)
|
||||
theirslocked(peer, h);
|
||||
else if (h->state == RCVD_REMOVE_ACK_COMMIT && h->r)
|
||||
theirsfulfilled(peer, h);
|
||||
}
|
||||
|
||||
/* FIXME: Commit to storage when this happens. */
|
||||
static bool change_htlcs(struct channel *channel,
|
||||
enum side sidechanged,
|
||||
const enum htlc_state *htlc_states,
|
||||
size_t n_hstates)
|
||||
size_t n_hstates,
|
||||
struct peer *peer,
|
||||
void (*oursfail)(struct peer *peer,
|
||||
const struct htlc *htlc),
|
||||
void (*theirslocked)(struct peer *peer,
|
||||
const struct htlc *htlc),
|
||||
void (*theirsfulfilled)(struct peer *peer,
|
||||
const struct htlc *htlc))
|
||||
{
|
||||
struct htlc_map_iter it;
|
||||
struct htlc *h;
|
||||
@ -636,6 +661,10 @@ static bool change_htlcs(struct channel *channel,
|
||||
for (i = 0; i < n_hstates; i++) {
|
||||
if (h->state == htlc_states[i]) {
|
||||
htlc_incstate(channel, h, sidechanged);
|
||||
check_lockedin(h, peer,
|
||||
oursfail,
|
||||
theirslocked,
|
||||
theirsfulfilled);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
@ -651,10 +680,16 @@ bool channel_sent_commit(struct channel *channel)
|
||||
SENT_ADD_REVOCATION,
|
||||
SENT_REMOVE_HTLC };
|
||||
status_trace("sent commit");
|
||||
return change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states));
|
||||
return change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states),
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
bool channel_rcvd_revoke_and_ack(struct channel *channel)
|
||||
bool channel_rcvd_revoke_and_ack(struct channel *channel,
|
||||
struct peer *peer,
|
||||
void (*oursfail)(struct peer *peer,
|
||||
const struct htlc *htlc),
|
||||
void (*theirslocked)(struct peer *peer,
|
||||
const struct htlc *htlc))
|
||||
{
|
||||
const enum htlc_state states[] = { SENT_ADD_COMMIT,
|
||||
SENT_REMOVE_ACK_COMMIT,
|
||||
@ -662,11 +697,15 @@ bool channel_rcvd_revoke_and_ack(struct channel *channel)
|
||||
SENT_REMOVE_COMMIT };
|
||||
|
||||
status_trace("received revoke_and_ack");
|
||||
return change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states));
|
||||
return change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states),
|
||||
peer, oursfail, theirslocked, NULL);
|
||||
}
|
||||
|
||||
/* FIXME: We can actually merge these two... */
|
||||
bool channel_rcvd_commit(struct channel *channel)
|
||||
bool channel_rcvd_commit(struct channel *channel,
|
||||
struct peer *peer,
|
||||
void (*theirsfulfilled)(struct peer *peer,
|
||||
const struct htlc *htlc))
|
||||
{
|
||||
const enum htlc_state states[] = { RCVD_ADD_REVOCATION,
|
||||
RCVD_REMOVE_HTLC,
|
||||
@ -674,7 +713,8 @@ bool channel_rcvd_commit(struct channel *channel)
|
||||
RCVD_REMOVE_REVOCATION };
|
||||
|
||||
status_trace("received commit");
|
||||
return change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states));
|
||||
return change_htlcs(channel, LOCAL, states, ARRAY_SIZE(states),
|
||||
peer, NULL, NULL, theirsfulfilled);
|
||||
}
|
||||
|
||||
bool channel_sent_revoke_and_ack(struct channel *channel)
|
||||
@ -684,7 +724,8 @@ bool channel_sent_revoke_and_ack(struct channel *channel)
|
||||
RCVD_ADD_COMMIT,
|
||||
RCVD_REMOVE_ACK_COMMIT };
|
||||
status_trace("sent revoke_and_ack");
|
||||
return change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states));
|
||||
return change_htlcs(channel, REMOTE, states, ARRAY_SIZE(states),
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
static char *fmt_channel_view(const tal_t *ctx, const struct channel_view *view)
|
||||
|
@ -10,6 +10,7 @@
|
||||
#include <lightningd/derive_basepoints.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
struct peer;
|
||||
struct signature;
|
||||
|
||||
/* View from each side */
|
||||
@ -330,18 +331,34 @@ bool channel_sent_commit(struct channel *channel);
|
||||
/**
|
||||
* channel_rcvd_revoke_and_ack: accept ack on remote committed changes.
|
||||
* @channel: the channel
|
||||
* @peer: argument to pass through to @ourhtlcfail & @theirhtlclocked
|
||||
* @oursfail: callback for any unfilfilled htlcs which are now fully removed.
|
||||
* @theirslocked: callback for any new htlcs which are now fully committed.
|
||||
*
|
||||
* This is where we commit to pending changes we've added; returns true if
|
||||
* anything changed. */
|
||||
bool channel_rcvd_revoke_and_ack(struct channel *channel);
|
||||
* anything changed.
|
||||
*/
|
||||
bool channel_rcvd_revoke_and_ack(struct channel *channel,
|
||||
struct peer *peer,
|
||||
void (*oursfail)(struct peer *peer,
|
||||
const struct htlc *htlc),
|
||||
void (*theirslocked)(struct peer *peer,
|
||||
const struct htlc *htlc));
|
||||
|
||||
/**
|
||||
* channel_rcvd_commit: commit all local outstanding changes.
|
||||
* @channel: the channel
|
||||
* @peer: argument to pass through to @theirsfulfilled
|
||||
* @theirsfulfilled: they are irrevocably committed to removal of htlc.
|
||||
*
|
||||
* This is where we commit to pending changes we've added; returns true if
|
||||
* anything changed. */
|
||||
bool channel_rcvd_commit(struct channel *channel);
|
||||
* anything changed. @theirsfulfilled is called for any HTLC we fulfilled
|
||||
* which they are irrevocably committed to, and is in our current commitment.
|
||||
*/
|
||||
bool channel_rcvd_commit(struct channel *channel,
|
||||
struct peer *peer,
|
||||
void (*theirsfulfilled)(struct peer *peer,
|
||||
const struct htlc *htlc));
|
||||
|
||||
/**
|
||||
* channel_sent_revoke_and_ack: sent ack on local committed changes.
|
||||
|
@ -369,7 +369,8 @@ static void handle_peer_commit_sig(struct peer *peer, const u8 *msg)
|
||||
const u8 **wscripts;
|
||||
size_t i;
|
||||
|
||||
if (!channel_rcvd_commit(peer->channel)) {
|
||||
/* FIXME: Handle theirsfulfilled! */
|
||||
if (!channel_rcvd_commit(peer->channel, peer, NULL)) {
|
||||
/* BOLT #2:
|
||||
*
|
||||
* A node MUST NOT send a `commitment_signed` message which
|
||||
|
@ -81,6 +81,10 @@ static u64 feerates[] = {
|
||||
9651936
|
||||
};
|
||||
|
||||
static void do_nothing(struct peer *peer, const struct htlc *htlc)
|
||||
{
|
||||
}
|
||||
|
||||
/* BOLT #3:
|
||||
*
|
||||
* htlc 0 direction: remote->local
|
||||
@ -150,11 +154,11 @@ static const struct htlc **include_htlcs(struct channel *channel, enum side side
|
||||
|
||||
/* Now make HTLCs fully committed. */
|
||||
channel_sent_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel);
|
||||
channel_rcvd_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel, NULL, NULL, NULL);
|
||||
channel_rcvd_commit(channel, NULL, NULL);
|
||||
channel_sent_revoke_and_ack(channel);
|
||||
channel_sent_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel);
|
||||
channel_rcvd_revoke_and_ack(channel, NULL, NULL, do_nothing);
|
||||
return htlcs;
|
||||
}
|
||||
|
||||
@ -236,27 +240,27 @@ static void send_and_fulfill_htlc(struct channel *channel,
|
||||
if (sender == LOCAL) {
|
||||
/* Step through a complete cycle. */
|
||||
channel_sent_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel);
|
||||
channel_rcvd_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel, NULL, NULL, NULL);
|
||||
channel_rcvd_commit(channel, NULL, NULL);
|
||||
channel_sent_revoke_and_ack(channel);
|
||||
assert(channel_fulfill_htlc(channel, REMOTE, 1337, &r)
|
||||
== CHANNEL_ERR_REMOVE_OK);
|
||||
channel_rcvd_commit(channel);
|
||||
channel_rcvd_commit(channel, NULL, NULL);
|
||||
channel_sent_revoke_and_ack(channel);
|
||||
channel_sent_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel);
|
||||
channel_rcvd_revoke_and_ack(channel, NULL, NULL, NULL);
|
||||
assert(channel_get_htlc(channel, sender, 1337)->state
|
||||
== RCVD_REMOVE_ACK_REVOCATION);
|
||||
} else {
|
||||
channel_rcvd_commit(channel);
|
||||
channel_rcvd_commit(channel, NULL, NULL);
|
||||
channel_sent_revoke_and_ack(channel);
|
||||
channel_sent_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel);
|
||||
channel_rcvd_revoke_and_ack(channel, NULL, NULL, do_nothing);
|
||||
assert(channel_fulfill_htlc(channel, LOCAL, 1337, &r)
|
||||
== CHANNEL_ERR_REMOVE_OK);
|
||||
channel_sent_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel);
|
||||
channel_rcvd_commit(channel);
|
||||
channel_rcvd_revoke_and_ack(channel, NULL, NULL, NULL);
|
||||
channel_rcvd_commit(channel, NULL, do_nothing);
|
||||
channel_sent_revoke_and_ack(channel);
|
||||
assert(channel_get_htlc(channel, sender, 1337)->state
|
||||
== SENT_REMOVE_ACK_REVOCATION);
|
||||
|
Loading…
Reference in New Issue
Block a user