use crate::io;
use crate::prelude::*;
-use crate::sync::Mutex;
+use crate::sync::{Mutex, MutexGuard};
use alloc::collections::BinaryHeap;
use core::{cmp, fmt};
use core::ops::Deref;
/// A [`Router`] implemented using [`find_route`].
-pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> where
+pub struct DefaultRouter<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> where
L::Target: Logger,
- S::Target: for <'a> LockableScore<'a>,
+ S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
{
network_graph: G,
logger: L,
random_seed_bytes: Mutex<[u8; 32]>,
- scorer: S
+ scorer: S,
+ score_params: SP
}
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> DefaultRouter<G, L, S> where
+impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> DefaultRouter<G, L, S, SP, Sc> where
L::Target: Logger,
- S::Target: for <'a> LockableScore<'a>,
+ S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
{
/// Creates a new router.
- pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S) -> Self {
+ pub fn new(network_graph: G, logger: L, random_seed_bytes: [u8; 32], scorer: S, score_params: SP) -> Self {
let random_seed_bytes = Mutex::new(random_seed_bytes);
- Self { network_graph, logger, random_seed_bytes, scorer }
+ Self { network_graph, logger, random_seed_bytes, scorer, score_params }
}
}
-impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref> Router for DefaultRouter<G, L, S> where
+impl< G: Deref<Target = NetworkGraph<L>>, L: Deref, S: Deref, SP: Sized, Sc: Score<ScoreParams = SP>> Router for DefaultRouter<G, L, S, SP, Sc> where
L::Target: Logger,
- S::Target: for <'a> LockableScore<'a>,
+ S::Target: for <'a> LockableScore<'a, Locked = MutexGuard<'a, Sc>>,
{
fn find_route(
- &self, payer: &PublicKey, params: &RouteParameters, first_hops: Option<&[&ChannelDetails]>,
+ &self,
+ payer: &PublicKey,
+ params: &RouteParameters,
+ first_hops: Option<&[&ChannelDetails]>,
inflight_htlcs: &InFlightHtlcs
) -> Result<Route, LightningError> {
let random_seed_bytes = {
*locked_random_seed_bytes = Sha256::hash(&*locked_random_seed_bytes).into_inner();
*locked_random_seed_bytes
};
-
find_route(
payer, params, &self.network_graph, first_hops, &*self.logger,
&ScorerAccountingForInFlightHtlcs::new(self.scorer.lock(), inflight_htlcs),
+ &self.score_params,
&random_seed_bytes
)
}
}
impl<'a, S: Score> Score for ScorerAccountingForInFlightHtlcs<'a, S> {
- fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
+ type ScoreParams = S::ScoreParams;
+ fn channel_penalty_msat(&self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
if let Some(used_liquidity) = self.inflight_htlcs.used_liquidity_msat(
source, target, short_channel_id
) {
..usage
};
- self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+ self.scorer.channel_penalty_msat(short_channel_id, source, target, usage, score_params)
} else {
- self.scorer.channel_penalty_msat(short_channel_id, source, target, usage)
+ self.scorer.channel_penalty_msat(short_channel_id, source, target, usage, score_params)
}
}
pub fn find_route<L: Deref, GL: Deref, S: Score>(
our_node_pubkey: &PublicKey, route_params: &RouteParameters,
network_graph: &NetworkGraph<GL>, first_hops: Option<&[&ChannelDetails]>, logger: L,
- scorer: &S, random_seed_bytes: &[u8; 32]
+ scorer: &S, score_params: &S::ScoreParams, random_seed_bytes: &[u8; 32]
) -> Result<Route, LightningError>
where L::Target: Logger, GL::Target: Logger {
let graph_lock = network_graph.read_only();
let mut route = get_route(our_node_pubkey, &route_params.payment_params, &graph_lock, first_hops,
- route_params.final_value_msat, logger, scorer,
+ route_params.final_value_msat, logger, scorer, score_params,
random_seed_bytes)?;
add_random_cltv_offset(&mut route, &route_params.payment_params, &graph_lock, random_seed_bytes);
Ok(route)
pub(crate) fn get_route<L: Deref, S: Score>(
our_node_pubkey: &PublicKey, payment_params: &PaymentParameters, network_graph: &ReadOnlyNetworkGraph,
- first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, logger: L, scorer: &S,
+ first_hops: Option<&[&ChannelDetails]>, final_value_msat: u64, logger: L, scorer: &S, score_params: &S::ScoreParams,
_random_seed_bytes: &[u8; 32]
) -> Result<Route, LightningError>
where L::Target: Logger {
effective_capacity,
};
let channel_penalty_msat = scorer.channel_penalty_msat(
- short_channel_id, &$src_node_id, &$dest_node_id, channel_usage
+ short_channel_id, &$src_node_id, &$dest_node_id, channel_usage, score_params
);
let path_penalty_msat = $next_hops_path_penalty_msat
.saturating_add(channel_penalty_msat);
effective_capacity: candidate.effective_capacity(),
};
let channel_penalty_msat = scorer.channel_penalty_msat(
- hop.short_channel_id, &source, &target, channel_usage
+ hop.short_channel_id, &source, &target, channel_usage, score_params
);
aggregate_next_hops_path_penalty_msat = aggregate_next_hops_path_penalty_msat
.saturating_add(channel_penalty_msat);
}
impl Score for HopScorer {
+ type ScoreParams = ();
fn channel_penalty_msat(&self, _short_channel_id: u64, source: &NodeId, target: &NodeId,
- _usage: ChannelUsage) -> u64
+ _usage: ChannelUsage, _score_params: &Self::ScoreParams) -> u64
{
let mut cur_id = self.our_node_id;
for i in 0..self.hop_ids.len() {
let scorer = HopScorer { our_node_id, hop_ids };
get_route(our_node_pubkey, payment_params, network_graph, None, final_value_msat,
- logger, &scorer, random_seed_bytes)
+ logger, &scorer, &(), random_seed_bytes)
}
#[cfg(test)]
use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features,
BlindedTail, InFlightHtlcs, Path, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees,
DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE};
- use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringParameters};
+ use crate::routing::scoring::{ChannelUsage, FixedPenaltyScorer, Score, ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
use crate::chain::transaction::OutPoint;
use crate::sign::EntropySource;
// Simple route to 2 via 1
- if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 0, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 0, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Cannot send a payment of 0 msat");
} else { panic!(); }
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
let our_chans = vec![get_channel_details(Some(2), our_id, InitFeatures::from_le_bytes(vec![0b11]), 100000)];
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) =
- get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "First hop cannot have our_node_pubkey as a destination.");
} else { panic!(); }
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
}
});
// Not possible to send 199_999_999, because the minimum on channel=2 is 200_000_000.
- if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a path to the given destination");
} else { panic!(); }
});
// A payment above the minimum should pass
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 199_999_999, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
}
excess_data: Vec::new()
});
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
// Overpay fees to hit htlc_minimum_msat.
let overpaid_fees = route.paths[0].hops[0].fee_msat + route.paths[1].hops[0].fee_msat;
// TODO: this could be better balanced to overpay 10k and not 15k.
excess_data: Vec::new()
});
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
// Fine to overpay for htlc_minimum_msat if it allows us to save fee.
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].hops[0].short_channel_id, 12);
let fees = route.paths[0].hops[0].fee_msat;
assert_eq!(fees, 5_000);
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
// Not fine to overpay for htlc_minimum_msat if it requires paying more than fee on
// the other channel.
assert_eq!(route.paths.len(), 1);
});
// If all the channels require some features we don't understand, route should fail
- if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a path to the given destination");
} else { panic!(); }
// If we specify a channel to node7, that overrides our local channel view and that gets used
let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[7]);
add_or_update_node(&gossip_sync, &secp_ctx, &privkeys[7], unknown_features.clone(), 1);
// If all nodes require some features we don't understand, route should fail
- if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a path to the given destination");
} else { panic!(); }
// If we specify a channel to node7, that overrides our local channel view and that gets used
let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[7]);
// Route to 1 via 2 and 3 because our channel to 1 is disabled
let payment_params = PaymentParameters::from_node_id(nodes[0], 42);
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 3);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
// If we specify a channel to node7, that overrides our local channel view and that gets used
let payment_params = PaymentParameters::from_node_id(nodes[2], 42);
let our_chans = vec![get_channel_details(Some(42), nodes[7].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[7]);
invalid_last_hops.push(invalid_last_hop);
{
let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(invalid_last_hops).unwrap();
- if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Route hint cannot have the payee as the source.");
} else { panic!(); }
}
let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops_multi_private_channels(&nodes)).unwrap();
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 5);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
// Test handling of an empty RouteHint passed in Invoice.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 5);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
excess_data: Vec::new()
});
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 4);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
excess_data: Vec::new()
});
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &[42u8; 32]).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &[42u8; 32]).unwrap();
assert_eq!(route.paths[0].hops.len(), 4);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
// This test shows that public routes can be present in the invoice
// which would be handled in the same manner.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 5);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
let our_chans = vec![get_channel_details(Some(42), nodes[3].clone(), InitFeatures::from_le_bytes(vec![0b11]), 250_000_000)];
let mut last_hops = last_hops(&nodes);
let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops.clone()).unwrap();
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 2);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[3]);
// Revert to via 6 as the fee on 8 goes up
let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops).unwrap();
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 4);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
assert_eq!(route.paths[0].hops[3].channel_features.le_flags(), &Vec::<u8>::new()); // We can't learn any flags from invoices, sadly
// ...but still use 8 for larger payments as 6 has a variable feerate
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 2000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 2000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths[0].hops.len(), 5);
assert_eq!(route.paths[0].hops[0].pubkey, nodes[1]);
let logger = ln_test_utils::TestLogger::new();
let network_graph = NetworkGraph::new(Network::Testnet, &logger);
let route = get_route(&source_node_id, &payment_params, &network_graph.read_only(),
- Some(&our_chans.iter().collect::<Vec<_>>()), route_val, &logger, &scorer, &random_seed_bytes);
+ Some(&our_chans.iter().collect::<Vec<_>>()), route_val, &logger, &scorer, &(), &random_seed_bytes);
route
}
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 250_000_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 250_000_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route an exact amount we have should be fine.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 250_000_000, Arc::clone(&logger), &scorer, &(),&random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let path = route.paths.last().unwrap();
assert_eq!(path.hops.len(), 2);
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route an exact amount we have should be fine.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&our_chans.iter().collect::<Vec<_>>()), 200_000_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let path = route.paths.last().unwrap();
assert_eq!(path.hops.len(), 2);
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route an exact amount we have should be fine.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let path = route.paths.last().unwrap();
assert_eq!(path.hops.len(), 2);
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 15_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route an exact amount we have should be fine.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 15_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let path = route.paths.last().unwrap();
assert_eq!(path.hops.len(), 2);
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 10_001, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 10_001, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route an exact amount we have should be fine.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let path = route.paths.last().unwrap();
assert_eq!(path.hops.len(), 2);
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 60_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route 49 sats (just a bit below the capacity).
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 49_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 49_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
{
// Attempt to route an exact amount is also fine
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
});
{
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 50_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
&our_id, &payment_params, &network_graph.read_only(), None, 300_000,
- Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
let zero_payment_params = payment_params.clone().with_max_path_count(0);
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
&our_id, &zero_payment_params, &network_graph.read_only(), None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Can't find a route with no paths allowed.");
} else { panic!(); }
}
let fail_payment_params = payment_params.clone().with_max_path_count(3);
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
&our_id, &fail_payment_params, &network_graph.read_only(), None, 250_000,
- Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
// Now, attempt to route 250 sats (just a bit below the capacity).
// Our algorithm should provide us with these 3 paths.
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
- 250_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ 250_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 3);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
{
// Attempt to route an exact amount is also fine
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None,
- 290_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ 290_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 3);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 350_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 350_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route 300 sats (exact amount we can route).
// Our algorithm should provide us with these 3 paths, 100 sats each.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 300_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 300_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 3);
let mut total_amount_paid_msat = 0;
{
// Now, attempt to route 180 sats.
// Our algorithm should provide us with these 2 paths.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 180_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 180_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
let mut total_value_transferred_msat = 0;
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 210_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 210_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route 200 sats (exact amount we can route).
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 200_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 200_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
let mut total_amount_paid_msat = 0;
// Get a route for 100 sats and check that we found the MPP route no problem and didn't
// overpay at all.
- let mut route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let mut route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
route.paths.sort_by_key(|path| path.hops[0].short_channel_id);
// Paths are manually ordered ordered by SCID, so:
{
// Attempt to route more than available results in a failure.
if let Err(LightningError{err, action: ErrorAction::IgnoreError}) = get_route(
- &our_id, &payment_params, &network_graph.read_only(), None, 150_000, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ &our_id, &payment_params, &network_graph.read_only(), None, 150_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
assert_eq!(err, "Failed to find a sufficient route to the given destination");
} else { panic!(); }
}
{
// Now, attempt to route 125 sats (just a bit below the capacity of 3 channels).
// Our algorithm should provide us with these 3 paths.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 125_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 125_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 3);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
{
// Attempt to route without the last small cheap channel
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
let mut total_amount_paid_msat = 0;
for path in &route.paths {
{
// Now ensure the route flows simply over nodes 1 and 4 to 6.
- let route = get_route(&our_id, &payment_params, &network.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network.read_only(), None, 10_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].hops.len(), 3);
{
// Now, attempt to route 90 sats, which is exactly 90 sats at the last hop, plus the
// 200% fee charged channel 13 in the 1-to-2 direction.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].hops.len(), 2);
// Now, attempt to route 90 sats, hitting the htlc_minimum on channel 4, but
// overshooting the htlc_maximum on channel 2. Thus, we should pick the (absurdly
// expensive) channels 12-13 path.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 90_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].hops.len(), 2);
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
&get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(&config), 200_000),
&get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(&config), 10_000),
- ]), 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ ]), 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].hops.len(), 1);
let route = get_route(&our_id, &payment_params, &network_graph.read_only(), Some(&[
&get_channel_details(Some(3), nodes[0], channelmanager::provided_init_features(&config), 50_000),
&get_channel_details(Some(2), nodes[0], channelmanager::provided_init_features(&config), 50_000),
- ]), 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ ]), 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
assert_eq!(route.paths[0].hops.len(), 1);
assert_eq!(route.paths[1].hops.len(), 1);
&get_channel_details(Some(8), nodes[0], channelmanager::provided_init_features(&config), 50_000),
&get_channel_details(Some(9), nodes[0], channelmanager::provided_init_features(&config), 50_000),
&get_channel_details(Some(4), nodes[0], channelmanager::provided_init_features(&config), 1_000_000),
- ]), 100_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ ]), 100_000, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
assert_eq!(route.paths[0].hops.len(), 1);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(
&our_id, &payment_params, &network_graph.read_only(), None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes
).unwrap();
let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
let scorer = FixedPenaltyScorer::with_penalty(100);
let route = get_route(
&our_id, &payment_params, &network_graph.read_only(), None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes
).unwrap();
let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
fn write<W: Writer>(&self, _w: &mut W) -> Result<(), crate::io::Error> { unimplemented!() }
}
impl Score for BadChannelScorer {
- fn channel_penalty_msat(&self, short_channel_id: u64, _: &NodeId, _: &NodeId, _: ChannelUsage) -> u64 {
+ type ScoreParams = ();
+ fn channel_penalty_msat(&self, short_channel_id: u64, _: &NodeId, _: &NodeId, _: ChannelUsage, _score_params:&Self::ScoreParams) -> u64 {
if short_channel_id == self.short_channel_id { u64::max_value() } else { 0 }
}
}
impl Score for BadNodeScorer {
- fn channel_penalty_msat(&self, _: u64, _: &NodeId, target: &NodeId, _: ChannelUsage) -> u64 {
+ type ScoreParams = ();
+ fn channel_penalty_msat(&self, _: u64, _: &NodeId, target: &NodeId, _: ChannelUsage, _score_params:&Self::ScoreParams) -> u64 {
if *target == self.node_id { u64::max_value() } else { 0 }
}
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let route = get_route(
&our_id, &payment_params, &network_graph, None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes
).unwrap();
let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
let scorer = BadChannelScorer { short_channel_id: 6 };
let route = get_route(
&our_id, &payment_params, &network_graph, None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes
).unwrap();
let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
let scorer = BadNodeScorer { node_id: NodeId::from_pubkey(&nodes[2]) };
match get_route(
&our_id, &payment_params, &network_graph, None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes
) {
Err(LightningError { err, .. } ) => {
assert_eq!(err, "Failed to find a path to the given destination");
.with_max_total_cltv_expiry_delta(feasible_max_total_cltv_delta);
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
assert_ne!(path.len(), 0);
let fail_max_total_cltv_delta = 23;
let fail_payment_params = PaymentParameters::from_node_id(nodes[6], 0).with_route_hints(last_hops(&nodes)).unwrap()
.with_max_total_cltv_expiry_delta(fail_max_total_cltv_delta);
- match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes)
+ match get_route(&our_id, &fail_payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes)
{
Err(LightningError { err, .. } ) => {
assert_eq!(err, "Failed to find a path to the given destination");
// We should be able to find a route initially, and then after we fail a few random
// channels eventually we won't be able to any longer.
- assert!(get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).is_ok());
+ assert!(get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).is_ok());
loop {
- if let Ok(route) = get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes) {
+ if let Ok(route) = get_route(&our_id, &payment_params, &network_graph, None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes) {
for chan in route.paths[0].hops.iter() {
assert!(!payment_params.previously_failed_channels.contains(&chan.short_channel_id));
}
// First check we can actually create a long route on this graph.
let feasible_payment_params = PaymentParameters::from_node_id(nodes[18], 0);
let route = get_route(&our_id, &feasible_payment_params, &network_graph, None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
let path = route.paths[0].hops.iter().map(|hop| hop.short_channel_id).collect::<Vec<_>>();
assert!(path.len() == MAX_PATH_LENGTH_ESTIMATE.into());
// But we can't create a path surpassing the MAX_PATH_LENGTH_ESTIMATE limit.
let fail_payment_params = PaymentParameters::from_node_id(nodes[19], 0);
match get_route(&our_id, &fail_payment_params, &network_graph, None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes)
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes)
{
Err(LightningError { err, .. } ) => {
assert_eq!(err, "Failed to find a path to the given destination");
let payment_params = PaymentParameters::from_node_id(nodes[6], 42).with_route_hints(last_hops(&nodes)).unwrap();
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 1);
let cltv_expiry_deltas_before = route.paths[0].hops.iter().map(|h| h.cltv_expiry_delta).collect::<Vec<u32>>();
let random_seed_bytes = keys_manager.get_secure_random_bytes();
let mut route = get_route(&our_id, &payment_params, &network_graph, None, 100,
- Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ Arc::clone(&logger), &scorer, &(), &random_seed_bytes).unwrap();
add_random_cltv_offset(&mut route, &payment_params, &network_graph, &random_seed_bytes);
let mut path_plausibility = vec![];
fn avoids_saturating_channels() {
let (secp_ctx, network_graph, gossip_sync, _, logger) = build_graph();
let (_, our_id, privkeys, nodes) = get_nodes(&secp_ctx);
-
- let scorer = ProbabilisticScorer::new(Default::default(), &*network_graph, Arc::clone(&logger));
+ let decay_params = ProbabilisticScoringDecayParameters::default();
+ let scorer = ProbabilisticScorer::new(decay_params, &*network_graph, Arc::clone(&logger));
// Set the fee on channel 13 to 100% to match channel 4 giving us two equivalent paths (us
// -> node 7 -> node2 and us -> node 1 -> node 2) which we should balance over.
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
// 100,000 sats is less than the available liquidity on each channel, set above.
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000_000, Arc::clone(&logger), &scorer, &random_seed_bytes).unwrap();
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100_000_000, Arc::clone(&logger), &scorer, &ProbabilisticScoringFeeParameters::default(), &random_seed_bytes).unwrap();
assert_eq!(route.paths.len(), 2);
assert!((route.paths[0].hops[1].short_channel_id == 4 && route.paths[1].hops[1].short_channel_id == 13) ||
(route.paths[1].hops[1].short_channel_id == 4 && route.paths[0].hops[1].short_channel_id == 13));
#[test]
#[cfg(not(feature = "no-std"))]
fn generate_routes() {
- use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+ use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
let mut d = match super::bench_utils::get_route_file() {
Ok(f) => f,
let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
let payment_params = PaymentParameters::from_node_id(dst, 42);
let amt = seed as u64 % 200_000_000;
- let params = ProbabilisticScoringParameters::default();
- let scorer = ProbabilisticScorer::new(params, &graph, &logger);
- if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, &random_seed_bytes).is_ok() {
+ let params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
+ if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, ¶ms, &random_seed_bytes).is_ok() {
continue 'load_endpoints;
}
}
#[test]
#[cfg(not(feature = "no-std"))]
fn generate_routes_mpp() {
- use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+ use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters};
let mut d = match super::bench_utils::get_route_file() {
Ok(f) => f,
let dst = PublicKey::from_slice(nodes.unordered_keys().skip(seed % nodes.len()).next().unwrap().as_slice()).unwrap();
let payment_params = PaymentParameters::from_node_id(dst, 42).with_bolt11_features(channelmanager::provided_invoice_features(&config)).unwrap();
let amt = seed as u64 % 200_000_000;
- let params = ProbabilisticScoringParameters::default();
- let scorer = ProbabilisticScorer::new(params, &graph, &logger);
- if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, &random_seed_bytes).is_ok() {
+ let params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &graph, &logger);
+ if get_route(src, &payment_params, &graph.read_only(), None, amt, &logger, &scorer, ¶ms, &random_seed_bytes).is_ok() {
continue 'load_endpoints;
}
}
let keys_manager = ln_test_utils::TestKeysInterface::new(&[0u8; 32], Network::Testnet);
let random_seed_bytes = keys_manager.get_secure_random_bytes();
- let scorer_params = ProbabilisticScoringParameters::default();
- let mut scorer = ProbabilisticScorer::new(scorer_params, Arc::clone(&network_graph), Arc::clone(&logger));
+ let mut scorer_params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), Arc::clone(&network_graph), Arc::clone(&logger));
// First check set manual penalties are returned by the scorer.
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
};
- scorer.set_manual_penalty(&NodeId::from_pubkey(&nodes[3]), 123);
- scorer.set_manual_penalty(&NodeId::from_pubkey(&nodes[4]), 456);
- assert_eq!(scorer.channel_penalty_msat(42, &NodeId::from_pubkey(&nodes[3]), &NodeId::from_pubkey(&nodes[4]), usage), 456);
+ scorer_params.set_manual_penalty(&NodeId::from_pubkey(&nodes[3]), 123);
+ scorer_params.set_manual_penalty(&NodeId::from_pubkey(&nodes[4]), 456);
+ assert_eq!(scorer.channel_penalty_msat(42, &NodeId::from_pubkey(&nodes[3]), &NodeId::from_pubkey(&nodes[4]), usage, &scorer_params), 456);
// Then check we can get a normal route
let payment_params = PaymentParameters::from_node_id(nodes[10], 42);
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes);
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &scorer_params,&random_seed_bytes);
assert!(route.is_ok());
// Then check that we can't get a route if we ban an intermediate node.
- scorer.add_banned(&NodeId::from_pubkey(&nodes[3]));
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes);
+ scorer_params.add_banned(&NodeId::from_pubkey(&nodes[3]));
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &scorer_params,&random_seed_bytes);
assert!(route.is_err());
// Finally make sure we can route again, when we remove the ban.
- scorer.remove_banned(&NodeId::from_pubkey(&nodes[3]));
- let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &random_seed_bytes);
+ scorer_params.remove_banned(&NodeId::from_pubkey(&nodes[3]));
+ let route = get_route(&our_id, &payment_params, &network_graph.read_only(), None, 100, Arc::clone(&logger), &scorer, &scorer_params,&random_seed_bytes);
assert!(route.is_ok());
}
use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
use crate::ln::features::InvoiceFeatures;
use crate::routing::gossip::NetworkGraph;
- use crate::routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters};
+ use crate::routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
use crate::util::config::UserConfig;
use crate::util::logger::{Logger, Record};
use crate::util::ser::ReadableArgs;
let logger = DummyLogger {};
let network_graph = read_network_graph(&logger);
let scorer = FixedPenaltyScorer::with_penalty(0);
- generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
+ generate_routes(bench, &network_graph, scorer, &(), InvoiceFeatures::empty());
}
#[bench]
let logger = DummyLogger {};
let network_graph = read_network_graph(&logger);
let scorer = FixedPenaltyScorer::with_penalty(0);
- generate_routes(bench, &network_graph, scorer, channelmanager::provided_invoice_features(&UserConfig::default()));
+ generate_routes(bench, &network_graph, scorer, &(), channelmanager::provided_invoice_features(&UserConfig::default()));
}
#[bench]
fn generate_routes_with_probabilistic_scorer(bench: &mut Bencher) {
let logger = DummyLogger {};
let network_graph = read_network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- generate_routes(bench, &network_graph, scorer, InvoiceFeatures::empty());
+ let params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ generate_routes(bench, &network_graph, scorer, ¶ms, InvoiceFeatures::empty());
}
#[bench]
fn generate_mpp_routes_with_probabilistic_scorer(bench: &mut Bencher) {
let logger = DummyLogger {};
let network_graph = read_network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- generate_routes(bench, &network_graph, scorer, channelmanager::provided_invoice_features(&UserConfig::default()));
+ let params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ generate_routes(bench, &network_graph, scorer, ¶ms, channelmanager::provided_invoice_features(&UserConfig::default()));
}
fn generate_routes<S: Score>(
- bench: &mut Bencher, graph: &NetworkGraph<&DummyLogger>, mut scorer: S,
+ bench: &mut Bencher, graph: &NetworkGraph<&DummyLogger>, mut scorer: S, score_params: &S::ScoreParams,
features: InvoiceFeatures
) {
let nodes = graph.read_only().nodes().clone();
let params = PaymentParameters::from_node_id(dst, 42).with_bolt11_features(features.clone()).unwrap();
let first_hop = first_hop(src);
let amt = seed as u64 % 1_000_000;
- if let Ok(route) = get_route(&payer, ¶ms, &graph.read_only(), Some(&[&first_hop]), amt, &DummyLogger{}, &scorer, &random_seed_bytes) {
+ if let Ok(route) = get_route(&payer, ¶ms, &graph.read_only(), Some(&[&first_hop]), amt, &DummyLogger{}, &scorer, score_params, &random_seed_bytes) {
routes.push(route);
route_endpoints.push((first_hop, params, amt));
continue 'load_endpoints;
// selected destinations, possibly causing us to fail because, eg, the newly-selected path
// requires a too-high CLTV delta.
route_endpoints.retain(|(first_hop, params, amt)| {
- get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok()
+ get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, score_params, &random_seed_bytes).is_ok()
});
route_endpoints.truncate(100);
assert_eq!(route_endpoints.len(), 100);
let mut idx = 0;
bench.iter(|| {
let (first_hop, params, amt) = &route_endpoints[idx % route_endpoints.len()];
- assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, &random_seed_bytes).is_ok());
+ assert!(get_route(&payer, params, &graph.read_only(), Some(&[first_hop]), *amt, &DummyLogger{}, &scorer, score_params, &random_seed_bytes).is_ok());
idx += 1;
});
}
//! #
//! # use lightning::routing::gossip::NetworkGraph;
//! # use lightning::routing::router::{RouteParameters, find_route};
-//! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters};
+//! # use lightning::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters};
//! # use lightning::sign::KeysManager;
//! # use lightning::util::logger::{Logger, Record};
//! # use bitcoin::secp256k1::PublicKey;
//! # let logger = FakeLogger {};
//! #
//! // Use the default channel penalties.
-//! let params = ProbabilisticScoringParameters::default();
-//! let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+//! let params = ProbabilisticScoringFeeParameters::default();
+//! let decay_params = ProbabilisticScoringDecayParameters::default();
+//! let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
//!
//! // Or use custom channel penalties.
-//! let params = ProbabilisticScoringParameters {
-//! liquidity_penalty_multiplier_msat: 2 * 1000,
-//! ..ProbabilisticScoringParameters::default()
+//! let params = ProbabilisticScoringFeeParameters {
+//! liquidity_penalty_multiplier_msat: 2 * 1000,
+//! ..ProbabilisticScoringFeeParameters::default()
//! };
-//! let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+//! let decay_params = ProbabilisticScoringDecayParameters::default();
+//! let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
//! # let random_seed_bytes = [42u8; 32];
//!
-//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, &random_seed_bytes);
+//! let route = find_route(&payer, &route_params, &network_graph, None, &logger, &scorer, ¶ms, &random_seed_bytes);
//! # }
//! ```
//!
///
/// Scoring is in terms of fees willing to be paid in order to avoid routing through a channel.
pub trait Score $(: $supertrait)* {
+ /// A configurable type which should contain various passed-in parameters for configuring the scorer,
+ /// on a per-routefinding-call basis through to the scorer methods,
+ /// which are used to determine the parameters for the suitability of channels for use.
+ type ScoreParams;
/// 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`.
///
/// [`u64::max_value`] is given to indicate sufficient capacity for the invoice's full amount.
/// Thus, implementations should be overflow-safe.
fn channel_penalty_msat(
- &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+ &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams
) -> u64;
/// Handles updating channel penalties after failing to route through a channel.
}
impl<S: Score, T: DerefMut<Target=S> $(+ $supertrait)*> Score for T {
+ type ScoreParams = S::ScoreParams;
fn channel_penalty_msat(
- &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+ &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams
) -> u64 {
- self.deref().channel_penalty_msat(short_channel_id, source, target, usage)
+ self.deref().channel_penalty_msat(short_channel_id, source, target, usage, score_params)
}
fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) {
pub struct MultiThreadedScoreLock<'a, S: Score>(MutexGuard<'a, S>);
#[cfg(c_bindings)]
impl<'a, T: Score + 'a> Score for MultiThreadedScoreLock<'a, T> {
- fn channel_penalty_msat(&self, scid: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage) -> u64 {
- self.0.channel_penalty_msat(scid, source, target, usage)
+ type ScoreParams = <T as Score>::ScoreParams;
+ fn channel_penalty_msat(&self, scid: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &Self::ScoreParams) -> u64 {
+ self.0.channel_penalty_msat(scid, source, target, usage, score_params)
}
fn payment_path_failed(&mut self, path: &Path, short_channel_id: u64) {
self.0.payment_path_failed(path, short_channel_id)
}
impl Score for FixedPenaltyScorer {
- fn channel_penalty_msat(&self, _: u64, _: &NodeId, _: &NodeId, _: ChannelUsage) -> u64 {
+ type ScoreParams = ();
+ fn channel_penalty_msat(&self, _: u64, _: &NodeId, _: &NodeId, _: ChannelUsage, _score_params: &Self::ScoreParams) -> u64 {
self.penalty_msat
}
/// behavior.
///
/// [1]: https://arxiv.org/abs/2107.05322
-/// [`liquidity_penalty_multiplier_msat`]: ProbabilisticScoringParameters::liquidity_penalty_multiplier_msat
-/// [`liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringParameters::liquidity_penalty_amount_multiplier_msat
-/// [`liquidity_offset_half_life`]: ProbabilisticScoringParameters::liquidity_offset_half_life
-/// [`historical_liquidity_penalty_multiplier_msat`]: ProbabilisticScoringParameters::historical_liquidity_penalty_multiplier_msat
-/// [`historical_liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringParameters::historical_liquidity_penalty_amount_multiplier_msat
+/// [`liquidity_penalty_multiplier_msat`]: ProbabilisticScoringFeeParameters::liquidity_penalty_multiplier_msat
+/// [`liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringFeeParameters::liquidity_penalty_amount_multiplier_msat
+/// [`liquidity_offset_half_life`]: ProbabilisticScoringDecayParameters::liquidity_offset_half_life
+/// [`historical_liquidity_penalty_multiplier_msat`]: ProbabilisticScoringFeeParameters::historical_liquidity_penalty_multiplier_msat
+/// [`historical_liquidity_penalty_amount_multiplier_msat`]: ProbabilisticScoringFeeParameters::historical_liquidity_penalty_amount_multiplier_msat
pub type ProbabilisticScorer<G, L> = ProbabilisticScorerUsingTime::<G, L, ConfiguredTime>;
/// Probabilistic [`Score`] implementation.
/// This is not exported to bindings users generally all users should use the [`ProbabilisticScorer`] type alias.
pub struct ProbabilisticScorerUsingTime<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time>
where L::Target: Logger {
- params: ProbabilisticScoringParameters,
+ decay_params: ProbabilisticScoringDecayParameters,
network_graph: G,
logger: L,
// TODO: Remove entries of closed channels.
/// The penalty applied to any channel by the [`ProbabilisticScorer`] is the sum of each of the
/// parameters here.
#[derive(Clone)]
-pub struct ProbabilisticScoringParameters {
+pub struct ProbabilisticScoringFeeParameters {
/// A fixed penalty in msats to apply to each channel.
///
/// Default value: 500 msat
///
/// Default value: 30,000 msat
///
- /// [`liquidity_offset_half_life`]: Self::liquidity_offset_half_life
+ /// [`liquidity_offset_half_life`]: ProbabilisticScoringDecayParameters::liquidity_offset_half_life
pub liquidity_penalty_multiplier_msat: u64,
- /// Whenever this amount of time elapses since the last update to a channel's liquidity bounds,
- /// the distance from the bounds to "zero" is cut in half. In other words, the lower-bound on
- /// the available liquidity is halved and the upper-bound moves half-way to the channel's total
- /// capacity.
- ///
- /// Because halving the liquidity bounds grows the uncertainty on the channel's liquidity,
- /// the penalty for an amount within the new bounds may change. See the [`ProbabilisticScorer`]
- /// struct documentation for more info on the way the liquidity bounds are used.
- ///
- /// For example, if the channel's capacity is 1 million sats, and the current upper and lower
- /// liquidity bounds are 200,000 sats and 600,000 sats, after this amount of time the upper
- /// and lower liquidity bounds will be decayed to 100,000 and 800,000 sats.
- ///
- /// Default value: 6 hours
- ///
- /// # Note
- ///
- /// When built with the `no-std` feature, time will never elapse. Therefore, the channel
- /// liquidity knowledge will never decay except when the bounds cross.
- pub liquidity_offset_half_life: Duration,
-
/// A multiplier used in conjunction with a payment amount and the negative `log10` of the
/// channel's success probability for the payment, as determined by our latest estimates of the
/// channel's liquidity, to determine the amount penalty.
/// [`liquidity_penalty_amount_multiplier_msat`]: Self::liquidity_penalty_amount_multiplier_msat
pub historical_liquidity_penalty_amount_multiplier_msat: u64,
- /// If we aren't learning any new datapoints for a channel, the historical liquidity bounds
- /// tracking can simply live on with increasingly stale data. Instead, when a channel has not
- /// seen a liquidity estimate update for this amount of time, the historical datapoints are
- /// decayed by half.
- ///
- /// Note that after 16 or more half lives all historical data will be completely gone.
- ///
- /// Default value: 14 days
- pub historical_no_updates_half_life: Duration,
-
/// Manual penalties used for the given nodes. Allows to set a particular penalty for a given
/// node. Note that a manual penalty of `u64::max_value()` means the node would not ever be
/// considered during path finding.
pub manual_node_penalties: HashMap<NodeId, u64>,
/// This penalty is applied when `htlc_maximum_msat` is equal to or larger than half of the
- /// channel's capacity, which makes us prefer nodes with a smaller `htlc_maximum_msat`. We
- /// treat such nodes preferentially as this makes balance discovery attacks harder to execute,
- /// thereby creating an incentive to restrict `htlc_maximum_msat` and improve privacy.
+ /// channel's capacity, (ie. htlc_maximum_msat ≥ 0.5 * channel_capacity) which makes us
+ /// prefer nodes with a smaller `htlc_maximum_msat`. We treat such nodes preferentially
+ /// as this makes balance discovery attacks harder to execute, thereby creating an incentive
+ /// to restrict `htlc_maximum_msat` and improve privacy.
///
/// Default value: 250 msat
pub anti_probing_penalty_msat: u64,
pub considered_impossible_penalty_msat: u64,
}
+/// Parameters for configuring [`ProbabilisticScorer`].
+///
+/// Used to configure decay parameters that are static throughout the lifetime of the scorer.
+/// these decay parameters affect the score of the channel penalty and are not changed on a
+/// per-route penalty cost call.
+#[derive(Copy, Clone)]
+pub struct ProbabilisticScoringDecayParameters {
+ /// If we aren't learning any new datapoints for a channel, the historical liquidity bounds
+ /// tracking can simply live on with increasingly stale data. Instead, when a channel has not
+ /// seen a liquidity estimate update for this amount of time, the historical datapoints are
+ /// decayed by half.
+ /// For an example of historical_no_updates_half_life being used see [`historical_estimated_channel_liquidity_probabilities`]
+ ///
+ /// Note that after 16 or more half lives all historical data will be completely gone.
+ ///
+ /// Default value: 14 days
+ ///
+ /// [`historical_estimated_channel_liquidity_probabilities`]: ProbabilisticScorerUsingTime::historical_estimated_channel_liquidity_probabilities
+ pub historical_no_updates_half_life: Duration,
+
+ /// Whenever this amount of time elapses since the last update to a channel's liquidity bounds,
+ /// the distance from the bounds to "zero" is cut in half. In other words, the lower-bound on
+ /// the available liquidity is halved and the upper-bound moves half-way to the channel's total
+ /// capacity.
+ ///
+ /// Because halving the liquidity bounds grows the uncertainty on the channel's liquidity,
+ /// the penalty for an amount within the new bounds may change. See the [`ProbabilisticScorer`]
+ /// struct documentation for more info on the way the liquidity bounds are used.
+ ///
+ /// For example, if the channel's capacity is 1 million sats, and the current upper and lower
+ /// liquidity bounds are 200,000 sats and 600,000 sats, after this amount of time the upper
+ /// and lower liquidity bounds will be decayed to 100,000 and 800,000 sats.
+ ///
+ /// Default value: 6 hours
+ ///
+ /// # Note
+ ///
+ /// When built with the `no-std` feature, time will never elapse. Therefore, the channel
+ /// liquidity knowledge will never decay except when the bounds cross.
+ pub liquidity_offset_half_life: Duration,
+}
+
+#[cfg(test)]
+impl ProbabilisticScoringDecayParameters {
+ fn zero_penalty() -> Self {
+ Self {
+ liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
+ historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
+ }
+ }
+}
+
+impl Default for ProbabilisticScoringDecayParameters {
+ fn default() -> Self {
+ Self {
+ liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
+ historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
+ }
+ }
+}
/// Tracks the historical state of a distribution as a weighted average of how much time was spent
/// in each of 8 buckets.
#[derive(Clone, Copy)]
/// A snapshot of [`ChannelLiquidity`] in one direction assuming a certain channel capacity and
/// decayed with a given half life.
-struct DirectedChannelLiquidity<'a, L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> {
+struct DirectedChannelLiquidity<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> {
min_liquidity_offset_msat: L,
max_liquidity_offset_msat: L,
min_liquidity_offset_history: BRT,
capacity_msat: u64,
last_updated: U,
now: T,
- params: &'a ProbabilisticScoringParameters,
+ decay_params: ProbabilisticScoringDecayParameters,
}
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
/// Creates a new scorer using the given scoring parameters for sending payments from a node
/// through a network graph.
- pub fn new(params: ProbabilisticScoringParameters, network_graph: G, logger: L) -> Self {
+ pub fn new(decay_params: ProbabilisticScoringDecayParameters, network_graph: G, logger: L) -> Self {
Self {
- params,
+ decay_params,
network_graph,
logger,
channel_liquidities: HashMap::new(),
let log_direction = |source, target| {
if let Some((directed_info, _)) = chan_debug.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
- let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
+ let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
let buckets = HistoricalMinMaxBuckets {
min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
};
let (min_buckets, max_buckets, _) = buckets.get_decayed_buckets(now,
- *dir_liq.last_updated, self.params.historical_no_updates_half_life);
+ *dir_liq.last_updated, self.decay_params.historical_no_updates_half_life);
log_debug!(self.logger, core::concat!(
"Liquidity from {} to {} via {} is in the range ({}, {}).\n",
if let Some(liq) = self.channel_liquidities.get(&scid) {
if let Some((directed_info, source)) = chan.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
- let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
+ let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
return Some((dir_liq.min_liquidity_msat(), dir_liq.max_liquidity_msat()));
}
}
if let Some(liq) = self.channel_liquidities.get(&scid) {
if let Some((directed_info, source)) = chan.as_directed_to(target) {
let amt = directed_info.effective_capacity().as_msat();
- let dir_liq = liq.as_directed(source, target, 0, amt, &self.params);
+ let dir_liq = liq.as_directed(source, target, 0, amt, self.decay_params);
let buckets = HistoricalMinMaxBuckets {
min_liquidity_offset_history: &dir_liq.min_liquidity_offset_history,
max_liquidity_offset_history: &dir_liq.max_liquidity_offset_history,
};
let (min_buckets, mut max_buckets, _) = buckets.get_decayed_buckets(T::now(),
- *dir_liq.last_updated, self.params.historical_no_updates_half_life);
+ *dir_liq.last_updated, self.decay_params.historical_no_updates_half_life);
// Note that the liquidity buckets are an offset from the edge, so we inverse
// the max order to get the probabilities from zero.
max_buckets.reverse();
}
None
}
-
- /// Marks the node with the given `node_id` as banned, i.e.,
- /// it will be avoided during path finding.
- pub fn add_banned(&mut self, node_id: &NodeId) {
- self.params.manual_node_penalties.insert(*node_id, u64::max_value());
- }
-
- /// Removes the node with the given `node_id` from the list of nodes to avoid.
- pub fn remove_banned(&mut self, node_id: &NodeId) {
- self.params.manual_node_penalties.remove(node_id);
- }
-
- /// Sets a manual penalty for the given node.
- pub fn set_manual_penalty(&mut self, node_id: &NodeId, penalty: u64) {
- self.params.manual_node_penalties.insert(*node_id, penalty);
- }
-
- /// Removes the node with the given `node_id` from the list of manual penalties.
- pub fn remove_manual_penalty(&mut self, node_id: &NodeId) {
- self.params.manual_node_penalties.remove(node_id);
- }
-
- /// Clears the list of manual penalties that are applied during path finding.
- pub fn clear_manual_penalties(&mut self) {
- self.params.manual_node_penalties = HashMap::new();
- }
}
-impl ProbabilisticScoringParameters {
+impl ProbabilisticScoringFeeParameters {
#[cfg(test)]
fn zero_penalty() -> Self {
Self {
base_penalty_msat: 0,
base_penalty_amount_multiplier_msat: 0,
liquidity_penalty_multiplier_msat: 0,
- liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
liquidity_penalty_amount_multiplier_msat: 0,
historical_liquidity_penalty_multiplier_msat: 0,
historical_liquidity_penalty_amount_multiplier_msat: 0,
- historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
manual_node_penalties: HashMap::new(),
anti_probing_penalty_msat: 0,
considered_impossible_penalty_msat: 0,
}
}
+ /// Marks the node with the given `node_id` as banned, i.e.,
+ /// it will be avoided during path finding.
+ pub fn add_banned(&mut self, node_id: &NodeId) {
+ self.manual_node_penalties.insert(*node_id, u64::max_value());
+ }
+
/// Marks all nodes in the given list as banned, i.e.,
/// they will be avoided during path finding.
pub fn add_banned_from_list(&mut self, node_ids: Vec<NodeId>) {
self.manual_node_penalties.insert(id, u64::max_value());
}
}
+
+ /// Removes the node with the given `node_id` from the list of nodes to avoid.
+ pub fn remove_banned(&mut self, node_id: &NodeId) {
+ self.manual_node_penalties.remove(node_id);
+ }
+
+ /// Sets a manual penalty for the given node.
+ pub fn set_manual_penalty(&mut self, node_id: &NodeId, penalty: u64) {
+ self.manual_node_penalties.insert(*node_id, penalty);
+ }
+
+ /// Removes the node with the given `node_id` from the list of manual penalties.
+ pub fn remove_manual_penalty(&mut self, node_id: &NodeId) {
+ self.manual_node_penalties.remove(node_id);
+ }
+
+ /// Clears the list of manual penalties that are applied during path finding.
+ pub fn clear_manual_penalties(&mut self) {
+ self.manual_node_penalties = HashMap::new();
+ }
}
-impl Default for ProbabilisticScoringParameters {
+impl Default for ProbabilisticScoringFeeParameters {
fn default() -> Self {
Self {
base_penalty_msat: 500,
base_penalty_amount_multiplier_msat: 8192,
liquidity_penalty_multiplier_msat: 30_000,
- liquidity_offset_half_life: Duration::from_secs(6 * 60 * 60),
liquidity_penalty_amount_multiplier_msat: 192,
- historical_liquidity_penalty_multiplier_msat: 10_000,
- historical_liquidity_penalty_amount_multiplier_msat: 64,
- historical_no_updates_half_life: Duration::from_secs(60 * 60 * 24 * 14),
manual_node_penalties: HashMap::new(),
anti_probing_penalty_msat: 250,
considered_impossible_penalty_msat: 1_0000_0000_000,
+ historical_liquidity_penalty_multiplier_msat: 10_000,
+ historical_liquidity_penalty_amount_multiplier_msat: 64,
}
}
}
/// Returns a view of the channel liquidity directed from `source` to `target` assuming
/// `capacity_msat`.
- fn as_directed<'a>(
- &self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64,
- params: &'a ProbabilisticScoringParameters
- ) -> DirectedChannelLiquidity<'a, &u64, &HistoricalBucketRangeTracker, T, &T> {
+ fn as_directed(
+ &self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
+ ) -> DirectedChannelLiquidity<&u64, &HistoricalBucketRangeTracker, T, &T> {
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
if source < target {
(&self.min_liquidity_offset_msat, &self.max_liquidity_offset_msat,
capacity_msat,
last_updated: &self.last_updated,
now: T::now(),
- params,
+ decay_params: decay_params,
}
}
/// Returns a mutable view of the channel liquidity directed from `source` to `target` assuming
/// `capacity_msat`.
- fn as_directed_mut<'a>(
- &mut self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64,
- params: &'a ProbabilisticScoringParameters
- ) -> DirectedChannelLiquidity<'a, &mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
+ fn as_directed_mut(
+ &mut self, source: &NodeId, target: &NodeId, inflight_htlc_msat: u64, capacity_msat: u64, decay_params: ProbabilisticScoringDecayParameters
+ ) -> DirectedChannelLiquidity<&mut u64, &mut HistoricalBucketRangeTracker, T, &mut T> {
let (min_liquidity_offset_msat, max_liquidity_offset_msat, min_liquidity_offset_history, max_liquidity_offset_history) =
if source < target {
(&mut self.min_liquidity_offset_msat, &mut self.max_liquidity_offset_msat,
capacity_msat,
last_updated: &mut self.last_updated,
now: T::now(),
- params,
+ decay_params: decay_params,
}
}
}
const AMOUNT_PENALTY_DIVISOR: u64 = 1 << 20;
const BASE_AMOUNT_PENALTY_DIVISOR: u64 = 1 << 30;
-impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity<'_, L, BRT, T, U> {
+impl<L: Deref<Target = u64>, BRT: Deref<Target = HistoricalBucketRangeTracker>, T: Time, U: Deref<Target = T>> DirectedChannelLiquidity< L, BRT, T, U> {
/// Returns a liquidity penalty for routing the given HTLC `amount_msat` through the channel in
/// this direction.
- fn penalty_msat(&self, amount_msat: u64, params: &ProbabilisticScoringParameters) -> u64 {
+ fn penalty_msat(&self, amount_msat: u64, score_params: &ProbabilisticScoringFeeParameters) -> u64 {
let max_liquidity_msat = self.max_liquidity_msat();
let min_liquidity_msat = core::cmp::min(self.min_liquidity_msat(), max_liquidity_msat);
// impossibility penalty.
let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048;
Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
- params.liquidity_penalty_multiplier_msat,
- params.liquidity_penalty_amount_multiplier_msat)
- .saturating_add(params.considered_impossible_penalty_msat)
+ score_params.liquidity_penalty_multiplier_msat,
+ score_params.liquidity_penalty_amount_multiplier_msat)
+ .saturating_add(score_params.considered_impossible_penalty_msat)
} else {
let numerator = (max_liquidity_msat - amount_msat).saturating_add(1);
let denominator = (max_liquidity_msat - min_liquidity_msat).saturating_add(1);
let negative_log10_times_2048 =
approx::negative_log10_times_2048(numerator, denominator);
Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
- params.liquidity_penalty_multiplier_msat,
- params.liquidity_penalty_amount_multiplier_msat)
+ score_params.liquidity_penalty_multiplier_msat,
+ score_params.liquidity_penalty_amount_multiplier_msat)
}
};
- if params.historical_liquidity_penalty_multiplier_msat != 0 ||
- params.historical_liquidity_penalty_amount_multiplier_msat != 0 {
+ if score_params.historical_liquidity_penalty_multiplier_msat != 0 ||
+ score_params.historical_liquidity_penalty_amount_multiplier_msat != 0 {
let payment_amt_64th_bucket = if amount_msat < u64::max_value() / 64 {
amount_msat * 64 / self.capacity_msat.saturating_add(1)
} else {
};
if let Some(cumulative_success_prob_times_billion) = buckets
.calculate_success_probability_times_billion(self.now, *self.last_updated,
- params.historical_no_updates_half_life, payment_amt_64th_bucket as u8)
+ self.decay_params.historical_no_updates_half_life, payment_amt_64th_bucket as u8)
{
let historical_negative_log10_times_2048 = approx::negative_log10_times_2048(cumulative_success_prob_times_billion + 1, 1024 * 1024 * 1024);
res = res.saturating_add(Self::combined_penalty_msat(amount_msat,
- historical_negative_log10_times_2048, params.historical_liquidity_penalty_multiplier_msat,
- params.historical_liquidity_penalty_amount_multiplier_msat));
+ historical_negative_log10_times_2048, score_params.historical_liquidity_penalty_multiplier_msat,
+ score_params.historical_liquidity_penalty_amount_multiplier_msat));
} else {
// If we don't have any valid points (or, once decayed, we have less than a full
// point), redo the non-historical calculation with no liquidity bounds tracked and
let negative_log10_times_2048 =
approx::negative_log10_times_2048(numerator, denominator);
res = res.saturating_add(Self::combined_penalty_msat(amount_msat, negative_log10_times_2048,
- params.historical_liquidity_penalty_multiplier_msat,
- params.historical_liquidity_penalty_amount_multiplier_msat));
+ score_params.historical_liquidity_penalty_multiplier_msat,
+ score_params.historical_liquidity_penalty_amount_multiplier_msat));
}
}
fn decayed_offset_msat(&self, offset_msat: u64) -> u64 {
self.now.duration_since(*self.last_updated).as_secs()
- .checked_div(self.params.liquidity_offset_half_life.as_secs())
+ .checked_div(self.decay_params.liquidity_offset_half_life.as_secs())
.and_then(|decays| offset_msat.checked_shr(decays as u32))
.unwrap_or(0)
}
}
-impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<'_, L, BRT, T, U> {
+impl<L: DerefMut<Target = u64>, BRT: DerefMut<Target = HistoricalBucketRangeTracker>, T: Time, U: DerefMut<Target = T>> DirectedChannelLiquidity<L, BRT, T, U> {
/// Adjusts the channel liquidity balance bounds when failing to route `amount_msat`.
fn failed_at_channel<Log: Deref>(&mut self, amount_msat: u64, chan_descr: fmt::Arguments, logger: &Log) where Log::Target: Logger {
let existing_max_msat = self.max_liquidity_msat();
fn update_history_buckets(&mut self) {
let half_lives = self.now.duration_since(*self.last_updated).as_secs()
- .checked_div(self.params.historical_no_updates_half_life.as_secs())
+ .checked_div(self.decay_params.historical_no_updates_half_life.as_secs())
.map(|v| v.try_into().unwrap_or(u32::max_value())).unwrap_or(u32::max_value());
self.min_liquidity_offset_history.time_decay_data(half_lives);
self.max_liquidity_offset_history.time_decay_data(half_lives);
}
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time> Score for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+ type ScoreParams = ProbabilisticScoringFeeParameters;
fn channel_penalty_msat(
- &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage
+ &self, short_channel_id: u64, source: &NodeId, target: &NodeId, usage: ChannelUsage, score_params: &ProbabilisticScoringFeeParameters
) -> u64 {
- if let Some(penalty) = self.params.manual_node_penalties.get(target) {
+ if let Some(penalty) = score_params.manual_node_penalties.get(target) {
return *penalty;
}
- let base_penalty_msat = self.params.base_penalty_msat.saturating_add(
- self.params.base_penalty_amount_multiplier_msat
+ let base_penalty_msat = score_params.base_penalty_msat.saturating_add(
+ score_params.base_penalty_amount_multiplier_msat
.saturating_mul(usage.amount_msat) / BASE_AMOUNT_PENALTY_DIVISOR);
let mut anti_probing_penalty_msat = 0;
},
EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat } => {
if htlc_maximum_msat >= capacity_msat/2 {
- anti_probing_penalty_msat = self.params.anti_probing_penalty_msat;
+ anti_probing_penalty_msat = score_params.anti_probing_penalty_msat;
}
},
_ => {},
self.channel_liquidities
.get(&short_channel_id)
.unwrap_or(&ChannelLiquidity::new())
- .as_directed(source, target, inflight_htlc_msat, capacity_msat, &self.params)
- .penalty_msat(amount_msat, &self.params)
+ .as_directed(source, target, inflight_htlc_msat, capacity_msat, self.decay_params)
+ .penalty_msat(amount_msat, score_params)
.saturating_add(anti_probing_penalty_msat)
.saturating_add(base_penalty_msat)
}
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(ChannelLiquidity::new)
- .as_directed_mut(source, &target, 0, capacity_msat, &self.params)
+ .as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
.failed_at_channel(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
} else {
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(ChannelLiquidity::new)
- .as_directed_mut(source, &target, 0, capacity_msat, &self.params)
+ .as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
.failed_downstream(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
}
} else {
self.channel_liquidities
.entry(hop.short_channel_id)
.or_insert_with(ChannelLiquidity::new)
- .as_directed_mut(source, &target, 0, capacity_msat, &self.params)
+ .as_directed_mut(source, &target, 0, capacity_msat, self.decay_params)
.successful(amount_msat, format_args!("SCID {}, towards {:?}", hop.short_channel_id, target), &self.logger);
} else {
log_debug!(self.logger, "Not able to learn for channel with SCID {} as we do not have graph info for it (likely a route-hint last-hop).",
}
impl<G: Deref<Target = NetworkGraph<L>>, L: Deref, T: Time>
-ReadableArgs<(ProbabilisticScoringParameters, G, L)> for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
+ReadableArgs<(ProbabilisticScoringDecayParameters, G, L)> for ProbabilisticScorerUsingTime<G, L, T> where L::Target: Logger {
#[inline]
fn read<R: Read>(
- r: &mut R, args: (ProbabilisticScoringParameters, G, L)
+ r: &mut R, args: (ProbabilisticScoringDecayParameters, G, L)
) -> Result<Self, DecodeError> {
- let (params, network_graph, logger) = args;
+ let (decay_params, network_graph, logger) = args;
let mut channel_liquidities = HashMap::new();
read_tlv_fields!(r, {
(0, channel_liquidities, required),
});
Ok(Self {
- params,
+ decay_params,
network_graph,
logger,
channel_liquidities,
#[cfg(test)]
mod tests {
- use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringParameters, ProbabilisticScorerUsingTime};
+ use super::{ChannelLiquidity, HistoricalBucketRangeTracker, ProbabilisticScoringFeeParameters, ProbabilisticScoringDecayParameters, ProbabilisticScorerUsingTime};
use crate::blinded_path::{BlindedHop, BlindedPath};
use crate::util::config::UserConfig;
use crate::util::time::Time;
let logger = TestLogger::new();
let last_updated = SinceEpoch::now();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+ let decay_params = ProbabilisticScoringDecayParameters::default();
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
min_liquidity_offset_msat: 700, max_liquidity_offset_msat: 100, last_updated,
// Update minimum liquidity.
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 100);
assert_eq!(liquidity.max_liquidity_msat(), 300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 900);
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&source, &target, 0, 1_000, &scorer.params)
+ .as_directed_mut(&source, &target, 0, 1_000, decay_params)
.set_min_liquidity_msat(200);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 800);
// Update maximum liquidity.
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&target, &recipient, 0, 1_000, &scorer.params);
+ .as_directed(&target, &recipient, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 900);
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&recipient, &target, 0, 1_000, &scorer.params);
+ .as_directed(&recipient, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 100);
assert_eq!(liquidity.max_liquidity_msat(), 300);
scorer.channel_liquidities.get_mut(&43).unwrap()
- .as_directed_mut(&target, &recipient, 0, 1_000, &scorer.params)
+ .as_directed_mut(&target, &recipient, 0, 1_000, decay_params)
.set_max_liquidity_msat(200);
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&target, &recipient, 0, 1_000, &scorer.params);
+ .as_directed(&target, &recipient, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 200);
let liquidity = scorer.channel_liquidities.get(&43).unwrap()
- .as_directed(&recipient, &target, 0, 1_000, &scorer.params);
+ .as_directed(&recipient, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 800);
assert_eq!(liquidity.max_liquidity_msat(), 1000);
}
let logger = TestLogger::new();
let last_updated = SinceEpoch::now();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+ let decay_params = ProbabilisticScoringDecayParameters::default();
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated,
// Check initial bounds.
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 800);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 600);
// Reset from source to target.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&source, &target, 0, 1_000, &scorer.params)
+ .as_directed_mut(&source, &target, 0, 1_000, decay_params)
.set_min_liquidity_msat(900);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 900);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 100);
// Reset from target to source.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&target, &source, 0, 1_000, &scorer.params)
+ .as_directed_mut(&target, &source, 0, 1_000, decay_params)
.set_min_liquidity_msat(400);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 600);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
}
let logger = TestLogger::new();
let last_updated = SinceEpoch::now();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+ let decay_params = ProbabilisticScoringDecayParameters::default();
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
min_liquidity_offset_msat: 200, max_liquidity_offset_msat: 400, last_updated,
// Check initial bounds.
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 800);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 200);
assert_eq!(liquidity.max_liquidity_msat(), 600);
// Reset from source to target.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&source, &target, 0, 1_000, &scorer.params)
+ .as_directed_mut(&source, &target, 0, 1_000, decay_params)
.set_max_liquidity_msat(300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 300);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 700);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
// Reset from target to source.
scorer.channel_liquidities.get_mut(&42).unwrap()
- .as_directed_mut(&target, &source, 0, 1_000, &scorer.params)
+ .as_directed_mut(&target, &source, 0, 1_000, decay_params)
.set_max_liquidity_msat(600);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 400);
assert_eq!(liquidity.max_liquidity_msat(), 1_000);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&target, &source, 0, 1_000, &scorer.params);
+ .as_directed(&target, &source, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 0);
assert_eq!(liquidity.max_liquidity_msat(), 600);
}
fn increased_penalty_nearing_liquidity_upper_bound() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let decay_params = ProbabilisticScoringDecayParameters::default();
+ let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 10_240, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 102_400, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 47);
let usage = ChannelUsage { amount_msat: 1_023_999, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 2_000);
let usage = ChannelUsage {
amount_msat: 128,
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 58);
let usage = ChannelUsage { amount_msat: 256, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 125);
let usage = ChannelUsage { amount_msat: 374, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 198);
let usage = ChannelUsage { amount_msat: 512, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
let usage = ChannelUsage { amount_msat: 640, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 425);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 425);
let usage = ChannelUsage { amount_msat: 768, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 602);
let usage = ChannelUsage { amount_msat: 896, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 902);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 902);
}
#[test]
let logger = TestLogger::new();
let last_updated = SinceEpoch::now();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
considered_impossible_penalty_msat: u64::max_value(),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
+ };
+ let decay_params = ProbabilisticScoringDecayParameters {
+ ..ProbabilisticScoringDecayParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
+ let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger)
.with_channel(42,
ChannelLiquidity {
min_liquidity_offset_msat: 40, max_liquidity_offset_msat: 40, last_updated,
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 100, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 50, ..usage };
- assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
- assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
+ assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
let usage = ChannelUsage { amount_msat: 61, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
}
#[test]
fn does_not_further_penalize_own_channel() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let sender = sender_node_id();
let source = source_node_id();
let usage = ChannelUsage {
let failed_path = payment_path_for_amount(500);
let successful_path = payment_path_for_amount(200);
- assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
+ assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, ¶ms), 301);
scorer.payment_path_failed(&failed_path, 41);
- assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
+ assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, ¶ms), 301);
scorer.payment_path_successful(&successful_path);
- assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 301);
+ assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, ¶ms), 301);
}
#[test]
fn sets_liquidity_lower_bound_on_downstream_failure() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let path = payment_path_for_amount(500);
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 128);
let usage = ChannelUsage { amount_msat: 500, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 301);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 301);
let usage = ChannelUsage { amount_msat: 750, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 602);
scorer.payment_path_failed(&path, 43);
let usage = ChannelUsage { amount_msat: 250, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 500, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 750, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
}
#[test]
fn sets_liquidity_upper_bound_on_failure() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
considered_impossible_penalty_msat: u64::max_value(),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let path = payment_path_for_amount(500);
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 128);
let usage = ChannelUsage { amount_msat: 500, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 301);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 301);
let usage = ChannelUsage { amount_msat: 750, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 602);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 602);
scorer.payment_path_failed(&path, 42);
let usage = ChannelUsage { amount_msat: 250, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
let usage = ChannelUsage { amount_msat: 500, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
let usage = ChannelUsage { amount_msat: 750, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
}
#[test]
let node_c = NodeId::from_pubkey(&pub_c);
let node_d = NodeId::from_pubkey(&pub_d);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let usage = ChannelUsage {
amount_msat: 250,
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage), 128);
+ assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage, ¶ms), 128);
// Note that a default liquidity bound is used for B -> C as no channel exists
- assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage), 128);
- assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage), 128);
+ assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage, ¶ms), 128);
+ assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage, ¶ms), 128);
scorer.payment_path_failed(&Path { hops: path, blinded_tail: None }, 43);
- assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage), 80);
+ assert_eq!(scorer.channel_penalty_msat(42, &node_a, &node_b, usage, ¶ms), 80);
// Note that a default liquidity bound is used for B -> C as no channel exists
- assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage), 128);
- assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage), 128);
+ assert_eq!(scorer.channel_penalty_msat(43, &node_b, &node_c, usage, ¶ms), 128);
+ assert_eq!(scorer.channel_penalty_msat(44, &node_c, &node_d, usage, ¶ms), 128);
}
#[test]
fn reduces_liquidity_upper_bound_along_path_on_success() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let sender = sender_node_id();
let source = source_node_id();
let target = target_node_id();
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 128);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 128);
- assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage), 128);
+ assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, ¶ms), 128);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 128);
+ assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage, ¶ms), 128);
scorer.payment_path_successful(&payment_path_for_amount(500));
- assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage), 128);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
- assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(41, &sender, &source, usage, ¶ms), 128);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
+ assert_eq!(scorer.channel_penalty_msat(43, &target, &recipient, usage, ¶ms), 300);
}
#[test]
fn decays_liquidity_bounds_over_time() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- liquidity_offset_half_life: Duration::from_secs(10),
considered_impossible_penalty_msat: u64::max_value(),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let decay_params = ProbabilisticScoringDecayParameters {
+ liquidity_offset_half_life: Duration::from_secs(10),
+ ..ProbabilisticScoringDecayParameters::zero_penalty()
+ };
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 1_023, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 2_000);
scorer.payment_path_failed(&payment_path_for_amount(768), 42);
scorer.payment_path_failed(&payment_path_for_amount(128), 43);
let usage = ChannelUsage { amount_msat: 128, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 256, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 93);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 93);
let usage = ChannelUsage { amount_msat: 768, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_479);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1_479);
let usage = ChannelUsage { amount_msat: 896, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
SinceEpoch::advance(Duration::from_secs(9));
let usage = ChannelUsage { amount_msat: 128, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 256, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 93);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 93);
let usage = ChannelUsage { amount_msat: 768, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_479);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1_479);
let usage = ChannelUsage { amount_msat: 896, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
SinceEpoch::advance(Duration::from_secs(1));
let usage = ChannelUsage { amount_msat: 64, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 128, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 34);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 34);
let usage = ChannelUsage { amount_msat: 896, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1_970);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1_970);
let usage = ChannelUsage { amount_msat: 960, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
// Fully decay liquidity lower bound.
SinceEpoch::advance(Duration::from_secs(10 * 7));
let usage = ChannelUsage { amount_msat: 0, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 1, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 1_023, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 2_000);
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
// Fully decay liquidity upper bound.
SinceEpoch::advance(Duration::from_secs(10));
let usage = ChannelUsage { amount_msat: 0, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
SinceEpoch::advance(Duration::from_secs(10));
let usage = ChannelUsage { amount_msat: 0, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
}
#[test]
fn decays_liquidity_bounds_without_shift_overflow() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
+ };
+ let decay_params = ProbabilisticScoringDecayParameters {
liquidity_offset_half_life: Duration::from_secs(10),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringDecayParameters::default()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 125);
scorer.payment_path_failed(&payment_path_for_amount(512), 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 281);
// An unchecked right shift 64 bits or more in DirectedChannelLiquidity::decayed_offset_msat
// would cause an overflow.
SinceEpoch::advance(Duration::from_secs(10 * 64));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 125);
SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 125);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 125);
}
#[test]
fn restricts_liquidity_bounds_after_decay() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
+ };
+ let decay_params = ProbabilisticScoringDecayParameters {
liquidity_offset_half_life: Duration::from_secs(10),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringDecayParameters::default()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
// More knowledge gives higher confidence (256, 768), meaning a lower penalty.
scorer.payment_path_failed(&payment_path_for_amount(768), 42);
scorer.payment_path_failed(&payment_path_for_amount(256), 43);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 281);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 281);
// Decaying knowledge gives less confidence (128, 896), meaning a higher penalty.
SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 291);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 291);
// Reducing the upper bound gives more confidence (128, 832) that the payment amount (512)
// is closer to the upper bound, meaning a higher penalty.
scorer.payment_path_successful(&payment_path_for_amount(64));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 331);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 331);
// Increasing the lower bound gives more confidence (256, 832) that the payment amount (512)
// is closer to the lower bound, meaning a lower penalty.
scorer.payment_path_failed(&payment_path_for_amount(256), 43);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 245);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 245);
// Further decaying affects the lower bound more than the upper bound (128, 928).
SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 280);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 280);
}
#[test]
fn restores_persisted_liquidity_bounds() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- liquidity_offset_half_life: Duration::from_secs(10),
considered_impossible_penalty_msat: u64::max_value(),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
+ let decay_params = ProbabilisticScoringDecayParameters {
+ liquidity_offset_half_life: Duration::from_secs(10),
+ ..ProbabilisticScoringDecayParameters::default()
+ };
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let usage = ChannelUsage {
};
scorer.payment_path_failed(&payment_path_for_amount(500), 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 473);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 473);
scorer.payment_path_failed(&payment_path_for_amount(250), 43);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
let mut serialized_scorer = Vec::new();
scorer.write(&mut serialized_scorer).unwrap();
let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
let deserialized_scorer =
- <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph, &logger)).unwrap();
- assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ <ProbabilisticScorer>::read(&mut serialized_scorer, (decay_params, &network_graph, &logger)).unwrap();
+ assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
}
#[test]
fn decays_persisted_liquidity_bounds() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- liquidity_offset_half_life: Duration::from_secs(10),
considered_impossible_penalty_msat: u64::max_value(),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
+ };
+ let decay_params = ProbabilisticScoringDecayParameters {
+ liquidity_offset_half_life: Duration::from_secs(10),
+ ..ProbabilisticScoringDecayParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let usage = ChannelUsage {
};
scorer.payment_path_failed(&payment_path_for_amount(500), 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
let mut serialized_scorer = Vec::new();
scorer.write(&mut serialized_scorer).unwrap();
let mut serialized_scorer = io::Cursor::new(&serialized_scorer);
let deserialized_scorer =
- <ProbabilisticScorer>::read(&mut serialized_scorer, (params, &network_graph, &logger)).unwrap();
- assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 473);
+ <ProbabilisticScorer>::read(&mut serialized_scorer, (decay_params, &network_graph, &logger)).unwrap();
+ assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 473);
scorer.payment_path_failed(&payment_path_for_amount(250), 43);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
SinceEpoch::advance(Duration::from_secs(10));
- assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage), 365);
+ assert_eq!(deserialized_scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 365);
}
#[test]
// 50k sat reserve).
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 950_000_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 4375);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 4375);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2739);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 2739);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 2_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2236);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 2236);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 3_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1983);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1983);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 4_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1637);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1637);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 5_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1606);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1606);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 6_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1331);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1331);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_450_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1387);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1387);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 7_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1379);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1379);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 8_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1363);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1363);
let usage = ChannelUsage {
effective_capacity: EffectiveCapacity::Total { capacity_msat: 9_950_000_000, htlc_maximum_msat: 1_000 }, ..usage
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 1355);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 1355);
}
#[test]
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
};
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 58);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 58);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
- anti_probing_penalty_msat: 0, ..ProbabilisticScoringParameters::zero_penalty()
+ anti_probing_penalty_msat: 0, ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 558);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
base_penalty_msat: 500, liquidity_penalty_multiplier_msat: 1_000,
base_penalty_amount_multiplier_msat: (1 << 30),
- anti_probing_penalty_msat: 0, ..ProbabilisticScoringParameters::zero_penalty()
+ anti_probing_penalty_msat: 0, ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 558 + 128);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 558 + 128);
}
#[test]
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
};
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
liquidity_penalty_amount_multiplier_msat: 0,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
liquidity_penalty_amount_multiplier_msat: 256,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 337);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 337);
}
#[test]
effective_capacity: EffectiveCapacity::Infinite,
};
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 40_000,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 80_000);
+ let decay_params = ProbabilisticScoringDecayParameters::zero_penalty();
+ let scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 80_000);
}
#[test]
fn accounts_for_inflight_htlc_usage() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
considered_impossible_penalty_msat: u64::max_value(),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_000, htlc_maximum_msat: 1_000 },
};
- assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_ne!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
let usage = ChannelUsage { inflight_htlc_msat: 251, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
}
#[test]
fn removes_uncertainity_when_exact_liquidity_known() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
- let scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
+ let params = ProbabilisticScoringFeeParameters::default();
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::ExactLiquidity { liquidity_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), base_penalty_msat);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), base_penalty_msat);
let usage = ChannelUsage { amount_msat: 1_000, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), base_penalty_msat);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), base_penalty_msat);
let usage = ChannelUsage { amount_msat: 1_001, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), u64::max_value());
}
#[test]
fn remembers_historical_failures() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
- liquidity_offset_half_life: Duration::from_secs(60 * 60),
+ let params = ProbabilisticScoringFeeParameters {
historical_liquidity_penalty_multiplier_msat: 1024,
historical_liquidity_penalty_amount_multiplier_msat: 1024,
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
+ };
+ let decay_params = ProbabilisticScoringDecayParameters {
+ liquidity_offset_half_life: Duration::from_secs(60 * 60),
historical_no_updates_half_life: Duration::from_secs(10),
- ..ProbabilisticScoringParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
};
// With no historical data the normal liquidity penalty calculation is used.
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 47);
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
None);
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2048);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 2048);
// The "it failed" increment is 32, where the probability should lie fully in the first
// octile.
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
// Even after we tell the scorer we definitely have enough available liquidity, it will
// still remember that there was some failure in the past, and assign a non-0 penalty.
scorer.payment_path_failed(&payment_path_for_amount(1000), 43);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 198);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 198);
// The first octile should be decayed just slightly and the last octile has a new point.
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
Some(([31, 0, 0, 0, 0, 0, 0, 32], [31, 0, 0, 0, 0, 0, 0, 32])));
// Advance the time forward 16 half-lives (which the docs claim will ensure all data is
// gone), and check that we're back to where we started.
SinceEpoch::advance(Duration::from_secs(10 * 16));
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 47);
// Once fully decayed we still have data, but its all-0s. In the future we may remove the
// data entirely instead.
assert_eq!(scorer.historical_estimated_channel_liquidity_probabilities(42, &target),
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_024 },
};
scorer.payment_path_failed(&payment_path_for_amount(1), 42);
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 409);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 409);
let usage = ChannelUsage {
amount_msat: 1,
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::MaximumHTLC { amount_msat: 0 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &target, &source, usage), 2048);
+ assert_eq!(scorer.channel_penalty_msat(42, &target, &source, usage, ¶ms), 2048);
// Advance to decay all liquidity offsets to zero.
SinceEpoch::advance(Duration::from_secs(60 * 60 * 10));
let network_graph = network_graph(&logger);
let source = source_node_id();
let target = target_node_id();
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
anti_probing_penalty_msat: 500,
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let scorer = ProbabilisticScorer::new(ProbabilisticScoringDecayParameters::default(), &network_graph, &logger);
// Check we receive no penalty for a low htlc_maximum_msat.
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
// Check we receive anti-probing penalty for htlc_maximum_msat == channel_capacity.
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 1_024_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 500);
// Check we receive anti-probing penalty for htlc_maximum_msat == channel_capacity/2.
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 512_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 500);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 500);
// Check we receive no anti-probing penalty for htlc_maximum_msat == channel_capacity/2 - 1.
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: 511_999 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 0);
}
#[test]
// Make sure we'll account for a blinded path's final_value_msat in scoring
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters {
+ let params = ProbabilisticScoringFeeParameters {
liquidity_penalty_multiplier_msat: 1_000,
- liquidity_offset_half_life: Duration::from_secs(10),
- ..ProbabilisticScoringParameters::zero_penalty()
+ ..ProbabilisticScoringFeeParameters::zero_penalty()
};
- let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
+ let decay_params = ProbabilisticScoringDecayParameters::default();
+ let mut scorer = ProbabilisticScorer::new(decay_params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();
let usage = ChannelUsage {
inflight_htlc_msat: 0,
effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: 1_000 },
};
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 300);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage, ¶ms), 300);
let mut path = payment_path_for_amount(768);
let recipient_hop = path.hops.pop().unwrap();
scorer.payment_path_failed(&path, 43);
let liquidity = scorer.channel_liquidities.get(&42).unwrap()
- .as_directed(&source, &target, 0, 1_000, &scorer.params);
+ .as_directed(&source, &target, 0, 1_000, decay_params);
assert_eq!(liquidity.min_liquidity_msat(), 256);
assert_eq!(liquidity.max_liquidity_msat(), 768);
}