Skip to content

Commit b57ed79

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

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

0 commit comments

Comments
 (0)