Fix missing PaymentSent::fee_paid_msat#4651
Conversation
|
👋 Thanks for assigning @TheBlueMatt as a reviewer! |
Review SummaryIssue found
DetailsThe core fix (preserving The new test only covers a single-path payment, so it doesn't exercise this edge case. |
|
Fuzz failure looks pre-existing, seems to error with "Expected disconnect" |
|
🔔 1st Reminder Hey @tankyleo! This PR has been waiting for your review. |
| if let Some(max_total_routing_fee_msat) = remaining_max_total_routing_fee_msat.as_mut() { | ||
| *max_total_routing_fee_msat = max_total_routing_fee_msat.saturating_add(path_fee_msat); | ||
| } | ||
| } else if let PendingOutboundPayment::Abandoned { pending_fee_msat, .. } = self { |
There was a problem hiding this comment.
In this block should we also subtract path.final_value_msat() from total_msat so that PaymentSent reports the amount that was actually sent ?
There was a problem hiding this comment.
I removed this block. If we go in this direction, we're starting to handle surfacing correct amounts/fees in the case that the recipient gave us the preimage without us paying them the full amount we originally intended. IIUC this indicates a very buggy recipient and is not a case we handle in PendingOutboundPayment::Fulfilled either, so a more "real" fix would be a larger change and probably not worth it. Similar applies to the below comment.
| @@ -318,6 +324,7 @@ impl PendingOutboundPayment { | |||
| payment_hash: *payment_hash, | |||
| reason: Some(reason), | |||
| total_msat, | |||
There was a problem hiding this comment.
curious here if we should be setting this to the sum of the current paths currently in-flight, and not the fixed total msat ?
If an outbound payment was abandoned with htlcs in-flight and later claimed, we would previously have the PaymentSent::fee_paid_msat be set to None. This contradicted some docs on the event that stated the field would always be Some after 0.0.103.
fb34479 to
3e9e6e9
Compare
| total_msat: Option<u64>, | ||
| /// Preserved from `Retryable` so we can still report `fee_paid_msat` if an HTLC succeeds after | ||
| /// the payment was abandoned. Added in 0.3. | ||
| pending_fee_msat: Option<u64>, |
There was a problem hiding this comment.
Bug: remove() (line 335) only decrements pending_fee_msat for the Retryable variant, not for Abandoned. This means if an MPP payment is manually abandoned with multiple paths in-flight, and then some paths fail back while others succeed, the fee for the failed paths won't be subtracted — causing PaymentSent::fee_paid_msat to be overstated.
Concrete scenario:
- Two-path MPP, path A (fee=100) and path B (fee=200) in-flight →
pending_fee_msat = Some(300) abandon_payment()→Abandoned { pending_fee_msat: Some(300) }- Path A fails (intermediate node timeout) →
remove()removes session_priv but doesn't decrement fee →pending_fee_msatstillSome(300) - Path B succeeds (recipient claims) →
PaymentSent { fee_paid_msat: Some(300) }— should beSome(200)
The remove() function at line 348-363 needs an additional branch for Abandoned:
if let PendingOutboundPayment::Abandoned {
ref mut pending_fee_msat, ..
} = self {
let path = path.expect("Removing a failed payment should always come with a path");
if let Some(fee_msat) = pending_fee_msat.as_mut() {
*fee_msat -= path.fee_msat();
}
}Note: for the auto-abandon path (in handle_update_fail_htlc), remove() is called before mark_abandoned(), so the fee is correctly captured. This bug only affects the manual-abandon path and any future failures arriving after auto-abandonment.
If an outbound payment was abandoned with htlcs in-flight and later claimed, we would previously have the
PaymentSent::fee_paid_msatbe set toNone. This contradicted some docs on the event that stated the field would always beSomeafter 0.0.103.Fixes #4639