@@ -47,7 +47,7 @@ use crate::blinded_path::IntroductionNode;
47
47
use crate :: blinded_path:: message:: BlindedMessagePath ;
48
48
use crate :: blinded_path:: payment:: { Bolt12OfferContext , Bolt12RefundContext , PaymentContext } ;
49
49
use crate :: blinded_path:: message:: { MessageContext , OffersContext } ;
50
- use crate :: events:: { Event , MessageSendEventsProvider , PaymentFailureReason , PaymentPurpose } ;
50
+ use crate :: events:: { ClosureReason , Event , MessageSendEventsProvider , PaymentFailureReason , PaymentPurpose } ;
51
51
use crate :: ln:: channelmanager:: { Bolt12PaymentError , MAX_SHORT_LIVED_RELATIVE_EXPIRY , PaymentId , RecentPaymentDetails , Retry , self } ;
52
52
use crate :: ln:: features:: Bolt12InvoiceFeatures ;
53
53
use crate :: ln:: functional_test_utils:: * ;
@@ -64,6 +64,7 @@ use crate::onion_message::offers::OffersMessage;
64
64
use crate :: onion_message:: packet:: ParsedOnionMessageContents ;
65
65
use crate :: routing:: gossip:: { NodeAlias , NodeId } ;
66
66
use crate :: sign:: { NodeSigner , Recipient } ;
67
+ use crate :: util:: ser:: Writeable ;
67
68
68
69
use crate :: prelude:: * ;
69
70
@@ -2253,3 +2254,92 @@ fn fails_paying_invoice_with_unknown_required_features() {
2253
2254
_ => panic ! ( "Expected Event::PaymentFailed with reason" ) ,
2254
2255
}
2255
2256
}
2257
+
2258
+ #[ test]
2259
+ fn no_double_pay_with_stale_channelmanager ( ) {
2260
+ // This tests the following bug:
2261
+ // - An outbound payment is AwaitingInvoice
2262
+ // - We receive an invoice and lock the HTLCs into the relevant ChannelMonitors
2263
+ // - The monitors are successfully persisted, but the ChannelManager fails to persist, so the
2264
+ // payment remains AwaitingInvoice
2265
+ // - We restart, causing the channels to close due to a stale ChannelManager
2266
+ // - We receive a duplicate invoice, and attempt to pay it again due to the payment still being
2267
+ // AwaitingInvoice in the stale ChannelManager
2268
+ // After the fix for this, we will notice that the payment is already locked into the monitors on
2269
+ // startup and transition the incorrectly-AwaitingInvoice payment to Retryable, which prevents
2270
+ // double-paying on duplicate invoice receipt.
2271
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
2272
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
2273
+ let persister;
2274
+ let chain_monitor;
2275
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
2276
+ let alice_deserialized;
2277
+ let mut nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
2278
+ let chan_id_0 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) . 2 ;
2279
+ let chan_id_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) . 2 ;
2280
+
2281
+ let alice_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
2282
+ let bob_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
2283
+
2284
+ let amt_msat = nodes[ 0 ] . node . list_usable_channels ( ) [ 0 ] . next_outbound_htlc_limit_msat + 1 ; // Force MPP
2285
+ let offer = nodes[ 1 ] . node
2286
+ . create_offer_builder ( None ) . unwrap ( )
2287
+ . clear_paths ( )
2288
+ . amount_msats ( amt_msat)
2289
+ . build ( ) . unwrap ( ) ;
2290
+ assert_eq ! ( offer. signing_pubkey( ) , Some ( bob_id) ) ;
2291
+ assert ! ( offer. paths( ) . is_empty( ) ) ;
2292
+
2293
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
2294
+ nodes[ 0 ] . node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
2295
+ expect_recent_payment ! ( nodes[ 0 ] , RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
2296
+
2297
+ let invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
2298
+ nodes[ 1 ] . onion_messenger . handle_onion_message ( alice_id, & invreq_om) ;
2299
+
2300
+ // Save the manager while the payment is in state AwaitingInvoice so we can reload it later.
2301
+ let alice_chan_manager_serialized = nodes[ 0 ] . node . encode ( ) ;
2302
+
2303
+ let invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
2304
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( bob_id, & invoice_om) ;
2305
+ let payment_hash = extract_invoice ( & nodes[ 0 ] , & invoice_om) . 0 . payment_hash ( ) ;
2306
+
2307
+ let expected_route: & [ & [ & Node ] ] = & [ & [ & nodes[ 1 ] ] , & [ & nodes[ 1 ] ] ] ;
2308
+ let mut events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
2309
+ assert_eq ! ( events. len( ) , 2 ) ;
2310
+ check_added_monitors ! ( nodes[ 0 ] , 2 ) ;
2311
+
2312
+ let ev = remove_first_msg_event_to_node ( & bob_id, & mut events) ;
2313
+ let args = PassAlongPathArgs :: new ( & nodes[ 0 ] , expected_route[ 0 ] , amt_msat, payment_hash, ev)
2314
+ . without_clearing_recipient_events ( ) ;
2315
+ do_pass_along_path ( args) ;
2316
+
2317
+ let ev = remove_first_msg_event_to_node ( & bob_id, & mut events) ;
2318
+ let args = PassAlongPathArgs :: new ( & nodes[ 0 ] , expected_route[ 0 ] , amt_msat, payment_hash, ev)
2319
+ . without_clearing_recipient_events ( ) ;
2320
+ do_pass_along_path ( args) ;
2321
+
2322
+ expect_recent_payment ! ( nodes[ 0 ] , RecentPaymentDetails :: Pending , payment_id) ;
2323
+ match get_event ! ( nodes[ 1 ] , Event :: PaymentClaimable ) {
2324
+ Event :: PaymentClaimable { .. } => { } ,
2325
+ _ => panic ! ( "No Event::PaymentClaimable" ) ,
2326
+ }
2327
+
2328
+ // Reload with the stale manager and check that receiving the invoice again won't result in a
2329
+ // duplicate payment attempt.
2330
+ let monitor_0 = get_monitor ! ( nodes[ 0 ] , chan_id_0) . encode ( ) ;
2331
+ let monitor_1 = get_monitor ! ( nodes[ 0 ] , chan_id_1) . encode ( ) ;
2332
+ reload_node ! ( nodes[ 0 ] , & alice_chan_manager_serialized, & [ & monitor_0, & monitor_1] , persister, chain_monitor, alice_deserialized) ;
2333
+ // The stale manager results in closing the channels.
2334
+ check_closed_event ! ( nodes[ 0 ] , 2 , ClosureReason :: OutdatedChannelManager , [ bob_id, bob_id] , 10_000_000 ) ;
2335
+ check_added_monitors ! ( nodes[ 0 ] , 2 ) ;
2336
+
2337
+ // Alice receives a duplicate invoice, but the payment should be transitioned to Retryable by now.
2338
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( bob_id, & invoice_om) ;
2339
+ // Previously, Alice would've attempted to pay the invoice a 2nd time. In this test case, this 2nd
2340
+ // attempt would have resulted in a PaymentFailed event here, since the only channels between
2341
+ // Alice and Bob is closed. Since no 2nd attempt should be made, check that no events are
2342
+ // generated in response to the duplicate invoice.
2343
+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
2344
+ }
2345
+
0 commit comments