Skip to content

Disconnect announcement_signatures sending from funding_locked #1179

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

3 changes: 2 additions & 1 deletion fuzz/src/chanmon_consistency.rs
Original file line number Diff line number Diff line change
Expand Up @@ -188,6 +188,7 @@ impl KeysInterface for KeyProvider {
let id = self.rand_bytes_id.fetch_add(1, atomic::Ordering::Relaxed);
let keys = InMemorySigner::new(
&secp_ctx,
self.get_node_secret(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, self.node_id]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, self.node_id]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 6, self.node_id]).unwrap(),
Expand All @@ -211,7 +212,7 @@ impl KeysInterface for KeyProvider {
fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::Signer, DecodeError> {
let mut reader = std::io::Cursor::new(buffer);

let inner: InMemorySigner = Readable::read(&mut reader)?;
let inner: InMemorySigner = ReadableArgs::read(&mut reader, self.get_node_secret())?;
let state = self.make_enforcement_state_cell(inner.commitment_seed);

Ok(EnforcingSigner {
Expand Down
6 changes: 4 additions & 2 deletions fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ use lightning::util::errors::APIError;
use lightning::util::events::Event;
use lightning::util::enforcing_trait_impls::{EnforcingSigner, EnforcementState};
use lightning::util::logger::Logger;
use lightning::util::ser::Readable;
use lightning::util::ser::ReadableArgs;

use utils::test_logger;
use utils::test_persister::TestPersister;
Expand Down Expand Up @@ -293,6 +293,7 @@ impl KeysInterface for KeyProvider {
EnforcingSigner::new(if inbound {
InMemorySigner::new(
&secp_ctx,
self.node_secret.clone(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, ctr]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, ctr]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, ctr]).unwrap(),
Expand All @@ -305,6 +306,7 @@ impl KeysInterface for KeyProvider {
} else {
InMemorySigner::new(
&secp_ctx,
self.node_secret.clone(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, ctr]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, ctr]).unwrap(),
SecretKey::from_slice(&[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, ctr]).unwrap(),
Expand All @@ -324,7 +326,7 @@ impl KeysInterface for KeyProvider {
}

fn read_chan_signer(&self, mut data: &[u8]) -> Result<EnforcingSigner, DecodeError> {
let inner: InMemorySigner = Readable::read(&mut data)?;
let inner: InMemorySigner = ReadableArgs::read(&mut data, self.node_secret.clone())?;
let state = Arc::new(Mutex::new(EnforcementState::new()));

Ok(EnforcingSigner::new_with_revoked(
Expand Down
1 change: 1 addition & 0 deletions lightning/src/chain/channelmonitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3479,6 +3479,7 @@ mod tests {
SecretKey::from_slice(&[41; 32]).unwrap(),
SecretKey::from_slice(&[41; 32]).unwrap(),
SecretKey::from_slice(&[41; 32]).unwrap(),
SecretKey::from_slice(&[41; 32]).unwrap(),
[41; 32],
0,
[0; 32]
Expand Down
29 changes: 20 additions & 9 deletions lightning/src/chain/keysinterface.rs
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ use bitcoin::secp256k1::recovery::RecoverableSignature;
use bitcoin::secp256k1;

use util::{byte_utils, transaction_utils};
use util::ser::{Writeable, Writer, Readable};
use util::ser::{Writeable, Writer, Readable, ReadableArgs};

use chain::transaction::OutPoint;
use ln::{chan_utils, PaymentPreimage};
Expand Down Expand Up @@ -346,13 +346,17 @@ pub trait BaseSign {
/// chosen to forgo their output as dust.
fn sign_closing_transaction(&self, closing_tx: &ClosingTransaction, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;

/// Signs a channel announcement message with our funding key, proving it comes from one
/// of the channel participants.
/// Signs a channel announcement message with our funding key and our node secret key (aka
/// node_id or network_key), proving it comes from one of the channel participants.
///
/// The first returned signature should be from our node secret key, the second from our
/// funding key.
///
/// Note that if this fails or is rejected, the channel will not be publicly announced and
/// our counterparty may (though likely will not) close the channel on us for violating the
/// protocol.
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()>;
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>)
-> Result<(Signature, Signature), ()>;

/// Set the counterparty static channel data, including basepoints,
/// counterparty_selected/holder_selected_contest_delay and funding outpoint.
Expand Down Expand Up @@ -447,6 +451,8 @@ pub struct InMemorySigner {
pub commitment_seed: [u8; 32],
/// Holder public keys and basepoints
pub(crate) holder_channel_pubkeys: ChannelPublicKeys,
/// Private key of our node secret, used for signing channel announcements
node_secret: SecretKey,
/// Counterparty public keys and counterparty/holder selected_contest_delay, populated on channel acceptance
channel_parameters: Option<ChannelTransactionParameters>,
/// The total value of this channel
Expand All @@ -459,6 +465,7 @@ impl InMemorySigner {
/// Create a new InMemorySigner
pub fn new<C: Signing>(
secp_ctx: &Secp256k1<C>,
node_secret: SecretKey,
funding_key: SecretKey,
revocation_base_key: SecretKey,
payment_key: SecretKey,
Expand All @@ -478,6 +485,7 @@ impl InMemorySigner {
delayed_payment_base_key,
htlc_base_key,
commitment_seed,
node_secret,
channel_value_satoshis,
holder_channel_pubkeys,
channel_parameters: None,
Expand Down Expand Up @@ -720,9 +728,10 @@ impl BaseSign for InMemorySigner {
Ok(closing_tx.trust().sign(&self.funding_key, &channel_funding_redeemscript, self.channel_value_satoshis, secp_ctx))
}

fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
fn sign_channel_announcement(&self, msg: &UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>)
-> Result<(Signature, Signature), ()> {
let msghash = hash_to_message!(&Sha256dHash::hash(&msg.encode()[..])[..]);
Ok(secp_ctx.sign(&msghash, &self.funding_key))
Ok((secp_ctx.sign(&msghash, &self.node_secret), secp_ctx.sign(&msghash, &self.funding_key)))
}

fn ready_channel(&mut self, channel_parameters: &ChannelTransactionParameters) {
Expand Down Expand Up @@ -757,8 +766,8 @@ impl Writeable for InMemorySigner {
}
}

impl Readable for InMemorySigner {
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
impl ReadableArgs<SecretKey> for InMemorySigner {
fn read<R: io::Read>(reader: &mut R, node_secret: SecretKey) -> Result<Self, DecodeError> {
let _ver = read_ver_prefix!(reader, SERIALIZATION_VERSION);

let funding_key = Readable::read(reader)?;
Expand All @@ -784,6 +793,7 @@ impl Readable for InMemorySigner {
payment_key,
delayed_payment_base_key,
htlc_base_key,
node_secret,
commitment_seed,
channel_value_satoshis,
holder_channel_pubkeys,
Expand Down Expand Up @@ -937,6 +947,7 @@ impl KeysManager {

InMemorySigner::new(
&self.secp_ctx,
self.node_secret,
funding_key,
revocation_base_key,
payment_key,
Expand Down Expand Up @@ -1119,7 +1130,7 @@ impl KeysInterface for KeysManager {
}

fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError> {
InMemorySigner::read(&mut io::Cursor::new(reader))
InMemorySigner::read(&mut io::Cursor::new(reader), self.get_node_secret())
}

fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5]) -> Result<RecoverableSignature, ()> {
Expand Down
45 changes: 29 additions & 16 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4596,17 +4596,19 @@ impl<Signer: Sign> Channel<Signer> {
})
}

/// Gets an UnsignedChannelAnnouncement, as well as a signature covering it using our
/// bitcoin_key, if available, for this channel. The channel must be publicly announceable and
/// available for use (have exchanged FundingLocked messages in both directions). Should be used
/// for both loose and in response to an AnnouncementSignatures message from the remote peer.
/// Gets an UnsignedChannelAnnouncement for this channel. The channel must be publicly
/// announceable and available for use (have exchanged FundingLocked messages in both
/// directions). Should be used for both loose and in response to an AnnouncementSignatures
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what does "should be used for loose" mean?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Was this resolved...?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I reworked the documentation to no longer say "loose".

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, it looks like the updated comment was put in ed1163a

/// message from the remote peer.
///
/// Will only fail if we're not in a state where channel_announcement may be sent (including
/// closing).
///
/// Note that the "channel must be funded" requirement is stricter than BOLT 7 requires - see
/// https://github.com/lightningnetwork/lightning-rfc/issues/468
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This issue is closed, does this need updating?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Will fix in a followup PR, since this has two acks.

///
/// This will only return ChannelError::Ignore upon failure.
pub fn get_channel_announcement(&self, node_id: PublicKey, chain_hash: BlockHash) -> Result<(msgs::UnsignedChannelAnnouncement, Signature), ChannelError> {
fn get_channel_announcement(&self, node_id: PublicKey, chain_hash: BlockHash) -> Result<msgs::UnsignedChannelAnnouncement, ChannelError> {
if !self.config.announced_channel {
return Err(ChannelError::Ignore("Channel is not available for public announcements".to_owned()));
}
Expand All @@ -4630,19 +4632,30 @@ impl<Signer: Sign> Channel<Signer> {
excess_data: Vec::new(),
};

let sig = self.holder_signer.sign_channel_announcement(&msg, &self.secp_ctx)
Ok(msg)
}

pub fn get_announcement_sigs(&self, node_pk: PublicKey, genesis_block_hash: BlockHash) -> Result<msgs::AnnouncementSignatures, ChannelError> {
let announcement = self.get_channel_announcement(node_pk, genesis_block_hash)?;
let (our_node_sig, our_bitcoin_sig) = self.holder_signer.sign_channel_announcement(&announcement, &self.secp_ctx)
.map_err(|_| ChannelError::Ignore("Signer rejected channel_announcement".to_owned()))?;

Ok((msg, sig))
Ok(msgs::AnnouncementSignatures {
channel_id: self.channel_id(),
short_channel_id: self.get_short_channel_id().unwrap(),
node_signature: our_node_sig,
bitcoin_signature: our_bitcoin_sig,
})
}

/// Signs the given channel announcement, returning a ChannelError::Ignore if no keys are
/// available.
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> {
fn sign_channel_announcement(&self, our_node_id: PublicKey, announcement: msgs::UnsignedChannelAnnouncement) -> 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);
let (our_node_sig, our_bitcoin_sig) = self.holder_signer.sign_channel_announcement(&announcement, &self.secp_ctx)
.map_err(|_| ChannelError::Ignore("Signer rejected channel_announcement".to_owned()))?;
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 },
Expand All @@ -4658,8 +4671,8 @@ impl<Signer: Sign> Channel<Signer> {
/// 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)?;
pub fn announcement_signatures(&mut self, our_node_id: PublicKey, chain_hash: BlockHash, msg: &msgs::AnnouncementSignatures) -> Result<msgs::ChannelAnnouncement, ChannelError> {
let announcement = self.get_channel_announcement(our_node_id.clone(), chain_hash)?;

let msghash = hash_to_message!(&Sha256d::hash(&announcement.encode()[..])[..]);

Expand All @@ -4676,18 +4689,17 @@ impl<Signer: Sign> Channel<Signer> {

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)
self.sign_channel_announcement(our_node_id, announcement)
}

/// Gets a signed channel_announcement for this channel, if we previously received an
/// announcement_signatures from our counterparty.
pub fn get_signed_channel_announcement(&self, our_node_secret: &SecretKey, our_node_id: PublicKey, chain_hash: BlockHash) -> Option<msgs::ChannelAnnouncement> {
let (announcement, our_bitcoin_sig) = match self.get_channel_announcement(our_node_id.clone(), chain_hash) {
pub fn get_signed_channel_announcement(&self, our_node_id: PublicKey, chain_hash: BlockHash) -> Option<msgs::ChannelAnnouncement> {
let announcement = match self.get_channel_announcement(our_node_id.clone(), chain_hash) {
Ok(res) => res,
Err(_) => return None,
};
let msghash = hash_to_message!(&Sha256d::hash(&announcement.encode()[..])[..]);
match self.sign_channel_announcement(our_node_secret, our_node_id, msghash, announcement, our_bitcoin_sig) {
match self.sign_channel_announcement(our_node_id, announcement) {
Ok(res) => Some(res),
Err(_) => None,
}
Expand Down Expand Up @@ -6270,6 +6282,7 @@ mod tests {

let mut signer = InMemorySigner::new(
&secp_ctx,
SecretKey::from_slice(&hex::decode("4242424242424242424242424242424242424242424242424242424242424242").unwrap()[..]).unwrap(),
SecretKey::from_slice(&hex::decode("30ff4956bbdd3222d44cc5e8a1261dab1e07957bdac5ae88fe3261ef321f3749").unwrap()[..]).unwrap(),
SecretKey::from_slice(&hex::decode("0fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff").unwrap()[..]).unwrap(),
SecretKey::from_slice(&hex::decode("1111111111111111111111111111111111111111111111111111111111111111").unwrap()[..]).unwrap(),
Expand Down
19 changes: 3 additions & 16 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2896,20 +2896,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
log_trace!(self.logger, "Can't send announcement_signatures for private channel {}", log_bytes!(chan.channel_id()));
return None
}

let (announcement, our_bitcoin_sig) = match chan.get_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) {
Ok(res) => res,
Err(_) => return None, // Only in case of state precondition violations eg channel is closing
};
let msghash = hash_to_message!(&Sha256dHash::hash(&announcement.encode()[..])[..]);
let our_node_sig = self.secp_ctx.sign(&msghash, &self.our_network_key);

Some(msgs::AnnouncementSignatures {
channel_id: chan.channel_id(),
short_channel_id: chan.get_short_channel_id().unwrap(),
node_signature: our_node_sig,
bitcoin_signature: our_bitcoin_sig,
})
chan.get_announcement_sigs(self.get_our_node_id(), self.genesis_hash.clone()).ok()
}

#[allow(dead_code)]
Expand Down Expand Up @@ -2969,7 +2956,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana

let mut announced_chans = false;
for (_, chan) in channel_state.by_id.iter() {
if let Some(msg) = chan.get_signed_channel_announcement(&self.our_network_key, self.get_our_node_id(), self.genesis_hash.clone()) {
if let Some(msg) = chan.get_signed_channel_announcement(self.get_our_node_id(), self.genesis_hash.clone()) {
channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
msg,
update_msg: match self.get_channel_update_for_broadcast(chan) {
Expand Down Expand Up @@ -4674,7 +4661,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
}

channel_state.pending_msg_events.push(events::MessageSendEvent::BroadcastChannelAnnouncement {
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),
msg: try_chan_entry!(self, chan.get_mut().announcement_signatures(self.get_our_node_id(), self.genesis_hash.clone(), msg), channel_state, chan),
// Note that announcement_signatures fails if the channel cannot be announced,
// so get_channel_update_for_broadcast will never fail by the time we get here.
update_msg: self.get_channel_update_for_broadcast(chan.get()).unwrap(),
Expand Down
3 changes: 2 additions & 1 deletion lightning/src/util/enforcing_trait_impls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,8 @@ impl BaseSign for EnforcingSigner {
Ok(self.inner.sign_closing_transaction(closing_tx, secp_ctx).unwrap())
}

fn sign_channel_announcement(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>) -> Result<Signature, ()> {
fn sign_channel_announcement(&self, msg: &msgs::UnsignedChannelAnnouncement, secp_ctx: &Secp256k1<secp256k1::All>)
-> Result<(Signature, Signature), ()> {
self.inner.sign_channel_announcement(msg, secp_ctx)
}

Expand Down
5 changes: 3 additions & 2 deletions lightning/src/util/test_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,7 +79,8 @@ impl keysinterface::KeysInterface for OnlyReadsKeysInterface {
fn get_secure_random_bytes(&self) -> [u8; 32] { [0; 32] }

fn read_chan_signer(&self, mut reader: &[u8]) -> Result<Self::Signer, msgs::DecodeError> {
let inner: InMemorySigner = Readable::read(&mut reader)?;
let dummy_sk = SecretKey::from_slice(&[42; 32]).unwrap();
let inner: InMemorySigner = ReadableArgs::read(&mut reader, dummy_sk)?;
let state = Arc::new(Mutex::new(EnforcementState::new()));

Ok(EnforcingSigner::new_with_revoked(
Expand Down Expand Up @@ -519,7 +520,7 @@ impl keysinterface::KeysInterface for TestKeysInterface {
fn read_chan_signer(&self, buffer: &[u8]) -> Result<Self::Signer, msgs::DecodeError> {
let mut reader = io::Cursor::new(buffer);

let inner: InMemorySigner = Readable::read(&mut reader)?;
let inner: InMemorySigner = ReadableArgs::read(&mut reader, self.get_node_secret())?;
let state = self.make_enforcement_state_cell(inner.commitment_seed);

Ok(EnforcingSigner::new_with_revoked(
Expand Down