From: Matt Corallo Date: Fri, 4 Mar 2022 21:24:39 +0000 (+0000) Subject: Handle cases where a channel is in use w/o an SCID in ChannelManager X-Git-Tag: v0.0.107~13^2~9 X-Git-Url: http://git.bitcoin.ninja/?a=commitdiff_plain;h=585493a3e1654e57d8be79b7d405d1290abe7ea1;p=rust-lightning Handle cases where a channel is in use w/o an SCID in ChannelManager In the next few commits we add support for 0conf channels, allowing us to have an active channel with HTLC and other updates flying prior to having an SCID available. This would break several assumptions made in `ChannelManager`, which we address here by looking at SCID aliases in addition to SCIDs. --- diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs index 43032c51a..a0b19920f 100644 --- a/lightning/src/ln/channel.rs +++ b/lightning/src/ln/channel.rs @@ -3565,9 +3565,10 @@ impl Channel { // We will never broadcast the funding transaction when we're in MonitorUpdateFailed (and // we assume the user never directly broadcasts the funding transaction and waits for us to - // do it). Thus, we can only ever hit monitor_pending_funding_locked when we're an inbound - // channel which failed to persist the monitor on funding_created, and we got the funding - // transaction confirmed before the monitor was persisted. + // do it). Thus, we can only ever hit monitor_pending_funding_locked when we're + // * an inbound channel that failed to persist the monitor on funding_created and we got + // the funding transaction confirmed before the monitor was persisted, or + // * a 0-conf channel and intended to send the funding_locked before any broadcast at all. let funding_locked = if self.monitor_pending_funding_locked { assert!(!self.is_outbound(), "Funding transaction broadcast by the local client before it should have - LDK didn't do it!"); self.monitor_pending_funding_locked = false; diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 8725059c3..239b45ebf 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -93,6 +93,8 @@ use util::crypto::sign; pub(super) enum PendingHTLCRouting { Forward { onion_packet: msgs::OnionPacket, + /// The SCID from the onion that we should forward to. This could be a "real" SCID, an + /// outbound SCID alias, or a phantom node SCID. short_channel_id: u64, // This should be NonZero eventually when we bump MSRV }, Receive { @@ -136,6 +138,8 @@ pub(super) enum HTLCForwardInfo { // `process_pending_htlc_forwards()` for constructing the // `HTLCSource::PreviousHopData` for failed and forwarded // HTLCs. + // + // Note that this may be an outbound SCID alias for the associated channel. prev_short_channel_id: u64, prev_htlc_id: u64, prev_funding_outpoint: OutPoint, @@ -149,6 +153,7 @@ pub(super) enum HTLCForwardInfo { /// Tracks the inbound corresponding to an outbound HTLC #[derive(Clone, Hash, PartialEq, Eq)] pub(crate) struct HTLCPreviousHopData { + // Note that this may be an outbound SCID alias for the associated channel. short_channel_id: u64, htlc_id: u64, incoming_packet_shared_secret: [u8; 32], @@ -1398,7 +1403,7 @@ macro_rules! handle_chan_restoration_locked { let res = loop { let forwards: Vec<(PendingHTLCInfo, u64)> = $pending_forwards; // Force type-checking to resolve if !forwards.is_empty() { - htlc_forwards = Some(($channel_entry.get().get_short_channel_id().expect("We can't have pending forwards before funding confirmation"), + htlc_forwards = Some(($channel_entry.get().get_short_channel_id().unwrap_or($channel_entry.get().outbound_scid_alias()), $channel_entry.get().get_funding_txo().unwrap(), forwards)); } @@ -4676,7 +4681,7 @@ impl ChannelMana break Ok((raa_updates.accepted_htlcs, raa_updates.failed_htlcs, raa_updates.finalized_claimed_htlcs, chan.get().get_short_channel_id() - .expect("RAA should only work on a short-id-available channel"), + .unwrap_or(chan.get().outbound_scid_alias()), chan.get().get_funding_txo().unwrap())) }, hash_map::Entry::Vacant(_) => break Err(MsgHandleErrInternal::send_err_msg_no_close("Failed to find corresponding channel".to_owned(), msg.channel_id))