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 > {
@@ -550,6 +588,17 @@ where
550
588
Event :: PaymentPathFailed {
551
589
payment_id, payment_hash, rejected_by_dest, path, short_channel_id, retry, ..
552
590
} => {
591
+ if let Some ( payment_id) = payment_id {
592
+ // When the failed payment was a probe, we make sure to not penalize the last
593
+ // hop and then drop the event instead of handing it up to the user's event
594
+ // handler.
595
+ if self . payer . payment_is_probe ( * payment_hash, * payment_id) {
596
+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
597
+ self . scorer . lock ( ) . payment_path_failed ( & path, u64:: max_value ( ) ) ;
598
+ return ;
599
+ }
600
+ }
601
+
553
602
if let Some ( short_channel_id) = short_channel_id {
554
603
let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
555
604
self . scorer . lock ( ) . payment_path_failed ( & path, * short_channel_id) ;
@@ -1402,6 +1451,14 @@ mod tests {
1402
1451
payment_params : Some ( route_params. payment_params . clone ( ) ) , ..Self :: route_for_value ( route_params. final_value_msat )
1403
1452
} )
1404
1453
}
1454
+
1455
+ fn build_route_from_hops (
1456
+ & self , _payer : & PublicKey , _hops : & [ PublicKey ] , route_params : & RouteParameters
1457
+ ) -> Result < Route , LightningError > {
1458
+ Ok ( Route {
1459
+ payment_params : Some ( route_params. payment_params . clone ( ) ) , ..Self :: route_for_value ( route_params. final_value_msat )
1460
+ } )
1461
+ }
1405
1462
}
1406
1463
1407
1464
struct FailingRouter ;
@@ -1413,6 +1470,12 @@ mod tests {
1413
1470
) -> Result < Route , LightningError > {
1414
1471
Err ( LightningError { err : String :: new ( ) , action : ErrorAction :: IgnoreError } )
1415
1472
}
1473
+
1474
+ fn build_route_from_hops (
1475
+ & self , _payer : & PublicKey , _hops : & [ PublicKey ] , _route_params : & RouteParameters
1476
+ ) -> Result < Route , LightningError > {
1477
+ Err ( LightningError { err : String :: new ( ) , action : ErrorAction :: IgnoreError } )
1478
+ }
1416
1479
}
1417
1480
1418
1481
struct TestScorer {
@@ -1604,6 +1667,17 @@ mod tests {
1604
1667
}
1605
1668
1606
1669
fn abandon_payment ( & self , _payment_id : PaymentId ) { }
1670
+
1671
+ fn send_probe_payment ( & self , route : & Route ) -> Result < PaymentId , PaymentSendFailure > {
1672
+ // TODO: for now copied from spontaneous, figure out what to do here.
1673
+ self . check_value_msats ( Amount :: Spontaneous ( route. get_total_amount ( ) ) ) ;
1674
+ self . check_attempts ( )
1675
+ }
1676
+
1677
+ fn payment_is_probe ( & self , _payment_hash : PaymentHash , _payment_id : PaymentId ) -> bool {
1678
+ // TODO: figure out what to do here.
1679
+ false
1680
+ }
1607
1681
}
1608
1682
1609
1683
// *** Full Featured Functional Tests with a Real ChannelManager ***
@@ -1616,6 +1690,12 @@ mod tests {
1616
1690
) -> Result < Route , LightningError > {
1617
1691
self . 0 . borrow_mut ( ) . pop_front ( ) . unwrap ( )
1618
1692
}
1693
+
1694
+ fn build_route_from_hops (
1695
+ & self , _payer : & PublicKey , _hops : & [ PublicKey ] , _route_params : & RouteParameters
1696
+ ) -> Result < Route , LightningError > {
1697
+ self . 0 . borrow_mut ( ) . pop_front ( ) . unwrap ( )
1698
+ }
1619
1699
}
1620
1700
impl ManualRouter {
1621
1701
fn expect_find_route ( & self , result : Result < Route , LightningError > ) {
0 commit comments