mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-25 07:17:40 +01:00
Avoid panic when 0conf channel's ann. sigs race on-chain confirmation
A channel's `short_channel_id` is currently only set when the funding transaction is confirmed via `transactions_confirmed`, which might be well after the channel initally becomes usable, e.g., in the 0conf case. Previously we would panic due to a reachable `unwrap` when receiving a counterparty's `announcement_signatures` message for a 0conf channel pending confirmation on-chain. Here we fix this bug by avoiding unsafe `unwrap`s and just erroring out and ignoring the announcement_signatures message if the `short_channel_id` hasn't been set yet.
This commit is contained in:
parent
ae9e96e277
commit
82fdf0f62d
2 changed files with 41 additions and 4 deletions
|
@ -948,9 +948,9 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
|
||||||
&self.channel_type
|
&self.channel_type
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Guaranteed to be Some after both ChannelReady messages have been exchanged (and, thus,
|
/// Gets the channel's `short_channel_id`.
|
||||||
/// is_usable() returns true).
|
///
|
||||||
/// Allowed in any state (including after shutdown)
|
/// Will return `None` if the channel hasn't been confirmed yet.
|
||||||
pub fn get_short_channel_id(&self) -> Option<u64> {
|
pub fn get_short_channel_id(&self) -> Option<u64> {
|
||||||
self.short_channel_id
|
self.short_channel_id
|
||||||
}
|
}
|
||||||
|
@ -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()));
|
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)
|
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()))?);
|
.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());
|
let counterparty_node_id = NodeId::from_pubkey(&self.context.get_counterparty_node_id());
|
||||||
|
@ -4840,7 +4842,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
|
||||||
let msg = msgs::UnsignedChannelAnnouncement {
|
let msg = msgs::UnsignedChannelAnnouncement {
|
||||||
features: channelmanager::provided_channel_features(&user_config),
|
features: channelmanager::provided_channel_features(&user_config),
|
||||||
chain_hash,
|
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_1: if were_node_one { node_id } else { counterparty_node_id },
|
||||||
node_id_2: if were_node_one { counterparty_node_id } else { 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() }),
|
bitcoin_key_1: NodeId::from_pubkey(if were_node_one { &self.context.get_holder_pubkeys().funding_pubkey } else { self.context.counterparty_funding_pubkey() }),
|
||||||
|
|
|
@ -1007,3 +1007,38 @@ fn test_connect_before_funding() {
|
||||||
connect_blocks(&nodes[0], 1);
|
connect_blocks(&nodes[0], 1);
|
||||||
connect_blocks(&nodes[1], 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);
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue