Skip to content
This repository was archived by the owner on Jan 6, 2025. It is now read-only.

Commit 9339a10

Browse files
authored
Merge pull request #102 from johncantrell97/fix-prepayment-probing
fix prepayment probing by sequencing subsequent payments
2 parents 8809ab1 + 97f5282 commit 9339a10

File tree

4 files changed

+931
-114
lines changed

4 files changed

+931
-114
lines changed

src/lsps2/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,5 +12,6 @@
1212
pub mod client;
1313
pub mod event;
1414
pub mod msgs;
15+
pub(crate) mod payment_queue;
1516
pub mod service;
1617
pub mod utils;

src/lsps2/payment_queue.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
use crate::prelude::Vec;
2+
use lightning::ln::channelmanager::InterceptId;
3+
use lightning::ln::PaymentHash;
4+
5+
/// Holds payments with the corresponding HTLCs until it is possible to pay the fee.
6+
/// When the fee is successfully paid with a forwarded payment, the queue should be consumed and the
7+
/// remaining payments forwarded.
8+
#[derive(Clone, PartialEq, Eq, Debug)]
9+
pub(crate) struct PaymentQueue {
10+
payments: Vec<(PaymentHash, Vec<InterceptedHTLC>)>,
11+
}
12+
13+
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
14+
pub(crate) struct InterceptedHTLC {
15+
pub(crate) intercept_id: InterceptId,
16+
pub(crate) expected_outbound_amount_msat: u64,
17+
pub(crate) payment_hash: PaymentHash,
18+
}
19+
20+
impl PaymentQueue {
21+
pub(crate) fn new() -> PaymentQueue {
22+
PaymentQueue { payments: Vec::new() }
23+
}
24+
25+
pub(crate) fn add_htlc(&mut self, new_htlc: InterceptedHTLC) -> (u64, usize) {
26+
let payment = self.payments.iter_mut().find(|(p, _)| p == &new_htlc.payment_hash);
27+
if let Some((payment_hash, htlcs)) = payment {
28+
// HTLCs within a payment should have the same payment hash.
29+
debug_assert!(htlcs.iter().all(|htlc| htlc.payment_hash == *payment_hash));
30+
// The given HTLC should not already be present.
31+
debug_assert!(htlcs.iter().all(|htlc| htlc.intercept_id != new_htlc.intercept_id));
32+
htlcs.push(new_htlc);
33+
let total_expected_outbound_amount_msat =
34+
htlcs.iter().map(|htlc| htlc.expected_outbound_amount_msat).sum();
35+
(total_expected_outbound_amount_msat, htlcs.len())
36+
} else {
37+
let expected_outbound_amount_msat = new_htlc.expected_outbound_amount_msat;
38+
self.payments.push((new_htlc.payment_hash, vec![new_htlc]));
39+
(expected_outbound_amount_msat, 1)
40+
}
41+
}
42+
43+
pub(crate) fn pop_greater_than_msat(
44+
&mut self, amount_msat: u64,
45+
) -> Option<(PaymentHash, Vec<InterceptedHTLC>)> {
46+
let position = self.payments.iter().position(|(_payment_hash, htlcs)| {
47+
htlcs.iter().map(|htlc| htlc.expected_outbound_amount_msat).sum::<u64>() >= amount_msat
48+
});
49+
position.map(|position| self.payments.remove(position))
50+
}
51+
52+
pub(crate) fn clear(&mut self) -> Vec<InterceptedHTLC> {
53+
self.payments.drain(..).map(|(_k, v)| v).flatten().collect()
54+
}
55+
}
56+
57+
#[cfg(test)]
58+
mod tests {
59+
use super::*;
60+
61+
#[test]
62+
fn test_payment_queue() {
63+
let mut payment_queue = PaymentQueue::new();
64+
assert_eq!(
65+
payment_queue.add_htlc(InterceptedHTLC {
66+
intercept_id: InterceptId([0; 32]),
67+
expected_outbound_amount_msat: 200_000_000,
68+
payment_hash: PaymentHash([100; 32]),
69+
}),
70+
(200_000_000, 1),
71+
);
72+
assert_eq!(payment_queue.pop_greater_than_msat(500_000_000), None);
73+
74+
assert_eq!(
75+
payment_queue.add_htlc(InterceptedHTLC {
76+
intercept_id: InterceptId([1; 32]),
77+
expected_outbound_amount_msat: 300_000_000,
78+
payment_hash: PaymentHash([101; 32]),
79+
}),
80+
(300_000_000, 1),
81+
);
82+
assert_eq!(payment_queue.pop_greater_than_msat(500_000_000), None);
83+
84+
assert_eq!(
85+
payment_queue.add_htlc(InterceptedHTLC {
86+
intercept_id: InterceptId([2; 32]),
87+
expected_outbound_amount_msat: 300_000_000,
88+
payment_hash: PaymentHash([100; 32]),
89+
}),
90+
(500_000_000, 2),
91+
);
92+
assert_eq!(
93+
payment_queue.pop_greater_than_msat(500_000_000),
94+
Some((
95+
PaymentHash([100; 32]),
96+
vec![
97+
InterceptedHTLC {
98+
intercept_id: InterceptId([0; 32]),
99+
expected_outbound_amount_msat: 200_000_000,
100+
payment_hash: PaymentHash([100; 32]),
101+
},
102+
InterceptedHTLC {
103+
intercept_id: InterceptId([2; 32]),
104+
expected_outbound_amount_msat: 300_000_000,
105+
payment_hash: PaymentHash([100; 32]),
106+
},
107+
]
108+
))
109+
);
110+
assert_eq!(
111+
payment_queue.clear(),
112+
vec![InterceptedHTLC {
113+
intercept_id: InterceptId([1; 32]),
114+
expected_outbound_amount_msat: 300_000_000,
115+
payment_hash: PaymentHash([101; 32]),
116+
}]
117+
);
118+
}
119+
}

0 commit comments

Comments
 (0)