@@ -439,18 +439,22 @@ where
439
439
mod tests {
440
440
use super :: * ;
441
441
use crate :: { DEFAULT_EXPIRY_TIME , InvoiceBuilder , Currency } ;
442
+ use utils:: create_invoice_from_channelmanager;
442
443
use bitcoin_hashes:: sha256:: Hash as Sha256 ;
443
444
use lightning:: ln:: PaymentPreimage ;
444
- use lightning:: ln:: features:: { ChannelFeatures , NodeFeatures } ;
445
+ use lightning:: ln:: features:: { ChannelFeatures , NodeFeatures , InitFeatures } ;
446
+ use lightning:: ln:: functional_test_utils:: * ;
445
447
use lightning:: ln:: msgs:: { ErrorAction , LightningError } ;
446
448
use lightning:: routing:: network_graph:: NodeId ;
447
449
use lightning:: routing:: router:: { Payee , Route , RouteHop } ;
448
450
use lightning:: util:: test_utils:: TestLogger ;
449
451
use lightning:: util:: errors:: APIError ;
450
- use lightning:: util:: events:: Event ;
452
+ use lightning:: util:: events:: { Event , MessageSendEventsProvider } ;
451
453
use secp256k1:: { SecretKey , PublicKey , Secp256k1 } ;
452
454
use std:: cell:: RefCell ;
453
455
use std:: time:: { SystemTime , Duration } ;
456
+ use std:: collections:: LinkedList ;
457
+ use std:: sync:: Mutex ;
454
458
455
459
fn invoice ( payment_preimage : PaymentPreimage ) -> Invoice {
456
460
let payment_hash = Sha256 :: hash ( & payment_preimage. 0 ) ;
@@ -1174,4 +1178,72 @@ mod tests {
1174
1178
}
1175
1179
}
1176
1180
}
1181
+
1182
+ // *** Full Featured Functional Tests with a Real ChannelManager ***
1183
+ struct ManualRouter ( Mutex < LinkedList < Result < Route , LightningError > > > ) ;
1184
+
1185
+ impl Router for ManualRouter {
1186
+ fn find_route ( & self , _payer : & PublicKey , _params : & RouteParameters , _first_hops : Option < & [ & ChannelDetails ] > )
1187
+ -> Result < Route , LightningError > {
1188
+ self . 0 . lock ( ) . unwrap ( ) . pop_front ( ) . unwrap ( )
1189
+ }
1190
+ }
1191
+
1192
+ impl Drop for ManualRouter {
1193
+ fn drop ( & mut self ) {
1194
+ assert ! ( self . 0 . lock( ) . unwrap( ) . is_empty( ) ) ;
1195
+ }
1196
+ }
1197
+
1198
+ #[ test]
1199
+ fn retry_multi_path_single_failed_payment ( ) {
1200
+ // Tests that we can/will retry after a single path of an MPP payment failed immediately
1201
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1202
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1203
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None , None ] ) ;
1204
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1205
+
1206
+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
1207
+ create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 1_000_000 , 0 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
1208
+ let chans = nodes[ 0 ] . node . list_usable_channels ( ) ;
1209
+ let mut route = Route {
1210
+ paths : vec ! [
1211
+ vec![ RouteHop {
1212
+ pubkey: nodes[ 1 ] . node. get_our_node_id( ) ,
1213
+ node_features: NodeFeatures :: known( ) ,
1214
+ short_channel_id: chans[ 0 ] . short_channel_id. unwrap( ) ,
1215
+ channel_features: ChannelFeatures :: known( ) ,
1216
+ fee_msat: 10_000 ,
1217
+ cltv_expiry_delta: 100 ,
1218
+ } ] ,
1219
+ vec![ RouteHop {
1220
+ pubkey: nodes[ 1 ] . node. get_our_node_id( ) ,
1221
+ node_features: NodeFeatures :: known( ) ,
1222
+ short_channel_id: chans[ 1 ] . short_channel_id. unwrap( ) ,
1223
+ channel_features: ChannelFeatures :: known( ) ,
1224
+ fee_msat: 100_000_001 , // Our default max-HTLC-value is 10% of the channel value
1225
+ cltv_expiry_delta: 100 ,
1226
+ } ] ,
1227
+ ] ,
1228
+ payee : Some ( Payee :: new ( nodes[ 1 ] . node . get_our_node_id ( ) ) ) ,
1229
+ } ;
1230
+ let mut routes = LinkedList :: new ( ) ;
1231
+ routes. push_back ( Ok ( route. clone ( ) ) ) ;
1232
+ // On retry, split the payment across both channels.
1233
+ route. paths [ 0 ] [ 0 ] . fee_msat = 50_000_001 ;
1234
+ route. paths [ 1 ] [ 0 ] . fee_msat = 50_000_000 ;
1235
+ routes. push_back ( Ok ( route. clone ( ) ) ) ;
1236
+ let route_res = ManualRouter ( Mutex :: new ( routes) ) ;
1237
+
1238
+ let event_handled = core:: cell:: RefCell :: new ( false ) ;
1239
+ let event_handler = |_: & _ | { * event_handled. borrow_mut ( ) = true ; } ;
1240
+ let invoice_payer = InvoicePayer :: new ( nodes[ 0 ] . node , route_res, nodes[ 0 ] . logger , event_handler, RetryAttempts ( 1 ) ) ;
1241
+
1242
+ invoice_payer. pay_invoice ( & create_invoice_from_channelmanager (
1243
+ & nodes[ 1 ] . node , nodes[ 1 ] . keys_manager , Currency :: Bitcoin , Some ( 100_010_000 ) , "Invoice" . to_string ( ) ) . unwrap ( ) ) . unwrap ( ) ;
1244
+ let htlc_msgs = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1245
+ assert_eq ! ( htlc_msgs. len( ) , 2 ) ;
1246
+ check_added_monitors ! ( nodes[ 0 ] , 2 ) ;
1247
+ assert ! ( !* event_handled. borrow( ) ) ;
1248
+ }
1177
1249
}
0 commit comments