Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions lightning/src/ln/channel.rs
Original file line number Diff line number Diff line change
Expand Up @@ -948,9 +948,9 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
&self.channel_type
}

/// Guaranteed to be Some after both ChannelReady messages have been exchanged (and, thus,
/// is_usable() returns true).
/// Allowed in any state (including after shutdown)
/// Gets the channel's `short_channel_id`.
///
/// Will return `None` if the channel hasn't been confirmed yet.
pub fn get_short_channel_id(&self) -> Option<u64> {
self.short_channel_id
}
Expand Down Expand Up @@ -4832,6 +4832,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
return Err(ChannelError::Ignore("Cannot get a ChannelAnnouncement if the channel is not currently usable".to_owned()));
}

let short_channel_id = self.context.get_short_channel_id()
.ok_or(ChannelError::Ignore("Cannot get a ChannelAnnouncement if the channel has not been confirmed yet".to_owned()))?;
let node_id = NodeId::from_pubkey(&node_signer.get_node_id(Recipient::Node)
.map_err(|_| ChannelError::Ignore("Failed to retrieve own public key".to_owned()))?);
let counterparty_node_id = NodeId::from_pubkey(&self.context.get_counterparty_node_id());
Expand All @@ -4840,7 +4842,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
let msg = msgs::UnsignedChannelAnnouncement {
features: channelmanager::provided_channel_features(&user_config),
chain_hash,
short_channel_id: self.context.get_short_channel_id().unwrap(),
short_channel_id,
node_id_1: if were_node_one { node_id } else { counterparty_node_id },
node_id_2: if were_node_one { counterparty_node_id } else { node_id },
bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.context.get_holder_pubkeys().funding_pubkey } else { self.context.counterparty_funding_pubkey() }),
Expand Down Expand Up @@ -4898,11 +4900,16 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
},
Ok(v) => v
};
let short_channel_id = match self.context.get_short_channel_id() {
Some(scid) => scid,
None => return None,
};

self.context.announcement_sigs_state = AnnouncementSigsState::MessageSent;

Some(msgs::AnnouncementSignatures {
channel_id: self.context.channel_id(),
short_channel_id: self.context.get_short_channel_id().unwrap(),
short_channel_id,
node_signature: our_node_sig,
bitcoin_signature: our_bitcoin_sig,
})
Expand Down
35 changes: 35 additions & 0 deletions lightning/src/ln/priv_short_conf_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1007,3 +1007,38 @@ fn test_connect_before_funding() {
connect_blocks(&nodes[0], 1);
connect_blocks(&nodes[1], 1);
}

#[test]
fn test_0conf_ann_sigs_racing_conf() {
// Previously we had a bug where we'd panic when receiving a counterparty's
// announcement_signatures message for a 0conf channel pending confirmation on-chain. Here we
// check that we just error out, ignore the announcement_signatures message, and proceed
// instead.
let chanmon_cfgs = create_chanmon_cfgs(2);
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
let mut chan_config = test_default_channel_config();
chan_config.manually_accept_inbound_channels = true;

let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(chan_config)]);
let nodes = create_network(2, &node_cfgs, &node_chanmgrs);

// This is the default but we force it on anyway
chan_config.channel_handshake_config.announced_channel = true;
let (tx, ..) = open_zero_conf_channel(&nodes[0], &nodes[1], Some(chan_config));

// We can use the channel immediately, but we can't announce it until we get 6+ confirmations
send_payment(&nodes[0], &[&nodes[1]], 100_000);

let scid = confirm_transaction(&nodes[0], &tx);
let as_announcement_sigs = get_event_msg!(nodes[0], MessageSendEvent::SendAnnouncementSignatures, nodes[1].node.get_our_node_id());

// Handling the announcement_signatures prior to the first confirmation would panic before.
nodes[1].node.handle_announcement_signatures(&nodes[0].node.get_our_node_id(), &as_announcement_sigs);

assert_eq!(confirm_transaction(&nodes[1], &tx), scid);
let bs_announcement_sigs = get_event_msg!(nodes[1], MessageSendEvent::SendAnnouncementSignatures, nodes[0].node.get_our_node_id());

nodes[0].node.handle_announcement_signatures(&nodes[1].node.get_our_node_id(), &bs_announcement_sigs);
let as_announcement = nodes[0].node.get_and_clear_pending_msg_events();
assert_eq!(as_announcement.len(), 1);
}