Add ChannelManager-specific HandleError type and macro to use it
[rust-lightning] / src / ln / channelmanager.rs
index dc7ac2a816106a1bd2919cc8587615d6237c7245..f12c3f7ac4a8c31b40362b971ad826ae643d96a3 100644 (file)
@@ -120,6 +120,32 @@ enum PendingOutboundHTLC {
        }
 }
 
+struct MsgHandleErrInternal {
+       err: msgs::HandleError,
+       needs_channel_force_close: bool,
+}
+impl MsgHandleErrInternal {
+       #[inline]
+       fn send_err_msg_no_close(err: &'static str, channel_id: [u8; 32]) -> Self {
+               Self {
+                       err: HandleError {
+                               err,
+                               action: Some(msgs::ErrorAction::SendErrorMessage {
+                                       msg: msgs::ErrorMessage {
+                                               channel_id,
+                                               data: err.to_string()
+                                       },
+                               }),
+                       },
+                       needs_channel_force_close: false,
+               }
+       }
+       #[inline]
+       fn from_no_close(err: msgs::HandleError) -> Self {
+               Self { err, needs_channel_force_close: false }
+       }
+}
+
 /// We hold back HTLCs we intend to relay for a random interval in the range (this, 5*this). This
 /// provides some limited amount of privacy. Ideally this would range from somewhere like 1 second
 /// to 30 seconds, but people expect lightning to be, you know, kinda fast, sadly. We could
@@ -189,11 +215,10 @@ pub struct ChannelManager {
 const CLTV_EXPIRY_DELTA: u16 = 6 * 24 * 2; //TODO?
 
 macro_rules! secp_call {
-       ( $res : expr ) => {
+       ( $res: expr, $err_msg: expr, $action: expr ) => {
                match $res {
                        Ok(key) => key,
-                       //TODO: Make the err a parameter!
-                       Err(_) => return Err(HandleError{err: "Key error", action: None})
+                       Err(_) => return Err(HandleError{err: $err_msg, action: Some($action)})
                }
        };
 }
@@ -475,10 +500,9 @@ impl ChannelManager {
 
        // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
        #[inline]
-       fn construct_onion_keys_callback<T: secp256k1::Signing, FType: FnMut(SharedSecret, [u8; 32], PublicKey, &RouteHop)> (secp_ctx: &Secp256k1<T>, route: &Route, session_priv: &SecretKey, mut callback: FType) -> Result<(), HandleError> {
+       fn construct_onion_keys_callback<T: secp256k1::Signing, FType: FnMut(SharedSecret, [u8; 32], PublicKey, &RouteHop)> (secp_ctx: &Secp256k1<T>, route: &Route, session_priv: &SecretKey, mut callback: FType) -> Result<(), secp256k1::Error> {
                let mut blinded_priv = session_priv.clone();
                let mut blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
-               let mut first_iteration = true;
 
                for hop in route.hops.iter() {
                        let shared_secret = SharedSecret::new(secp_ctx, &hop.pubkey, &blinded_priv);
@@ -489,13 +513,9 @@ impl ChannelManager {
                        let mut blinding_factor = [0u8; 32];
                        sha.result(&mut blinding_factor);
 
-                       if first_iteration {
-                               blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
-                               first_iteration = false;
-                       }
                        let ephemeral_pubkey = blinded_pub;
 
-                       secp_call!(blinded_priv.mul_assign(secp_ctx, &secp_call!(SecretKey::from_slice(secp_ctx, &blinding_factor))));
+                       blinded_priv.mul_assign(secp_ctx, &SecretKey::from_slice(secp_ctx, &blinding_factor)?)?;
                        blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
 
                        callback(shared_secret, blinding_factor, ephemeral_pubkey, hop);
@@ -505,7 +525,7 @@ impl ChannelManager {
        }
 
        // can only fail if an intermediary hop has an invalid public key or session_priv is invalid
-       fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, route: &Route, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, HandleError> {
+       fn construct_onion_keys<T: secp256k1::Signing>(secp_ctx: &Secp256k1<T>, route: &Route, session_priv: &SecretKey) -> Result<Vec<OnionKeys>, secp256k1::Error> {
                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, _| {
@@ -910,15 +930,17 @@ impl ChannelManager {
                        }
                }
 
-               let session_priv = secp_call!(SecretKey::from_slice(&self.secp_ctx, &{
+               let session_priv = SecretKey::from_slice(&self.secp_ctx, &{
                        let mut session_key = [0; 32];
                        rng::fill_bytes(&mut session_key);
                        session_key
-               }));
+               }).expect("RNG is bad!");
 
                let cur_height = self.latest_block_height.load(Ordering::Acquire) as u32 + 1;
 
-               let onion_keys = ChannelManager::construct_onion_keys(&self.secp_ctx, &route, &session_priv)?;
+               //TODO: This should return something other than HandleError, that's really intended for
+               //p2p-returns only.
+               let onion_keys = secp_call!(ChannelManager::construct_onion_keys(&self.secp_ctx, &route, &session_priv), "Pubkey along hop was maliciously selected", msgs::ErrorAction::IgnoreError);
                let (onion_payloads, htlc_msat, htlc_cltv) = ChannelManager::build_onion_payloads(&route, cur_height)?;
                let onion_packet = ChannelManager::construct_onion_packet(onion_payloads, onion_keys, &payment_hash)?;
 
@@ -1487,6 +1509,38 @@ impl ChainListener for ChannelManager {
        }
 }
 
+macro_rules! handle_error {
+       ($self: ident, $internal: expr, $their_node_id: expr) => {
+               match $internal {
+                       Ok(msg) => Ok(msg),
+                       Err(MsgHandleErrInternal { err, needs_channel_force_close }) => {
+                               if needs_channel_force_close {
+                                       match &err.action {
+                                               &Some(msgs::ErrorAction::DisconnectPeer { msg: Some(ref msg) }) => {
+                                                       if msg.channel_id == [0; 32] {
+                                                               $self.peer_disconnected(&$their_node_id, true);
+                                                       } else {
+                                                               $self.force_close_channel(&msg.channel_id);
+                                                       }
+                                               },
+                                               &Some(msgs::ErrorAction::DisconnectPeer { msg: None }) => {},
+                                               &Some(msgs::ErrorAction::IgnoreError) => {},
+                                               &Some(msgs::ErrorAction::SendErrorMessage { ref msg }) => {
+                                                       if msg.channel_id == [0; 32] {
+                                                               $self.peer_disconnected(&$their_node_id, true);
+                                                       } else {
+                                                               $self.force_close_channel(&msg.channel_id);
+                                                       }
+                                               },
+                                               &None => {},
+                                       }
+                               }
+                               Err(err)
+                       },
+               }
+       }
+}
+
 impl ChannelMessageHandler for ChannelManager {
        //TODO: Handle errors and close channel (or so)
        fn handle_open_channel(&self, their_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result<msgs::AcceptChannel, HandleError> {
@@ -1987,10 +2041,10 @@ impl ChannelMessageHandler for ChannelManager {
                        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!", action: None})
+                                               return Err(HandleError{err: "Got a message for a channel from the wrong node!", action: Some(msgs::ErrorAction::IgnoreError) })
                                        }
                                        if !chan.is_usable() {
-                                               return Err(HandleError{err: "Got an announcement_signatures before we were ready for it", action: None });
+                                               return Err(HandleError{err: "Got an announcement_signatures before we were ready for it", action: Some(msgs::ErrorAction::IgnoreError) });
                                        }
 
                                        let our_node_id = self.get_our_node_id();
@@ -1998,8 +2052,9 @@ impl ChannelMessageHandler for ChannelManager {
 
                                        let were_node_one = announcement.node_id_1 == our_node_id;
                                        let msghash = Message::from_slice(&Sha256dHash::from_data(&announcement.encode()[..])[..]).unwrap();
-                                       secp_call!(self.secp_ctx.verify(&msghash, &msg.node_signature, if were_node_one { &announcement.node_id_2 } else { &announcement.node_id_1 }));
-                                       secp_call!(self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, if were_node_one { &announcement.bitcoin_key_2 } else { &announcement.bitcoin_key_1 }));
+                                       let bad_sig_action = msgs::ErrorAction::SendErrorMessage { msg: msgs::ErrorMessage { channel_id: msg.channel_id.clone(), data: "Invalid signature in announcement_signatures".to_string() } };
+                                       secp_call!(self.secp_ctx.verify(&msghash, &msg.node_signature, if were_node_one { &announcement.node_id_2 } else { &announcement.node_id_1 }), "Bad announcement_signatures node_signature", bad_sig_action);
+                                       secp_call!(self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, if were_node_one { &announcement.bitcoin_key_2 } else { &announcement.bitcoin_key_1 }), "Bad announcement_signatures bitcoin_signature", bad_sig_action);
 
                                        let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key);
 
@@ -2011,7 +2066,7 @@ impl ChannelMessageHandler for ChannelManager {
                                                contents: announcement,
                                        }, self.get_channel_update(chan).unwrap()) // can only fail if we're not in a ready state
                                },
-                               None => return Err(HandleError{err: "Failed to find corresponding channel", action: None})
+                               None => return Err(HandleError{err: "Failed to find corresponding channel", action: Some(msgs::ErrorAction::IgnoreError)})
                        }
                };
                let mut pending_events = self.pending_events.lock().unwrap();
@@ -2093,13 +2148,14 @@ mod tests {
        use bitcoin::util::hash::Sha256dHash;
        use bitcoin::blockdata::block::{Block, BlockHeader};
        use bitcoin::blockdata::transaction::{Transaction, TxOut};
+       use bitcoin::blockdata::constants::genesis_block;
        use bitcoin::network::constants::Network;
        use bitcoin::network::serialize::serialize;
        use bitcoin::network::serialize::BitcoinHash;
 
        use hex;
 
-       use secp256k1::Secp256k1;
+       use secp256k1::{Secp256k1, Message};
        use secp256k1::key::{PublicKey,SecretKey};
 
        use crypto::sha2::Sha256;
@@ -2274,7 +2330,6 @@ mod tests {
        }
 
        struct Node {
-               feeest: Arc<test_utils::TestFeeEstimator>,
                chain_monitor: Arc<chaininterface::ChainWatchInterfaceUtil>,
                tx_broadcaster: Arc<test_utils::TestBroadcaster>,
                chan_monitor: Arc<test_utils::TestChannelMonitor>,
@@ -2817,7 +2872,7 @@ mod tests {
 
                for _ in 0..node_count {
                        let feeest = Arc::new(test_utils::TestFeeEstimator { sat_per_kw: 253 });
-                       let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Arc::clone(&logger)));
+                       let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
                        let tx_broadcaster = Arc::new(test_utils::TestBroadcaster{txn_broadcasted: Mutex::new(Vec::new())});
                        let chan_monitor = Arc::new(test_utils::TestChannelMonitor::new(chain_monitor.clone(), tx_broadcaster.clone()));
                        let node_id = {
@@ -2826,8 +2881,8 @@ mod tests {
                                SecretKey::from_slice(&secp_ctx, &key_slice).unwrap()
                        };
                        let node = ChannelManager::new(node_id.clone(), 0, true, Network::Testnet, feeest.clone(), chan_monitor.clone(), chain_monitor.clone(), tx_broadcaster.clone(), Arc::clone(&logger)).unwrap();
-                       let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), Arc::clone(&logger));
-                       nodes.push(Node { feeest, chain_monitor, tx_broadcaster, chan_monitor, node, router });
+                       let router = Router::new(PublicKey::from_secret_key(&secp_ctx, &node_id), chain_monitor.clone(), Arc::clone(&logger));
+                       nodes.push(Node { chain_monitor, tx_broadcaster, chan_monitor, node, router });
                }
 
                nodes
@@ -3236,4 +3291,78 @@ mod tests {
                assert_eq!(channel_state.by_id.len(), 0);
                assert_eq!(channel_state.short_to_id.len(), 0);
        }
+
+       #[test]
+       fn test_invalid_channel_announcement() {
+               //Test BOLT 7 channel_announcement msg requirement for final node, gather data to build customed channel_announcement msgs
+               let secp_ctx = Secp256k1::new();
+               let nodes = create_network(2);
+
+               let chan_announcement = create_chan_between_nodes(&nodes[0], &nodes[1]);
+
+               let a_channel_lock = nodes[0].node.channel_state.lock().unwrap();
+               let b_channel_lock = nodes[1].node.channel_state.lock().unwrap();
+               let as_chan = a_channel_lock.by_id.get(&chan_announcement.3).unwrap();
+               let bs_chan = b_channel_lock.by_id.get(&chan_announcement.3).unwrap();
+
+               let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap() } );
+
+               let as_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &as_chan.get_local_keys().funding_key);
+               let bs_bitcoin_key = PublicKey::from_secret_key(&secp_ctx, &bs_chan.get_local_keys().funding_key);
+
+               let as_network_key = nodes[0].node.get_our_node_id();
+               let bs_network_key = nodes[1].node.get_our_node_id();
+
+               let were_node_one = as_bitcoin_key.serialize()[..] < bs_bitcoin_key.serialize()[..];
+
+               let mut chan_announcement;
+
+               macro_rules! dummy_unsigned_msg {
+                       () => {
+                               msgs::UnsignedChannelAnnouncement {
+                                       features: msgs::GlobalFeatures::new(),
+                                       chain_hash: genesis_block(Network::Testnet).header.bitcoin_hash(),
+                                       short_channel_id: as_chan.get_short_channel_id().unwrap(),
+                                       node_id_1: if were_node_one { as_network_key } else { bs_network_key },
+                                       node_id_2: if !were_node_one { bs_network_key } else { as_network_key },
+                                       bitcoin_key_1: if were_node_one { as_bitcoin_key } else { bs_bitcoin_key },
+                                       bitcoin_key_2: if !were_node_one { bs_bitcoin_key } else { as_bitcoin_key },
+                                       excess_data: Vec::new(),
+                               };
+                       }
+               }
+
+               macro_rules! sign_msg {
+                       ($unsigned_msg: expr) => {
+                               let msghash = Message::from_slice(&Sha256dHash::from_data(&$unsigned_msg.encode()[..])[..]).unwrap();
+                               let as_bitcoin_sig = secp_ctx.sign(&msghash, &as_chan.get_local_keys().funding_key);
+                               let bs_bitcoin_sig = secp_ctx.sign(&msghash, &bs_chan.get_local_keys().funding_key);
+                               let as_node_sig = secp_ctx.sign(&msghash, &nodes[0].node.our_network_key);
+                               let bs_node_sig = secp_ctx.sign(&msghash, &nodes[1].node.our_network_key);
+                               chan_announcement = msgs::ChannelAnnouncement {
+                                       node_signature_1 : if were_node_one { as_node_sig } else { bs_node_sig},
+                                       node_signature_2 : if !were_node_one { bs_node_sig } else { as_node_sig},
+                                       bitcoin_signature_1: if were_node_one { as_bitcoin_sig } else { bs_bitcoin_sig },
+                                       bitcoin_signature_2 : if !were_node_one { bs_bitcoin_sig } else { as_bitcoin_sig },
+                                       contents: $unsigned_msg
+                               }
+                       }
+               }
+
+               let unsigned_msg = dummy_unsigned_msg!();
+               sign_msg!(unsigned_msg);
+               assert_eq!(nodes[0].router.handle_channel_announcement(&chan_announcement).unwrap(), true);
+               let _ = nodes[0].router.handle_htlc_fail_channel_update(&msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id : as_chan.get_short_channel_id().unwrap() } );
+
+               // Configured with Network::Testnet
+               let mut unsigned_msg = dummy_unsigned_msg!();
+               unsigned_msg.chain_hash = genesis_block(Network::Bitcoin).header.bitcoin_hash();
+               sign_msg!(unsigned_msg);
+               assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err());
+
+               let mut unsigned_msg = dummy_unsigned_msg!();
+               unsigned_msg.chain_hash = Sha256dHash::from_data(&[1,2,3,4,5,6,7,8,9]);
+               sign_msg!(unsigned_msg);
+               assert!(nodes[0].router.handle_channel_announcement(&chan_announcement).is_err());
+       }
 }