Skip to content

Commit d03d6a8

Browse files
committed
Remove inflight HTLC value from map on PaymentPathFailed/Successful
When processing a `PaymentPathSuccessful` event, the associated inflight HTLC value is subtracted from the map, `total_inflight_map`. On `PaymentPathFailed`, when a payment is abandoned, we subtract the previously-inflight value from any existing records in the map. Remove need to explicitly drop locks
1 parent ae6f582 commit d03d6a8

File tree

1 file changed

+60
-2
lines changed

1 file changed

+60
-2
lines changed

lightning-invoice/src/payment.rs

Lines changed: 60 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -517,6 +517,23 @@ where
517517
}
518518
}
519519

520+
fn remove_path_inflight_htlcs(&self, hops: &Vec<RouteHop>) {
521+
// Here, just like `process_path_inflight_htlcs`, we are given a vector of hops that excludes
522+
// any information about the payer. However, in our `total_inflight_map`, we keep track
523+
// of possible inbound/outbound liquidity from the payer as well. Therefore, it is accounted
524+
// for by hard-coding the same tuple as in `process_path_inflight_htlcs`
525+
let our_node_id: PublicKey = self.payer.node_id();
526+
let hops_with_us = core::iter::once((0u64, our_node_id)).chain(hops.iter().map(|hop| (hop.fee_msat, hop.pubkey)));
527+
528+
for (next_hop, prev_hop) in hops.iter().zip(hops_with_us) {
529+
println!("Subtracting {} inflight msats from {}", next_hop.fee_msat, next_hop.short_channel_id);
530+
self.total_inflight_map.lock().unwrap()
531+
.entry((next_hop.short_channel_id, next_hop.pubkey < prev_hop.1))
532+
.and_modify(|used_liquidity_msat| *used_liquidity_msat = used_liquidity_msat.saturating_sub(next_hop.fee_msat) )
533+
.or_insert(0);
534+
}
535+
}
536+
520537
fn retry_payment(
521538
&self, payment_id: PaymentId, payment_hash: PaymentHash, params: &RouteParameters
522539
) -> Result<(), ()> {
@@ -613,22 +630,26 @@ where
613630
} else if *rejected_by_dest {
614631
log_trace!(self.logger, "Payment {} rejected by destination; not retrying", log_bytes!(payment_hash.0));
615632
self.payer.abandon_payment(payment_id.unwrap());
633+
self.remove_path_inflight_htlcs(path);
616634
} else if retry.is_none() {
617635
log_trace!(self.logger, "Payment {} missing retry params; not retrying", log_bytes!(payment_hash.0));
618636
self.payer.abandon_payment(payment_id.unwrap());
637+
self.remove_path_inflight_htlcs(path);
619638
} else if self.retry_payment(payment_id.unwrap(), *payment_hash, retry.as_ref().unwrap()).is_ok() {
620639
// We retried at least somewhat, don't provide the PaymentPathFailed event to the user.
621640
return;
622641
} else {
623642
self.payer.abandon_payment(payment_id.unwrap());
643+
self.remove_path_inflight_htlcs(path);
624644
}
625645
},
626646
Event::PaymentFailed { payment_hash, .. } => {
627647
self.remove_cached_payment(&payment_hash);
628648
},
629649
Event::PaymentPathSuccessful { path, .. } => {
630-
let path = path.iter().collect::<Vec<_>>();
631-
self.scorer.lock().payment_path_successful(&path);
650+
let path_with_refs = path.iter().collect::<Vec<_>>();
651+
self.scorer.lock().payment_path_successful(&path_with_refs);
652+
self.remove_path_inflight_htlcs(path);
632653
},
633654
Event::PaymentSent { payment_hash, .. } => {
634655
let mut payment_cache = self.payment_cache.lock().unwrap();
@@ -766,11 +787,32 @@ mod tests {
766787
let payment_id = Some(invoice_payer.pay_invoice(&invoice).unwrap());
767788
assert_eq!(*payer.attempts.borrow(), 1);
768789

790+
{
791+
let inflight_map = invoice_payer.total_inflight_map.lock().unwrap();
792+
// TestRouter returns two hops, with `fee_msat` divided by two. The invoice instantiated above
793+
// is hard-coded to test sending an invoice with a value of 128 msats.
794+
assert_eq!(inflight_map.get(&(0, true)).unwrap().clone(), 64);
795+
assert_eq!(inflight_map.get(&(1, true)).unwrap().clone(), 64);
796+
}
797+
769798
invoice_payer.handle_event(&Event::PaymentSent {
770799
payment_id, payment_preimage, payment_hash, fee_paid_msat: None
771800
});
772801
assert_eq!(*event_handled.borrow(), true);
773802
assert_eq!(*payer.attempts.borrow(), 1);
803+
804+
invoice_payer.handle_event(&Event::PaymentPathSuccessful {
805+
payment_id: payment_id.unwrap(), payment_hash: Some(payment_hash),
806+
path: TestRouter::route_for_value(final_value_msat).paths[0].clone()
807+
});
808+
invoice_payer.handle_event(&Event::PaymentPathSuccessful {
809+
payment_id: payment_id.unwrap(), payment_hash: Some(payment_hash),
810+
path: TestRouter::route_for_value(final_value_msat).paths[1].clone()
811+
});
812+
813+
let inflight_map = invoice_payer.total_inflight_map.lock().unwrap();
814+
assert_eq!(inflight_map.get(&(0, true)).unwrap().clone(), 0);
815+
assert_eq!(inflight_map.get(&(1, true)).unwrap().clone(), 0);
774816
}
775817

776818
#[test]
@@ -808,12 +850,28 @@ mod tests {
808850
invoice_payer.handle_event(&event);
809851
assert_eq!(*event_handled.borrow(), false);
810852
assert_eq!(*payer.attempts.borrow(), 2);
853+
let inflight_map = invoice_payer.total_inflight_map.lock().unwrap();
854+
assert_eq!(inflight_map.get(&(0, true)).unwrap().clone(), 64);
855+
assert_eq!(inflight_map.get(&(1, true)).unwrap().clone(), 64);
856+
drop(inflight_map);
811857

812858
invoice_payer.handle_event(&Event::PaymentSent {
813859
payment_id, payment_preimage, payment_hash, fee_paid_msat: None
814860
});
815861
assert_eq!(*event_handled.borrow(), true);
816862
assert_eq!(*payer.attempts.borrow(), 2);
863+
864+
invoice_payer.handle_event(&Event::PaymentPathSuccessful {
865+
payment_id: payment_id.unwrap(), payment_hash: Some(payment_hash),
866+
path: TestRouter::route_for_value(final_value_msat).paths[0].clone()
867+
});
868+
invoice_payer.handle_event(&Event::PaymentPathSuccessful {
869+
payment_id: payment_id.unwrap(), payment_hash: Some(payment_hash),
870+
path: TestRouter::route_for_value(final_value_msat).paths[1].clone()
871+
});
872+
let inflight_map = invoice_payer.total_inflight_map.lock().unwrap();
873+
assert_eq!(inflight_map.get(&(0, true)).unwrap().clone(), 0);
874+
assert_eq!(inflight_map.get(&(1, true)).unwrap().clone(), 0);
817875
}
818876

819877
#[test]

0 commit comments

Comments
 (0)