Skip to content

Commit 5fa9c20

Browse files
committed
Add unit tests for Scorer
Test basic and channel failure penalties, including after a (de-)serialization round trip.
1 parent 78bac94 commit 5fa9c20

File tree

1 file changed

+155
-0
lines changed

1 file changed

+155
-0
lines changed

lightning/src/routing/scorer.rs

Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,11 +328,13 @@ mod tests {
328328

329329
use routing::Score;
330330
use routing::network_graph::NodeId;
331+
use util::ser::{Readable, Writeable};
331332

332333
use bitcoin::secp256k1::PublicKey;
333334
use core::cell::Cell;
334335
use core::ops::Sub;
335336
use core::time::Duration;
337+
use io;
336338

337339
/// Time that can be advanced manually in tests.
338340
#[derive(Debug, PartialEq, Eq)]
@@ -407,4 +409,157 @@ mod tests {
407409
assert!(elapsed >= Duration::from_secs(0));
408410
assert!(later - elapsed >= now);
409411
}
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+
}
410565
}

0 commit comments

Comments
 (0)