1616#[ cfg( any( test, feature = "std" ) ) ]
1717extern crate core;
1818
19+ #[ cfg( not( feature = "std" ) ) ]
20+ extern crate alloc;
21+
1922#[ macro_use] extern crate lightning;
2023extern crate lightning_rapid_gossip_sync;
2124
@@ -28,7 +31,7 @@ use lightning::ln::msgs::{ChannelMessageHandler, OnionMessageHandler, RoutingMes
2831use lightning:: ln:: peer_handler:: { CustomMessageHandler , PeerManager , SocketDescriptor } ;
2932use lightning:: routing:: gossip:: { NetworkGraph , P2PGossipSync } ;
3033use lightning:: routing:: router:: Router ;
31- use lightning:: routing:: scoring:: WriteableScore ;
34+ use lightning:: routing:: scoring:: { Score , WriteableScore } ;
3235use lightning:: util:: events:: { Event , EventHandler , EventsProvider } ;
3336use lightning:: util:: logger:: Logger ;
3437use lightning:: util:: persist:: Persister ;
@@ -49,6 +52,8 @@ use std::time::Instant;
4952
5053#[ cfg( feature = "futures" ) ]
5154use futures_util:: { select_biased, future:: FutureExt , task} ;
55+ #[ cfg( not( feature = "std" ) ) ]
56+ use alloc:: vec:: Vec ;
5257
5358/// `BackgroundProcessor` takes care of tasks that (1) need to happen periodically to keep
5459/// Rust-Lightning running properly, and (2) either can or should be run in the background. Its
@@ -216,6 +221,37 @@ fn handle_network_graph_update<L: Deref>(
216221 }
217222}
218223
224+ fn update_scorer < ' a , S : ' static + Deref < Target = SC > + Send + Sync , SC : ' a + WriteableScore < ' a > > (
225+ scorer : & ' a S , event : & Event
226+ ) {
227+ let mut score = scorer. lock ( ) ;
228+ match event {
229+ Event :: PaymentPathFailed { ref path, short_channel_id : Some ( scid) , .. } => {
230+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
231+ score. payment_path_failed ( & path, * scid) ;
232+ } ,
233+ Event :: PaymentPathFailed { ref path, payment_failed_permanently : true , .. } => {
234+ // Reached if the destination explicitly failed it back. We treat this as a successful probe
235+ // because the payment made it all the way to the destination with sufficient liquidity.
236+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
237+ score. probe_successful ( & path) ;
238+ } ,
239+ Event :: PaymentPathSuccessful { path, .. } => {
240+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
241+ score. payment_path_successful ( & path) ;
242+ } ,
243+ Event :: ProbeSuccessful { path, .. } => {
244+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
245+ score. probe_successful ( & path) ;
246+ } ,
247+ Event :: ProbeFailed { path, short_channel_id : Some ( scid) , .. } => {
248+ let path = path. iter ( ) . collect :: < Vec < _ > > ( ) ;
249+ score. probe_failed ( & path, * scid) ;
250+ } ,
251+ _ => { } ,
252+ }
253+ }
254+
219255macro_rules! define_run_body {
220256 ( $persister: ident, $chain_monitor: ident, $process_chain_monitor_events: expr,
221257 $channel_manager: ident, $process_channel_manager_events: expr,
@@ -387,7 +423,7 @@ pub async fn process_events_async<
387423 UMH : ' static + Deref + Send + Sync ,
388424 PM : ' static + Deref < Target = PeerManager < Descriptor , CMH , RMH , OMH , L , UMH , NS > > + Send + Sync ,
389425 S : ' static + Deref < Target = SC > + Send + Sync ,
390- SC : WriteableScore < ' a > ,
426+ SC : for < ' b > WriteableScore < ' b > ,
391427 SleepFuture : core:: future:: Future < Output = bool > + core:: marker:: Unpin ,
392428 Sleeper : Fn ( Duration ) -> SleepFuture
393429> (
@@ -417,10 +453,14 @@ where
417453 let async_event_handler = |event| {
418454 let network_graph = gossip_sync. network_graph ( ) ;
419455 let event_handler = & event_handler;
456+ let scorer = & scorer;
420457 async move {
421458 if let Some ( network_graph) = network_graph {
422459 handle_network_graph_update ( network_graph, & event)
423460 }
461+ if let Some ( ref scorer) = scorer {
462+ update_scorer ( scorer, & event) ;
463+ }
424464 event_handler ( event) . await ;
425465 }
426466 } ;
@@ -516,7 +556,7 @@ impl BackgroundProcessor {
516556 UMH : ' static + Deref + Send + Sync ,
517557 PM : ' static + Deref < Target = PeerManager < Descriptor , CMH , RMH , OMH , L , UMH , NS > > + Send + Sync ,
518558 S : ' static + Deref < Target = SC > + Send + Sync ,
519- SC : WriteableScore < ' a > ,
559+ SC : for < ' b > WriteableScore < ' b > ,
520560 > (
521561 persister : PS , event_handler : EH , chain_monitor : M , channel_manager : CM ,
522562 gossip_sync : GossipSync < PGS , RGS , G , CA , L > , peer_manager : PM , logger : L , scorer : Option < S > ,
@@ -547,6 +587,9 @@ impl BackgroundProcessor {
547587 if let Some ( network_graph) = network_graph {
548588 handle_network_graph_update ( network_graph, & event)
549589 }
590+ if let Some ( ref scorer) = scorer {
591+ update_scorer ( scorer, & event) ;
592+ }
550593 event_handler. handle_event ( event) ;
551594 } ;
552595 define_run_body ! ( persister, chain_monitor, chain_monitor. process_pending_events( & event_handler) ,
@@ -613,14 +656,16 @@ mod tests {
613656 use bitcoin:: blockdata:: locktime:: PackedLockTime ;
614657 use bitcoin:: blockdata:: transaction:: { Transaction , TxOut } ;
615658 use bitcoin:: network:: constants:: Network ;
659+ use bitcoin:: secp256k1:: { SecretKey , PublicKey , Secp256k1 } ;
616660 use lightning:: chain:: { BestBlock , Confirm , chainmonitor} ;
617661 use lightning:: chain:: channelmonitor:: ANTI_REORG_DELAY ;
618662 use lightning:: chain:: keysinterface:: { InMemorySigner , EntropySource , KeysManager } ;
619663 use lightning:: chain:: transaction:: OutPoint ;
620664 use lightning:: get_event_msg;
665+ use lightning:: ln:: PaymentHash ;
621666 use lightning:: ln:: channelmanager;
622- use lightning:: ln:: channelmanager:: { BREAKDOWN_TIMEOUT , ChainParameters } ;
623- use lightning:: ln:: features:: ChannelFeatures ;
667+ use lightning:: ln:: channelmanager:: { BREAKDOWN_TIMEOUT , ChainParameters , MIN_CLTV_EXPIRY_DELTA , PaymentId } ;
668+ use lightning:: ln:: features:: { ChannelFeatures , NodeFeatures } ;
624669 use lightning:: ln:: msgs:: { ChannelMessageHandler , Init } ;
625670 use lightning:: ln:: peer_handler:: { PeerManager , MessageHandler , SocketDescriptor , IgnoringMessageHandler } ;
626671 use lightning:: routing:: gossip:: { NetworkGraph , NodeId , P2PGossipSync } ;
@@ -1296,4 +1341,124 @@ mod tests {
12961341 let bg_processor = BackgroundProcessor :: start ( persister, event_handler, nodes[ 0 ] . chain_monitor . clone ( ) , nodes[ 0 ] . node . clone ( ) , nodes[ 0 ] . no_gossip_sync ( ) , nodes[ 0 ] . peer_manager . clone ( ) , nodes[ 0 ] . logger . clone ( ) , Some ( nodes[ 0 ] . scorer . clone ( ) ) ) ;
12971342 assert ! ( bg_processor. stop( ) . is_ok( ) ) ;
12981343 }
1344+
1345+ #[ test]
1346+ fn test_payment_path_scoring ( ) {
1347+ // Ensure that we update the scorer when relevant events are processed. In this case, we ensure
1348+ // that we update the scorer upon a payment path succeeding (note that the channel must be
1349+ // public or else we won't score it).
1350+ // Set up a background event handler for FundingGenerationReady events.
1351+ let ( sender, receiver) = std:: sync:: mpsc:: sync_channel ( 1 ) ;
1352+ let event_handler = move |event : Event | match event {
1353+ Event :: PaymentPathFailed { .. } => sender. send ( event) . unwrap ( ) ,
1354+ Event :: PaymentPathSuccessful { .. } => sender. send ( event) . unwrap ( ) ,
1355+ Event :: ProbeSuccessful { .. } => sender. send ( event) . unwrap ( ) ,
1356+ Event :: ProbeFailed { .. } => sender. send ( event) . unwrap ( ) ,
1357+ _ => panic ! ( "Unexpected event: {:?}" , event) ,
1358+ } ;
1359+
1360+ let nodes = create_nodes ( 1 , "test_payment_path_scoring" . to_string ( ) ) ;
1361+ let data_dir = nodes[ 0 ] . persister . get_data_dir ( ) ;
1362+ let persister = Arc :: new ( Persister :: new ( data_dir. clone ( ) ) ) ;
1363+ let bg_processor = BackgroundProcessor :: start ( persister, event_handler, nodes[ 0 ] . chain_monitor . clone ( ) , nodes[ 0 ] . node . clone ( ) , nodes[ 0 ] . no_gossip_sync ( ) , nodes[ 0 ] . peer_manager . clone ( ) , nodes[ 0 ] . logger . clone ( ) , Some ( nodes[ 0 ] . scorer . clone ( ) ) ) ;
1364+
1365+ let scored_scid = 4242 ;
1366+ let secp_ctx = Secp256k1 :: new ( ) ;
1367+ let node_1_privkey = SecretKey :: from_slice ( & [ 42 ; 32 ] ) . unwrap ( ) ;
1368+ let node_1_id = PublicKey :: from_secret_key ( & secp_ctx, & node_1_privkey) ;
1369+
1370+ let path = vec ! [ RouteHop {
1371+ pubkey: node_1_id,
1372+ node_features: NodeFeatures :: empty( ) ,
1373+ short_channel_id: scored_scid,
1374+ channel_features: ChannelFeatures :: empty( ) ,
1375+ fee_msat: 0 ,
1376+ cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA as u32 ,
1377+ } ] ;
1378+
1379+ nodes[ 0 ] . scorer . lock ( ) . unwrap ( ) . expect ( TestResult :: PaymentFailure { path : path. clone ( ) , short_channel_id : scored_scid } ) ;
1380+ nodes[ 0 ] . node . push_pending_event ( Event :: PaymentPathFailed {
1381+ payment_id : None ,
1382+ payment_hash : PaymentHash ( [ 42 ; 32 ] ) ,
1383+ payment_failed_permanently : false ,
1384+ network_update : None ,
1385+ all_paths_failed : true ,
1386+ path : path. clone ( ) ,
1387+ short_channel_id : Some ( scored_scid) ,
1388+ retry : None ,
1389+ } ) ;
1390+ let event = receiver
1391+ . recv_timeout ( Duration :: from_secs ( EVENT_DEADLINE ) )
1392+ . expect ( "PaymentPathFailed not handled within deadline" ) ;
1393+ match event {
1394+ Event :: PaymentPathFailed { .. } => { } ,
1395+ _ => panic ! ( "Unexpected event" ) ,
1396+ }
1397+
1398+ // Ensure we'll score payments that were explicitly failed back by the destination as
1399+ // ProbeSuccess.
1400+ nodes[ 0 ] . scorer . lock ( ) . unwrap ( ) . expect ( TestResult :: ProbeSuccess { path : path. clone ( ) } ) ;
1401+ nodes[ 0 ] . node . push_pending_event ( Event :: PaymentPathFailed {
1402+ payment_id : None ,
1403+ payment_hash : PaymentHash ( [ 42 ; 32 ] ) ,
1404+ payment_failed_permanently : true ,
1405+ network_update : None ,
1406+ all_paths_failed : true ,
1407+ path : path. clone ( ) ,
1408+ short_channel_id : None ,
1409+ retry : None ,
1410+ } ) ;
1411+ let event = receiver
1412+ . recv_timeout ( Duration :: from_secs ( EVENT_DEADLINE ) )
1413+ . expect ( "PaymentPathFailed not handled within deadline" ) ;
1414+ match event {
1415+ Event :: PaymentPathFailed { .. } => { } ,
1416+ _ => panic ! ( "Unexpected event" ) ,
1417+ }
1418+
1419+ nodes[ 0 ] . scorer . lock ( ) . unwrap ( ) . expect ( TestResult :: PaymentSuccess { path : path. clone ( ) } ) ;
1420+ nodes[ 0 ] . node . push_pending_event ( Event :: PaymentPathSuccessful {
1421+ payment_id : PaymentId ( [ 42 ; 32 ] ) ,
1422+ payment_hash : None ,
1423+ path : path. clone ( ) ,
1424+ } ) ;
1425+ let event = receiver
1426+ . recv_timeout ( Duration :: from_secs ( EVENT_DEADLINE ) )
1427+ . expect ( "PaymentPathSuccessful not handled within deadline" ) ;
1428+ match event {
1429+ Event :: PaymentPathSuccessful { .. } => { } ,
1430+ _ => panic ! ( "Unexpected event" ) ,
1431+ }
1432+
1433+ nodes[ 0 ] . scorer . lock ( ) . unwrap ( ) . expect ( TestResult :: ProbeSuccess { path : path. clone ( ) } ) ;
1434+ nodes[ 0 ] . node . push_pending_event ( Event :: ProbeSuccessful {
1435+ payment_id : PaymentId ( [ 42 ; 32 ] ) ,
1436+ payment_hash : PaymentHash ( [ 42 ; 32 ] ) ,
1437+ path : path. clone ( ) ,
1438+ } ) ;
1439+ let event = receiver
1440+ . recv_timeout ( Duration :: from_secs ( EVENT_DEADLINE ) )
1441+ . expect ( "ProbeSuccessful not handled within deadline" ) ;
1442+ match event {
1443+ Event :: ProbeSuccessful { .. } => { } ,
1444+ _ => panic ! ( "Unexpected event" ) ,
1445+ }
1446+
1447+ nodes[ 0 ] . scorer . lock ( ) . unwrap ( ) . expect ( TestResult :: ProbeFailure { path : path. clone ( ) } ) ;
1448+ nodes[ 0 ] . node . push_pending_event ( Event :: ProbeFailed {
1449+ payment_id : PaymentId ( [ 42 ; 32 ] ) ,
1450+ payment_hash : PaymentHash ( [ 42 ; 32 ] ) ,
1451+ path : path. clone ( ) ,
1452+ short_channel_id : Some ( scored_scid) ,
1453+ } ) ;
1454+ let event = receiver
1455+ . recv_timeout ( Duration :: from_secs ( EVENT_DEADLINE ) )
1456+ . expect ( "ProbeFailure not handled within deadline" ) ;
1457+ match event {
1458+ Event :: ProbeFailed { .. } => { } ,
1459+ _ => panic ! ( "Unexpected event" ) ,
1460+ }
1461+
1462+ assert ! ( bg_processor. stop( ) . is_ok( ) ) ;
1463+ }
12991464}
0 commit comments