Relicense as dual Apache-2.0 + MIT
[rust-lightning] / lightning / src / routing / network_graph.rs
index fedfad79fe6381a408207b63c3c2d0638793d3fc..89c19b84896bdb37c4644322871131461bf8354c 100644 (file)
@@ -1,3 +1,12 @@
+// This file is Copyright its original authors, visible in version control
+// history.
+//
+// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
+// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
+// You may not use this file except in accordance with one or both of these
+// licenses.
+
 //! The top-level network map tracking logic lives here.
 
 use bitcoin::secp256k1::key::PublicKey;
@@ -11,39 +20,40 @@ use bitcoin::blockdata::opcodes;
 
 use chain::chaininterface::{ChainError, ChainWatchInterface};
 use ln::features::{ChannelFeatures, NodeFeatures};
-use ln::msgs::{DecodeError,ErrorAction,LightningError,RoutingMessageHandler,NetAddress};
+use ln::msgs::{DecodeError, ErrorAction, LightningError, RoutingMessageHandler, NetAddress, OptionalField, MAX_VALUE_MSAT};
 use ln::msgs;
 use util::ser::{Writeable, Readable, Writer};
 use util::logger::Logger;
 
-use std::cmp;
-use std::sync::{RwLock,Arc};
+use std::{cmp, fmt};
+use std::sync::RwLock;
 use std::sync::atomic::{AtomicUsize, Ordering};
 use std::collections::BTreeMap;
 use std::collections::btree_map::Entry as BtreeEntry;
-use std;
+use std::ops::Deref;
+use bitcoin::hashes::hex::ToHex;
 
 /// Receives and validates network updates from peers,
 /// stores authentic and relevant data as a network graph.
 /// This network graph is then used for routing payments.
 /// Provides interface to help with initial routing sync by
 /// serving historical announcements.
-pub struct NetGraphMsgHandler {
+pub struct NetGraphMsgHandler<C: Deref, L: Deref> where C::Target: ChainWatchInterface, L::Target: Logger {
        secp_ctx: Secp256k1<secp256k1::VerifyOnly>,
        /// Representation of the payment channel network
        pub network_graph: RwLock<NetworkGraph>,
-       chain_monitor: Arc<ChainWatchInterface>,
+       chain_monitor: C,
        full_syncs_requested: AtomicUsize,
-       logger: Arc<Logger>,
+       logger: L,
 }
 
-impl NetGraphMsgHandler {
+impl<C: Deref, L: Deref> NetGraphMsgHandler<C, L> where C::Target: ChainWatchInterface, L::Target: Logger {
        /// Creates a new tracker of the actual state of the network of channels and nodes,
        /// assuming a fresh network graph.
        /// Chain monitor is used to make sure announced channels exist on-chain,
        /// channel data is correct, and that the announcement is signed with
        /// channel owners' keys.
-       pub fn new(chain_monitor: Arc<ChainWatchInterface>, logger: Arc<Logger>) -> Self {
+       pub fn new(chain_monitor: C, logger: L) -> Self {
                NetGraphMsgHandler {
                        secp_ctx: Secp256k1::verification_only(),
                        network_graph: RwLock::new(NetworkGraph {
@@ -52,19 +62,19 @@ impl NetGraphMsgHandler {
                        }),
                        full_syncs_requested: AtomicUsize::new(0),
                        chain_monitor,
-                       logger: logger.clone(),
+                       logger,
                }
        }
 
        /// Creates a new tracker of the actual state of the network of channels and nodes,
        /// assuming an existing Network Graph.
-       pub fn from_net_graph(chain_monitor: Arc<ChainWatchInterface>, logger: Arc<Logger>, network_graph: RwLock<NetworkGraph>) -> Self {
+       pub fn from_net_graph(chain_monitor: C, logger: L, network_graph: NetworkGraph) -> Self {
                NetGraphMsgHandler {
                        secp_ctx: Secp256k1::verification_only(),
-                       network_graph: network_graph,
+                       network_graph: RwLock::new(network_graph),
                        full_syncs_requested: AtomicUsize::new(0),
                        chain_monitor,
-                       logger: logger.clone(),
+                       logger,
                }
        }
 }
@@ -74,48 +84,48 @@ macro_rules! secp_verify_sig {
        ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => {
                match $secp_ctx.verify($msg, $sig, $pubkey) {
                        Ok(_) => {},
-                       Err(_) => return Err(LightningError{err: "Invalid signature from remote node", action: ErrorAction::IgnoreError}),
+                       Err(_) => return Err(LightningError{err: "Invalid signature from remote node".to_owned(), action: ErrorAction::IgnoreError}),
                }
        };
 }
 
-impl RoutingMessageHandler for NetGraphMsgHandler {
+impl<C: Deref + Sync + Send, L: Deref + Sync + Send> RoutingMessageHandler for NetGraphMsgHandler<C, L> where C::Target: ChainWatchInterface, L::Target: Logger {
        fn handle_node_announcement(&self, msg: &msgs::NodeAnnouncement) -> Result<bool, LightningError> {
                self.network_graph.write().unwrap().update_node_from_announcement(msg, Some(&self.secp_ctx))
        }
 
        fn handle_channel_announcement(&self, msg: &msgs::ChannelAnnouncement) -> Result<bool, LightningError> {
                if msg.contents.node_id_1 == msg.contents.node_id_2 || msg.contents.bitcoin_key_1 == msg.contents.bitcoin_key_2 {
-                       return Err(LightningError{err: "Channel announcement node had a channel with itself", action: ErrorAction::IgnoreError});
+                       return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError});
                }
 
-               let checked_utxo = match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) {
-                       Ok((script_pubkey, _value)) => {
+               let utxo_value = match self.chain_monitor.get_chain_utxo(msg.contents.chain_hash, msg.contents.short_channel_id) {
+                       Ok((script_pubkey, value)) => {
                                let expected_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2)
                                                                    .push_slice(&msg.contents.bitcoin_key_1.serialize())
                                                                    .push_slice(&msg.contents.bitcoin_key_2.serialize())
                                                                    .push_opcode(opcodes::all::OP_PUSHNUM_2)
                                                                    .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh();
                                if script_pubkey != expected_script {
-                                       return Err(LightningError{err: "Channel announcement keys didn't match on-chain script", action: ErrorAction::IgnoreError});
+                                       return Err(LightningError{err: format!("Channel announcement key ({}) didn't match on-chain script ({})", script_pubkey.to_hex(), expected_script.to_hex()), action: ErrorAction::IgnoreError});
                                }
                                //TODO: Check if value is worth storing, use it to inform routing, and compare it
                                //to the new HTLC max field in channel_update
-                               true
+                               Some(value)
                        },
                        Err(ChainError::NotSupported) => {
                                // Tentatively accept, potentially exposing us to DoS attacks
-                               false
+                               None
                        },
                        Err(ChainError::NotWatched) => {
-                               return Err(LightningError{err: "Channel announced on an unknown chain", action: ErrorAction::IgnoreError});
+                               return Err(LightningError{err: format!("Channel announced on an unknown chain ({})", msg.contents.chain_hash.encode().to_hex()), action: ErrorAction::IgnoreError});
                        },
                        Err(ChainError::UnknownTx) => {
-                               return Err(LightningError{err: "Channel announced without corresponding UTXO entry", action: ErrorAction::IgnoreError});
+                               return Err(LightningError{err: "Channel announced without corresponding UTXO entry".to_owned(), action: ErrorAction::IgnoreError});
                        },
                };
-               let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, checked_utxo, Some(&self.secp_ctx));
-               log_trace!(self, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
+               let result = self.network_graph.write().unwrap().update_channel_from_announcement(msg, utxo_value, Some(&self.secp_ctx));
+               log_trace!(self.logger, "Added channel_announcement for {}{}", msg.contents.short_channel_id, if !msg.contents.excess_data.is_empty() { " with excess uninterpreted data!" } else { "" });
                result
        }
 
@@ -124,11 +134,11 @@ impl RoutingMessageHandler for NetGraphMsgHandler {
                        &msgs::HTLCFailChannelUpdate::ChannelUpdateMessage { ref msg } => {
                                let _ = self.network_graph.write().unwrap().update_channel(msg, Some(&self.secp_ctx));
                        },
-                       &msgs::HTLCFailChannelUpdate::ChannelClosed { ref short_channel_id, ref is_permanent } => {
-                               self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, &is_permanent);
+                       &msgs::HTLCFailChannelUpdate::ChannelClosed { short_channel_id, is_permanent } => {
+                               self.network_graph.write().unwrap().close_channel_from_update(short_channel_id, is_permanent);
                        },
-                       &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, ref is_permanent } => {
-                               self.network_graph.write().unwrap().fail_node(node_id, &is_permanent);
+                       &msgs::HTLCFailChannelUpdate::NodeFailure { ref node_id, is_permanent } => {
+                               self.network_graph.write().unwrap().fail_node(node_id, is_permanent);
                        },
                }
        }
@@ -214,6 +224,8 @@ pub struct DirectionalChannelInfo {
        pub cltv_expiry_delta: u16,
        /// The minimum value, which must be relayed to the next hop via the channel
        pub htlc_minimum_msat: u64,
+       /// The maximum value which may be relayed to the next hop via the channel.
+       pub htlc_maximum_msat: Option<u64>,
        /// Fees charged when the channel is used for routing
        pub fees: RoutingFees,
        /// Most recent update for the channel received from the network
@@ -223,8 +235,8 @@ pub struct DirectionalChannelInfo {
        pub last_update_message: Option<msgs::ChannelUpdate>,
 }
 
-impl std::fmt::Display for DirectionalChannelInfo {
-       fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for DirectionalChannelInfo {
+       fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                write!(f, "last_update {}, enabled {}, cltv_expiry_delta {}, htlc_minimum_msat {}, fees {:?}", self.last_update, self.enabled, self.cltv_expiry_delta, self.htlc_minimum_msat, self.fees)?;
                Ok(())
        }
@@ -235,6 +247,7 @@ impl_writeable!(DirectionalChannelInfo, 0, {
        enabled,
        cltv_expiry_delta,
        htlc_minimum_msat,
+       htlc_maximum_msat,
        fees,
        last_update_message
 });
@@ -253,6 +266,8 @@ pub struct ChannelInfo {
        pub node_two: PublicKey,
        /// Details about the second direction of a channel
        pub two_to_one: Option<DirectionalChannelInfo>,
+       /// The channel capacity as seen on-chain, if chain lookup is available.
+       pub capacity_sats: Option<u64>,
        /// An initial announcement of the channel
        /// Mostly redundant with the data we store in fields explicitly.
        /// Everything else is useful only for sending out for initial routing sync.
@@ -260,8 +275,8 @@ pub struct ChannelInfo {
        pub announcement_message: Option<msgs::ChannelAnnouncement>,
 }
 
-impl std::fmt::Display for ChannelInfo {
-       fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for ChannelInfo {
+       fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                write!(f, "features: {}, node_one: {}, one_to_two: {:?}, node_two: {}, two_to_one: {:?}",
                   log_bytes!(self.features.encode()), log_pubkey!(self.node_one), self.one_to_two, log_pubkey!(self.node_two), self.two_to_one)?;
                Ok(())
@@ -274,6 +289,7 @@ impl_writeable!(ChannelInfo, 0, {
        one_to_two,
        node_two,
        two_to_one,
+       capacity_sats,
        announcement_message
 });
 
@@ -388,8 +404,8 @@ pub struct NodeInfo {
        pub announcement_info: Option<NodeAnnouncementInfo>
 }
 
-impl std::fmt::Display for NodeInfo {
-       fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for NodeInfo {
+       fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                write!(f, "lowest_inbound_channel_fees: {:?}, channels: {:?}, announcement_info: {:?}",
                   self.lowest_inbound_channel_fees, &self.channels[..], self.announcement_info)?;
                Ok(())
@@ -473,8 +489,8 @@ impl Readable for NetworkGraph {
        }
 }
 
-impl std::fmt::Display for NetworkGraph {
-       fn fmt(&self, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> {
+impl fmt::Display for NetworkGraph {
+       fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
                write!(f, "Network map\n[Channels]\n")?;
                for (key, val) in self.channels.iter() {
                        write!(f, " {}: {}\n", key, val)?;
@@ -505,6 +521,14 @@ impl NetworkGraph {
                None
        }
 
+       /// Creates a new, empty, network graph.
+       pub fn new() -> NetworkGraph {
+               Self {
+                       channels: BTreeMap::new(),
+                       nodes: BTreeMap::new(),
+               }
+       }
+
        /// For an already known node (from channel announcements), update its stored properties from a given node announcement
        /// Announcement signatures are checked here only if Secp256k1 object is provided.
        fn update_node_from_announcement(&mut self, msg: &msgs::NodeAnnouncement, secp_ctx: Option<&Secp256k1<secp256k1::VerifyOnly>>) -> Result<bool, LightningError> {
@@ -514,11 +538,11 @@ impl NetworkGraph {
                }
 
                match self.nodes.get_mut(&msg.contents.node_id) {
-                       None => Err(LightningError{err: "No existing channels for node_announcement", action: ErrorAction::IgnoreError}),
+                       None => Err(LightningError{err: "No existing channels for node_announcement".to_owned(), action: ErrorAction::IgnoreError}),
                        Some(node) => {
                                if let Some(node_info) = node.announcement_info.as_ref() {
                                        if node_info.last_update  >= msg.contents.timestamp {
-                                               return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
+                                               return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError});
                                        }
                                }
 
@@ -543,7 +567,7 @@ impl NetworkGraph {
        /// which is probably result of a reorg. In that case, we update channel info only if the
        /// utxo was checked, otherwise stick to the existing update, to prevent DoS risks.
        /// Announcement signatures are checked here only if Secp256k1 object is provided.
-       fn update_channel_from_announcement(&mut self, msg: &msgs::ChannelAnnouncement, checked_utxo: bool, secp_ctx: Option<&Secp256k1<secp256k1::VerifyOnly>>) -> Result<bool, LightningError> {
+       fn update_channel_from_announcement(&mut self, msg: &msgs::ChannelAnnouncement, utxo_value: Option<u64>, secp_ctx: Option<&Secp256k1<secp256k1::VerifyOnly>>) -> Result<bool, LightningError> {
                if let Some(sig_verifier) = secp_ctx {
                        let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
                        secp_verify_sig!(sig_verifier, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1);
@@ -560,6 +584,7 @@ impl NetworkGraph {
                                one_to_two: None,
                                node_two: msg.contents.node_id_2.clone(),
                                two_to_one: None,
+                               capacity_sats: utxo_value,
                                announcement_message: if should_relay { Some(msg.clone()) } else { None },
                        };
 
@@ -568,7 +593,7 @@ impl NetworkGraph {
                                //TODO: because asking the blockchain if short_channel_id is valid is only optional
                                //in the blockchain API, we need to handle it smartly here, though it's unclear
                                //exactly how...
-                               if checked_utxo {
+                               if utxo_value.is_some() {
                                        // Either our UTXO provider is busted, there was a reorg, or the UTXO provider
                                        // only sometimes returns results. In any case remove the previous entry. Note
                                        // that the spec expects us to "blacklist" the node_ids involved, but we can't
@@ -580,7 +605,7 @@ impl NetworkGraph {
                                        Self::remove_channel_in_nodes(&mut self.nodes, &entry.get(), msg.contents.short_channel_id);
                                        *entry.get_mut() = chan_info;
                                } else {
-                                       return Err(LightningError{err: "Already have knowledge of channel", action: ErrorAction::IgnoreError})
+                                       return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreError})
                                }
                        },
                        BtreeEntry::Vacant(entry) => {
@@ -615,10 +640,10 @@ impl NetworkGraph {
        /// If permanent, removes a channel from the local storage.
        /// May cause the removal of nodes too, if this was their last channel.
        /// If not permanent, makes channels unavailable for routing.
-       pub fn close_channel_from_update(&mut self, short_channel_id: &u64, is_permanent: &bool) {
-               if *is_permanent {
-                       if let Some(chan) = self.channels.remove(short_channel_id) {
-                               Self::remove_channel_in_nodes(&mut self.nodes, &chan, *short_channel_id);
+       pub fn close_channel_from_update(&mut self, short_channel_id: u64, is_permanent: bool) {
+               if is_permanent {
+                       if let Some(chan) = self.channels.remove(&short_channel_id) {
+                               Self::remove_channel_in_nodes(&mut self.nodes, &chan, short_channel_id);
                        }
                } else {
                        if let Some(chan) = self.channels.get_mut(&short_channel_id) {
@@ -632,8 +657,8 @@ impl NetworkGraph {
                }
        }
 
-       fn fail_node(&mut self, _node_id: &PublicKey, is_permanent: &bool) {
-               if *is_permanent {
+       fn fail_node(&mut self, _node_id: &PublicKey, is_permanent: bool) {
+               if is_permanent {
                        // TODO: Wholly remove the node
                } else {
                        // TODO: downgrade the node
@@ -648,13 +673,26 @@ impl NetworkGraph {
                let chan_was_enabled;
 
                match self.channels.get_mut(&msg.contents.short_channel_id) {
-                       None => return Err(LightningError{err: "Couldn't find channel for update", action: ErrorAction::IgnoreError}),
+                       None => return Err(LightningError{err: "Couldn't find channel for update".to_owned(), action: ErrorAction::IgnoreError}),
                        Some(channel) => {
+                               if let OptionalField::Present(htlc_maximum_msat) = msg.contents.htlc_maximum_msat {
+                                       if htlc_maximum_msat > MAX_VALUE_MSAT {
+                                               return Err(LightningError{err: "htlc_maximum_msat is larger than maximum possible msats".to_owned(), action: ErrorAction::IgnoreError});
+                                       }
+
+                                       if let Some(capacity_sats) = channel.capacity_sats {
+                                               // It's possible channel capacity is available now, although it wasn't available at announcement (so the field is None).
+                                               // Don't query UTXO set here to reduce DoS risks.
+                                               if htlc_maximum_msat > capacity_sats * 1000 {
+                                                       return Err(LightningError{err: "htlc_maximum_msat is larger than channel capacity".to_owned(), action: ErrorAction::IgnoreError});
+                                               }
+                                       }
+                               }
                                macro_rules! maybe_update_channel_info {
                                        ( $target: expr, $src_node: expr) => {
                                                if let Some(existing_chan_info) = $target.as_ref() {
                                                        if existing_chan_info.last_update >= msg.contents.timestamp {
-                                                               return Err(LightningError{err: "Update older than last processed update", action: ErrorAction::IgnoreError});
+                                                               return Err(LightningError{err: "Update older than last processed update".to_owned(), action: ErrorAction::IgnoreError});
                                                        }
                                                        chan_was_enabled = existing_chan_info.enabled;
                                                } else {
@@ -672,6 +710,7 @@ impl NetworkGraph {
                                                        last_update: msg.contents.timestamp,
                                                        cltv_expiry_delta: msg.contents.cltv_expiry_delta,
                                                        htlc_minimum_msat: msg.contents.htlc_minimum_msat,
+                                                       htlc_maximum_msat: if let OptionalField::Present(max_value) = msg.contents.htlc_maximum_msat { Some(max_value) } else { None },
                                                        fees: RoutingFees {
                                                                base_msat: msg.contents.fee_base_msat,
                                                                proportional_millionths: msg.contents.fee_proportional_millionths,
@@ -712,7 +751,7 @@ impl NetworkGraph {
                                proportional_millionths
                        });
                } else if chan_was_enabled {
-                       let mut node = self.nodes.get_mut(&dest_node_id).unwrap();
+                       let node = self.nodes.get_mut(&dest_node_id).unwrap();
                        let mut lowest_inbound_channel_fees = None;
 
                        for chan_id in node.channels.iter() {
@@ -765,8 +804,9 @@ mod tests {
        use chain::chaininterface;
        use ln::features::{ChannelFeatures, NodeFeatures};
        use routing::network_graph::{NetGraphMsgHandler, NetworkGraph};
-       use ln::msgs::{RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
-               UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, HTLCFailChannelUpdate};
+       use ln::msgs::{OptionalField, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
+               UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, HTLCFailChannelUpdate,
+               MAX_VALUE_MSAT};
        use util::test_utils;
        use util::logger::Logger;
        use util::ser::{Readable, Writeable};
@@ -786,10 +826,10 @@ mod tests {
 
        use std::sync::Arc;
 
-       fn create_net_graph_msg_handler() -> (Secp256k1<All>, NetGraphMsgHandler) {
+       fn create_net_graph_msg_handler() -> (Secp256k1<All>, NetGraphMsgHandler<Arc<chaininterface::ChainWatchInterfaceUtil>, Arc<test_utils::TestLogger>>) {
                let secp_ctx = Secp256k1::new();
-               let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
-               let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet, Arc::clone(&logger)));
+               let logger = Arc::new(test_utils::TestLogger::new());
+               let chain_monitor = Arc::new(chaininterface::ChainWatchInterfaceUtil::new(Network::Testnet));
                let net_graph_msg_handler = NetGraphMsgHandler::new(chain_monitor, Arc::clone(&logger));
                (secp_ctx, net_graph_msg_handler)
        }
@@ -1101,7 +1141,11 @@ mod tests {
 
        #[test]
        fn handling_channel_update() {
-               let (secp_ctx, net_graph_msg_handler) = create_net_graph_msg_handler();
+               let secp_ctx = Secp256k1::new();
+               let logger: Arc<Logger> = Arc::new(test_utils::TestLogger::new());
+               let chain_monitor = Arc::new(test_utils::TestChainWatcher::new());
+               let net_graph_msg_handler = NetGraphMsgHandler::new(chain_monitor.clone(), Arc::clone(&logger));
+
                let node_1_privkey = &SecretKey::from_slice(&[42; 32]).unwrap();
                let node_2_privkey = &SecretKey::from_slice(&[41; 32]).unwrap();
                let node_id_1 = PublicKey::from_secret_key(&secp_ctx, node_1_privkey);
@@ -1112,8 +1156,16 @@ mod tests {
                let zero_hash = Sha256dHash::hash(&[0; 32]);
                let short_channel_id = 0;
                let chain_hash = genesis_block(Network::Testnet).header.bitcoin_hash();
+               let amount_sats = 1000_000;
+
                {
                        // Announce a channel we will update
+                       let good_script = Builder::new().push_opcode(opcodes::all::OP_PUSHNUM_2)
+                          .push_slice(&PublicKey::from_secret_key(&secp_ctx, node_1_btckey).serialize())
+                          .push_slice(&PublicKey::from_secret_key(&secp_ctx, node_2_btckey).serialize())
+                          .push_opcode(opcodes::all::OP_PUSHNUM_2)
+                          .push_opcode(opcodes::all::OP_CHECKMULTISIG).into_script().to_v0_p2wsh();
+                       *chain_monitor.utxo_ret.lock().unwrap() = Ok((good_script.clone(), amount_sats));
                        let unsigned_announcement = UnsignedChannelAnnouncement {
                                features: ChannelFeatures::empty(),
                                chain_hash,
@@ -1147,6 +1199,7 @@ mod tests {
                        flags: 0,
                        cltv_expiry_delta: 144,
                        htlc_minimum_msat: 1000000,
+                       htlc_maximum_msat: OptionalField::Absent,
                        fee_base_msat: 10000,
                        fee_proportional_millionths: 20,
                        excess_data: Vec::new()
@@ -1185,6 +1238,7 @@ mod tests {
                        Ok(res) => assert!(!res),
                        _ => panic!()
                };
+               unsigned_channel_update.timestamp += 10;
 
                unsigned_channel_update.short_channel_id += 1;
                let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
@@ -1199,6 +1253,31 @@ mod tests {
                };
                unsigned_channel_update.short_channel_id = short_channel_id;
 
+               unsigned_channel_update.htlc_maximum_msat = OptionalField::Present(MAX_VALUE_MSAT + 1);
+               let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
+               let valid_channel_update = ChannelUpdate {
+                       signature: secp_ctx.sign(&msghash, node_1_privkey),
+                       contents: unsigned_channel_update.clone()
+               };
+
+               match net_graph_msg_handler.handle_channel_update(&valid_channel_update) {
+                       Ok(_) => panic!(),
+                       Err(e) => assert_eq!(e.err, "htlc_maximum_msat is larger than maximum possible msats")
+               };
+               unsigned_channel_update.htlc_maximum_msat = OptionalField::Absent;
+
+               unsigned_channel_update.htlc_maximum_msat = OptionalField::Present(amount_sats * 1000 + 1);
+               let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
+               let valid_channel_update = ChannelUpdate {
+                       signature: secp_ctx.sign(&msghash, node_1_privkey),
+                       contents: unsigned_channel_update.clone()
+               };
+
+               match net_graph_msg_handler.handle_channel_update(&valid_channel_update) {
+                       Ok(_) => panic!(),
+                       Err(e) => assert_eq!(e.err, "htlc_maximum_msat is larger than channel capacity")
+               };
+               unsigned_channel_update.htlc_maximum_msat = OptionalField::Absent;
 
                // Even though previous update was not relayed further, we still accepted it,
                // so we now won't accept update before the previous one.
@@ -1280,6 +1359,7 @@ mod tests {
                                flags: 0,
                                cltv_expiry_delta: 144,
                                htlc_minimum_msat: 1000000,
+                               htlc_maximum_msat: OptionalField::Absent,
                                fee_base_msat: 10000,
                                fee_proportional_millionths: 20,
                                excess_data: Vec::new()
@@ -1407,6 +1487,7 @@ mod tests {
                                flags: 0,
                                cltv_expiry_delta: 144,
                                htlc_minimum_msat: 1000000,
+                               htlc_maximum_msat: OptionalField::Absent,
                                fee_base_msat: 10000,
                                fee_proportional_millionths: 20,
                                excess_data: Vec::new()
@@ -1443,6 +1524,7 @@ mod tests {
                                flags: 0,
                                cltv_expiry_delta: 144,
                                htlc_minimum_msat: 1000000,
+                               htlc_maximum_msat: OptionalField::Absent,
                                fee_base_msat: 10000,
                                fee_proportional_millionths: 20,
                                excess_data: [1; 3].to_vec()