From dd1a81d8bd3f8672e0e4562a558f71ba6a5ffc7a Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 29 Mar 2017 21:27:15 +1030 Subject: [PATCH] lightningd/channel: implement channel_fail_htlc. Signed-off-by: Rusty Russell --- lightningd/channel.c | 37 +++++++++++++++++++++++++++++++++++++ 1 file changed, 37 insertions(+) diff --git a/lightningd/channel.c b/lightningd/channel.c index 62031f582..1ac05c4f5 100644 --- a/lightningd/channel.c +++ b/lightningd/channel.c @@ -454,6 +454,43 @@ enum channel_remove_err channel_fulfill_htlc(struct channel *channel, return CHANNEL_ERR_REMOVE_OK; } +enum channel_remove_err channel_fail_htlc(struct channel *channel, + enum side sender, u64 id) +{ + struct htlc *htlc; + + /* Fail is done by !creator of HTLC */ + htlc = channel_get_htlc(channel, !sender, id); + if (!htlc) + return CHANNEL_ERR_NO_SUCH_ID; + + /* BOLT #2: + * + * A receiving node MUST check that `id` corresponds to an HTLC in its + * current commitment transaction, and MUST fail the channel if it + * does not. + */ + if (!htlc_has(htlc, HTLC_FLAG(!htlc_owner(htlc), HTLC_F_COMMITTED))) { + status_trace("channel_fail_htlc: %"PRIu64" in state %s", + htlc->id, htlc_state_name(htlc->state)); + return CHANNEL_ERR_HTLC_UNCOMMITTED; + } + + /* FIXME: Technically, they can fail this before we're committed to + * it. This implies a non-linear state machine. */ + if (htlc->state == SENT_ADD_ACK_REVOCATION) + htlc->state = RCVD_REMOVE_HTLC; + else if (htlc->state == RCVD_ADD_ACK_REVOCATION) + htlc->state = SENT_REMOVE_HTLC; + else { + status_trace("channel_fail_htlc: %"PRIu64" in state %s", + htlc->id, htlc_state_name(htlc->state)); + return CHANNEL_ERR_HTLC_NOT_IRREVOCABLE; + } + + return CHANNEL_ERR_REMOVE_OK; +} + static void htlc_incstate(struct channel *channel, struct htlc *htlc, enum side sidechanged)