@@ -24,7 +24,7 @@ use crate::types::payment::{PaymentHash, PaymentSecret, PaymentPreimage};
24
24
use crate :: ln:: chan_utils;
25
25
use crate :: ln:: msgs:: ChannelMessageHandler ;
26
26
use crate :: ln:: onion_utils;
27
- use crate :: ln:: outbound_payment:: { IDEMPOTENCY_TIMEOUT_TICKS , Retry , RetryableSendFailure } ;
27
+ use crate :: ln:: outbound_payment:: { IDEMPOTENCY_TIMEOUT_TICKS , ProbeSendFailure , Retry , RetryableSendFailure } ;
28
28
use crate :: routing:: gossip:: { EffectiveCapacity , RoutingFees } ;
29
29
use crate :: routing:: router:: { get_route, Path , PaymentParameters , Route , Router , RouteHint , RouteHintHop , RouteHop , RouteParameters } ;
30
30
use crate :: routing:: scoring:: ChannelUsage ;
@@ -1249,6 +1249,7 @@ fn sent_probe_is_probe_of_sending_node() {
1249
1249
// First check we refuse to build a single-hop probe
1250
1250
let ( route, _, _, _) = get_route_and_payment_hash ! ( & nodes[ 0 ] , nodes[ 1 ] , 100_000 ) ;
1251
1251
assert ! ( nodes[ 0 ] . node. send_probe( route. paths[ 0 ] . clone( ) ) . is_err( ) ) ;
1252
+ assert ! ( nodes[ 0 ] . node. pending_outbound_payments. pending_outbound_payments. lock( ) . unwrap( ) . is_empty( ) ) ;
1252
1253
1253
1254
// Then build an actual two-hop probing path
1254
1255
let ( route, _, _, _) = get_route_and_payment_hash ! ( & nodes[ 0 ] , nodes[ 2 ] , 100_000 ) ;
@@ -4375,3 +4376,77 @@ fn test_non_strict_forwarding() {
4375
4376
let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
4376
4377
expect_payment_failed_conditions_event ( events, payment_hash, false , PaymentFailedConditions :: new ( ) . blamed_scid ( routed_scid) ) ;
4377
4378
}
4379
+
4380
+ #[ test]
4381
+ fn remove_pending_outbounds_on_buggy_router ( ) {
4382
+ // Ensure that if a payment errors due to a bogus route, we'll abandon the payment and remove the
4383
+ // pending outbound from storage.
4384
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
4385
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
4386
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
4387
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
4388
+ create_announced_chan_between_nodes ( & nodes, 0 , 1 ) ;
4389
+
4390
+ let amt_msat = 10_000 ;
4391
+ let payment_id = PaymentId ( [ 42 ; 32 ] ) ;
4392
+ let payment_params = PaymentParameters :: from_node_id ( nodes[ 1 ] . node . get_our_node_id ( ) , 0 )
4393
+ . with_bolt11_features ( nodes[ 1 ] . node . bolt11_invoice_features ( ) ) . unwrap ( ) ;
4394
+ let ( mut route, payment_hash, _, payment_secret) = get_route_and_payment_hash ! ( nodes[ 0 ] , nodes[ 1 ] , payment_params, amt_msat) ;
4395
+
4396
+ // Extend the path by itself, essentially simulating route going through same channel twice
4397
+ let cloned_hops = route. paths [ 0 ] . hops . clone ( ) ;
4398
+ route. paths [ 0 ] . hops . extend_from_slice ( & cloned_hops) ;
4399
+ let route_params = route. route_params . clone ( ) . unwrap ( ) ;
4400
+ nodes[ 0 ] . router . expect_find_route ( route_params. clone ( ) , Ok ( route. clone ( ) ) ) ;
4401
+
4402
+ nodes[ 0 ] . node . send_payment (
4403
+ payment_hash, RecipientOnionFields :: secret_only ( payment_secret) , payment_id, route_params,
4404
+ Retry :: Attempts ( 1 ) // Even though another attempt is allowed, the payment should fail
4405
+ ) . unwrap ( ) ;
4406
+ let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
4407
+ assert_eq ! ( events. len( ) , 2 ) ;
4408
+ match & events[ 0 ] {
4409
+ Event :: PaymentPathFailed { failure, payment_failed_permanently, .. } => {
4410
+ assert_eq ! ( failure, & PathFailure :: InitialSend {
4411
+ err: APIError :: InvalidRoute { err: "Path went through the same channel twice" . to_string( ) }
4412
+ } ) ;
4413
+ assert ! ( !payment_failed_permanently) ;
4414
+ } ,
4415
+ _ => panic ! ( )
4416
+ }
4417
+ match events[ 1 ] {
4418
+ Event :: PaymentFailed { reason, .. } => {
4419
+ assert_eq ! ( reason. unwrap( ) , PaymentFailureReason :: UnexpectedError ) ;
4420
+ } ,
4421
+ _ => panic ! ( )
4422
+ }
4423
+ assert ! ( nodes[ 0 ] . node. pending_outbound_payments. pending_outbound_payments. lock( ) . unwrap( ) . is_empty( ) ) ;
4424
+ }
4425
+
4426
+ #[ test]
4427
+ fn remove_pending_outbound_probe_on_buggy_path ( ) {
4428
+ // Ensure that if a probe errors due to a bogus route, we'll return an error and remove the
4429
+ // pending outbound from storage.
4430
+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
4431
+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
4432
+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
4433
+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
4434
+ create_announced_chan_between_nodes ( & nodes, 0 , 1 ) ;
4435
+
4436
+ let amt_msat = 10_000 ;
4437
+ let payment_params = PaymentParameters :: from_node_id ( nodes[ 1 ] . node . get_our_node_id ( ) , 0 )
4438
+ . with_bolt11_features ( nodes[ 1 ] . node . bolt11_invoice_features ( ) ) . unwrap ( ) ;
4439
+ let ( mut route, _, _, _) = get_route_and_payment_hash ! ( nodes[ 0 ] , nodes[ 1 ] , payment_params, amt_msat) ;
4440
+
4441
+ // Extend the path by itself, essentially simulating route going through same channel twice
4442
+ let cloned_hops = route. paths [ 0 ] . hops . clone ( ) ;
4443
+ route. paths [ 0 ] . hops . extend_from_slice ( & cloned_hops) ;
4444
+
4445
+ assert_eq ! (
4446
+ nodes[ 0 ] . node. send_probe( route. paths. pop( ) . unwrap( ) ) . unwrap_err( ) ,
4447
+ ProbeSendFailure :: ParameterError (
4448
+ APIError :: InvalidRoute { err: "Path went through the same channel twice" . to_string( ) }
4449
+ )
4450
+ ) ;
4451
+ assert ! ( nodes[ 0 ] . node. pending_outbound_payments. pending_outbound_payments. lock( ) . unwrap( ) . is_empty( ) ) ;
4452
+ }
0 commit comments