use crate::ln::wire::Encode;
use crate::routing::gossip::NetworkUpdate;
use crate::routing::router::{BlindedTail, Path, RouteHop};
+use crate::sign::NodeSigner;
use crate::util::chacha20::{ChaCha20, ChaChaReader};
use crate::util::errors::{self, APIError};
use crate::util::ser::{Readable, ReadableArgs, Writeable, Writer, LengthCalculatingWriter};
pub(crate) struct DecodedOnionFailure {
pub(crate) network_update: Option<NetworkUpdate>,
pub(crate) short_channel_id: Option<u64>,
- pub(crate) payment_retryable: bool,
+ pub(crate) payment_failed_permanently: bool,
#[cfg(test)]
pub(crate) onion_error_code: Option<u16>,
#[cfg(test)]
} = htlc_source {
(path, session_priv, first_hop_htlc_msat)
} else { unreachable!() };
- let mut res = None;
+
+ // Learnings from the HTLC failure to inform future payment retries and scoring.
+ struct FailureLearnings {
+ network_update: Option<NetworkUpdate>,
+ short_channel_id: Option<u64>,
+ payment_failed_permanently: bool,
+ }
+ let mut res: Option<FailureLearnings> = None;
let mut htlc_msat = *first_hop_htlc_msat;
let mut error_code_ret = None;
let mut error_packet_ret = None;
// Got an error from within a blinded route.
error_code_ret = Some(BADONION | PERM | 24); // invalid_onion_blinding
error_packet_ret = Some(vec![0; 32]);
- is_from_final_node = false;
+ res = Some(FailureLearnings {
+ network_update: None, short_channel_id: None, payment_failed_permanently: false
+ });
return
},
};
is_permanent: true,
});
let short_channel_id = Some(route_hop.short_channel_id);
- res = Some((network_update, short_channel_id, !is_from_final_node));
+ res = Some(FailureLearnings {
+ network_update, short_channel_id, payment_failed_permanently: is_from_final_node
+ });
return
}
};
short_channel_id = Some(route_hop.short_channel_id);
}
- res = Some((network_update, short_channel_id, !(error_code & PERM == PERM && is_from_final_node)));
+ res = Some(FailureLearnings {
+ network_update, short_channel_id,
+ payment_failed_permanently: error_code & PERM == PERM && is_from_final_node
+ });
let (description, title) = errors::get_onion_error_description(error_code);
if debug_field_size > 0 && err_packet.failuremsg.len() >= 4 + debug_field_size {
log_info!(logger, "Onion Error[from {}: {}({:#x})] {}", route_hop.pubkey, title, error_code, description);
}
}).expect("Route that we sent via spontaneously grew invalid keys in the middle of it?");
- if let Some((network_update, short_channel_id, payment_retryable)) = res {
+ if let Some(FailureLearnings {
+ network_update, short_channel_id, payment_failed_permanently
+ }) = res {
DecodedOnionFailure {
- network_update, short_channel_id, payment_retryable,
+ network_update, short_channel_id, payment_failed_permanently,
#[cfg(test)]
onion_error_code: error_code_ret,
#[cfg(test)]
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
DecodedOnionFailure {
- network_update: None, short_channel_id: None, payment_retryable: !is_from_final_node,
+ network_update: None, short_channel_id: None, payment_failed_permanently: is_from_final_node,
#[cfg(test)]
onion_error_code: None,
#[cfg(test)]
if let &HTLCSource::OutboundRoute { ref path, .. } = htlc_source {
DecodedOnionFailure {
network_update: None,
- payment_retryable: true,
+ payment_failed_permanently: false,
short_channel_id: Some(path.hops[0].short_channel_id),
#[cfg(test)]
onion_error_code: Some(*failure_code),
},
}
-pub(crate) fn decode_next_payment_hop(shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], payment_hash: PaymentHash) -> Result<Hop, OnionDecodeErr> {
- match decode_next_hop(shared_secret, hop_data, hmac_bytes, Some(payment_hash), ()) {
+pub(crate) fn decode_next_payment_hop<NS: Deref>(
+ shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], payment_hash: PaymentHash,
+ node_signer: &NS,
+) -> Result<Hop, OnionDecodeErr> where NS::Target: NodeSigner {
+ match decode_next_hop(shared_secret, hop_data, hmac_bytes, Some(payment_hash), node_signer) {
Ok((next_hop_data, None)) => Ok(Hop::Receive(next_hop_data)),
Ok((next_hop_data, Some((next_hop_hmac, FixedSizeOnionPacket(new_packet_bytes))))) => {
Ok(Hop::Forward {