@@ -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,73 @@ 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 ChannelMonitor
2263
+ // - The monitor is successfully persisted, but the ChannelManager fails to persist, so the
2264
+ // payment remains AwaitingInvoice
2265
+ // - We restart, causing the channel 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 monitor 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 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 10_000_000 , 1_000_000_000 ) . 2 ;
2279
+
2280
+ let alice_id = nodes[ 0 ] . node . get_our_node_id ( ) ;
2281
+ let bob_id = nodes[ 1 ] . node . get_our_node_id ( ) ;
2282
+
2283
+ let offer = nodes[ 1 ] . node
2284
+ . create_offer_builder ( None ) . unwrap ( )
2285
+ . clear_paths ( )
2286
+ . amount_msats ( 10_000_000 )
2287
+ . build ( ) . unwrap ( ) ;
2288
+ assert_eq ! ( offer. signing_pubkey( ) , Some ( bob_id) ) ;
2289
+ assert ! ( offer. paths( ) . is_empty( ) ) ;
2290
+
2291
+ let payment_id = PaymentId ( [ 1 ; 32 ] ) ;
2292
+ nodes[ 0 ] . node . pay_for_offer ( & offer, None , None , None , payment_id, Retry :: Attempts ( 0 ) , None ) . unwrap ( ) ;
2293
+ expect_recent_payment ! ( nodes[ 0 ] , RecentPaymentDetails :: AwaitingInvoice , payment_id) ;
2294
+
2295
+ let invreq_om = nodes[ 0 ] . onion_messenger . next_onion_message_for_peer ( bob_id) . unwrap ( ) ;
2296
+ nodes[ 1 ] . onion_messenger . handle_onion_message ( alice_id, & invreq_om) ;
2297
+
2298
+ // Save the manager while the payment is in state AwaitingInvoice so we can reload it later.
2299
+ let alice_chan_manager_serialized = nodes[ 0 ] . node . encode ( ) ;
2300
+
2301
+ let invoice_om = nodes[ 1 ] . onion_messenger . next_onion_message_for_peer ( alice_id) . unwrap ( ) ;
2302
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( bob_id, & invoice_om) ;
2303
+
2304
+ let ( invoice, _) = extract_invoice ( & nodes[ 0 ] , & invoice_om) ;
2305
+ route_bolt12_payment ( & nodes[ 0 ] , & [ & nodes[ 1 ] ] , & invoice) ;
2306
+ expect_recent_payment ! ( nodes[ 0 ] , RecentPaymentDetails :: Pending , payment_id) ;
2307
+ match get_event ! ( nodes[ 1 ] , Event :: PaymentClaimable ) {
2308
+ Event :: PaymentClaimable { .. } => { } ,
2309
+ _ => panic ! ( "No Event::PaymentClaimable" ) ,
2310
+ }
2311
+
2312
+ // Reload with the stale manager and check that receiving the invoice again won't result in a
2313
+ // duplicate payment attempt.
2314
+ let monitor = get_monitor ! ( nodes[ 0 ] , chan_id) . encode ( ) ;
2315
+ reload_node ! ( nodes[ 0 ] , & alice_chan_manager_serialized, & [ & monitor] , persister, chain_monitor, alice_deserialized) ;
2316
+ // The stale manager results in closing the channel.
2317
+ check_closed_event ! ( nodes[ 0 ] , 1 , ClosureReason :: OutdatedChannelManager , [ bob_id] , 10_000_000 ) ;
2318
+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
2319
+
2320
+ // Alice receives a duplicate invoice, but the payment should be transitioned to Retryable by now.
2321
+ nodes[ 0 ] . onion_messenger . handle_onion_message ( bob_id, & invoice_om) ;
2322
+ // Previously we would've attempted to pay the invoice a 2nd time, resulting in a PaymentFailed
2323
+ // event here.
2324
+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_events( ) . is_empty( ) ) ;
2325
+ }
2326
+
0 commit comments