X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=9d3324c7b6454947e84e2981839663a625ede569;hb=384c4dc7753e4b7ac53ea380e52809babd8f0f9b;hp=170ac9c991c43b3f4b079a026bd388801a6ca12d;hpb=d6321e6e11b3e1b11e26617d3bab0b8c21da0b5b;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index 170ac9c9..9d3324c7 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -14,21 +14,64 @@ use bitcoin::secp256k1::PublicKey; -use ln::channelmanager::ChannelDetails; -use ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures}; -use ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT}; -use routing::gossip::{DirectedChannelInfoWithUpdate, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees}; -use routing::scoring::{ChannelUsage, Score}; -use util::ser::{Writeable, Readable, Writer}; -use util::logger::{Level, Logger}; -use util::chacha20::ChaCha20; - -use io; -use prelude::*; +use crate::ln::channelmanager::ChannelDetails; +use crate::ln::features::{ChannelFeatures, InvoiceFeatures, NodeFeatures}; +use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT}; +use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees}; +use crate::routing::scoring::{ChannelUsage, Score}; +use crate::util::ser::{Writeable, Readable, Writer}; +use crate::util::logger::{Level, Logger}; +use crate::util::chacha20::ChaCha20; + +use crate::io; +use crate::prelude::*; use alloc::collections::BinaryHeap; use core::cmp; use core::ops::Deref; +/// A trait defining behavior for routing a payment. +pub trait Router { + /// Finds a [`Route`] between `payer` and `payee` for a payment with the given values. + fn find_route( + &self, payer: &PublicKey, route_params: &RouteParameters, + first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs + ) -> Result; +} + +/// A map with liquidity value (in msat) keyed by a short channel id and the direction the HTLC +/// is traveling in. The direction boolean is determined by checking if the HTLC source's public +/// key is less than its destination. See [`InFlightHtlcs::used_liquidity_msat`] for more +/// details. +#[cfg(not(any(test, feature = "_test_utils")))] +pub struct InFlightHtlcs(HashMap<(u64, bool), u64>); +#[cfg(any(test, feature = "_test_utils"))] +pub struct InFlightHtlcs(pub HashMap<(u64, bool), u64>); + +impl InFlightHtlcs { + /// Create a new `InFlightHtlcs` via a mapping from: + /// (short_channel_id, source_pubkey < target_pubkey) -> used_liquidity_msat + pub fn new(inflight_map: HashMap<(u64, bool), u64>) -> Self { + InFlightHtlcs(inflight_map) + } + + /// Returns liquidity in msat given the public key of the HTLC source, target, and short channel + /// id. + pub fn used_liquidity_msat(&self, source: &NodeId, target: &NodeId, channel_scid: u64) -> Option { + self.0.get(&(channel_scid, source < target)).map(|v| *v) + } +} + +impl Writeable for InFlightHtlcs { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { self.0.write(writer) } +} + +impl Readable for InFlightHtlcs { + fn read(reader: &mut R) -> Result { + let infight_map: HashMap<(u64, bool), u64> = Readable::read(reader)?; + Ok(Self(infight_map)) + } +} + /// A hop in a route #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct RouteHop { @@ -112,7 +155,7 @@ const SERIALIZATION_VERSION: u8 = 1; const MIN_SERIALIZATION_VERSION: u8 = 1; impl Writeable for Route { - fn write(&self, writer: &mut W) -> Result<(), io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); (self.paths.len() as u64).write(writer)?; for hops in self.paths.iter() { @@ -326,7 +369,7 @@ impl PaymentParameters { pub struct RouteHint(pub Vec); impl Writeable for RouteHint { - fn write(&self, writer: &mut W) -> Result<(), io::Error> { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { (self.0.len() as u64).write(writer)?; for hop in self.0.iter() { hop.write(writer)?; @@ -421,7 +464,7 @@ enum CandidateRouteHop<'a> { }, /// A hop found in the [`ReadOnlyNetworkGraph`], where the channel capacity may be unknown. PublicHop { - info: DirectedChannelInfoWithUpdate<'a>, + info: DirectedChannelInfo<'a>, short_channel_id: u64, }, /// A hop to the payee found in the payment invoice, though not necessarily a direct channel. @@ -494,10 +537,8 @@ fn max_htlc_from_capacity(capacity: EffectiveCapacity, max_channel_saturation_po EffectiveCapacity::Unknown => EffectiveCapacity::Unknown.as_msat(), EffectiveCapacity::MaximumHTLC { amount_msat } => amount_msat.checked_shr(saturation_shift).unwrap_or(0), - EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: None } => - capacity_msat.checked_shr(saturation_shift).unwrap_or(0), - EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat: Some(htlc_max) } => - cmp::min(capacity_msat.checked_shr(saturation_shift).unwrap_or(0), htlc_max), + EffectiveCapacity::Total { capacity_msat, htlc_maximum_msat } => + cmp::min(capacity_msat.checked_shr(saturation_shift).unwrap_or(0), htlc_maximum_msat), } } @@ -1276,13 +1317,11 @@ where L::Target: Logger { for chan_id in $node.channels.iter() { let chan = network_channels.get(chan_id).unwrap(); if !chan.features.requires_unknown_bits() { - let (directed_channel, source) = - chan.as_directed_to(&$node_id).expect("inconsistent NetworkGraph"); - if first_hops.is_none() || *source != our_node_id { - if let Some(direction) = directed_channel.direction() { - if direction.enabled { + if let Some((directed_channel, source)) = chan.as_directed_to(&$node_id) { + if first_hops.is_none() || *source != our_node_id { + if directed_channel.direction().enabled { let candidate = CandidateRouteHop::PublicHop { - info: directed_channel.with_update().unwrap(), + info: directed_channel, short_channel_id: *chan_id, }; add_entry!(candidate, *source, $node_id, @@ -1367,8 +1406,7 @@ where L::Target: Logger { let candidate = network_channels .get(&hop.short_channel_id) .and_then(|channel| channel.as_directed_to(&target)) - .and_then(|(channel, _)| channel.with_update()) - .map(|info| CandidateRouteHop::PublicHop { + .map(|(info, _)| CandidateRouteHop::PublicHop { info, short_channel_id: hop.short_channel_id, }) @@ -1816,10 +1854,8 @@ fn add_random_cltv_offset(route: &mut Route, payment_params: &PaymentParameters, random_channel.as_directed_from(&cur_node_id).map(|(dir_info, next_id)| { if !nodes_to_avoid.iter().any(|x| x == next_id) { nodes_to_avoid[random_hop] = *next_id; - dir_info.direction().map(|channel_update_info| { - random_hop_offset = channel_update_info.cltv_expiry_delta.into(); - cur_hop = Some(*next_id); - }); + random_hop_offset = dir_info.direction().cltv_expiry_delta.into(); + cur_hop = Some(*next_id); } }); } @@ -1932,21 +1968,21 @@ fn build_route_from_hops_internal( #[cfg(test)] mod tests { - use routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity}; - use routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features, + use crate::routing::gossip::{NetworkGraph, P2PGossipSync, NodeId, EffectiveCapacity}; + use crate::routing::router::{get_route, build_route_from_hops_internal, add_random_cltv_offset, default_node_features, PaymentParameters, Route, RouteHint, RouteHintHop, RouteHop, RoutingFees, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA, MAX_PATH_LENGTH_ESTIMATE}; - use routing::scoring::{ChannelUsage, Score, ProbabilisticScorer, ProbabilisticScoringParameters}; - use routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel}; - use chain::transaction::OutPoint; - use chain::keysinterface::KeysInterface; - use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; - use ln::msgs::{ErrorAction, LightningError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; - use ln::channelmanager; - use util::test_utils as ln_test_utils; - use util::chacha20::ChaCha20; + use crate::routing::scoring::{ChannelUsage, Score, ProbabilisticScorer, ProbabilisticScoringParameters}; + 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::chain::keysinterface::KeysInterface; + use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures}; + use crate::ln::msgs::{ErrorAction, LightningError, UnsignedChannelUpdate, MAX_VALUE_MSAT}; + use crate::ln::channelmanager; + use crate::util::test_utils as ln_test_utils; + use crate::util::chacha20::ChaCha20; #[cfg(c_bindings)] - use util::ser::{Writeable, Writer}; + use crate::util::ser::{Writeable, Writer}; use bitcoin::hashes::Hash; use bitcoin::network::constants::Network; @@ -1960,8 +1996,8 @@ mod tests { use bitcoin::secp256k1::{PublicKey,SecretKey}; use bitcoin::secp256k1::Secp256k1; - use prelude::*; - use sync::Arc; + use crate::prelude::*; + use crate::sync::Arc; use core::convert::TryInto; @@ -4895,7 +4931,7 @@ mod tests { #[cfg(c_bindings)] impl Writeable for BadChannelScorer { - fn write(&self, _w: &mut W) -> Result<(), ::io::Error> { unimplemented!() } + fn write(&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 { @@ -4914,7 +4950,7 @@ mod tests { #[cfg(c_bindings)] impl Writeable for BadNodeScorer { - fn write(&self, _w: &mut W) -> Result<(), ::io::Error> { unimplemented!() } + fn write(&self, _w: &mut W) -> Result<(), crate::io::Error> { unimplemented!() } } impl Score for BadNodeScorer { @@ -5214,14 +5250,12 @@ mod tests { for channel_id in &cur_node.channels { if let Some(channel_info) = network_channels.get(&channel_id) { if let Some((dir_info, next_id)) = channel_info.as_directed_from(&cur_node_id) { - if let Some(channel_update_info) = dir_info.direction() { - let next_cltv_expiry_delta = channel_update_info.cltv_expiry_delta as u32; - if cur_path_cltv_deltas.iter().sum::() - .saturating_add(next_cltv_expiry_delta) <= observed_cltv_expiry_delta { - let mut new_path_cltv_deltas = cur_path_cltv_deltas.clone(); - new_path_cltv_deltas.push(next_cltv_expiry_delta); - candidates.push_back((*next_id, new_path_cltv_deltas)); - } + let next_cltv_expiry_delta = dir_info.direction().cltv_expiry_delta as u32; + if cur_path_cltv_deltas.iter().sum::() + .saturating_add(next_cltv_expiry_delta) <= observed_cltv_expiry_delta { + let mut new_path_cltv_deltas = cur_path_cltv_deltas.clone(); + new_path_cltv_deltas.push(next_cltv_expiry_delta); + candidates.push_back((*next_id, new_path_cltv_deltas)); } } } @@ -5307,12 +5341,12 @@ mod tests { seed } #[cfg(not(feature = "no-std"))] - use util::ser::ReadableArgs; + use crate::util::ser::ReadableArgs; #[test] #[cfg(not(feature = "no-std"))] fn generate_routes() { - use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters}; + use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters}; let mut d = match super::bench_utils::get_route_file() { Ok(f) => f, @@ -5349,7 +5383,7 @@ mod tests { #[test] #[cfg(not(feature = "no-std"))] fn generate_routes_mpp() { - use routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters}; + use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringParameters}; let mut d = match super::bench_utils::get_route_file() { Ok(f) => f, @@ -5398,7 +5432,7 @@ mod tests { let usage = ChannelUsage { amount_msat: 0, inflight_htlc_msat: 0, - effective_capacity: EffectiveCapacity::Total { capacity_msat: 1_024_000, htlc_maximum_msat: Some(1_000) }, + 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); @@ -5453,14 +5487,14 @@ mod benches { use super::*; use bitcoin::hashes::Hash; use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; - use chain::transaction::OutPoint; - use chain::keysinterface::{KeysManager,KeysInterface}; - use ln::channelmanager::{self, ChannelCounterparty, ChannelDetails}; - use ln::features::{InitFeatures, InvoiceFeatures}; - use routing::gossip::NetworkGraph; - use routing::scoring::{FixedPenaltyScorer, ProbabilisticScorer, ProbabilisticScoringParameters}; - use util::logger::{Logger, Record}; - use util::ser::ReadableArgs; + use crate::chain::transaction::OutPoint; + use crate::chain::keysinterface::{KeysManager,KeysInterface}; + 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::util::logger::{Logger, Record}; + use crate::util::ser::ReadableArgs; use test::Bencher;