lightningd: fail htlcs we fulfill if peer unresponsive after deadline.

Closes: #241
Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
Rusty Russell
2017-11-02 10:26:07 +10:30
parent 1142c44c29
commit 8cef36cbd7
2 changed files with 100 additions and 3 deletions

View File

@@ -289,9 +289,6 @@ static void fulfill_htlc(struct htlc_in *hin, const struct preimage *preimage)
if (peer_state_on_chain(hin->key.peer->state)) {
msg = towire_onchain_known_preimage(hin, preimage);
} else {
/* FIXME: fail the peer if it doesn't tell us that htlc
* fulfill is committed before deadline.
*/
msg = towire_channel_fulfill_htlc(hin, hin->key.id, preimage);
}
subd_send_msg(hin->key.peer->owner, take(msg));
@@ -1437,6 +1434,21 @@ static u32 htlc_out_deadline(const struct htlc_out *hout)
return hout->cltv_expiry + 1;
}
/* BOLT #2:
*
* For HTLCs we accept and have a preimage: the fulfillment deadline when we
* have to fail the channel and fulfill the HTLC onchain before its
* `cltv_expiry`. This is steps 4-7 above, which means a deadline of `2R+G+S`
* blocks before `cltv_expiry`; 7 blocks is reasonable.
*/
/* We approximate this, by using half the cltv_expiry_delta (3R+2G+2S),
* rounded up. */
static u32 htlc_in_deadline(const struct lightningd *ld,
const struct htlc_in *hin)
{
return hin->cltv_expiry - (ld->config.cltv_expiry_delta + 1)/2;
}
void notify_new_block(struct lightningd *ld, u32 height)
{
bool removed;
@@ -1480,4 +1492,49 @@ void notify_new_block(struct lightningd *ld, u32 height)
}
/* Iteration while removing is safe, but can skip entries! */
} while (removed);
/* BOLT #2:
*
* A node MUST estimate a fulfillment deadline for each HTLC it is
* attempting to fulfill. A node ... MUST fail the connection if a
* HTLC it has fulfilled is in either node's current commitment
* transaction past this fulfillment deadline.
*/
do {
struct htlc_in *hin;
struct htlc_in_map_iter ini;
removed = false;
for (hin = htlc_in_map_first(&ld->htlcs_in, &ini);
hin;
hin = htlc_in_map_next(&ld->htlcs_in, &ini)) {
/* Not fulfilled? If overdue, that's their problem... */
if (!hin->preimage)
continue;
/* Not timed out yet? */
if (height < htlc_in_deadline(ld, hin))
continue;
/* Peer on chain already? */
if (peer_on_chain(hin->key.peer))
continue;
/* Peer already failed, or we hit it? */
if (hin->key.peer->error)
continue;
peer_fail_permanent_str(hin->key.peer,
take(tal_fmt(hin,
"Fulfilled HTLC %"PRIu64
" %s cltv %u hit deadline",
hin->key.id,
htlc_state_name(hin->hstate),
hin->cltv_expiry)));
removed = true;
}
/* Iteration while removing is safe, but can skip entries! */
} while (removed);
}