From: Matt Corallo Date: Mon, 29 Aug 2022 18:42:34 +0000 (+0000) Subject: Fix spurious panic on receipt of a block while awaiting funding X-Git-Tag: v0.0.111~7^2 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=refs%2Fheads%2F2022-08-0conf-panic;p=rust-lightning Fix spurious panic on receipt of a block while awaiting funding When we receive a block we always test if we should send our channel_ready via `check_get_channel_ready`. If the channel in question requires confirmations, we quickly return if the funding transaction has not yet confirmed (or even been defined), however for 0conf channels the checks are necessarily more involved. In any case, we wish to panic if the funding transaction has confirmations prior to when it should have been broadcasted. This is useful as it is easy for users to violate our broadcast-time invariants without noticing and the panic gives us an opportunity to catch it. Sadly, in the case of 0conf channels, if we hadn't yet seen the funding transaction at all but receive a block we would hit this sanity check as we don't check whether there are actually funding transaction confirmations prior to panicing. --- diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 6da5de043..d4da0ccb0 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -4755,6 +4755,9 @@ impl Channel { } fn check_get_channel_ready(&mut self, height: u32) -> Option { + // Called: + // * always when a new block/transactions are confirmed with the new height + // * when funding is signed with a height of 0 if self.funding_tx_confirmation_height == 0 && self.minimum_depth != Some(0) { return None; } @@ -4780,7 +4783,7 @@ impl Channel { // We got a reorg but not enough to trigger a force close, just ignore. false } else { - if self.channel_state < ChannelState::ChannelFunded as u32 { + if self.funding_tx_confirmation_height != 0 && self.channel_state < ChannelState::ChannelFunded as u32 { // We should never see a funding transaction on-chain until we've received // funding_signed (if we're an outbound channel), or seen funding_generated (if we're // an inbound channel - before that we have no known funding TXID). The fuzzer, diff --git a/lightning/src/ln/priv_short_conf_tests.rs b/lightning/src/ln/priv_short_conf_tests.rs index ed0311945..35b5c20c6 100644 --- a/lightning/src/ln/priv_short_conf_tests.rs +++ b/lightning/src/ln/priv_short_conf_tests.rs @@ -1021,3 +1021,45 @@ fn test_zero_conf_accept_reject() { _ => panic!(), } } + +#[test] +fn test_connect_before_funding() { + // Tests for a particularly dumb explicit panic that existed prior to 0.0.111 for 0conf + // channels. If we received a block while awaiting funding for 0-conf channels we'd hit an + // explicit panic when deciding if we should broadcast our channel_ready message. + let chanmon_cfgs = create_chanmon_cfgs(2); + let node_cfgs = create_node_cfgs(2, &chanmon_cfgs); + + let mut manually_accept_conf = test_default_channel_config(); + manually_accept_conf.manually_accept_inbound_channels = true; + + let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[None, Some(manually_accept_conf)]); + let nodes = create_network(2, &node_cfgs, &node_chanmgrs); + + nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 10_001, 42, None).unwrap(); + let open_channel = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id()); + + nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), InitFeatures::known(), &open_channel); + let events = nodes[1].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::OpenChannelRequest { temporary_channel_id, .. } => { + nodes[1].node.accept_inbound_channel_from_trusted_peer_0conf(&temporary_channel_id, &nodes[0].node.get_our_node_id(), 0).unwrap(); + }, + _ => panic!("Unexpected event"), + }; + + let mut accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id()); + assert_eq!(accept_channel.minimum_depth, 0); + nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), InitFeatures::known(), &accept_channel); + + let events = nodes[0].node.get_and_clear_pending_events(); + assert_eq!(events.len(), 1); + match events[0] { + Event::FundingGenerationReady { .. } => {}, + _ => panic!("Unexpected event"), + } + + connect_blocks(&nodes[0], 1); + connect_blocks(&nodes[1], 1); +}