X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Frouting%2Frouter.rs;h=b01d853be334cf3635d7f116ba0b878d8648ac43;hb=63ebaccca3c284c28f24537c2c0c034f9cc9c3c4;hp=f79da5ee9ec2d5b4340837cd486b1f59678c74b7;hpb=db81c650baf2faa3a551bab216981ac84149176a;p=rust-lightning diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs index f79da5ee..b01d853b 100644 --- a/lightning/src/routing/router.rs +++ b/lightning/src/routing/router.rs @@ -10,59 +10,58 @@ //! The router finds paths within a [`NetworkGraph`] for a payment. use bitcoin::secp256k1::{PublicKey, Secp256k1, self}; -use bitcoin::hashes::Hash; -use bitcoin::hashes::sha256::Hash as Sha256; use crate::blinded_path::{BlindedHop, BlindedPath}; use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, PaymentConstraints, PaymentRelay, ReceiveTlvs}; use crate::ln::PaymentHash; -use crate::ln::channelmanager::{ChannelDetails, PaymentId}; +use crate::ln::channelmanager::{ChannelDetails, PaymentId, MIN_FINAL_CLTV_EXPIRY_DELTA}; use crate::ln::features::{BlindedHopFeatures, Bolt11InvoiceFeatures, Bolt12InvoiceFeatures, ChannelFeatures, NodeFeatures}; use crate::ln::msgs::{DecodeError, ErrorAction, LightningError, MAX_VALUE_MSAT}; use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice}; -use crate::onion_message::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath}; +use crate::onion_message::messenger::{DefaultMessageRouter, Destination, MessageRouter, OnionMessagePath}; use crate::routing::gossip::{DirectedChannelInfo, EffectiveCapacity, ReadOnlyNetworkGraph, NetworkGraph, NodeId, RoutingFees}; use crate::routing::scoring::{ChannelUsage, LockableScore, ScoreLookUp}; use crate::sign::EntropySource; use crate::util::ser::{Writeable, Readable, ReadableArgs, Writer}; use crate::util::logger::{Level, Logger}; -use crate::util::chacha20::ChaCha20; +use crate::crypto::chacha20::ChaCha20; use crate::io; use crate::prelude::*; -use crate::sync::Mutex; use alloc::collections::BinaryHeap; use core::{cmp, fmt}; use core::ops::Deref; /// A [`Router`] implemented using [`find_route`]. -pub struct DefaultRouter> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> where +pub struct DefaultRouter> + Clone, L: Deref, ES: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> where L::Target: Logger, S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>, + ES::Target: EntropySource, { network_graph: G, logger: L, - random_seed_bytes: Mutex<[u8; 32]>, + entropy_source: ES, scorer: S, score_params: SP, - message_router: DefaultMessageRouter, + message_router: DefaultMessageRouter, } -impl> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> DefaultRouter where +impl> + Clone, L: Deref, ES: Deref + Clone, S: Deref, SP: Sized, Sc: ScoreLookUp> DefaultRouter where L::Target: Logger, S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>, + ES::Target: EntropySource, { /// Creates a new router. - 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); - let message_router = DefaultMessageRouter::new(network_graph.clone()); - Self { network_graph, logger, random_seed_bytes, scorer, score_params, message_router } + pub fn new(network_graph: G, logger: L, entropy_source: ES, scorer: S, score_params: SP) -> Self { + let message_router = DefaultMessageRouter::new(network_graph.clone(), entropy_source.clone()); + Self { network_graph, logger, entropy_source, scorer, score_params, message_router } } } -impl> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> Router for DefaultRouter where +impl> + Clone, L: Deref, ES: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> Router for DefaultRouter where L::Target: Logger, S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>, + ES::Target: EntropySource, { fn find_route( &self, @@ -71,11 +70,7 @@ impl> + Clone, L: Deref, S: Deref, SP: Sized, first_hops: Option<&[&ChannelDetails]>, inflight_htlcs: InFlightHtlcs ) -> Result { - let random_seed_bytes = { - let mut locked_random_seed_bytes = self.random_seed_bytes.lock().unwrap(); - *locked_random_seed_bytes = Sha256::hash(&*locked_random_seed_bytes).to_byte_array(); - *locked_random_seed_bytes - }; + let random_seed_bytes = self.entropy_source.get_secure_random_bytes(); find_route( payer, params, &self.network_graph, first_hops, &*self.logger, &ScorerAccountingForInFlightHtlcs::new(self.scorer.read_lock(), &inflight_htlcs), @@ -85,10 +80,10 @@ impl> + Clone, L: Deref, S: Deref, SP: Sized, } fn create_blinded_payment_paths< - ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification - >( + T: secp256k1::Signing + secp256k1::Verification + > ( &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, - amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1 + amount_msats: u64, secp_ctx: &Secp256k1 ) -> Result, ()> { // Limit the number of blinded paths that are computed. const MAX_PAYMENT_PATHS: usize = 3; @@ -114,19 +109,14 @@ impl> + Clone, L: Deref, S: Deref, SP: Sized, None => return None, }; let payment_relay: PaymentRelay = match details.counterparty.forwarding_info { - Some(forwarding_info) => forwarding_info.into(), + Some(forwarding_info) => match forwarding_info.try_into() { + Ok(payment_relay) => payment_relay, + Err(()) => return None, + }, None => return None, }; - // Avoid exposing esoteric CLTV expiry deltas - let cltv_expiry_delta = match payment_relay.cltv_expiry_delta { - 0..=40 => 40u32, - 41..=80 => 80u32, - 81..=144 => 144u32, - 145..=216 => 216u32, - _ => return None, - }; - + let cltv_expiry_delta = payment_relay.cltv_expiry_delta as u32; let payment_constraints = PaymentConstraints { max_cltv_expiry: tlvs.payment_constraints.max_cltv_expiry + cltv_expiry_delta, htlc_minimum_msat: details.inbound_htlc_minimum_msat.unwrap_or(0), @@ -144,7 +134,8 @@ impl> + Clone, L: Deref, S: Deref, SP: Sized, }) .map(|forward_node| { BlindedPath::new_for_payment( - &[forward_node], recipient, tlvs.clone(), u64::MAX, entropy_source, secp_ctx + &[forward_node], recipient, tlvs.clone(), u64::MAX, MIN_FINAL_CLTV_EXPIRY_DELTA, + &*self.entropy_source, secp_ctx ) }) .take(MAX_PAYMENT_PATHS) @@ -154,8 +145,9 @@ impl> + Clone, L: Deref, S: Deref, SP: Sized, Ok(paths) if !paths.is_empty() => Ok(paths), _ => { if network_graph.nodes().contains_key(&NodeId::from_pubkey(&recipient)) { - BlindedPath::one_hop_for_payment(recipient, tlvs, entropy_source, secp_ctx) - .map(|path| vec![path]) + BlindedPath::one_hop_for_payment( + recipient, tlvs, MIN_FINAL_CLTV_EXPIRY_DELTA, &*self.entropy_source, secp_ctx + ).map(|path| vec![path]) } else { Err(()) } @@ -164,9 +156,10 @@ impl> + Clone, L: Deref, S: Deref, SP: Sized, } } -impl< G: Deref> + Clone, L: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> MessageRouter for DefaultRouter where +impl< G: Deref> + Clone, L: Deref, ES: Deref, S: Deref, SP: Sized, Sc: ScoreLookUp> MessageRouter for DefaultRouter where L::Target: Logger, S::Target: for <'a> LockableScore<'a, ScoreLookUp = Sc>, + ES::Target: EntropySource, { fn find_path( &self, sender: PublicKey, peers: Vec, destination: Destination @@ -175,12 +168,11 @@ impl< G: Deref> + Clone, L: Deref, S: Deref, SP: Sized, } fn create_blinded_paths< - ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification - >( - &self, recipient: PublicKey, peers: Vec, entropy_source: &ES, - secp_ctx: &Secp256k1 + T: secp256k1::Signing + secp256k1::Verification + > ( + &self, recipient: PublicKey, peers: Vec, secp_ctx: &Secp256k1, ) -> Result, ()> { - self.message_router.create_blinded_paths(recipient, peers, entropy_source, secp_ctx) + self.message_router.create_blinded_paths(recipient, peers, secp_ctx) } } @@ -214,10 +206,10 @@ pub trait Router: MessageRouter { /// are assumed to be with the `recipient`'s peers. The payment secret and any constraints are /// given in `tlvs`. fn create_blinded_payment_paths< - ES: EntropySource + ?Sized, T: secp256k1::Signing + secp256k1::Verification - >( + T: secp256k1::Signing + secp256k1::Verification + > ( &self, recipient: PublicKey, first_hops: Vec, tlvs: ReceiveTlvs, - amount_msats: u64, entropy_source: &ES, secp_ctx: &Secp256k1 + amount_msats: u64, secp_ctx: &Secp256k1 ) -> Result, ()>; } @@ -282,7 +274,7 @@ pub struct InFlightHtlcs( impl InFlightHtlcs { /// Constructs an empty `InFlightHtlcs`. - pub fn new() -> Self { InFlightHtlcs(HashMap::new()) } + pub fn new() -> Self { InFlightHtlcs(new_hash_map()) } /// Takes in a path with payer's node id and adds the path's details to `InFlightHtlcs`. pub fn process_path(&mut self, path: &Path, payer_node_id: PublicKey) { @@ -513,20 +505,20 @@ impl Writeable for Route { write_ver_prefix!(writer, SERIALIZATION_VERSION, MIN_SERIALIZATION_VERSION); (self.paths.len() as u64).write(writer)?; let mut blinded_tails = Vec::new(); - for path in self.paths.iter() { + for (idx, path) in self.paths.iter().enumerate() { (path.hops.len() as u8).write(writer)?; - for (idx, hop) in path.hops.iter().enumerate() { + for hop in path.hops.iter() { hop.write(writer)?; - if let Some(blinded_tail) = &path.blinded_tail { - if blinded_tails.is_empty() { - blinded_tails = Vec::with_capacity(path.hops.len()); - for _ in 0..idx { - blinded_tails.push(None); - } - } - blinded_tails.push(Some(blinded_tail)); - } else if !blinded_tails.is_empty() { blinded_tails.push(None); } } + if let Some(blinded_tail) = &path.blinded_tail { + if blinded_tails.is_empty() { + blinded_tails = Vec::with_capacity(path.hops.len()); + for _ in 0..idx { + blinded_tails.push(None); + } + } + blinded_tails.push(Some(blinded_tail)); + } else if !blinded_tails.is_empty() { blinded_tails.push(None); } } write_tlv_fields!(writer, { // For compatibility with LDK versions prior to 0.0.117, we take the individual @@ -534,7 +526,7 @@ impl Writeable for Route { (1, self.route_params.as_ref().map(|p| &p.payment_params), option), (2, blinded_tails, optional_vec), (3, self.route_params.as_ref().map(|p| p.final_value_msat), option), - (5, self.route_params.as_ref().map(|p| p.max_total_routing_fee_msat), option), + (5, self.route_params.as_ref().and_then(|p| p.max_total_routing_fee_msat), option), }); Ok(()) } @@ -711,6 +703,11 @@ pub struct PaymentParameters { /// payment to fail. Future attempts for the same payment shouldn't be relayed through any of /// these SCIDs. pub previously_failed_channels: Vec, + + /// A list of indices corresponding to blinded paths in [`Payee::Blinded::route_hints`] which this + /// payment was previously attempted over and which caused the payment to fail. Future attempts + /// for the same payment shouldn't be relayed through any of these blinded paths. + pub previously_failed_blinded_path_idxs: Vec, } impl Writeable for PaymentParameters { @@ -732,6 +729,7 @@ impl Writeable for PaymentParameters { (7, self.previously_failed_channels, required_vec), (8, *blinded_hints, optional_vec), (9, self.payee.final_cltv_expiry_delta(), option), + (11, self.previously_failed_blinded_path_idxs, required_vec), }); Ok(()) } @@ -750,6 +748,7 @@ impl ReadableArgs for PaymentParameters { (7, previously_failed_channels, optional_vec), (8, blinded_route_hints, optional_vec), (9, final_cltv_expiry_delta, (default_value, default_final_cltv_expiry_delta)), + (11, previously_failed_blinded_path_idxs, optional_vec), }); let blinded_route_hints = blinded_route_hints.unwrap_or(vec![]); let payee = if blinded_route_hints.len() != 0 { @@ -773,6 +772,7 @@ impl ReadableArgs for PaymentParameters { max_channel_saturation_power_of_half: _init_tlv_based_struct_field!(max_channel_saturation_power_of_half, (default_value, unused)), expiry_time, previously_failed_channels: previously_failed_channels.unwrap_or(Vec::new()), + previously_failed_blinded_path_idxs: previously_failed_blinded_path_idxs.unwrap_or(Vec::new()), }) } } @@ -791,6 +791,7 @@ impl PaymentParameters { max_path_count: DEFAULT_MAX_PATH_COUNT, max_channel_saturation_power_of_half: DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF, previously_failed_channels: Vec::new(), + previously_failed_blinded_path_idxs: Vec::new(), } } @@ -829,6 +830,7 @@ impl PaymentParameters { max_path_count: DEFAULT_MAX_PATH_COUNT, max_channel_saturation_power_of_half: DEFAULT_MAX_CHANNEL_SATURATION_POW_HALF, previously_failed_channels: Vec::new(), + previously_failed_blinded_path_idxs: Vec::new(), } } @@ -904,6 +906,19 @@ impl PaymentParameters { pub fn with_max_channel_saturation_power_of_half(self, max_channel_saturation_power_of_half: u8) -> Self { Self { max_channel_saturation_power_of_half, ..self } } + + pub(crate) fn insert_previously_failed_blinded_path(&mut self, failed_blinded_tail: &BlindedTail) { + let mut found_blinded_tail = false; + for (idx, (_, path)) in self.payee.blinded_route_hints().iter().enumerate() { + if failed_blinded_tail.hops == path.blinded_hops && + failed_blinded_tail.blinding_point == path.blinding_point + { + self.previously_failed_blinded_path_idxs.push(idx as u64); + found_blinded_tail = true; + } + } + debug_assert!(found_blinded_tail); + } } /// The recipient of a payment, differing based on whether they've hidden their identity with route @@ -971,7 +986,7 @@ impl Payee { _ => None, } } - fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] { + pub(crate) fn blinded_route_hints(&self) -> &[(BlindedPayInfo, BlindedPath)] { match self { Self::Blinded { route_hints, .. } => &route_hints[..], Self::Clear { .. } => &[] @@ -1128,8 +1143,12 @@ pub struct FirstHopCandidate<'a> { /// has been funded and is able to pay), and accessor methods may panic otherwise. /// /// [`find_route`] validates this prior to constructing a [`CandidateRouteHop`]. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub details: &'a ChannelDetails, /// The node id of the payer, which is also the source side of this candidate route hop. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub payer_node_id: &'a NodeId, } @@ -1138,6 +1157,8 @@ pub struct FirstHopCandidate<'a> { pub struct PublicHopCandidate<'a> { /// Information about the channel, including potentially its capacity and /// direction-specific information. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub info: DirectedChannelInfo<'a>, /// The short channel ID of the channel, i.e. the identifier by which we refer to this /// channel. @@ -1148,8 +1169,12 @@ pub struct PublicHopCandidate<'a> { #[derive(Clone, Debug)] pub struct PrivateHopCandidate<'a> { /// Information about the private hop communicated via BOLT 11. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub hint: &'a RouteHintHop, /// Node id of the next hop in BOLT 11 route hint. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub target_node_id: &'a NodeId } @@ -1158,6 +1183,8 @@ pub struct PrivateHopCandidate<'a> { pub struct BlindedPathCandidate<'a> { /// Information about the blinded path including the fee, HTLC amount limits, and /// cryptographic material required to build an HTLC through the given path. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub hint: &'a (BlindedPayInfo, BlindedPath), /// Index of the hint in the original list of blinded hints. /// @@ -1173,6 +1200,8 @@ pub struct OneHopBlindedPathCandidate<'a> { /// cryptographic material required to build an HTLC terminating with the given path. /// /// Note that the [`BlindedPayInfo`] is ignored here. + /// + /// This is not exported to bindings users as lifetimes are not expressable in most languages. pub hint: &'a (BlindedPayInfo, BlindedPath), /// Index of the hint in the original list of blinded hints. /// @@ -1360,6 +1389,15 @@ impl<'a> CandidateRouteHop<'a> { _ => None, } } + fn blinded_hint_idx(&self) -> Option { + match self { + Self::Blinded(BlindedPathCandidate { hint_idx, .. }) | + Self::OneHopBlinded(OneHopBlindedPathCandidate { hint_idx, .. }) => { + Some(*hint_idx) + }, + _ => None, + } + } /// Returns the source node id of current hop. /// /// Source node id refers to the node forwarding the HTLC through this hop. @@ -1825,17 +1863,17 @@ where L::Target: Logger { } }, Payee::Blinded { route_hints, .. } => { - if route_hints.iter().all(|(_, path)| &path.introduction_node_id == our_node_pubkey) { + if route_hints.iter().all(|(_, path)| path.public_introduction_node_id(network_graph) == Some(&our_node_id)) { return Err(LightningError{err: "Cannot generate a route to blinded paths if we are the introduction node to all of them".to_owned(), action: ErrorAction::IgnoreError}); } for (_, blinded_path) in route_hints.iter() { if blinded_path.blinded_hops.len() == 0 { return Err(LightningError{err: "0-hop blinded path provided".to_owned(), action: ErrorAction::IgnoreError}); - } else if &blinded_path.introduction_node_id == our_node_pubkey { + } else if blinded_path.public_introduction_node_id(network_graph) == Some(&our_node_id) { log_info!(logger, "Got blinded path with ourselves as the introduction node, ignoring"); } else if blinded_path.blinded_hops.len() == 1 && route_hints.iter().any( |(_, p)| p.blinded_hops.len() == 1 - && p.introduction_node_id != blinded_path.introduction_node_id) + && p.public_introduction_node_id(network_graph) != blinded_path.public_introduction_node_id(network_graph)) { return Err(LightningError{err: format!("1-hop blinded paths must all have matching introduction node ids"), action: ErrorAction::IgnoreError}); } @@ -1935,7 +1973,7 @@ where L::Target: Logger { // inserting first hops suggested by the caller as targets. // Our search will then attempt to reach them while traversing from the payee node. let mut first_hop_targets: HashMap<_, Vec<&ChannelDetails>> = - HashMap::with_capacity(if first_hops.is_some() { first_hops.as_ref().unwrap().len() } else { 0 }); + hash_map_with_capacity(if first_hops.is_some() { first_hops.as_ref().unwrap().len() } else { 0 }); if let Some(hops) = first_hops { for chan in hops { if chan.get_outbound_payment_scid().is_none() { @@ -1954,7 +1992,7 @@ where L::Target: Logger { } } - let mut private_hop_key_cache = HashMap::with_capacity( + let mut private_hop_key_cache = hash_map_with_capacity( payment_params.payee.unblinded_route_hints().iter().map(|path| path.0.len()).sum() ); @@ -1975,7 +2013,7 @@ where L::Target: Logger { // Map from node_id to information about the best current path to that node, including feerate // information. - let mut dist: HashMap = HashMap::with_capacity(network_nodes.len()); + let mut dist: HashMap = hash_map_with_capacity(network_nodes.len()); // During routing, if we ignore a path due to an htlc_minimum_msat limit, we set this, // indicating that we may wish to try again with a higher value, potentially paying to meet an @@ -2016,7 +2054,7 @@ where L::Target: Logger { // is used. Hence, liquidity used in one direction will not offset any used in the opposite // direction. let mut used_liquidities: HashMap = - HashMap::with_capacity(network_nodes.len()); + hash_map_with_capacity(network_nodes.len()); // Keeping track of how much value we already collected across other paths. Helps to decide // when we want to stop looking for new paths. @@ -2111,8 +2149,15 @@ where L::Target: Logger { (amount_to_transfer_over_msat < $next_hops_path_htlc_minimum_msat && recommended_value_msat >= $next_hops_path_htlc_minimum_msat)); - let payment_failed_on_this_channel = scid_opt.map_or(false, - |scid| payment_params.previously_failed_channels.contains(&scid)); + let payment_failed_on_this_channel = match scid_opt { + Some(scid) => payment_params.previously_failed_channels.contains(&scid), + None => match $candidate.blinded_hint_idx() { + Some(idx) => { + payment_params.previously_failed_blinded_path_idxs.contains(&(idx as u64)) + }, + None => false, + }, + }; let (should_log_candidate, first_hop_details) = match $candidate { CandidateRouteHop::FirstHop(hop) => (true, Some(hop.details)), @@ -2532,9 +2577,9 @@ where L::Target: Logger { let mut aggregate_path_contribution_msat = path_value_msat; for (idx, (hop, prev_hop_id)) in hop_iter.zip(prev_hop_iter).enumerate() { - let target = private_hop_key_cache.get(&prev_hop_id).unwrap(); + let target = private_hop_key_cache.get(prev_hop_id).unwrap(); - if let Some(first_channels) = first_hop_targets.get(&target) { + if let Some(first_channels) = first_hop_targets.get(target) { if first_channels.iter().any(|d| d.outbound_scid_alias == Some(hop.short_channel_id)) { log_trace!(logger, "Ignoring route hint with SCID {} (and any previous) due to it being a direct channel of ours.", hop.short_channel_id); @@ -2544,7 +2589,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.as_directed_to(target)) .map(|(info, _)| CandidateRouteHop::PublicHop(PublicHopCandidate { info, short_channel_id: hop.short_channel_id, @@ -2585,7 +2630,7 @@ where L::Target: Logger { .saturating_add(1); // Searching for a direct channel between last checked hop and first_hop_targets - if let Some(first_channels) = first_hop_targets.get_mut(&target) { + if let Some(first_channels) = first_hop_targets.get_mut(target) { sort_first_hop_channels(first_channels, &used_liquidities, recommended_value_msat, our_node_pubkey); for details in first_channels { @@ -2706,7 +2751,7 @@ where L::Target: Logger { } } - // Means we succesfully traversed from the payer to the payee, now + // Means we successfully traversed from the payer to the payee, now // save this path for the payment route. Also, update the liquidity // remaining on the used hops, so that we take them into account // while looking for more paths. @@ -3195,7 +3240,7 @@ mod tests { use crate::offers::invoice::BlindedPayInfo; use crate::util::config::UserConfig; use crate::util::test_utils as ln_test_utils; - use crate::util::chacha20::ChaCha20; + use crate::crypto::chacha20::ChaCha20; use crate::util::ser::{Readable, Writeable}; #[cfg(c_bindings)] use crate::util::ser::Writer; @@ -3214,8 +3259,6 @@ mod tests { use crate::prelude::*; use crate::sync::Arc; - use core::convert::TryInto; - fn get_channel_details(short_channel_id: Option, node_id: PublicKey, features: InitFeatures, outbound_capacity_msat: u64) -> channelmanager::ChannelDetails { channelmanager::ChannelDetails { @@ -3251,6 +3294,8 @@ mod tests { config: None, feerate_sat_per_1000_weight: None, channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown), + pending_inbound_htlcs: Vec::new(), + pending_outbound_htlcs: Vec::new(), } } @@ -5256,10 +5301,15 @@ mod tests { if let Some(bt) = &path.blinded_tail { assert_eq!(path.hops.len() + if bt.hops.len() == 1 { 0 } else { 1 }, 2); if bt.hops.len() > 1 { - assert_eq!(path.hops.last().unwrap().pubkey, + let network_graph = network_graph.read_only(); + assert_eq!( + NodeId::from_pubkey(&path.hops.last().unwrap().pubkey), payment_params.payee.blinded_route_hints().iter() .find(|(p, _)| p.htlc_maximum_msat == path.final_value_msat()) - .map(|(_, p)| p.introduction_node_id).unwrap()); + .and_then(|(_, p)| p.public_introduction_node_id(&network_graph)) + .copied() + .unwrap() + ); } else { assert_eq!(path.hops.last().unwrap().pubkey, nodes[2]); } @@ -6902,7 +6952,7 @@ mod tests { (route.paths[1].hops[1].short_channel_id == 4 && route.paths[0].hops[1].short_channel_id == 13)); } - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] pub(super) fn random_init_seed() -> u64 { // Because the default HashMap in std pulls OS randomness, we can use it as a (bad) RNG. use core::hash::{BuildHasher, Hasher}; @@ -6912,7 +6962,7 @@ mod tests { } #[test] - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] fn generate_routes() { use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters}; @@ -6933,7 +6983,7 @@ mod tests { } #[test] - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] fn generate_routes_mpp() { use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters}; @@ -6954,7 +7004,7 @@ mod tests { } #[test] - #[cfg(not(feature = "no-std"))] + #[cfg(feature = "std")] fn generate_large_mpp_routes() { use crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters}; @@ -7387,7 +7437,10 @@ mod tests { assert_eq!(tail.final_value_msat, 1001); let final_hop = route.paths[0].hops.last().unwrap(); - assert_eq!(final_hop.pubkey, blinded_path.introduction_node_id); + assert_eq!( + NodeId::from_pubkey(&final_hop.pubkey), + *blinded_path.public_introduction_node_id(&network_graph).unwrap() + ); if tail.hops.len() > 1 { assert_eq!(final_hop.fee_msat, blinded_payinfo.fee_base_msat as u64 + blinded_payinfo.fee_proportional_millionths as u64 * tail.final_value_msat / 1000000); @@ -7803,7 +7856,7 @@ mod tests { fn do_min_htlc_overpay_violates_max_htlc(blinded_payee: bool) { // Test that if overpaying to meet a later hop's min_htlc and causes us to violate an earlier // hop's max_htlc, we don't consider that candidate hop valid. Previously we would add this hop - // to `targets` and build an invalid path with it, and subsquently hit a debug panic asserting + // to `targets` and build an invalid path with it, and subsequently hit a debug panic asserting // that the used liquidity for a hop was less than its available liquidity limit. let secp_ctx = Secp256k1::new(); let logger = Arc::new(ln_test_utils::TestLogger::new()); @@ -8290,24 +8343,21 @@ mod tests { } } -#[cfg(all(any(test, ldk_bench), not(feature = "no-std")))] +#[cfg(all(any(test, ldk_bench), feature = "std"))] pub(crate) mod bench_utils { use super::*; use std::fs::File; use std::time::Duration; use bitcoin::hashes::Hash; - use bitcoin::secp256k1::{PublicKey, Secp256k1, SecretKey}; + use bitcoin::secp256k1::SecretKey; use crate::chain::transaction::OutPoint; use crate::routing::scoring::ScoreUpdate; - use crate::sign::{EntropySource, KeysManager}; + use crate::sign::KeysManager; use crate::ln::ChannelId; - use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails}; - use crate::ln::features::Bolt11InvoiceFeatures; - use crate::routing::gossip::NetworkGraph; + use crate::ln::channelmanager::{self, ChannelCounterparty}; use crate::util::config::UserConfig; - use crate::util::ser::ReadableArgs; use crate::util::test_utils::TestLogger; /// Tries to open a network graph file, or panics with a URL to fetch it. @@ -8392,6 +8442,8 @@ pub(crate) mod bench_utils { config: None, feerate_sat_per_1000_weight: None, channel_shutdown_state: Some(channelmanager::ChannelShutdownState::NotShuttingDown), + pending_inbound_htlcs: Vec::new(), + pending_outbound_htlcs: Vec::new(), } } @@ -8452,7 +8504,7 @@ pub(crate) mod bench_utils { } break; } - // If we couldn't find a path with a higer amount, reduce and try again. + // If we couldn't find a path with a higher amount, reduce and try again. score_amt /= 100; }