Merge pull request #2816 from wpaulino/retryable-holder-sigs
authorMatt Corallo <649246+TheBlueMatt@users.noreply.github.com>
Tue, 13 Feb 2024 21:22:55 +0000 (21:22 +0000)
committerGitHub <noreply@github.com>
Tue, 13 Feb 2024 21:22:55 +0000 (21:22 +0000)
Allow holder commitment and HTLC signature requests to fail

1  2 
lightning/src/ln/async_signer_tests.rs
lightning/src/ln/channel.rs
lightning/src/ln/channelmanager.rs
lightning/src/ln/functional_test_utils.rs

index 2beb3c2d0516a7f421fa1767da7ff4db1df062d6,10f4239a188dd225114f1ea06bcb93835aa7fb64..613df570d4e3bf40051d25e59a5d6fa45823dbdb
  //! Tests for asynchronous signing. These tests verify that the channel state machine behaves
  //! properly with a signer implementation that asynchronously derives signatures.
  
- use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider};
+ use bitcoin::{Transaction, TxOut, TxIn, Amount};
+ use bitcoin::blockdata::locktime::absolute::LockTime;
+ use crate::chain::channelmonitor::LATENCY_GRACE_PERIOD_BLOCKS;
+ use crate::events::bump_transaction::WalletSource;
+ use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
  use crate::ln::functional_test_utils::*;
  use crate::ln::msgs::ChannelMessageHandler;
  use crate::ln::channelmanager::{PaymentId, RecipientOnionFields};
@@@ -197,7 -202,7 +202,7 @@@ fn test_async_commitment_signature_for_
  
        // nodes[0] <-- accept_channel --- nodes[1]
        let accept_channel = get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
 -      assert_eq!(accept_channel.minimum_depth, 0, "Expected minimum depth of 0");
 +      assert_eq!(accept_channel.common_fields.minimum_depth, 0, "Expected minimum depth of 0");
        nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel);
  
        // nodes[0] --- funding_created --> nodes[1]
@@@ -321,3 -326,124 +326,124 @@@ fn test_async_commitment_signature_for_
                };
        }
  }
+ fn do_test_async_holder_signatures(anchors: bool, remote_commitment: bool) {
+       // Ensures that we can obtain holder signatures for commitment and HTLC transactions
+       // asynchronously by allowing their retrieval to fail and retrying via
+       // `ChannelMonitor::signer_unblocked`.
+       let mut config = test_default_channel_config();
+       if anchors {
+               config.channel_handshake_config.negotiate_anchors_zero_fee_htlc_tx = true;
+               config.manually_accept_inbound_channels = true;
+       }
+       let chanmon_cfgs = create_chanmon_cfgs(2);
+       let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
+       let node_chanmgrs = create_node_chanmgrs(2, &node_cfgs, &[Some(config), Some(config)]);
+       let nodes = create_network(2, &node_cfgs, &node_chanmgrs);
+       let closing_node = if remote_commitment { &nodes[1] } else { &nodes[0] };
+       let coinbase_tx = Transaction {
+               version: 2,
+               lock_time: LockTime::ZERO,
+               input: vec![TxIn { ..Default::default() }],
+               output: vec![
+                       TxOut {
+                               value: Amount::ONE_BTC.to_sat(),
+                               script_pubkey: closing_node.wallet_source.get_change_script().unwrap(),
+                       },
+               ],
+       };
+       if anchors {
+               *nodes[0].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
+               *nodes[1].fee_estimator.sat_per_kw.lock().unwrap() *= 2;
+               closing_node.wallet_source.add_utxo(bitcoin::OutPoint { txid: coinbase_tx.txid(), vout: 0 }, coinbase_tx.output[0].value);
+       }
+       // Route an HTLC and set the signer as unavailable.
+       let (_, _, chan_id, funding_tx) = create_announced_chan_between_nodes(&nodes, 0, 1);
+       route_payment(&nodes[0], &[&nodes[1]], 1_000_000);
+       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, false);
+       if remote_commitment {
+               // Make the counterparty broadcast its latest commitment.
+               nodes[1].node.force_close_broadcasting_latest_txn(&chan_id, &nodes[0].node.get_our_node_id()).unwrap();
+               check_added_monitors(&nodes[1], 1);
+               check_closed_broadcast(&nodes[1], 1, true);
+               check_closed_event(&nodes[1], 1, ClosureReason::HolderForceClosed, false, &[nodes[0].node.get_our_node_id()], 100_000);
+       } else {
+               // We'll connect blocks until the sender has to go onchain to time out the HTLC.
+               connect_blocks(&nodes[0], TEST_FINAL_CLTV + LATENCY_GRACE_PERIOD_BLOCKS + 1);
+               // No transaction should be broadcast since the signer is not available yet.
+               assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
+               assert!(nodes[0].chain_monitor.chain_monitor.get_and_clear_pending_events().is_empty());
+               // Mark it as available now, we should see the signed commitment transaction.
+               nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, true);
+               get_monitor!(nodes[0], chan_id).signer_unblocked(nodes[0].tx_broadcaster, nodes[0].fee_estimator, &nodes[0].logger);
+       }
+       let commitment_tx = {
+               let mut txn = closing_node.tx_broadcaster.txn_broadcast();
+               if anchors || remote_commitment {
+                       assert_eq!(txn.len(), 1);
+                       check_spends!(txn[0], funding_tx);
+                       txn.remove(0)
+               } else {
+                       assert_eq!(txn.len(), 2);
+                       if txn[0].input[0].previous_output.txid == funding_tx.txid() {
+                               check_spends!(txn[0], funding_tx);
+                               check_spends!(txn[1], txn[0]);
+                               txn.remove(0)
+                       } else {
+                               check_spends!(txn[1], funding_tx);
+                               check_spends!(txn[0], txn[1]);
+                               txn.remove(1)
+                       }
+               }
+       };
+       // Mark it as unavailable again to now test the HTLC transaction. We'll mine the commitment such
+       // that the HTLC transaction is retried.
+       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, false);
+       mine_transaction(&nodes[0], &commitment_tx);
+       check_added_monitors(&nodes[0], 1);
+       check_closed_broadcast(&nodes[0], 1, true);
+       check_closed_event(&nodes[0], 1, ClosureReason::CommitmentTxConfirmed, false, &[nodes[1].node.get_our_node_id()], 100_000);
+       // If the counterparty broadcast its latest commitment, we need to mine enough blocks for the
+       // HTLC timeout.
+       if remote_commitment {
+               connect_blocks(&nodes[0], TEST_FINAL_CLTV);
+       }
+       // No HTLC transaction should be broadcast as the signer is not available yet.
+       if anchors && !remote_commitment {
+               handle_bump_htlc_event(&nodes[0], 1);
+       }
+       assert!(nodes[0].tx_broadcaster.txn_broadcast().is_empty());
+       // Mark it as available now, we should see the signed HTLC transaction.
+       nodes[0].set_channel_signer_available(&nodes[1].node.get_our_node_id(), &chan_id, true);
+       get_monitor!(nodes[0], chan_id).signer_unblocked(nodes[0].tx_broadcaster, nodes[0].fee_estimator, &nodes[0].logger);
+       if anchors && !remote_commitment {
+               handle_bump_htlc_event(&nodes[0], 1);
+       }
+       {
+               let txn = nodes[0].tx_broadcaster.txn_broadcast();
+               assert_eq!(txn.len(), 1);
+               check_spends!(txn[0], commitment_tx, coinbase_tx);
+       }
+ }
+ #[test]
+ fn test_async_holder_signatures() {
+       do_test_async_holder_signatures(false, false);
+       do_test_async_holder_signatures(false, true);
+       do_test_async_holder_signatures(true, false);
+       do_test_async_holder_signatures(true, true);
+ }
index 0bc9f5e57939c29028cf16dc9942050d0d123b28,ac409b2c666c2cda9e317a87b0083c5ea77d9413..a82f4d41be4f161e333ae307fdc0df2ad834c708
@@@ -1492,7 -1492,10 +1492,10 @@@ pub(super) struct ChannelContext<SP: De
  
        /// The unique identifier used to re-derive the private key material for the channel through
        /// [`SignerProvider::derive_channel_signer`].
+       #[cfg(not(test))]
        channel_keys_id: [u8; 32],
+       #[cfg(test)]
+       pub channel_keys_id: [u8; 32],
  
        /// If we can't release a [`ChannelMonitorUpdate`] until some external action completes, we
        /// store it here and only release it to the `ChannelManager` once it asks for it.
@@@ -6955,31 -6958,29 +6958,31 @@@ impl<SP: Deref> OutboundV1Channel<SP> w
                let keys = self.context.get_holder_pubkeys();
  
                msgs::OpenChannel {
 -                      chain_hash,
 -                      temporary_channel_id: self.context.channel_id,
 -                      funding_satoshis: self.context.channel_value_satoshis,
 +                      common_fields: msgs::CommonOpenChannelFields {
 +                              chain_hash,
 +                              temporary_channel_id: self.context.channel_id,
 +                              funding_satoshis: self.context.channel_value_satoshis,
 +                              dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
 +                              max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
 +                              htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
 +                              commitment_feerate_sat_per_1000_weight: self.context.feerate_per_kw as u32,
 +                              to_self_delay: self.context.get_holder_selected_contest_delay(),
 +                              max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
 +                              funding_pubkey: keys.funding_pubkey,
 +                              revocation_basepoint: keys.revocation_basepoint.to_public_key(),
 +                              payment_basepoint: keys.payment_point,
 +                              delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
 +                              htlc_basepoint: keys.htlc_basepoint.to_public_key(),
 +                              first_per_commitment_point,
 +                              channel_flags: if self.context.config.announced_channel {1} else {0},
 +                              shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
 +                                      Some(script) => script.clone().into_inner(),
 +                                      None => Builder::new().into_script(),
 +                              }),
 +                              channel_type: Some(self.context.channel_type.clone()),
 +                      },
                        push_msat: self.context.channel_value_satoshis * 1000 - self.context.value_to_self_msat,
 -                      dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
 -                      max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
                        channel_reserve_satoshis: self.context.holder_selected_channel_reserve_satoshis,
 -                      htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
 -                      feerate_per_kw: self.context.feerate_per_kw as u32,
 -                      to_self_delay: self.context.get_holder_selected_contest_delay(),
 -                      max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
 -                      funding_pubkey: keys.funding_pubkey,
 -                      revocation_basepoint: keys.revocation_basepoint.to_public_key(),
 -                      payment_point: keys.payment_point,
 -                      delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
 -                      htlc_basepoint: keys.htlc_basepoint.to_public_key(),
 -                      first_per_commitment_point,
 -                      channel_flags: if self.context.config.announced_channel {1} else {0},
 -                      shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
 -                              Some(script) => script.clone().into_inner(),
 -                              None => Builder::new().into_script(),
 -                      }),
 -                      channel_type: Some(self.context.channel_type.clone()),
                }
        }
  
                if !matches!(self.context.channel_state, ChannelState::NegotiatingFunding(flags) if flags == NegotiatingFundingFlags::OUR_INIT_SENT) {
                        return Err(ChannelError::Close("Got an accept_channel message at a strange time".to_owned()));
                }
 -              if msg.dust_limit_satoshis > 21000000 * 100000000 {
 -                      return Err(ChannelError::Close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", msg.dust_limit_satoshis)));
 +              if msg.common_fields.dust_limit_satoshis > 21000000 * 100000000 {
 +                      return Err(ChannelError::Close(format!("Peer never wants payout outputs? dust_limit_satoshis was {}", msg.common_fields.dust_limit_satoshis)));
                }
                if msg.channel_reserve_satoshis > self.context.channel_value_satoshis {
                        return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than ({})", msg.channel_reserve_satoshis, self.context.channel_value_satoshis)));
                }
 -              if msg.dust_limit_satoshis > self.context.holder_selected_channel_reserve_satoshis {
 -                      return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.dust_limit_satoshis, self.context.holder_selected_channel_reserve_satoshis)));
 +              if msg.common_fields.dust_limit_satoshis > self.context.holder_selected_channel_reserve_satoshis {
 +                      return Err(ChannelError::Close(format!("Dust limit ({}) is bigger than our channel reserve ({})", msg.common_fields.dust_limit_satoshis, self.context.holder_selected_channel_reserve_satoshis)));
                }
                if msg.channel_reserve_satoshis > self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis {
                        return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must not be greater than channel value minus our reserve ({})",
                                msg.channel_reserve_satoshis, self.context.channel_value_satoshis - self.context.holder_selected_channel_reserve_satoshis)));
                }
                let full_channel_value_msat = (self.context.channel_value_satoshis - msg.channel_reserve_satoshis) * 1000;
 -              if msg.htlc_minimum_msat >= full_channel_value_msat {
 -                      return Err(ChannelError::Close(format!("Minimum htlc value ({}) is full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
 +              if msg.common_fields.htlc_minimum_msat >= full_channel_value_msat {
 +                      return Err(ChannelError::Close(format!("Minimum htlc value ({}) is full channel value ({})", msg.common_fields.htlc_minimum_msat, full_channel_value_msat)));
                }
                let max_delay_acceptable = u16::min(peer_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
 -              if msg.to_self_delay > max_delay_acceptable {
 -                      return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_delay_acceptable, msg.to_self_delay)));
 +              if msg.common_fields.to_self_delay > max_delay_acceptable {
 +                      return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_delay_acceptable, msg.common_fields.to_self_delay)));
                }
 -              if msg.max_accepted_htlcs < 1 {
 +              if msg.common_fields.max_accepted_htlcs < 1 {
                        return Err(ChannelError::Close("0 max_accepted_htlcs makes for a useless channel".to_owned()));
                }
 -              if msg.max_accepted_htlcs > MAX_HTLCS {
 -                      return Err(ChannelError::Close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.max_accepted_htlcs, MAX_HTLCS)));
 +              if msg.common_fields.max_accepted_htlcs > MAX_HTLCS {
 +                      return Err(ChannelError::Close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.common_fields.max_accepted_htlcs, MAX_HTLCS)));
                }
  
                // Now check against optional parameters as set by config...
 -              if msg.htlc_minimum_msat > peer_limits.max_htlc_minimum_msat {
 -                      return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat, peer_limits.max_htlc_minimum_msat)));
 +              if msg.common_fields.htlc_minimum_msat > peer_limits.max_htlc_minimum_msat {
 +                      return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.common_fields.htlc_minimum_msat, peer_limits.max_htlc_minimum_msat)));
                }
 -              if msg.max_htlc_value_in_flight_msat < peer_limits.min_max_htlc_value_in_flight_msat {
 -                      return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, peer_limits.min_max_htlc_value_in_flight_msat)));
 +              if msg.common_fields.max_htlc_value_in_flight_msat < peer_limits.min_max_htlc_value_in_flight_msat {
 +                      return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.common_fields.max_htlc_value_in_flight_msat, peer_limits.min_max_htlc_value_in_flight_msat)));
                }
                if msg.channel_reserve_satoshis > peer_limits.max_channel_reserve_satoshis {
                        return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, peer_limits.max_channel_reserve_satoshis)));
                }
 -              if msg.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs {
 -                      return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs)));
 +              if msg.common_fields.max_accepted_htlcs < peer_limits.min_max_accepted_htlcs {
 +                      return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.common_fields.max_accepted_htlcs, peer_limits.min_max_accepted_htlcs)));
                }
 -              if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
 -                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
 +              if msg.common_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
 +                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.common_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
                }
 -              if msg.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
 -                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
 +              if msg.common_fields.dust_limit_satoshis > MAX_CHAN_DUST_LIMIT_SATOSHIS {
 +                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.common_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
                }
 -              if msg.minimum_depth > peer_limits.max_minimum_depth {
 -                      return Err(ChannelError::Close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, msg.minimum_depth)));
 +              if msg.common_fields.minimum_depth > peer_limits.max_minimum_depth {
 +                      return Err(ChannelError::Close(format!("We consider the minimum depth to be unreasonably large. Expected minimum: ({}). Actual: ({})", peer_limits.max_minimum_depth, msg.common_fields.minimum_depth)));
                }
  
 -              if let Some(ty) = &msg.channel_type {
 +              if let Some(ty) = &msg.common_fields.channel_type {
                        if *ty != self.context.channel_type {
                                return Err(ChannelError::Close("Channel Type in accept_channel didn't match the one sent in open_channel.".to_owned()));
                        }
                }
  
                let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
 -                      match &msg.shutdown_scriptpubkey {
 +                      match &msg.common_fields.shutdown_scriptpubkey {
                                &Some(ref script) => {
                                        // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
                                        if script.len() == 0 {
                        }
                } else { None };
  
 -              self.context.counterparty_dust_limit_satoshis = msg.dust_limit_satoshis;
 -              self.context.counterparty_max_htlc_value_in_flight_msat = cmp::min(msg.max_htlc_value_in_flight_msat, self.context.channel_value_satoshis * 1000);
 +              self.context.counterparty_dust_limit_satoshis = msg.common_fields.dust_limit_satoshis;
 +              self.context.counterparty_max_htlc_value_in_flight_msat = cmp::min(msg.common_fields.max_htlc_value_in_flight_msat, self.context.channel_value_satoshis * 1000);
                self.context.counterparty_selected_channel_reserve_satoshis = Some(msg.channel_reserve_satoshis);
 -              self.context.counterparty_htlc_minimum_msat = msg.htlc_minimum_msat;
 -              self.context.counterparty_max_accepted_htlcs = msg.max_accepted_htlcs;
 +              self.context.counterparty_htlc_minimum_msat = msg.common_fields.htlc_minimum_msat;
 +              self.context.counterparty_max_accepted_htlcs = msg.common_fields.max_accepted_htlcs;
  
                if peer_limits.trust_own_funding_0conf {
 -                      self.context.minimum_depth = Some(msg.minimum_depth);
 +                      self.context.minimum_depth = Some(msg.common_fields.minimum_depth);
                } else {
 -                      self.context.minimum_depth = Some(cmp::max(1, msg.minimum_depth));
 +                      self.context.minimum_depth = Some(cmp::max(1, msg.common_fields.minimum_depth));
                }
  
                let counterparty_pubkeys = ChannelPublicKeys {
 -                      funding_pubkey: msg.funding_pubkey,
 -                      revocation_basepoint: RevocationBasepoint::from(msg.revocation_basepoint),
 -                      payment_point: msg.payment_point,
 -                      delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.delayed_payment_basepoint),
 -                      htlc_basepoint: HtlcBasepoint::from(msg.htlc_basepoint)
 +                      funding_pubkey: msg.common_fields.funding_pubkey,
 +                      revocation_basepoint: RevocationBasepoint::from(msg.common_fields.revocation_basepoint),
 +                      payment_point: msg.common_fields.payment_basepoint,
 +                      delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.common_fields.delayed_payment_basepoint),
 +                      htlc_basepoint: HtlcBasepoint::from(msg.common_fields.htlc_basepoint)
                };
  
                self.context.channel_transaction_parameters.counterparty_parameters = Some(CounterpartyChannelTransactionParameters {
 -                      selected_contest_delay: msg.to_self_delay,
 +                      selected_contest_delay: msg.common_fields.to_self_delay,
                        pubkeys: counterparty_pubkeys,
                });
  
 -              self.context.counterparty_cur_commitment_point = Some(msg.first_per_commitment_point);
 +              self.context.counterparty_cur_commitment_point = Some(msg.common_fields.first_per_commitment_point);
                self.context.counterparty_shutdown_scriptpubkey = counterparty_shutdown_scriptpubkey;
  
                self.context.channel_state = ChannelState::NegotiatingFunding(
@@@ -7235,7 -7236,7 +7238,7 @@@ pub(super) fn channel_type_from_open_ch
        msg: &msgs::OpenChannel, their_features: &InitFeatures,
        our_supported_features: &ChannelTypeFeatures
  ) -> Result<ChannelTypeFeatures, ChannelError> {
 -      if let Some(channel_type) = &msg.channel_type {
 +      if let Some(channel_type) = &msg.common_fields.channel_type {
                if channel_type.supports_any_optional_bits() {
                        return Err(ChannelError::Close("Channel Type field contained optional bits - this is not allowed".to_owned()));
                }
                if !channel_type.is_subset(our_supported_features) {
                        return Err(ChannelError::Close("Channel Type contains unsupported features".to_owned()));
                }
 -              let announced_channel = if (msg.channel_flags & 1) == 1 { true } else { false };
 +              let announced_channel = if (msg.common_fields.channel_flags & 1) == 1 { true } else { false };
                if channel_type.requires_scid_privacy() && announced_channel {
                        return Err(ChannelError::Close("SCID Alias/Privacy Channel Type cannot be set on a public channel".to_owned()));
                }
@@@ -7277,22 -7278,22 +7280,22 @@@ impl<SP: Deref> InboundV1Channel<SP> wh
                          F::Target: FeeEstimator,
                          L::Target: Logger,
        {
 -              let logger = WithContext::from(logger, Some(counterparty_node_id), Some(msg.temporary_channel_id));
 -              let announced_channel = if (msg.channel_flags & 1) == 1 { true } else { false };
 +              let logger = WithContext::from(logger, Some(counterparty_node_id), Some(msg.common_fields.temporary_channel_id));
 +              let announced_channel = if (msg.common_fields.channel_flags & 1) == 1 { true } else { false };
  
                // First check the channel type is known, failing before we do anything else if we don't
                // support this channel type.
                let channel_type = channel_type_from_open_channel(msg, their_features, our_supported_features)?;
  
 -              let channel_keys_id = signer_provider.generate_channel_keys_id(true, msg.funding_satoshis, user_id);
 -              let holder_signer = signer_provider.derive_channel_signer(msg.funding_satoshis, channel_keys_id);
 +              let channel_keys_id = signer_provider.generate_channel_keys_id(true, msg.common_fields.funding_satoshis, user_id);
 +              let holder_signer = signer_provider.derive_channel_signer(msg.common_fields.funding_satoshis, channel_keys_id);
                let pubkeys = holder_signer.pubkeys().clone();
                let counterparty_pubkeys = ChannelPublicKeys {
 -                      funding_pubkey: msg.funding_pubkey,
 -                      revocation_basepoint: RevocationBasepoint::from(msg.revocation_basepoint),
 -                      payment_point: msg.payment_point,
 -                      delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.delayed_payment_basepoint),
 -                      htlc_basepoint: HtlcBasepoint::from(msg.htlc_basepoint)
 +                      funding_pubkey: msg.common_fields.funding_pubkey,
 +                      revocation_basepoint: RevocationBasepoint::from(msg.common_fields.revocation_basepoint),
 +                      payment_point: msg.common_fields.payment_basepoint,
 +                      delayed_payment_basepoint: DelayedPaymentBasepoint::from(msg.common_fields.delayed_payment_basepoint),
 +                      htlc_basepoint: HtlcBasepoint::from(msg.common_fields.htlc_basepoint)
                };
  
                if config.channel_handshake_config.our_to_self_delay < BREAKDOWN_TIMEOUT {
                }
  
                // Check sanity of message fields:
 -              if msg.funding_satoshis > config.channel_handshake_limits.max_funding_satoshis {
 -                      return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.channel_handshake_limits.max_funding_satoshis, msg.funding_satoshis)));
 +              if msg.common_fields.funding_satoshis > config.channel_handshake_limits.max_funding_satoshis {
 +                      return Err(ChannelError::Close(format!("Per our config, funding must be at most {}. It was {}", config.channel_handshake_limits.max_funding_satoshis, msg.common_fields.funding_satoshis)));
                }
 -              if msg.funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS {
 -                      return Err(ChannelError::Close(format!("Funding must be smaller than the total bitcoin supply. It was {}", msg.funding_satoshis)));
 +              if msg.common_fields.funding_satoshis >= TOTAL_BITCOIN_SUPPLY_SATOSHIS {
 +                      return Err(ChannelError::Close(format!("Funding must be smaller than the total bitcoin supply. It was {}", msg.common_fields.funding_satoshis)));
                }
 -              if msg.channel_reserve_satoshis > msg.funding_satoshis {
 -                      return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must be not greater than funding_satoshis: {}", msg.channel_reserve_satoshis, msg.funding_satoshis)));
 +              if msg.channel_reserve_satoshis > msg.common_fields.funding_satoshis {
 +                      return Err(ChannelError::Close(format!("Bogus channel_reserve_satoshis ({}). Must be not greater than funding_satoshis: {}", msg.channel_reserve_satoshis, msg.common_fields.funding_satoshis)));
                }
 -              let full_channel_value_msat = (msg.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
 +              let full_channel_value_msat = (msg.common_fields.funding_satoshis - msg.channel_reserve_satoshis) * 1000;
                if msg.push_msat > full_channel_value_msat {
                        return Err(ChannelError::Close(format!("push_msat {} was larger than channel amount minus reserve ({})", msg.push_msat, full_channel_value_msat)));
                }
 -              if msg.dust_limit_satoshis > msg.funding_satoshis {
 -                      return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.dust_limit_satoshis, msg.funding_satoshis)));
 +              if msg.common_fields.dust_limit_satoshis > msg.common_fields.funding_satoshis {
 +                      return Err(ChannelError::Close(format!("dust_limit_satoshis {} was larger than funding_satoshis {}. Peer never wants payout outputs?", msg.common_fields.dust_limit_satoshis, msg.common_fields.funding_satoshis)));
                }
 -              if msg.htlc_minimum_msat >= full_channel_value_msat {
 -                      return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.htlc_minimum_msat, full_channel_value_msat)));
 +              if msg.common_fields.htlc_minimum_msat >= full_channel_value_msat {
 +                      return Err(ChannelError::Close(format!("Minimum htlc value ({}) was larger than full channel value ({})", msg.common_fields.htlc_minimum_msat, full_channel_value_msat)));
                }
 -              Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, msg.feerate_per_kw, None, &&logger)?;
 +              Channel::<SP>::check_remote_fee(&channel_type, fee_estimator, msg.common_fields.commitment_feerate_sat_per_1000_weight, None, &&logger)?;
  
                let max_counterparty_selected_contest_delay = u16::min(config.channel_handshake_limits.their_to_self_delay, MAX_LOCAL_BREAKDOWN_TIMEOUT);
 -              if msg.to_self_delay > max_counterparty_selected_contest_delay {
 -                      return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_counterparty_selected_contest_delay, msg.to_self_delay)));
 +              if msg.common_fields.to_self_delay > max_counterparty_selected_contest_delay {
 +                      return Err(ChannelError::Close(format!("They wanted our payments to be delayed by a needlessly long period. Upper limit: {}. Actual: {}", max_counterparty_selected_contest_delay, msg.common_fields.to_self_delay)));
                }
 -              if msg.max_accepted_htlcs < 1 {
 +              if msg.common_fields.max_accepted_htlcs < 1 {
                        return Err(ChannelError::Close("0 max_accepted_htlcs makes for a useless channel".to_owned()));
                }
 -              if msg.max_accepted_htlcs > MAX_HTLCS {
 -                      return Err(ChannelError::Close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.max_accepted_htlcs, MAX_HTLCS)));
 +              if msg.common_fields.max_accepted_htlcs > MAX_HTLCS {
 +                      return Err(ChannelError::Close(format!("max_accepted_htlcs was {}. It must not be larger than {}", msg.common_fields.max_accepted_htlcs, MAX_HTLCS)));
                }
  
                // Now check against optional parameters as set by config...
 -              if msg.funding_satoshis < config.channel_handshake_limits.min_funding_satoshis {
 -                      return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.funding_satoshis, config.channel_handshake_limits.min_funding_satoshis)));
 +              if msg.common_fields.funding_satoshis < config.channel_handshake_limits.min_funding_satoshis {
 +                      return Err(ChannelError::Close(format!("Funding satoshis ({}) is less than the user specified limit ({})", msg.common_fields.funding_satoshis, config.channel_handshake_limits.min_funding_satoshis)));
                }
 -              if msg.htlc_minimum_msat > config.channel_handshake_limits.max_htlc_minimum_msat {
 -                      return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.htlc_minimum_msat,  config.channel_handshake_limits.max_htlc_minimum_msat)));
 +              if msg.common_fields.htlc_minimum_msat > config.channel_handshake_limits.max_htlc_minimum_msat {
 +                      return Err(ChannelError::Close(format!("htlc_minimum_msat ({}) is higher than the user specified limit ({})", msg.common_fields.htlc_minimum_msat,  config.channel_handshake_limits.max_htlc_minimum_msat)));
                }
 -              if msg.max_htlc_value_in_flight_msat < config.channel_handshake_limits.min_max_htlc_value_in_flight_msat {
 -                      return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.max_htlc_value_in_flight_msat, config.channel_handshake_limits.min_max_htlc_value_in_flight_msat)));
 +              if msg.common_fields.max_htlc_value_in_flight_msat < config.channel_handshake_limits.min_max_htlc_value_in_flight_msat {
 +                      return Err(ChannelError::Close(format!("max_htlc_value_in_flight_msat ({}) is less than the user specified limit ({})", msg.common_fields.max_htlc_value_in_flight_msat, config.channel_handshake_limits.min_max_htlc_value_in_flight_msat)));
                }
                if msg.channel_reserve_satoshis > config.channel_handshake_limits.max_channel_reserve_satoshis {
                        return Err(ChannelError::Close(format!("channel_reserve_satoshis ({}) is higher than the user specified limit ({})", msg.channel_reserve_satoshis, config.channel_handshake_limits.max_channel_reserve_satoshis)));
                }
 -              if msg.max_accepted_htlcs < config.channel_handshake_limits.min_max_accepted_htlcs {
 -                      return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.max_accepted_htlcs, config.channel_handshake_limits.min_max_accepted_htlcs)));
 +              if msg.common_fields.max_accepted_htlcs < config.channel_handshake_limits.min_max_accepted_htlcs {
 +                      return Err(ChannelError::Close(format!("max_accepted_htlcs ({}) is less than the user specified limit ({})", msg.common_fields.max_accepted_htlcs, config.channel_handshake_limits.min_max_accepted_htlcs)));
                }
 -              if msg.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
 -                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
 +              if msg.common_fields.dust_limit_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
 +                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is less than the implementation limit ({})", msg.common_fields.dust_limit_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS)));
                }
 -              if msg.dust_limit_satoshis >  MAX_CHAN_DUST_LIMIT_SATOSHIS {
 -                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
 +              if msg.common_fields.dust_limit_satoshis >  MAX_CHAN_DUST_LIMIT_SATOSHIS {
 +                      return Err(ChannelError::Close(format!("dust_limit_satoshis ({}) is greater than the implementation limit ({})", msg.common_fields.dust_limit_satoshis, MAX_CHAN_DUST_LIMIT_SATOSHIS)));
                }
  
                // Convert things into internal flags and prep our state:
                        }
                }
  
 -              let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(msg.funding_satoshis, config);
 +              let holder_selected_channel_reserve_satoshis = get_holder_selected_channel_reserve_satoshis(msg.common_fields.funding_satoshis, config);
                if holder_selected_channel_reserve_satoshis < MIN_CHAN_DUST_LIMIT_SATOSHIS {
                        // Protocol level safety check in place, although it should never happen because
                        // of `MIN_THEIR_CHAN_RESERVE_SATOSHIS`
                        log_debug!(logger, "channel_reserve_satoshis ({}) is smaller than our dust limit ({}). We can broadcast stale states without any risk, implying this channel is very insecure for our counterparty.",
                                msg.channel_reserve_satoshis, MIN_CHAN_DUST_LIMIT_SATOSHIS);
                }
 -              if holder_selected_channel_reserve_satoshis < msg.dust_limit_satoshis {
 -                      return Err(ChannelError::Close(format!("Dust limit ({}) too high for the channel reserve we require the remote to keep ({})", msg.dust_limit_satoshis, holder_selected_channel_reserve_satoshis)));
 +              if holder_selected_channel_reserve_satoshis < msg.common_fields.dust_limit_satoshis {
 +                      return Err(ChannelError::Close(format!("Dust limit ({}) too high for the channel reserve we require the remote to keep ({})", msg.common_fields.dust_limit_satoshis, holder_selected_channel_reserve_satoshis)));
                }
  
                // check if the funder's amount for the initial commitment tx is sufficient
                } else {
                        0
                };
 -              let funders_amount_msat = msg.funding_satoshis * 1000 - msg.push_msat;
 -              let commitment_tx_fee = commit_tx_fee_msat(msg.feerate_per_kw, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) / 1000;
 +              let funders_amount_msat = msg.common_fields.funding_satoshis * 1000 - msg.push_msat;
 +              let commitment_tx_fee = commit_tx_fee_msat(msg.common_fields.commitment_feerate_sat_per_1000_weight, MIN_AFFORDABLE_HTLC_COUNT, &channel_type) / 1000;
                if (funders_amount_msat / 1000).saturating_sub(anchor_outputs_value) < commitment_tx_fee {
                        return Err(ChannelError::Close(format!("Funding amount ({} sats) can't even pay fee for initial commitment transaction fee of {} sats.", (funders_amount_msat / 1000).saturating_sub(anchor_outputs_value), commitment_tx_fee)));
                }
                }
  
                let counterparty_shutdown_scriptpubkey = if their_features.supports_upfront_shutdown_script() {
 -                      match &msg.shutdown_scriptpubkey {
 +                      match &msg.common_fields.shutdown_scriptpubkey {
                                &Some(ref script) => {
                                        // Peer is signaling upfront_shutdown and has opt-out with a 0-length script. We don't enforce anything
                                        if script.len() == 0 {
  
                                inbound_handshake_limits_override: None,
  
 -                              temporary_channel_id: Some(msg.temporary_channel_id),
 -                              channel_id: msg.temporary_channel_id,
 +                              temporary_channel_id: Some(msg.common_fields.temporary_channel_id),
 +                              channel_id: msg.common_fields.temporary_channel_id,
                                channel_state: ChannelState::NegotiatingFunding(
                                        NegotiatingFundingFlags::OUR_INIT_SENT | NegotiatingFundingFlags::THEIR_INIT_SENT
                                ),
                                signer_pending_funding: false,
  
                                #[cfg(debug_assertions)]
 -                              holder_max_commitment_tx_output: Mutex::new((msg.push_msat, msg.funding_satoshis * 1000 - msg.push_msat)),
 +                              holder_max_commitment_tx_output: Mutex::new((msg.push_msat, msg.common_fields.funding_satoshis * 1000 - msg.push_msat)),
                                #[cfg(debug_assertions)]
 -                              counterparty_max_commitment_tx_output: Mutex::new((msg.push_msat, msg.funding_satoshis * 1000 - msg.push_msat)),
 +                              counterparty_max_commitment_tx_output: Mutex::new((msg.push_msat, msg.common_fields.funding_satoshis * 1000 - msg.push_msat)),
  
                                last_sent_closing_fee: None,
                                pending_counterparty_closing_signed: None,
                                short_channel_id: None,
                                channel_creation_height: current_chain_height,
  
 -                              feerate_per_kw: msg.feerate_per_kw,
 -                              channel_value_satoshis: msg.funding_satoshis,
 -                              counterparty_dust_limit_satoshis: msg.dust_limit_satoshis,
 +                              feerate_per_kw: msg.common_fields.commitment_feerate_sat_per_1000_weight,
 +                              channel_value_satoshis: msg.common_fields.funding_satoshis,
 +                              counterparty_dust_limit_satoshis: msg.common_fields.dust_limit_satoshis,
                                holder_dust_limit_satoshis: MIN_CHAN_DUST_LIMIT_SATOSHIS,
 -                              counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.max_htlc_value_in_flight_msat, msg.funding_satoshis * 1000),
 -                              holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(msg.funding_satoshis, &config.channel_handshake_config),
 +                              counterparty_max_htlc_value_in_flight_msat: cmp::min(msg.common_fields.max_htlc_value_in_flight_msat, msg.common_fields.funding_satoshis * 1000),
 +                              holder_max_htlc_value_in_flight_msat: get_holder_max_htlc_value_in_flight_msat(msg.common_fields.funding_satoshis, &config.channel_handshake_config),
                                counterparty_selected_channel_reserve_satoshis: Some(msg.channel_reserve_satoshis),
                                holder_selected_channel_reserve_satoshis,
 -                              counterparty_htlc_minimum_msat: msg.htlc_minimum_msat,
 +                              counterparty_htlc_minimum_msat: msg.common_fields.htlc_minimum_msat,
                                holder_htlc_minimum_msat: if config.channel_handshake_config.our_htlc_minimum_msat == 0 { 1 } else { config.channel_handshake_config.our_htlc_minimum_msat },
 -                              counterparty_max_accepted_htlcs: msg.max_accepted_htlcs,
 +                              counterparty_max_accepted_htlcs: msg.common_fields.max_accepted_htlcs,
                                holder_max_accepted_htlcs: cmp::min(config.channel_handshake_config.our_max_accepted_htlcs, MAX_HTLCS),
                                minimum_depth,
  
                                        holder_selected_contest_delay: config.channel_handshake_config.our_to_self_delay,
                                        is_outbound_from_holder: false,
                                        counterparty_parameters: Some(CounterpartyChannelTransactionParameters {
 -                                              selected_contest_delay: msg.to_self_delay,
 +                                              selected_contest_delay: msg.common_fields.to_self_delay,
                                                pubkeys: counterparty_pubkeys,
                                        }),
                                        funding_outpoint: None,
                                funding_transaction: None,
                                is_batch_funding: None,
  
 -                              counterparty_cur_commitment_point: Some(msg.first_per_commitment_point),
 +                              counterparty_cur_commitment_point: Some(msg.common_fields.first_per_commitment_point),
                                counterparty_prev_commitment_point: None,
                                counterparty_node_id,
  
                let keys = self.context.get_holder_pubkeys();
  
                msgs::AcceptChannel {
 -                      temporary_channel_id: self.context.channel_id,
 -                      dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
 -                      max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
 +                      common_fields: msgs::CommonAcceptChannelFields {
 +                              temporary_channel_id: self.context.channel_id,
 +                              dust_limit_satoshis: self.context.holder_dust_limit_satoshis,
 +                              max_htlc_value_in_flight_msat: self.context.holder_max_htlc_value_in_flight_msat,
 +                              htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
 +                              minimum_depth: self.context.minimum_depth.unwrap(),
 +                              to_self_delay: self.context.get_holder_selected_contest_delay(),
 +                              max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
 +                              funding_pubkey: keys.funding_pubkey,
 +                              revocation_basepoint: keys.revocation_basepoint.to_public_key(),
 +                              payment_basepoint: keys.payment_point,
 +                              delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
 +                              htlc_basepoint: keys.htlc_basepoint.to_public_key(),
 +                              first_per_commitment_point,
 +                              shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
 +                                      Some(script) => script.clone().into_inner(),
 +                                      None => Builder::new().into_script(),
 +                              }),
 +                              channel_type: Some(self.context.channel_type.clone()),
 +                      },
                        channel_reserve_satoshis: self.context.holder_selected_channel_reserve_satoshis,
 -                      htlc_minimum_msat: self.context.holder_htlc_minimum_msat,
 -                      minimum_depth: self.context.minimum_depth.unwrap(),
 -                      to_self_delay: self.context.get_holder_selected_contest_delay(),
 -                      max_accepted_htlcs: self.context.holder_max_accepted_htlcs,
 -                      funding_pubkey: keys.funding_pubkey,
 -                      revocation_basepoint: keys.revocation_basepoint.to_public_key(),
 -                      payment_point: keys.payment_point,
 -                      delayed_payment_basepoint: keys.delayed_payment_basepoint.to_public_key(),
 -                      htlc_basepoint: keys.htlc_basepoint.to_public_key(),
 -                      first_per_commitment_point,
 -                      shutdown_scriptpubkey: Some(match &self.context.shutdown_scriptpubkey {
 -                              Some(script) => script.clone().into_inner(),
 -                              None => Builder::new().into_script(),
 -                      }),
 -                      channel_type: Some(self.context.channel_type.clone()),
                        #[cfg(taproot)]
                        next_local_nonce: None,
                }
@@@ -8877,7 -8876,7 +8880,7 @@@ mod tests 
                // same as the old fee.
                fee_est.fee_est = 500;
                let open_channel_msg = node_a_chan.get_open_channel(ChainHash::using_genesis_block(network));
 -              assert_eq!(open_channel_msg.feerate_per_kw, original_fee);
 +              assert_eq!(open_channel_msg.common_fields.commitment_feerate_sat_per_1000_weight, original_fee);
        }
  
        #[test]
  
                // Node B --> Node A: accept channel, explicitly setting B's dust limit.
                let mut accept_channel_msg = node_b_chan.accept_inbound_channel();
 -              accept_channel_msg.dust_limit_satoshis = 546;
 +              accept_channel_msg.common_fields.dust_limit_satoshis = 546;
                node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &channelmanager::provided_init_features(&config)).unwrap();
                node_a_chan.context.holder_dust_limit_satoshis = 1560;
  
  
                // Node B --> Node A: accept channel, explicitly setting B's dust limit.
                let mut accept_channel_msg = node_b_chan.accept_inbound_channel();
 -              accept_channel_msg.dust_limit_satoshis = 546;
 +              accept_channel_msg.common_fields.dust_limit_satoshis = 546;
                node_a_chan.accept_channel(&accept_channel_msg, &config.channel_handshake_limits, &channelmanager::provided_init_features(&config)).unwrap();
                node_a_chan.context.holder_dust_limit_satoshis = 1560;
  
                channel_type_features.set_zero_conf_required();
  
                let mut open_channel_msg = node_a_chan.get_open_channel(ChainHash::using_genesis_block(network));
 -              open_channel_msg.channel_type = Some(channel_type_features);
 +              open_channel_msg.common_fields.channel_type = Some(channel_type_features);
                let node_b_node_id = PublicKey::from_secret_key(&secp_ctx, &SecretKey::from_slice(&[7; 32]).unwrap());
                let res = InboundV1Channel::<&TestKeysInterface>::new(&feeest, &&keys_provider, &&keys_provider,
                        node_b_node_id, &channelmanager::provided_channel_type_features(&config),
  
                // Set `channel_type` to `None` to force the implicit feature negotiation.
                let mut open_channel_msg = channel_a.get_open_channel(ChainHash::using_genesis_block(network));
 -              open_channel_msg.channel_type = None;
 +              open_channel_msg.common_fields.channel_type = None;
  
                // Since A supports both `static_remote_key` and `option_anchors`, but B only accepts
                // `static_remote_key`, it will fail the channel.
                ).unwrap();
  
                let mut open_channel_msg = channel_a.get_open_channel(ChainHash::using_genesis_block(network));
 -              open_channel_msg.channel_type = Some(simple_anchors_channel_type.clone());
 +              open_channel_msg.common_fields.channel_type = Some(simple_anchors_channel_type.clone());
  
                let res = InboundV1Channel::<&TestKeysInterface>::new(
                        &fee_estimator, &&keys_provider, &&keys_provider, node_id_a,
                ).unwrap();
  
                let mut accept_channel_msg = channel_b.get_accept_channel_message();
 -              accept_channel_msg.channel_type = Some(simple_anchors_channel_type.clone());
 +              accept_channel_msg.common_fields.channel_type = Some(simple_anchors_channel_type.clone());
  
                let res = channel_a.accept_channel(
                        &accept_channel_msg, &config.channel_handshake_limits, &simple_anchors_init
index 87ac05ccb2b905e262f5b32cff5354515a75ba08,ea5c1bb88187131a0262e044ed3c89383a179cf7..243cf74182205a61f62fae90b66e58f4da0c62bd
@@@ -3021,8 -3021,8 +3021,8 @@@ wher
        /// the latest local transaction(s). Fails if `channel_id` is unknown to the manager, or if the
        /// `counterparty_node_id` isn't the counterparty of the corresponding channel.
        ///
-       /// You can always get the latest local transaction(s) to broadcast from
-       /// [`ChannelMonitor::get_latest_holder_commitment_txn`].
+       /// You can always broadcast the latest local transaction(s) via
+       /// [`ChannelMonitor::broadcast_latest_holder_commitment_txn`].
        pub fn force_close_without_broadcasting_txn(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey)
        -> Result<(), APIError> {
                self.force_close_sending_error(channel_id, counterparty_node_id, false)
        fn internal_open_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannel) -> Result<(), MsgHandleErrInternal> {
                // Note that the ChannelManager is NOT re-persisted on disk after this, so any changes are
                // likely to be lost on restart!
 -              if msg.chain_hash != self.chain_hash {
 -                      return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(), msg.temporary_channel_id.clone()));
 +              if msg.common_fields.chain_hash != self.chain_hash {
 +                      return Err(MsgHandleErrInternal::send_err_msg_no_close("Unknown genesis block hash".to_owned(),
 +                               msg.common_fields.temporary_channel_id.clone()));
                }
  
                if !self.default_configuration.accept_inbound_channels {
 -                      return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(), msg.temporary_channel_id.clone()));
 +                      return Err(MsgHandleErrInternal::send_err_msg_no_close("No inbound channels accepted".to_owned(),
 +                               msg.common_fields.temporary_channel_id.clone()));
                }
  
                // Get the number of peers with channels, but without funded ones. We don't care too much
                let peer_state_mutex = per_peer_state.get(counterparty_node_id)
                    .ok_or_else(|| {
                                debug_assert!(false);
 -                              MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), msg.temporary_channel_id.clone())
 +                              MsgHandleErrInternal::send_err_msg_no_close(
 +                                      format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id),
 +                                      msg.common_fields.temporary_channel_id.clone())
                        })?;
                let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                let peer_state = &mut *peer_state_lock;
                {
                        return Err(MsgHandleErrInternal::send_err_msg_no_close(
                                "Have too many peers with unfunded channels, not accepting new ones".to_owned(),
 -                              msg.temporary_channel_id.clone()));
 +                              msg.common_fields.temporary_channel_id.clone()));
                }
  
                let best_block_height = self.best_block.read().unwrap().height();
                if Self::unfunded_channel_count(peer_state, best_block_height) >= MAX_UNFUNDED_CHANS_PER_PEER {
                        return Err(MsgHandleErrInternal::send_err_msg_no_close(
                                format!("Refusing more than {} unfunded channels.", MAX_UNFUNDED_CHANS_PER_PEER),
 -                              msg.temporary_channel_id.clone()));
 +                              msg.common_fields.temporary_channel_id.clone()));
                }
  
 -              let channel_id = msg.temporary_channel_id;
 +              let channel_id = msg.common_fields.temporary_channel_id;
                let channel_exists = peer_state.has_channel(&channel_id);
                if channel_exists {
 -                      return Err(MsgHandleErrInternal::send_err_msg_no_close("temporary_channel_id collision for the same peer!".to_owned(), msg.temporary_channel_id.clone()));
 +                      return Err(MsgHandleErrInternal::send_err_msg_no_close(
 +                              "temporary_channel_id collision for the same peer!".to_owned(),
 +                              msg.common_fields.temporary_channel_id.clone()));
                }
  
                // If we're doing manual acceptance checks on the channel, then defer creation until we're sure we want to accept.
                        let channel_type = channel::channel_type_from_open_channel(
                                        &msg, &peer_state.latest_features, &self.channel_type_features()
                                ).map_err(|e|
 -                                      MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id)
 +                                      MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id)
                                )?;
                        let mut pending_events = self.pending_events.lock().unwrap();
                        pending_events.push_back((events::Event::OpenChannelRequest {
 -                              temporary_channel_id: msg.temporary_channel_id.clone(),
 +                              temporary_channel_id: msg.common_fields.temporary_channel_id.clone(),
                                counterparty_node_id: counterparty_node_id.clone(),
 -                              funding_satoshis: msg.funding_satoshis,
 +                              funding_satoshis: msg.common_fields.funding_satoshis,
                                push_msat: msg.push_msat,
                                channel_type,
                        }, None));
                        &self.default_configuration, best_block_height, &self.logger, /*is_0conf=*/false)
                {
                        Err(e) => {
 -                              return Err(MsgHandleErrInternal::from_chan_no_close(e, msg.temporary_channel_id));
 +                              return Err(MsgHandleErrInternal::from_chan_no_close(e, msg.common_fields.temporary_channel_id));
                        },
                        Ok(res) => res
                };
  
                let channel_type = channel.context.get_channel_type();
                if channel_type.requires_zero_conf() {
 -                      return Err(MsgHandleErrInternal::send_err_msg_no_close("No zero confirmation channels accepted".to_owned(), msg.temporary_channel_id.clone()));
 +                      return Err(MsgHandleErrInternal::send_err_msg_no_close(
 +                              "No zero confirmation channels accepted".to_owned(),
 +                              msg.common_fields.temporary_channel_id.clone()));
                }
                if channel_type.requires_anchors_zero_fee_htlc_tx() {
 -                      return Err(MsgHandleErrInternal::send_err_msg_no_close("No channels with anchor outputs accepted".to_owned(), msg.temporary_channel_id.clone()));
 +                      return Err(MsgHandleErrInternal::send_err_msg_no_close(
 +                              "No channels with anchor outputs accepted".to_owned(),
 +                              msg.common_fields.temporary_channel_id.clone()));
                }
  
                let outbound_scid_alias = self.create_and_insert_outbound_scid_alias();
                        let peer_state_mutex = per_peer_state.get(counterparty_node_id)
                                .ok_or_else(|| {
                                        debug_assert!(false);
 -                                      MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), msg.temporary_channel_id)
 +                                      MsgHandleErrInternal::send_err_msg_no_close(format!("Can't find a peer matching the passed counterparty node_id {}", counterparty_node_id), msg.common_fields.temporary_channel_id)
                                })?;
                        let mut peer_state_lock = peer_state_mutex.lock().unwrap();
                        let peer_state = &mut *peer_state_lock;
 -                      match peer_state.channel_by_id.entry(msg.temporary_channel_id) {
 +                      match peer_state.channel_by_id.entry(msg.common_fields.temporary_channel_id) {
                                hash_map::Entry::Occupied(mut phase) => {
                                        match phase.get_mut() {
                                                ChannelPhase::UnfundedOutboundV1(chan) => {
                                                        (chan.context.get_value_satoshis(), chan.context.get_funding_redeemscript().to_v0_p2wsh(), chan.context.get_user_id())
                                                },
                                                _ => {
 -                                                      return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got an unexpected accept_channel message from peer with counterparty_node_id {}", counterparty_node_id), msg.temporary_channel_id));
 +                                                      return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got an unexpected accept_channel message from peer with counterparty_node_id {}", counterparty_node_id), msg.common_fields.temporary_channel_id));
                                                }
                                        }
                                },
 -                              hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.temporary_channel_id))
 +                              hash_map::Entry::Vacant(_) => return Err(MsgHandleErrInternal::send_err_msg_no_close(format!("Got a message for a channel from the wrong node! No such channel for the passed counterparty_node_id {}", counterparty_node_id), msg.common_fields.temporary_channel_id))
                        }
                };
                let mut pending_events = self.pending_events.lock().unwrap();
                pending_events.push_back((events::Event::FundingGenerationReady {
 -                      temporary_channel_id: msg.temporary_channel_id,
 +                      temporary_channel_id: msg.common_fields.temporary_channel_id,
                        counterparty_node_id: *counterparty_node_id,
                        channel_value_satoshis: value,
                        output_script,
@@@ -8723,7 -8713,7 +8723,7 @@@ wher
        fn handle_open_channel_v2(&self, counterparty_node_id: &PublicKey, msg: &msgs::OpenChannelV2) {
                let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
                        "Dual-funded channels not supported".to_owned(),
 -                       msg.temporary_channel_id.clone())), *counterparty_node_id);
 +                       msg.common_fields.temporary_channel_id.clone())), *counterparty_node_id);
        }
  
        fn handle_accept_channel(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannel) {
        fn handle_accept_channel_v2(&self, counterparty_node_id: &PublicKey, msg: &msgs::AcceptChannelV2) {
                let _: Result<(), _> = handle_error!(self, Err(MsgHandleErrInternal::send_err_msg_no_close(
                        "Dual-funded channels not supported".to_owned(),
 -                       msg.temporary_channel_id.clone())), *counterparty_node_id);
 +                       msg.common_fields.temporary_channel_id.clone())), *counterparty_node_id);
        }
  
        fn handle_funding_created(&self, counterparty_node_id: &PublicKey, msg: &msgs::FundingCreated) {
@@@ -12043,15 -12033,14 +12043,15 @@@ mod tests 
                                check_added_monitors!(nodes[0], 1);
                                expect_channel_pending_event(&nodes[0], &nodes[1].node.get_our_node_id());
                        }
 -                      open_channel_msg.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
 +                      open_channel_msg.common_fields.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
                }
  
                // A MAX_UNFUNDED_CHANS_PER_PEER + 1 channel will be summarily rejected
 -              open_channel_msg.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
 +              open_channel_msg.common_fields.temporary_channel_id = ChannelId::temporary_from_entropy_source(
 +                      &nodes[0].keys_manager);
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
                assert_eq!(get_err_msg(&nodes[1], &nodes[0].node.get_our_node_id()).channel_id,
 -                      open_channel_msg.temporary_channel_id);
 +                      open_channel_msg.common_fields.temporary_channel_id);
  
                // Further, because all of our channels with nodes[0] are inbound, and none of them funded,
                // it doesn't count as a "protected" peer, i.e. it counts towards the MAX_NO_CHANNEL_PEERS
                for i in 0..super::MAX_UNFUNDED_CHANNEL_PEERS - 1 {
                        nodes[1].node.handle_open_channel(&peer_pks[i], &open_channel_msg);
                        get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, peer_pks[i]);
 -                      open_channel_msg.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
 +                      open_channel_msg.common_fields.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
                }
                nodes[1].node.handle_open_channel(&last_random_pk, &open_channel_msg);
                assert_eq!(get_err_msg(&nodes[1], &last_random_pk).channel_id,
 -                      open_channel_msg.temporary_channel_id);
 +                      open_channel_msg.common_fields.temporary_channel_id);
  
                // Of course, however, outbound channels are always allowed
                nodes[1].node.create_channel(last_random_pk, 100_000, 0, 42, None, None).unwrap();
                for _ in 0..super::MAX_UNFUNDED_CHANS_PER_PEER {
                        nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
                        get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, nodes[0].node.get_our_node_id());
 -                      open_channel_msg.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
 +                      open_channel_msg.common_fields.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
                }
  
                // Once we have MAX_UNFUNDED_CHANS_PER_PEER unfunded channels, new inbound channels will be
                // rejected.
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
                assert_eq!(get_err_msg(&nodes[1], &nodes[0].node.get_our_node_id()).channel_id,
 -                      open_channel_msg.temporary_channel_id);
 +                      open_channel_msg.common_fields.temporary_channel_id);
  
                // but we can still open an outbound channel.
                nodes[1].node.create_channel(nodes[0].node.get_our_node_id(), 100_000, 0, 42, None, None).unwrap();
                // but even with such an outbound channel, additional inbound channels will still fail.
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
                assert_eq!(get_err_msg(&nodes[1], &nodes[0].node.get_our_node_id()).channel_id,
 -                      open_channel_msg.temporary_channel_id);
 +                      open_channel_msg.common_fields.temporary_channel_id);
        }
  
        #[test]
                                _ => panic!("Unexpected event"),
                        }
                        get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, random_pk);
 -                      open_channel_msg.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
 +                      open_channel_msg.common_fields.temporary_channel_id = ChannelId::temporary_from_entropy_source(&nodes[0].keys_manager);
                }
  
                // If we try to accept a channel from another peer non-0conf it will fail.
                        _ => panic!("Unexpected event"),
                }
                assert_eq!(get_err_msg(&nodes[1], &last_random_pk).channel_id,
 -                      open_channel_msg.temporary_channel_id);
 +                      open_channel_msg.common_fields.temporary_channel_id);
  
                // ...however if we accept the same channel 0conf it should work just fine.
                nodes[1].node.handle_open_channel(&last_random_pk, &open_channel_msg);
  
                nodes[0].node.create_channel(nodes[1].node.get_our_node_id(), 100_000, 0, 0, None, None).unwrap();
                let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 -              assert!(open_channel_msg.channel_type.as_ref().unwrap().supports_anchors_zero_fee_htlc_tx());
 +              assert!(open_channel_msg.common_fields.channel_type.as_ref().unwrap().supports_anchors_zero_fee_htlc_tx());
  
                nodes[1].node.handle_open_channel(&nodes[0].node.get_our_node_id(), &open_channel_msg);
                let events = nodes[1].node.get_and_clear_pending_events();
                nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &error_msg);
  
                let open_channel_msg = get_event_msg!(nodes[0], MessageSendEvent::SendOpenChannel, nodes[1].node.get_our_node_id());
 -              assert!(!open_channel_msg.channel_type.unwrap().supports_anchors_zero_fee_htlc_tx());
 +              assert!(!open_channel_msg.common_fields.channel_type.unwrap().supports_anchors_zero_fee_htlc_tx());
  
                // Since nodes[1] should not have accepted the channel, it should
                // not have generated any events.
index d2cfce3608a7064c4fd9faf04986c787a422d232,31a258d84493d6831fa4b5dd1fa1140af6c1e530..adf2768b4152700ed82172e9a44ab75c6c3475a2
@@@ -487,16 -487,38 +487,38 @@@ impl<'a, 'b, 'c> Node<'a, 'b, 'c> 
        /// `release_commitment_secret` are affected by this setting.
        #[cfg(test)]
        pub fn set_channel_signer_available(&self, peer_id: &PublicKey, chan_id: &ChannelId, available: bool) {
+               use crate::sign::ChannelSigner;
+               log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
                let per_peer_state = self.node.per_peer_state.read().unwrap();
                let chan_lock = per_peer_state.get(peer_id).unwrap().lock().unwrap();
-               let signer = (|| {
-                       match chan_lock.channel_by_id.get(chan_id) {
-                               Some(phase) => phase.context().get_signer(),
-                               None => panic!("Couldn't find a channel with id {}", chan_id),
+               let mut channel_keys_id = None;
+               if let Some(chan) = chan_lock.channel_by_id.get(chan_id).map(|phase| phase.context()) {
+                       chan.get_signer().as_ecdsa().unwrap().set_available(available);
+                       channel_keys_id = Some(chan.channel_keys_id);
+               }
+               let mut monitor = None;
+               for (funding_txo, channel_id) in self.chain_monitor.chain_monitor.list_monitors() {
+                       if *chan_id == channel_id {
+                               monitor = self.chain_monitor.chain_monitor.get_monitor(funding_txo).ok();
                        }
-               })();
-               log_debug!(self.logger, "Setting channel signer for {} as available={}", chan_id, available);
-               signer.as_ecdsa().unwrap().set_available(available);
+               }
+               if let Some(monitor) = monitor {
+                       monitor.do_signer_call(|signer| {
+                               channel_keys_id = channel_keys_id.or(Some(signer.inner.channel_keys_id()));
+                               signer.set_available(available)
+                       });
+               }
+               if available {
+                       self.keys_manager.unavailable_signers.lock().unwrap()
+                               .remove(channel_keys_id.as_ref().unwrap());
+               } else {
+                       self.keys_manager.unavailable_signers.lock().unwrap()
+                               .insert(channel_keys_id.unwrap());
+               }
        }
  }
  
@@@ -1203,7 -1225,7 +1225,7 @@@ pub fn open_zero_conf_channel<'a, 'b, '
        };
  
        let accept_channel = get_event_msg!(receiver, MessageSendEvent::SendAcceptChannel, initiator.node.get_our_node_id());
 -      assert_eq!(accept_channel.minimum_depth, 0);
 +      assert_eq!(accept_channel.common_fields.minimum_depth, 0);
        initiator.node.handle_accept_channel(&receiver.node.get_our_node_id(), &accept_channel);
  
        let (temporary_channel_id, tx, _) = create_funding_transaction(&initiator, &receiver.node.get_our_node_id(), 100_000, 42);
  pub fn exchange_open_accept_chan<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, push_msat: u64) -> ChannelId {
        let create_chan_id = node_a.node.create_channel(node_b.node.get_our_node_id(), channel_value, push_msat, 42, None, None).unwrap();
        let open_channel_msg = get_event_msg!(node_a, MessageSendEvent::SendOpenChannel, node_b.node.get_our_node_id());
 -      assert_eq!(open_channel_msg.temporary_channel_id, create_chan_id);
 +      assert_eq!(open_channel_msg.common_fields.temporary_channel_id, create_chan_id);
        assert_eq!(node_a.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 42);
        node_b.node.handle_open_channel(&node_a.node.get_our_node_id(), &open_channel_msg);
        if node_b.node.get_current_default_configuration().manually_accept_inbound_channels {
                };
        }
        let accept_channel_msg = get_event_msg!(node_b, MessageSendEvent::SendAcceptChannel, node_a.node.get_our_node_id());
 -      assert_eq!(accept_channel_msg.temporary_channel_id, create_chan_id);
 +      assert_eq!(accept_channel_msg.common_fields.temporary_channel_id, create_chan_id);
        node_a.node.handle_accept_channel(&node_b.node.get_our_node_id(), &accept_channel_msg);
        assert_ne!(node_b.node.list_channels().iter().find(|channel| channel.channel_id == create_chan_id).unwrap().user_channel_id, 0);