-
Notifications
You must be signed in to change notification settings - Fork 373
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
Allow forwarding less than the amount in the onion #2319
Allow forwarding less than the amount in the onion #2319
Conversation
ad259dd
to
2a07438
Compare
Codecov ReportPatch coverage:
❗ Your organization is not using the GitHub App Integration. As a result you may experience degraded service beginning May 15th. Please install the Github App Integration for your organization. Read more. Additional details and impacted files@@ Coverage Diff @@
## main #2319 +/- ##
==========================================
+ Coverage 90.35% 90.50% +0.15%
==========================================
Files 106 106
Lines 54347 59105 +4758
Branches 54347 59105 +4758
==========================================
+ Hits 49105 53494 +4389
- Misses 5242 5611 +369
☔ View full report in Codecov by Sentry. |
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.
At first glance this basically looks good I think.
2a07438
to
a1cbf67
Compare
I removed phantom support for now. |
a1cbf67
to
db93d1b
Compare
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.
Nice!
lightning/src/ln/channelmanager.rs
Outdated
@@ -3760,6 +3812,7 @@ where | |||
payment_hash, | |||
purpose: purpose(), | |||
amount_msat, | |||
counterparty_skimmed_fee_msat: total_value.saturating_sub(amount_msat), |
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.
In the case where a counterparty overshoots the amount in the onion, I think this would report the skimmed fee inaccurately? E.g. the counterparty_skimmed_fee_msat
would be offset by amount_msat - total_value
. It probably wouldn't happen very often and the offset probably wouldn't be much, but figured I'd still make note of it.
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, I think this field will be inaccurate if some non-penultimate intermediate node took took less fee than intended by the sender (if I understand you correctly), but I'm not sure if we're able to detect that? IIUC we only have sender_intended_total
and actual_received_total
to work off of here, though might be missing something.
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 it'd be possible by adding the skimmed fee to PendingHTLCRouting::Receive
/ReceiveKeysend
(which seems possible since the skimmed fee gets sent through construct_recv_pending_htlc_info
), and then probably keeping this on ClaimableHTLC
and using those when finally calculating? Not sure if it's worth trying to fit it in here, could maybe be followup
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 think this would be nice, otherwise an intermediary node can cause a payment to fail by not taking enough fee? Its not itself a super big deal, but I think you could use it to figure out if the destination node is an LSP Client and if so a recent one - eg if you have a guess that the ultimate node is one further than some large LSP you could short yourself 1 msat and see if the payment fails to see if its an LSP client or just a routing node peer?
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.
Nice catch! Fixed. I didn't want to just trust whatever the counterparty set as the skimmed fee since they could technically lie about that, so it's now a mix of the previous and new solution, PTAL.
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.
Looks good to me after a quick initial pass.
I wonder if it would be nice to also expose the counterparty_skimmed_fee_msat
field via PaymentClaimed
?
db93d1b
to
ca293bd
Compare
Added a TODO for this to #1999 |
Feel free to squash IMO. |
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.
Will need a small rebase after #2077
lightning/src/ln/channelmanager.rs
Outdated
@@ -3760,6 +3812,7 @@ where | |||
payment_hash, | |||
purpose: purpose(), | |||
amount_msat, | |||
counterparty_skimmed_fee_msat: total_value.saturating_sub(amount_msat), |
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 think this would be nice, otherwise an intermediary node can cause a payment to fail by not taking enough fee? Its not itself a super big deal, but I think you could use it to figure out if the destination node is an LSP Client and if so a recent one - eg if you have a guess that the ultimate node is one further than some large LSP you could short yourself 1 msat and see if the payment fails to see if its an LSP client or just a routing node peer?
lightning/src/ln/channelmanager.rs
Outdated
onion_packet, | ||
short_channel_id: next_hop_scid, | ||
skimmed_fee_msat: | ||
// The minuend here must match the expected forward amount generated for the |
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.
TIL what minuend means.
lightning/src/ln/channelmanager.rs
Outdated
skimmed_fee_msat: | ||
// The minuend here must match the expected forward amount generated for the | ||
// HTLCIntercepted event. | ||
Some(payment.forward_info.outgoing_amt_msat.saturating_sub(amt_to_forward_msat)), |
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.
This should be None
if we're not subtracting anything. Also do we want to fail if the resulting amount is zero?
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.
Switched to None
. I don't think we should fail if we forward more than expected, since the docs already say we allow this?
ca293bd
to
8370444
Compare
Rebased on #2077 to get a head start on rebase conflicts. |
45a7180
to
703b03a
Compare
703b03a
to
1c63f20
Compare
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.
LGTM, one real comment and a nit, feel free to squash.
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.
LGTM I think!
/// # Note | ||
/// It's important for payee wallet software to verify that [`PaymentClaimable::amount_msat`] is | ||
/// as-expected if this feature is activated, otherwise they may lose money! | ||
/// [`PaymentClaimable::counterparty_skimmed_fee_msat`] provides the fee taken by the | ||
/// counterparty. |
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.
Not sure if it's worth mentioning here or is maybe more fit for an LSP client spec, but I think the attack described in #2319 (comment) is still possible if the payee fails a payment based on the skimmed fee being too high instead of just checking amount_msat
and that the sum of amount_msat + counterparty_skimmed_fee_msat
add up to at least what they expected. The docs here already only say to check amount_msat
so I think it's probably fine as is but figured I'd still make note of it :)
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 think so? If the fee skimmed is too high that means the immediately-prior node took too much, if a node prior to that in the path took too much it should result in the second-to-last hop taking too little (if they're taking a percentage fee).
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.
Oh my bad, for some reason I was thinking intermediate nodes could still affect the final skimmed fee but that was fixed, oops
646a030
to
134e631
Compare
We need the channel lock for constructing a pending HTLC's status because we need to know if the channel accepts underpaying HTLCs in upcoming commits.
See ChannelConfig::accept_underpaying_htlcs
Receivers need to use this value to verify incoming payments if ChannelConfig::accept_underpaying_htlcs is set.
Used to get an accurate skimmed fee in the resulting PaymentClaimable event.
Useful for penultimate hops in routes to take an extra fee, if for example they opened a JIT channel to the payee and want them to help bear the channel open cost.
So the receiver can verify it and approve underpaying HTLCs (see ChannelConfig::accept_underpaying_htlcs).
Make sure the penultimate hop took the amount of fee that they claimed to take. Without checking this TLV, we're heavily relying on the receiving wallet code to correctly implement logic to calculate that that the fee is as expected.
134e631
to
2127eb8
Compare
Squashed. |
@@ -2984,7 +3032,7 @@ where | |||
session_priv: session_priv.clone(), | |||
first_hop_htlc_msat: htlc_msat, | |||
payment_id, | |||
}, onion_packet, &self.logger); | |||
}, onion_packet, None, &self.logger); |
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.
We probably need, as a followup, to support setting this - if you're an LSP and want to be the first payment to a given client you'll need it to take a fee on the first hop. Ideally we'd have something to handle that, but right now I don't think we will let you "just" send a payment to an intercept SCID, which we may consider.
Support skimming an additional fee off of intercepted HTLCs, per lightning/blips#25.
V1 of addressing #1999
Based on #2305