- } else if error_code & UPDATE == UPDATE {
- if let Some(update_len_slice) = err_packet.failuremsg.get(debug_field_size+2..debug_field_size+4) {
- let update_len = u16::from_be_bytes(update_len_slice.try_into().expect("len is 2")) as usize;
- if let Some(mut update_slice) = err_packet.failuremsg.get(debug_field_size + 4..debug_field_size + 4 + update_len) {
- // Historically, the BOLTs were unclear if the message type
- // bytes should be included here or not. The BOLTs have now
- // been updated to indicate that they *are* included, but many
- // nodes still send messages without the type bytes, so we
- // support both here.
- // TODO: Switch to hard require the type prefix, as the current
- // permissiveness introduces the (although small) possibility
- // that we fail to decode legitimate channel updates that
- // happen to start with ChannelUpdate::TYPE, i.e., [0x01, 0x02].
- if update_slice.len() > 2 && update_slice[0..2] == msgs::ChannelUpdate::TYPE.to_be_bytes() {
- update_slice = &update_slice[2..];
- } else {
- log_trace!(logger, "Failure provided features a channel update without type prefix. Deprecated, but allowing for now.");
- }
- if let Ok(chan_update) = msgs::ChannelUpdate::read(&mut Cursor::new(&update_slice)) {
- // if channel_update should NOT have caused the failure:
- // MAY treat the channel_update as invalid.
- let is_chan_update_invalid = match error_code & 0xff {
- 7 => false,
- 11 => amt_to_forward > chan_update.contents.htlc_minimum_msat,
- 12 => amt_to_forward
- .checked_mul(chan_update.contents.fee_proportional_millionths as u64)
- .map(|prop_fee| prop_fee / 1_000_000)
- .and_then(|prop_fee| prop_fee.checked_add(chan_update.contents.fee_base_msat as u64))
- .map(|fee_msats| route_hop.fee_msat >= fee_msats)
- .unwrap_or(false),
- 13 => route_hop.cltv_expiry_delta as u16 >= chan_update.contents.cltv_expiry_delta,
- 14 => false, // expiry_too_soon; always valid?
- 20 => chan_update.contents.flags & 2 == 0,
- _ => false, // unknown error code; take channel_update as valid
- };
- if is_chan_update_invalid {
- // This probably indicates the node which forwarded
- // to the node in question corrupted something.
- network_update = Some(NetworkUpdate::ChannelFailure {
- short_channel_id: route_hop.short_channel_id,
- is_permanent: true,
- });
- } else {
- // Make sure the ChannelUpdate contains the expected
- // short channel id.
- if failing_route_hop.short_channel_id == chan_update.contents.short_channel_id {
- short_channel_id = Some(failing_route_hop.short_channel_id);
- } else {
- log_info!(logger, "Node provided a channel_update for which it was not authoritative, ignoring.");
- }
- network_update = Some(NetworkUpdate::ChannelUpdateMessage {
- msg: chan_update,
- })
- };
- }
- }
- }
- if network_update.is_none() {
- // They provided an UPDATE which was obviously bogus, not worth
- // trying to relay through them anymore.
- network_update = Some(NetworkUpdate::NodeFailure {
- node_id: route_hop.pubkey,
- is_permanent: true,
- });
- }
- if short_channel_id.is_none() {
- short_channel_id = Some(route_hop.short_channel_id);
- }
- } else if payment_failed {
- // Only blame the hop when a value in the HTLC doesn't match the
- // corresponding value in the onion.
- short_channel_id = match error_code & 0xff {
- 18|19 => Some(route_hop.short_channel_id),
- _ => None,
- };
- } else {
- // We can't understand their error messages and they failed to
- // forward...they probably can't understand our forwards so its
- // really not worth trying any further.
- network_update = Some(NetworkUpdate::NodeFailure {
- node_id: route_hop.pubkey,
- is_permanent: true,
- });
- short_channel_id = Some(route_hop.short_channel_id);
- }
-
- res = Some((network_update, short_channel_id, !(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, debug_field, log_bytes!(&err_packet.failuremsg[4..4+debug_field_size]), description);
- }
- else {
- log_info!(logger, "Onion Error[from {}: {}({:#x})] {}", route_hop.pubkey, title, error_code, description);
- }