Allow deserialization of new Channels before we've seen a block
[rust-lightning] / lightning / src / ln / channelmanager.rs
index fc521b345a641736d0c72a8f700b75e63a11bfd1..015894e594dc1246efecef452d312171eed099ba 100644 (file)
@@ -910,6 +910,9 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                Err(err) => {
                                        let error_code = match err {
                                                msgs::DecodeError::UnknownVersion => 0x4000 | 1, // unknown realm byte
+                                               msgs::DecodeError::UnknownRequiredFeature|
+                                               msgs::DecodeError::InvalidValue|
+                                               msgs::DecodeError::ShortRead => 0x4000 | 22, // invalid_onion_payload
                                                _ => 0x2000 | 2, // Should never happen
                                        };
                                        return_err!("Unable to decode our hop data", error_code, &[0;0]);
@@ -917,7 +920,7 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                Ok(msg) => {
                                        let mut hmac = [0; 32];
                                        if let Err(_) = chacha_stream.read_exact(&mut hmac[..]) {
-                                               return_err!("Unable to decode hop data", 0x4000 | 1, &[0;0]);
+                                               return_err!("Unable to decode hop data", 0x4000 | 22, &[0;0]);
                                        }
                                        (msg, hmac)
                                },
@@ -971,6 +974,15 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                        } else {
                                let mut new_packet_data = [0; 20*65];
                                let read_pos = chacha_stream.read(&mut new_packet_data).unwrap();
+                               #[cfg(debug_assertions)]
+                               {
+                                       // Check two things:
+                                       // a) that the behavior of our stream here will return Ok(0) even if the TLV
+                                       //    read above emptied out our buffer and the unwrap() wont needlessly panic
+                                       // b) that we didn't somehow magically end up with extra data.
+                                       let mut t = [0; 1];
+                                       debug_assert!(chacha_stream.read(&mut t).unwrap() == 0);
+                               }
                                // Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we
                                // fill the onion hop data we'll forward to our next-hop peer.
                                chacha_stream.chacha.process_in_place(&mut new_packet_data[read_pos..]);
@@ -995,10 +1007,18 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                                        hmac: next_hop_hmac.clone(),
                                };
 
+                               let short_channel_id = match next_hop_data.format {
+                                       msgs::OnionHopDataFormat::Legacy { short_channel_id } => short_channel_id,
+                                       msgs::OnionHopDataFormat::NonFinalNode { short_channel_id } => short_channel_id,
+                                       msgs::OnionHopDataFormat::FinalNode => {
+                                               return_err!("Final Node OnionHopData provided for us as an intermediary node", 0x4000 | 22, &[0;0]);
+                                       },
+                               };
+
                                PendingHTLCStatus::Forward(PendingForwardHTLCInfo {
                                        onion_packet: Some(outgoing_packet),
                                        payment_hash: msg.payment_hash.clone(),
-                                       short_channel_id: next_hop_data.short_channel_id,
+                                       short_channel_id: short_channel_id,
                                        incoming_shared_secret: shared_secret,
                                        amt_to_forward: next_hop_data.amt_to_forward,
                                        outgoing_cltv_value: next_hop_data.outgoing_cltv_value,
@@ -1143,6 +1163,9 @@ impl<ChanSigner: ChannelKeys, M: Deref> ChannelManager<ChanSigner, M> where M::T
                let onion_keys = secp_call!(onion_utils::construct_onion_keys(&self.secp_ctx, &route, &session_priv),
                                APIError::RouteError{err: "Pubkey along hop was maliciously selected"});
                let (onion_payloads, htlc_msat, htlc_cltv) = onion_utils::build_onion_payloads(&route, cur_height)?;
+               if onion_utils::route_size_insane(&onion_payloads) {
+                       return Err(APIError::RouteError{err: "Route size too large considering onion data"});
+               }
                let onion_packet = onion_utils::construct_onion_packet(onion_payloads, onion_keys, prng_seed, &payment_hash);
 
                let _ = self.total_consistency_lock.read().unwrap();
@@ -3287,7 +3310,7 @@ impl<'a, R : ::std::io::Read, ChanSigner: ChannelKeys + Readable<R>, M: Deref> R
                let mut short_to_id = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
                for _ in 0..channel_count {
                        let mut channel: Channel<ChanSigner> = ReadableArgs::read(reader, args.logger.clone())?;
-                       if channel.last_block_connected != last_block_hash {
+                       if channel.last_block_connected != Default::default() && channel.last_block_connected != last_block_hash {
                                return Err(DecodeError::InvalidValue);
                        }