- // now, error_code should be only from the intermediate nodes
- match error_code {
- _c if error_code & PERM == PERM => {
- res = Some((Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
- short_channel_id: route_hop.short_channel_id,
- is_permanent: true,
- }), false));
- },
- _c if error_code & UPDATE == UPDATE => {
- let offset = match error_code {
- c if c == UPDATE|7 => 0, // temporary_channel_failure
- c if c == UPDATE|11 => 8, // amount_below_minimum
- c if c == UPDATE|12 => 8, // fee_insufficient
- c if c == UPDATE|13 => 4, // incorrect_cltv_expiry
- c if c == UPDATE|14 => 0, // expiry_too_soon
- c if c == UPDATE|20 => 2, // channel_disabled
- _ => {
- // node sending unknown code
- res = Some((Some(msgs::HTLCFailChannelUpdate::NodeFailure {
- node_id: route_hop.pubkey,
- is_permanent: true,
- }), false));
- return;
- }
- };
-
- if err_packet.failuremsg.len() >= offset + 2 {
- let update_len = byte_utils::slice_to_be16(&err_packet.failuremsg[offset+2..offset+4]) as usize;
- if err_packet.failuremsg.len() >= offset + 4 + update_len {
- if let Ok(chan_update) = msgs::ChannelUpdate::read(&mut Cursor::new(&err_packet.failuremsg[offset + 4..offset + 4 + update_len])) {
- // if channel_update should NOT have caused the failure:
- // MAY treat the channel_update as invalid.
- let is_chan_update_invalid = match error_code {
- c if c == UPDATE|7 => { // temporary_channel_failure
- false
- },
- c if c == UPDATE|11 => { // amount_below_minimum
- let reported_htlc_msat = byte_utils::slice_to_be64(&err_packet.failuremsg[2..2+8]);
- onion_failure_log!("amount_below_minimum", UPDATE|11, "htlc_msat", reported_htlc_msat);
- incoming_htlc_msat > chan_update.contents.htlc_minimum_msat
- },
- c if c == UPDATE|12 => { // fee_insufficient
- let reported_htlc_msat = byte_utils::slice_to_be64(&err_packet.failuremsg[2..2+8]);
- let new_fee = amt_to_forward.checked_mul(chan_update.contents.fee_proportional_millionths as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan_update.contents.fee_base_msat as u64) });
- onion_failure_log!("fee_insufficient", UPDATE|12, "htlc_msat", reported_htlc_msat);
- new_fee.is_none() || incoming_htlc_msat >= new_fee.unwrap() && incoming_htlc_msat >= amt_to_forward + new_fee.unwrap()
- }
- c if c == UPDATE|13 => { // incorrect_cltv_expiry
- let reported_cltv_expiry = byte_utils::slice_to_be32(&err_packet.failuremsg[2..2+4]);
- onion_failure_log!("incorrect_cltv_expiry", UPDATE|13, "cltv_expiry", reported_cltv_expiry);
- route_hop.cltv_expiry_delta as u16 >= chan_update.contents.cltv_expiry_delta
- },
- c if c == UPDATE|20 => { // channel_disabled
- let reported_flags = byte_utils::slice_to_be16(&err_packet.failuremsg[2..2+2]);
- onion_failure_log!("channel_disabled", UPDATE|20, "flags", reported_flags);
- chan_update.contents.flags & 0x01 == 0x01
- },
- c if c == UPDATE|21 => true, // expiry_too_far
- _ => { unreachable!(); },
- };
-
- let msg = if is_chan_update_invalid { None } else {
- Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
- msg: chan_update,
- })
- };
- res = Some((msg, true));
- return;
- }
+ let (debug_field, debug_field_size) = errors::get_onion_debug_field(error_code);
+
+ // indicate that payment parameter has failed and no need to
+ // update Route object
+ let payment_failed = (match error_code & 0xff {
+ 15|16|17|18|19 => true,
+ _ => false,
+ } && is_from_final_node) // PERM bit observed below even this error is from the intermediate nodes
+ || error_code == 21; // Special case error 21 as the Route object is bogus, TODO: Maybe fail the node if the CLTV was reasonable?
+
+ let mut fail_channel_update = None;
+
+ if error_code & NODE == NODE {
+ fail_channel_update = Some(msgs::HTLCFailChannelUpdate::NodeFailure { node_id: route_hop.pubkey, is_permanent: error_code & PERM == PERM });
+ }
+ else if error_code & PERM == PERM {
+ fail_channel_update = if payment_failed {None} else {Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
+ short_channel_id: route.hops[next_route_hop_ix - if next_route_hop_ix == route.hops.len() { 1 } else { 0 }].short_channel_id,
+ is_permanent: true,
+ })};
+ }
+ 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 = byte_utils::slice_to_be16(&update_len_slice) as usize;
+ if let Some(update_slice) = err_packet.failuremsg.get(debug_field_size + 4..debug_field_size + 4 + update_len) {
+ 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 => {
+ let new_fee = amt_to_forward.checked_mul(chan_update.contents.fee_proportional_millionths as u64).and_then(|prop_fee| { (prop_fee / 1000000).checked_add(chan_update.contents.fee_base_msat as u64) });
+ new_fee.is_some() && route_hop.fee_msat >= new_fee.unwrap()
+ }
+ 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
+ };
+ fail_channel_update = if is_chan_update_invalid {
+ // This probably indicates the node which forwarded
+ // to the node in question corrupted something.
+ Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
+ short_channel_id: route_hop.short_channel_id,
+ is_permanent: true,
+ })
+ } else {
+ Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
+ msg: chan_update,
+ })
+ };