@@ -328,11 +328,13 @@ mod tests {
328
328
329
329
use routing:: Score ;
330
330
use routing:: network_graph:: NodeId ;
331
+ use util:: ser:: { Readable , Writeable } ;
331
332
332
333
use bitcoin:: secp256k1:: PublicKey ;
333
334
use core:: cell:: Cell ;
334
335
use core:: ops:: Sub ;
335
336
use core:: time:: Duration ;
337
+ use io;
336
338
337
339
/// Time that can be advanced manually in tests.
338
340
#[ derive( Debug , PartialEq , Eq ) ]
@@ -408,4 +410,157 @@ mod tests {
408
410
assert ! ( elapsed > Duration :: from_secs( 0 ) ) ;
409
411
assert ! ( later - elapsed > now) ;
410
412
}
413
+
414
+ /// A scorer for testing with time that can be manually advanced.
415
+ type Scorer = ScorerUsingTime :: < SinceEpoch > ;
416
+
417
+ fn source_node_id ( ) -> NodeId {
418
+ NodeId :: from_pubkey ( & PublicKey :: from_slice ( & hex:: decode ( "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619" ) . unwrap ( ) [ ..] ) . unwrap ( ) )
419
+ }
420
+
421
+ fn target_node_id ( ) -> NodeId {
422
+ NodeId :: from_pubkey ( & PublicKey :: from_slice ( & hex:: decode ( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap ( ) [ ..] ) . unwrap ( ) )
423
+ }
424
+
425
+ #[ test]
426
+ fn penalizes_without_channel_failures ( ) {
427
+ let scorer = Scorer :: new ( ScoringParameters {
428
+ base_penalty_msat : 1_000 ,
429
+ failure_penalty_msat : 512 ,
430
+ failure_penalty_half_life : Duration :: from_secs ( 1 ) ,
431
+ } ) ;
432
+ let source = source_node_id ( ) ;
433
+ let target = target_node_id ( ) ;
434
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
435
+
436
+ SinceEpoch :: advance ( Duration :: from_secs ( 1 ) ) ;
437
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
438
+ }
439
+
440
+ #[ test]
441
+ fn accumulates_channel_failure_penalties ( ) {
442
+ let mut scorer = Scorer :: new ( ScoringParameters {
443
+ base_penalty_msat : 1_000 ,
444
+ failure_penalty_msat : 64 ,
445
+ failure_penalty_half_life : Duration :: from_secs ( 10 ) ,
446
+ } ) ;
447
+ let source = source_node_id ( ) ;
448
+ let target = target_node_id ( ) ;
449
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
450
+
451
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
452
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_064 ) ;
453
+
454
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
455
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_128 ) ;
456
+
457
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
458
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_192 ) ;
459
+ }
460
+
461
+ #[ test]
462
+ fn decays_channel_failure_penalties_over_time ( ) {
463
+ let mut scorer = Scorer :: new ( ScoringParameters {
464
+ base_penalty_msat : 1_000 ,
465
+ failure_penalty_msat : 512 ,
466
+ failure_penalty_half_life : Duration :: from_secs ( 10 ) ,
467
+ } ) ;
468
+ let source = source_node_id ( ) ;
469
+ let target = target_node_id ( ) ;
470
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
471
+
472
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
473
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_512 ) ;
474
+
475
+ SinceEpoch :: advance ( Duration :: from_secs ( 9 ) ) ;
476
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_512 ) ;
477
+
478
+ SinceEpoch :: advance ( Duration :: from_secs ( 1 ) ) ;
479
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_256 ) ;
480
+
481
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 * 8 ) ) ;
482
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_001 ) ;
483
+
484
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
485
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
486
+
487
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
488
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
489
+ }
490
+
491
+ #[ test]
492
+ fn accumulates_channel_failure_penalties_after_decay ( ) {
493
+ let mut scorer = Scorer :: new ( ScoringParameters {
494
+ base_penalty_msat : 1_000 ,
495
+ failure_penalty_msat : 512 ,
496
+ failure_penalty_half_life : Duration :: from_secs ( 10 ) ,
497
+ } ) ;
498
+ let source = source_node_id ( ) ;
499
+ let target = target_node_id ( ) ;
500
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_000 ) ;
501
+
502
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
503
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_512 ) ;
504
+
505
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
506
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_256 ) ;
507
+
508
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
509
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_768 ) ;
510
+
511
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
512
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_384 ) ;
513
+ }
514
+
515
+ #[ test]
516
+ fn restores_persisted_channel_failure_penalties ( ) {
517
+ let mut scorer = Scorer :: new ( ScoringParameters {
518
+ base_penalty_msat : 1_000 ,
519
+ failure_penalty_msat : 512 ,
520
+ failure_penalty_half_life : Duration :: from_secs ( 10 ) ,
521
+ } ) ;
522
+ let source = source_node_id ( ) ;
523
+ let target = target_node_id ( ) ;
524
+
525
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
526
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_512 ) ;
527
+
528
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
529
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_256 ) ;
530
+
531
+ scorer. payment_path_failed ( & [ ] , 43 ) ;
532
+ assert_eq ! ( scorer. channel_penalty_msat( 43 , & source, & target) , 1_512 ) ;
533
+
534
+ let mut serialized_scorer = Vec :: new ( ) ;
535
+ scorer. write ( & mut serialized_scorer) . unwrap ( ) ;
536
+
537
+ let deserialized_scorer = <Scorer >:: read ( & mut io:: Cursor :: new ( & serialized_scorer) ) . unwrap ( ) ;
538
+ assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , & source, & target) , 1_256 ) ;
539
+ assert_eq ! ( deserialized_scorer. channel_penalty_msat( 43 , & source, & target) , 1_512 ) ;
540
+ }
541
+
542
+ #[ test]
543
+ fn decays_persisted_channel_failure_penalties ( ) {
544
+ let mut scorer = Scorer :: new ( ScoringParameters {
545
+ base_penalty_msat : 1_000 ,
546
+ failure_penalty_msat : 512 ,
547
+ failure_penalty_half_life : Duration :: from_secs ( 10 ) ,
548
+ } ) ;
549
+ let source = source_node_id ( ) ;
550
+ let target = target_node_id ( ) ;
551
+
552
+ scorer. payment_path_failed ( & [ ] , 42 ) ;
553
+ assert_eq ! ( scorer. channel_penalty_msat( 42 , & source, & target) , 1_512 ) ;
554
+
555
+ let mut serialized_scorer = Vec :: new ( ) ;
556
+ scorer. write ( & mut serialized_scorer) . unwrap ( ) ;
557
+
558
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
559
+
560
+ let deserialized_scorer = <Scorer >:: read ( & mut io:: Cursor :: new ( & serialized_scorer) ) . unwrap ( ) ;
561
+ assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , & source, & target) , 1_256 ) ;
562
+
563
+ SinceEpoch :: advance ( Duration :: from_secs ( 10 ) ) ;
564
+ assert_eq ! ( deserialized_scorer. channel_penalty_msat( 42 , & source, & target) , 1_128 ) ;
565
+ }
411
566
}
0 commit comments