mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 06:57:53 +01:00
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".
This commit is contained in:
parent
e1ad422c1b
commit
8dc7cfab3a
4 changed files with 50 additions and 40 deletions
|
@ -73,7 +73,7 @@
|
|||
//! # struct FakeScorer {};
|
||||
//! # impl routing::Score for FakeScorer {
|
||||
//! # fn channel_penalty_msat(
|
||||
//! # &self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId
|
||||
//! # &self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId
|
||||
//! # ) -> u64 { 0 }
|
||||
//! # fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
|
||||
//! # }
|
||||
|
@ -1227,7 +1227,7 @@ mod tests {
|
|||
|
||||
impl routing::Score for TestScorer {
|
||||
fn channel_penalty_msat(
|
||||
&self, _short_channel_id: u64, _source: &NodeId, _target: &NodeId
|
||||
&self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId
|
||||
) -> u64 { 0 }
|
||||
|
||||
fn payment_path_failed(&mut self, _path: &[&RouteHop], short_channel_id: u64) {
|
||||
|
|
|
@ -24,9 +24,19 @@ use sync::{Mutex, MutexGuard};
|
|||
///
|
||||
/// Scoring is in terms of fees willing to be paid in order to avoid routing through a channel.
|
||||
pub trait Score {
|
||||
/// Returns the fee in msats willing to be paid to avoid routing through the given channel
|
||||
/// in the direction from `source` to `target`.
|
||||
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId) -> u64;
|
||||
/// Returns the fee in msats willing to be paid to avoid routing `send_amt_msat` through the
|
||||
/// given channel in the direction from `source` to `target`.
|
||||
///
|
||||
/// The channel's capacity (less any other MPP parts which are also being considered for use in
|
||||
/// the same payment) is given by `channel_capacity_msat`. It may be guessed from various
|
||||
/// sources or assumed from no data at all.
|
||||
///
|
||||
/// For hints provided in the invoice, we assume the channel has sufficient capacity to accept
|
||||
/// the invoice's full amount, and provide a `channel_capacity_msat` of `None`. In all other
|
||||
/// cases it is set to `Some`, even if we're guessing at the channel value.
|
||||
///
|
||||
/// Your code should be overflow-safe through a `channel_capacity_msat` of 21 million BTC.
|
||||
fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, channel_capacity_msat: Option<u64>, source: &NodeId, target: &NodeId) -> u64;
|
||||
|
||||
/// Handles updating channel penalties after failing to route through a channel.
|
||||
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> {
|
|||
}
|
||||
|
||||
impl<S: Score, T: DerefMut<Target=S>> Score for T {
|
||||
fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId) -> u64 {
|
||||
self.deref().channel_penalty_msat(short_channel_id, source, target)
|
||||
fn channel_penalty_msat(&self, short_channel_id: u64, send_amt_msat: u64, channel_capacity_msat: Option<u64>, source: &NodeId, target: &NodeId) -> u64 {
|
||||
self.deref().channel_penalty_msat(short_channel_id, send_amt_msat, channel_capacity_msat, source, target)
|
||||
}
|
||||
|
||||
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
|
||||
|
|
|
@ -892,9 +892,9 @@ where L::Target: Logger {
|
|||
}
|
||||
}
|
||||
|
||||
let path_penalty_msat = $next_hops_path_penalty_msat
|
||||
.checked_add(scorer.channel_penalty_msat($chan_id.clone(), &$src_node_id, &$dest_node_id))
|
||||
.unwrap_or_else(|| u64::max_value());
|
||||
let path_penalty_msat = $next_hops_path_penalty_msat.checked_add(
|
||||
scorer.channel_penalty_msat($chan_id.clone(), amount_to_transfer_over_msat, Some(*available_liquidity_msat),
|
||||
&$src_node_id, &$dest_node_id)).unwrap_or_else(|| u64::max_value());
|
||||
let new_graph_node = RouteGraphNode {
|
||||
node_id: $src_node_id,
|
||||
lowest_fee_to_peer_through_node: total_fee_msat,
|
||||
|
@ -1121,7 +1121,7 @@ where L::Target: Logger {
|
|||
let src_node_id = NodeId::from_pubkey(&hop.src_node_id);
|
||||
let dest_node_id = NodeId::from_pubkey(&prev_hop_id);
|
||||
aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
|
||||
.checked_add(scorer.channel_penalty_msat(hop.short_channel_id, &src_node_id, &dest_node_id))
|
||||
.checked_add(scorer.channel_penalty_msat(hop.short_channel_id, final_value_msat, None, &src_node_id, &dest_node_id))
|
||||
.unwrap_or_else(|| u64::max_value());
|
||||
|
||||
// We assume that the recipient only included route hints for routes which had
|
||||
|
@ -4550,7 +4550,7 @@ mod tests {
|
|||
}
|
||||
|
||||
impl routing::Score for BadChannelScorer {
|
||||
fn channel_penalty_msat(&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId) -> u64 {
|
||||
fn channel_penalty_msat(&self, short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, _target: &NodeId) -> u64 {
|
||||
if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
|
||||
}
|
||||
|
||||
|
@ -4562,7 +4562,7 @@ mod tests {
|
|||
}
|
||||
|
||||
impl routing::Score for BadNodeScorer {
|
||||
fn channel_penalty_msat(&self, _short_channel_id: u64, _source: &NodeId, target: &NodeId) -> u64 {
|
||||
fn channel_penalty_msat(&self, _short_channel_id: u64, _send_amt: u64, _chan_amt: Option<u64>, _source: &NodeId, target: &NodeId) -> u64 {
|
||||
if *target == self.node_id { u64::max_value() } else { 0 }
|
||||
}
|
||||
|
||||
|
|
|
@ -211,7 +211,7 @@ impl Default for ScoringParameters {
|
|||
|
||||
impl<T: Time> routing::Score for ScorerUsingTime<T> {
|
||||
fn channel_penalty_msat(
|
||||
&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId
|
||||
&self, short_channel_id: u64, _send_amt_msat: u64, _chan_capacity_msat: Option<u64>, _source: &NodeId, _target: &NodeId
|
||||
) -> u64 {
|
||||
let failure_penalty_msat = self.channel_failures
|
||||
.get(&short_channel_id)
|
||||
|
@ -417,10 +417,10 @@ mod tests {
|
|||
});
|
||||
let source = source_node_id();
|
||||
let target = target_node_id();
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(1));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -432,16 +432,16 @@ mod tests {
|
|||
});
|
||||
let source = source_node_id();
|
||||
let target = target_node_id();
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_064);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_064);
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_128);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_128);
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_192);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_192);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -453,25 +453,25 @@ mod tests {
|
|||
});
|
||||
let source = source_node_id();
|
||||
let target = target_node_id();
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(9));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(1));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_256);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10 * 8));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_001);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_001);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -483,19 +483,19 @@ mod tests {
|
|||
});
|
||||
let source = source_node_id();
|
||||
let target = target_node_id();
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_000);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_000);
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_256);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_768);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_768);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_384);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_384);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -509,20 +509,20 @@ mod tests {
|
|||
let target = target_node_id();
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_256);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
|
||||
|
||||
scorer.payment_path_failed(&[], 43);
|
||||
assert_eq!(scorer.channel_penalty_msat(43, &source, &target), 1_512);
|
||||
assert_eq!(scorer.channel_penalty_msat(43, 1, Some(1), &source, &target), 1_512);
|
||||
|
||||
let mut serialized_scorer = Vec::new();
|
||||
scorer.write(&mut serialized_scorer).unwrap();
|
||||
|
||||
let deserialized_scorer = <Scorer>::read(&mut io::Cursor::new(&serialized_scorer)).unwrap();
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target), 1_256);
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(43, &source, &target), 1_512);
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(43, 1, Some(1), &source, &target), 1_512);
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -536,7 +536,7 @@ mod tests {
|
|||
let target = target_node_id();
|
||||
|
||||
scorer.payment_path_failed(&[], 42);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, &source, &target), 1_512);
|
||||
assert_eq!(scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_512);
|
||||
|
||||
let mut serialized_scorer = Vec::new();
|
||||
scorer.write(&mut serialized_scorer).unwrap();
|
||||
|
@ -544,9 +544,9 @@ mod tests {
|
|||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
|
||||
let deserialized_scorer = <Scorer>::read(&mut io::Cursor::new(&serialized_scorer)).unwrap();
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target), 1_256);
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_256);
|
||||
|
||||
SinceEpoch::advance(Duration::from_secs(10));
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target), 1_128);
|
||||
assert_eq!(deserialized_scorer.channel_penalty_msat(42, 1, Some(1), &source, &target), 1_128);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue