-
Notifications
You must be signed in to change notification settings - Fork 376
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
Add a PaymentForwarded
Event
#1004
Add a PaymentForwarded
Event
#1004
Conversation
Codecov Report
@@ Coverage Diff @@
## main #1004 +/- ##
==========================================
- Coverage 90.81% 90.79% -0.03%
==========================================
Files 60 61 +1
Lines 31428 31578 +150
==========================================
+ Hits 28542 28671 +129
- Misses 2886 2907 +21
Continue to review full report at Codecov.
|
7cd334a
to
25379af
Compare
clients cannot read. The likelihood of this can be reduced by ensuring you | ||
process all pending events immediately before serialization. | ||
|
||
|
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.
Mentions e00bf8d serialization relaxation? Maybe we'll have users eager to experiment with the odd type semantic
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.
I don't believe you can currently (reasonably) serialize events in a way that LDK cares about - I believe we only (really) read them as a part of a ChannelManager
or ChannelMonitor
, so in order for users to get anything out of it they'd need to be editing ChannelManager
s in the middle of the serialization logic.
lightning/src/util/events.rs
Outdated
/// | ||
/// If the channel which sent us the payment has been force-closed, we will claim the funds | ||
/// via an on-chain transaction. In that case we do not consider the on-chain transaction | ||
/// fees involved in such a claim and this value will be `None`. |
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.
Wait I think a onchain_value_satoshis
value is passed in process_pending_monitor_events
and consumed as part of the generated PaymentForwarded
there ? Or are you thinking about another case ?
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.
Wait, I'm confused, those are only about claims that our counterparty did on-chain, causing us to update off-chain state. Did I miss something about how HTLCUpdate
events are generated?
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.
I think Antoine's right, seems like this will always be non-None
with the current code?
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.
If claim_funds_from_hop
hits the short_to_id.get(..) == None
branch right at the top, it'll return (None, Err(None))
which gets translated into our ChannelMonitorUpdate
-generation branch, but should still consider claimed_htlc
to be true, resulting in claimed_value_msat
being None
.
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.
You say this value can be None
in the case where the backward channel has been force-closed and we won't fetch the claimed amount from onchain, thus only yielding None
as earned fees. So IIUC, I think it's confusing to say "on-chain transaction fees", it should say "amount" or values" ?
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.
See updated doc commit, is that sufficient?
Rebase plz |
The wait_threshold_conf!() macro in check_spend_holder_transaction was only used once, making it a good candidate for inlining at the callsite. Further, it incorrectly always logged that we were failing HTLCs from the "latest" commitment transaction, when it is sometimes actually failing HTLCs from the previous commitment transaction.
This should provide some additional future extensibility, allowing for new informational events which can be safely ignored to be ignored by older versions.
test_onchain_to_onchain_claim was connecting additional blocks in order to reach HTLC timeout and broadcast an HTLC-Timeout transaction, resulting in it not testing whether HTLC preimages are learned instantly in response to HTLC-Success transactions.
25379af
to
997899d
Compare
Rebased. |
if claimed_htlc { | ||
if let Some(forwarded_htlc_value) = forwarded_htlc_value_msat { | ||
let fee_earned_msat = if let Some(claimed_htlc_value) = claimed_value_msat { | ||
Some(claimed_htlc_value - forwarded_htlc_value) |
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.
No risk/need for mitigation of overflow here, right?
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.
I think not, my logic is this:
- for only-off-chain forwards + claims, the
fee_insufficient
check indecode_update_add_htlc_onion
should preventforwarded_htlc_value
from ever being belowclaimed_htlc_value
(obviously if it ever did happen that would be a massive bug anyway), - for on-chain claims leading to a backwards off-chain claim,
claimed_htlc_value
will always be the original received value, whereasforwarded_htlc_value
can only decrease (as its rounded down to the nearest whole satoshi value), so the above applies. - we do not get here for off-chain claims leading to a backwards on-chain claim, which would be possible to underflow on.
lightning/src/util/events.rs
Outdated
fee_earned_msat: Option<u64>, | ||
/// If this is `true`, the forwarded HTLC was claimed on-chain after a force-closure. | ||
claim_from_onchain_tx: bool, |
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.
Could these be combined into an enum, something like:
ForwardClaim::OnChain
ForwardClaim::OffChain(fee_earned_msat: u64)
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.
They are two separate concepts - one is about the forward edge of the HTLC, the other is about the backwards edge of the HTLC. Any suggestions for how to make the docs more clear?
lightning/src/util/events.rs
Outdated
/// | ||
/// If the channel which sent us the payment has been force-closed, we will claim the funds | ||
/// via an on-chain transaction. In that case we do not consider the on-chain transaction | ||
/// fees involved in such a claim and this value will be `None`. |
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.
I think Antoine's right, seems like this will always be non-None
with the current code?
lightning/src/ln/channelmanager.rs
Outdated
@@ -207,6 +207,12 @@ pub(super) enum HTLCFailReason { | |||
} | |||
} | |||
|
|||
/// Return value for claim_funds_from_hop | |||
struct ClaimFundsRes { |
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.
Could we switch this to be an enum, something along these lines:
enum ClaimFundsRes {
PrevHopForceClosed,
MonitorUpdateFailed((u64, PublicKey, MsgHandleErrInternal)),
... other states
}
This refactor is @jkczyz -approved 😛
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.
Hmm, I'm not sure that that's that much clearer. All four possible states of (None, Ok(..))
, (Some(..), Ok(..))
, (None, Err(..))
, and (Some(..), Err(..))
are used, so we'd need at least four variants, and we'd have a really hard time keeping the callsite match
DRY.
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.
IMO seeing a descriptive name like PrevHopForceClosed
makes the code more readable at a glance than seeing (None, Ok(..))
.
It seems like the callsite might only need to repeat a few lines? Is that off?
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.
I mean I can split it into a struct containing two enums, but that seems to border on enough volume that it becomes unreadable just by weight. Sticking it all in one enum (with four variants) would be really harsh for claim-funds
, too, which only actually cares about one of the two fields, now it would have to have a match and conversion instead of being able to just access the field. I agree having names for things is useful, but I don't think I agree it is if it results in more code by volume including matches that the reader has to figure out. Maybe there's a way to rename the fields in ClaimFundsRes
to make it more clear instead?
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.
Briefly jammed with @jkczyz on this patch: valentinewallace@f9d338d It seems more readable and the code volume doesn't seem significantly increased!
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.
Yea, I guess I underestimated the amount of parameter conversion in the current code. I do think the MonitorUpdateFail
overload that can mean both "channel is bogus, closing" and Success
, we claimed is a bit confusing, but its not strictly worse than it was. I took that commit and added one tweak.
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.
build is sad
Pretty much good with this PR!
lightning/src/util/events.rs
Outdated
/// fees involved in such a claim and this value will be `None`. It is possible duplicate | ||
/// `PaymentForwarded` events are generated for the same payment iff `fee_earned_msat` is | ||
/// `None`. |
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.
Because duplicates may be generated, could a (future?) direction be to add some kind of unique identifier of the HTLC to this event?
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.
Yea, what we'd really need to do is have the event be generated by the ChannelMonitor
if the inbound leg of the payment has gone on-chain, but there's a lot of complexity to ensuring we de-duplicate them all properly that we don't currently do that I figured it wasn't worth it for now.
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.
Yeah we could return either a monotonic payment_id or PaymentHash
at least.
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.
or
PaymentHash
at least.
I'm a little torn on this. I initially didn't include it on purpose because, at least my thinking was, we really dont want users to log that or even care about it - its not their payment, and logging/giving users details about the payments others made (at least the parts that don't matter to you) is generally a bad idea.
On the other hand, I see the point about wanting to de-dup by them, but of course note that you can have the same PaymentHash
multiple times, even if its insecure.
Ultimately I think adding PaymentHash
is just not more confusing than helpful, especially since users may try to de-duplicate by it and have bad accounting, much better to just say you will have bad accounting, and leave it at that.
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.
Right, we already have case where accounting might not be exact like rouding down or backward channel closed and where fee_earned_msat
is None
. We can revisit in the future if needed.
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.
SGTM once build is fixed
9a6398d
to
eebb0d1
Compare
lol it was working locally. Anyway, I just dropped the whole partialeq thing. Also went ahead and squashed. |
lightning/src/util/events.rs
Outdated
/// fees involved in such a claim and this value will be `None`. It is possible duplicate | ||
/// `PaymentForwarded` events are generated for the same payment iff `fee_earned_msat` is | ||
/// `None`. |
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.
Yeah we could return either a monotonic payment_id or PaymentHash
at least.
lightning/src/util/events.rs
Outdated
/// `None`. | ||
fee_earned_msat: Option<u64>, | ||
/// If this is `true`, the forwarded HTLC will be claimed on-chain after the channel on | ||
/// which we received the HTLC was force-closed. |
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.
I think claim_funds_internal()
in process_pending_monitor_events
is called with from_onchain=true. Though this callsite at monitor events processing doesn't imply the backward channel has been force-closed, a check we only realize at the beginning of claim_funds_from_hop
.
So I think this comment is confusing...Shouldn't this say "we offered the HTLC was force-closed" to be correct ?
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.
Lol, these docs are just entirely wrong. I pushed a fixup commit.
b9dab4e
to
90c5d00
Compare
Pushed an additional doc change commit to take changes from @ariard. |
Code Review ACK 90c5d00 |
It is useful for accounting and informational reasons for users to be informed when a payment has been successfully forwarded. Thus, when an HTLC which represents a forwarded leg is claimed, we generate a new `PaymentForwarded` event. This requires some additional plumbing to return HTLC values from `OnchainEvent`s. Further, when we have to go on-chain to claim the inbound side of the payment, we do not inform the user of the fee reward, as we cannot calculate it until we see what is confirmed on-chain. Substantial code structure rewrites by: Valentine Wallace <[email protected]>
While we should never reach `ClaimFundsFromHop::DuplicateClaim` in most cases, if we do, it likely indicates the HTLC was timed out some time ago and is no longer available to be claimed. Thus, it does not make sense to imply that we `claimed_any_htlcs`.
90c5d00
to
50f47ec
Compare
Squashed without changes. Diff since Val's review is all docs, so will merge after CI.
|
Based on #977.
It is useful for accounting and informational reasons for users to
be informed when a payment has been successfully forwarded. Thus,
when an HTLC which represents a forwarded leg is claimed, we
generate a new
PaymentForwarded
event.This requires some additional plumbing to return HTLC values from
OnchainEvent
s. Further, when we have to go on-chain to claim theinbound side of the payment, we do not inform the user of the fee
reward, as we cannot calculate it until we see what is confirmed
on-chain.