Skip to content

Commit 8dc7cfa

Browse files
committed
Provide Score the HTLC amount and channel capacity
This should allow `Score` implementations to make substantially better decisions, including of the form "willing to pay X to avoid routing over this channel which may have a high failure rate".
1 parent e1ad422 commit 8dc7cfa

File tree

4 files changed

+50
-40
lines changed

4 files changed

+50
-40
lines changed

lightning-invoice/src/payment.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@
7373
//! # struct FakeScorer {};
7474
//! # impl routing::Score for FakeScorer {
7575
//! # fn channel_penalty_msat(
76-
//! # &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId
76+
//! # &self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId
7777
//! # ) -> u64 { 0 }
7878
//! # fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
7979
//! # }
@@ -1227,7 +1227,7 @@ mod tests {
12271227

12281228
impl routing::Score for TestScorer {
12291229
fn channel_penalty_msat(
1230-
&self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId
1230+
&self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId
12311231
) -> u64 { 0 }
12321232

12331233
fn payment_path_failed(&mut self, _path: &[&RouteHop], short_channel_id: u64) {

lightning/src/routing/mod.rs

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,19 @@ use sync::{Mutex, MutexGuard};
2424
///
2525
/// Scoring is in terms of fees willing to be paid in order to avoid routing through a channel.
2626
pub trait Score {
27-
/// Returns the fee in msats willing to be paid to avoid routing through the given channel
28-
/// in the direction from `source` to `target`.
29-
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId) -> u64;
27+
/// Returns the fee in msats willing to be paid to avoid routing `send_amt_msat` through the
28+
/// given channel in the direction from `source` to `target`.
29+
///
30+
/// The channel's capacity (less any other MPP parts which are also being considered for use in
31+
/// the same payment) is given by `channel_capacity_msat`. It may be guessed from various
32+
/// sources or assumed from no data at all.
33+
///
34+
/// For hints provided in the invoice, we assume the channel has sufficient capacity to accept
35+
/// the invoice's full amount, and provide a `channel_capacity_msat` of `None`. In all other
36+
/// cases it is set to `Some`, even if we're guessing at the channel value.
37+
///
38+
/// Your code should be overflow-safe through a `channel_capacity_msat` of 21 million BTC.
39+
fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, channel_capacity_msat: Option<u64>, source: &NodeId, target: &NodeId) -> u64;
3040

3141
/// Handles updating channel penalties after failing to route through a channel.
3242
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64);
@@ -65,8 +75,8 @@ impl<'a, T: 'a + Score> LockableScore<'a> for RefCell<T> {
6575
}
6676

6777
impl<S: Score, T: DerefMut<Target=S>> Score for T {
68-
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId) -> u64 {
69-
self.deref().channel_penalty_msat(short_channel_id, source, target)
78+
fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, channel_capacity_msat: Option<u64>, source: &NodeId, target: &NodeId) -> u64 {
79+
self.deref().channel_penalty_msat(short_channel_id, send_amt_msat, channel_capacity_msat, source, target)
7080
}
7181

7282
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {

lightning/src/routing/router.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -892,9 +892,9 @@ where L::Target: Logger {
892892
}
893893
}
894894

895-
let path_penalty_msat = $next_hops_path_penalty_msat
896-
.checked_add(scorer.channel_penalty_msat($chan_id.clone(), &$src_node_id, &$dest_node_id))
897-
.unwrap_or_else(|| u64::max_value());
895+
let path_penalty_msat = $next_hops_path_penalty_msat.checked_add(
896+
scorer.channel_penalty_msat($chan_id.clone(), amount_to_transfer_over_msat, Some(*available_liquidity_msat),
897+
&$src_node_id, &$dest_node_id)).unwrap_or_else(|| u64::max_value());
898898
let new_graph_node = RouteGraphNode {
899899
node_id: $src_node_id,
900900
lowest_fee_to_peer_through_node: total_fee_msat,
@@ -1121,7 +1121,7 @@ where L::Target: Logger {
11211121
let src_node_id = NodeId::from_pubkey(&hop.src_node_id);
11221122
let dest_node_id = NodeId::from_pubkey(&prev_hop_id);
11231123
aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
1124-
.checked_add(scorer.channel_penalty_msat(hop.short_channel_id, &src_node_id, &dest_node_id))
1124+
.checked_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, None, &src_node_id, &dest_node_id))
11251125
.unwrap_or_else(|| u64::max_value());
11261126

11271127
// We assume that the recipient only included route hints for routes which had
@@ -4550,7 +4550,7 @@ mod tests {
45504550
}
45514551

45524552
impl routing::Score for BadChannelScorer {
4553-
fn channel_penalty_msat(&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId) -> u64 {
4553+
fn channel_penalty_msat(&self, short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId) -> u64 {
45544554
if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
45554555
}
45564556

@@ -4562,7 +4562,7 @@ mod tests {
45624562
}
45634563

45644564
impl routing::Score for BadNodeScorer {
4565-
fn channel_penalty_msat(&self, _short_channel_id: u64, _source: &NodeId, target: &NodeId) -> u64 {
4565+
fn channel_penalty_msat(&self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, target: &NodeId) -> u64 {
45664566
if *target == self.node_id { u64::max_value() } else { 0 }
45674567
}
45684568

lightning/src/routing/scorer.rs

Lines changed: 27 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,7 @@ impl Default for ScoringParameters {
211211

212212
impl<T: Time> routing::Score for ScorerUsingTime<T> {
213213
fn channel_penalty_msat(
214-
&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId
214+
&self, short_channel_id: u64, _send_amt_msat: u64, _chan_capacity_msat: Option<u64>, _source: &NodeId, _target: &NodeId
215215
) -> u64 {
216216
let failure_penalty_msat = self.channel_failures
217217
.get(&short_channel_id)
@@ -417,10 +417,10 @@ mod tests {
417417
});
418418
let source = source_node_id();
419419
let target = target_node_id();
420-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
420+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
421421

422422
SinceEpoch::advance(Duration::from_secs(1));
423-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
423+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
424424
}
425425

426426
#[test]
@@ -432,16 +432,16 @@ mod tests {
432432
});
433433
let source = source_node_id();
434434
let target = target_node_id();
435-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
435+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
436436

437437
scorer.payment_path_failed(&[], 42);
438-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_064);
438+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_064);
439439

440440
scorer.payment_path_failed(&[], 42);
441-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_128);
441+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_128);
442442

443443
scorer.payment_path_failed(&[], 42);
444-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_192);
444+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_192);
445445
}
446446

447447
#[test]
@@ -453,25 +453,25 @@ mod tests {
453453
});
454454
let source = source_node_id();
455455
let target = target_node_id();
456-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
456+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
457457

458458
scorer.payment_path_failed(&[], 42);
459-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
459+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
460460

461461
SinceEpoch::advance(Duration::from_secs(9));
462-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
462+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
463463

464464
SinceEpoch::advance(Duration::from_secs(1));
465-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_256);
465+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
466466

467467
SinceEpoch::advance(Duration::from_secs(10 * 8));
468-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_001);
468+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_001);
469469

470470
SinceEpoch::advance(Duration::from_secs(10));
471-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
471+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
472472

473473
SinceEpoch::advance(Duration::from_secs(10));
474-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
474+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
475475
}
476476

477477
#[test]
@@ -483,19 +483,19 @@ mod tests {
483483
});
484484
let source = source_node_id();
485485
let target = target_node_id();
486-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
486+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
487487

488488
scorer.payment_path_failed(&[], 42);
489-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
489+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
490490

491491
SinceEpoch::advance(Duration::from_secs(10));
492-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_256);
492+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
493493

494494
scorer.payment_path_failed(&[], 42);
495-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_768);
495+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_768);
496496

497497
SinceEpoch::advance(Duration::from_secs(10));
498-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_384);
498+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_384);
499499
}
500500

501501
#[test]
@@ -509,20 +509,20 @@ mod tests {
509509
let target = target_node_id();
510510

511511
scorer.payment_path_failed(&[], 42);
512-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
512+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
513513

514514
SinceEpoch::advance(Duration::from_secs(10));
515-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_256);
515+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
516516

517517
scorer.payment_path_failed(&[], 43);
518-
assert_eq!(scorer.channel_penalty_msat(43, &source, &target), 1_512);
518+
assert_eq!(scorer.channel_penalty_msat(43, 1, Some(1), &source, &target), 1_512);
519519

520520
let mut serialized_scorer = Vec::new();
521521
scorer.write(&mut serialized_scorer).unwrap();
522522

523523
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);
524+
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
525+
assert_eq!(deserialized_scorer.channel_penalty_msat(43, 1, Some(1), &source, &target), 1_512);
526526
}
527527

528528
#[test]
@@ -536,17 +536,17 @@ mod tests {
536536
let target = target_node_id();
537537

538538
scorer.payment_path_failed(&[], 42);
539-
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
539+
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
540540

541541
let mut serialized_scorer = Vec::new();
542542
scorer.write(&mut serialized_scorer).unwrap();
543543

544544
SinceEpoch::advance(Duration::from_secs(10));
545545

546546
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);
547+
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
548548

549549
SinceEpoch::advance(Duration::from_secs(10));
550-
assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target), 1_128);
550+
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_128);
551551
}
552552
}

0 commit comments

Comments
 (0)