Remove stale reference to incomplete BOLT compliance
[rust-lightning] / lightning / src / routing / network_graph.rs
index 67dc302246325b7efa219e98acdde875e5be702c..a26b549b43d45de4d96cc91ddf3d32921c241f3b 100644 (file)
@@ -249,6 +249,14 @@ where C::Target: chain::Access, L::Target: Logger
                self.chain_access = chain_access;
        }
 
+       /// Gets a reference to the underlying [`NetworkGraph`] which was provided in
+       /// [`NetGraphMsgHandler::new`].
+       ///
+       /// (C-not exported) as bindings don't support a reference-to-a-reference yet
+       pub fn network_graph(&self) -> &G {
+               &self.network_graph
+       }
+
        /// Returns true when a full routing table sync should be performed with a peer.
        fn should_request_full_sync(&self, _node_id: &PublicKey) -> bool {
                //TODO: Determine whether to request a full sync based on the network map.
@@ -286,10 +294,21 @@ where C::Target: chain::Access, L::Target: Logger
 }
 
 macro_rules! secp_verify_sig {
-       ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr ) => {
+       ( $secp_ctx: expr, $msg: expr, $sig: expr, $pubkey: expr, $msg_type: expr ) => {
                match $secp_ctx.verify($msg, $sig, $pubkey) {
                        Ok(_) => {},
-                       Err(_) => return Err(LightningError{err: "Invalid signature from remote node".to_owned(), action: ErrorAction::IgnoreError}),
+                       Err(_) => {
+                               return Err(LightningError {
+                                       err: format!("Invalid signature on {} message", $msg_type),
+                                       action: ErrorAction::SendWarningMessage {
+                                               msg: msgs::WarningMessage {
+                                                       channel_id: [0; 32],
+                                                       data: format!("Invalid signature on {} message", $msg_type),
+                                               },
+                                               log_level: Level::Trace,
+                                       },
+                               });
+                       },
                }
        };
 }
@@ -842,7 +861,7 @@ impl NetworkGraph {
        /// routing messages from a source using a protocol other than the lightning P2P protocol.
        pub fn update_node_from_announcement<T: secp256k1::Verification>(&self, msg: &msgs::NodeAnnouncement, secp_ctx: &Secp256k1<T>) -> Result<(), LightningError> {
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id);
+               secp_verify_sig!(secp_ctx, &msg_hash, &msg.signature, &msg.contents.node_id, "node_announcement");
                self.update_node_from_announcement_intern(&msg.contents, Some(&msg))
        }
 
@@ -902,10 +921,10 @@ impl NetworkGraph {
                C::Target: chain::Access,
        {
                let msg_hash = hash_to_message!(&Sha256dHash::hash(&msg.contents.encode()[..])[..]);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1);
-               secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2);
+               secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_1, &msg.contents.node_id_1, "channel_announcement");
+               secp_verify_sig!(secp_ctx, &msg_hash, &msg.node_signature_2, &msg.contents.node_id_2, "channel_announcement");
+               secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_1, &msg.contents.bitcoin_key_1, "channel_announcement");
+               secp_verify_sig!(secp_ctx, &msg_hash, &msg.bitcoin_signature_2, &msg.contents.bitcoin_key_2, "channel_announcement");
                self.update_channel_from_unsigned_announcement_intern(&msg.contents, Some(msg), chain_access)
        }
 
@@ -1074,6 +1093,8 @@ impl NetworkGraph {
        /// updates every two weeks, the non-normative section of BOLT 7 currently suggests that
        /// pruning occur for updates which are at least two weeks old, which we implement here.
        ///
+       /// Note that for users of the `lightning-background-processor` crate this method may be
+       /// automatically called regularly for you.
        ///
        /// This method is only available with the `std` feature. See
        /// [`NetworkGraph::remove_stale_channels_with_time`] for `no-std` use.
@@ -1132,6 +1153,9 @@ impl NetworkGraph {
        /// You probably don't want to call this directly, instead relying on a NetGraphMsgHandler'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<T: secp256k1::Verification>(&self, msg: &msgs::ChannelUpdate, secp_ctx: &Secp256k1<T>) -> Result<(), LightningError> {
                self.update_channel_intern(&msg.contents, Some(&msg), Some((&msg.signature, secp_ctx)))
        }
@@ -1139,6 +1163,9 @@ impl NetworkGraph {
        /// For an already known (from announcement) channel, update info about one of the directions
        /// of the channel without verifying the associated signatures. Because we aren't given the
        /// associated signatures here we cannot relay the channel update to any of our peers.
+       ///
+       /// 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>)>)
        }
@@ -1148,6 +1175,19 @@ impl NetworkGraph {
                let chan_enabled = msg.flags & (1 << 1) != (1 << 1);
                let chan_was_enabled;
 
+               #[cfg(all(feature = "std", not(test), not(feature = "_test_utils")))]
+               {
+                       // Note that many tests rely on being able to set arbitrarily old timestamps, thus we
+                       // disable this check during tests!
+                       let time = SystemTime::now().duration_since(UNIX_EPOCH).expect("Time must be > 1970").as_secs();
+                       if (msg.timestamp as u64) < time - STALE_CHANNEL_UPDATE_AGE_LIMIT_SECS {
+                               return Err(LightningError{err: "channel_update is older than two weeks old".to_owned(), action: ErrorAction::IgnoreAndLog(Level::Gossip)});
+                       }
+                       if msg.timestamp as u64 > time + 60 * 60 * 24 {
+                               return Err(LightningError{err: "channel_update has a timestamp more than a day in the future".to_owned(), action: ErrorAction::IgnoreAndLog(Level::Gossip)});
+                       }
+               }
+
                let mut channels = self.channels.write().unwrap();
                match channels.get_mut(&msg.short_channel_id) {
                        None => return Err(LightningError{err: "Couldn't find channel for update".to_owned(), action: ErrorAction::IgnoreError}),
@@ -1210,7 +1250,7 @@ impl NetworkGraph {
                                                secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_two.as_slice()).map_err(|_| LightningError{
                                                        err: "Couldn't parse source node pubkey".to_owned(),
                                                        action: ErrorAction::IgnoreAndLog(Level::Debug)
-                                               })?);
+                                               })?, "channel_update");
                                        }
                                        maybe_update_channel_info!(channel.two_to_one, channel.node_two);
                                } else {
@@ -1219,7 +1259,7 @@ impl NetworkGraph {
                                                secp_verify_sig!(ctx, &msg_hash, &sig, &PublicKey::from_slice(channel.node_one.as_slice()).map_err(|_| LightningError{
                                                        err: "Couldn't parse destination node pubkey".to_owned(),
                                                        action: ErrorAction::IgnoreAndLog(Level::Debug)
-                                               })?);
+                                               })?, "channel_update");
                                        }
                                        maybe_update_channel_info!(channel.one_to_two, channel.node_one);
                                }
@@ -1493,7 +1533,7 @@ mod tests {
                                contents: valid_announcement.contents.clone()
                }) {
                        Ok(_) => panic!(),
-                       Err(e) => assert_eq!(e.err, "Invalid signature from remote node")
+                       Err(e) => assert_eq!(e.err, "Invalid signature on node_announcement message")
                };
 
                let announcement_with_data = get_signed_node_announcement(|unsigned_announcement| {
@@ -1622,7 +1662,7 @@ mod tests {
                invalid_sig_announcement.contents.excess_data = Vec::new();
                match net_graph_msg_handler.handle_channel_announcement(&invalid_sig_announcement) {
                        Ok(_) => panic!(),
-                       Err(e) => assert_eq!(e.err, "Invalid signature from remote node")
+                       Err(e) => assert_eq!(e.err, "Invalid signature on channel_announcement message")
                };
 
                let channel_to_itself_announcement = get_signed_channel_announcement(|_| {}, node_1_privkey, node_1_privkey, &secp_ctx);
@@ -1731,7 +1771,7 @@ mod tests {
                invalid_sig_channel_update.signature = secp_ctx.sign(&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 from remote node")
+                       Err(e) => assert_eq!(e.err, "Invalid signature on channel_update message")
                };
        }