Merge pull request #2529 from TheBlueMatt/2023-08-shutdown-remove-early-sign
[rust-lightning] / lightning / src / routing / gossip.rs
index edb6226041d2e694b31842a7149cda25ed28ebe8..7791737d9e2f70513fb7a70049f6bca8857b373b 100644 (file)
@@ -341,6 +341,9 @@ where U::Target: UtxoLookup, L::Target: Logger
 
 impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        /// Handles any network updates originating from [`Event`]s.
+       //
+       /// Note that this will skip applying any [`NetworkUpdate::ChannelUpdateMessage`] to avoid
+       /// leaking possibly identifying information of the sender to the public network.
        ///
        /// [`Event`]: crate::events::Event
        pub fn handle_network_update(&self, network_update: &NetworkUpdate) {
@@ -349,8 +352,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                                let short_channel_id = msg.contents.short_channel_id;
                                let is_enabled = msg.contents.flags & (1 << 1) != (1 << 1);
                                let status = if is_enabled { "enabled" } else { "disabled" };
-                               log_debug!(self.logger, "Updating channel with channel_update from a payment failure. Channel {} is {}.", short_channel_id, status);
-                               let _ = self.update_channel(msg);
+                               log_debug!(self.logger, "Skipping application of a channel update from a payment failure. Channel {} is {}.", short_channel_id, status);
                        },
                        NetworkUpdate::ChannelFailure { short_channel_id, is_permanent } => {
                                if is_permanent {
@@ -410,11 +412,17 @@ macro_rules! get_pubkey_from_node_id {
        }
 }
 
+fn message_sha256d_hash<M: Writeable>(msg: &M) -> Sha256dHash {
+       let mut engine = Sha256dHash::engine();
+       msg.write(&mut engine).expect("In-memory structs should not fail to serialize");
+       Sha256dHash::from_engine(engine)
+}
+
 /// Verifies the signature of a [`NodeAnnouncement`].
 ///
 /// Returns an error if it is invalid.
 pub fn verify_node_announcement<C: Verification>(msg: &NodeAnnouncement, secp_ctx: &Secp256k1<C>) -> Result<(), LightningError> {
-       let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
+       let msg_hash = hash_to_message!(&message_sha256d_hash(&msg.contents)[..]);
        secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &get_pubkey_from_node_id!(msg.contents.node_id, "node_announcement"), "node_announcement");
 
        Ok(())
@@ -424,7 +432,7 @@ pub fn verify_node_announcement<C: Verification>(msg: &NodeAnnouncement, secp_ct
 ///
 /// Returns an error if one of the signatures is invalid.
 pub fn verify_channel_announcement<C: Verification>(msg: &ChannelAnnouncement, secp_ctx: &Secp256k1<C>) -> Result<(), LightningError> {
-       let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
+       let msg_hash = hash_to_message!(&message_sha256d_hash(&msg.contents)[..]);
        secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &get_pubkey_from_node_id!(msg.contents.node_id_1, "channel_announcement"), "channel_announcement");
        secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &get_pubkey_from_node_id!(msg.contents.node_id_2, "channel_announcement"), "channel_announcement");
        secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &get_pubkey_from_node_id!(msg.contents.bitcoin_key_1, "channel_announcement"), "channel_announcement");
@@ -1170,7 +1178,7 @@ impl Readable for NodeAnnouncementInfo {
 ///
 /// Since node aliases are provided by third parties, they are a potential avenue for injection
 /// attacks. Care must be taken when processing.
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
+#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq)]
 pub struct NodeAlias(pub [u8; 32]);
 
 impl fmt::Display for NodeAlias {
@@ -1310,14 +1318,16 @@ impl<L: Deref> ReadableArgs<L> for NetworkGraph<L> where L::Target: Logger {
 
                let chain_hash: ChainHash = Readable::read(reader)?;
                let channels_count: u64 = Readable::read(reader)?;
-               let mut channels = IndexedMap::new();
+               // In Nov, 2023 there were about 15,000 nodes; we cap allocations to 1.5x that.
+               let mut channels = IndexedMap::with_capacity(cmp::min(channels_count as usize, 22500));
                for _ in 0..channels_count {
                        let chan_id: u64 = Readable::read(reader)?;
                        let chan_info = Readable::read(reader)?;
                        channels.insert(chan_id, chan_info);
                }
                let nodes_count: u64 = Readable::read(reader)?;
-               let mut nodes = IndexedMap::new();
+               // In Nov, 2023 there were about 69K channels; we cap allocations to 1.5x that.
+               let mut nodes = IndexedMap::with_capacity(cmp::min(nodes_count as usize, 103500));
                for _ in 0..nodes_count {
                        let node_id = Readable::read(reader)?;
                        let node_info = Readable::read(reader)?;
@@ -1845,14 +1855,14 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        /// For an already known (from announcement) channel, update info about one of the directions
        /// of the channel.
        ///
-       /// You probably don't want to call this directly, instead relying on a P2PGossipSync's
-       /// RoutingMessageHandler implementation to call it indirectly. This may be useful to accept
+       /// You probably don't want to call this directly, instead relying on a [`P2PGossipSync`]'s
+       /// [`RoutingMessageHandler`] implementation to call it indirectly. This may be useful to accept
        /// routing messages from a source using a protocol other than the lightning P2P protocol.
        ///
        /// 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(&self, msg: &msgs::ChannelUpdate) -> Result<(), LightningError> {
-               self.update_channel_intern(&msg.contents, Some(&msg), Some(&msg.signature))
+               self.update_channel_internal(&msg.contents, Some(&msg), Some(&msg.signature), false)
        }
 
        /// For an already known (from announcement) channel, update info about one of the directions
@@ -1862,10 +1872,23 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
        /// 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)
+               self.update_channel_internal(msg, None, None, false)
        }
 
-       fn update_channel_intern(&self, msg: &msgs::UnsignedChannelUpdate, full_msg: Option<&msgs::ChannelUpdate>, sig: Option<&secp256k1::ecdsa::Signature>) -> Result<(), LightningError> {
+       /// For an already known (from announcement) channel, verify the given [`ChannelUpdate`].
+       ///
+       /// This checks whether the update currently is applicable by [`Self::update_channel`].
+       ///
+       /// 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 verify_channel_update(&self, msg: &msgs::ChannelUpdate) -> Result<(), LightningError> {
+               self.update_channel_internal(&msg.contents, Some(&msg), Some(&msg.signature), true)
+       }
+
+       fn update_channel_internal(&self, msg: &msgs::UnsignedChannelUpdate,
+               full_msg: Option<&msgs::ChannelUpdate>, sig: Option<&secp256k1::ecdsa::Signature>,
+               only_verify: bool) -> Result<(), LightningError>
+       {
                let chan_enabled = msg.flags & (1 << 1) != (1 << 1);
 
                if msg.chain_hash != self.chain_hash {
@@ -1952,7 +1975,7 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                                        } }
                                }
 
-                               let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
+                               let msg_hash = hash_to_message!(&message_sha256d_hash(&msg)[..]);
                                if msg.flags & 1 == 1 {
                                        check_update_latest!(channel.two_to_one);
                                        if let Some(sig) = sig {
@@ -1961,7 +1984,9 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                                                        action: ErrorAction::IgnoreAndLog(Level::Debug)
                                                })?, "channel_update");
                                        }
-                                       channel.two_to_one = get_new_channel_info!();
+                                       if !only_verify {
+                                               channel.two_to_one = get_new_channel_info!();
+                                       }
                                } else {
                                        check_update_latest!(channel.one_to_two);
                                        if let Some(sig) = sig {
@@ -1970,7 +1995,9 @@ impl<L: Deref> NetworkGraph<L> where L::Target: Logger {
                                                        action: ErrorAction::IgnoreAndLog(Level::Debug)
                                                })?, "channel_update");
                                        }
-                                       channel.one_to_two = get_new_channel_info!();
+                                       if !only_verify {
+                                               channel.one_to_two = get_new_channel_info!();
+                                       }
                                }
                        }
                }
@@ -2411,6 +2438,7 @@ pub(crate) mod tests {
                }
 
                let valid_channel_update = get_signed_channel_update(|_| {}, node_1_privkey, &secp_ctx);
+               network_graph.verify_channel_update(&valid_channel_update).unwrap();
                match gossip_sync.handle_channel_update(&valid_channel_update) {
                        Ok(res) => assert!(res),
                        _ => panic!(),
@@ -2513,7 +2541,8 @@ pub(crate) mod tests {
 
                let short_channel_id;
                {
-                       // Announce a channel we will update
+                       // Check we won't apply an update via `handle_network_update` for privacy reasons, but
+                       // can continue fine if we manually apply it.
                        let valid_channel_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_2_privkey, &secp_ctx);
                        short_channel_id = valid_channel_announcement.contents.short_channel_id;
                        let chain_source: Option<&test_utils::TestChainSource> = None;
@@ -2524,10 +2553,11 @@ pub(crate) mod tests {
                        assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_none());
 
                        network_graph.handle_network_update(&NetworkUpdate::ChannelUpdateMessage {
-                               msg: valid_channel_update,
+                               msg: valid_channel_update.clone(),
                        });
 
-                       assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_some());
+                       assert!(network_graph.read_only().channels().get(&short_channel_id).unwrap().one_to_two.is_none());
+                       network_graph.update_channel(&valid_channel_update).unwrap();
                }
 
                // Non-permanent failure doesn't touch the channel at all