Process announcement_signatures messages in Channel and store sigs
authorMatt Corallo <git@bluematt.me>
Thu, 6 May 2021 01:15:35 +0000 (01:15 +0000)
committerMatt Corallo <git@bluematt.me>
Tue, 25 May 2021 20:06:45 +0000 (20:06 +0000)
Previously we handled most of the logic of announcement_signatures
in ChannelManager, rather than Channel. This is somewhat unique as
far as our message processing goes, but it also avoided having to
pass the node_secret in to the Channel.

Eventually, we'll move the node_secret behind the signer anyway, so
there isn't much reason for this, and storing the
announcement_signatures-provided signatures in the Channel allows
us to recreate the channel_announcement later for rebroadcast,
which may be useful.

lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs

index f41a8dd8440361c0ebae3c9f1b274b6308769110..94bf4c6f7c5567a485d509ccd13e8422e8e7d3ba 100644 (file)
@@ -15,6 +15,7 @@ use bitcoin::consensus::encode;
 
 use bitcoin::hashes::Hash;
 use bitcoin::hashes::sha256::Hash as Sha256;
+use bitcoin::hashes::sha256d::Hash as Sha256d;
 use bitcoin::hash_types::{Txid, BlockHash, WPubkeyHash};
 
 use bitcoin::secp256k1::key::{PublicKey,SecretKey};
@@ -420,6 +421,10 @@ pub(super) struct Channel<Signer: Sign> {
 
        channel_update_status: ChannelUpdateStatus,
 
+       /// Our counterparty's channel_announcement signatures provided in announcement_signatures.
+       /// This can be used to rebroadcast the channel_announcement message later.
+       announcement_sigs: Option<(Signature, Signature)>,
+
        // We save these values so we can make sure `next_local_commit_tx_fee_msat` and
        // `next_remote_commit_tx_fee_msat` properly predict what the next commitment transaction fee will
        // be, by comparing the cached values to the fee of the tranaction generated by
@@ -621,6 +626,8 @@ impl<Signer: Sign> Channel<Signer> {
 
                        channel_update_status: ChannelUpdateStatus::Enabled,
 
+                       announcement_sigs: None,
+
                        #[cfg(any(test, feature = "fuzztarget"))]
                        next_local_commitment_tx_fee_info_cached: Mutex::new(None),
                        #[cfg(any(test, feature = "fuzztarget"))]
@@ -862,6 +869,8 @@ impl<Signer: Sign> Channel<Signer> {
 
                        channel_update_status: ChannelUpdateStatus::Enabled,
 
+                       announcement_sigs: None,
+
                        #[cfg(any(test, feature = "fuzztarget"))]
                        next_local_commitment_tx_fee_info_cached: Mutex::new(None),
                        #[cfg(any(test, feature = "fuzztarget"))]
@@ -3852,6 +3861,47 @@ impl<Signer: Sign> Channel<Signer> {
                Ok((msg, sig))
        }
 
+       fn sign_channel_announcement(&self, our_node_secret: &SecretKey, our_node_id: PublicKey, msghash: secp256k1::Message, announcement: msgs::UnsignedChannelAnnouncement, our_bitcoin_sig: Signature) -> Result<msgs::ChannelAnnouncement, ChannelError> {
+               if let Some((their_node_sig, their_bitcoin_sig)) = self.announcement_sigs {
+                       let were_node_one = announcement.node_id_1 == our_node_id;
+
+                       let our_node_sig = self.secp_ctx.sign(&msghash, our_node_secret);
+                       Ok(msgs::ChannelAnnouncement {
+                               node_signature_1: if were_node_one { our_node_sig } else { their_node_sig },
+                               node_signature_2: if were_node_one { their_node_sig } else { our_node_sig },
+                               bitcoin_signature_1: if were_node_one { our_bitcoin_sig } else { their_bitcoin_sig },
+                               bitcoin_signature_2: if were_node_one { their_bitcoin_sig } else { our_bitcoin_sig },
+                               contents: announcement,
+                       })
+               } else {
+                       Err(ChannelError::Ignore("Attempted to sign channel announcement before we'd received announcement_signatures".to_string()))
+               }
+       }
+
+       /// Processes an incoming announcement_signatures message, providing a fully-signed
+       /// channel_announcement message which we can broadcast and storing our counterparty's
+       /// signatures for later reconstruction/rebroadcast of the channel_announcement.
+       pub fn announcement_signatures(&mut self, our_node_secret: &SecretKey, our_node_id: PublicKey, chain_hash: BlockHash, msg: &msgs::AnnouncementSignatures) -> Result<msgs::ChannelAnnouncement, ChannelError> {
+               let (announcement, our_bitcoin_sig) = self.get_channel_announcement(our_node_id.clone(), chain_hash)?;
+
+               let msghash = hash_to_message!(&Sha256d::hash(&announcement.encode()[..])[..]);
+
+               if self.secp_ctx.verify(&msghash, &msg.node_signature, &self.get_counterparty_node_id()).is_err() {
+                       return Err(ChannelError::Close(format!(
+                               "Bad announcement_signatures. Failed to verify node_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_node_key is {:?}",
+                                &announcement, self.get_counterparty_node_id())));
+               }
+               if self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, self.counterparty_funding_pubkey()).is_err() {
+                       return Err(ChannelError::Close(format!(
+                               "Bad announcement_signatures. Failed to verify bitcoin_signature. UnsignedChannelAnnouncement used for verification is {:?}. their_bitcoin_key is ({:?})",
+                               &announcement, self.counterparty_funding_pubkey())));
+               }
+
+               self.announcement_sigs = Some((msg.node_signature, msg.bitcoin_signature));
+
+               self.sign_channel_announcement(our_node_secret, our_node_id, msghash, announcement, our_bitcoin_sig)
+       }
+
        /// May panic if called on a channel that wasn't immediately-previously
        /// self.remove_uncommitted_htlcs_and_mark_paused()'d
        pub fn get_channel_reestablish<L: Deref>(&self, logger: &L) -> msgs::ChannelReestablish where L::Target: Logger {
@@ -4565,7 +4615,7 @@ impl<Signer: Sign> Writeable for Channel<Signer> {
 
                self.channel_update_status.write(writer)?;
 
-               write_tlv_fields!(writer, {}, {});
+               write_tlv_fields!(writer, {}, {(0, self.announcement_sigs)});
 
                Ok(())
        }
@@ -4737,7 +4787,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
 
                let channel_update_status = Readable::read(reader)?;
 
-               read_tlv_fields!(reader, {}, {});
+               let mut announcement_sigs = None;
+               read_tlv_fields!(reader, {}, {(0, announcement_sigs)});
 
                let mut secp_ctx = Secp256k1::new();
                secp_ctx.seeded_randomize(&keys_source.get_secure_random_bytes());
@@ -4815,6 +4866,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel<Signer>
 
                        channel_update_status,
 
+                       announcement_sigs,
+
                        #[cfg(any(test, feature = "fuzztarget"))]
                        next_local_commitment_tx_fee_info_cached: Mutex::new(None),
                        #[cfg(any(test, feature = "fuzztarget"))]
index b1416c30f53becd5450306dcb3daa64db02181f0..6e18cbfa4a2d7cd2b3950942a30489da140fd5d6 100644 (file)
@@ -3301,39 +3301,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
                                        return Err(MsgHandleErrInternal::from_no_close(LightningError{err: "Got an announcement_signatures before we were ready for it".to_owned(), action: msgs::ErrorAction::IgnoreError}));
                                }
 
-                               let our_node_id = self.get_our_node_id();
-                               let (announcement, our_bitcoin_sig) =
-                                       try_chan_entry!(self, chan.get_mut().get_channel_announcement(our_node_id.clone(), self.genesis_hash.clone()), channel_state, chan);
-
-                               let were_node_one = announcement.node_id_1 == our_node_id;
-                               let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]);
-                               {
-                                       let their_node_key = if were_node_one { &announcement.node_id_2 } else { &announcement.node_id_1 };
-                                       let their_bitcoin_key = if were_node_one { &announcement.bitcoin_key_2 } else { &announcement.bitcoin_key_1 };
-                                       match (self.secp_ctx.verify(&msghash, &msg.node_signature, their_node_key),
-                                                  self.secp_ctx.verify(&msghash, &msg.bitcoin_signature, their_bitcoin_key)) {
-                                               (Err(e), _) => {
-                                                       let chan_err: ChannelError = ChannelError::Close(format!("Bad announcement_signatures. Failed to verify node_signature: {:?}. Maybe using different node_secret for transport and routing msg? UnsignedChannelAnnouncement used for verification is {:?}. their_node_key is {:?}", e, &announcement, their_node_key));
-                                                       try_chan_entry!(self, Err(chan_err), channel_state, chan);
-                                               },
-                                               (_, Err(e)) => {
-                                                       let chan_err: ChannelError = ChannelError::Close(format!("Bad announcement_signatures. Failed to verify bitcoin_signature: {:?}. UnsignedChannelAnnouncement used for verification is {:?}. their_bitcoin_key is ({:?})", e, &announcement, their_bitcoin_key));
-                                                       try_chan_entry!(self, Err(chan_err), channel_state, chan);
-                                               },
-                                               _ => {}
-                                       }
-                               }
-
-                               let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key);
-
                                channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
-                                       msg: msgs::ChannelAnnouncement {
-                                               node_signature_1: if were_node_one { our_node_sig } else { msg.node_signature },
-                                               node_signature_2: if were_node_one { msg.node_signature } else { our_node_sig },
-                                               bitcoin_signature_1: if were_node_one { our_bitcoin_sig } else { msg.bitcoin_signature },
-                                               bitcoin_signature_2: if were_node_one { msg.bitcoin_signature } else { our_bitcoin_sig },
-                                               contents: announcement,
-                                       },
+                                       msg: try_chan_entry!(self, chan.get_mut().announcement_signatures(&self.our_network_key, self.get_our_node_id(), self.genesis_hash.clone(), msg), channel_state, chan),
                                        update_msg: self.get_channel_update(chan.get()).unwrap(), // can only fail if we're not in a ready state
                                });
                        },