HTLC Failure message handling
authorMatt Corallo <git@bluematt.me>
Tue, 24 Apr 2018 04:18:54 +0000 (00:18 -0400)
committerMatt Corallo <git@bluematt.me>
Tue, 24 Apr 2018 15:55:08 +0000 (11:55 -0400)
src/ln/channel.rs
src/ln/channelmanager.rs
src/ln/msgs.rs
src/ln/peer_handler.rs
src/ln/router.rs

index 1a2dd0606ba554513793c87404c67c97c729154d..fcdb9fcb94066e89598141af878c3c7ede9f5131 100644 (file)
@@ -1315,7 +1315,8 @@ impl Channel {
        }
 
        /// Removes an outbound HTLC which has been commitment_signed by the remote end
-       fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>, fail_reason: Option<HTLCFailReason>) -> Result<(), HandleError> {
+       #[inline]
+       fn mark_outbound_htlc_removed(&mut self, htlc_id: u64, check_preimage: Option<[u8; 32]>, fail_reason: Option<HTLCFailReason>) -> Result<[u8; 32], HandleError> {
                for mut htlc in self.pending_htlcs.iter_mut() {
                        if htlc.outbound && htlc.htlc_id == htlc_id {
                                match check_preimage {
@@ -1335,7 +1336,7 @@ impl Channel {
                                } else {
                                        panic!("Got a non-outbound state on an outbound HTLC");
                                }
-                               return Ok(());
+                               return Ok(htlc.payment_hash.clone());
                        }
                }
                Err(HandleError{err: "Remote tried to fulfill/fail an HTLC we couldn't find", msg: None})
@@ -1352,10 +1353,11 @@ impl Channel {
                sha.result(&mut payment_hash);
 
                self.channel_monitor.provide_payment_preimage(&msg.payment_preimage);
-               self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)
+               self.mark_outbound_htlc_removed(msg.htlc_id, Some(payment_hash), None)?;
+               Ok(())
        }
 
-       pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<(), HandleError> {
+       pub fn update_fail_htlc(&mut self, msg: &msgs::UpdateFailHTLC, fail_reason: HTLCFailReason) -> Result<[u8; 32], HandleError> {
                if (self.channel_state & (ChannelState::ChannelFunded as u32)) != (ChannelState::ChannelFunded as u32) {
                        return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None});
                }
@@ -1368,7 +1370,8 @@ impl Channel {
                        return Err(HandleError{err: "Got add HTLC message when channel was not in an operational state", msg: None});
                }
 
-               self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))
+               self.mark_outbound_htlc_removed(msg.htlc_id, None, Some(fail_reason))?;
+               Ok(())
        }
 
        pub fn commitment_signed(&mut self, msg: &msgs::CommitmentSigned) -> Result<(msgs::RevokeAndACK, Option<msgs::CommitmentSigned>), HandleError> {
index dda41c9a4f4309b84addaa01deb4f229bc1dc6de..4488232017e5d643622db37fcca07317e043cde8 100644 (file)
@@ -14,12 +14,13 @@ use secp256k1;
 use chain::chaininterface::{BroadcasterInterface,ChainListener,ChainWatchInterface,FeeEstimator};
 use ln::channel::{Channel, ChannelKeys};
 use ln::channelmonitor::ManyChannelMonitor;
-use ln::router::Route;
+use ln::router::{Route,RouteHop};
 use ln::msgs;
 use ln::msgs::{HandleError,ChannelMessageHandler,MsgEncodable,MsgDecodable};
 use util::{byte_utils, events, internal_traits, rng};
 use util::sha2::Sha256;
 
+use crypto;
 use crypto::mac::{Mac,MacResult};
 use crypto::hmac::Hmac;
 use crypto::digest::Digest;
@@ -91,12 +92,14 @@ enum PendingOutboundHTLC {
        },
        OutboundRoute {
                route: Route,
+               session_priv: SecretKey,
        },
        /// Used for channel rebalancing
        CycledRoute {
                source_short_channel_id: u64,
                incoming_packet_shared_secret: SharedSecret,
                route: Route,
+               session_priv: SecretKey,
        }
 }
 
@@ -336,8 +339,9 @@ impl ChannelManager {
                res
        }
 
-       fn construct_onion_keys(secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, HandleError> {
-               let mut res = Vec::with_capacity(route.hops.len());
+       // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
+       #[inline]
+       fn construct_onion_keys_callback<FType: FnMut(SharedSecret, [u8; 32], PublicKey, &RouteHop)> (secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey, mut callback: FType) -> Result<(), HandleError> {
                let mut blinded_priv = session_priv.clone();
                let mut blinded_pub = secp_call!(PublicKey::from_secret_key(secp_ctx, &blinded_priv));
                let mut first_iteration = true;
@@ -360,18 +364,29 @@ impl ChannelManager {
                        secp_call!(blinded_priv.mul_assign(secp_ctx, &secp_call!(SecretKey::from_slice(secp_ctx, &blinding_factor))));
                        blinded_pub = secp_call!(PublicKey::from_secret_key(secp_ctx, &blinded_priv));
 
+                       callback(shared_secret, blinding_factor, ephemeral_pubkey, hop);
+               }
+
+               Ok(())
+       }
+
+       // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
+       fn construct_onion_keys(secp_ctx: &Secp256k1, route: &Route, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, HandleError> {
+               let mut res = Vec::with_capacity(route.hops.len());
+
+               Self::construct_onion_keys_callback(secp_ctx, route, session_priv, |shared_secret, _blinding_factor, ephemeral_pubkey, _| {
                        let (rho, mu) = ChannelManager::gen_rho_mu_from_shared_secret(&shared_secret);
 
                        res.push(OnionKeys {
                                #[cfg(test)]
-                               shared_secret: shared_secret,
+                               shared_secret,
                                #[cfg(test)]
-                               blinding_factor: blinding_factor,
-                               ephemeral_pubkey: ephemeral_pubkey,
-                               rho: rho,
-                               mu: mu,
+                               blinding_factor: _blinding_factor,
+                               ephemeral_pubkey,
+                               rho,
+                               mu,
                        });
-               }
+               })?;
 
                Ok(res)
        }
@@ -602,7 +617,8 @@ impl ChannelManager {
                };
 
                if channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute {
-                       route: route,
+                       route,
+                       session_priv,
                }).is_some() {
                        // TODO: We need to track these better, we're not generating these, so a
                        // third-party might make this happen:
@@ -747,7 +763,7 @@ impl ChannelManager {
                for failed_forward in failed_forwards.drain(..) {
                        match failed_forward.2 {
                                None => self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failed_forward.0, HTLCFailReason::Reason { failure_code: failed_forward.1, data: Vec::new() }),
-                               Some(chan_update) => self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failed_forward.0, HTLCFailReason::Reason { failure_code: failed_forward.1, data: chan_update.encode() }),
+                               Some(chan_update) => self.fail_htlc_backwards_internal(self.channel_state.lock().unwrap(), &failed_forward.0, HTLCFailReason::Reason { failure_code: failed_forward.1, data: chan_update.encode_with_len() }),
                        };
                }
 
@@ -774,7 +790,11 @@ impl ChannelManager {
                };
 
                match pending_htlc {
-                       PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, .. } => {
+                       PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, route, session_priv } => {
+                               channel_state.claimable_htlcs.insert(payment_hash.clone(), PendingOutboundHTLC::OutboundRoute {
+                                       route,
+                                       session_priv,
+                               });
                                pending_htlc = PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret };
                        },
                        _ => {}
@@ -783,8 +803,8 @@ impl ChannelManager {
                match pending_htlc {
                        PendingOutboundHTLC::CycledRoute { .. } => { panic!("WAT"); },
                        PendingOutboundHTLC::OutboundRoute { .. } => {
-                               //TODO: DECRYPT route from OutboundRoute
                                mem::drop(channel_state);
+
                                let mut pending_events = self.pending_events.lock().unwrap();
                                pending_events.push(events::Event::PaymentFailed {
                                        payment_hash: payment_hash.clone()
@@ -858,13 +878,13 @@ impl ChannelManager {
                };
 
                match pending_htlc {
-                       PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, route } => {
+                       PendingOutboundHTLC::CycledRoute { source_short_channel_id, incoming_packet_shared_secret, route, session_priv } => {
                                if from_user { // This was the end hop back to us
                                        pending_htlc = PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret };
-                                       channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute { route });
+                                       channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::OutboundRoute { route, session_priv });
                                } else { // This came from the first upstream node
                                        // Bank error in our favor! Maybe we should tell the user this somehow???
-                                       pending_htlc = PendingOutboundHTLC::OutboundRoute { route };
+                                       pending_htlc = PendingOutboundHTLC::OutboundRoute { route, session_priv };
                                        channel_state.claimable_htlcs.insert(payment_hash, PendingOutboundHTLC::IntermediaryHopData { source_short_channel_id, incoming_packet_shared_secret });
                                }
                        },
@@ -1332,7 +1352,7 @@ impl ChannelMessageHandler for ChannelManager {
                        let chan = channel_state.by_id.get_mut(&forwarding_id).unwrap();
                        if !chan.is_live() {
                                let chan_update = self.get_channel_update(chan).unwrap();
-                               return_err!("Forwarding channel is not in a ready state.", 0x4000 | 10, &chan_update.encode()[..]);
+                               return_err!("Forwarding channel is not in a ready state.", 0x4000 | 7, &chan_update.encode_with_len()[..]);
                        }
                }
 
@@ -1376,16 +1396,17 @@ impl ChannelMessageHandler for ChannelManager {
                match claimable_htlcs_entry {
                        hash_map::Entry::Occupied(mut e) => {
                                let outbound_route = e.get_mut();
-                               let route = match outbound_route {
-                                       &mut PendingOutboundHTLC::OutboundRoute { ref route } => {
-                                               route.clone()
+                               let (route, session_priv) = match outbound_route {
+                                       &mut PendingOutboundHTLC::OutboundRoute { ref route, ref session_priv } => {
+                                               (route.clone(), session_priv.clone())
                                        },
                                        _ => { panic!("WAT") },
                                };
                                *outbound_route = PendingOutboundHTLC::CycledRoute {
                                        source_short_channel_id,
                                        incoming_packet_shared_secret: shared_secret,
-                                       route
+                                       route,
+                                       session_priv,
                                };
                        },
                        hash_map::Entry::Vacant(e) => {
@@ -1422,9 +1443,9 @@ impl ChannelMessageHandler for ChannelManager {
                Ok(())
        }
 
-       fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result<(), HandleError> {
+       fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &msgs::UpdateFailHTLC) -> Result<Option<msgs::HTLCFailChannelUpdate>, HandleError> {
                let mut channel_state = self.channel_state.lock().unwrap();
-               match channel_state.by_id.get_mut(&msg.channel_id) {
+               let payment_hash = match channel_state.by_id.get_mut(&msg.channel_id) {
                        Some(chan) => {
                                if chan.get_their_node_id() != *their_node_id {
                                        return Err(HandleError{err: "Got a message for a channel from the wrong node!", msg: None})
@@ -1432,6 +1453,68 @@ impl ChannelMessageHandler for ChannelManager {
                                chan.update_fail_htlc(&msg, HTLCFailReason::ErrorPacket { err: msg.reason.clone() })
                        },
                        None => return Err(HandleError{err: "Failed to find corresponding channel", msg: None})
+               }?;
+
+               if let Some(pending_htlc) = channel_state.claimable_htlcs.get(&payment_hash) {
+                       match pending_htlc {
+                               &PendingOutboundHTLC::OutboundRoute { ref route, ref session_priv } => {
+                                       // Handle packed channel/node updates for passing back for the route handler
+                                       let mut packet_decrypted = msg.reason.data.clone();
+                                       let mut res = None;
+                                       Self::construct_onion_keys_callback(&self.secp_ctx, &route, &session_priv, |shared_secret, _, _, route_hop| {
+                                               if res.is_some() { return; }
+
+                                               let ammag = ChannelManager::gen_ammag_from_shared_secret(&shared_secret);
+
+                                               let mut decryption_tmp = Vec::with_capacity(packet_decrypted.len());
+                                               decryption_tmp.resize(packet_decrypted.len(), 0);
+                                               let mut chacha = ChaCha20::new(&ammag, &[0u8; 8]);
+                                               chacha.process(&packet_decrypted, &mut decryption_tmp[..]);
+                                               packet_decrypted = decryption_tmp;
+
+                                               if let Ok(err_packet) = msgs::DecodedOnionErrorPacket::decode(&packet_decrypted) {
+                                                       if err_packet.failuremsg.len() >= 2 {
+                                                               let um = ChannelManager::gen_um_from_shared_secret(&shared_secret);
+
+                                                               let mut hmac = Hmac::new(Sha256::new(), &um);
+                                                               hmac.input(&err_packet.encode()[32..]);
+                                                               let mut calc_tag =  [0u8; 32];
+                                                               hmac.raw_result(&mut calc_tag);
+                                                               if crypto::util::fixed_time_eq(&calc_tag, &err_packet.hmac) {
+                                                                       const UNKNOWN_CHAN: u16 = 0x4000|10;
+                                                                       const TEMP_CHAN_FAILURE: u16 = 0x4000|7;
+                                                                       match byte_utils::slice_to_be16(&err_packet.failuremsg[0..2]) {
+                                                                               TEMP_CHAN_FAILURE => {
+                                                                                       if err_packet.failuremsg.len() >= 4 {
+                                                                                               let update_len = byte_utils::slice_to_be16(&err_packet.failuremsg[2..4]) as usize;
+                                                                                               if err_packet.failuremsg.len() >= 4 + update_len {
+                                                                                                       if let Ok(chan_update) = msgs::ChannelUpdate::decode(&err_packet.failuremsg[4..4 + update_len]) {
+                                                                                                               res = Some(msgs::HTLCFailChannelUpdate::ChannelUpdateMessage {
+                                                                                                                       msg: chan_update,
+                                                                                                               });
+                                                                                                       }
+                                                                                               }
+                                                                                       }
+                                                                               },
+                                                                               UNKNOWN_CHAN => {
+                                                                                       // No such next-hop. We know this came from the
+                                                                                       // current node as the HMAC validated.
+                                                                                       res = Some(msgs::HTLCFailChannelUpdate::ChannelClosed {
+                                                                                               short_channel_id: route_hop.short_channel_id
+                                                                                       });
+                                                                               },
+                                                                               _ => {}, //TODO: Enumerate all of these!
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }).unwrap();
+                                       Ok(res)
+                               },
+                               _ => { Ok(None) },
+                       }
+               } else {
+                       Ok(None)
                }
        }
 
@@ -2169,14 +2252,7 @@ mod tests {
                claim_payment(&origin, expected_route, our_payment_preimage);
        }
 
-       fn send_failed_payment(origin_node: &Node, expected_route: &[&Node]) {
-               let route = origin_node.router.get_route(&expected_route.last().unwrap().node.get_our_node_id(), &Vec::new(), 1000000, 142).unwrap();
-               assert_eq!(route.hops.len(), expected_route.len());
-               for (node, hop) in expected_route.iter().zip(route.hops.iter()) {
-                       assert_eq!(hop.pubkey, node.node.get_our_node_id());
-               }
-               let our_payment_hash = send_along_route(origin_node, route, expected_route, 1000000).1;
-
+       fn fail_payment(origin_node: &Node, expected_route: &[&Node], our_payment_hash: [u8; 32]) {
                assert!(expected_route.last().unwrap().node.fail_htlc_backwards(&our_payment_hash));
 
                let mut next_msgs: Option<(msgs::UpdateFailHTLC, msgs::CommitmentSigned)> = None;
@@ -2288,7 +2364,8 @@ mod tests {
                send_payment(&nodes[3], &vec!(&nodes[2], &nodes[1])[..], 1000000);
 
                // Test failure packets
-               send_failed_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..]);
+               let payment_hash_1 = route_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..], 1000000).1;
+               fail_payment(&nodes[0], &vec!(&nodes[1], &nodes[2], &nodes[3])[..], payment_hash_1);
 
                // Add a new channel that skips 3
                let chan_4 = create_announced_chan_between_nodes(&nodes, 1, 3);
@@ -2346,10 +2423,10 @@ mod tests {
                });
                hops[1].fee_msat = chan_2.1.contents.fee_base_msat as u64 + chan_2.1.contents.fee_proportional_millionths as u64 * hops[2].fee_msat as u64 / 1000000;
                hops[0].fee_msat = chan_3.1.contents.fee_base_msat as u64 + chan_3.1.contents.fee_proportional_millionths as u64 * hops[1].fee_msat as u64 / 1000000;
-               let payment_preimage_2 = send_along_route(&nodes[1], Route { hops }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).0;
+               let payment_hash_2 = send_along_route(&nodes[1], Route { hops }, &vec!(&nodes[3], &nodes[2], &nodes[1])[..], 1000000).1;
 
                // Claim the rebalances...
-               claim_payment(&nodes[1], &vec!(&nodes[3], &nodes[2], &nodes[1])[..], payment_preimage_2);
+               fail_payment(&nodes[1], &vec!(&nodes[3], &nodes[2], &nodes[1])[..], payment_hash_2);
                claim_payment(&nodes[1], &vec!(&nodes[2], &nodes[3], &nodes[1])[..], payment_preimage_1);
 
                // Add a duplicate new channel from 2 to 4
index c48e0568169c121e6f434df99dc5ec495eecd329..681817a9e1c007720d15da34c95f4f26ef51eeab 100644 (file)
@@ -15,6 +15,14 @@ pub trait MsgEncodable {
        fn encode(&self) -> Vec<u8>;
        #[inline]
        fn encoded_len(&self) -> usize { self.encode().len() }
+       #[inline]
+       fn encode_with_len(&self) -> Vec<u8> {
+               let enc = self.encode();
+               let mut res = Vec::with_capacity(enc.len() + 2);
+               res.extend_from_slice(&byte_utils::be16_to_array(enc.len() as u16));
+               res.extend_from_slice(&enc);
+               res
+       }
 }
 #[derive(Debug)]
 pub enum DecodeError {
@@ -366,6 +374,15 @@ pub struct CommitmentUpdate {
        pub commitment_signed: CommitmentSigned,
 }
 
+pub enum HTLCFailChannelUpdate {
+       ChannelUpdateMessage {
+               msg: ChannelUpdate,
+       },
+       ChannelClosed {
+               short_channel_id: u64,
+       },
+}
+
 /// A trait to describe an object which can receive channel messages. Messages MAY be called in
 /// paralell when they originate from different their_node_ids, however they MUST NOT be called in
 /// paralell when the two calls have the same their_node_id.
@@ -384,7 +401,7 @@ pub trait ChannelMessageHandler : events::EventsProvider {
        // HTLC handling:
        fn handle_update_add_htlc(&self, their_node_id: &PublicKey, msg: &UpdateAddHTLC) -> Result<(), HandleError>;
        fn handle_update_fulfill_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFulfillHTLC) -> Result<(), HandleError>;
-       fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC) -> Result<(), HandleError>;
+       fn handle_update_fail_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailHTLC) -> Result<Option<HTLCFailChannelUpdate>, HandleError>;
        fn handle_update_fail_malformed_htlc(&self, their_node_id: &PublicKey, msg: &UpdateFailMalformedHTLC) -> Result<(), HandleError>;
        fn handle_commitment_signed(&self, their_node_id: &PublicKey, msg: &CommitmentSigned) -> Result<(RevokeAndACK, Option<CommitmentSigned>), HandleError>;
        fn handle_revoke_and_ack(&self, their_node_id: &PublicKey, msg: &RevokeAndACK) -> Result<Option<CommitmentUpdate>, HandleError>;
@@ -408,6 +425,7 @@ pub trait RoutingMessageHandler {
        /// or returning an Err otherwise.
        fn handle_channel_announcement(&self, msg: &ChannelAnnouncement) -> Result<bool, HandleError>;
        fn handle_channel_update(&self, msg: &ChannelUpdate) -> Result<(), HandleError>;
+       fn handle_htlc_fail_channel_update(&self, update: &HTLCFailChannelUpdate);
 }
 
 pub struct OnionRealm0HopData {
@@ -1316,8 +1334,26 @@ impl MsgEncodable for OnionPacket {
 }
 
 impl MsgDecodable for DecodedOnionErrorPacket {
-       fn decode(_v: &[u8]) -> Result<Self, DecodeError> {
-               unimplemented!();
+       fn decode(v: &[u8]) -> Result<Self, DecodeError> {
+               if v.len() < 32 + 4 {
+                       return Err(DecodeError::WrongLength);
+               }
+               let failuremsg_len = byte_utils::slice_to_be16(&v[32..34]) as usize;
+               if v.len() < 32 + 4 + failuremsg_len {
+                       return Err(DecodeError::WrongLength);
+               }
+               let padding_len = byte_utils::slice_to_be16(&v[34 + failuremsg_len..]) as usize;
+               if v.len() < 32 + 4 + failuremsg_len + padding_len {
+                       return Err(DecodeError::WrongLength);
+               }
+
+               let mut hmac = [0; 32];
+               hmac.copy_from_slice(&v[0..32]);
+               Ok(Self {
+                       hmac,
+                       failuremsg: v[34..34 + failuremsg_len].to_vec(),
+                       pad: v[36 + failuremsg_len..36 + failuremsg_len + padding_len].to_vec(),
+               })
        }
 }
 impl MsgEncodable for DecodedOnionErrorPacket {
index d7b1e9d691238f34161c53d6c0e1eebf5ba35606..624c6494930dec39060b0119a933c4a81eaf1c7a 100644 (file)
@@ -424,7 +424,10 @@ impl<Descriptor: SocketDescriptor> PeerManager<Descriptor> {
                                                                                        },
                                                                                        131 => {
                                                                                                let msg = try_potential_decodeerror!(msgs::UpdateFailHTLC::decode(&msg_data[2..]));
-                                                                                               try_potential_handleerror!(self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg));
+                                                                                               let chan_update = try_potential_handleerror!(self.message_handler.chan_handler.handle_update_fail_htlc(&peer.their_node_id.unwrap(), &msg));
+                                                                                               if let Some(update) = chan_update {
+                                                                                                       self.message_handler.route_handler.handle_htlc_fail_channel_update(&update);
+                                                                                               }
                                                                                        },
                                                                                        135 => {
                                                                                                let msg = try_potential_decodeerror!(msgs::UpdateFailMalformedHTLC::decode(&msg_data[2..]));
index 75df79450f3507d80969ee0eb186a3a8022d28f6..19a677580a5c101fe08e78d52ac17dbee4dc0ffe 100644 (file)
@@ -51,9 +51,9 @@ struct ChannelInfo {
 
 struct NodeInfo {
        #[cfg(feature = "non_bitcoin_chain_hash_routing")]
-    channels: Vec<(u64, Sha256dHash)>,
+       channels: Vec<(u64, Sha256dHash)>,
        #[cfg(not(feature = "non_bitcoin_chain_hash_routing"))]
-    channels: Vec<u64>,
+       channels: Vec<u64>,
 
        lowest_inbound_channel_fee_base_msat: u32,
        lowest_inbound_channel_fee_proportional_millionths: u32,
@@ -214,6 +214,18 @@ impl RoutingMessageHandler for Router {
                Ok(!msg.contents.features.supports_unknown_bits())
        }
 
+       fn handle_htlc_fail_channel_update(&self, update: &msgs::HTLCFailChannelUpdate) {
+               match update {
+                       &msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => {
+                               let _ = self.handle_channel_update(msg);
+                       },
+                       &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id } => {
+                               let mut network = self.network_map.write().unwrap();
+                               network.channels.remove(short_channel_id);
+                       },
+               }
+       }
+
        fn handle_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<(), HandleError> {
                let mut network = self.network_map.write().unwrap();
                let dest_node_id;