Skip to content

Commit 89cf906

Browse files
committed
Handle new event processing logic when enqueuing forward event
This was a regression resulting from f2453b7 since we now process events in a loop until there aren't any left. Processing events is done in batches and they are not removed until we're done processing each batch. Since handling a `PendingHTLCsForwardable` event will call back into the `ChannelManager`, we'll still see the original forwarding event not removed. Phantom payments will need an additional forwarding event before being claimed to make them look real by taking more time.
1 parent 86fd9e7 commit 89cf906

File tree

3 files changed

+55
-32
lines changed

3 files changed

+55
-32
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

+17-10
Original file line numberDiff line numberDiff line change
@@ -1978,6 +1978,8 @@ macro_rules! process_events_body {
19781978
let mut pending_events = $self.pending_events.lock().unwrap();
19791979
pending_events.drain(..num_events);
19801980
processed_all_events = pending_events.is_empty();
1981+
// Note that `push_pending_forwards_ev` relies on `pending_events_processor` being
1982+
// updated here with the `pending_events` lock acquired.
19811983
$self.pending_events_processor.store(false, Ordering::Release);
19821984
}
19831985

@@ -5613,8 +5615,8 @@ where
56135615
for (forward_info, prev_htlc_id) in pending_forwards.drain(..) {
56145616
let scid = match forward_info.routing {
56155617
PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id,
5616-
PendingHTLCRouting::Receive { .. } => 0,
5617-
PendingHTLCRouting::ReceiveKeysend { .. } => 0,
5618+
PendingHTLCRouting::Receive { .. } => { 0 },
5619+
PendingHTLCRouting::ReceiveKeysend { .. } => { 0 },
56185620
};
56195621
// Pull this now to avoid introducing a lock order with `forward_htlcs`.
56205622
let is_our_scid = self.short_to_chan_info.read().unwrap().contains_key(&scid);
@@ -5686,16 +5688,21 @@ where
56865688
}
56875689
}
56885690

5689-
// We only want to push a PendingHTLCsForwardable event if no others are queued.
56905691
fn push_pending_forwards_ev(&self) {
56915692
let mut pending_events = self.pending_events.lock().unwrap();
5692-
let forward_ev_exists = pending_events.iter()
5693-
.find(|(ev, _)| if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false })
5694-
.is_some();
5695-
if !forward_ev_exists {
5696-
pending_events.push_back((events::Event::PendingHTLCsForwardable {
5697-
time_forwardable:
5698-
Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
5693+
let is_processing_events = self.pending_events_processor.load(Ordering::Acquire);
5694+
let num_forward_events = pending_events.iter().filter(|(ev, _)|
5695+
if let events::Event::PendingHTLCsForwardable { .. } = ev { true } else { false }
5696+
).count();
5697+
// We only want to push a PendingHTLCsForwardable event if no others are queued. Processing
5698+
// events is done in batches and they are not removed until we're done processing each
5699+
// batch. Since handling a `PendingHTLCsForwardable` event will call back into the
5700+
// `ChannelManager`, we'll still see the original forwarding event not removed. Phantom
5701+
// payments will need an additional forwarding event before being claimed to make them look
5702+
// real by taking more time.
5703+
if (is_processing_events && num_forward_events <= 1) || num_forward_events < 1 {
5704+
pending_events.push_back((Event::PendingHTLCsForwardable {
5705+
time_forwardable: Duration::from_millis(MIN_HTLC_RELAY_HOLDING_CELL_MILLIS),
56995706
}, None));
57005707
}
57015708
}

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)