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::*;
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
(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(())
}
/// payment to fail. Future attempts for the same payment shouldn't be relayed through any of
/// these SCIDs.
pub previously_failed_channels: Vec<u64>,
+
+ /// 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<u64>,
}
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(())
}
(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 {
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()),
})
}
}
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(),
}
}
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(),
}
}
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
_ => None,
}
}
+ fn blinded_hint_idx(&self) -> Option<usize> {
+ 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.
(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)),
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;