Allow building of a route from given hops
[rust-lightning] / lightning / src / routing / network_graph.rs
index 282c87051dd48f2c3b3a82db778cc20a78f7e2c5..26719cc279061f180f5617f204846922271f3f3b 100644 (file)
@@ -10,7 +10,7 @@
 //! The top-level network map tracking logic lives here.
 
 use bitcoin::secp256k1::constants::PUBLIC_KEY_SIZE;
-use bitcoin::secp256k1::key::PublicKey;
+use bitcoin::secp256k1::PublicKey;
 use bitcoin::secp256k1::Secp256k1;
 use bitcoin::secp256k1;
 
@@ -67,7 +67,7 @@ impl NodeId {
        pub fn from_pubkey(pubkey: &PublicKey) -> Self {
                NodeId(pubkey.serialize())
        }
-       
+
        /// Get the public key slice from this NodeId
        pub fn as_slice(&self) -> &[u8] {
                &self.0
@@ -150,7 +150,7 @@ pub struct ReadOnlyNetworkGraph<'a> {
 /// Update to the [`NetworkGraph`] based on payment failure information conveyed via the Onion
 /// return packet by a node along the route. See [BOLT #4] for details.
 ///
-/// [BOLT #4]: https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md
+/// [BOLT #4]: https://github.com/lightning/bolts/blob/master/04-onion-routing.md
 #[derive(Clone, Debug, PartialEq)]
 pub enum NetworkUpdate {
        /// An error indicating a `channel_update` messages should be applied via
@@ -295,7 +295,7 @@ where C::Target: chain::Access, L::Target: Logger
 
 macro_rules! secp_verify_sig {
        ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr, $msg_type: expr ) => {
-               match $secp_ctx.verify($msg, $sig, $pubkey) {
+               match $secp_ctx.verify_ecdsa($msg, $sig, $pubkey) {
                        Ok(_) => {},
                        Err(_) => {
                                return Err(LightningError {
@@ -695,7 +695,7 @@ impl ChannelInfo {
                                return None;
                        }
                };
-               Some((DirectedChannelInfo { channel: self, direction }, source))
+               Some((DirectedChannelInfo::new(self, direction), source))
        }
 
        /// Returns a [`DirectedChannelInfo`] for the channel directed from the given `source` to a
@@ -710,7 +710,17 @@ impl ChannelInfo {
                                return None;
                        }
                };
-               Some((DirectedChannelInfo { channel: self, direction }, target))
+               Some((DirectedChannelInfo::new(self, direction), target))
+       }
+
+       /// Returns a [`ChannelUpdateInfo`] based on the direction implied by the channel_flag.
+       pub fn get_directional_info(&self, channel_flags: u8) -> Option<&ChannelUpdateInfo> {
+               let direction = channel_flags & 1u8;
+               if direction == 0 {
+                       self.one_to_two.as_ref()
+               } else {
+                       self.two_to_one.as_ref()
+               }
        }
 }
 
@@ -739,35 +749,53 @@ impl_writeable_tlv_based!(ChannelInfo, {
 pub struct DirectedChannelInfo<'a> {
        channel: &'a ChannelInfo,
        direction: Option<&'a ChannelUpdateInfo>,
+       htlc_maximum_msat: u64,
+       effective_capacity: EffectiveCapacity,
 }
 
 impl<'a> DirectedChannelInfo<'a> {
+       #[inline]
+       fn new(channel: &'a ChannelInfo, direction: Option<&'a ChannelUpdateInfo>) -> Self {
+               let htlc_maximum_msat = direction.and_then(|direction| direction.htlc_maximum_msat);
+               let capacity_msat = channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
+
+               let (htlc_maximum_msat, effective_capacity) = match (htlc_maximum_msat, capacity_msat) {
+                       (Some(amount_msat), Some(capacity_msat)) => {
+                               let htlc_maximum_msat = cmp::min(amount_msat, capacity_msat);
+                               (htlc_maximum_msat, EffectiveCapacity::Total { capacity_msat })
+                       },
+                       (Some(amount_msat), None) => {
+                               (amount_msat, EffectiveCapacity::MaximumHTLC { amount_msat })
+                       },
+                       (None, Some(capacity_msat)) => {
+                               (capacity_msat, EffectiveCapacity::Total { capacity_msat })
+                       },
+                       (None, None) => (EffectiveCapacity::Unknown.as_msat(), EffectiveCapacity::Unknown),
+               };
+
+               Self {
+                       channel, direction, htlc_maximum_msat, effective_capacity
+               }
+       }
+
        /// Returns information for the channel.
        pub fn channel(&self) -> &'a ChannelInfo { self.channel }
 
        /// Returns information for the direction.
        pub fn direction(&self) -> Option<&'a ChannelUpdateInfo> { self.direction }
 
+       /// Returns the maximum HTLC amount allowed over the channel in the direction.
+       pub fn htlc_maximum_msat(&self) -> u64 {
+               self.htlc_maximum_msat
+       }
+
        /// Returns the [`EffectiveCapacity`] of the channel in the direction.
        ///
        /// This is either the total capacity from the funding transaction, if known, or the
        /// `htlc_maximum_msat` for the direction as advertised by the gossip network, if known,
-       /// whichever is smaller.
+       /// otherwise.
        pub fn effective_capacity(&self) -> EffectiveCapacity {
-               let capacity_msat = self.channel.capacity_sats.map(|capacity_sats| capacity_sats * 1000);
-               self.direction
-                       .and_then(|direction| direction.htlc_maximum_msat)
-                       .map(|max_htlc_msat| {
-                               let capacity_msat = capacity_msat.unwrap_or(u64::max_value());
-                               if max_htlc_msat < capacity_msat {
-                                       EffectiveCapacity::MaximumHTLC { amount_msat: max_htlc_msat }
-                               } else {
-                                       EffectiveCapacity::Total { capacity_msat }
-                               }
-                       })
-                       .or_else(|| capacity_msat.map(|capacity_msat|
-                                       EffectiveCapacity::Total { capacity_msat }))
-                       .unwrap_or(EffectiveCapacity::Unknown)
+               self.effective_capacity
        }
 
        /// Returns `Some` if [`ChannelUpdateInfo`] is available in the direction.
@@ -805,6 +833,10 @@ impl<'a> DirectedChannelInfoWithUpdate<'a> {
        /// Returns the [`EffectiveCapacity`] of the channel in the direction.
        #[inline]
        pub(super) fn effective_capacity(&self) -> EffectiveCapacity { self.inner.effective_capacity() }
+
+       /// Returns the maximum HTLC amount allowed over the channel in the direction.
+       #[inline]
+       pub(super) fn htlc_maximum_msat(&self) -> u64 { self.inner.htlc_maximum_msat() }
 }
 
 impl<'a> fmt::Debug for DirectedChannelInfoWithUpdate<'a> {
@@ -817,6 +849,7 @@ impl<'a> fmt::Debug for DirectedChannelInfoWithUpdate<'a> {
 ///
 /// While this may be smaller than the actual channel capacity, amounts greater than
 /// [`Self::as_msat`] should not be routed through the channel.
+#[derive(Clone, Copy)]
 pub enum EffectiveCapacity {
        /// The available liquidity in the channel known from being a channel counterparty, and thus a
        /// direct hop.
@@ -1033,6 +1066,15 @@ impl NetworkGraph {
                }
        }
 
+       /// Clears the `NodeAnnouncementInfo` field for all nodes in the `NetworkGraph` for testing
+       /// purposes.
+       #[cfg(test)]
+       pub fn clear_nodes_announcement_info(&self) {
+               for node in self.nodes.write().unwrap().iter_mut() {
+                       node.1.announcement_info = None;
+               }
+       }
+
        /// For an already known node (from channel announcements), update its stored properties from a
        /// given node announcement.
        ///
@@ -1123,6 +1165,83 @@ impl NetworkGraph {
                self.update_channel_from_unsigned_announcement_intern(msg, None, chain_access)
        }
 
+       /// Update channel from partial announcement data received via rapid gossip sync
+       ///
+       /// `timestamp: u64`: Timestamp emulating the backdated original announcement receipt (by the
+       /// rapid gossip sync server)
+       ///
+       /// All other parameters as used in [`msgs::UnsignedChannelAnnouncement`] fields.
+       pub fn add_channel_from_partial_announcement(&self, short_channel_id: u64, timestamp: u64, features: ChannelFeatures, node_id_1: PublicKey, node_id_2: PublicKey) -> Result<(), LightningError> {
+               if node_id_1 == node_id_2 {
+                       return Err(LightningError{err: "Channel announcement node had a channel with itself".to_owned(), action: ErrorAction::IgnoreError});
+               };
+
+               let node_1 = NodeId::from_pubkey(&node_id_1);
+               let node_2 = NodeId::from_pubkey(&node_id_2);
+               let channel_info = ChannelInfo {
+                       features,
+                       node_one: node_1.clone(),
+                       one_to_two: None,
+                       node_two: node_2.clone(),
+                       two_to_one: None,
+                       capacity_sats: None,
+                       announcement_message: None,
+                       announcement_received_time: timestamp,
+               };
+
+               self.add_channel_between_nodes(short_channel_id, channel_info, None)
+       }
+
+       fn add_channel_between_nodes(&self, short_channel_id: u64, channel_info: ChannelInfo, utxo_value: Option<u64>) -> Result<(), LightningError> {
+               let mut channels = self.channels.write().unwrap();
+               let mut nodes = self.nodes.write().unwrap();
+
+               let node_id_a = channel_info.node_one.clone();
+               let node_id_b = channel_info.node_two.clone();
+
+               match channels.entry(short_channel_id) {
+                       BtreeEntry::Occupied(mut entry) => {
+                               //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 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
+                                       // do that because
+                                       // a) we don't *require* a UTXO provider that always returns results.
+                                       // b) we don't track UTXOs of channels we know about and remove them if they
+                                       //    get reorg'd out.
+                                       // c) it's unclear how to do so without exposing ourselves to massive DoS risk.
+                                       Self::remove_channel_in_nodes(&mut nodes, &entry.get(), short_channel_id);
+                                       *entry.get_mut() = channel_info;
+                               } else {
+                                       return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreDuplicateGossip});
+                               }
+                       },
+                       BtreeEntry::Vacant(entry) => {
+                               entry.insert(channel_info);
+                       }
+               };
+
+               for current_node_id in [node_id_a, node_id_b].iter() {
+                       match nodes.entry(current_node_id.clone()) {
+                               BtreeEntry::Occupied(node_entry) => {
+                                       node_entry.into_mut().channels.push(short_channel_id);
+                               },
+                               BtreeEntry::Vacant(node_entry) => {
+                                       node_entry.insert(NodeInfo {
+                                               channels: vec!(short_channel_id),
+                                               lowest_inbound_channel_fees: None,
+                                               announcement_info: None,
+                                       });
+                               }
+                       };
+               };
+
+               Ok(())
+       }
+
        fn update_channel_from_unsigned_announcement_intern<C: Deref>(
                &self, msg: &msgs::UnsignedChannelAnnouncement, full_msg: Option<&msgs::ChannelAnnouncement>, chain_access: &Option<C>
        ) -> Result<(), LightningError>
@@ -1171,65 +1290,18 @@ impl NetworkGraph {
                }
 
                let chan_info = ChannelInfo {
-                               features: msg.features.clone(),
-                               node_one: NodeId::from_pubkey(&msg.node_id_1),
-                               one_to_two: None,
-                               node_two: NodeId::from_pubkey(&msg.node_id_2),
-                               two_to_one: None,
-                               capacity_sats: utxo_value,
-                               announcement_message: if msg.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY
-                                       { full_msg.cloned() } else { None },
-                               announcement_received_time,
-                       };
-
-               let mut channels = self.channels.write().unwrap();
-               let mut nodes = self.nodes.write().unwrap();
-               match channels.entry(msg.short_channel_id) {
-                       BtreeEntry::Occupied(mut entry) => {
-                               //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 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
-                                       // do that because
-                                       // a) we don't *require* a UTXO provider that always returns results.
-                                       // b) we don't track UTXOs of channels we know about and remove them if they
-                                       //    get reorg'd out.
-                                       // c) it's unclear how to do so without exposing ourselves to massive DoS risk.
-                                       Self::remove_channel_in_nodes(&mut nodes, &entry.get(), msg.short_channel_id);
-                                       *entry.get_mut() = chan_info;
-                               } else {
-                                       return Err(LightningError{err: "Already have knowledge of channel".to_owned(), action: ErrorAction::IgnoreDuplicateGossip});
-                               }
-                       },
-                       BtreeEntry::Vacant(entry) => {
-                               entry.insert(chan_info);
-                       }
+                       features: msg.features.clone(),
+                       node_one: NodeId::from_pubkey(&msg.node_id_1),
+                       one_to_two: None,
+                       node_two: NodeId::from_pubkey(&msg.node_id_2),
+                       two_to_one: None,
+                       capacity_sats: utxo_value,
+                       announcement_message: if msg.excess_data.len() <= MAX_EXCESS_BYTES_FOR_RELAY
+                               { full_msg.cloned() } else { None },
+                       announcement_received_time,
                };
 
-               macro_rules! add_channel_to_node {
-                       ( $node_id: expr ) => {
-                               match nodes.entry($node_id) {
-                                       BtreeEntry::Occupied(node_entry) => {
-                                               node_entry.into_mut().channels.push(msg.short_channel_id);
-                                       },
-                                       BtreeEntry::Vacant(node_entry) => {
-                                               node_entry.insert(NodeInfo {
-                                                       channels: vec!(msg.short_channel_id),
-                                                       lowest_inbound_channel_fees: None,
-                                                       announcement_info: None,
-                                               });
-                                       }
-                               }
-                       };
-               }
-
-               add_channel_to_node!(NodeId::from_pubkey(&msg.node_id_1));
-               add_channel_to_node!(NodeId::from_pubkey(&msg.node_id_2));
-
-               Ok(())
+               self.add_channel_between_nodes(msg.short_channel_id, chan_info, utxo_value)
        }
 
        /// Close a channel if a corresponding HTLC fail was sent.
@@ -1347,10 +1419,10 @@ impl NetworkGraph {
        /// If built with `no-std`, any updates with a timestamp more than two weeks in the past or
        /// materially in the future will be rejected.
        pub fn update_channel_unsigned(&self, msg: &msgs::UnsignedChannelUpdate) -> Result<(), LightningError> {
-               self.update_channel_intern(msg, None, None::<(&secp256k1::Signature, &Secp256k1<secp256k1::VerifyOnly>)>)
+               self.update_channel_intern(msg, None, None::<(&secp256k1::ecdsa::Signature, &Secp256k1<secp256k1::VerifyOnly>)>)
        }
 
-       fn update_channel_intern<T: secp256k1::Verification>(&self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig_info: Option<(&secp256k1::Signature, &Secp256k1<T>)>) -> Result<(), LightningError> {
+       fn update_channel_intern<T: secp256k1::Verification>(&self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig_info: Option<(&secp256k1::ecdsa::Signature, &Secp256k1<T>)>) -> Result<(), LightningError> {
                let dest_node_id;
                let chan_enabled = msg.flags & (1 << 1) != (1 << 1);
                let chan_was_enabled;
@@ -1549,7 +1621,7 @@ mod tests {
        use ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
        use routing::network_graph::{NetGraphMsgHandler, NetworkGraph, NetworkUpdate, MAX_EXCESS_BYTES_FOR_RELAY};
        use ln::msgs::{Init, OptionalField, RoutingMessageHandler, UnsignedNodeAnnouncement, NodeAnnouncement,
-               UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate, 
+               UnsignedChannelAnnouncement, ChannelAnnouncement, UnsignedChannelUpdate, ChannelUpdate,
                ReplyChannelRange, QueryChannelRange, QueryShortChannelIds, MAX_VALUE_MSAT};
        use util::test_utils;
        use util::logger::Logger;
@@ -1569,10 +1641,11 @@ mod tests {
 
        use hex;
 
-       use bitcoin::secp256k1::key::{PublicKey, SecretKey};
+       use bitcoin::secp256k1::{PublicKey, SecretKey};
        use bitcoin::secp256k1::{All, Secp256k1};
 
        use io;
+       use bitcoin::secp256k1;
        use prelude::*;
        use sync::Arc;
 
@@ -1619,7 +1692,7 @@ mod tests {
                f(&mut unsigned_announcement);
                let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
                NodeAnnouncement {
-                       signature: secp_ctx.sign(&msghash, node_key),
+                       signature: secp_ctx.sign_ecdsa(&msghash, node_key),
                        contents: unsigned_announcement
                }
        }
@@ -1643,10 +1716,10 @@ mod tests {
                f(&mut unsigned_announcement);
                let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_announcement.encode()[..])[..]);
                ChannelAnnouncement {
-                       node_signature_1: secp_ctx.sign(&msghash, node_1_key),
-                       node_signature_2: secp_ctx.sign(&msghash, node_2_key),
-                       bitcoin_signature_1: secp_ctx.sign(&msghash, node_1_btckey),
-                       bitcoin_signature_2: secp_ctx.sign(&msghash, node_2_btckey),
+                       node_signature_1: secp_ctx.sign_ecdsa(&msghash, node_1_key),
+                       node_signature_2: secp_ctx.sign_ecdsa(&msghash, node_2_key),
+                       bitcoin_signature_1: secp_ctx.sign_ecdsa(&msghash, node_1_btckey),
+                       bitcoin_signature_2: secp_ctx.sign_ecdsa(&msghash, node_2_btckey),
                        contents: unsigned_announcement,
                }
        }
@@ -1678,7 +1751,7 @@ mod tests {
                f(&mut unsigned_channel_update);
                let msghash = hash_to_message!(&Sha256dHash::hash(&unsigned_channel_update.encode()[..])[..]);
                ChannelUpdate {
-                       signature: secp_ctx.sign(&msghash, node_key),
+                       signature: secp_ctx.sign_ecdsa(&msghash, node_key),
                        contents: unsigned_channel_update
                }
        }
@@ -1715,7 +1788,7 @@ mod tests {
                let fake_msghash = hash_to_message!(&zero_hash);
                match net_graph_msg_handler.handle_node_announcement(
                        &NodeAnnouncement {
-                               signature: secp_ctx.sign(&fake_msghash, node_1_privkey),
+                               signature: secp_ctx.sign_ecdsa(&fake_msghash, node_1_privkey),
                                contents: valid_announcement.contents.clone()
                }) {
                        Ok(_) => panic!(),
@@ -1954,7 +2027,7 @@ mod tests {
                }, node_1_privkey, &secp_ctx);
                let zero_hash = Sha256dHash::hash(&[0; 32]);
                let fake_msghash = hash_to_message!(&zero_hash);
-               invalid_sig_channel_update.signature = secp_ctx.sign(&fake_msghash, node_1_privkey);
+               invalid_sig_channel_update.signature = secp_ctx.sign_ecdsa(&fake_msghash, node_1_privkey);
                match net_graph_msg_handler.handle_channel_update(&invalid_sig_channel_update) {
                        Ok(_) => panic!(),
                        Err(e) => assert_eq!(e.err, "Invalid signature on channel_update message")