Skip to content

Commit 313af81

Browse files
committed
Force enqueue second forward event for phantom receives
This was a regression resulting from f2453b7 since we now process events in a loop until there aren't any left. Phantom receives rely on two calls to `ChannelManager::process_pending_htlc_forwards` before emiting the `PaymentClaimable` event, providing better privacy to make them look "real" by taking more time.
1 parent 86fd9e7 commit 313af81

File tree

3 files changed

+63
-25
lines changed

3 files changed

+63
-25
lines changed

lightning-invoice/src/utils.rs

+14-6
Original file line numberDiff line numberDiff line change
@@ -792,12 +792,13 @@ fn prefer_current_channel(min_inbound_capacity_msat: Option<u64>, current_channe
792792

793793
#[cfg(test)]
794794
mod test {
795+
use core::cell::RefCell;
795796
use core::time::Duration;
796797
use crate::{Currency, Description, InvoiceDescription, SignOrCreationError, CreationError};
797798
use bitcoin_hashes::{Hash, sha256};
798799
use bitcoin_hashes::sha256::Hash as Sha256;
799800
use lightning::sign::PhantomKeysManager;
800-
use lightning::events::{MessageSendEvent, MessageSendEventsProvider, Event};
801+
use lightning::events::{MessageSendEvent, MessageSendEventsProvider, Event, EventsProvider};
801802
use lightning::ln::{PaymentPreimage, PaymentHash};
802803
use lightning::ln::channelmanager::{PhantomRouteHints, MIN_FINAL_CLTV_EXPIRY_DELTA, PaymentId, RecipientOnionFields, Retry};
803804
use lightning::ln::functional_test_utils::*;
@@ -1357,13 +1358,20 @@ mod test {
13571358
// Note that we have to "forward pending HTLCs" twice before we see the PaymentClaimable as
13581359
// this "emulates" the payment taking two hops, providing some privacy to make phantom node
13591360
// payments "look real" by taking more time.
1360-
expect_pending_htlcs_forwardable_ignore!(nodes[fwd_idx]);
1361-
nodes[fwd_idx].node.process_pending_htlc_forwards();
1362-
expect_pending_htlcs_forwardable_ignore!(nodes[fwd_idx]);
1363-
nodes[fwd_idx].node.process_pending_htlc_forwards();
1361+
let other_events = RefCell::new(Vec::new());
1362+
let forward_event_handler = |event: Event| {
1363+
if let Event::PendingHTLCsForwardable { .. } = event {
1364+
nodes[fwd_idx].node.process_pending_htlc_forwards();
1365+
} else {
1366+
other_events.borrow_mut().push(event);
1367+
}
1368+
};
1369+
nodes[fwd_idx].node.process_pending_events(&forward_event_handler);
1370+
nodes[fwd_idx].node.process_pending_events(&forward_event_handler);
13641371

13651372
let payment_preimage_opt = if user_generated_pmt_hash { None } else { Some(payment_preimage) };
1366-
expect_payment_claimable!(&nodes[fwd_idx], payment_hash, payment_secret, payment_amt, payment_preimage_opt, invoice.recover_payee_pub_key());
1373+
assert_eq!(other_events.borrow().len(), 1);
1374+
check_payment_claimable(&other_events.borrow()[0], payment_hash, payment_secret, payment_amt, payment_preimage_opt, invoice.recover_payee_pub_key());
13671375
do_claim_payment_along_route(&nodes[0], &[&vec!(&nodes[fwd_idx])[..]], false, payment_preimage);
13681376
let events = nodes[0].node.get_and_clear_pending_events();
13691377
assert_eq!(events.len(), 2);

lightning/src/ln/channelmanager.rs

+25-3
Original file line numberDiff line numberDiff line change
@@ -5607,14 +5607,21 @@ where
56075607
fn forward_htlcs(&self, per_source_pending_forwards: &mut [(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)]) {
56085608
for &mut (prev_short_channel_id, prev_funding_outpoint, prev_user_channel_id, ref mut pending_forwards) in per_source_pending_forwards {
56095609
let mut push_forward_event = false;
5610+
let mut has_phantom_receive = false;
56105611
let mut new_intercept_events = VecDeque::new();
56115612
let mut failed_intercept_forwards = Vec::new();
56125613
if !pending_forwards.is_empty() {
56135614
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
56145615
let scid = match forward_info.routing {
56155616
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5616-
PendingHTLCRouting::Receive { .. } => 0,
5617-
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5617+
PendingHTLCRouting::Receive { .. } => {
5618+
has_phantom_receive = true;
5619+
0
5620+
},
5621+
PendingHTLCRouting::ReceiveKeysend { .. } => {
5622+
has_phantom_receive = true;
5623+
0
5624+
},
56185625
};
56195626
// Pull this now to avoid introducing a lock order with `forward_htlcs`.
56205627
let is_our_scid = self.short_to_chan_info.read().unwrap().contains_key(&scid);
@@ -5682,7 +5689,22 @@ where
56825689
let mut events = self.pending_events.lock().unwrap();
56835690
events.append(&mut new_intercept_events);
56845691
}
5685-
if push_forward_event { self.push_pending_forwards_ev() }
5692+
if push_forward_event {
5693+
let mut pending_events = self.pending_events.lock().unwrap();
5694+
let num_forward_events = pending_events.iter().filter(|(ev, _)|
5695+
if let Event::PendingHTLCsForwardable { .. } = ev { true } else { false }
5696+
).count();
5697+
// Processing events is done in batches and they are not removed until we're done
5698+
// processing each batch. Since handling a `PendingHTLCsForwardable` event will call
5699+
// back into the `ChannelManager`, we'll still see the original forwarding event not
5700+
// removed. Phantom payments will need an additional forwarding event before being
5701+
// claimed to make them look real by taking more time.
5702+
if (has_phantom_receive && num_forward_events <= 1) || num_forward_events < 1 {
5703+
pending_events.push_back((Event::PendingHTLCsForwardable {
5704+
time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
5705+
}, None));
5706+
}
5707+
}
56865708
}
56875709
}
56885710

lightning/src/ln/functional_test_utils.rs

+24-16
Original file line numberDiff line numberDiff line change
@@ -1806,6 +1806,28 @@ macro_rules! get_route_and_payment_hash {
18061806
}}
18071807
}
18081808

1809+
pub fn check_payment_claimable(
1810+
event: &Event, expected_payment_hash: PaymentHash, expected_payment_secret: PaymentSecret,
1811+
expected_recv_value: u64, expected_payment_preimage: Option<PaymentPreimage>,
1812+
expected_receiver_node_id: PublicKey,
1813+
) {
1814+
match event {
1815+
Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, .. } => {
1816+
assert_eq!(expected_payment_hash, *payment_hash);
1817+
assert_eq!(expected_recv_value, *amount_msat);
1818+
assert_eq!(expected_receiver_node_id, receiver_node_id.unwrap());
1819+
match purpose {
1820+
PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
1821+
assert_eq!(&expected_payment_preimage, payment_preimage);
1822+
assert_eq!(expected_payment_secret, *payment_secret);
1823+
},
1824+
_ => {},
1825+
}
1826+
},
1827+
_ => panic!("Unexpected event"),
1828+
}
1829+
}
1830+
18091831
#[macro_export]
18101832
#[cfg(any(test, ldk_bench, feature = "_test_utils"))]
18111833
macro_rules! expect_payment_claimable {
@@ -1815,22 +1837,8 @@ macro_rules! expect_payment_claimable {
18151837
($node: expr, $expected_payment_hash: expr, $expected_payment_secret: expr, $expected_recv_value: expr, $expected_payment_preimage: expr, $expected_receiver_node_id: expr) => {
18161838
let events = $node.node.get_and_clear_pending_events();
18171839
assert_eq!(events.len(), 1);
1818-
match events[0] {
1819-
$crate::events::Event::PaymentClaimable { ref payment_hash, ref purpose, amount_msat, receiver_node_id, .. } => {
1820-
assert_eq!($expected_payment_hash, *payment_hash);
1821-
assert_eq!($expected_recv_value, amount_msat);
1822-
assert_eq!($expected_receiver_node_id, receiver_node_id.unwrap());
1823-
match purpose {
1824-
$crate::events::PaymentPurpose::InvoicePayment { payment_preimage, payment_secret, .. } => {
1825-
assert_eq!(&$expected_payment_preimage, payment_preimage);
1826-
assert_eq!($expected_payment_secret, *payment_secret);
1827-
},
1828-
_ => {},
1829-
}
1830-
},
1831-
_ => panic!("Unexpected event"),
1832-
}
1833-
}
1840+
$crate::ln::functional_test_utils::check_payment_claimable(&events[0], $expected_payment_hash, $expected_payment_secret, $expected_recv_value, $expected_payment_preimage, $expected_receiver_node_id)
1841+
};
18341842
}
18351843

18361844
#[macro_export]

0 commit comments

Comments
 (0)