From: Matt Corallo Date: Sun, 1 Apr 2018 23:23:09 +0000 (-0400) Subject: Basic error handling framework in peer_handler X-Git-Tag: v0.0.12~413^2~3 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=91b964ae1f5280d0340080bdbe8c80d733f5f676;p=rust-lightning Basic error handling framework in peer_handler --- diff --git a/src/ln/channelmanager.rs b/src/ln/channelmanager.rs index 6d631435a..d2854ca74 100644 --- a/src/ln/channelmanager.rs +++ b/src/ln/channelmanager.rs @@ -1481,6 +1481,37 @@ impl ChannelMessageHandler for ChannelManager { pending_events.push(events::Event::BroadcastChannelAnnouncement { msg: chan_announcement, update_msg: chan_update }); Ok(()) } + + fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool) { + let mut channel_state_lock = self.channel_state.lock().unwrap(); + let channel_state = channel_state_lock.borrow_parts(); + let short_to_id = channel_state.short_to_id; + if no_connection_possible { + channel_state.by_id.retain(move |_, chan| { + if chan.get_their_node_id() == *their_node_id { + match chan.get_short_channel_id() { + Some(short_id) => { + short_to_id.remove(&short_id); + }, + None => {}, + } + //TODO: get the latest commitment tx, any HTLC txn built on top of it, etc out + //of the channel and throw those into the announcement blackhole. + false + } else { + true + } + }); + } else { + for chan in channel_state.by_id { + if chan.1.get_their_node_id() == *their_node_id { + //TODO: mark channel disabled (and maybe announce such after a timeout). Also + //fail and wipe any uncommitted outbound HTLCs as those are considered after + //reconnect. + } + } + } + } } #[cfg(test)] diff --git a/src/ln/msgs.rs b/src/ln/msgs.rs index 0d5e4ec7c..347a30798 100644 --- a/src/ln/msgs.rs +++ b/src/ln/msgs.rs @@ -381,6 +381,13 @@ pub trait ChannelMessageHandler : events::EventsProvider { // Channel-to-announce: fn handle_announcement_signatures(&self, their_node_id: &PublicKey, msg: &AnnouncementSignatures) -> Result<(), HandleError>; + + // Informational: + /// Indicates a connection to the peer failed/an existing connection was lost. If no connection + /// is believed to be possible in the future (eg they're sending us messages we don't + /// understand or indicate they require unknown feature bits), no_connection_possible is set + /// and any outstanding channels should be failed. + fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool); } pub trait RoutingMessageHandler { diff --git a/src/ln/peer_handler.rs b/src/ln/peer_handler.rs index e01d2c9b8..01081845a 100644 --- a/src/ln/peer_handler.rs +++ b/src/ln/peer_handler.rs @@ -223,7 +223,7 @@ impl PeerManager { match self.do_read_event(peer_descriptor, data) { Ok(res) => Ok(res), Err(e) => { - self.disconnect_event(peer_descriptor); + self.disconnect_event_internal(peer_descriptor, e.no_connection_possible); Err(e) } } @@ -238,38 +238,7 @@ impl PeerManager { assert!(peer.pending_read_buffer.len() > 0); assert!(peer.pending_read_buffer.len() > peer.pending_read_buffer_pos); - macro_rules! try_potential_handleerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(_e) => { - //TODO: Handle e appropriately! - return Err(PeerHandleError{}); - } - }; - } - } - - macro_rules! try_potential_decodeerror { - ($thing: expr) => { - match $thing { - Ok(x) => x, - Err(_e) => { - //TODO: Handle e? - return Err(PeerHandleError{}); - } - }; - } - } - - macro_rules! encode_and_send_msg { - ($msg: expr, $msg_code: expr) => { - peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!($msg, $msg_code)[..])); - } - } - let mut insert_node_id = None; - let mut read_pos = 0; while read_pos < data.len() { { @@ -278,7 +247,52 @@ impl PeerManager { read_pos += data_to_copy; peer.pending_read_buffer_pos += data_to_copy; } + if peer.pending_read_buffer_pos == peer.pending_read_buffer.len() { + peer.pending_read_buffer_pos = 0; + + macro_rules! encode_and_send_msg { + ($msg: expr, $msg_code: expr) => { + peer.pending_outbound_buffer.push_back(peer.channel_encryptor.encrypt_message(&encode_msg!($msg, $msg_code)[..])); + } + } + + macro_rules! try_potential_handleerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(e) => { + // TODO: Log e.err + if let Some(action) = e.msg { + match action { + msgs::ErrorAction::UpdateFailHTLC { msg } => { + encode_and_send_msg!(msg, 131); + continue; + }, + msgs::ErrorAction::DisconnectPeer {} => { + return Err(PeerHandleError{ no_connection_possible: false }); + }, + } + } else { + return Err(PeerHandleError{ no_connection_possible: false }); + } + } + }; + } + } + + macro_rules! try_potential_decodeerror { + ($thing: expr) => { + match $thing { + Ok(x) => x, + Err(_e) => { + //TODO: Handle e? + return Err(PeerHandleError{ no_connection_possible: false }); + } + }; + } + } + let next_step = peer.channel_encryptor.get_noise_step(); match next_step { NextNoiseStep::ActOne => { @@ -311,27 +325,31 @@ impl PeerManager { peer.pending_read_buffer = Vec::with_capacity(msg_len as usize + 16); peer.pending_read_buffer.resize(msg_len as usize + 16, 0); if msg_len < 2 { // Need at least the message type tag - return Err(PeerHandleError{}); + return Err(PeerHandleError{ no_connection_possible: false }); } peer.pending_read_is_header = false; } else { let msg_data = try_potential_handleerror!(peer.channel_encryptor.decrypt_message(&peer.pending_read_buffer[..])); assert!(msg_data.len() >= 2); + // Reset read buffer + peer.pending_read_buffer = [0; 18].to_vec(); + peer.pending_read_is_header = true; + let msg_type = byte_utils::slice_to_be16(&msg_data[0..2]); if msg_type != 16 && peer.their_global_features.is_none() { // Need an init message as first message - return Err(PeerHandleError{}); + return Err(PeerHandleError{ no_connection_possible: false }); } match msg_type { // Connection control: 16 => { let msg = try_potential_decodeerror!(msgs::Init::decode(&msg_data[2..])); if msg.global_features.requires_unknown_bits() { - return Err(PeerHandleError{}); + return Err(PeerHandleError{ no_connection_possible: true }); } if msg.local_features.requires_unknown_bits() { - return Err(PeerHandleError{}); + return Err(PeerHandleError{ no_connection_possible: true }); } peer.their_global_features = Some(msg.global_features); peer.their_local_features = Some(msg.local_features); @@ -460,18 +478,13 @@ impl PeerManager { }, _ => { if (msg_type & 1) == 0 { - //TODO: Fail all channels. Kill the peer! - return Err(PeerHandleError{}); + return Err(PeerHandleError{ no_connection_possible: true }); } }, } - - peer.pending_read_buffer = [0; 18].to_vec(); - peer.pending_read_is_header = true; } } } - peer.pending_read_buffer_pos = 0; } } @@ -623,18 +636,22 @@ impl PeerManager { /// but must NOT be called if a PeerHandleError was provided out of a new_*_connection event! /// Panics if the descriptor was not previously registered in a successful new_*_connection event. pub fn disconnect_event(&self, descriptor: &Descriptor) { + self.disconnect_event_internal(descriptor, false); + } + + fn disconnect_event_internal(&self, descriptor: &Descriptor, no_connection_possible: bool) { let mut peers = self.peers.lock().unwrap(); let peer_option = peers.peers.remove(descriptor); match peer_option { None => panic!("Descriptor for disconnect_event is not already known to PeerManager"), Some(peer) => { match peer.their_node_id { - Some(node_id) => { peers.node_id_to_descriptor.remove(&node_id); }, + Some(node_id) => { + peers.node_id_to_descriptor.remove(&node_id); + self.message_handler.chan_handler.peer_disconnected(&node_id, no_connection_possible); + }, None => {} } - //TODO: Notify the chan_handler that this node disconnected, and do something about - //handling response messages that were queued for sending (maybe the send buffer - //needs to be unencrypted?) } }; }