Merge pull request #1166 from TheBlueMatt/2021-11-chan-size-scoring

This commit is contained in:
Matt Corallo 2021-11-16 22:10:42 +00:00 committed by GitHub
commit 77948dbcd7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
9 changed files with 211 additions and 138 deletions

View file

@ -39,7 +39,7 @@ use lightning::ln::msgs::DecodeError;
use lightning::ln::script::ShutdownScript;
use lightning::routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
use lightning::routing::router::{find_route, Payee, RouteParameters};
use lightning::routing::scorer::Scorer;
use lightning::routing::scoring::Scorer;
use lightning::util::config::UserConfig;
use lightning::util::errors::APIError;
use lightning::util::events::Event;

View file

@ -17,7 +17,7 @@ use lightning::ln::channelmanager::{ChannelDetails, ChannelCounterparty};
use lightning::ln::features::InitFeatures;
use lightning::ln::msgs;
use lightning::routing::router::{find_route, Payee, RouteHint, RouteHintHop, RouteParameters};
use lightning::routing::scorer::Scorer;
use lightning::routing::scoring::Scorer;
use lightning::util::logger::Logger;
use lightning::util::ser::Readable;
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};

View file

@ -31,7 +31,7 @@
//! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
//! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
//! # use lightning::ln::msgs::LightningError;
//! # use lightning::routing;
//! # use lightning::routing::scoring::Score;
//! # use lightning::routing::network_graph::NodeId;
//! # use lightning::routing::router::{Route, RouteHop, RouteParameters};
//! # use lightning::util::events::{Event, EventHandler, EventsProvider};
@ -63,7 +63,7 @@
//! # }
//! #
//! # struct FakeRouter {};
//! # impl<S: routing::Score> Router<S> for FakeRouter {
//! # impl<S: Score> Router<S> for FakeRouter {
//! # fn find_route(
//! # &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
//! # first_hops: Option<&[&ChannelDetails]>, scorer: &S
@ -71,9 +71,9 @@
//! # }
//! #
//! # struct FakeScorer {};
//! # impl routing::Score for FakeScorer {
//! # impl 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) {}
//! # }
@ -122,8 +122,7 @@ use bitcoin_hashes::sha256::Hash as Sha256;
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
use lightning::ln::msgs::LightningError;
use lightning::routing;
use lightning::routing::{LockableScore, Score};
use lightning::routing::scoring::{LockableScore, Score};
use lightning::routing::router::{Payee, Route, RouteParameters};
use lightning::util::events::{Event, EventHandler};
use lightning::util::logger::Logger;
@ -139,8 +138,8 @@ use std::time::{Duration, SystemTime};
pub struct InvoicePayer<P: Deref, R, S: Deref, L: Deref, E>
where
P::Target: Payer,
R: for <'a> Router<<<S as Deref>::Target as routing::LockableScore<'a>>::Locked>,
S::Target: for <'a> routing::LockableScore<'a>,
R: for <'a> Router<<<S as Deref>::Target as LockableScore<'a>>::Locked>,
S::Target: for <'a> LockableScore<'a>,
L::Target: Logger,
E: EventHandler,
{
@ -177,7 +176,7 @@ pub trait Payer {
}
/// A trait defining behavior for routing an [`Invoice`] payment.
pub trait Router<S: routing::Score> {
pub trait Router<S: Score> {
/// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
fn find_route(
&self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
@ -207,8 +206,8 @@ pub enum PaymentError {
impl<P: Deref, R, S: Deref, L: Deref, E> InvoicePayer<P, R, S, L, E>
where
P::Target: Payer,
R: for <'a> Router<<<S as Deref>::Target as routing::LockableScore<'a>>::Locked>,
S::Target: for <'a> routing::LockableScore<'a>,
R: for <'a> Router<<<S as Deref>::Target as LockableScore<'a>>::Locked>,
S::Target: for <'a> LockableScore<'a>,
L::Target: Logger,
E: EventHandler,
{
@ -441,8 +440,8 @@ fn has_expired(params: &RouteParameters) -> bool {
impl<P: Deref, R, S: Deref, L: Deref, E> EventHandler for InvoicePayer<P, R, S, L, E>
where
P::Target: Payer,
R: for <'a> Router<<<S as Deref>::Target as routing::LockableScore<'a>>::Locked>,
S::Target: for <'a> routing::LockableScore<'a>,
R: for <'a> Router<<<S as Deref>::Target as LockableScore<'a>>::Locked>,
S::Target: for <'a> LockableScore<'a>,
L::Target: Logger,
E: EventHandler,
{
@ -1186,7 +1185,7 @@ mod tests {
}
}
impl<S: routing::Score> Router<S> for TestRouter {
impl<S: Score> Router<S> for TestRouter {
fn find_route(
&self, _payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
@ -1199,7 +1198,7 @@ mod tests {
struct FailingRouter;
impl<S: routing::Score> Router<S> for FailingRouter {
impl<S: Score> Router<S> for FailingRouter {
fn find_route(
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
@ -1225,9 +1224,9 @@ mod tests {
}
}
impl routing::Score for TestScorer {
impl 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) {
@ -1364,7 +1363,7 @@ mod tests {
// *** Full Featured Functional Tests with a Real ChannelManager ***
struct ManualRouter(RefCell<VecDeque<Result<Route, LightningError>>>);
impl<S: routing::Score> Router<S> for ManualRouter {
impl<S: Score> Router<S> for ManualRouter {
fn find_route(
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S

View file

@ -11,7 +11,7 @@ use lightning::chain::keysinterface::{Sign, KeysInterface};
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY};
use lightning::ln::msgs::LightningError;
use lightning::routing;
use lightning::routing::scoring::Score;
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
use lightning::util::logger::Logger;
@ -109,7 +109,7 @@ impl<G, L: Deref> DefaultRouter<G, L> where G: Deref<Target = NetworkGraph>, L::
}
}
impl<G, L: Deref, S: routing::Score> Router<S> for DefaultRouter<G, L>
impl<G, L: Deref, S: Score> Router<S> for DefaultRouter<G, L>
where G: Deref<Target = NetworkGraph>, L::Target: Logger {
fn find_route(
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,

View file

@ -6552,7 +6552,7 @@ pub mod bench {
use ln::msgs::{ChannelMessageHandler, Init};
use routing::network_graph::NetworkGraph;
use routing::router::{Payee, get_route};
use routing::scorer::Scorer;
use routing::scoring::Scorer;
use util::test_utils;
use util::config::UserConfig;
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};

View file

@ -11,65 +11,4 @@
pub mod network_graph;
pub mod router;
pub mod scorer;
use routing::network_graph::NodeId;
use routing::router::RouteHop;
use core::cell::{RefCell, RefMut};
use core::ops::DerefMut;
use sync::{Mutex, MutexGuard};
/// An interface used to score payment channels for path finding.
///
/// 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;
/// Handles updating channel penalties after failing to route through a channel.
fn payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64);
}
/// A scorer that is accessed under a lock.
///
/// Needed so that calls to [`Score::channel_penalty_msat`] in [`find_route`] can be made while
/// having shared ownership of a scorer but without requiring internal locking in [`Score`]
/// implementations. Internal locking would be detrimental to route finding performance and could
/// result in [`Score::channel_penalty_msat`] returning a different value for the same channel.
///
/// [`find_route`]: crate::routing::router::find_route
pub trait LockableScore<'a> {
/// The locked [`Score`] type.
type Locked: 'a + Score;
/// Returns the locked scorer.
fn lock(&'a self) -> Self::Locked;
}
impl<'a, T: 'a + Score> LockableScore<'a> for Mutex<T> {
type Locked = MutexGuard<'a, T>;
fn lock(&'a self) -> MutexGuard<'a, T> {
Mutex::lock(self).unwrap()
}
}
impl<'a, T: 'a + Score> LockableScore<'a> for RefCell<T> {
type Locked = RefMut<'a, T>;
fn lock(&'a self) -> RefMut<'a, T> {
self.borrow_mut()
}
}
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 payment_path_failed(&mut self, path: &[&RouteHop], short_channel_id: u64) {
self.deref_mut().payment_path_failed(path, short_channel_id)
}
}
pub mod scoring;

View file

@ -17,7 +17,7 @@ use bitcoin::secp256k1::key::PublicKey;
use ln::channelmanager::ChannelDetails;
use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
use routing;
use routing::scoring::Score;
use routing::network_graph::{NetworkGraph, NodeId, RoutingFees};
use util::ser::{Writeable, Readable};
use util::logger::{Level, Logger};
@ -529,7 +529,7 @@ fn compute_fees(amount_msat: u64, channel_fees: RoutingFees) -> Option<u64> {
///
/// [`ChannelManager::list_usable_channels`]: crate::ln::channelmanager::ChannelManager::list_usable_channels
/// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
pub fn find_route<L: Deref, S: routing::Score>(
pub fn find_route<L: Deref, S: Score>(
our_node_pubkey: &PublicKey, params: &RouteParameters, network: &NetworkGraph,
first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S
) -> Result<Route, LightningError>
@ -540,7 +540,7 @@ where L::Target: Logger {
)
}
pub(crate) fn get_route<L: Deref, S: routing::Score>(
pub(crate) fn get_route<L: Deref, S: Score>(
our_node_pubkey: &PublicKey, payee: &Payee, network: &NetworkGraph,
first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32,
logger: L, scorer: &S
@ -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
@ -1472,7 +1472,7 @@ where L::Target: Logger {
#[cfg(test)]
mod tests {
use routing;
use routing::scoring::Score;
use routing::network_graph::{NetworkGraph, NetGraphMsgHandler, NodeId};
use routing::router::{get_route, Payee, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees};
use chain::transaction::OutPoint;
@ -4549,8 +4549,8 @@ mod tests {
short_channel_id: u64,
}
impl routing::Score for BadChannelScorer {
fn channel_penalty_msat(&self, short_channel_id: u64, _source: &NodeId, _target: &NodeId) -> u64 {
impl Score for BadChannelScorer {
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 }
}
@ -4561,8 +4561,8 @@ mod tests {
node_id: NodeId,
}
impl routing::Score for BadNodeScorer {
fn channel_penalty_msat(&self, _short_channel_id: u64, _source: &NodeId, target: &NodeId) -> u64 {
impl Score for BadNodeScorer {
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 }
}
@ -4787,7 +4787,7 @@ pub(crate) mod test_utils {
#[cfg(all(test, feature = "unstable", not(feature = "no-std")))]
mod benches {
use super::*;
use routing::scorer::Scorer;
use routing::scoring::Scorer;
use util::logger::{Logger, Record};
use test::Bencher;

View file

@ -10,7 +10,7 @@
//! Utilities for scoring payment channels.
//!
//! [`Scorer`] may be given to [`find_route`] to score payment channels during path finding when a
//! custom [`routing::Score`] implementation is not needed.
//! custom [`Score`] implementation is not needed.
//!
//! # Example
//!
@ -19,7 +19,7 @@
//! #
//! # use lightning::routing::network_graph::NetworkGraph;
//! # use lightning::routing::router::{RouteParameters, find_route};
//! # use lightning::routing::scorer::{Scorer, ScoringParameters};
//! # use lightning::routing::scoring::{Scorer, ScoringParameters};
//! # use lightning::util::logger::{Logger, Record};
//! # use secp256k1::key::PublicKey;
//! #
@ -52,26 +52,89 @@
//!
//! [`find_route`]: crate::routing::router::find_route
use routing;
use ln::msgs::DecodeError;
use routing::network_graph::NodeId;
use routing::router::RouteHop;
use util::ser::{Readable, Writeable, Writer};
use prelude::*;
use core::ops::Sub;
use core::cell::{RefCell, RefMut};
use core::ops::{DerefMut, Sub};
use core::time::Duration;
use io::{self, Read};
use io::{self, Read}; use sync::{Mutex, MutexGuard};
/// [`routing::Score`] implementation that provides reasonable default behavior.
/// An interface used to score payment channels for path finding.
///
/// 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 `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);
}
/// A scorer that is accessed under a lock.
///
/// Needed so that calls to [`Score::channel_penalty_msat`] in [`find_route`] can be made while
/// having shared ownership of a scorer but without requiring internal locking in [`Score`]
/// implementations. Internal locking would be detrimental to route finding performance and could
/// result in [`Score::channel_penalty_msat`] returning a different value for the same channel.
///
/// [`find_route`]: crate::routing::router::find_route
pub trait LockableScore<'a> {
/// The locked [`Score`] type.
type Locked: 'a + Score;
/// Returns the locked scorer.
fn lock(&'a self) -> Self::Locked;
}
impl<'a, T: 'a + Score> LockableScore<'a> for Mutex<T> {
type Locked = MutexGuard<'a, T>;
fn lock(&'a self) -> MutexGuard<'a, T> {
Mutex::lock(self).unwrap()
}
}
impl<'a, T: 'a + Score> LockableScore<'a> for RefCell<T> {
type Locked = RefMut<'a, T>;
fn lock(&'a self) -> RefMut<'a, T> {
self.borrow_mut()
}
}
impl<S: Score, T: DerefMut<Target=S>> Score for T {
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) {
self.deref_mut().payment_path_failed(path, short_channel_id)
}
}
/// [`Score`] implementation that provides reasonable default behavior.
///
/// Used to apply a fixed penalty to each channel, thus avoiding long paths when shorter paths with
/// slightly higher fees are available. Will further penalize channels that fail to relay payments.
///
/// See [module-level documentation] for usage.
///
/// [module-level documentation]: crate::routing::scorer
/// [module-level documentation]: crate::routing::scoring
pub type Scorer = ScorerUsingTime::<DefaultTime>;
/// Time used by [`Scorer`].
@ -82,7 +145,7 @@ pub type DefaultTime = std::time::Instant;
#[cfg(feature = "no-std")]
pub type DefaultTime = Eternity;
/// [`routing::Score`] implementation parameterized by [`Time`].
/// [`Score`] implementation parameterized by [`Time`].
///
/// See [`Scorer`] for details.
///
@ -98,6 +161,8 @@ pub struct ScorerUsingTime<T: Time> {
/// Parameters for configuring [`Scorer`].
pub struct ScoringParameters {
/// A fixed penalty in msats to apply to each channel.
///
/// Default value: 500 msat
pub base_penalty_msat: u64,
/// A penalty in msats to apply to a channel upon failing to relay a payment.
@ -105,9 +170,28 @@ pub struct ScoringParameters {
/// This accumulates for each failure but may be reduced over time based on
/// [`failure_penalty_half_life`].
///
/// Default value: 1,024,000 msat
///
/// [`failure_penalty_half_life`]: Self::failure_penalty_half_life
pub failure_penalty_msat: u64,
/// When the amount being sent over a channel is this many 1024ths of the total channel
/// capacity, we begin applying [`overuse_penalty_msat_per_1024th`].
///
/// Default value: 128 1024ths (i.e. begin penalizing when an HTLC uses 1/8th of a channel)
///
/// [`overuse_penalty_msat_per_1024th`]: Self::overuse_penalty_msat_per_1024th
pub overuse_penalty_start_1024th: u16,
/// A penalty applied, per whole 1024ths of the channel capacity which the amount being sent
/// over the channel exceeds [`overuse_penalty_start_1024th`] by.
///
/// Default value: 20 msat (i.e. 2560 msat penalty to use 1/4th of a channel, 7680 msat penalty
/// to use half a channel, and 12,560 msat penalty to use 3/4ths of a channel)
///
/// [`overuse_penalty_start_1024th`]: Self::overuse_penalty_start_1024th
pub overuse_penalty_msat_per_1024th: u64,
/// The time required to elapse before any accumulated [`failure_penalty_msat`] penalties are
/// cut in half.
///
@ -122,7 +206,9 @@ pub struct ScoringParameters {
impl_writeable_tlv_based!(ScoringParameters, {
(0, base_penalty_msat, required),
(1, overuse_penalty_start_1024th, (default_value, 128)),
(2, failure_penalty_msat, required),
(3, overuse_penalty_msat_per_1024th, (default_value, 20)),
(4, failure_penalty_half_life, required),
});
@ -167,6 +253,8 @@ impl<T: Time> ScorerUsingTime<T> {
base_penalty_msat: penalty_msat,
failure_penalty_msat: 0,
failure_penalty_half_life: Duration::from_secs(0),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
})
}
}
@ -205,19 +293,34 @@ impl Default for ScoringParameters {
base_penalty_msat: 500,
failure_penalty_msat: 1024 * 1000,
failure_penalty_half_life: Duration::from_secs(3600),
overuse_penalty_start_1024th: 1024 / 8,
overuse_penalty_msat_per_1024th: 20,
}
}
}
impl<T: Time> routing::Score for ScorerUsingTime<T> {
impl<T: Time> 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_opt: Option<u64>, _source: &NodeId, _target: &NodeId
) -> u64 {
let failure_penalty_msat = self.channel_failures
.get(&short_channel_id)
.map_or(0, |value| value.decayed_penalty_msat(self.params.failure_penalty_half_life));
self.params.base_penalty_msat + failure_penalty_msat
let mut penalty_msat = self.params.base_penalty_msat + failure_penalty_msat;
if let Some(chan_capacity_msat) = chan_capacity_opt {
let send_1024ths = send_amt_msat.checked_mul(1024).unwrap_or(u64::max_value()) / chan_capacity_msat;
if send_1024ths > self.params.overuse_penalty_start_1024th as u64 {
penalty_msat = penalty_msat.checked_add(
(send_1024ths - self.params.overuse_penalty_start_1024th as u64)
.checked_mul(self.params.overuse_penalty_msat_per_1024th).unwrap_or(u64::max_value()))
.unwrap_or(u64::max_value());
}
}
penalty_msat
}
fn payment_path_failed(&mut self, _path: &[&RouteHop], short_channel_id: u64) {
@ -326,7 +429,7 @@ impl<T: Time> Readable for ChannelFailure<T> {
mod tests {
use super::{Eternity, ScoringParameters, ScorerUsingTime, Time};
use routing::Score;
use routing::scoring::Score;
use routing::network_graph::NodeId;
use util::ser::{Readable, Writeable};
@ -414,13 +517,15 @@ mod tests {
base_penalty_msat: 1_000,
failure_penalty_msat: 512,
failure_penalty_half_life: Duration::from_secs(1),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
});
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]
@ -429,19 +534,21 @@ mod tests {
base_penalty_msat: 1_000,
failure_penalty_msat: 64,
failure_penalty_half_life: Duration::from_secs(10),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
});
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]
@ -450,28 +557,30 @@ mod tests {
base_penalty_msat: 1_000,
failure_penalty_msat: 512,
failure_penalty_half_life: Duration::from_secs(10),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
});
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]
@ -480,22 +589,24 @@ mod tests {
base_penalty_msat: 1_000,
failure_penalty_msat: 512,
failure_penalty_half_life: Duration::from_secs(10),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
});
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]
@ -504,25 +615,27 @@ mod tests {
base_penalty_msat: 1_000,
failure_penalty_msat: 512,
failure_penalty_half_life: Duration::from_secs(10),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
});
let source = source_node_id();
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]
@ -531,12 +644,14 @@ mod tests {
base_penalty_msat: 1_000,
failure_penalty_msat: 512,
failure_penalty_half_life: Duration::from_secs(10),
overuse_penalty_start_1024th: 1024,
overuse_penalty_msat_per_1024th: 0,
});
let source = source_node_id();
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 +659,29 @@ 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);
}
#[test]
fn charges_per_1024th_penalty() {
let scorer = Scorer::new(ScoringParameters {
base_penalty_msat: 0,
failure_penalty_msat: 0,
failure_penalty_half_life: Duration::from_secs(0),
overuse_penalty_start_1024th: 256,
overuse_penalty_msat_per_1024th: 100,
});
let source = source_node_id();
let target = target_node_id();
assert_eq!(scorer.channel_penalty_msat(42, 1_000, None, &source, &target), 0);
assert_eq!(scorer.channel_penalty_msat(42, 1_000, Some(1_024_000), &source, &target), 0);
assert_eq!(scorer.channel_penalty_msat(42, 256_999, Some(1_024_000), &source, &target), 0);
assert_eq!(scorer.channel_penalty_msat(42, 257_000, Some(1_024_000), &source, &target), 100);
assert_eq!(scorer.channel_penalty_msat(42, 258_000, Some(1_024_000), &source, &target), 200);
assert_eq!(scorer.channel_penalty_msat(42, 512_000, Some(1_024_000), &source, &target), 256 * 100);
}
}

View file

@ -21,7 +21,7 @@ use ln::features::{ChannelFeatures, InitFeatures};
use ln::msgs;
use ln::msgs::OptionalField;
use ln::script::ShutdownScript;
use routing::scorer::{Eternity, ScorerUsingTime};
use routing::scoring::{Eternity, ScorerUsingTime};
use util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
use util::events;
use util::logger::{Logger, Level, Record};