Skip to content
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

Fix infinite loop when closing a pre-funding channel #2760

Merged
merged 5 commits into from Dec 8, 2023

Conversation

TheBlueMatt
Copy link
Collaborator

Because a Funded Channel cannot possibly be pre-funding, the
logic in ChannelManager::close_channel_internal to handle
pre-funding channels is in the wrong place.

Rather than being handled inside the Funded branch, it should be
in an else following it, handling either of the two
ChannelPhases outside of Funded.

Sadly, because of a previous control flow management loop {}, the
existing code will infinite loop, which is fixed here.

@TheBlueMatt TheBlueMatt added this to the 0.0.119 milestone Nov 29, 2023
Copy link
Contributor

@luckysori luckysori left a comment

Choose a reason for hiding this comment

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

FWIW, 73b20e2 LGTM. Thanks!

I still have to try it with the test that was failing for us.

tnull
tnull previously approved these changes Nov 29, 2023
Copy link
Contributor

@tnull tnull left a comment

Choose a reason for hiding this comment

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

LGTM, but since I wasn't involved in the Channel refactor I'll leave merging to a second reviewer. Also, CI seems to need some kicking.

Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

ACK

  • Verified the infinite loop case by reverting changes in this PR and running the test introduced here. And, as expected, the code got stuck in an endless loop.
  • Verified that the code works as intended, allowing the proper closing of pre-funding channels.

lightning/src/ln/shutdown_tests.rs Outdated Show resolved Hide resolved
@TheBlueMatt
Copy link
Collaborator Author

Lol I was paying no attention and built this on 0.0.118, rather than git HEAD, rebased now.

@codecov-commenter
Copy link

codecov-commenter commented Nov 30, 2023

Codecov Report

Attention: 27 lines in your changes are missing coverage. Please review.

Comparison is base (2d26679) 88.52% compared to head (5ba4c07) 88.52%.

Files Patch % Lines
lightning/src/ln/channel.rs 89.43% 6 Missing and 9 partials ⚠️
lightning/src/ln/channelmanager.rs 82.35% 9 Missing and 3 partials ⚠️

❗ Your organization needs to install the Codecov GitHub app to enable full functionality.

Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2760      +/-   ##
==========================================
- Coverage   88.52%   88.52%   -0.01%     
==========================================
  Files         115      115              
  Lines       90996    90999       +3     
  Branches    90996    90999       +3     
==========================================
+ Hits        80557    80558       +1     
- Misses       8012     8014       +2     
  Partials     2427     2427              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@TheBlueMatt
Copy link
Collaborator Author

Okay, pushed two commits to start to redo the line between funded and unfunded channels yet again, but I think everyone should be happy with this (it was the original idea, and now no longer has the temporary-vs-post-funding-channel-id map key problem).

dunxen
dunxen previously approved these changes Nov 30, 2023

/// Handles a funding_signed message from the remote end.
/// If this call is successful, broadcast the funding transaction (and not before!)
pub fn funding_signed<L: Deref>(
Copy link
Contributor

Choose a reason for hiding this comment

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

Ok this makes sense for unfunded V1 channels since there's no need to persist the channel before a funding_signed. Also it's great that this is only in outbound now.
It has given me a little more to think about in the V2 case.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Yea, sorry for the back-and-forth on it, I know we'd discussed this originally but I think I pushed back cause I was annoyed about the different channel id keys.

Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

ACK modulo nit

(Adding to my previous review)

Thanks for this great update to the codebase! 🚀

  • Handling funding signed from the remote end, is a behavior specific to OutboundV1Channel, and until the funding sign is handled, the OutboundV1Channel is not yet technically a Channel.
  • So it makes sense to make this handler part of the OutboundV1Channel struct.
  • Updates to the code are clean and clear, and a few added comments are helpful.
  • All the tests of the codebase pass, and hence, there is no broken behavioral change.

lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
Copy link
Contributor

@wpaulino wpaulino left a comment

Choose a reason for hiding this comment

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

Needs a rebase

lightning/src/ln/channel.rs Show resolved Hide resolved
lightning/src/ln/channelmanager.rs Outdated Show resolved Hide resolved
@TheBlueMatt
Copy link
Collaborator Author

Rebased and addressed feedback:

$ git range-diff 4fc3a171152140860440311743178d922c6b7c4b..5db34c58542b06ae8f92d186aab45b43b6d28956 37150b4d697f723f278b6cf3f63892df272b9aa5..3f6e29bd0519dba925992b24455118f1a4e3400d
1:  1de0f5f45 ! 1:  c8124e4fb Move to `Funded` after `funding_signed` rather than on funding
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
     -                                                    funding_redeemscript.clone(), self.context.channel_value_satoshis,
     -                                                    obscure_factor,
     -                                                    holder_commitment_tx, best_block, self.context.counterparty_node_id);
    --
    +-          let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor);
     -          channel_monitor.provide_initial_counterparty_commitment_tx(
     -                  counterparty_initial_bitcoin_tx.txid, Vec::new(),
     -                  self.context.cur_counterparty_commitment_transaction_number,
     -                  self.context.counterparty_cur_commitment_point.unwrap(),
     -                  counterparty_initial_commitment_tx.feerate_per_kw(),
     -                  counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
    --                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
    +-                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor);
     -
     -          assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update!
     -          if self.context.is_batch_funding() {
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Tar
     +          Ok(funding_created)
        }

    -+
        fn get_initial_channel_type(config: &UserConfig, their_features: &InitFeatures) -> ChannelTypeFeatures {
    -           // The default channel type (ie the first one we try) depends on whether the channel is
    -           // public - if it is, we just go with `only_static_remotekey` as it's the only option
     @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Target: SignerProvider {

                Ok(())
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Tar
     +                                                    funding_redeemscript.clone(), self.context.channel_value_satoshis,
     +                                                    obscure_factor,
     +                                                    holder_commitment_tx, best_block, self.context.counterparty_node_id);
    -+
    ++          let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor);
     +          channel_monitor.provide_initial_counterparty_commitment_tx(
     +                  counterparty_initial_bitcoin_tx.txid, Vec::new(),
     +                  self.context.cur_counterparty_commitment_transaction_number,
     +                  self.context.counterparty_cur_commitment_point.unwrap(),
     +                  counterparty_initial_commitment_tx.feerate_per_kw(),
     +                  counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
    -+                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
    ++                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor);
     +
     +          assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update!
     +          if self.context.is_batch_funding() {
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Tar
      }

      /// A not-yet-funded inbound (from counterparty) channel using V1 channel establishment.
    -@@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
    +@@ lightning/src/ln/channel.rs: mod tests {
                        value: 10000000, script_pubkey: output_script.clone(),
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
    @@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, P

                // Put some inbound and outbound HTLCs in A's channel.
                let htlc_amount_msat = 11_092_000; // put an amount below A's effective dust limit but above B's.
    -@@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
    +@@ lightning/src/ln/channel.rs: mod tests {
                        value: 10000000, script_pubkey: output_script.clone(),
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
    @@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, P

                // Now disconnect the two nodes and check that the commitment point in
                // Node B's channel_reestablish message is sane.
    -@@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
    +@@ lightning/src/ln/channel.rs: mod tests {
                        value: 10000000, script_pubkey: output_script.clone(),
                }]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
    @@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, P

                // Make sure that receiving a channel update will update the Channel as expected.
                let update = ChannelUpdate {
    -@@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
    +@@ lightning/src/ln/channel.rs: mod tests {
                                },
                        ]};
                let funding_outpoint = OutPoint{ txid: tx.txid(), index: 0 };
    @@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, P
                ).map_err(|_| ()).unwrap();
                let (mut node_b_chan, funding_signed_msg, _) = node_b_chan.funding_created(
                        &funding_created_msg.unwrap(),
    -@@ lightning/src/ln/channel.rs: use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
    +@@ lightning/src/ln/channel.rs: mod tests {

                // Receive funding_signed, but the channel will be configured to hold sending channel_ready and
                // broadcasting the funding transaction until the batch is ready.
    @@ lightning/src/ln/channelmanager.rs: where
     +                  Some(ChannelPhase::UnfundedOutboundV1(mut chan)) => {
                                let funding_txo = find_funding_output(&chan, &funding_transaction)?;

    -                           let funding_res = chan.get_funding_created(funding_transaction, funding_txo, is_batch_funding, &self.logger)
    +                           let logger = WithChannelContext::from(&self.logger, &chan.context);
     @@ lightning/src/ln/channelmanager.rs: where
                                                (chan, MsgHandleErrInternal::from_finish_shutdown(msg, channel_id, user_id, shutdown_res, None, channel_capacity))
                                        } else { unreachable!(); });
    @@ lightning/src/ln/channelmanager.rs: where
                        }
                }
                Ok(())
    +@@ lightning/src/ln/channelmanager.rs: where
    +                                           // We got a temporary failure updating monitor, but will claim the
    +                                           // HTLC when the monitor updating is restored (or on chain).
    +                                           let logger = WithContext::from(&self.logger, None, Some(prev_hop_chan_id));
    +-                                          log_error!(self.logger, "Temporary failure claiming HTLC, treating as success: {}", err.err.err);
    ++                                          log_error!(logger, "Temporary failure claiming HTLC, treating as success: {}", err.err.err);
    +                                   } else { errs.push((pk, err)); }
    +                           }
    +                   }
     @@ lightning/src/ln/channelmanager.rs: where
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
    @@ lightning/src/ln/channelmanager.rs: where
     -                  hash_map::Entry::Occupied(mut chan_phase_entry) => {
     -                          match chan_phase_entry.get_mut() {
     -                                  ChannelPhase::Funded(ref mut chan) => {
    +-                                          let logger = WithChannelContext::from(&self.logger, &chan.context);
     -                                          let monitor = try_chan_phase_entry!(self,
    --                                                  chan.funding_signed(&msg, best_block, &self.signer_provider, &self.logger), chan_phase_entry);
    +-                                                  chan.funding_signed(&msg, best_block, &self.signer_provider, &&logger), chan_phase_entry);
     -                                          if let Ok(persist_status) = self.chain_monitor.watch_channel(chan.context.get_funding_txo().unwrap(), monitor) {
     -                                                  handle_new_monitor_update!(self, persist_status, peer_state_lock, peer_state, per_peer_state, chan, INITIAL_MONITOR);
     -                                                  Ok(())
    @@ lightning/src/ln/channelmanager.rs: where
     +                  hash_map::Entry::Occupied(chan_phase_entry) => {
     +                          if matches!(chan_phase_entry.get(), ChannelPhase::UnfundedOutboundV1(_)) {
     +                                  let chan = if let ChannelPhase::UnfundedOutboundV1(chan) = chan_phase_entry.remove() { chan } else { unreachable!() };
    ++                                  let logger = WithContext::from(
    ++                                          &self.logger,
    ++                                          Some(chan.context.get_counterparty_node_id()),
    ++                                          Some(chan.context.channel_id())
    ++                                  );
     +                                  let res =
    -+                                          chan.funding_signed(&msg, best_block, &self.signer_provider, &self.logger);
    ++                                          chan.funding_signed(&msg, best_block, &self.signer_provider, &&logger);
     +                                  match res {
     +                                          Ok((chan, monitor)) => {
     +                                                  if let Ok(persist_status) = self.chain_monitor.watch_channel(chan.context.get_funding_txo().unwrap(), monitor) {
    @@ lightning/src/ln/channelmanager.rs: where
     +                                          Err((chan, e)) => {
     +                                                  debug_assert!(matches!(e, ChannelError::Close(_)),
     +                                                          "We don't have a channel anymore, so the error better have expected close");
    -+                                                  // We've already removed this inbound channel from the map in `PeerState`
    -+                                                  // above so at this point we just need to clean up any lingering entries
    -+                                                  // concerning this channel as it is safe to do so.
    ++                                                  // We've already removed this outbound channel from the map in
    ++                                                  // `PeerState` above so at this point we just need to clean up any
    ++                                                  // lingering entries concerning this channel as it is safe to do so.
     +                                                  return Err(convert_chan_phase_err!(self, e, &mut ChannelPhase::UnfundedOutboundV1(chan), &msg.channel_id).1);
                                                }
     -                                  },
2:  fc8daa30e ! 2:  973de6f4e Limit the scope of `get_funding_created_msg` to outbound channels
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> ChannelContext<SP> where SP::Target
     -          let signature = match &self.holder_signer {
     -                  // TODO (taproot|arik): move match into calling method for Taproot
     -                  ChannelSignerType::Ecdsa(ecdsa) => {
    --                          ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.secp_ctx)
    +-                          ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.secp_ctx)
     -                                  .map(|(sig, _)| sig).ok()?
     -                  },
     -                  // TODO (taproot|arik)
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Tar
                })
        }

    -+  /// Only allowed after [`Self::channel_transaction_parameters`] is set.
    ++  /// Only allowed after [`ChannelContext::channel_transaction_parameters`] is set.
     +  fn get_funding_created_msg<L: Deref>(&mut self, logger: &L) -> Option<msgs::FundingCreated> where L::Target: Logger {
     +          let counterparty_keys = self.context.build_remote_transaction_keys();
     +          let counterparty_initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_counterparty_commitment_transaction_number, &counterparty_keys, false, false, logger).tx;
     +          let signature = match &self.context.holder_signer {
     +                  // TODO (taproot|arik): move match into calling method for Taproot
     +                  ChannelSignerType::Ecdsa(ecdsa) => {
    -+                          ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
    ++                          ecdsa.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), Vec::new(), &self.context.secp_ctx)
     +                                  .map(|(sig, _)| sig).ok()?
     +                  },
     +                  // TODO (taproot|arik)
3:  0e264f9df ! 3:  bfb503eec Drop unreachable shutdown code in `Channel::get_shutdown`
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
     -                          monitor_update: None,
     -                          dropped_outbound_htlcs: Vec::new(),
     -                          unbroadcasted_batch_funding_txid: self.context.unbroadcasted_batch_funding_txid(),
    +-                          channel_id: self.context.channel_id,
    +-                          counterparty_node_id: self.context.counterparty_node_id,
     -                  };
     -                  self.context.channel_state = ChannelState::ShutdownComplete as u32;
     -                  Some(shutdown_result)
4:  80f9d505a = 4:  0d3000520 Move pre-funded-channel immediate shutdown logic to the right place
5:  5db34c585 = 5:  3f6e29bd0 Immediately error in `close_channel_internal` if there is no chan

wpaulino
wpaulino previously approved these changes Dec 5, 2023
Copy link
Contributor

@shaavan shaavan left a comment

Choose a reason for hiding this comment

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

ACK! 🚀

@wpaulino
Copy link
Contributor

wpaulino commented Dec 7, 2023

Needs rebase

Previously, channels were stored in different maps in `PeerState`
based on whether the funding had been set, keeping the keys across
the maps consistent (pre-funding temporary_channel_ids vs
funding-outpoint-based channel_ids). However, channels are now
stored in a single `channel_by_id` map, making that point moot.

Instead, here, we convert the `ChannelPhase` state transition
boundary to "once we have a `ChannelMonitor`", which makes more
sense now, and was actually the original proposed boundary.

This also requires calling `signer_maybe_unblocked` on a pre-funded
outbound channel, but that nicely also lets us limit the scope of
`FundingCreated` message generation, which we do in the next
commit.
Since we no longer use `ChannelContext::get_funding_created_msg`,
it can be moved back into `UnfundedOutboundV1` channels only,
where it realistically belongs.
`Channel` is only a thing for funded channels. Thus, checking if a
channel has not yet been funded is dead code and can simply be
elided.
Because a `Funded` `Channel` cannot possibly be pre-funding, the
logic in `ChannelManager::close_channel_internal` to handle
pre-funding channels is in the wrong place.

Rather than being handled inside the `Funded` branch, it should be
in an `else` following it, handling either of the two
`ChannelPhases` outside of `Funded`.

Sadly, because of a previous control flow management `loop {}`, the
existing code will infinite loop, which is fixed here.
Previously, unfunded channels would be stored outside of
`PeerState::channel_by_id`, and thus if there is no channel when
we look in `PeerState::channel_by_id`, `close_channel_internal`
called `force_close_channel_with_peer` to hunt for unfunded
channels.

However, that is no longer the case, so the call is redundant, and
we can simply return an error instead.
@TheBlueMatt
Copy link
Collaborator Author

Rebased:

$ git range-diff 37150b4d697f723f278b6cf3f63892df272b9aa5..3f6e29bd0519dba925992b24455118f1a4e3400d 2d266794c2133782938ce62a96538ef138c85781..5ba4c079bb242f5a0279a36d24ba87e3d8d1d528
1:  c8124e4fb ! 1:  6ab56a40b Move to `Funded` after `funding_signed` rather than on funding
    @@ lightning/src/ln/channel.rs: pub(super) struct MonitorRestoreUpdates {
      }

     @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
    +   }

        // Message handlers:
    -
    +-
     -  /// Handles a funding_signed message from the remote end.
     -  /// If this call is successful, broadcast the funding transaction (and not before!)
     -  pub fn funding_signed<L: Deref>(
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
     -          if !self.context.is_outbound() {
     -                  return Err(ChannelError::Close("Received funding_signed for an inbound channel?".to_owned()));
     -          }
    --          if self.context.channel_state & !(ChannelState::MonitorUpdateInProgress as u32) != ChannelState::FundingCreated as u32 {
    +-          if !matches!(self.context.channel_state, ChannelState::FundingNegotiated) {
     -                  return Err(ChannelError::Close("Received funding_signed in strange state!".to_owned()));
     -          }
     -          if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
     -                                                    funding_redeemscript.clone(), self.context.channel_value_satoshis,
     -                                                    obscure_factor,
     -                                                    holder_commitment_tx, best_block, self.context.counterparty_node_id);
    --          let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor);
     -          channel_monitor.provide_initial_counterparty_commitment_tx(
     -                  counterparty_initial_bitcoin_tx.txid, Vec::new(),
     -                  self.context.cur_counterparty_commitment_transaction_number,
     -                  self.context.counterparty_cur_commitment_point.unwrap(),
     -                  counterparty_initial_commitment_tx.feerate_per_kw(),
     -                  counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
    --                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor);
    +-                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
     -
    --          assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update!
    +-          assert!(!self.context.channel_state.is_monitor_update_in_progress()); // We have no had any monitor(s) yet to fail update!
     -          if self.context.is_batch_funding() {
    --                  self.context.channel_state = ChannelState::FundingSent as u32 | ChannelState::WaitingForBatch as u32;
    +-                  self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH);
     -          } else {
    --                  self.context.channel_state = ChannelState::FundingSent as u32;
    +-                  self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
     -          }
     -          self.context.cur_holder_commitment_transaction_number -= 1;
     -          self.context.cur_counterparty_commitment_transaction_number -= 1;
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Tar
     +          if !self.context.is_outbound() {
     +                  return Err((self, ChannelError::Close("Received funding_signed for an inbound channel?".to_owned())));
     +          }
    -+          if self.context.channel_state & !(ChannelState::MonitorUpdateInProgress as u32) != ChannelState::FundingCreated as u32 {
    ++          if !matches!(self.context.channel_state, ChannelState::FundingNegotiated) {
     +                  return Err((self, ChannelError::Close("Received funding_signed in strange state!".to_owned())));
     +          }
     +          if self.context.commitment_secrets.get_min_seen_secret() != (1 << 48) ||
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> OutboundV1Channel<SP> where SP::Tar
     +                                                    funding_redeemscript.clone(), self.context.channel_value_satoshis,
     +                                                    obscure_factor,
     +                                                    holder_commitment_tx, best_block, self.context.counterparty_node_id);
    -+          let logger_with_chan_monitor = WithChannelMonitor::from(logger, &channel_monitor);
     +          channel_monitor.provide_initial_counterparty_commitment_tx(
     +                  counterparty_initial_bitcoin_tx.txid, Vec::new(),
     +                  self.context.cur_counterparty_commitment_transaction_number,
     +                  self.context.counterparty_cur_commitment_point.unwrap(),
     +                  counterparty_initial_commitment_tx.feerate_per_kw(),
     +                  counterparty_initial_commitment_tx.to_broadcaster_value_sat(),
    -+                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), &&logger_with_chan_monitor);
    ++                  counterparty_initial_commitment_tx.to_countersignatory_value_sat(), logger);
     +
    -+          assert_eq!(self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32), 0); // We have no had any monitor(s) yet to fail update!
    ++          assert!(!self.context.channel_state.is_monitor_update_in_progress()); // We have no had any monitor(s) yet to fail update!
     +          if self.context.is_batch_funding() {
    -+                  self.context.channel_state = ChannelState::FundingSent as u32 | ChannelState::WaitingForBatch as u32;
    ++                  self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::WAITING_FOR_BATCH);
     +          } else {
    -+                  self.context.channel_state = ChannelState::FundingSent as u32;
    ++                  self.context.channel_state = ChannelState::AwaitingChannelReady(AwaitingChannelReadyFlags::new());
     +          }
     +          self.context.cur_holder_commitment_transaction_number -= 1;
     +          self.context.cur_counterparty_commitment_transaction_number -= 1;
2:  973de6f4e = 2:  8e519b56d Limit the scope of `get_funding_created_msg` to outbound channels
3:  bfb503eec ! 3:  1667b4d20 Drop unreachable shutdown code in `Channel::get_shutdown`
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
     -          // If we haven't funded the channel yet, we don't need to bother ensuring the shutdown
     -          // script is set, we just force-close and call it a day.
     -          let mut chan_closed = false;
    --          if self.context.channel_state & !STATE_FLAGS < ChannelState::FundingSent as u32 {
    +-          if self.context.channel_state.is_pre_funded_state() {
     -                  chan_closed = true;
     -          }
     -
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where

                // From here on out, we may not fail!
                self.context.target_closing_feerate_sats_per_kw = target_feerate_sats_per_kw;
    --          let shutdown_result = if self.context.channel_state & !STATE_FLAGS < ChannelState::FundingSent as u32 {
    +-          let shutdown_result = if self.context.channel_state.is_pre_funded_state() {
     -                  let shutdown_result = ShutdownResult {
     -                          monitor_update: None,
     -                          dropped_outbound_htlcs: Vec::new(),
    @@ lightning/src/ln/channel.rs: impl<SP: Deref> Channel<SP> where
     -                          channel_id: self.context.channel_id,
     -                          counterparty_node_id: self.context.counterparty_node_id,
     -                  };
    --                  self.context.channel_state = ChannelState::ShutdownComplete as u32;
    +-                  self.context.channel_state = ChannelState::ShutdownComplete;
     -                  Some(shutdown_result)
     -          } else {
    --                  self.context.channel_state |= ChannelState::LocalShutdownSent as u32;
    +-                  self.context.channel_state.set_local_shutdown_sent();
     -                  None
     -          };
    -+          self.context.channel_state |= ChannelState::LocalShutdownSent as u32;
    ++          self.context.channel_state.set_local_shutdown_sent();
                self.context.update_time_counter += 1;

                let monitor_update = if update_shutdown_script {
4:  0d3000520 = 4:  3a2690c8a Move pre-funded-channel immediate shutdown logic to the right place
5:  3f6e29bd0 = 5:  5ba4c079b Immediately error in `close_channel_internal` if there is no chan

@wpaulino wpaulino merged commit ec8e0fe into lightningdevkit:main Dec 8, 2023
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

7 participants