///
/// Default value: 250 msat
pub anti_probing_penalty_msat: u64,
+
+ /// This penalty is applied when the amount we're attempting to send over a channel exceeds our
+ /// current estimate of the channel's available liquidity.
+ ///
+ /// Note that in this case all other penalties, including the
+ /// [`liquidity_penalty_multiplier_msat`] and [`amount_penalty_multiplier_msat`]-based
+ /// penalties, as well as the [`base_penalty_msat`] and the [`anti_probing_penalty_msat`], if
+ /// applicable, are still included in the overall penalty.
+ ///
+ /// If you wish to avoid creating paths with such channels entirely, setting this to a value of
+ /// `u64::max_value()` will guarantee that.
+ ///
+ /// Default value: 1_0000_0000_000 msat (1 Bitcoin)
+ ///
+ /// [`liquidity_penalty_multiplier_msat`]: Self::liquidity_penalty_multiplier_msat
+ /// [`amount_penalty_multiplier_msat`]: Self::amount_penalty_multiplier_msat
+ /// [`base_penalty_msat`]: Self::base_penalty_msat
+ /// [`anti_probing_penalty_msat`]: Self::anti_probing_penalty_msat
+ pub considered_impossible_penalty_msat: u64,
}
/// Accounting for channel liquidity balance uncertainty.
amount_penalty_multiplier_msat: 0,
manual_node_penalties: HashMap::new(),
anti_probing_penalty_msat: 0,
+ considered_impossible_penalty_msat: 0,
}
}
amount_penalty_multiplier_msat: 256,
manual_node_penalties: HashMap::new(),
anti_probing_penalty_msat: 250,
+ considered_impossible_penalty_msat: 1_0000_0000_000,
}
}
}
if amount_msat <= min_liquidity_msat {
0
} else if amount_msat >= max_liquidity_msat {
- if amount_msat > max_liquidity_msat {
- u64::max_value()
- } else if max_liquidity_msat != self.capacity_msat {
- // Avoid using the failed channel on retry.
- u64::max_value()
- } else {
- // Equivalent to hitting the else clause below with the amount equal to the
- // effective capacity and without any certainty on the liquidity upper bound.
- let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048;
- self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params)
- }
+ // Equivalent to hitting the else clause below with the amount equal to the effective
+ // capacity and without any certainty on the liquidity upper bound, plus the
+ // impossibility penalty.
+ let negative_log10_times_2048 = NEGATIVE_LOG10_UPPER_BOUND * 2048;
+ self.combined_penalty_msat(amount_msat, negative_log10_times_2048, params)
+ .saturating_add(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);
(2, max_liquidity_offset_msat, required),
(4, duration_since_epoch, required),
});
+ // On rust prior to 1.60 `Instant::duration_since` will panic if time goes backwards.
+ // We write `last_updated` as wallclock time even though its ultimately an `Instant` (which
+ // is a time from a monotonic clock usually represented as an offset against boot time).
+ // Thus, we have to construct an `Instant` by subtracting the difference in wallclock time
+ // from the one that was written. However, because `Instant` can panic if we construct one
+ // in the future, we must handle wallclock time jumping backwards, which we do by simply
+ // using `Instant::now()` in that case.
+ let wall_clock_now = T::duration_since_epoch();
+ let now = T::now();
+ let last_updated = if wall_clock_now > duration_since_epoch {
+ now - (wall_clock_now - duration_since_epoch)
+ } else { now };
Ok(Self {
min_liquidity_offset_msat,
max_liquidity_offset_msat,
- last_updated: T::now() - (T::duration_since_epoch() - duration_since_epoch),
+ last_updated,
})
}
}
use util::time::tests::SinceEpoch;
use ln::features::{ChannelFeatures, NodeFeatures};
- use ln::msgs::{ChannelAnnouncement, ChannelUpdate, OptionalField, UnsignedChannelAnnouncement, UnsignedChannelUpdate};
+ use ln::msgs::{ChannelAnnouncement, ChannelUpdate, UnsignedChannelAnnouncement, UnsignedChannelUpdate};
use routing::gossip::{EffectiveCapacity, NetworkGraph, NodeId};
use routing::router::RouteHop;
use routing::scoring::{ChannelUsage, Score};
flags,
cltv_expiry_delta: 18,
htlc_minimum_msat: 0,
- htlc_maximum_msat: OptionalField::Present(1_000),
+ htlc_maximum_msat: 1_000,
fee_base_msat: 1,
fee_proportional_millionths: 0,
excess_data: Vec::new(),
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
let usage = ChannelUsage { amount_msat: 102_400, ..usage };
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 47);
- let usage = ChannelUsage { amount_msat: 1_024_000, ..usage };
+ let usage = ChannelUsage { amount_msat: 1_023_999, ..usage };
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
let usage = ChannelUsage {
let network_graph = network_graph(&logger);
let params = ProbabilisticScoringParameters {
liquidity_penalty_multiplier_msat: 1_000,
+ considered_impossible_penalty_msat: u64::max_value(),
..ProbabilisticScoringParameters::zero_penalty()
};
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger)
let network_graph = network_graph(&logger);
let params = ProbabilisticScoringParameters {
liquidity_penalty_multiplier_msat: 1_000,
+ considered_impossible_penalty_msat: u64::max_value(),
..ProbabilisticScoringParameters::zero_penalty()
};
let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
let params = ProbabilisticScoringParameters {
liquidity_penalty_multiplier_msat: 1_000,
liquidity_offset_half_life: Duration::from_secs(10),
+ considered_impossible_penalty_msat: u64::max_value(),
..ProbabilisticScoringParameters::zero_penalty()
};
let mut scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
let usage = ChannelUsage {
amount_msat: 0,
inflight_htlc_msat: 0,
- effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_000) },
+ effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024, htlc_maximum_msat: Some(1_024) },
};
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 0);
- let usage = ChannelUsage { amount_msat: 1_024, ..usage };
+ let usage = ChannelUsage { amount_msat: 1_023, ..usage };
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
scorer.payment_path_failed(&payment_path_for_amount(768).iter().collect::<Vec<_>>(), 42);
let usage = ChannelUsage { amount_msat: 1_023, ..usage };
assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 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);
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 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);
let usage = ChannelUsage { amount_msat: 1_024, ..usage };
- assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), 2_000);
+ assert_eq!(scorer.channel_penalty_msat(42, &source, &target, usage), u64::max_value());
}
#[test]
let params = ProbabilisticScoringParameters {
liquidity_penalty_multiplier_msat: 1_000,
liquidity_offset_half_life: Duration::from_secs(10),
+ considered_impossible_penalty_msat: u64::max_value(),
..ProbabilisticScoringParameters::zero_penalty()
};
let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
let params = ProbabilisticScoringParameters {
liquidity_penalty_multiplier_msat: 1_000,
liquidity_offset_half_life: Duration::from_secs(10),
+ considered_impossible_penalty_msat: u64::max_value(),
..ProbabilisticScoringParameters::zero_penalty()
};
let mut scorer = ProbabilisticScorer::new(params.clone(), &network_graph, &logger);
fn accounts_for_inflight_htlc_usage() {
let logger = TestLogger::new();
let network_graph = network_graph(&logger);
- let params = ProbabilisticScoringParameters::default();
+ let params = ProbabilisticScoringParameters {
+ considered_impossible_penalty_msat: u64::max_value(),
+ ..ProbabilisticScoringParameters::zero_penalty()
+ };
let scorer = ProbabilisticScorer::new(params, &network_graph, &logger);
let source = source_node_id();
let target = target_node_id();