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