@@ -118,11 +118,11 @@ use io::KVStore;
118118use payment_store:: PaymentStore ;
119119pub use payment_store:: { PaymentDetails , PaymentDirection , PaymentStatus } ;
120120use peer_store:: { PeerInfo , PeerStore } ;
121- use types:: { ChainMonitor , ChannelManager , KeysManager , NetworkGraph , PeerManager , Scorer } ;
121+ use types:: { ChainMonitor , ChannelManager , KeysManager , NetworkGraph , PeerManager , Router , Scorer } ;
122122pub use types:: { ChannelDetails , ChannelId , PeerDetails , UserChannelId } ;
123123use wallet:: Wallet ;
124124
125- use logger:: { log_error, log_info, log_trace, FilesystemLogger , Logger } ;
125+ use logger:: { log_debug , log_error, log_info, log_trace, FilesystemLogger , Logger } ;
126126
127127use lightning:: chain:: keysinterface:: EntropySource ;
128128use lightning:: chain:: Confirm ;
@@ -136,7 +136,7 @@ use lightning_background_processor::process_events_async;
136136
137137use lightning_transaction_sync:: EsploraSyncClient ;
138138
139- use lightning:: routing:: router:: { PaymentParameters , RouteParameters } ;
139+ use lightning:: routing:: router:: { PaymentParameters , RouteParameters , Router as LdkRouter } ;
140140use lightning_invoice:: { payment, Currency , Invoice } ;
141141
142142use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
@@ -284,6 +284,7 @@ pub struct Node<K: KVStore + Sync + Send + 'static> {
284284 gossip_source : Arc < GossipSource > ,
285285 kv_store : Arc < K > ,
286286 logger : Arc < FilesystemLogger > ,
287+ router : Arc < Router > ,
287288 scorer : Arc < Mutex < Scorer > > ,
288289 peer_store : Arc < PeerStore < K , Arc < FilesystemLogger > > > ,
289290 payment_store : Arc < PaymentStore < K , Arc < FilesystemLogger > > > ,
@@ -1287,6 +1288,76 @@ impl<K: KVStore + Sync + Send + 'static> Node<K> {
12871288 }
12881289 }
12891290
1291+ /// Sends payment probes over all paths of a route that would be used to pay the given invoice.
1292+ ///
1293+ /// This may be used to send "pre-flight" probes, i.e., to train our scorer before conducting
1294+ /// the actual payment. Note this is only useful if there likely is sufficient time for the
1295+ /// probe to settle before sending out the actual payment, e.g., when waiting for user
1296+ /// confirmation in a wallet UI.
1297+ pub fn send_payment_probe ( & self , invoice : & Invoice ) -> Result < ( ) , Error > {
1298+ let rt_lock = self . runtime . read ( ) . unwrap ( ) ;
1299+ if rt_lock. is_none ( ) {
1300+ return Err ( Error :: NotRunning ) ;
1301+ }
1302+
1303+ let amount_msat = if let Some ( invoice_amount_msat) = invoice. amount_milli_satoshis ( ) {
1304+ invoice_amount_msat
1305+ } else {
1306+ log_error ! ( self . logger, "Failed to send probe as no amount was given in the invoice." ) ;
1307+ return Err ( Error :: InvalidAmount ) ;
1308+ } ;
1309+
1310+ let expiry_time = invoice. duration_since_epoch ( ) . saturating_add ( invoice. expiry_time ( ) ) ;
1311+ let mut payment_params = PaymentParameters :: from_node_id (
1312+ invoice. recover_payee_pub_key ( ) ,
1313+ invoice. min_final_cltv_expiry_delta ( ) as u32 ,
1314+ )
1315+ . with_expiry_time ( expiry_time. as_secs ( ) )
1316+ . with_route_hints ( invoice. route_hints ( ) ) ;
1317+ if let Some ( features) = invoice. features ( ) {
1318+ payment_params = payment_params. with_features ( features. clone ( ) ) ;
1319+ }
1320+ let route_params = RouteParameters { payment_params, final_value_msat : amount_msat } ;
1321+
1322+ self . send_payment_probe_internal ( route_params)
1323+ }
1324+
1325+ fn send_payment_probe_internal ( & self , route_params : RouteParameters ) -> Result < ( ) , Error > {
1326+ let payer = self . channel_manager . get_our_node_id ( ) ;
1327+ let first_hops = self . channel_manager . list_usable_channels ( ) ;
1328+ let inflight_htlcs = self . channel_manager . compute_inflight_htlcs ( ) ;
1329+
1330+ let route = self
1331+ . router
1332+ . find_route (
1333+ & payer,
1334+ & route_params,
1335+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) ,
1336+ & inflight_htlcs,
1337+ )
1338+ . map_err ( |e| {
1339+ log_error ! ( self . logger, "Failed to find path for payment probe: {:?}" , e) ;
1340+ Error :: ProbeSendingFailed
1341+ } ) ?;
1342+
1343+ for path in route. paths {
1344+ if path. hops . len ( ) + path. blinded_tail . as_ref ( ) . map_or ( 0 , |t| t. hops . len ( ) ) < 2 {
1345+ log_debug ! (
1346+ self . logger,
1347+ "Skipped sending payment probe over path with less than two hops."
1348+ ) ;
1349+ continue ;
1350+ }
1351+
1352+ self . channel_manager . send_probe ( path) . map_err ( |e| {
1353+ log_error ! ( self . logger, "Failed to send payment probe: {:?}" , e) ;
1354+ Error :: ProbeSendingFailed
1355+ } ) ?;
1356+ }
1357+
1358+ Ok ( ( ) )
1359+ }
1360+
12901361 /// Returns a payable invoice that can be used to request and receive a payment of the amount
12911362 /// given.
12921363 pub fn receive_payment (
0 commit comments