-
Notifications
You must be signed in to change notification settings - Fork 404
Be less aggressive in outbound HTLC CLTV timeout checks #1119
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1850,17 +1850,24 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana | |
break Some(("Forwarding node has tampered with the intended HTLC values or origin node has an obsolete cltv_expiry_delta", 0x1000 | 13, Some(self.get_channel_update_for_unicast(chan).unwrap()))); | ||
} | ||
let cur_height = self.best_block.read().unwrap().height() + 1; | ||
// Theoretically, channel counterparty shouldn't send us a HTLC expiring now, but we want to be robust wrt to counterparty | ||
// packet sanitization (see HTLC_FAIL_BACK_BUFFER rational) | ||
// Theoretically, channel counterparty shouldn't send us a HTLC expiring now, | ||
// but we want to be robust wrt to counterparty packet sanitization (see | ||
// HTLC_FAIL_BACK_BUFFER rationale). | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW, There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I kinda like keeping it next to the other block count security assumption constants above it? I don't feel super strongly but unless you do I'm not gonna bother moving it. |
||
if msg.cltv_expiry <= cur_height + HTLC_FAIL_BACK_BUFFER as u32 { // expiry_too_soon | ||
break Some(("CLTV expiry is too close", 0x1000 | 14, Some(self.get_channel_update_for_unicast(chan).unwrap()))); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think we don't have functional test coverage for this check, I don't get a failure when I'm blanking it out ? In fact, do we really need it, because I think if we check that incoming There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, I buy that we could drop this check. Doesn't mean we should, of course, but I buy that its actually unreachable. I appreciate the simplicity/readability of a <= and a > check right after each other with straight constants and not having to dig into channel/config code to make sure we don't accidentally do something stupid :) There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Sure, I think ultimately we should be able to capture safety invariant of our HTLC forwarding policy with constants a la There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, I think this is basically doing that? I'm not suggesting we couldn't document more, only that this is a nice simple straightforward check, in addition to our configuration-based one. |
||
} | ||
if msg.cltv_expiry > cur_height + CLTV_FAR_FAR_AWAY as u32 { // expiry_too_far | ||
break Some(("CLTV expiry is too far in the future", 21, None)); | ||
} | ||
// In theory, we would be safe against unintentional channel-closure, if we only required a margin of LATENCY_GRACE_PERIOD_BLOCKS. | ||
// But, to be safe against policy reception, we use a longer delay. | ||
if (*outgoing_cltv_value) as u64 <= (cur_height + HTLC_FAIL_BACK_BUFFER) as u64 { | ||
// If the HTLC expires ~now, don't bother trying to forward it to our | ||
// counterparty. They should fail it anyway, but we don't want to bother with | ||
// the round-trips or risk them deciding they definitely want the HTLC and | ||
// force-closing to ensure they get it if we're offline. | ||
// We previously had a much more aggressive check here which tried to ensure | ||
// our counterparty receives an HTLC which has *our* risk threshold met on it, | ||
// but there is no need to do that, and since we're a bit conservative with our | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think it can be interesting to dissociate the two different types of risks we're exposed too. The first risk is missing the onchain confirmation of a HTLC on the backward link and as such accounting a loss in our forward HTLC balance. The second risk is the automatic force-close of a channel to achieve the onchain confirmation. I think what this PR highlights is that we can decrease the latter without affecting the former. Onchain confirmation is function of when the forward link is going to go onchain ( However I think we increase our exposure to the second type of risk. In I think this is okay, though if we observe an increase rate of channel force-closed, we could still bump to an intermediary value between There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Right, I think part of the argument in this PR is that we kinda leave correct handling up to our counterparty. If we give them an HTLC which expires soon they either need to claim it ASAP or fail it ASAP, and probably shouldn't themselves forward it. This is why we use If our counterparty does take a few blocks to fail/claim the HTLC and we have to force-close, I think that speaks more to our counterparty being buggy than us. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yes, the only cases of non-buggy peers taking more than few blocks to fail/claim the HTLC are hold-invoices or Lightning Rod styles of setup. Though their inflated CLTVs are going to be encompassed within There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
I don't think that matters? By the time an invoice gets close to claimable, our counterparty needs to have failed the forwarding end on-chain so that they can do an offchain failure with us. If they don't or if they forward without enough time to do so, then they are buggy, long-CLTV or not. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Yes we agree here, this is what I meant by "should not interfere" :) |
||
// risk threshold it just results in failing to forward payments. | ||
if (*outgoing_cltv_value) as u64 <= (cur_height + LATENCY_GRACE_PERIOD_BLOCKS) as u64 { | ||
break Some(("Outgoing CLTV value is too soon", 0x1000 | 14, Some(self.get_channel_update_for_unicast(chan).unwrap()))); | ||
} | ||
|
||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Are these comment removals related to the main change? The check that was changed doesn't seem related to awaiting on a peer connection/state update..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah! Good catch - so these two things are really the same thing, but this comment was actually referring to a check in
channel
and not inchannelmanager
, even though they're the same check. I've updated the check in channel as well.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we mirror this in
ChannelManager::do_chain_event
as well? It still usesHTLC_FAIL_BACK_BUFFER
to check for timed out HTLCsThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No, that one is about our own incoming HTLCs, not forwarded ones - that is case
2
.