16
16
#[ cfg( any( test, feature = "std" ) ) ]
17
17
extern crate core;
18
18
19
+ #[ cfg( not( feature = "std" ) ) ]
20
+ extern crate alloc;
21
+
19
22
#[ macro_use] extern crate lightning;
20
23
extern crate lightning_rapid_gossip_sync;
21
24
@@ -28,7 +31,7 @@ use lightning::ln::msgs::{ChannelMessageHandler, OnionMessageHandler, RoutingMes
28
31
use lightning:: ln:: peer_handler:: { CustomMessageHandler , PeerManager , SocketDescriptor } ;
29
32
use lightning:: routing:: gossip:: { NetworkGraph , P2PGossipSync } ;
30
33
use lightning:: routing:: router:: Router ;
31
- use lightning:: routing:: scoring:: WriteableScore ;
34
+ use lightning:: routing:: scoring:: { Score , WriteableScore } ;
32
35
use lightning:: util:: events:: { Event , EventHandler , EventsProvider } ;
33
36
use lightning:: util:: logger:: Logger ;
34
37
use lightning:: util:: persist:: Persister ;
@@ -49,6 +52,8 @@ use std::time::Instant;
49
52
50
53
#[ cfg( feature = "futures" ) ]
51
54
use futures_util:: { select_biased, future:: FutureExt , task} ;
55
+ #[ cfg( not( feature = "std" ) ) ]
56
+ use alloc:: vec:: Vec ;
52
57
53
58
/// `BackgroundProcessor` takes care of tasks that (1) need to happen periodically to keep
54
59
/// 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>(
216
221
}
217
222
}
218
223
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
+
219
255
macro_rules! define_run_body {
220
256
( $persister: ident, $chain_monitor: ident, $process_chain_monitor_events: expr,
221
257
$channel_manager: ident, $process_channel_manager_events: expr,
@@ -387,7 +423,7 @@ pub async fn process_events_async<
387
423
UMH : ' static + Deref + Send + Sync ,
388
424
PM : ' static + Deref < Target = PeerManager < Descriptor , CMH , RMH , OMH , L , UMH , NS > > + Send + Sync ,
389
425
S : ' static + Deref < Target = SC > + Send + Sync ,
390
- SC : WriteableScore < ' a > ,
426
+ SC : for < ' b > WriteableScore < ' b > ,
391
427
SleepFuture : core:: future:: Future < Output = bool > + core:: marker:: Unpin ,
392
428
Sleeper : Fn ( Duration ) -> SleepFuture
393
429
> (
@@ -417,10 +453,14 @@ where
417
453
let async_event_handler = |event| {
418
454
let network_graph = gossip_sync. network_graph ( ) ;
419
455
let event_handler = & event_handler;
456
+ let scorer = & scorer;
420
457
async move {
421
458
if let Some ( network_graph) = network_graph {
422
459
handle_network_graph_update ( network_graph, & event)
423
460
}
461
+ if let Some ( ref scorer) = scorer {
462
+ update_scorer ( scorer, & event) ;
463
+ }
424
464
event_handler ( event) . await ;
425
465
}
426
466
} ;
@@ -516,7 +556,7 @@ impl BackgroundProcessor {
516
556
UMH : ' static + Deref + Send + Sync ,
517
557
PM : ' static + Deref < Target = PeerManager < Descriptor , CMH , RMH , OMH , L , UMH , NS > > + Send + Sync ,
518
558
S : ' static + Deref < Target = SC > + Send + Sync ,
519
- SC : WriteableScore < ' a > ,
559
+ SC : for < ' b > WriteableScore < ' b > ,
520
560
> (
521
561
persister : PS , event_handler : EH , chain_monitor : M , channel_manager : CM ,
522
562
gossip_sync : GossipSync < PGS , RGS , G , CA , L > , peer_manager : PM , logger : L , scorer : Option < S > ,
@@ -547,6 +587,9 @@ impl BackgroundProcessor {
547
587
if let Some ( network_graph) = network_graph {
548
588
handle_network_graph_update ( network_graph, & event)
549
589
}
590
+ if let Some ( ref scorer) = scorer {
591
+ update_scorer ( scorer, & event) ;
592
+ }
550
593
event_handler. handle_event ( event) ;
551
594
} ;
552
595
define_run_body ! ( persister, chain_monitor, chain_monitor. process_pending_events( & event_handler) ,
@@ -613,14 +656,16 @@ mod tests {
613
656
use bitcoin:: blockdata:: locktime:: PackedLockTime ;
614
657
use bitcoin:: blockdata:: transaction:: { Transaction , TxOut } ;
615
658
use bitcoin:: network:: constants:: Network ;
659
+ use bitcoin:: secp256k1:: { SecretKey , PublicKey , Secp256k1 } ;
616
660
use lightning:: chain:: { BestBlock , Confirm , chainmonitor} ;
617
661
use lightning:: chain:: channelmonitor:: ANTI_REORG_DELAY ;
618
662
use lightning:: chain:: keysinterface:: { InMemorySigner , EntropySource , KeysManager } ;
619
663
use lightning:: chain:: transaction:: OutPoint ;
620
664
use lightning:: get_event_msg;
665
+ use lightning:: ln:: PaymentHash ;
621
666
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 } ;
624
669
use lightning:: ln:: msgs:: { ChannelMessageHandler , Init } ;
625
670
use lightning:: ln:: peer_handler:: { PeerManager , MessageHandler , SocketDescriptor , IgnoringMessageHandler } ;
626
671
use lightning:: routing:: gossip:: { NetworkGraph , NodeId , P2PGossipSync } ;
@@ -1296,4 +1341,124 @@ mod tests {
1296
1341
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 ( ) ) ) ;
1297
1342
assert ! ( bg_processor. stop( ) . is_ok( ) ) ;
1298
1343
}
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
+ }
1299
1464
}
0 commit comments