74
74
//! # &self, route: &Route, payment_id: PaymentId
75
75
//! # ) -> Result<(), PaymentSendFailure> { unimplemented!() }
76
76
//! # fn abandon_payment(&self, payment_id: PaymentId) { unimplemented!() }
77
+ //! # fn send_probe_payment(
78
+ //! # &self, route: &Route
79
+ //! # ) -> Result<PaymentId, PaymentSendFailure> { unimplemented!() }
80
+ //! # fn payment_is_probe(
81
+ //! # &self, payment_hash: PaymentHash, payment_id: PaymentId
82
+ //! # ) -> bool { unimplemented!() }
77
83
//! # }
78
84
//! #
79
85
//! # struct FakeRouter {}
82
88
//! # &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
83
89
//! # first_hops: Option<&[&ChannelDetails]>, scorer: &S
84
90
//! # ) -> Result<Route, LightningError> { unimplemented!() }
91
+ //! #
92
+ //! # fn build_route_from_hops(
93
+ //! # &self, _payer: &PublicKey, _hops: &[PublicKey], route_params: &RouteParameters
94
+ //! # ) -> Result<Route, LightningError> { unimplemented!() }
85
95
//! # }
86
96
//! #
87
97
//! # struct FakeScorer {}
@@ -247,6 +257,12 @@ pub trait Payer {
247
257
248
258
/// Signals that no further retries for the given payment will occur.
249
259
fn abandon_payment ( & self , payment_id : PaymentId ) ;
260
+
261
+ /// Send a payment probe over the given [`Route`].
262
+ fn send_probe_payment ( & self , route : & Route ) -> Result < PaymentId , PaymentSendFailure > ;
263
+
264
+ /// Returns whether payment with the given [`PaymentId`] and [`PaymentHash`] is a probe.
265
+ fn payment_is_probe ( & self , payment_hash : PaymentHash , payment_id : PaymentId ) -> bool ;
250
266
}
251
267
252
268
/// A trait defining behavior for routing an [`Invoice`] payment.
@@ -256,6 +272,11 @@ pub trait Router<S: Score> {
256
272
& self , payer : & PublicKey , route_params : & RouteParameters , payment_hash : & PaymentHash ,
257
273
first_hops : Option < & [ & ChannelDetails ] > , scorer : & S
258
274
) -> Result < Route , LightningError > ;
275
+
276
+ /// Builds a [`Route`] from `payer` along the given path.
277
+ fn build_route_from_hops (
278
+ & self , payer : & PublicKey , hops : & [ PublicKey ] , params : & RouteParameters
279
+ ) -> Result < Route , LightningError > ;
259
280
}
260
281
261
282
/// Strategies available to retry payment path failures for an [`Invoice`].
@@ -411,6 +432,23 @@ where
411
432
. map_err ( |e| { self . payment_cache . lock ( ) . unwrap ( ) . remove ( & payment_hash) ; e } )
412
433
}
413
434
435
+ /// Sends a probe payment along the given path. The resulting payment will not be cached and
436
+ /// resulting failures will be handled differently from regular payments.
437
+ pub fn send_probe_along_path (
438
+ & self , pubkey : PublicKey , hops : & [ PublicKey ] , amount_msats : u64 , final_cltv_expiry_delta : u32
439
+ ) -> Result < PaymentId , PaymentError > {
440
+ let route_params = RouteParameters {
441
+ payment_params : PaymentParameters :: for_keysend ( pubkey) ,
442
+ final_value_msat : amount_msats,
443
+ final_cltv_expiry_delta,
444
+ } ;
445
+ let payer = self . payer . node_id ( ) ;
446
+ let route = self . router . build_route_from_hops ( & payer, hops, & route_params)
447
+ . map_err ( |e| PaymentError :: Routing ( e) ) ?;
448
+
449
+ self . payer . send_probe_payment ( & route) . map_err ( |e| PaymentError :: Sending ( e) )
450
+ }
451
+
414
452
fn pay_internal < F : FnOnce ( & Route ) -> Result < PaymentId , PaymentSendFailure > + Copy > (
415
453
& self , params : & RouteParameters , payment_hash : PaymentHash , send_payment : F ,
416
454
) -> Result < PaymentId , PaymentError > {
@@ -552,6 +590,20 @@ where
552
590
} => {
553
591
if let Some ( short_channel_id) = short_channel_id {
554
592
let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
593
+ if let Some ( payment_id) = payment_id {
594
+ // When the failed payment was a probe, we make sure to not penalize the last
595
+ // hop and then drop the event instead of handing it up to the user's event
596
+ // handler.
597
+ if self . payer . payment_is_probe ( * payment_hash, * payment_id) {
598
+ if * rejected_by_dest {
599
+ self . scorer . lock ( ) . payment_path_failed ( & path, u64:: max_value ( ) ) ;
600
+ } else {
601
+ self . scorer . lock ( ) . payment_path_failed ( & path, * short_channel_id) ;
602
+ }
603
+ return ;
604
+ }
605
+ }
606
+
555
607
self . scorer . lock ( ) . payment_path_failed ( & path, * short_channel_id) ;
556
608
}
557
609
@@ -1402,6 +1454,14 @@ mod tests {
1402
1454
payment_params : Some ( route_params. payment_params . clone ( ) ) , ..Self :: route_for_value ( route_params. final_value_msat )
1403
1455
} )
1404
1456
}
1457
+
1458
+ fn build_route_from_hops (
1459
+ & self , _payer : & PublicKey , _hops : & [ PublicKey ] , route_params : & RouteParameters
1460
+ ) -> Result < Route , LightningError > {
1461
+ Ok ( Route {
1462
+ payment_params : Some ( route_params. payment_params . clone ( ) ) , ..Self :: route_for_value ( route_params. final_value_msat )
1463
+ } )
1464
+ }
1405
1465
}
1406
1466
1407
1467
struct FailingRouter ;
@@ -1413,6 +1473,12 @@ mod tests {
1413
1473
) -> Result < Route , LightningError > {
1414
1474
Err ( LightningError { err : String :: new ( ) , action : ErrorAction :: IgnoreError } )
1415
1475
}
1476
+
1477
+ fn build_route_from_hops (
1478
+ & self , _payer : & PublicKey , _hops : & [ PublicKey ] , _route_params : & RouteParameters
1479
+ ) -> Result < Route , LightningError > {
1480
+ Err ( LightningError { err : String :: new ( ) , action : ErrorAction :: IgnoreError } )
1481
+ }
1416
1482
}
1417
1483
1418
1484
struct TestScorer {
@@ -1604,6 +1670,17 @@ mod tests {
1604
1670
}
1605
1671
1606
1672
fn abandon_payment ( & self , _payment_id : PaymentId ) { }
1673
+
1674
+ fn send_probe_payment ( & self , route : & Route ) -> Result < PaymentId , PaymentSendFailure > {
1675
+ // TODO: for now copied from spontaneous, figure out what to do here.
1676
+ self . check_value_msats ( Amount :: Spontaneous ( route. get_total_amount ( ) ) ) ;
1677
+ self . check_attempts ( )
1678
+ }
1679
+
1680
+ fn payment_is_probe ( & self , _payment_hash : PaymentHash , _payment_id : PaymentId ) -> bool {
1681
+ // TODO: figure out what to do here.
1682
+ false
1683
+ }
1607
1684
}
1608
1685
1609
1686
// *** Full Featured Functional Tests with a Real ChannelManager ***
@@ -1616,6 +1693,12 @@ mod tests {
1616
1693
) -> Result < Route , LightningError > {
1617
1694
self . 0 . borrow_mut ( ) . pop_front ( ) . unwrap ( )
1618
1695
}
1696
+
1697
+ fn build_route_from_hops (
1698
+ & self , _payer : & PublicKey , _hops : & [ PublicKey ] , _route_params : & RouteParameters
1699
+ ) -> Result < Route , LightningError > {
1700
+ self . 0 . borrow_mut ( ) . pop_front ( ) . unwrap ( )
1701
+ }
1619
1702
}
1620
1703
impl ManualRouter {
1621
1704
fn expect_find_route ( & self , result : Result < Route , LightningError > ) {
0 commit comments