From: Matt Corallo Date: Thu, 6 May 2021 01:15:35 +0000 (+0000) Subject: Process announcement_signatures messages in Channel and store sigs X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=bc6281693715b01f719a815119b60d3f84d9f6f6;p=rust-lightning Process announcement_signatures messages in Channel and store sigs 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. --- diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 88e853b49..8f293bff5 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -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 { 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 Channel { 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 Channel { 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"))] @@ -3872,6 +3881,47 @@ impl Channel { 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 { + 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 get 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 { + 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(&self, logger: &L) -> msgs::ChannelReestablish where L::Target: Logger { @@ -4585,7 +4635,7 @@ impl Writeable for Channel { self.channel_update_status.write(writer)?; - write_tlv_fields!(writer, {}, {}); + write_tlv_fields!(writer, {}, {(0, self.announcement_sigs)}); Ok(()) } @@ -4757,7 +4807,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel 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()); @@ -4835,6 +4886,8 @@ impl<'a, Signer: Sign, K: Deref> ReadableArgs<&'a K> for Channel 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"))] diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index e06213c78..0b60be34b 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -3217,39 +3217,8 @@ impl 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 }); },