mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 15:20:24 +01:00
Merge pull request #1166 from TheBlueMatt/2021-11-chan-size-scoring
This commit is contained in:
commit
77948dbcd7
9 changed files with 211 additions and 138 deletions
|
@ -39,7 +39,7 @@ use lightning::ln::msgs::DecodeError;
|
||||||
use lightning::ln::script::ShutdownScript;
|
use lightning::ln::script::ShutdownScript;
|
||||||
use lightning::routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
|
use lightning::routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
|
||||||
use lightning::routing::router::{find_route, Payee, RouteParameters};
|
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::config::UserConfig;
|
||||||
use lightning::util::errors::APIError;
|
use lightning::util::errors::APIError;
|
||||||
use lightning::util::events::Event;
|
use lightning::util::events::Event;
|
||||||
|
|
|
@ -17,7 +17,7 @@ use lightning::ln::channelmanager::{ChannelDetails, ChannelCounterparty};
|
||||||
use lightning::ln::features::InitFeatures;
|
use lightning::ln::features::InitFeatures;
|
||||||
use lightning::ln::msgs;
|
use lightning::ln::msgs;
|
||||||
use lightning::routing::router::{find_route, Payee, RouteHint, RouteHintHop, RouteParameters};
|
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::logger::Logger;
|
||||||
use lightning::util::ser::Readable;
|
use lightning::util::ser::Readable;
|
||||||
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
|
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
|
||||||
|
|
|
@ -31,7 +31,7 @@
|
||||||
//! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
|
//! # use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
|
||||||
//! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
|
//! # use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
|
||||||
//! # use lightning::ln::msgs::LightningError;
|
//! # use lightning::ln::msgs::LightningError;
|
||||||
//! # use lightning::routing;
|
//! # use lightning::routing::scoring::Score;
|
||||||
//! # use lightning::routing::network_graph::NodeId;
|
//! # use lightning::routing::network_graph::NodeId;
|
||||||
//! # use lightning::routing::router::{Route, RouteHop, RouteParameters};
|
//! # use lightning::routing::router::{Route, RouteHop, RouteParameters};
|
||||||
//! # use lightning::util::events::{Event, EventHandler, EventsProvider};
|
//! # use lightning::util::events::{Event, EventHandler, EventsProvider};
|
||||||
|
@ -63,7 +63,7 @@
|
||||||
//! # }
|
//! # }
|
||||||
//! #
|
//! #
|
||||||
//! # struct FakeRouter {};
|
//! # struct FakeRouter {};
|
||||||
//! # impl<S: routing::Score> Router<S> for FakeRouter {
|
//! # impl<S: Score> Router<S> for FakeRouter {
|
||||||
//! # fn find_route(
|
//! # fn find_route(
|
||||||
//! # &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
|
//! # &self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
|
||||||
//! # first_hops: Option<&[&ChannelDetails]>, scorer: &S
|
//! # first_hops: Option<&[&ChannelDetails]>, scorer: &S
|
||||||
|
@ -71,9 +71,9 @@
|
||||||
//! # }
|
//! # }
|
||||||
//! #
|
//! #
|
||||||
//! # struct FakeScorer {};
|
//! # struct FakeScorer {};
|
||||||
//! # impl routing::Score for FakeScorer {
|
//! # impl Score for FakeScorer {
|
||||||
//! # fn channel_penalty_msat(
|
//! # 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 }
|
//! # ) -> u64 { 0 }
|
||||||
//! # fn payment_path_failed(&mut self, _path: &[&RouteHop], _short_channel_id: u64) {}
|
//! # 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::{PaymentHash, PaymentPreimage, PaymentSecret};
|
||||||
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
|
use lightning::ln::channelmanager::{ChannelDetails, PaymentId, PaymentSendFailure};
|
||||||
use lightning::ln::msgs::LightningError;
|
use lightning::ln::msgs::LightningError;
|
||||||
use lightning::routing;
|
use lightning::routing::scoring::{LockableScore, Score};
|
||||||
use lightning::routing::{LockableScore, Score};
|
|
||||||
use lightning::routing::router::{Payee, Route, RouteParameters};
|
use lightning::routing::router::{Payee, Route, RouteParameters};
|
||||||
use lightning::util::events::{Event, EventHandler};
|
use lightning::util::events::{Event, EventHandler};
|
||||||
use lightning::util::logger::Logger;
|
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>
|
pub struct InvoicePayer<P: Deref, R, S: Deref, L: Deref, E>
|
||||||
where
|
where
|
||||||
P::Target: Payer,
|
P::Target: Payer,
|
||||||
R: for <'a> Router<<<S as Deref>::Target as routing::LockableScore<'a>>::Locked>,
|
R: for <'a> Router<<<S as Deref>::Target as LockableScore<'a>>::Locked>,
|
||||||
S::Target: for <'a> routing::LockableScore<'a>,
|
S::Target: for <'a> LockableScore<'a>,
|
||||||
L::Target: Logger,
|
L::Target: Logger,
|
||||||
E: EventHandler,
|
E: EventHandler,
|
||||||
{
|
{
|
||||||
|
@ -177,7 +176,7 @@ pub trait Payer {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A trait defining behavior for routing an [`Invoice`] payment.
|
/// 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.
|
/// Finds a [`Route`] between `payer` and `payee` for a payment with the given values.
|
||||||
fn find_route(
|
fn find_route(
|
||||||
&self, payer: &PublicKey, params: &RouteParameters, payment_hash: &PaymentHash,
|
&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>
|
impl<P: Deref, R, S: Deref, L: Deref, E> InvoicePayer<P, R, S, L, E>
|
||||||
where
|
where
|
||||||
P::Target: Payer,
|
P::Target: Payer,
|
||||||
R: for <'a> Router<<<S as Deref>::Target as routing::LockableScore<'a>>::Locked>,
|
R: for <'a> Router<<<S as Deref>::Target as LockableScore<'a>>::Locked>,
|
||||||
S::Target: for <'a> routing::LockableScore<'a>,
|
S::Target: for <'a> LockableScore<'a>,
|
||||||
L::Target: Logger,
|
L::Target: Logger,
|
||||||
E: EventHandler,
|
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>
|
impl<P: Deref, R, S: Deref, L: Deref, E> EventHandler for InvoicePayer<P, R, S, L, E>
|
||||||
where
|
where
|
||||||
P::Target: Payer,
|
P::Target: Payer,
|
||||||
R: for <'a> Router<<<S as Deref>::Target as routing::LockableScore<'a>>::Locked>,
|
R: for <'a> Router<<<S as Deref>::Target as LockableScore<'a>>::Locked>,
|
||||||
S::Target: for <'a> routing::LockableScore<'a>,
|
S::Target: for <'a> LockableScore<'a>,
|
||||||
L::Target: Logger,
|
L::Target: Logger,
|
||||||
E: EventHandler,
|
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(
|
fn find_route(
|
||||||
&self, _payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
|
&self, _payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
|
||||||
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
|
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
|
||||||
|
@ -1199,7 +1198,7 @@ mod tests {
|
||||||
|
|
||||||
struct FailingRouter;
|
struct FailingRouter;
|
||||||
|
|
||||||
impl<S: routing::Score> Router<S> for FailingRouter {
|
impl<S: Score> Router<S> for FailingRouter {
|
||||||
fn find_route(
|
fn find_route(
|
||||||
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
|
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
|
||||||
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
|
_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(
|
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 }
|
) -> u64 { 0 }
|
||||||
|
|
||||||
fn payment_path_failed(&mut self, _path: &[&RouteHop], short_channel_id: u64) {
|
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 ***
|
// *** Full Featured Functional Tests with a Real ChannelManager ***
|
||||||
struct ManualRouter(RefCell<VecDeque<Result<Route, LightningError>>>);
|
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(
|
fn find_route(
|
||||||
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
|
&self, _payer: &PublicKey, _params: &RouteParameters, _payment_hash: &PaymentHash,
|
||||||
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
|
_first_hops: Option<&[&ChannelDetails]>, _scorer: &S
|
||||||
|
|
|
@ -11,7 +11,7 @@ use lightning::chain::keysinterface::{Sign, KeysInterface};
|
||||||
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
|
use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
|
||||||
use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY};
|
use lightning::ln::channelmanager::{ChannelDetails, ChannelManager, PaymentId, PaymentSendFailure, MIN_FINAL_CLTV_EXPIRY};
|
||||||
use lightning::ln::msgs::LightningError;
|
use lightning::ln::msgs::LightningError;
|
||||||
use lightning::routing;
|
use lightning::routing::scoring::Score;
|
||||||
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
|
use lightning::routing::network_graph::{NetworkGraph, RoutingFees};
|
||||||
use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
|
use lightning::routing::router::{Route, RouteHint, RouteHintHop, RouteParameters, find_route};
|
||||||
use lightning::util::logger::Logger;
|
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 {
|
where G: Deref<Target = NetworkGraph>, L::Target: Logger {
|
||||||
fn find_route(
|
fn find_route(
|
||||||
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
|
&self, payer: &PublicKey, params: &RouteParameters, _payment_hash: &PaymentHash,
|
||||||
|
|
|
@ -6552,7 +6552,7 @@ pub mod bench {
|
||||||
use ln::msgs::{ChannelMessageHandler, Init};
|
use ln::msgs::{ChannelMessageHandler, Init};
|
||||||
use routing::network_graph::NetworkGraph;
|
use routing::network_graph::NetworkGraph;
|
||||||
use routing::router::{Payee, get_route};
|
use routing::router::{Payee, get_route};
|
||||||
use routing::scorer::Scorer;
|
use routing::scoring::Scorer;
|
||||||
use util::test_utils;
|
use util::test_utils;
|
||||||
use util::config::UserConfig;
|
use util::config::UserConfig;
|
||||||
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
|
use util::events::{Event, MessageSendEvent, MessageSendEventsProvider, PaymentPurpose};
|
||||||
|
|
|
@ -11,65 +11,4 @@
|
||||||
|
|
||||||
pub mod network_graph;
|
pub mod network_graph;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
pub mod scorer;
|
pub mod scoring;
|
||||||
|
|
||||||
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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
@ -17,7 +17,7 @@ use bitcoin::secp256k1::key::PublicKey;
|
||||||
use ln::channelmanager::ChannelDetails;
|
use ln::channelmanager::ChannelDetails;
|
||||||
use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
|
use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures};
|
||||||
use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
|
use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT};
|
||||||
use routing;
|
use routing::scoring::Score;
|
||||||
use routing::network_graph::{NetworkGraph, NodeId, RoutingFees};
|
use routing::network_graph::{NetworkGraph, NodeId, RoutingFees};
|
||||||
use util::ser::{Writeable, Readable};
|
use util::ser::{Writeable, Readable};
|
||||||
use util::logger::{Level, Logger};
|
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
|
/// [`ChannelManager::list_usable_channels`]: crate::ln::channelmanager::ChannelManager::list_usable_channels
|
||||||
/// [`Event::PaymentPathFailed`]: crate::util::events::Event::PaymentPathFailed
|
/// [`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,
|
our_node_pubkey: &PublicKey, params: &RouteParameters, network: &NetworkGraph,
|
||||||
first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S
|
first_hops: Option<&[&ChannelDetails]>, logger: L, scorer: &S
|
||||||
) -> Result<Route, LightningError>
|
) -> 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,
|
our_node_pubkey: &PublicKey, payee: &Payee, network: &NetworkGraph,
|
||||||
first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32,
|
first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, final_cltv_expiry_delta: u32,
|
||||||
logger: L, scorer: &S
|
logger: L, scorer: &S
|
||||||
|
@ -892,9 +892,9 @@ where L::Target: Logger {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let path_penalty_msat = $next_hops_path_penalty_msat
|
let path_penalty_msat = $next_hops_path_penalty_msat.checked_add(
|
||||||
.checked_add(scorer.channel_penalty_msat($chan_id.clone(), &$src_node_id, &$dest_node_id))
|
scorer.channel_penalty_msat($chan_id.clone(), amount_to_transfer_over_msat, Some(*available_liquidity_msat),
|
||||||
.unwrap_or_else(|| u64::max_value());
|
&$src_node_id, &$dest_node_id)).unwrap_or_else(|| u64::max_value());
|
||||||
let new_graph_node = RouteGraphNode {
|
let new_graph_node = RouteGraphNode {
|
||||||
node_id: $src_node_id,
|
node_id: $src_node_id,
|
||||||
lowest_fee_to_peer_through_node: total_fee_msat,
|
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 src_node_id = NodeId::from_pubkey(&hop.src_node_id);
|
||||||
let dest_node_id = NodeId::from_pubkey(&prev_hop_id);
|
let dest_node_id = NodeId::from_pubkey(&prev_hop_id);
|
||||||
aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
|
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());
|
.unwrap_or_else(|| u64::max_value());
|
||||||
|
|
||||||
// We assume that the recipient only included route hints for routes which had
|
// We assume that the recipient only included route hints for routes which had
|
||||||
|
@ -1472,7 +1472,7 @@ where L::Target: Logger {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use routing;
|
use routing::scoring::Score;
|
||||||
use routing::network_graph::{NetworkGraph, NetGraphMsgHandler, NodeId};
|
use routing::network_graph::{NetworkGraph, NetGraphMsgHandler, NodeId};
|
||||||
use routing::router::{get_route, Payee, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees};
|
use routing::router::{get_route, Payee, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees};
|
||||||
use chain::transaction::OutPoint;
|
use chain::transaction::OutPoint;
|
||||||
|
@ -4549,8 +4549,8 @@ mod tests {
|
||||||
short_channel_id: u64,
|
short_channel_id: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl routing::Score for BadChannelScorer {
|
impl 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 }
|
if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4561,8 +4561,8 @@ mod tests {
|
||||||
node_id: NodeId,
|
node_id: NodeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl routing::Score for BadNodeScorer {
|
impl 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 }
|
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")))]
|
#[cfg(all(test, feature = "unstable", not(feature = "no-std")))]
|
||||||
mod benches {
|
mod benches {
|
||||||
use super::*;
|
use super::*;
|
||||||
use routing::scorer::Scorer;
|
use routing::scoring::Scorer;
|
||||||
use util::logger::{Logger, Record};
|
use util::logger::{Logger, Record};
|
||||||
|
|
||||||
use test::Bencher;
|
use test::Bencher;
|
||||||
|
|
|
@ -10,7 +10,7 @@
|
||||||
//! Utilities for scoring payment channels.
|
//! Utilities for scoring payment channels.
|
||||||
//!
|
//!
|
||||||
//! [`Scorer`] may be given to [`find_route`] to score payment channels during path finding when a
|
//! [`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
|
//! # Example
|
||||||
//!
|
//!
|
||||||
|
@ -19,7 +19,7 @@
|
||||||
//! #
|
//! #
|
||||||
//! # use lightning::routing::network_graph::NetworkGraph;
|
//! # use lightning::routing::network_graph::NetworkGraph;
|
||||||
//! # use lightning::routing::router::{RouteParameters, find_route};
|
//! # 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 lightning::util::logger::{Logger, Record};
|
||||||
//! # use secp256k1::key::PublicKey;
|
//! # use secp256k1::key::PublicKey;
|
||||||
//! #
|
//! #
|
||||||
|
@ -52,26 +52,89 @@
|
||||||
//!
|
//!
|
||||||
//! [`find_route`]: crate::routing::router::find_route
|
//! [`find_route`]: crate::routing::router::find_route
|
||||||
|
|
||||||
use routing;
|
|
||||||
|
|
||||||
use ln::msgs::DecodeError;
|
use ln::msgs::DecodeError;
|
||||||
use routing::network_graph::NodeId;
|
use routing::network_graph::NodeId;
|
||||||
use routing::router::RouteHop;
|
use routing::router::RouteHop;
|
||||||
use util::ser::{Readable, Writeable, Writer};
|
use util::ser::{Readable, Writeable, Writer};
|
||||||
|
|
||||||
use prelude::*;
|
use prelude::*;
|
||||||
use core::ops::Sub;
|
use core::cell::{RefCell, RefMut};
|
||||||
|
use core::ops::{DerefMut, Sub};
|
||||||
use core::time::Duration;
|
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
|
/// 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.
|
/// slightly higher fees are available. Will further penalize channels that fail to relay payments.
|
||||||
///
|
///
|
||||||
/// See [module-level documentation] for usage.
|
/// See [module-level documentation] for usage.
|
||||||
///
|
///
|
||||||
/// [module-level documentation]: crate::routing::scorer
|
/// [module-level documentation]: crate::routing::scoring
|
||||||
pub type Scorer = ScorerUsingTime::<DefaultTime>;
|
pub type Scorer = ScorerUsingTime::<DefaultTime>;
|
||||||
|
|
||||||
/// Time used by [`Scorer`].
|
/// Time used by [`Scorer`].
|
||||||
|
@ -82,7 +145,7 @@ pub type DefaultTime = std::time::Instant;
|
||||||
#[cfg(feature = "no-std")]
|
#[cfg(feature = "no-std")]
|
||||||
pub type DefaultTime = Eternity;
|
pub type DefaultTime = Eternity;
|
||||||
|
|
||||||
/// [`routing::Score`] implementation parameterized by [`Time`].
|
/// [`Score`] implementation parameterized by [`Time`].
|
||||||
///
|
///
|
||||||
/// See [`Scorer`] for details.
|
/// See [`Scorer`] for details.
|
||||||
///
|
///
|
||||||
|
@ -98,6 +161,8 @@ pub struct ScorerUsingTime<T: Time> {
|
||||||
/// Parameters for configuring [`Scorer`].
|
/// Parameters for configuring [`Scorer`].
|
||||||
pub struct ScoringParameters {
|
pub struct ScoringParameters {
|
||||||
/// A fixed penalty in msats to apply to each channel.
|
/// A fixed penalty in msats to apply to each channel.
|
||||||
|
///
|
||||||
|
/// Default value: 500 msat
|
||||||
pub base_penalty_msat: u64,
|
pub base_penalty_msat: u64,
|
||||||
|
|
||||||
/// A penalty in msats to apply to a channel upon failing to relay a payment.
|
/// 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
|
/// This accumulates for each failure but may be reduced over time based on
|
||||||
/// [`failure_penalty_half_life`].
|
/// [`failure_penalty_half_life`].
|
||||||
///
|
///
|
||||||
|
/// Default value: 1,024,000 msat
|
||||||
|
///
|
||||||
/// [`failure_penalty_half_life`]: Self::failure_penalty_half_life
|
/// [`failure_penalty_half_life`]: Self::failure_penalty_half_life
|
||||||
pub failure_penalty_msat: u64,
|
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
|
/// The time required to elapse before any accumulated [`failure_penalty_msat`] penalties are
|
||||||
/// cut in half.
|
/// cut in half.
|
||||||
///
|
///
|
||||||
|
@ -122,7 +206,9 @@ pub struct ScoringParameters {
|
||||||
|
|
||||||
impl_writeable_tlv_based!(ScoringParameters, {
|
impl_writeable_tlv_based!(ScoringParameters, {
|
||||||
(0, base_penalty_msat, required),
|
(0, base_penalty_msat, required),
|
||||||
|
(1, overuse_penalty_start_1024th, (default_value, 128)),
|
||||||
(2, failure_penalty_msat, required),
|
(2, failure_penalty_msat, required),
|
||||||
|
(3, overuse_penalty_msat_per_1024th, (default_value, 20)),
|
||||||
(4, failure_penalty_half_life, required),
|
(4, failure_penalty_half_life, required),
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -167,6 +253,8 @@ impl<T: Time> ScorerUsingTime<T> {
|
||||||
base_penalty_msat: penalty_msat,
|
base_penalty_msat: penalty_msat,
|
||||||
failure_penalty_msat: 0,
|
failure_penalty_msat: 0,
|
||||||
failure_penalty_half_life: Duration::from_secs(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,
|
base_penalty_msat: 500,
|
||||||
failure_penalty_msat: 1024 * 1000,
|
failure_penalty_msat: 1024 * 1000,
|
||||||
failure_penalty_half_life: Duration::from_secs(3600),
|
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(
|
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 {
|
) -> u64 {
|
||||||
let failure_penalty_msat = self.channel_failures
|
let failure_penalty_msat = self.channel_failures
|
||||||
.get(&short_channel_id)
|
.get(&short_channel_id)
|
||||||
.map_or(0, |value| value.decayed_penalty_msat(self.params.failure_penalty_half_life));
|
.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) {
|
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 {
|
mod tests {
|
||||||
use super::{Eternity, ScoringParameters, ScorerUsingTime, Time};
|
use super::{Eternity, ScoringParameters, ScorerUsingTime, Time};
|
||||||
|
|
||||||
use routing::Score;
|
use routing::scoring::Score;
|
||||||
use routing::network_graph::NodeId;
|
use routing::network_graph::NodeId;
|
||||||
use util::ser::{Readable, Writeable};
|
use util::ser::{Readable, Writeable};
|
||||||
|
|
||||||
|
@ -414,13 +517,15 @@ mod tests {
|
||||||
base_penalty_msat: 1_000,
|
base_penalty_msat: 1_000,
|
||||||
failure_penalty_msat: 512,
|
failure_penalty_msat: 512,
|
||||||
failure_penalty_half_life: Duration::from_secs(1),
|
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 source = source_node_id();
|
||||||
let target = target_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));
|
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]
|
#[test]
|
||||||
|
@ -429,19 +534,21 @@ mod tests {
|
||||||
base_penalty_msat: 1_000,
|
base_penalty_msat: 1_000,
|
||||||
failure_penalty_msat: 64,
|
failure_penalty_msat: 64,
|
||||||
failure_penalty_half_life: Duration::from_secs(10),
|
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 source = source_node_id();
|
||||||
let target = target_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);
|
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);
|
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);
|
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]
|
#[test]
|
||||||
|
@ -450,28 +557,30 @@ mod tests {
|
||||||
base_penalty_msat: 1_000,
|
base_penalty_msat: 1_000,
|
||||||
failure_penalty_msat: 512,
|
failure_penalty_msat: 512,
|
||||||
failure_penalty_half_life: Duration::from_secs(10),
|
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 source = source_node_id();
|
||||||
let target = target_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);
|
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));
|
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));
|
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));
|
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));
|
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));
|
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]
|
#[test]
|
||||||
|
@ -480,22 +589,24 @@ mod tests {
|
||||||
base_penalty_msat: 1_000,
|
base_penalty_msat: 1_000,
|
||||||
failure_penalty_msat: 512,
|
failure_penalty_msat: 512,
|
||||||
failure_penalty_half_life: Duration::from_secs(10),
|
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 source = source_node_id();
|
||||||
let target = target_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);
|
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));
|
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);
|
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));
|
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]
|
#[test]
|
||||||
|
@ -504,25 +615,27 @@ mod tests {
|
||||||
base_penalty_msat: 1_000,
|
base_penalty_msat: 1_000,
|
||||||
failure_penalty_msat: 512,
|
failure_penalty_msat: 512,
|
||||||
failure_penalty_half_life: Duration::from_secs(10),
|
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 source = source_node_id();
|
||||||
let target = target_node_id();
|
let target = target_node_id();
|
||||||
|
|
||||||
scorer.payment_path_failed(&[], 42);
|
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));
|
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);
|
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();
|
let mut serialized_scorer = Vec::new();
|
||||||
scorer.write(&mut serialized_scorer).unwrap();
|
scorer.write(&mut serialized_scorer).unwrap();
|
||||||
|
|
||||||
let deserialized_scorer = <Scorer>::read(&mut io::Cursor::new(&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(42, 1, Some(1), &source, &target), 1_256);
|
||||||
assert_eq!(deserialized_scorer.channel_penalty_msat(43, &source, &target), 1_512);
|
assert_eq!(deserialized_scorer.channel_penalty_msat(43, 1, Some(1), &source, &target), 1_512);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -531,12 +644,14 @@ mod tests {
|
||||||
base_penalty_msat: 1_000,
|
base_penalty_msat: 1_000,
|
||||||
failure_penalty_msat: 512,
|
failure_penalty_msat: 512,
|
||||||
failure_penalty_half_life: Duration::from_secs(10),
|
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 source = source_node_id();
|
||||||
let target = target_node_id();
|
let target = target_node_id();
|
||||||
|
|
||||||
scorer.payment_path_failed(&[], 42);
|
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();
|
let mut serialized_scorer = Vec::new();
|
||||||
scorer.write(&mut serialized_scorer).unwrap();
|
scorer.write(&mut serialized_scorer).unwrap();
|
||||||
|
@ -544,9 +659,29 @@ mod tests {
|
||||||
SinceEpoch::advance(Duration::from_secs(10));
|
SinceEpoch::advance(Duration::from_secs(10));
|
||||||
|
|
||||||
let deserialized_scorer = <Scorer>::read(&mut io::Cursor::new(&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(42, 1, Some(1), &source, &target), 1_256);
|
||||||
|
|
||||||
SinceEpoch::advance(Duration::from_secs(10));
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -21,7 +21,7 @@ use ln::features::{ChannelFeatures, InitFeatures};
|
||||||
use ln::msgs;
|
use ln::msgs;
|
||||||
use ln::msgs::OptionalField;
|
use ln::msgs::OptionalField;
|
||||||
use ln::script::ShutdownScript;
|
use ln::script::ShutdownScript;
|
||||||
use routing::scorer::{Eternity, ScorerUsingTime};
|
use routing::scoring::{Eternity, ScorerUsingTime};
|
||||||
use util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
|
use util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
|
||||||
use util::events;
|
use util::events;
|
||||||
use util::logger::{Logger, Level, Record};
|
use util::logger::{Logger, Level, Record};
|
||||||
|
|
Loading…
Add table
Reference in a new issue