From e7fc79cb440629cb7e2b82ce83d313837ee5c191 Mon Sep 17 00:00:00 2001
From: optout <13562139+optout21@users.noreply.github.com>
Date: Wed, 12 Jul 2023 00:34:45 +0200
Subject: [PATCH 1/5] Add ChannelId alias for channel_id type

---
 lightning/src/chain/transaction.rs        |  3 +-
 lightning/src/events/mod.rs               | 26 +++++-----
 lightning/src/ln/channel.rs               | 31 ++++++------
 lightning/src/ln/channelmanager.rs        | 48 +++++++++---------
 lightning/src/ln/functional_test_utils.rs |  5 +-
 lightning/src/ln/msgs.rs                  | 59 ++++++++++++-----------
 lightning/src/ln/peer_handler.rs          |  3 +-
 lightning/src/util/test_utils.rs          |  3 +-
 8 files changed, 93 insertions(+), 85 deletions(-)

diff --git a/lightning/src/chain/transaction.rs b/lightning/src/chain/transaction.rs
index ce449a4102c..cd8ec4571fd 100644
--- a/lightning/src/chain/transaction.rs
+++ b/lightning/src/chain/transaction.rs
@@ -9,6 +9,7 @@
 
 //! Types describing on-chain transactions.
 
+use crate::ln::channel::ChannelId;
 use bitcoin::hash_types::Txid;
 use bitcoin::blockdata::transaction::OutPoint as BitcoinOutPoint;
 use bitcoin::blockdata::transaction::Transaction;
@@ -57,7 +58,7 @@ pub struct OutPoint {
 
 impl OutPoint {
 	/// Convert an `OutPoint` to a lightning channel id.
-	pub fn to_channel_id(&self) -> [u8; 32] {
+	pub fn to_channel_id(&self) -> ChannelId {
 		let mut res = [0; 32];
 		res[..].copy_from_slice(&self.txid[..]);
 		res[30] ^= ((self.index >> 8) & 0xff) as u8;
diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs
index d08e563cbf6..b22bfb6a0b3 100644
--- a/lightning/src/events/mod.rs
+++ b/lightning/src/events/mod.rs
@@ -20,7 +20,7 @@ pub use bump_transaction::BumpTransactionEvent;
 
 use crate::sign::SpendableOutputDescriptor;
 use crate::ln::channelmanager::{InterceptId, PaymentId, RecipientOnionFields};
-use crate::ln::channel::FUNDING_CONF_DEADLINE_BLOCKS;
+use crate::ln::channel::{ChannelId, FUNDING_CONF_DEADLINE_BLOCKS};
 use crate::ln::features::ChannelTypeFeatures;
 use crate::ln::msgs;
 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
@@ -215,7 +215,7 @@ pub enum HTLCDestination {
 		/// counterparty node information.
 		node_id: Option<PublicKey>,
 		/// The outgoing `channel_id` between us and the next node.
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 	},
 	/// Scenario where we are unsure of the next node to forward the HTLC to.
 	UnknownNextHop {
@@ -333,7 +333,7 @@ pub enum Event {
 		/// [`ChannelManager::funding_transaction_generated`].
 		///
 		/// [`ChannelManager::funding_transaction_generated`]: crate::ln::channelmanager::ChannelManager::funding_transaction_generated
-		temporary_channel_id: [u8; 32],
+		temporary_channel_id: ChannelId,
 		/// The counterparty's node_id, which you'll need to pass back into
 		/// [`ChannelManager::funding_transaction_generated`].
 		///
@@ -411,7 +411,7 @@ pub enum Event {
 		/// payment is to pay an invoice or to send a spontaneous payment.
 		purpose: PaymentPurpose,
 		/// The `channel_id` indicating over which channel we received the payment.
-		via_channel_id: Option<[u8; 32]>,
+		via_channel_id: Option<ChannelId>,
 		/// The `user_channel_id` indicating over which channel we received the payment.
 		via_user_channel_id: Option<u128>,
 		/// The block height at which this payment will be failed back and will no longer be
@@ -663,10 +663,10 @@ pub enum Event {
 	PaymentForwarded {
 		/// The incoming channel between the previous node and us. This is only `None` for events
 		/// generated or serialized by versions prior to 0.0.107.
-		prev_channel_id: Option<[u8; 32]>,
+		prev_channel_id: Option<ChannelId>,
 		/// The outgoing channel between the next node and us. This is only `None` for events
 		/// generated or serialized by versions prior to 0.0.107.
-		next_channel_id: Option<[u8; 32]>,
+		next_channel_id: Option<ChannelId>,
 		/// The fee, in milli-satoshis, which was earned as a result of the payment.
 		///
 		/// Note that if we force-closed the channel over which we forwarded an HTLC while the HTLC
@@ -697,7 +697,7 @@ pub enum Event {
 	/// [`Event::ChannelReady`] event.
 	ChannelPending {
 		/// The `channel_id` of the channel that is pending confirmation.
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 		/// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound
 		/// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if
 		/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
@@ -710,7 +710,7 @@ pub enum Event {
 		/// The `temporary_channel_id` this channel used to be known by during channel establishment.
 		///
 		/// Will be `None` for channels created prior to LDK version 0.0.115.
-		former_temporary_channel_id: Option<[u8; 32]>,
+		former_temporary_channel_id: Option<ChannelId>,
 		/// The `node_id` of the channel counterparty.
 		counterparty_node_id: PublicKey,
 		/// The outpoint of the channel's funding transaction.
@@ -722,7 +722,7 @@ pub enum Event {
 	/// establishment.
 	ChannelReady {
 		/// The `channel_id` of the channel that is ready.
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 		/// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound
 		/// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if
 		/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
@@ -742,7 +742,7 @@ pub enum Event {
 	ChannelClosed  {
 		/// The `channel_id` of the channel which has been closed. Note that on-chain transactions
 		/// resolving the channel are likely still awaiting confirmation.
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 		/// The `user_channel_id` value passed in to [`ChannelManager::create_channel`] for outbound
 		/// channels, or to [`ChannelManager::accept_inbound_channel`] for inbound channels if
 		/// [`UserConfig::manually_accept_inbound_channels`] config flag is set to true. Otherwise
@@ -761,7 +761,7 @@ pub enum Event {
 	/// inputs for another purpose.
 	DiscardFunding {
 		/// The channel_id of the channel which has been closed.
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 		/// The full transaction received from the user
 		transaction: Transaction
 	},
@@ -785,7 +785,7 @@ pub enum Event {
 		///
 		/// [`ChannelManager::accept_inbound_channel`]: crate::ln::channelmanager::ChannelManager::accept_inbound_channel
 		/// [`ChannelManager::force_close_without_broadcasting_txn`]: crate::ln::channelmanager::ChannelManager::force_close_without_broadcasting_txn
-		temporary_channel_id: [u8; 32],
+		temporary_channel_id: ChannelId,
 		/// The node_id of the counterparty requesting to open the channel.
 		///
 		/// When responding to the request, the `counterparty_node_id` should be passed
@@ -831,7 +831,7 @@ pub enum Event {
 	/// requirements (i.e. insufficient fees paid, or a CLTV that is too soon).
 	HTLCHandlingFailed {
 		/// The channel over which the HTLC was received.
-		prev_channel_id: [u8; 32],
+		prev_channel_id: ChannelId,
 		/// Destination of the HTLC that failed to be processed.
 		failed_next_destination: HTLCDestination,
 	},
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index e559ac33550..bf0f32b170c 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -603,6 +603,9 @@ impl_writeable_tlv_based!(PendingChannelMonitorUpdate, {
 	(0, update, required),
 });
 
+/// Channel ID is 32 bytes
+pub type ChannelId = [u8; 32];
+
 /// Contains all state common to unfunded inbound/outbound channels.
 pub(super) struct UnfundedChannelContext {
 	/// A counter tracking how many ticks have elapsed since this unfunded channel was
@@ -638,8 +641,8 @@ pub(super) struct ChannelContext<Signer: ChannelSigner> {
 
 	user_id: u128,
 
-	channel_id: [u8; 32],
-	temporary_channel_id: Option<[u8; 32]>, // Will be `None` for channels created prior to 0.0.115.
+	channel_id: ChannelId,
+	temporary_channel_id: Option<ChannelId>, // Will be `None` for channels created prior to 0.0.115.
 	channel_state: u32,
 
 	// When we reach max(6 blocks, minimum_depth), we need to send an AnnouncementSigs message to
@@ -971,7 +974,7 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
 
 	// Public utilities:
 
-	pub fn channel_id(&self) -> [u8; 32] {
+	pub fn channel_id(&self) -> ChannelId {
 		self.channel_id
 	}
 
@@ -7211,7 +7214,7 @@ impl<'a, 'b, 'c, ES: Deref, SP: Deref> ReadableArgs<(&'a ES, &'b SP, u32, &'c Ch
 
 		let mut user_id_high_opt: Option<u64> = None;
 		let mut channel_keys_id: Option<[u8; 32]> = None;
-		let mut temporary_channel_id: Option<[u8; 32]> = None;
+		let mut temporary_channel_id: Option<ChannelId> = None;
 		let mut holder_max_accepted_htlcs: Option<u16> = None;
 
 		let mut blocked_monitor_updates = Some(Vec::new());
@@ -7453,16 +7456,16 @@ mod tests {
 	use bitcoin::blockdata::opcodes;
 	use bitcoin::network::constants::Network;
 	use hex;
-	use crate::ln::PaymentHash;
-	use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
-	use crate::ln::channel::InitFeatures;
-	use crate::ln::channel::{Channel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat};
-	use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
-	use crate::ln::features::ChannelTypeFeatures;
-	use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
-	use crate::ln::script::ShutdownScript;
-	use crate::ln::chan_utils;
-	use crate::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight};
+use crate::ln::PaymentHash;
+use crate::ln::channelmanager::{self, HTLCSource, PaymentId};
+use crate::ln::channel::InitFeatures;
+use crate::ln::channel::{Channel, InboundHTLCOutput, OutboundV1Channel, InboundV1Channel, OutboundHTLCOutput, InboundHTLCState, OutboundHTLCState, HTLCCandidate, HTLCInitiator, commit_tx_fee_msat};
+use crate::ln::channel::{MAX_FUNDING_SATOSHIS_NO_WUMBO, TOTAL_BITCOIN_SUPPLY_SATOSHIS, MIN_THEIR_CHAN_RESERVE_SATOSHIS};
+use crate::ln::features::ChannelTypeFeatures;
+use crate::ln::msgs::{ChannelUpdate, DecodeError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
+use crate::ln::script::ShutdownScript;
+use crate::ln::chan_utils;
+use crate::ln::chan_utils::{htlc_success_tx_weight, htlc_timeout_tx_weight};
 	use crate::chain::BestBlock;
 	use crate::chain::chaininterface::{FeeEstimator, LowerBoundedFeeEstimator, ConfirmationTarget};
 	use crate::sign::{ChannelSigner, InMemorySigner, EntropySource, SignerProvider};
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index b22c3716ccb..6c1ff584bbd 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -40,7 +40,7 @@ use crate::events::{Event, EventHandler, EventsProvider, MessageSendEvent, Messa
 // Since this struct is returned in `list_channels` methods, expose it here in case users want to
 // construct one themselves.
 use crate::ln::{inbound_payment, PaymentHash, PaymentPreimage, PaymentSecret};
-use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
+use crate::ln::channel::{Channel, ChannelContext, ChannelError, ChannelId, ChannelUpdateStatus, ShutdownResult, UnfundedChannelContext, UpdateFulfillCommitFetch, OutboundV1Channel, InboundV1Channel};
 use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 #[cfg(any(feature = "_test_utils", test))]
 use crate::ln::features::Bolt11InvoiceFeatures;
@@ -379,7 +379,7 @@ struct MsgHandleErrInternal {
 }
 impl MsgHandleErrInternal {
 	#[inline]
-	fn send_err_msg_no_close(err: String, channel_id: [u8; 32]) -> Self {
+	fn send_err_msg_no_close(err: String, channel_id: ChannelId) -> Self {
 		Self {
 			err: LightningError {
 				err: err.clone(),
@@ -399,7 +399,7 @@ impl MsgHandleErrInternal {
 		Self { err, chan_id: None, shutdown_finish: None }
 	}
 	#[inline]
-	fn from_finish_shutdown(err: String, channel_id: [u8; 32], user_channel_id: u128, shutdown_res: ShutdownResult, channel_update: Option<msgs::ChannelUpdate>) -> Self {
+	fn from_finish_shutdown(err: String, channel_id: ChannelId, user_channel_id: u128, shutdown_res: ShutdownResult, channel_update: Option<msgs::ChannelUpdate>) -> Self {
 		Self {
 			err: LightningError {
 				err: err.clone(),
@@ -415,7 +415,7 @@ impl MsgHandleErrInternal {
 		}
 	}
 	#[inline]
-	fn from_chan_no_close(err: ChannelError, channel_id: [u8; 32]) -> Self {
+	fn from_chan_no_close(err: ChannelError, channel_id: ChannelId) -> Self {
 		Self {
 			err: match err {
 				ChannelError::Warn(msg) =>  LightningError {
@@ -596,7 +596,7 @@ pub(crate) enum RAAMonitorUpdateBlockingAction {
 	/// durably to disk.
 	ForwardedPaymentInboundClaim {
 		/// The upstream channel ID (i.e. the inbound edge).
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 		/// The HTLC ID on the inbound edge.
 		htlc_id: u64,
 	},
@@ -693,7 +693,7 @@ impl <Signer: ChannelSigner> PeerState<Signer> {
 	}
 
 	// Returns a bool indicating if the given `channel_id` matches a channel we have with this peer.
-	fn has_channel(&self, channel_id: &[u8; 32]) -> bool {
+	fn has_channel(&self, channel_id: &ChannelId) -> bool {
 		self.channel_by_id.contains_key(channel_id) ||
 			self.outbound_v1_channel_by_id.contains_key(channel_id) ||
 			self.inbound_v1_channel_by_id.contains_key(channel_id)
@@ -1338,7 +1338,7 @@ pub struct ChannelDetails {
 	/// thereafter this is the txid of the funding transaction xor the funding transaction output).
 	/// Note that this means this value is *not* persistent - it can change once during the
 	/// lifetime of the channel.
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// Parameters which apply to our counterparty. See individual fields for more information.
 	pub counterparty: ChannelCounterparty,
 	/// The Channel's funding transaction output, if we've negotiated the funding transaction with
@@ -2375,7 +2375,7 @@ where
 		}, None));
 	}
 
-	fn close_channel_internal(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, override_shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
+	fn close_channel_internal(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, override_shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
 		let mut failed_htlcs: Vec<(HTLCSource, PaymentHash)>;
@@ -2467,7 +2467,7 @@ where
 	/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
 	/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
 	/// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown
-	pub fn close_channel(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey) -> Result<(), APIError> {
+	pub fn close_channel(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey) -> Result<(), APIError> {
 		self.close_channel_internal(channel_id, counterparty_node_id, None, None)
 	}
 
@@ -2501,7 +2501,7 @@ where
 	/// [`Background`]: crate::chain::chaininterface::ConfirmationTarget::Background
 	/// [`Normal`]: crate::chain::chaininterface::ConfirmationTarget::Normal
 	/// [`SendShutdown`]: crate::events::MessageSendEvent::SendShutdown
-	pub fn close_channel_with_feerate_and_script(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
+	pub fn close_channel_with_feerate_and_script(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, target_feerate_sats_per_1000_weight: Option<u32>, shutdown_script: Option<ShutdownScript>) -> Result<(), APIError> {
 		self.close_channel_internal(channel_id, counterparty_node_id, target_feerate_sats_per_1000_weight, shutdown_script)
 	}
 
@@ -2526,7 +2526,7 @@ where
 
 	/// `peer_msg` should be set when we receive a message from a peer, but not set when the
 	/// user closes, which will be re-exposed as the `ChannelClosed` reason.
-	fn force_close_channel_with_peer(&self, channel_id: &[u8; 32], peer_node_id: &PublicKey, peer_msg: Option<&String>, broadcast: bool)
+	fn force_close_channel_with_peer(&self, channel_id: &ChannelId, peer_node_id: &PublicKey, peer_msg: Option<&String>, broadcast: bool)
 	-> Result<PublicKey, APIError> {
 		let per_peer_state = self.per_peer_state.read().unwrap();
 		let peer_state_mutex = per_peer_state.get(peer_node_id)
@@ -2573,7 +2573,7 @@ where
 		Ok(counterparty_node_id)
 	}
 
-	fn force_close_sending_error(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey, broadcast: bool) -> Result<(), APIError> {
+	fn force_close_sending_error(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey, broadcast: bool) -> Result<(), APIError> {
 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 		match self.force_close_channel_with_peer(channel_id, counterparty_node_id, None, broadcast) {
 			Ok(counterparty_node_id) => {
@@ -2599,7 +2599,7 @@ where
 	/// rejecting new HTLCs on the given channel. Fails if `channel_id` is unknown to
 	/// the manager, or if the `counterparty_node_id` isn't the counterparty of the corresponding
 	/// channel.
-	pub fn force_close_broadcasting_latest_txn(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey)
+	pub fn force_close_broadcasting_latest_txn(&self, channel_id: &ChannelId, counterparty_node_id: &PublicKey)
 	-> Result<(), APIError> {
 		self.force_close_sending_error(channel_id, counterparty_node_id, true)
 	}
@@ -2610,7 +2610,7 @@ where
 	///
 	/// You can always get the latest local transaction(s) to broadcast from
 	/// [`ChannelMonitor::get_latest_holder_commitment_txn`].
-	pub fn force_close_without_broadcasting_txn(&self, channel_id: &[u8; 32], counterparty_node_id: &PublicKey)
+	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)
 	}
@@ -3353,7 +3353,7 @@ where
 	/// Handles the generation of a funding transaction, optionally (for tests) with a function
 	/// which checks the correctness of the funding transaction given the associated channel.
 	fn funding_transaction_generated_intern<FundingOutput: Fn(&OutboundV1Channel<<SP::Target as SignerProvider>::Signer>, &Transaction) -> Result<OutPoint, APIError>>(
-		&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, funding_transaction: Transaction, find_funding_output: FundingOutput
+		&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction, find_funding_output: FundingOutput
 	) -> Result<(), APIError> {
 		let per_peer_state = self.per_peer_state.read().unwrap();
 		let peer_state_mutex = per_peer_state.get(counterparty_node_id)
@@ -3414,7 +3414,7 @@ where
 	}
 
 	#[cfg(test)]
-	pub(crate) fn funding_transaction_generated_unchecked(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, funding_transaction: Transaction, output_index: u16) -> Result<(), APIError> {
+	pub(crate) fn funding_transaction_generated_unchecked(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction, output_index: u16) -> Result<(), APIError> {
 		self.funding_transaction_generated_intern(temporary_channel_id, counterparty_node_id, funding_transaction, |_, tx| {
 			Ok(OutPoint { txid: tx.txid(), index: output_index })
 		})
@@ -3450,7 +3450,7 @@ where
 	///
 	/// [`Event::FundingGenerationReady`]: crate::events::Event::FundingGenerationReady
 	/// [`Event::ChannelClosed`]: crate::events::Event::ChannelClosed
-	pub fn funding_transaction_generated(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> {
+	pub fn funding_transaction_generated(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, funding_transaction: Transaction) -> Result<(), APIError> {
 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
 		for inp in funding_transaction.input.iter() {
@@ -3637,7 +3637,7 @@ where
 	/// [`HTLCIntercepted::expected_outbound_amount_msat`]: events::Event::HTLCIntercepted::expected_outbound_amount_msat
 	// TODO: when we move to deciding the best outbound channel at forward time, only take
 	// `next_node_id` and not `next_hop_channel_id`
-	pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &[u8; 32], next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {
+	pub fn forward_intercepted_htlc(&self, intercept_id: InterceptId, next_hop_channel_id: &ChannelId, next_node_id: PublicKey, amt_to_forward_msat: u64) -> Result<(), APIError> {
 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
 		let next_hop_scid = {
@@ -4624,7 +4624,7 @@ where
 	// failed backwards or, if they were one of our outgoing HTLCs, then their failure needs to
 	// be surfaced to the user.
 	fn fail_holding_cell_htlcs(
-		&self, mut htlcs_to_fail: Vec<(HTLCSource, PaymentHash)>, channel_id: [u8; 32],
+		&self, mut htlcs_to_fail: Vec<(HTLCSource, PaymentHash)>, channel_id: ChannelId,
 		counterparty_node_id: &PublicKey
 	) {
 		let (failure_code, onion_failure_data) = {
@@ -4936,7 +4936,7 @@ where
 		self.pending_outbound_payments.finalize_claims(sources, &self.pending_events);
 	}
 
-	fn claim_funds_internal(&self, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_id: [u8; 32]) {
+	fn claim_funds_internal(&self, source: HTLCSource, payment_preimage: PaymentPreimage, forwarded_htlc_value_msat: Option<u64>, from_onchain: bool, next_channel_id: ChannelId) {
 		match source {
 			HTLCSource::OutboundRoute { session_priv, payment_id, path, .. } => {
 				debug_assert!(self.background_events_processed_since_startup.load(Ordering::Acquire),
@@ -5137,7 +5137,7 @@ where
 	///
 	/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
 	/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
-	pub fn accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
+	pub fn accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
 		self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, false, user_channel_id)
 	}
 
@@ -5159,11 +5159,11 @@ where
 	///
 	/// [`Event::OpenChannelRequest`]: events::Event::OpenChannelRequest
 	/// [`Event::ChannelClosed::user_channel_id`]: events::Event::ChannelClosed::user_channel_id
-	pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
+	pub fn accept_inbound_channel_from_trusted_peer_0conf(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, user_channel_id: u128) -> Result<(), APIError> {
 		self.do_accept_inbound_channel(temporary_channel_id, counterparty_node_id, true, user_channel_id)
 	}
 
-	fn do_accept_inbound_channel(&self, temporary_channel_id: &[u8; 32], counterparty_node_id: &PublicKey, accept_0conf: bool, user_channel_id: u128) -> Result<(), APIError> {
+	fn do_accept_inbound_channel(&self, temporary_channel_id: &ChannelId, counterparty_node_id: &PublicKey, accept_0conf: bool, user_channel_id: u128) -> Result<(), APIError> {
 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
 		let peers_without_funded_channels =
@@ -6204,7 +6204,7 @@ where
 						if let Some(monitor_update) = monitor_opt {
 							has_monitor_update = true;
 
-							let channel_id: [u8; 32] = *channel_id;
+							let channel_id: ChannelId = *channel_id;
 							let res = handle_new_monitor_update!(self, funding_txo.unwrap(), monitor_update,
 								peer_state_lock, peer_state, per_peer_state, chan, MANUALLY_REMOVING,
 								peer_state.channel_by_id.remove(&channel_id));
diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs
index 84bc1a1b3f0..e4b69dbac76 100644
--- a/lightning/src/ln/functional_test_utils.rs
+++ b/lightning/src/ln/functional_test_utils.rs
@@ -17,6 +17,7 @@ use crate::chain::transaction::OutPoint;
 use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, PaymentFailureReason};
 use crate::events::bump_transaction::{BumpTransactionEventHandler, Wallet, WalletSource};
 use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+use crate::ln::channel::ChannelId;
 use crate::ln::channelmanager::{AChannelManager, ChainParameters, ChannelManager, ChannelManagerReadArgs, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, PaymentId, MIN_CLTV_EXPIRY_DELTA};
 use crate::routing::gossip::{P2PGossipSync, NetworkGraph, NetworkUpdate};
 use crate::routing::router::{self, PaymentParameters, Route};
@@ -1001,7 +1002,7 @@ pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_
 		_ => panic!("Unexpected event"),
 	}
 }
-pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, expected_temporary_channel_id: [u8; 32]) -> Transaction {
+pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &Node<'a, 'b, 'c>, channel_value: u64, expected_temporary_channel_id: ChannelId) -> Transaction {
 	let (temporary_channel_id, tx, funding_output) = create_funding_transaction(node_a, &node_b.node.get_our_node_id(), channel_value, 42);
 	assert_eq!(temporary_channel_id, expected_temporary_channel_id);
 
@@ -1449,7 +1450,7 @@ macro_rules! check_closed_event {
 	}
 }
 
-pub fn close_channel<'a, 'b, 'c>(outbound_node: &Node<'a, 'b, 'c>, inbound_node: &Node<'a, 'b, 'c>, channel_id: &[u8; 32], funding_tx: Transaction, close_inbound_first: bool) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, Transaction) {
+pub fn close_channel<'a, 'b, 'c>(outbound_node: &Node<'a, 'b, 'c>, inbound_node: &Node<'a, 'b, 'c>, channel_id: &ChannelId, funding_tx: Transaction, close_inbound_first: bool) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, Transaction) {
 	let (node_a, broadcaster_a, struct_a) = if close_inbound_first { (&inbound_node.node, &inbound_node.tx_broadcaster, inbound_node) } else { (&outbound_node.node, &outbound_node.tx_broadcaster, outbound_node) };
 	let (node_b, broadcaster_b, struct_b) = if close_inbound_first { (&outbound_node.node, &outbound_node.tx_broadcaster, outbound_node) } else { (&inbound_node.node, &inbound_node.tx_broadcaster, inbound_node) };
 	let (tx_a, tx_b);
diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs
index 0c23d4425f8..d06aa26ee7c 100644
--- a/lightning/src/ln/msgs.rs
+++ b/lightning/src/ln/msgs.rs
@@ -31,6 +31,7 @@ use bitcoin::{secp256k1, Witness};
 use bitcoin::blockdata::script::Script;
 use bitcoin::hash_types::{Txid, BlockHash};
 
+use crate::ln::channel::ChannelId;
 use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 use crate::ln::onion_utils;
 use crate::onion_message;
@@ -111,7 +112,7 @@ pub struct ErrorMessage {
 	///
 	/// All-0s indicates a general error unrelated to a specific channel, after which all channels
 	/// with the sending peer should be closed.
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// A possibly human-readable error description.
 	///
 	/// The string should be sanitized before it is used (e.g., emitted to logs or printed to
@@ -128,7 +129,7 @@ pub struct WarningMessage {
 	/// The channel ID involved in the warning.
 	///
 	/// All-0s indicates a warning unrelated to a specific channel.
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// A possibly human-readable warning description.
 	///
 	/// The string should be sanitized before it is used (e.g. emitted to logs or printed to
@@ -171,7 +172,7 @@ pub struct OpenChannel {
 	/// The genesis hash of the blockchain where the channel is to be opened
 	pub chain_hash: BlockHash,
 	/// A temporary channel ID, until the funding outpoint is announced
-	pub temporary_channel_id: [u8; 32],
+	pub temporary_channel_id: ChannelId,
 	/// The channel value
 	pub funding_satoshis: u64,
 	/// The amount to push to the counterparty as part of the open, in milli-satoshi
@@ -225,7 +226,7 @@ pub struct OpenChannelV2 {
 	/// The genesis hash of the blockchain where the channel is to be opened
 	pub chain_hash: BlockHash,
 	/// A temporary channel ID derived using a zeroed out value for the channel acceptor's revocation basepoint
-	pub temporary_channel_id: [u8; 32],
+	pub temporary_channel_id: ChannelId,
 	/// The feerate for the funding transaction set by the channel initiator
 	pub funding_feerate_sat_per_1000_weight: u32,
 	/// The feerate for the commitment transaction set by the channel initiator
@@ -282,7 +283,7 @@ pub struct OpenChannelV2 {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct AcceptChannel {
 	/// A temporary channel ID, until the funding outpoint is announced
-	pub temporary_channel_id: [u8; 32],
+	pub temporary_channel_id: ChannelId,
 	/// The threshold below which outputs on transactions broadcast by sender will be omitted
 	pub dust_limit_satoshis: u64,
 	/// The maximum inbound HTLC value in flight towards sender, in milli-satoshi
@@ -330,7 +331,7 @@ pub struct AcceptChannel {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct AcceptChannelV2 {
 	/// The same `temporary_channel_id` received from the initiator's `open_channel2` message.
-	pub temporary_channel_id: [u8; 32],
+	pub temporary_channel_id: ChannelId,
 	/// Part of the channel value contributed by the channel acceptor
 	pub funding_satoshis: u64,
 	/// The threshold below which outputs on transactions broadcast by the channel acceptor will be
@@ -383,7 +384,7 @@ pub struct AcceptChannelV2 {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct FundingCreated {
 	/// A temporary channel ID, until the funding is established
-	pub temporary_channel_id: [u8; 32],
+	pub temporary_channel_id: ChannelId,
 	/// The funding transaction ID
 	pub funding_txid: Txid,
 	/// The specific output index funding this channel
@@ -406,7 +407,7 @@ pub struct FundingCreated {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct FundingSigned {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The signature of the channel acceptor (fundee) on the initial commitment transaction
 	pub signature: Signature,
 	#[cfg(taproot)]
@@ -420,7 +421,7 @@ pub struct FundingSigned {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ChannelReady {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The per-commitment point of the second commitment transaction
 	pub next_per_commitment_point: PublicKey,
 	/// If set, provides a `short_channel_id` alias for this channel.
@@ -436,7 +437,7 @@ pub struct ChannelReady {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxAddInput {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// A randomly chosen unique identifier for this input, which is even for initiators and odd for
 	/// non-initiators.
 	pub serial_id: u64,
@@ -455,7 +456,7 @@ pub struct TxAddInput {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxAddOutput {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// A randomly chosen unique identifier for this output, which is even for initiators and odd for
 	/// non-initiators.
 	pub serial_id: u64,
@@ -471,7 +472,7 @@ pub struct TxAddOutput {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxRemoveInput {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The serial ID of the input to be removed
 	pub serial_id: u64,
 }
@@ -482,7 +483,7 @@ pub struct TxRemoveInput {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxRemoveOutput {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The serial ID of the output to be removed
 	pub serial_id: u64,
 }
@@ -494,7 +495,7 @@ pub struct TxRemoveOutput {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxComplete {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 }
 
 /// A tx_signatures message containing the sender's signatures for a transaction constructed with
@@ -504,7 +505,7 @@ pub struct TxComplete {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxSignatures {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The TXID
 	pub tx_hash: Txid,
 	/// The list of witnesses
@@ -518,7 +519,7 @@ pub struct TxSignatures {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxInitRbf {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The locktime of the transaction
 	pub locktime: u32,
 	/// The feerate of the transaction
@@ -535,7 +536,7 @@ pub struct TxInitRbf {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxAckRbf {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The number of satoshis the sender will contribute to or, if negative, remove from
 	/// (e.g. splice-out) the funding output of the transaction
 	pub funding_output_contribution: Option<i64>,
@@ -547,7 +548,7 @@ pub struct TxAckRbf {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct TxAbort {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// Message data
 	pub data: Vec<u8>,
 }
@@ -558,7 +559,7 @@ pub struct TxAbort {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct Shutdown {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The destination of this peer's funds on closing.
 	///
 	/// Must be in one of these forms: P2PKH, P2SH, P2WPKH, P2WSH, P2TR.
@@ -585,7 +586,7 @@ pub struct ClosingSignedFeeRange {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ClosingSigned {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The proposed total fee for the closing transaction
 	pub fee_satoshis: u64,
 	/// A signature on the closing transaction
@@ -601,7 +602,7 @@ pub struct ClosingSigned {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateAddHTLC {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The HTLC ID
 	pub htlc_id: u64,
 	/// The HTLC value in milli-satoshi
@@ -634,7 +635,7 @@ pub struct OnionMessage {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFulfillHTLC {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The HTLC ID
 	pub htlc_id: u64,
 	/// The pre-image of the payment hash, allowing HTLC redemption
@@ -647,7 +648,7 @@ pub struct UpdateFulfillHTLC {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFailHTLC {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The HTLC ID
 	pub htlc_id: u64,
 	pub(crate) reason: OnionErrorPacket,
@@ -659,7 +660,7 @@ pub struct UpdateFailHTLC {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFailMalformedHTLC {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The HTLC ID
 	pub htlc_id: u64,
 	pub(crate) sha256_of_onion: [u8; 32],
@@ -673,7 +674,7 @@ pub struct UpdateFailMalformedHTLC {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct CommitmentSigned {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// A signature on the commitment transaction
 	pub signature: Signature,
 	/// Signatures on the HTLC transactions
@@ -689,7 +690,7 @@ pub struct CommitmentSigned {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct RevokeAndACK {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The secret corresponding to the per-commitment point
 	pub per_commitment_secret: [u8; 32],
 	/// The next sender-broadcast commitment transaction's per-commitment point
@@ -705,7 +706,7 @@ pub struct RevokeAndACK {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct UpdateFee {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// Fee rate per 1000-weight of the transaction
 	pub feerate_per_kw: u32,
 }
@@ -716,7 +717,7 @@ pub struct UpdateFee {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct ChannelReestablish {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The next commitment number for the sender
 	pub next_local_commitment_number: u64,
 	/// The next commitment number for the recipient
@@ -736,7 +737,7 @@ pub struct ChannelReestablish {
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub struct AnnouncementSignatures {
 	/// The channel ID
-	pub channel_id: [u8; 32],
+	pub channel_id: ChannelId,
 	/// The short channel ID
 	pub short_channel_id: u64,
 	/// A signature by the node key
diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs
index 1a39bbb3ae4..bc3eb720c07 100644
--- a/lightning/src/ln/peer_handler.rs
+++ b/lightning/src/ln/peer_handler.rs
@@ -20,6 +20,7 @@ use bitcoin::secp256k1::{self, Secp256k1, SecretKey, PublicKey};
 
 use crate::sign::{KeysManager, NodeSigner, Recipient};
 use crate::events::{MessageSendEvent, MessageSendEventsProvider, OnionMessageProvider};
+use crate::ln::channel::ChannelId;
 use crate::ln::features::{InitFeatures, NodeFeatures};
 use crate::ln::msgs;
 use crate::ln::msgs::{ChannelMessageHandler, LightningError, NetAddress, OnionMessageHandler, RoutingMessageHandler};
@@ -186,7 +187,7 @@ impl ErroringMessageHandler {
 	pub fn new() -> Self {
 		Self { message_queue: Mutex::new(Vec::new()) }
 	}
-	fn push_error(&self, node_id: &PublicKey, channel_id: [u8; 32]) {
+	fn push_error(&self, node_id: &PublicKey, channel_id: ChannelId) {
 		self.message_queue.lock().unwrap().push(MessageSendEvent::HandleError {
 			action: msgs::ErrorAction::SendErrorMessage {
 				msg: msgs::ErrorMessage { channel_id, data: "We do not support channel messages, sorry.".to_owned() },
diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs
index 65c0483a59c..ee3f19c6581 100644
--- a/lightning/src/util/test_utils.rs
+++ b/lightning/src/util/test_utils.rs
@@ -19,6 +19,7 @@ use crate::chain::transaction::OutPoint;
 use crate::sign;
 use crate::events;
 use crate::events::bump_transaction::{WalletSource, Utxo};
+use crate::ln::channel::ChannelId;
 use crate::ln::channelmanager;
 use crate::ln::features::{ChannelFeatures, InitFeatures, NodeFeatures};
 use crate::ln::{msgs, wire};
@@ -212,7 +213,7 @@ impl<'a> TestChainMonitor<'a> {
 		}
 	}
 
-	pub fn complete_sole_pending_chan_update(&self, channel_id: &[u8; 32]) {
+	pub fn complete_sole_pending_chan_update(&self, channel_id: &ChannelId) {
 		let (outpoint, _, latest_update) = self.latest_monitor_update_id.lock().unwrap().get(channel_id).unwrap().clone();
 		self.chain_monitor.channel_monitor_updated(outpoint, latest_update).unwrap();
 	}

From 86d3143b0284b86617261929c4955faf52124dff Mon Sep 17 00:00:00 2001
From: optout <13562139+optout21@users.noreply.github.com>
Date: Tue, 25 Jul 2023 00:13:53 +0200
Subject: [PATCH 2/5] ChannelId, a wrapper type around [u8; 32]

---
 fuzz/src/router.rs                        |   2 +-
 lightning-invoice/src/utils.rs            |  18 +--
 lightning/src/chain/channelmonitor.rs     |   4 +-
 lightning/src/chain/transaction.rs        |   6 +-
 lightning/src/events/mod.rs               |  10 +-
 lightning/src/ln/channel.rs               | 124 +++++++++-------
 lightning/src/ln/channelmanager.rs        | 171 +++++++++++-----------
 lightning/src/ln/functional_test_utils.rs |  22 +--
 lightning/src/ln/functional_tests.rs      |  13 +-
 lightning/src/ln/msgs.rs                  |  63 ++++----
 lightning/src/ln/payment_tests.rs         |   6 +-
 lightning/src/ln/peer_handler.rs          |  57 ++++----
 lightning/src/routing/gossip.rs           |   5 +-
 lightning/src/routing/router.rs           |   6 +-
 lightning/src/util/macro_logger.rs        |   4 +-
 lightning/src/util/test_utils.rs          |   6 +-
 16 files changed, 274 insertions(+), 243 deletions(-)

diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs
index 31732257c3f..5fa505b5395 100644
--- a/fuzz/src/router.rs
+++ b/fuzz/src/router.rs
@@ -240,7 +240,7 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], out: Out) {
 							let rnid = node_pks.iter().skip(u16::from_be_bytes(get_slice!(2).try_into().unwrap()) as usize % node_pks.len()).next().unwrap();
 							let capacity = u64::from_be_bytes(get_slice!(8).try_into().unwrap());
 							first_hops_vec.push(ChannelDetails {
-								channel_id: [0; 32],
+								channel_id: ChannelId([0; 32]),
 								counterparty: ChannelCounterparty {
 									node_id: *rnid,
 									features: channelmanager::provided_init_features(&UserConfig::default()),
diff --git a/lightning-invoice/src/utils.rs b/lightning-invoice/src/utils.rs
index 25a7cf77d5e..a71d4867480 100644
--- a/lightning-invoice/src/utils.rs
+++ b/lightning-invoice/src/utils.rs
@@ -627,7 +627,7 @@ where
 	log_trace!(logger, "Considering {} channels for invoice route hints", channels.len());
 	for channel in channels.into_iter().filter(|chan| chan.is_channel_ready) {
 		if channel.get_inbound_payment_scid().is_none() || channel.counterparty.forwarding_info.is_none() {
-			log_trace!(logger, "Ignoring channel {} for invoice route hints", log_bytes!(channel.channel_id));
+			log_trace!(logger, "Ignoring channel {} for invoice route hints", log_bytes!(channel.channel_id.0));
 			continue;
 		}
 
@@ -641,7 +641,7 @@ where
 				// If any public channel exists, return no hints and let the sender
 				// look at the public channels instead.
 				log_trace!(logger, "Not including channels in invoice route hints on account of public channel {}",
-					log_bytes!(channel.channel_id));
+					log_bytes!(channel.channel_id.0));
 				return vec![].into_iter().take(MAX_CHANNEL_HINTS).map(route_hint_from_channel);
 			}
 		}
@@ -681,18 +681,18 @@ where
 					log_trace!(logger,
 						"Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints",
 						log_pubkey!(channel.counterparty.node_id),
-						log_bytes!(channel.channel_id), channel.short_channel_id,
+						log_bytes!(channel.channel_id.0), channel.short_channel_id,
 						channel.inbound_capacity_msat,
-						log_bytes!(entry.get().channel_id), entry.get().short_channel_id,
+						log_bytes!(entry.get().channel_id.0), entry.get().short_channel_id,
 						current_max_capacity);
 					entry.insert(channel);
 				} else {
 					log_trace!(logger,
 						"Preferring counterparty {} channel {} (SCID {:?}, {} msats) over {} (SCID {:?}, {} msats) for invoice route hints",
 						log_pubkey!(channel.counterparty.node_id),
-						log_bytes!(entry.get().channel_id), entry.get().short_channel_id,
+						log_bytes!(entry.get().channel_id.0), entry.get().short_channel_id,
 						current_max_capacity,
-						log_bytes!(channel.channel_id), channel.short_channel_id,
+						log_bytes!(channel.channel_id.0), channel.short_channel_id,
 						channel.inbound_capacity_msat);
 				}
 			}
@@ -731,14 +731,14 @@ where
 
 			if include_channel {
 				log_trace!(logger, "Including channel {} in invoice route hints",
-					log_bytes!(channel.channel_id));
+					log_bytes!(channel.channel_id.0));
 			} else if !has_enough_capacity {
 				log_trace!(logger, "Ignoring channel {} without enough capacity for invoice route hints",
-					log_bytes!(channel.channel_id));
+					log_bytes!(channel.channel_id.0));
 			} else {
 				debug_assert!(!channel.is_usable || (has_pub_unconf_chan && !channel.is_public));
 				log_trace!(logger, "Ignoring channel {} with disconnected peer",
-					log_bytes!(channel.channel_id));
+					log_bytes!(channel.channel_id.0));
 			}
 
 			include_channel
diff --git a/lightning/src/chain/channelmonitor.rs b/lightning/src/chain/channelmonitor.rs
index f98c0bcac8c..aa8cd5d58d9 100644
--- a/lightning/src/chain/channelmonitor.rs
+++ b/lightning/src/chain/channelmonitor.rs
@@ -2531,7 +2531,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
 						}
 					} else if !self.holder_tx_signed {
 						log_error!(logger, "WARNING: You have a potentially-unsafe holder commitment transaction available to broadcast");
-						log_error!(logger, "    in channel monitor for channel {}!", log_bytes!(self.funding_info.0.to_channel_id()));
+						log_error!(logger, "    in channel monitor for channel {}!", log_bytes!(self.funding_info.0.to_channel_id().0));
 						log_error!(logger, "    Read the docs for ChannelMonitor::get_latest_holder_commitment_txn and take manual action!");
 					} else {
 						// If we generated a MonitorEvent::CommitmentTxConfirmed, the ChannelManager
@@ -3189,7 +3189,7 @@ impl<Signer: WriteableEcdsaChannelSigner> ChannelMonitorImpl<Signer> {
 				if prevout.txid == self.funding_info.0.txid && prevout.vout == self.funding_info.0.index as u32 {
 					let mut balance_spendable_csv = None;
 					log_info!(logger, "Channel {} closed by funding output spend in txid {}.",
-						log_bytes!(self.funding_info.0.to_channel_id()), txid);
+						log_bytes!(self.funding_info.0.to_channel_id().0), txid);
 					self.funding_spend_seen = true;
 					let mut commitment_tx_to_counterparty_output = None;
 					if (tx.input[0].sequence.0 >> 8*3) as u8 == 0x80 && (tx.lock_time.0 >> 8*3) as u8 == 0x20 {
diff --git a/lightning/src/chain/transaction.rs b/lightning/src/chain/transaction.rs
index cd8ec4571fd..250e80160ef 100644
--- a/lightning/src/chain/transaction.rs
+++ b/lightning/src/chain/transaction.rs
@@ -63,7 +63,7 @@ impl OutPoint {
 		res[..].copy_from_slice(&self.txid[..]);
 		res[30] ^= ((self.index >> 8) & 0xff) as u8;
 		res[31] ^= ((self.index >> 0) & 0xff) as u8;
-		res
+		ChannelId(res)
 	}
 
 	/// Converts this OutPoint into the OutPoint field as used by rust-bitcoin
@@ -95,10 +95,10 @@ mod tests {
 		assert_eq!(&OutPoint {
 			txid: tx.txid(),
 			index: 0
-		}.to_channel_id(), &hex::decode("3e88dd7165faf7be58b3c5bb2c9c452aebef682807ea57080f62e6f6e113c25e").unwrap()[..]);
+		}.to_channel_id().0, &hex::decode("3e88dd7165faf7be58b3c5bb2c9c452aebef682807ea57080f62e6f6e113c25e").unwrap()[..]);
 		assert_eq!(&OutPoint {
 			txid: tx.txid(),
 			index: 1
-		}.to_channel_id(), &hex::decode("3e88dd7165faf7be58b3c5bb2c9c452aebef682807ea57080f62e6f6e113c25f").unwrap()[..]);
+		}.to_channel_id().0, &hex::decode("3e88dd7165faf7be58b3c5bb2c9c452aebef682807ea57080f62e6f6e113c25f").unwrap()[..]);
 	}
 }
diff --git a/lightning/src/events/mod.rs b/lightning/src/events/mod.rs
index b22bfb6a0b3..8d6bf6e9e5e 100644
--- a/lightning/src/events/mod.rs
+++ b/lightning/src/events/mod.rs
@@ -1248,7 +1248,7 @@ impl MaybeReadable for Event {
 			},
 			9u8 => {
 				let f = || {
-					let mut channel_id = [0; 32];
+					let mut channel_id = ChannelId([0; 32]);
 					let mut reason = UpgradableRequired(None);
 					let mut user_channel_id_low_opt: Option<u64> = None;
 					let mut user_channel_id_high_opt: Option<u64> = None;
@@ -1271,7 +1271,7 @@ impl MaybeReadable for Event {
 			},
 			11u8 => {
 				let f = || {
-					let mut channel_id = [0; 32];
+					let mut channel_id = ChannelId([0; 32]);
 					let mut transaction = Transaction{ version: 2, lock_time: PackedLockTime::ZERO, input: Vec::new(), output: Vec::new() };
 					read_tlv_fields!(reader, {
 						(0, channel_id, required),
@@ -1376,7 +1376,7 @@ impl MaybeReadable for Event {
 			},
 			25u8 => {
 				let f = || {
-					let mut prev_channel_id = [0; 32];
+					let mut prev_channel_id = ChannelId([0; 32]);
 					let mut failed_next_destination_opt = UpgradableRequired(None);
 					read_tlv_fields!(reader, {
 						(0, prev_channel_id, required),
@@ -1392,7 +1392,7 @@ impl MaybeReadable for Event {
 			27u8 => Ok(None),
 			29u8 => {
 				let f = || {
-					let mut channel_id = [0; 32];
+					let mut channel_id = ChannelId([0; 32]);
 					let mut user_channel_id: u128 = 0;
 					let mut counterparty_node_id = RequiredWrapper(None);
 					let mut channel_type = RequiredWrapper(None);
@@ -1414,7 +1414,7 @@ impl MaybeReadable for Event {
 			},
 			31u8 => {
 				let f = || {
-					let mut channel_id = [0; 32];
+					let mut channel_id = ChannelId([0; 32]);
 					let mut user_channel_id: u128 = 0;
 					let mut former_temporary_channel_id = None;
 					let mut counterparty_node_id = RequiredWrapper(None);
diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index bf0f32b170c..2f56e53b4e6 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -51,6 +51,7 @@ use core::ops::Deref;
 #[cfg(any(test, fuzzing, debug_assertions))]
 use crate::sync::Mutex;
 use bitcoin::hashes::hex::ToHex;
+use std::io::Read;
 
 #[cfg(test)]
 pub struct ChannelValueStat {
@@ -533,7 +534,7 @@ pub(super) struct ReestablishResponses {
 /// channel's counterparty_node_id and channel_id).
 pub(crate) type ShutdownResult = (
 	Option<(PublicKey, OutPoint, ChannelMonitorUpdate)>,
-	Vec<(HTLCSource, PaymentHash, PublicKey, [u8; 32])>
+	Vec<(HTLCSource, PaymentHash, PublicKey, ChannelId)>
 );
 
 /// If the majority of the channels funds are to the fundee and the initiator holds only just
@@ -603,8 +604,31 @@ impl_writeable_tlv_based!(PendingChannelMonitorUpdate, {
 	(0, update, required),
 });
 
-/// Channel ID is 32 bytes
-pub type ChannelId = [u8; 32];
+/// A unique 32-byte identifier for a channel.
+/// 
+/// This is not exported to bindings users as we just use [u8; 32] directly
+#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
+pub struct ChannelId(pub [u8; 32]);
+
+impl ChannelId {
+	pub fn serialized_length(&self) -> usize {
+		self.0.serialized_length()
+	}
+}
+
+impl Writeable for ChannelId {
+	fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+		self.0.write(w)
+	}
+}
+
+impl Readable for ChannelId {
+	fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+		let buf: [u8; 32] = Readable::read(r)?;
+		Ok(ChannelId(buf))
+	}
+}
+
 
 /// Contains all state common to unfunded inbound/outbound channels.
 pub(super) struct UnfundedChannelContext {
@@ -981,7 +1005,7 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
 	// Return the `temporary_channel_id` used during channel establishment.
 	//
 	// Will return `None` for channels created prior to LDK version 0.0.115.
-	pub fn temporary_channel_id(&self) -> Option<[u8; 32]> {
+	pub fn temporary_channel_id(&self) -> Option<ChannelId> {
 		self.temporary_channel_id
 	}
 
@@ -1248,7 +1272,7 @@ impl<Signer: ChannelSigner> ChannelContext<Signer> {
 		log_trace!(logger, "Building commitment transaction number {} (really {} xor {}) for channel {} for {}, generated by {} with fee {}...",
 			commitment_number, (INITIAL_COMMITMENT_NUMBER - commitment_number),
 			get_commitment_transaction_number_obscure_factor(&self.get_holder_pubkeys().payment_point, &self.get_counterparty_pubkeys().payment_point, self.is_outbound()),
-			log_bytes!(self.channel_id), if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw);
+			log_bytes!(self.channel_id.0), if local { "us" } else { "remote" }, if generated_by_local { "us" } else { "remote" }, feerate_per_kw);
 
 		macro_rules! get_htlc_in_commitment {
 			($htlc: expr, $offered: expr) => {
@@ -2244,7 +2268,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 					InboundHTLCState::LocalRemoved(ref reason) => {
 						if let &InboundHTLCRemovalReason::Fulfill(_) = reason {
 						} else {
-							log_warn!(logger, "Have preimage and want to fulfill HTLC with payment hash {} we already failed against channel {}", log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id()));
+							log_warn!(logger, "Have preimage and want to fulfill HTLC with payment hash {} we already failed against channel {}", log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id().0));
 							debug_assert!(false, "Tried to fulfill an HTLC that was already failed");
 						}
 						return UpdateFulfillFetch::DuplicateClaim {};
@@ -2297,7 +2321,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 					},
 					&HTLCUpdateAwaitingACK::FailHTLC { htlc_id, .. } => {
 						if htlc_id_arg == htlc_id {
-							log_warn!(logger, "Have preimage and want to fulfill HTLC with pending failure against channel {}", log_bytes!(self.context.channel_id()));
+							log_warn!(logger, "Have preimage and want to fulfill HTLC with pending failure against channel {}", log_bytes!(self.context.channel_id().0));
 							// TODO: We may actually be able to switch to a fulfill here, though its
 							// rare enough it may not be worth the complexity burden.
 							debug_assert!(false, "Tried to fulfill an HTLC that was already failed");
@@ -2307,7 +2331,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 					_ => {}
 				}
 			}
-			log_trace!(logger, "Adding HTLC claim to holding_cell in channel {}! Current state: {}", log_bytes!(self.context.channel_id()), self.context.channel_state);
+			log_trace!(logger, "Adding HTLC claim to holding_cell in channel {}! Current state: {}", log_bytes!(self.context.channel_id().0), self.context.channel_state);
 			self.context.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::ClaimHTLC {
 				payment_preimage: payment_preimage_arg, htlc_id: htlc_id_arg,
 			});
@@ -2325,7 +2349,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 				debug_assert!(false, "Have an inbound HTLC we tried to claim before it was fully committed to");
 				return UpdateFulfillFetch::NewClaim { monitor_update, htlc_value_msat, msg: None };
 			}
-			log_trace!(logger, "Upgrading HTLC {} to LocalRemoved with a Fulfill in channel {}!", log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id));
+			log_trace!(logger, "Upgrading HTLC {} to LocalRemoved with a Fulfill in channel {}!", log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id.0));
 			htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::Fulfill(payment_preimage_arg.clone()));
 		}
 
@@ -2464,7 +2488,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 					_ => {}
 				}
 			}
-			log_trace!(logger, "Placing failure for HTLC ID {} in holding cell in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id()));
+			log_trace!(logger, "Placing failure for HTLC ID {} in holding cell in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id().0));
 			self.context.holding_cell_htlc_updates.push(HTLCUpdateAwaitingACK::FailHTLC {
 				htlc_id: htlc_id_arg,
 				err_packet,
@@ -2472,7 +2496,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			return Ok(None);
 		}
 
-		log_trace!(logger, "Failing HTLC ID {} back with a update_fail_htlc message in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id()));
+		log_trace!(logger, "Failing HTLC ID {} back with a update_fail_htlc message in channel {}.", htlc_id_arg, log_bytes!(self.context.channel_id().0));
 		{
 			let htlc = &mut self.context.pending_inbound_htlcs[pending_idx];
 			htlc.state = InboundHTLCState::LocalRemoved(InboundHTLCRemovalReason::FailRelay(err_packet.clone()));
@@ -2516,7 +2540,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
 
 		log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
-			log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
+			log_bytes!(self.context.channel_id().0), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
 
 		let holder_signer = self.context.build_holder_transaction_keys(self.context.cur_holder_commitment_transaction_number);
 		let initial_commitment_tx = self.context.build_commitment_transaction(self.context.cur_holder_commitment_transaction_number, &holder_signer, true, false, logger).tx;
@@ -2564,7 +2588,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		self.context.cur_holder_commitment_transaction_number -= 1;
 		self.context.cur_counterparty_commitment_transaction_number -= 1;
 
-		log_info!(logger, "Received funding_signed from peer for channel {}", log_bytes!(self.context.channel_id()));
+		log_info!(logger, "Received funding_signed from peer for channel {}", log_bytes!(self.context.channel_id().0));
 
 		let need_channel_ready = self.check_get_channel_ready(0).is_some();
 		self.monitor_updating_paused(false, false, need_channel_ready, Vec::new(), Vec::new(), Vec::new());
@@ -2638,7 +2662,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		self.context.counterparty_prev_commitment_point = self.context.counterparty_cur_commitment_point;
 		self.context.counterparty_cur_commitment_point = Some(msg.next_per_commitment_point);
 
-		log_info!(logger, "Received channel_ready from peer for channel {}", log_bytes!(self.context.channel_id()));
+		log_info!(logger, "Received channel_ready from peer for channel {}", log_bytes!(self.context.channel_id().0));
 
 		Ok(self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, best_block.height(), logger))
 	}
@@ -2766,7 +2790,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			if pending_remote_value_msat - msg.amount_msat - self.context.holder_selected_channel_reserve_satoshis * 1000 < remote_fee_cost_incl_stuck_buffer_msat {
 				// Note that if the pending_forward_status is not updated here, then it's because we're already failing
 				// the HTLC, i.e. its status is already set to failing.
-				log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", log_bytes!(self.context.channel_id()));
+				log_info!(logger, "Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", log_bytes!(self.context.channel_id().0));
 				pending_forward_status = create_pending_htlc_status(self, pending_forward_status, 0x1000|7);
 			}
 		} else {
@@ -2894,7 +2918,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			log_trace!(logger, "Checking commitment tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}",
 				log_bytes!(msg.signature.serialize_compact()[..]),
 				log_bytes!(self.context.counterparty_funding_pubkey().serialize()), encode::serialize_hex(&bitcoin_tx.transaction),
-				log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id()));
+				log_bytes!(sighash[..]), encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id().0));
 			if let Err(_) = self.context.secp_ctx.verify_ecdsa(&sighash, &msg.signature, &self.context.counterparty_funding_pubkey()) {
 				return Err(ChannelError::Close("Invalid commitment tx signature from peer".to_owned()));
 			}
@@ -2964,7 +2988,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 				let htlc_sighash = hash_to_message!(&sighash::SighashCache::new(&htlc_tx).segwit_signature_hash(0, &htlc_redeemscript, htlc.amount_msat / 1000, htlc_sighashtype).unwrap()[..]);
 				log_trace!(logger, "Checking HTLC tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} in channel {}.",
 					log_bytes!(msg.htlc_signatures[idx].serialize_compact()[..]), log_bytes!(keys.countersignatory_htlc_key.serialize()),
-					encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), log_bytes!(self.context.channel_id()));
+					encode::serialize_hex(&htlc_tx), log_bytes!(htlc_sighash[..]), encode::serialize_hex(&htlc_redeemscript), log_bytes!(self.context.channel_id().0));
 				if let Err(_) = self.context.secp_ctx.verify_ecdsa(&htlc_sighash, &msg.htlc_signatures[idx], &keys.countersignatory_htlc_key) {
 					return Err(ChannelError::Close("Invalid HTLC tx signature from peer".to_owned()));
 				}
@@ -3008,7 +3032,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			} else { None };
 			if let Some(forward_info) = new_forward {
 				log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToAnnounce due to commitment_signed in channel {}.",
-					log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id));
+					log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id.0));
 				htlc.state = InboundHTLCState::AwaitingRemoteRevokeToAnnounce(forward_info);
 				need_commitment = true;
 			}
@@ -3017,7 +3041,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		for htlc in self.context.pending_outbound_htlcs.iter_mut() {
 			if let &mut OutboundHTLCState::RemoteRemoved(ref mut outcome) = &mut htlc.state {
 				log_trace!(logger, "Updating HTLC {} to AwaitingRemoteRevokeToRemove due to commitment_signed in channel {}.",
-					log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id));
+					log_bytes!(htlc.payment_hash.0), log_bytes!(self.context.channel_id.0));
 				// Grab the preimage, if it exists, instead of cloning
 				let mut reason = OutboundHTLCOutcome::Success(None);
 				mem::swap(outcome, &mut reason);
@@ -3067,7 +3091,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 				monitor_update.updates.append(&mut additional_update.updates);
 			}
 			log_debug!(logger, "Received valid commitment_signed from peer in channel {}, updated HTLC state but awaiting a monitor update resolution to reply.",
-				log_bytes!(self.context.channel_id));
+				log_bytes!(self.context.channel_id.0));
 			return Ok(self.push_ret_blockable_mon_update(monitor_update));
 		}
 
@@ -3084,7 +3108,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		} else { false };
 
 		log_debug!(logger, "Received valid commitment_signed from peer in channel {}, updating HTLC state and responding with{} a revoke_and_ack.",
-			log_bytes!(self.context.channel_id()), if need_commitment_signed { " our own commitment_signed and" } else { "" });
+			log_bytes!(self.context.channel_id().0), if need_commitment_signed { " our own commitment_signed and" } else { "" });
 		self.monitor_updating_paused(true, need_commitment_signed, false, Vec::new(), Vec::new(), Vec::new());
 		return Ok(self.push_ret_blockable_mon_update(monitor_update));
 	}
@@ -3113,7 +3137,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		assert_eq!(self.context.channel_state & ChannelState::MonitorUpdateInProgress as u32, 0);
 		if self.context.holding_cell_htlc_updates.len() != 0 || self.context.holding_cell_update_fee.is_some() {
 			log_trace!(logger, "Freeing holding cell with {} HTLC updates{} in channel {}", self.context.holding_cell_htlc_updates.len(),
-				if self.context.holding_cell_update_fee.is_some() { " and a fee update" } else { "" }, log_bytes!(self.context.channel_id()));
+				if self.context.holding_cell_update_fee.is_some() { " and a fee update" } else { "" }, log_bytes!(self.context.channel_id().0));
 
 			let mut monitor_update = ChannelMonitorUpdate {
 				update_id: self.context.latest_monitor_update_id + 1, // We don't increment this yet!
@@ -3145,7 +3169,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 								match e {
 									ChannelError::Ignore(ref msg) => {
 										log_info!(logger, "Failed to send HTLC with payment_hash {} due to {} in channel {}",
-											log_bytes!(payment_hash.0), msg, log_bytes!(self.context.channel_id()));
+											log_bytes!(payment_hash.0), msg, log_bytes!(self.context.channel_id().0));
 										// If we fail to send here, then this HTLC should
 										// be failed backwards. Failing to send here
 										// indicates that this HTLC may keep being put back
@@ -3210,7 +3234,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			monitor_update.updates.append(&mut additional_update.updates);
 
 			log_debug!(logger, "Freeing holding cell in channel {} resulted in {}{} HTLCs added, {} HTLCs fulfilled, and {} HTLCs failed.",
-				log_bytes!(self.context.channel_id()), if update_fee.is_some() { "a fee update, " } else { "" },
+				log_bytes!(self.context.channel_id().0), if update_fee.is_some() { "a fee update, " } else { "" },
 				update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len());
 
 			self.monitor_updating_paused(false, true, false, Vec::new(), Vec::new(), Vec::new());
@@ -3295,7 +3319,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			self.context.announcement_sigs_state = AnnouncementSigsState::PeerReceived;
 		}
 
-		log_trace!(logger, "Updating HTLCs on receipt of RAA in channel {}...", log_bytes!(self.context.channel_id()));
+		log_trace!(logger, "Updating HTLCs on receipt of RAA in channel {}...", log_bytes!(self.context.channel_id().0));
 		let mut to_forward_infos = Vec::new();
 		let mut revoked_htlcs = Vec::new();
 		let mut finalized_claimed_htlcs = Vec::new();
@@ -3424,7 +3448,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			self.context.monitor_pending_forwards.append(&mut to_forward_infos);
 			self.context.monitor_pending_failures.append(&mut revoked_htlcs);
 			self.context.monitor_pending_finalized_fulfills.append(&mut finalized_claimed_htlcs);
-			log_debug!(logger, "Received a valid revoke_and_ack for channel {} but awaiting a monitor update resolution to reply.", log_bytes!(self.context.channel_id()));
+			log_debug!(logger, "Received a valid revoke_and_ack for channel {} but awaiting a monitor update resolution to reply.", log_bytes!(self.context.channel_id().0));
 			return Ok((Vec::new(), self.push_ret_blockable_mon_update(monitor_update)));
 		}
 
@@ -3448,11 +3472,11 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 					monitor_update.updates.append(&mut additional_update.updates);
 
 					log_debug!(logger, "Received a valid revoke_and_ack for channel {}. Responding with a commitment update with {} HTLCs failed.",
-						log_bytes!(self.context.channel_id()), update_fail_htlcs.len() + update_fail_malformed_htlcs.len());
+						log_bytes!(self.context.channel_id().0), update_fail_htlcs.len() + update_fail_malformed_htlcs.len());
 					self.monitor_updating_paused(false, true, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs);
 					Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update)))
 				} else {
-					log_debug!(logger, "Received a valid revoke_and_ack for channel {} with no reply necessary.", log_bytes!(self.context.channel_id()));
+					log_debug!(logger, "Received a valid revoke_and_ack for channel {} with no reply necessary.", log_bytes!(self.context.channel_id().0));
 					self.monitor_updating_paused(false, false, false, to_forward_infos, revoked_htlcs, finalized_claimed_htlcs);
 					Ok((htlcs_to_fail, self.push_ret_blockable_mon_update(monitor_update)))
 				}
@@ -3613,7 +3637,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		self.context.sent_message_awaiting_response = None;
 
 		self.context.channel_state |= ChannelState::PeerDisconnected as u32;
-		log_trace!(logger, "Peer disconnection resulted in {} remote-announced HTLC drops on channel {}", inbound_drop_count, log_bytes!(self.context.channel_id()));
+		log_trace!(logger, "Peer disconnection resulted in {} remote-announced HTLC drops on channel {}", inbound_drop_count, log_bytes!(self.context.channel_id().0));
 	}
 
 	/// Indicates that a ChannelMonitor update is in progress and has not yet been fully persisted.
@@ -3716,7 +3740,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		self.context.monitor_pending_commitment_signed = false;
 		let order = self.context.resend_order.clone();
 		log_debug!(logger, "Restored monitor updating in channel {} resulting in {}{} commitment update and {} RAA, with {} first",
-			log_bytes!(self.context.channel_id()), if funding_broadcastable.is_some() { "a funding broadcastable, " } else { "" },
+			log_bytes!(self.context.channel_id().0), if funding_broadcastable.is_some() { "a funding broadcastable, " } else { "" },
 			if commitment_update.is_some() { "a" } else { "no" }, if raa.is_some() { "an" } else { "no" },
 			match order { RAACommitmentOrder::CommitmentFirst => "commitment", RAACommitmentOrder::RevokeAndACKFirst => "RAA"});
 		MonitorRestoreUpdates {
@@ -3828,7 +3852,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		} else { None };
 
 		log_trace!(logger, "Regenerated latest commitment update in channel {} with{} {} update_adds, {} update_fulfills, {} update_fails, and {} update_fail_malformeds",
-				log_bytes!(self.context.channel_id()), if update_fee.is_some() { " update_fee," } else { "" },
+				log_bytes!(self.context.channel_id().0), if update_fee.is_some() { " update_fee," } else { "" },
 				update_add_htlcs.len(), update_fulfill_htlcs.len(), update_fail_htlcs.len(), update_fail_malformed_htlcs.len());
 		msgs::CommitmentUpdate {
 			update_add_htlcs, update_fulfill_htlcs, update_fail_htlcs, update_fail_malformed_htlcs, update_fee,
@@ -3873,8 +3897,8 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			if msg.next_remote_commitment_number > INITIAL_COMMITMENT_NUMBER - self.context.cur_holder_commitment_transaction_number {
 				macro_rules! log_and_panic {
 					($err_msg: expr) => {
-						log_error!(logger, $err_msg, log_bytes!(self.context.channel_id), log_pubkey!(self.context.counterparty_node_id));
-						panic!($err_msg, log_bytes!(self.context.channel_id), log_pubkey!(self.context.counterparty_node_id));
+						log_error!(logger, $err_msg, log_bytes!(self.context.channel_id.0), log_pubkey!(self.context.counterparty_node_id));
+						panic!($err_msg, log_bytes!(self.context.channel_id.0), log_pubkey!(self.context.counterparty_node_id));
 					}
 				}
 				log_and_panic!("We have fallen behind - we have received proof that if we broadcast our counterparty is going to claim all our funds.\n\
@@ -3979,9 +4003,9 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 
 		if msg.next_local_commitment_number == next_counterparty_commitment_number {
 			if required_revoke.is_some() {
-				log_debug!(logger, "Reconnected channel {} with only lost outbound RAA", log_bytes!(self.context.channel_id()));
+				log_debug!(logger, "Reconnected channel {} with only lost outbound RAA", log_bytes!(self.context.channel_id().0));
 			} else {
-				log_debug!(logger, "Reconnected channel {} with no loss", log_bytes!(self.context.channel_id()));
+				log_debug!(logger, "Reconnected channel {} with no loss", log_bytes!(self.context.channel_id().0));
 			}
 
 			Ok(ReestablishResponses {
@@ -3992,9 +4016,9 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			})
 		} else if msg.next_local_commitment_number == next_counterparty_commitment_number - 1 {
 			if required_revoke.is_some() {
-				log_debug!(logger, "Reconnected channel {} with lost outbound RAA and lost remote commitment tx", log_bytes!(self.context.channel_id()));
+				log_debug!(logger, "Reconnected channel {} with lost outbound RAA and lost remote commitment tx", log_bytes!(self.context.channel_id().0));
 			} else {
-				log_debug!(logger, "Reconnected channel {} with only lost remote commitment tx", log_bytes!(self.context.channel_id()));
+				log_debug!(logger, "Reconnected channel {} with only lost remote commitment tx", log_bytes!(self.context.channel_id().0));
 			}
 
 			if self.context.channel_state & (ChannelState::MonitorUpdateInProgress as u32) != 0 {
@@ -4728,14 +4752,14 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 					// send it immediately instead of waiting for a best_block_updated call (which
 					// may have already happened for this block).
 					if let Some(channel_ready) = self.check_get_channel_ready(height) {
-						log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.context.channel_id));
+						log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.context.channel_id.0));
 						let announcement_sigs = self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger);
 						return Ok((Some(channel_ready), announcement_sigs));
 					}
 				}
 				for inp in tx.input.iter() {
 					if inp.previous_output == funding_txo.into_bitcoin_outpoint() {
-						log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.context.channel_id()));
+						log_info!(logger, "Detected channel-closing tx {} spending {}:{}, closing channel {}", tx.txid(), inp.previous_output.txid, inp.previous_output.vout, log_bytes!(self.context.channel_id().0));
 						return Err(ClosureReason::CommitmentTxConfirmed);
 					}
 				}
@@ -4797,7 +4821,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			let announcement_sigs = if let Some((genesis_block_hash, node_signer, user_config)) = genesis_node_signer {
 				self.get_announcement_sigs(node_signer, genesis_block_hash, user_config, height, logger)
 			} else { None };
-			log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.context.channel_id));
+			log_info!(logger, "Sending a channel_ready to our peer for channel {}", log_bytes!(self.context.channel_id.0));
 			return Ok((Some(channel_ready), timed_out_htlcs, announcement_sigs));
 		}
 
@@ -4828,7 +4852,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			}
 		} else if !self.context.is_outbound() && self.context.funding_tx_confirmed_in.is_none() &&
 				height >= self.context.channel_creation_height + FUNDING_CONF_DEADLINE_BLOCKS {
-			log_info!(logger, "Closing channel {} due to funding timeout", log_bytes!(self.context.channel_id));
+			log_info!(logger, "Closing channel {} due to funding timeout", log_bytes!(self.context.channel_id.0));
 			// If funding_tx_confirmed_in is unset, the channel must not be active
 			assert!(non_shutdown_state <= ChannelState::ChannelReady as u32);
 			assert_eq!(non_shutdown_state & ChannelState::OurChannelReady as u32, 0);
@@ -4936,7 +4960,7 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			return None;
 		}
 
-		log_trace!(logger, "Creating an announcement_signatures message for channel {}", log_bytes!(self.context.channel_id()));
+		log_trace!(logger, "Creating an announcement_signatures message for channel {}", log_bytes!(self.context.channel_id().0));
 		let announcement = match self.get_channel_announcement(node_signer, genesis_block_hash, user_config) {
 			Ok(a) => a,
 			Err(e) => {
@@ -5063,10 +5087,10 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 		let dummy_pubkey = PublicKey::from_slice(&pk).unwrap();
 		let remote_last_secret = if self.context.cur_counterparty_commitment_transaction_number + 1 < INITIAL_COMMITMENT_NUMBER {
 			let remote_last_secret = self.context.commitment_secrets.get_secret(self.context.cur_counterparty_commitment_transaction_number + 2).unwrap();
-			log_trace!(logger, "Enough info to generate a Data Loss Protect with per_commitment_secret {} for channel {}", log_bytes!(remote_last_secret), log_bytes!(self.context.channel_id()));
+			log_trace!(logger, "Enough info to generate a Data Loss Protect with per_commitment_secret {} for channel {}", log_bytes!(remote_last_secret), log_bytes!(self.context.channel_id().0));
 			remote_last_secret
 		} else {
-			log_info!(logger, "Sending a data_loss_protect with no previous remote per_commitment_secret for channel {}", log_bytes!(self.context.channel_id()));
+			log_info!(logger, "Sending a data_loss_protect with no previous remote per_commitment_secret for channel {}", log_bytes!(self.context.channel_id().0));
 			[0;32]
 		};
 		self.mark_awaiting_response();
@@ -5335,14 +5359,14 @@ impl<Signer: WriteableEcdsaChannelSigner> Channel<Signer> {
 			log_trace!(logger, "Signed remote commitment tx {} (txid {}) with redeemscript {} -> {} in channel {}",
 				encode::serialize_hex(&commitment_stats.tx.trust().built_transaction().transaction),
 				&counterparty_commitment_txid, encode::serialize_hex(&self.context.get_funding_redeemscript()),
-				log_bytes!(signature.serialize_compact()[..]), log_bytes!(self.context.channel_id()));
+				log_bytes!(signature.serialize_compact()[..]), log_bytes!(self.context.channel_id().0));
 
 			for (ref htlc_sig, ref htlc) in htlc_signatures.iter().zip(htlcs) {
 				log_trace!(logger, "Signed remote HTLC tx {} with redeemscript {} with pubkey {} -> {} in channel {}",
 					encode::serialize_hex(&chan_utils::build_htlc_transaction(&counterparty_commitment_txid, commitment_stats.feerate_per_kw, self.context.get_holder_selected_contest_delay(), htlc, &self.context.channel_type, &counterparty_keys.broadcaster_delayed_payment_key, &counterparty_keys.revocation_key)),
 					encode::serialize_hex(&chan_utils::get_htlc_redeemscript(&htlc, &self.context.channel_type, &counterparty_keys)),
 					log_bytes!(counterparty_keys.broadcaster_htlc_key.serialize()),
-					log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.context.channel_id()));
+					log_bytes!(htlc_sig.serialize_compact()[..]), log_bytes!(self.context.channel_id().0));
 			}
 		}
 
@@ -5589,7 +5613,7 @@ impl<Signer: WriteableEcdsaChannelSigner> OutboundV1Channel<Signer> {
 			Err(_) => return Err(APIError::ChannelUnavailable { err: "Failed to get destination script".to_owned()}),
 		};
 
-		let temporary_channel_id = entropy_source.get_secure_random_bytes();
+		let temporary_channel_id = ChannelId(entropy_source.get_secure_random_bytes());
 
 		Ok(Self {
 			context: ChannelContext {
@@ -6447,7 +6471,7 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
 			log_trace!(logger, "Checking funding_created tx signature {} by key {} against tx {} (sighash {}) with redeemscript {} for channel {}.",
 				log_bytes!(sig.serialize_compact()[..]), log_bytes!(self.context.counterparty_funding_pubkey().serialize()),
 				encode::serialize_hex(&initial_commitment_bitcoin_tx.transaction), log_bytes!(sighash[..]),
-				encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id()));
+				encode::serialize_hex(&funding_script), log_bytes!(self.context.channel_id().0));
 			secp_check!(self.context.secp_ctx.verify_ecdsa(&sighash, &sig, self.context.counterparty_funding_pubkey()), "Invalid funding_created signature from peer".to_owned());
 		}
 
@@ -6457,7 +6481,7 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
 		let counterparty_trusted_tx = counterparty_initial_commitment_tx.trust();
 		let counterparty_initial_bitcoin_tx = counterparty_trusted_tx.built_transaction();
 		log_trace!(logger, "Initial counterparty tx for channel {} is: txid {} tx {}",
-			log_bytes!(self.context.channel_id()), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
+			log_bytes!(self.context.channel_id().0), counterparty_initial_bitcoin_tx.txid, encode::serialize_hex(&counterparty_initial_bitcoin_tx.transaction));
 
 		let counterparty_signature = self.context.holder_signer.sign_counterparty_commitment(&counterparty_initial_commitment_tx, Vec::new(), &self.context.secp_ctx)
 				.map_err(|_| ChannelError::Close("Failed to get signatures for new commitment_signed".to_owned()))?.0;
@@ -6545,7 +6569,7 @@ impl<Signer: WriteableEcdsaChannelSigner> InboundV1Channel<Signer> {
 		self.context.cur_counterparty_commitment_transaction_number -= 1;
 		self.context.cur_holder_commitment_transaction_number -= 1;
 
-		log_info!(logger, "Generated funding_signed for peer for channel {}", log_bytes!(self.context.channel_id()));
+		log_info!(logger, "Generated funding_signed for peer for channel {}", log_bytes!(self.context.channel_id().0));
 
 		// Promote the channel to a full-fledged one now that we have updated the state and have a
 		// `ChannelMonitor`.
diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index 6c1ff584bbd..efd846f59d7 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -374,7 +374,7 @@ pub enum FailureCode {
 
 struct MsgHandleErrInternal {
 	err: msgs::LightningError,
-	chan_id: Option<([u8; 32], u128)>, // If Some a channel of ours has been closed
+	chan_id: Option<(ChannelId, u128)>, // If Some a channel of ours has been closed
 	shutdown_finish: Option<(ShutdownResult, Option<msgs::ChannelUpdate>)>,
 }
 impl MsgHandleErrInternal {
@@ -535,7 +535,7 @@ enum BackgroundEvent {
 	/// on a channel.
 	MonitorUpdatesComplete {
 		counterparty_node_id: PublicKey,
-		channel_id: [u8; 32],
+		channel_id: ChannelId,
 	},
 }
 
@@ -622,19 +622,19 @@ pub(super) struct PeerState<Signer: ChannelSigner> {
 	/// `channel_id` -> `Channel`.
 	///
 	/// Holds all funded channels where the peer is the counterparty.
-	pub(super) channel_by_id: HashMap<[u8; 32], Channel<Signer>>,
+	pub(super) channel_by_id: HashMap<ChannelId, Channel<Signer>>,
 	/// `temporary_channel_id` -> `OutboundV1Channel`.
 	///
 	/// Holds all outbound V1 channels where the peer is the counterparty. Once an outbound channel has
 	/// been assigned a `channel_id`, the entry in this map is removed and one is created in
 	/// `channel_by_id`.
-	pub(super) outbound_v1_channel_by_id: HashMap<[u8; 32], OutboundV1Channel<Signer>>,
+	pub(super) outbound_v1_channel_by_id: HashMap<ChannelId, OutboundV1Channel<Signer>>,
 	/// `temporary_channel_id` -> `InboundV1Channel`.
 	///
 	/// Holds all inbound V1 channels where the peer is the counterparty. Once an inbound channel has
 	/// been assigned a `channel_id`, the entry in this map is removed and one is created in
 	/// `channel_by_id`.
-	pub(super) inbound_v1_channel_by_id: HashMap<[u8; 32], InboundV1Channel<Signer>>,
+	pub(super) inbound_v1_channel_by_id: HashMap<ChannelId, InboundV1Channel<Signer>>,
 	/// The latest `InitFeatures` we heard from the peer.
 	latest_features: InitFeatures,
 	/// Messages to send to the peer - pushed to in the same lock that they are generated in (except
@@ -661,12 +661,12 @@ pub(super) struct PeerState<Signer: ChannelSigner> {
 	/// same `temporary_channel_id` (or final `channel_id` in the case of 0conf channels or prior
 	/// to funding appearing on-chain), the downstream `ChannelMonitor` set is required to ensure
 	/// duplicates do not occur, so such channels should fail without a monitor update completing.
-	monitor_update_blocked_actions: BTreeMap<[u8; 32], Vec<MonitorUpdateCompletionAction>>,
+	monitor_update_blocked_actions: BTreeMap<ChannelId, Vec<MonitorUpdateCompletionAction>>,
 	/// If another channel's [`ChannelMonitorUpdate`] needs to complete before a channel we have
 	/// with this peer can complete an RAA [`ChannelMonitorUpdate`] (e.g. because the RAA update
 	/// will remove a preimage that needs to be durably in an upstream channel first), we put an
 	/// entry here to note that the channel with the key's ID is blocked on a set of actions.
-	actions_blocking_raa_monitor_updates: BTreeMap<[u8; 32], Vec<RAAMonitorUpdateBlockingAction>>,
+	actions_blocking_raa_monitor_updates: BTreeMap<ChannelId, Vec<RAAMonitorUpdateBlockingAction>>,
 	/// The peer is currently connected (i.e. we've seen a
 	/// [`ChannelMessageHandler::peer_connected`] and no corresponding
 	/// [`ChannelMessageHandler::peer_disconnected`].
@@ -694,9 +694,9 @@ impl <Signer: ChannelSigner> PeerState<Signer> {
 
 	// Returns a bool indicating if the given `channel_id` matches a channel we have with this peer.
 	fn has_channel(&self, channel_id: &ChannelId) -> bool {
-		self.channel_by_id.contains_key(channel_id) ||
-			self.outbound_v1_channel_by_id.contains_key(channel_id) ||
-			self.inbound_v1_channel_by_id.contains_key(channel_id)
+		self.channel_by_id.contains_key(&channel_id) ||
+			self.outbound_v1_channel_by_id.contains_key(&channel_id) ||
+			self.inbound_v1_channel_by_id.contains_key(&channel_id)
 	}
 }
 
@@ -1030,7 +1030,7 @@ where
 	/// required to access the channel with the `counterparty_node_id`.
 	///
 	/// See `ChannelManager` struct-level documentation for lock order requirements.
-	id_to_peer: Mutex<HashMap<[u8; 32], PublicKey>>,
+	id_to_peer: Mutex<HashMap<ChannelId, PublicKey>>,
 
 	/// SCIDs (and outbound SCID aliases) -> `counterparty_node_id`s and `channel_id`s.
 	///
@@ -1044,9 +1044,9 @@ where
 	///
 	/// See `ChannelManager` struct-level documentation for lock order requirements.
 	#[cfg(test)]
-	pub(super) short_to_chan_info: FairRwLock<HashMap<u64, (PublicKey, [u8; 32])>>,
+	pub(super) short_to_chan_info: FairRwLock<HashMap<u64, (PublicKey, ChannelId)>>,
 	#[cfg(not(test))]
-	short_to_chan_info: FairRwLock<HashMap<u64, (PublicKey, [u8; 32])>>,
+	short_to_chan_info: FairRwLock<HashMap<u64, (PublicKey, ChannelId)>>,
 
 	our_network_pubkey: PublicKey,
 
@@ -1741,7 +1741,7 @@ macro_rules! convert_chan_err {
 				(false, MsgHandleErrInternal::from_chan_no_close(ChannelError::Ignore(msg), $channel_id.clone()))
 			},
 			ChannelError::Close(msg) => {
-				log_error!($self.logger, "Closing channel {} due to close-required error: {}", log_bytes!($channel_id[..]), msg);
+				log_error!($self.logger, "Closing channel {} due to close-required error: {}", log_bytes!($channel_id.0[..]), msg);
 				update_maps_on_chan_removal!($self, &$channel.context);
 				let shutdown_res = $channel.context.force_shutdown(true);
 				(true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel.context.get_user_id(),
@@ -1754,7 +1754,7 @@ macro_rules! convert_chan_err {
 			// We should only ever have `ChannelError::Close` when unfunded channels error.
 			// In any case, just close the channel.
 			ChannelError::Warn(msg) | ChannelError::Ignore(msg) | ChannelError::Close(msg) => {
-				log_error!($self.logger, "Closing unfunded channel {} due to an error: {}", log_bytes!($channel_id[..]), msg);
+				log_error!($self.logger, "Closing unfunded channel {} due to an error: {}", log_bytes!($channel_id.0[..]), msg);
 				update_maps_on_chan_removal!($self, &$channel_context);
 				let shutdown_res = $channel_context.force_shutdown(false);
 				(true, MsgHandleErrInternal::from_finish_shutdown(msg, *$channel_id, $channel_context.get_user_id(),
@@ -1927,12 +1927,12 @@ macro_rules! handle_new_monitor_update {
 		match $update_res {
 			ChannelMonitorUpdateStatus::InProgress => {
 				log_debug!($self.logger, "ChannelMonitor update for {} in flight, holding messages until the update completes.",
-					log_bytes!($chan.context.channel_id()[..]));
+					log_bytes!($chan.context.channel_id().0[..]));
 				Ok(false)
 			},
 			ChannelMonitorUpdateStatus::PermanentFailure => {
 				log_error!($self.logger, "Closing channel {} due to monitor update ChannelMonitorUpdateStatus::PermanentFailure",
-					log_bytes!($chan.context.channel_id()[..]));
+					log_bytes!($chan.context.channel_id().0[..]));
 				update_maps_on_chan_removal!($self, &$chan.context);
 				let res = Err(MsgHandleErrInternal::from_finish_shutdown(
 					"ChannelMonitor storage failure".to_owned(), $chan.context.channel_id(),
@@ -2181,7 +2181,7 @@ where
 	/// [`Event::FundingGenerationReady::user_channel_id`]: events::Event::FundingGenerationReady::user_channel_id
 	/// [`Event::FundingGenerationReady::temporary_channel_id`]: events::Event::FundingGenerationReady::temporary_channel_id
 	/// [`Event::ChannelClosed::channel_id`]: events::Event::ChannelClosed::channel_id
-	pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, override_config: Option<UserConfig>) -> Result<[u8; 32], APIError> {
+	pub fn create_channel(&self, their_network_key: PublicKey, channel_value_satoshis: u64, push_msat: u64, user_channel_id: u128, override_config: Option<UserConfig>) -> Result<ChannelId, APIError> {
 		if channel_value_satoshis < 1000 {
 			return Err(APIError::APIMisuseError { err: format!("Channel value must be at least 1000 satoshis. It was {}", channel_value_satoshis) });
 		}
@@ -2232,7 +2232,7 @@ where
 		Ok(temporary_channel_id)
 	}
 
-	fn list_funded_channels_with_filter<Fn: FnMut(&(&[u8; 32], &Channel<<SP::Target as SignerProvider>::Signer>)) -> bool + Copy>(&self, f: Fn) -> Vec<ChannelDetails> {
+	fn list_funded_channels_with_filter<Fn: FnMut(&(&ChannelId, &Channel<<SP::Target as SignerProvider>::Signer>)) -> bool + Copy>(&self, f: Fn) -> Vec<ChannelDetails> {
 		// Allocate our best estimate of the number of channels we have in the `res`
 		// Vec. Sadly the `short_to_chan_info` map doesn't cover channels without
 		// a scid or a scid alias, and the `id_to_peer` shouldn't be used outside
@@ -2540,27 +2540,27 @@ where
 				ClosureReason::HolderForceClosed
 			};
 			if let hash_map::Entry::Occupied(chan) = peer_state.channel_by_id.entry(channel_id.clone()) {
-				log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id[..]));
+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id.0[..]));
 				self.issue_channel_close_events(&chan.get().context, closure_reason);
 				let mut chan = remove_channel!(self, chan);
 				self.finish_force_close_channel(chan.context.force_shutdown(broadcast));
 				(self.get_channel_update_for_broadcast(&chan).ok(), chan.context.get_counterparty_node_id())
 			} else if let hash_map::Entry::Occupied(chan) = peer_state.outbound_v1_channel_by_id.entry(channel_id.clone()) {
-				log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id[..]));
+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id.0[..]));
 				self.issue_channel_close_events(&chan.get().context, closure_reason);
 				let mut chan = remove_channel!(self, chan);
 				self.finish_force_close_channel(chan.context.force_shutdown(false));
 				// Unfunded channel has no update
 				(None, chan.context.get_counterparty_node_id())
 			} else if let hash_map::Entry::Occupied(chan) = peer_state.inbound_v1_channel_by_id.entry(channel_id.clone()) {
-				log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id[..]));
+				log_error!(self.logger, "Force-closing channel {}", log_bytes!(channel_id.0[..]));
 				self.issue_channel_close_events(&chan.get().context, closure_reason);
 				let mut chan = remove_channel!(self, chan);
 				self.finish_force_close_channel(chan.context.force_shutdown(false));
 				// Unfunded channel has no update
 				(None, chan.context.get_counterparty_node_id())
 			} else {
-				return Err(APIError::ChannelUnavailable{ err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*channel_id), peer_node_id) });
+				return Err(APIError::ChannelUnavailable{ err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!((*channel_id).0), peer_node_id) });
 			}
 		};
 		if let Some(update) = update_opt {
@@ -3034,7 +3034,7 @@ where
 		if chan.context.get_short_channel_id().is_none() {
 			return Err(LightningError{err: "Channel not yet established".to_owned(), action: msgs::ErrorAction::IgnoreError});
 		}
-		log_trace!(self.logger, "Attempting to generate broadcast channel update for channel {}", log_bytes!(chan.context.channel_id()));
+		log_trace!(self.logger, "Attempting to generate broadcast channel update for channel {}", log_bytes!(chan.context.channel_id().0));
 		self.get_channel_update_for_unicast(chan)
 	}
 
@@ -3050,7 +3050,7 @@ where
 	/// [`channel_update`]: msgs::ChannelUpdate
 	/// [`internal_closing_signed`]: Self::internal_closing_signed
 	fn get_channel_update_for_unicast(&self, chan: &Channel<<SP::Target as SignerProvider>::Signer>) -> Result<msgs::ChannelUpdate, LightningError> {
-		log_trace!(self.logger, "Attempting to generate channel update for channel {}", log_bytes!(chan.context.channel_id()));
+		log_trace!(self.logger, "Attempting to generate channel update for channel {}", log_bytes!(chan.context.channel_id().0));
 		let short_channel_id = match chan.context.get_short_channel_id().or(chan.context.latest_inbound_scid_alias()) {
 			None => return Err(LightningError{err: "Channel not yet established".to_owned(), action: msgs::ErrorAction::IgnoreError}),
 			Some(id) => id,
@@ -3060,7 +3060,7 @@ where
 	}
 
 	fn get_channel_update_for_onion(&self, short_channel_id: u64, chan: &Channel<<SP::Target as SignerProvider>::Signer>) -> Result<msgs::ChannelUpdate, LightningError> {
-		log_trace!(self.logger, "Generating channel update for channel {}", log_bytes!(chan.context.channel_id()));
+		log_trace!(self.logger, "Generating channel update for channel {}", log_bytes!(chan.context.channel_id().0));
 		let were_node_one = self.our_network_pubkey.serialize()[..] < chan.context.get_counterparty_node_id().serialize()[..];
 
 		let enabled = chan.context.is_usable() && match chan.channel_update_status() {
@@ -3361,7 +3361,7 @@ where
 
 		let mut peer_state_lock = peer_state_mutex.lock().unwrap();
 		let peer_state = &mut *peer_state_lock;
-		let (chan, msg) = match peer_state.outbound_v1_channel_by_id.remove(temporary_channel_id) {
+		let (chan, msg) = match peer_state.outbound_v1_channel_by_id.remove(&temporary_channel_id) {
 			Some(chan) => {
 				let funding_txo = find_funding_output(&chan, &funding_transaction)?;
 
@@ -3389,7 +3389,7 @@ where
 				return Err(APIError::ChannelUnavailable {
 					err: format!(
 						"Channel with id {} not found for the passed counterparty node_id {}",
-						log_bytes!(*temporary_channel_id), counterparty_node_id),
+						log_bytes!((*temporary_channel_id).0), counterparty_node_id),
 				})
 			},
 		};
@@ -3523,7 +3523,7 @@ where
 	/// [`ChannelUnavailable`]: APIError::ChannelUnavailable
 	/// [`APIMisuseError`]: APIError::APIMisuseError
 	pub fn update_partial_channel_config(
-		&self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config_update: &ChannelConfigUpdate,
+		&self, counterparty_node_id: &PublicKey, channel_ids: &[ChannelId], config_update: &ChannelConfigUpdate,
 	) -> Result<(), APIError> {
 		if config_update.cltv_expiry_delta.map(|delta| delta < MIN_CLTV_EXPIRY_DELTA).unwrap_or(false) {
 			return Err(APIError::APIMisuseError {
@@ -3540,7 +3540,7 @@ where
 		for channel_id in channel_ids {
 			if !peer_state.has_channel(channel_id) {
 				return Err(APIError::ChannelUnavailable {
-					err: format!("Channel with ID {} was not found for the passed counterparty_node_id {}", log_bytes!(*channel_id), counterparty_node_id),
+					err: format!("Channel with ID {} was not found for the passed counterparty_node_id {}", log_bytes!((*channel_id).0), counterparty_node_id),
 				});
 			};
 		}
@@ -3572,7 +3572,7 @@ where
 				return Err(APIError::ChannelUnavailable {
 					err: format!(
 						"Channel with ID {} for passed counterparty_node_id {} disappeared after we confirmed its existence - this should not be reachable!",
-						log_bytes!(*channel_id), counterparty_node_id),
+						log_bytes!((*channel_id).0), counterparty_node_id),
 				});
 			};
 			let mut config = context.config();
@@ -3607,7 +3607,7 @@ where
 	/// [`ChannelUnavailable`]: APIError::ChannelUnavailable
 	/// [`APIMisuseError`]: APIError::APIMisuseError
 	pub fn update_channel_config(
-		&self, counterparty_node_id: &PublicKey, channel_ids: &[[u8; 32]], config: &ChannelConfig,
+		&self, counterparty_node_id: &PublicKey, channel_ids: &[ChannelId], config: &ChannelConfig,
 	) -> Result<(), APIError> {
 		return self.update_partial_channel_config(counterparty_node_id, channel_ids, &(*config).into());
 	}
@@ -3646,18 +3646,18 @@ where
 				.ok_or_else(|| APIError::ChannelUnavailable { err: format!("Can't find a peer matching the passed counterparty node_id {}", next_node_id) })?;
 			let mut peer_state_lock = peer_state_mutex.lock().unwrap();
 			let peer_state = &mut *peer_state_lock;
-			match peer_state.channel_by_id.get(next_hop_channel_id) {
+			match peer_state.channel_by_id.get(&next_hop_channel_id) {
 				Some(chan) => {
 					if !chan.context.is_usable() {
 						return Err(APIError::ChannelUnavailable {
-							err: format!("Channel with id {} not fully established", log_bytes!(*next_hop_channel_id))
+							err: format!("Channel with id {} not fully established", log_bytes!((*next_hop_channel_id).0))
 						})
 					}
 					chan.context.get_short_channel_id().unwrap_or(chan.context.outbound_scid_alias())
 				},
 				None => return Err(APIError::ChannelUnavailable {
 					err: format!("Funded channel with id {} not found for the passed counterparty node_id {}. Channel may still be opening.",
-						log_bytes!(*next_hop_channel_id), next_node_id)
+						log_bytes!((*next_hop_channel_id).0), next_node_id)
 				})
 			}
 		};
@@ -4265,21 +4265,21 @@ where
 		let _ = self.process_background_events();
 	}
 
-	fn update_channel_fee(&self, chan_id: &[u8; 32], chan: &mut Channel<<SP::Target as SignerProvider>::Signer>, new_feerate: u32) -> NotifyOption {
+	fn update_channel_fee(&self, chan_id: &ChannelId, chan: &mut Channel<<SP::Target as SignerProvider>::Signer>, new_feerate: u32) -> NotifyOption {
 		if !chan.context.is_outbound() { return NotifyOption::SkipPersist; }
 		// If the feerate has decreased by less than half, don't bother
 		if new_feerate <= chan.context.get_feerate_sat_per_1000_weight() && new_feerate * 2 > chan.context.get_feerate_sat_per_1000_weight() {
 			log_trace!(self.logger, "Channel {} does not qualify for a feerate change from {} to {}.",
-				log_bytes!(chan_id[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
+				log_bytes!(chan_id.0[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
 			return NotifyOption::SkipPersist;
 		}
 		if !chan.context.is_live() {
 			log_trace!(self.logger, "Channel {} does not qualify for a feerate change from {} to {} as it cannot currently be updated (probably the peer is disconnected).",
-				log_bytes!(chan_id[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
+				log_bytes!(chan_id.0[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
 			return NotifyOption::SkipPersist;
 		}
 		log_trace!(self.logger, "Channel {} qualifies for a feerate change from {} to {}.",
-			log_bytes!(chan_id[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
+			log_bytes!(chan_id.0[..]), chan.context.get_feerate_sat_per_1000_weight(), new_feerate);
 
 		chan.queue_update_fee(new_feerate, &self.fee_estimator, &self.logger);
 		NotifyOption::DoPersist
@@ -4407,7 +4407,7 @@ where
 
 						if chan.should_disconnect_peer_awaiting_response() {
 							log_debug!(self.logger, "Disconnecting peer {} due to not making any progress on channel {}",
-									counterparty_node_id, log_bytes!(*chan_id));
+									counterparty_node_id, log_bytes!((*chan_id).0));
 							pending_msg_events.push(MessageSendEvent::HandleError {
 								node_id: counterparty_node_id,
 								action: msgs::ErrorAction::DisconnectPeerWithWarning {
@@ -4423,13 +4423,13 @@ where
 					});
 
 					let process_unfunded_channel_tick = |
-						chan_id: &[u8; 32],
+						chan_id: &ChannelId,
 						chan_context: &mut ChannelContext<<SP::Target as SignerProvider>::Signer>,
 						unfunded_chan_context: &mut UnfundedChannelContext,
 					| {
 						chan_context.maybe_expire_prev_config();
 						if unfunded_chan_context.should_expire_unfunded_channel() {
-							log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id[..]));
+							log_error!(self.logger, "Force-closing pending outbound channel {} for not establishing in a timely manner", log_bytes!(&chan_id.0[..]));
 							update_maps_on_chan_removal!(self, &chan_context);
 							self.issue_channel_close_events(&chan_context, ClosureReason::HolderForceClosed);
 							self.finish_force_close_channel(chan_context.force_shutdown(false));
@@ -4859,7 +4859,7 @@ where
 					if let UpdateFulfillCommitFetch::NewClaim { htlc_value_msat, monitor_update } = fulfill_res {
 						if let Some(action) = completion_action(Some(htlc_value_msat)) {
 							log_trace!(self.logger, "Tracking monitor update completion action for channel {}: {:?}",
-								log_bytes!(chan_id), action);
+								log_bytes!(chan_id.0), action);
 							peer_state.monitor_update_blocked_actions.entry(chan_id).or_insert(Vec::new()).push(action);
 						}
 						if !during_init {
@@ -5009,7 +5009,7 @@ where
 		channel_ready: Option<msgs::ChannelReady>, announcement_sigs: Option<msgs::AnnouncementSignatures>)
 	-> Option<(u64, OutPoint, u128, Vec<(PendingHTLCInfo, u64)>)> {
 		log_trace!(self.logger, "Handling channel resumption for channel {} with {} RAA, {} commitment update, {} pending forwards, {}broadcasting funding, {} channel ready, {} announcement",
-			log_bytes!(channel.context.channel_id()),
+			log_bytes!(channel.context.channel_id().0),
 			if raa.is_some() { "an" } else { "no" },
 			if commitment_update.is_some() { "a" } else { "no" }, pending_forwards.len(),
 			if funding_broadcastable.is_some() { "" } else { "not " },
@@ -5214,7 +5214,7 @@ where
 				});
 			}
 			hash_map::Entry::Vacant(_) => {
-				return Err(APIError::ChannelUnavailable { err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(*temporary_channel_id), counterparty_node_id) });
+				return Err(APIError::ChannelUnavailable { err: format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!((*temporary_channel_id).0), counterparty_node_id) });
 			}
 		}
 		Ok(())
@@ -5509,7 +5509,7 @@ where
 				let announcement_sigs_opt = try_chan_entry!(self, chan.get_mut().channel_ready(&msg, &self.node_signer,
 					self.genesis_hash.clone(), &self.default_configuration, &self.best_block.read().unwrap(), &self.logger), chan);
 				if let Some(announcement_sigs) = announcement_sigs_opt {
-					log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(chan.get().context.channel_id()));
+					log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(chan.get().context.channel_id().0));
 					peer_state.pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
 						node_id: counterparty_node_id.clone(),
 						msg: announcement_sigs,
@@ -5520,7 +5520,7 @@ where
 					// counterparty's announcement_signatures. Thus, we only bother to send a
 					// channel_update here if the channel is not public, i.e. we're not sending an
 					// announcement_signatures.
-					log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().context.channel_id()));
+					log_trace!(self.logger, "Sending private initial channel_update for our counterparty on channel {}", log_bytes!(chan.get().context.channel_id().0));
 					if let Ok(msg) = self.get_channel_update_for_unicast(chan.get()) {
 						peer_state.pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
 							node_id: counterparty_node_id.clone(),
@@ -5554,13 +5554,13 @@ where
 			// TODO(dunxen): Fix this duplication when we switch to a single map with enums as per
 			// https://github.com/lightningdevkit/rust-lightning/issues/2422
 			if let hash_map::Entry::Occupied(chan_entry) = peer_state.outbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
-				log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
+				log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id.0[..]));
 				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
 				let mut chan = remove_channel!(self, chan_entry);
 				self.finish_force_close_channel(chan.context.force_shutdown(false));
 				return Ok(());
 			} else if let hash_map::Entry::Occupied(chan_entry) = peer_state.inbound_v1_channel_by_id.entry(msg.channel_id.clone()) {
-				log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id[..]));
+				log_error!(self.logger, "Immediately closing unfunded channel {} as peer asked to cooperatively shut it down (which is unnecessary)", log_bytes!(&msg.channel_id.0[..]));
 				self.issue_channel_close_events(&chan_entry.get().context, ClosureReason::CounterpartyCoopClosedUnfundedChannel);
 				let mut chan = remove_channel!(self, chan_entry);
 				self.finish_force_close_channel(chan.context.force_shutdown(false));
@@ -5568,7 +5568,7 @@ where
 			} else if let hash_map::Entry::Occupied(mut chan_entry) = peer_state.channel_by_id.entry(msg.channel_id.clone()) {
 				if !chan_entry.get().received_shutdown() {
 					log_info!(self.logger, "Received a shutdown message from our counterparty for channel {}{}.",
-						log_bytes!(msg.channel_id),
+						log_bytes!(msg.channel_id.0),
 						if chan_entry.get().sent_shutdown() { " after we initiated shutdown" } else { "" });
 				}
 
@@ -5901,7 +5901,7 @@ where
 	/// completes. Note that this needs to happen in the same [`PeerState`] mutex as any release of
 	/// the [`ChannelMonitorUpdate`] in question.
 	fn raa_monitor_updates_held(&self,
-		actions_blocking_raa_monitor_updates: &BTreeMap<[u8; 32], Vec<RAAMonitorUpdateBlockingAction>>,
+		actions_blocking_raa_monitor_updates: &BTreeMap<ChannelId, Vec<RAAMonitorUpdateBlockingAction>>,
 		channel_funding_outpoint: OutPoint, counterparty_node_id: PublicKey
 	) -> bool {
 		actions_blocking_raa_monitor_updates
@@ -6020,7 +6020,7 @@ where
 				if were_node_one == msg_from_node_one {
 					return Ok(NotifyOption::SkipPersist);
 				} else {
-					log_debug!(self.logger, "Received channel_update for channel {}.", log_bytes!(chan_id));
+					log_debug!(self.logger, "Received channel_update for channel {}.", log_bytes!(chan_id.0));
 					try_chan_entry!(self, chan.get_mut().channel_update(&msg), chan);
 				}
 			},
@@ -6538,7 +6538,7 @@ where
 					// blocking monitor updates for this channel. If we do, release the monitor
 					// update(s) when those blockers complete.
 					log_trace!(self.logger, "Delaying monitor unlock for channel {} as another channel's mon update needs to complete first",
-						log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
+						log_bytes!(&channel_funding_outpoint.to_channel_id().0[..]));
 					break;
 				}
 
@@ -6546,7 +6546,7 @@ where
 					debug_assert_eq!(chan.get().context.get_funding_txo().unwrap(), channel_funding_outpoint);
 					if let Some((monitor_update, further_update_exists)) = chan.get_mut().unblock_next_blocked_monitor_update() {
 						log_debug!(self.logger, "Unlocking monitor updating for channel {} and updating monitor",
-							log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
+							log_bytes!(&channel_funding_outpoint.to_channel_id().0[..]));
 						if let Err(e) = handle_new_monitor_update!(self, channel_funding_outpoint, monitor_update,
 							peer_state_lck, peer_state, per_peer_state, chan)
 						{
@@ -6559,7 +6559,7 @@ where
 						}
 					} else {
 						log_trace!(self.logger, "Unlocked monitor updating for channel {} without monitors to update",
-							log_bytes!(&channel_funding_outpoint.to_channel_id()[..]));
+							log_bytes!(&channel_funding_outpoint.to_channel_id().0[..]));
 					}
 				}
 			} else {
@@ -6857,7 +6857,7 @@ where
 						if let Some(channel_ready) = channel_ready_opt {
 							send_channel_ready!(self, pending_msg_events, channel, channel_ready);
 							if channel.context.is_usable() {
-								log_trace!(self.logger, "Sending channel_ready with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.context.channel_id()));
+								log_trace!(self.logger, "Sending channel_ready with private initial channel_update for our counterparty on channel {}", log_bytes!(channel.context.channel_id().0));
 								if let Ok(msg) = self.get_channel_update_for_unicast(channel) {
 									pending_msg_events.push(events::MessageSendEvent::SendChannelUpdate {
 										node_id: channel.context.get_counterparty_node_id(),
@@ -6865,7 +6865,7 @@ where
 									});
 								}
 							} else {
-								log_trace!(self.logger, "Sending channel_ready WITHOUT channel_update for {}", log_bytes!(channel.context.channel_id()));
+								log_trace!(self.logger, "Sending channel_ready WITHOUT channel_update for {}", log_bytes!(channel.context.channel_id().0));
 							}
 						}
 
@@ -6875,7 +6875,7 @@ where
 						}
 
 						if let Some(announcement_sigs) = announcement_sigs {
-							log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.context.channel_id()));
+							log_trace!(self.logger, "Sending announcement_signatures for channel {}", log_bytes!(channel.context.channel_id().0));
 							pending_msg_events.push(events::MessageSendEvent::SendAnnouncementSignatures {
 								node_id: channel.context.get_counterparty_node_id(),
 								msg: announcement_sigs,
@@ -7318,8 +7318,8 @@ where
 	fn handle_error(&self, counterparty_node_id: &PublicKey, msg: &msgs::ErrorMessage) {
 		let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
 
-		if msg.channel_id == [0; 32] {
-			let channel_ids: Vec<[u8; 32]> = {
+		if msg.channel_id.0 == [0; 32] {
+			let channel_ids: Vec<ChannelId> = {
 				let per_peer_state = self.per_peer_state.read().unwrap();
 				let peer_state_mutex_opt = per_peer_state.get(counterparty_node_id);
 				if peer_state_mutex_opt.is_none() { return; }
@@ -8324,7 +8324,7 @@ where
 
 		let channel_count: u64 = Readable::read(reader)?;
 		let mut funding_txo_set = HashSet::with_capacity(cmp::min(channel_count as usize, 128));
-		let mut peer_channels: HashMap<PublicKey, HashMap<[u8; 32], Channel<<SP::Target as SignerProvider>::Signer>>> = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
+		let mut peer_channels: HashMap<PublicKey, HashMap<ChannelId, Channel<<SP::Target as SignerProvider>::Signer>>> = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
 		let mut id_to_peer = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
 		let mut short_to_chan_info = HashMap::with_capacity(cmp::min(channel_count as usize, 128));
 		let mut channel_closures = VecDeque::new();
@@ -8344,7 +8344,7 @@ where
 					log_error!(args.logger, "A ChannelManager is stale compared to the current ChannelMonitor!");
 					log_error!(args.logger, " The channel will be force-closed and the latest commitment transaction from the ChannelMonitor broadcast.");
 					log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} but the ChannelManager is at update_id {}.",
-						log_bytes!(channel.context.channel_id()), monitor.get_latest_update_id(), channel.context.get_latest_monitor_update_id());
+						log_bytes!(channel.context.channel_id().0), monitor.get_latest_update_id(), channel.context.get_latest_monitor_update_id());
 					let (monitor_update, mut new_failed_htlcs) = channel.context.force_shutdown(true);
 					if let Some((counterparty_node_id, funding_txo, update)) = monitor_update {
 						close_background_events.push(BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
@@ -8372,13 +8372,13 @@ where
 							// backwards leg of the HTLC will simply be rejected.
 							log_info!(args.logger,
 								"Failing HTLC with hash {} as it is missing in the ChannelMonitor for channel {} but was present in the (stale) ChannelManager",
-								log_bytes!(channel.context.channel_id()), log_bytes!(payment_hash.0));
+								log_bytes!(channel.context.channel_id().0), log_bytes!(payment_hash.0));
 							failed_htlcs.push((channel_htlc_source.clone(), *payment_hash, channel.context.get_counterparty_node_id(), channel.context.channel_id()));
 						}
 					}
 				} else {
 					log_info!(args.logger, "Successfully loaded channel {} at update_id {} against monitor at update id {}",
-						log_bytes!(channel.context.channel_id()), channel.context.get_latest_monitor_update_id(),
+						log_bytes!(channel.context.channel_id().0), channel.context.get_latest_monitor_update_id(),
 						monitor.get_latest_update_id());
 					if let Some(short_channel_id) = channel.context.get_short_channel_id() {
 						short_to_chan_info.insert(short_channel_id, (channel.context.get_counterparty_node_id(), channel.context.channel_id()));
@@ -8409,7 +8409,7 @@ where
 					reason: ClosureReason::DisconnectedPeer,
 				}, None));
 			} else {
-				log_error!(args.logger, "Missing ChannelMonitor for channel {} needed by ChannelManager.", log_bytes!(channel.context.channel_id()));
+				log_error!(args.logger, "Missing ChannelMonitor for channel {} needed by ChannelManager.", log_bytes!(channel.context.channel_id().0));
 				log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
 				log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
 				log_error!(args.logger, " Without the ChannelMonitor we cannot continue without risking funds.");
@@ -8421,7 +8421,7 @@ where
 		for (funding_txo, _) in args.channel_monitors.iter() {
 			if !funding_txo_set.contains(funding_txo) {
 				log_info!(args.logger, "Queueing monitor update to ensure missing channel {} is force closed",
-					log_bytes!(funding_txo.to_channel_id()));
+					log_bytes!(funding_txo.to_channel_id().0));
 				let monitor_update = ChannelMonitorUpdate {
 					update_id: CLOSED_CHANNEL_UPDATE_ID,
 					updates: vec![ChannelMonitorUpdateStep::ChannelForceClosed { should_broadcast: true }],
@@ -8604,7 +8604,7 @@ where
 				$chan_in_flight_upds.retain(|upd| upd.update_id > $monitor.get_latest_update_id());
 				for update in $chan_in_flight_upds.iter() {
 					log_trace!(args.logger, "Replaying ChannelMonitorUpdate {} for {}channel {}",
-						update.update_id, $channel_info_log, log_bytes!($funding_txo.to_channel_id()));
+						update.update_id, $channel_info_log, log_bytes!($funding_txo.to_channel_id().0));
 					max_in_flight_update_id = cmp::max(max_in_flight_update_id, update.update_id);
 					pending_background_events.push(
 						BackgroundEvent::MonitorUpdateRegeneratedOnStartup {
@@ -8652,7 +8652,7 @@ where
 					// If the channel is ahead of the monitor, return InvalidValue:
 					log_error!(args.logger, "A ChannelMonitor is stale compared to the current ChannelManager! This indicates a potentially-critical violation of the chain::Watch API!");
 					log_error!(args.logger, " The ChannelMonitor for channel {} is at update_id {} with update_id through {} in-flight",
-						log_bytes!(chan.context.channel_id()), monitor.get_latest_update_id(), max_in_flight_update_id);
+						log_bytes!(chan.context.channel_id().0), monitor.get_latest_update_id(), max_in_flight_update_id);
 					log_error!(args.logger, " but the ChannelManager is at update_id {}.", chan.get_latest_unblocked_monitor_update_id());
 					log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
 					log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
@@ -8678,7 +8678,7 @@ where
 				} else {
 					log_error!(args.logger, "A ChannelMonitor is missing even though we have in-flight updates for it! This indicates a potentially-critical violation of the chain::Watch API!");
 					log_error!(args.logger, " The ChannelMonitor for channel {} is missing.",
-						log_bytes!(funding_txo.to_channel_id()));
+						log_bytes!(funding_txo.to_channel_id().0));
 					log_error!(args.logger, " The chain::Watch API *requires* that monitors are persisted durably before returning,");
 					log_error!(args.logger, " client applications must ensure that ChannelMonitor data is always available and the latest to avoid funds loss!");
 					log_error!(args.logger, " Without the latest ChannelMonitor we cannot continue without risking funds.");
@@ -8763,7 +8763,7 @@ where
 										if let HTLCForwardInfo::AddHTLC(htlc_info) = forward {
 											if pending_forward_matches_htlc(&htlc_info) {
 												log_info!(args.logger, "Removing pending to-forward HTLC with hash {} as it was forwarded to the closed channel {}",
-													log_bytes!(htlc.payment_hash.0), log_bytes!(monitor.get_funding_txo().0.to_channel_id()));
+													log_bytes!(htlc.payment_hash.0), log_bytes!(monitor.get_funding_txo().0.to_channel_id().0));
 												false
 											} else { true }
 										} else { true }
@@ -8773,7 +8773,7 @@ where
 								pending_intercepted_htlcs.as_mut().unwrap().retain(|intercepted_id, htlc_info| {
 									if pending_forward_matches_htlc(&htlc_info) {
 										log_info!(args.logger, "Removing pending intercepted HTLC with hash {} as it was forwarded to the closed channel {}",
-											log_bytes!(htlc.payment_hash.0), log_bytes!(monitor.get_funding_txo().0.to_channel_id()));
+											log_bytes!(htlc.payment_hash.0), log_bytes!(monitor.get_funding_txo().0.to_channel_id().0));
 										pending_events_read.retain(|(event, _)| {
 											if let Event::HTLCIntercepted { intercept_id: ev_id, .. } = event {
 												intercepted_id != ev_id
@@ -9107,6 +9107,7 @@ mod tests {
 	use core::sync::atomic::Ordering;
 	use crate::events::{Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, ClosureReason};
 	use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+	use crate::ln::channel::ChannelId;
 	use crate::ln::channelmanager::{inbound_payment, PaymentId, PaymentSendFailure, RecipientOnionFields, InterceptId};
 	use crate::ln::functional_test_utils::*;
 	use crate::ln::msgs::{self, ErrorAction};
@@ -9687,7 +9688,7 @@ mod tests {
 		nodes[0].node.handle_accept_channel(&nodes[1].node.get_our_node_id(), &accept_channel);
 
 		let (temporary_channel_id, tx, _funding_output) = create_funding_transaction(&nodes[0], &nodes[1].node.get_our_node_id(), 1_000_000, 42);
-		let channel_id = &tx.txid().into_inner();
+		let channel_id = ChannelId(tx.txid().into_inner());
 		{
 			// Ensure that the `id_to_peer` map is empty until either party has received the
 			// funding transaction, and have the real `channel_id`.
@@ -9701,7 +9702,7 @@ mod tests {
 			// as it has the funding transaction.
 			let nodes_0_lock = nodes[0].node.id_to_peer.lock().unwrap();
 			assert_eq!(nodes_0_lock.len(), 1);
-			assert!(nodes_0_lock.contains_key(channel_id));
+			assert!(nodes_0_lock.contains_key(&channel_id));
 		}
 
 		assert_eq!(nodes[1].node.id_to_peer.lock().unwrap().len(), 0);
@@ -9712,7 +9713,7 @@ mod tests {
 		{
 			let nodes_0_lock = nodes[0].node.id_to_peer.lock().unwrap();
 			assert_eq!(nodes_0_lock.len(), 1);
-			assert!(nodes_0_lock.contains_key(channel_id));
+			assert!(nodes_0_lock.contains_key(&channel_id));
 		}
 		expect_channel_pending_event(&nodes[1], &nodes[0].node.get_our_node_id());
 
@@ -9721,7 +9722,7 @@ mod tests {
 			// as it has the funding transaction.
 			let nodes_1_lock = nodes[1].node.id_to_peer.lock().unwrap();
 			assert_eq!(nodes_1_lock.len(), 1);
-			assert!(nodes_1_lock.contains_key(channel_id));
+			assert!(nodes_1_lock.contains_key(&channel_id));
 		}
 		check_added_monitors!(nodes[1], 1);
 		let funding_signed = get_event_msg!(nodes[1], MessageSendEvent::SendFundingSigned, nodes[0].node.get_our_node_id());
@@ -9732,7 +9733,7 @@ mod tests {
 		let (announcement, nodes_0_update, nodes_1_update) = create_chan_between_nodes_with_value_b(&nodes[0], &nodes[1], &channel_ready);
 		update_nodes_with_chan_announce(&nodes, 0, 1, &announcement, &nodes_0_update, &nodes_1_update);
 
-		nodes[0].node.close_channel(channel_id, &nodes[1].node.get_our_node_id()).unwrap();
+		nodes[0].node.close_channel(&channel_id, &nodes[1].node.get_our_node_id()).unwrap();
 		nodes[1].node.handle_shutdown(&nodes[0].node.get_our_node_id(), &get_event_msg!(nodes[0], MessageSendEvent::SendShutdown, nodes[1].node.get_our_node_id()));
 		let nodes_1_shutdown = get_event_msg!(nodes[1], MessageSendEvent::SendShutdown, nodes[0].node.get_our_node_id());
 		nodes[0].node.handle_shutdown(&nodes[1].node.get_our_node_id(), &nodes_1_shutdown);
@@ -9746,7 +9747,7 @@ mod tests {
 			// party's signature for the fee negotiated closing transaction.)
 			let nodes_0_lock = nodes[0].node.id_to_peer.lock().unwrap();
 			assert_eq!(nodes_0_lock.len(), 1);
-			assert!(nodes_0_lock.contains_key(channel_id));
+			assert!(nodes_0_lock.contains_key(&channel_id));
 		}
 
 		{
@@ -9756,7 +9757,7 @@ mod tests {
 			// kept in the `nodes[1]`'s `id_to_peer` map.
 			let nodes_1_lock = nodes[1].node.id_to_peer.lock().unwrap();
 			assert_eq!(nodes_1_lock.len(), 1);
-			assert!(nodes_1_lock.contains_key(channel_id));
+			assert!(nodes_1_lock.contains_key(&channel_id));
 		}
 
 		nodes[0].node.handle_closing_signed(&nodes[1].node.get_our_node_id(), &get_event_msg!(nodes[1], MessageSendEvent::SendClosingSigned, nodes[0].node.get_our_node_id()));
@@ -9772,7 +9773,7 @@ mod tests {
 			// doesn't have `nodes[0]`'s signature for the closing transaction yet.
 			let nodes_1_lock = nodes[1].node.id_to_peer.lock().unwrap();
 			assert_eq!(nodes_1_lock.len(), 1);
-			assert!(nodes_1_lock.contains_key(channel_id));
+			assert!(nodes_1_lock.contains_key(&channel_id));
 		}
 
 		let (_nodes_0_update, closing_signed_node_0) = get_closing_signed_broadcast!(nodes[0].node, nodes[1].node.get_our_node_id());
@@ -9823,7 +9824,7 @@ mod tests {
 		let nodes = create_network(2, &node_cfg, &node_chanmgr);
 
 		// Dummy values
-		let channel_id = [4; 32];
+		let channel_id = ChannelId([4; 32]);
 		let unkown_public_key = PublicKey::from_secret_key(&Secp256k1::signing_only(), &SecretKey::from_slice(&[42; 32]).unwrap());
 		let intercept_id = InterceptId([0; 32]);
 
@@ -9878,11 +9879,11 @@ 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 = nodes[0].keys_manager.get_secure_random_bytes();
+			open_channel_msg.temporary_channel_id = ChannelId(nodes[0].keys_manager.get_secure_random_bytes());
 		}
 
 		// A MAX_UNFUNDED_CHANS_PER_PEER + 1 channel will be summarily rejected
-		open_channel_msg.temporary_channel_id = nodes[0].keys_manager.get_secure_random_bytes();
+		open_channel_msg.temporary_channel_id = ChannelId(nodes[0].keys_manager.get_secure_random_bytes());
 		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);
@@ -9933,7 +9934,7 @@ mod tests {
 		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 = nodes[0].keys_manager.get_secure_random_bytes();
+			open_channel_msg.temporary_channel_id = ChannelId(nodes[0].keys_manager.get_secure_random_bytes());
 		}
 		nodes[1].node.handle_open_channel(&last_random_pk, &open_channel_msg);
 		assert_eq!(get_err_msg(&nodes[1], &last_random_pk).channel_id,
@@ -9973,7 +9974,7 @@ mod tests {
 		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 = nodes[0].keys_manager.get_secure_random_bytes();
+			open_channel_msg.temporary_channel_id = ChannelId(nodes[0].keys_manager.get_secure_random_bytes());
 		}
 
 		// Once we have MAX_UNFUNDED_CHANS_PER_PEER unfunded channels, new inbound channels will be
@@ -10025,7 +10026,7 @@ mod tests {
 				_ => panic!("Unexpected event"),
 			}
 			get_event_msg!(nodes[1], MessageSendEvent::SendAcceptChannel, random_pk);
-			open_channel_msg.temporary_channel_id = nodes[0].keys_manager.get_secure_random_bytes();
+			open_channel_msg.temporary_channel_id = ChannelId(nodes[0].keys_manager.get_secure_random_bytes());
 		}
 
 		// If we try to accept a channel from another peer non-0conf it will fail.
diff --git a/lightning/src/ln/functional_test_utils.rs b/lightning/src/ln/functional_test_utils.rs
index e4b69dbac76..8e8e87d3638 100644
--- a/lightning/src/ln/functional_test_utils.rs
+++ b/lightning/src/ln/functional_test_utils.rs
@@ -562,11 +562,11 @@ impl<'a, 'b, 'c> Drop for Node<'a, 'b, 'c> {
 	}
 }
 
-pub fn create_chan_between_nodes<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
+pub fn create_chan_between_nodes<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, ChannelId, Transaction) {
 	create_chan_between_nodes_with_value(node_a, node_b, 100000, 10001)
 }
 
-pub fn create_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>, channel_value: u64, push_msat: u64) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
+pub fn create_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>, channel_value: u64, push_msat: u64) -> (msgs::ChannelAnnouncement, msgs::ChannelUpdate, msgs::ChannelUpdate, ChannelId, Transaction) {
 	let (channel_ready, channel_id, tx) = create_chan_between_nodes_with_value_a(node_a, node_b, channel_value, push_msat);
 	let (announcement, as_update, bs_update) = create_chan_between_nodes_with_value_b(node_a, node_b, &channel_ready);
 	(announcement, as_update, bs_update, channel_id, tx)
@@ -860,7 +860,7 @@ macro_rules! get_monitor {
 			for index in 0..2 {
 				if let Ok(mon) = $node.chain_monitor.chain_monitor.get_monitor(
 					$crate::chain::transaction::OutPoint {
-						txid: bitcoin::Txid::from_slice(&$channel_id[..]).unwrap(), index
+						txid: bitcoin::Txid::from_slice(&$channel_id.0[..]).unwrap(), index
 					})
 				{
 					monitor = Some(mon);
@@ -982,7 +982,7 @@ macro_rules! reload_node {
 	};
 }
 
-pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_counterparty_node_id: &PublicKey, expected_chan_value: u64, expected_user_chan_id: u128) -> ([u8; 32], Transaction, OutPoint) {
+pub fn create_funding_transaction<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, expected_counterparty_node_id: &PublicKey, expected_chan_value: u64, expected_user_chan_id: u128) -> (ChannelId, Transaction, OutPoint) {
 	let chan_id = *node.network_chan_count.borrow();
 
 	let events = node.node.get_and_clear_pending_events();
@@ -1045,7 +1045,7 @@ pub fn sign_funding_transaction<'a, 'b, 'c>(node_a: &Node<'a, 'b, 'c>, node_b: &
 }
 
 // Receiver must have been initialized with manually_accept_inbound_channels set to true.
-pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, receiver: &'a Node<'b, 'c, 'd>, initiator_config: Option<UserConfig>) -> (bitcoin::Transaction, [u8; 32]) {
+pub fn open_zero_conf_channel<'a, 'b, 'c, 'd>(initiator: &'a Node<'b, 'c, 'd>, receiver: &'a Node<'b, 'c, 'd>, initiator_config: Option<UserConfig>) -> (bitcoin::Transaction, ChannelId) {
 	let initiator_channels = initiator.node.list_usable_channels().len();
 	let receiver_channels = receiver.node.list_usable_channels().len();
 
@@ -1143,7 +1143,7 @@ pub fn create_chan_between_nodes_with_value_confirm_first<'a, 'b, 'c, 'd>(node_r
 	node_recv.node.handle_channel_ready(&node_conf.node.get_our_node_id(), &get_event_msg!(node_conf, MessageSendEvent::SendChannelReady, node_recv.node.get_our_node_id()));
 }
 
-pub fn create_chan_between_nodes_with_value_confirm_second<'a, 'b, 'c>(node_recv: &Node<'a, 'b, 'c>, node_conf: &Node<'a, 'b, 'c>) -> ((msgs::ChannelReady, msgs::AnnouncementSignatures), [u8; 32]) {
+pub fn create_chan_between_nodes_with_value_confirm_second<'a, 'b, 'c>(node_recv: &Node<'a, 'b, 'c>, node_conf: &Node<'a, 'b, 'c>) -> ((msgs::ChannelReady, msgs::AnnouncementSignatures), ChannelId) {
 	let channel_id;
 	let events_6 = node_conf.node.get_and_clear_pending_msg_events();
 	assert_eq!(events_6.len(), 3);
@@ -1170,7 +1170,7 @@ pub fn create_chan_between_nodes_with_value_confirm_second<'a, 'b, 'c>(node_recv
 	}), channel_id)
 }
 
-pub fn create_chan_between_nodes_with_value_confirm<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>, tx: &Transaction) -> ((msgs::ChannelReady, msgs::AnnouncementSignatures), [u8; 32]) {
+pub fn create_chan_between_nodes_with_value_confirm<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>, tx: &Transaction) -> ((msgs::ChannelReady, msgs::AnnouncementSignatures), ChannelId) {
 	let conf_height = core::cmp::max(node_a.best_block_info().1 + 1, node_b.best_block_info().1 + 1);
 	create_chan_between_nodes_with_value_confirm_first(node_a, node_b, tx, conf_height);
 	confirm_transaction_at(node_a, tx, conf_height);
@@ -1179,7 +1179,7 @@ pub fn create_chan_between_nodes_with_value_confirm<'a, 'b, 'c, 'd>(node_a: &'a
 	create_chan_between_nodes_with_value_confirm_second(node_b, node_a)
 }
 
-pub fn create_chan_between_nodes_with_value_a<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>, channel_value: u64, push_msat: u64) -> ((msgs::ChannelReady, msgs::AnnouncementSignatures), [u8; 32], Transaction) {
+pub fn create_chan_between_nodes_with_value_a<'a, 'b, 'c, 'd>(node_a: &'a Node<'b, 'c, 'd>, node_b: &'a Node<'b, 'c, 'd>, channel_value: u64, push_msat: u64) -> ((msgs::ChannelReady, msgs::AnnouncementSignatures), ChannelId, Transaction) {
 	let tx = create_chan_between_nodes_with_value_init(node_a, node_b, channel_value, push_msat);
 	let (msgs, chan_id) = create_chan_between_nodes_with_value_confirm(node_a, node_b, &tx);
 	(msgs, chan_id, tx)
@@ -1219,11 +1219,11 @@ pub fn create_chan_between_nodes_with_value_b<'a, 'b, 'c>(node_a: &Node<'a, 'b,
 	((*announcement).clone(), as_update, bs_update)
 }
 
-pub fn create_announced_chan_between_nodes<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
+pub fn create_announced_chan_between_nodes<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, ChannelId, Transaction) {
 	create_announced_chan_between_nodes_with_value(nodes, a, b, 100000, 10001)
 }
 
-pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, channel_value: u64, push_msat: u64) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction) {
+pub fn create_announced_chan_between_nodes_with_value<'a, 'b, 'c, 'd>(nodes: &'a Vec<Node<'b, 'c, 'd>>, a: usize, b: usize, channel_value: u64, push_msat: u64) -> (msgs::ChannelUpdate, msgs::ChannelUpdate, ChannelId, Transaction) {
 	let chan_announcement = create_chan_between_nodes_with_value(&nodes[a], &nodes[b], channel_value, push_msat);
 	update_nodes_with_chan_announce(nodes, a, b, &chan_announcement.0, &chan_announcement.1, &chan_announcement.2);
 	(chan_announcement.1, chan_announcement.2, chan_announcement.3, chan_announcement.4)
@@ -2695,7 +2695,7 @@ pub enum HTLCType { NONE, TIMEOUT, SUCCESS }
 ///
 /// All broadcast transactions must be accounted for in one of the above three types of we'll
 /// also fail.
-pub fn test_txn_broadcast<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, [u8; 32], Transaction), commitment_tx: Option<Transaction>, has_htlc_tx: HTLCType) -> Vec<Transaction>  {
+pub fn test_txn_broadcast<'a, 'b, 'c>(node: &Node<'a, 'b, 'c>, chan: &(msgs::ChannelUpdate, msgs::ChannelUpdate, ChannelId, Transaction), commitment_tx: Option<Transaction>, has_htlc_tx: HTLCType) -> Vec<Transaction>  {
 	let mut node_txn = node.tx_broadcaster.txn_broadcasted.lock().unwrap();
 	let mut txn_seen = HashSet::new();
 	node_txn.retain(|tx| txn_seen.insert(tx.txid()));
diff --git a/lightning/src/ln/functional_tests.rs b/lightning/src/ln/functional_tests.rs
index 8de2e9f631a..732c9545092 100644
--- a/lightning/src/ln/functional_tests.rs
+++ b/lightning/src/ln/functional_tests.rs
@@ -20,6 +20,7 @@ use crate::chain::transaction::OutPoint;
 use crate::sign::{ChannelSigner, EcdsaChannelSigner, EntropySource};
 use crate::events::{Event, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentPurpose, ClosureReason, HTLCDestination, PaymentFailureReason};
 use crate::ln::{PaymentPreimage, PaymentSecret, PaymentHash};
+use crate::ln::channel::ChannelId;
 use crate::ln::channel::{commitment_tx_base_weight, COMMITMENT_TX_WEIGHT_PER_HTLC, CONCURRENT_INBOUND_HTLC_FEE_BUFFER, FEE_SPIKE_BUFFER_FEE_INCREASE_MULTIPLE, MIN_AFFORDABLE_HTLC_COUNT, get_holder_selected_channel_reserve_satoshis, OutboundV1Channel, InboundV1Channel};
 use crate::ln::channelmanager::{self, PaymentId, RAACommitmentOrder, PaymentSendFailure, RecipientOnionFields, BREAKDOWN_TIMEOUT, ENABLE_GOSSIP_TICKS, DISABLE_GOSSIP_TICKS, MIN_CLTV_EXPIRY_DELTA};
 use crate::ln::channel::{DISCONNECT_PEER_AWAITING_RESPONSE_TICKS, ChannelError};
@@ -1504,7 +1505,7 @@ fn test_fee_spike_violation_fails_htlc() {
 		_ => panic!("Unexpected event"),
 	};
 	nodes[1].logger.assert_log("lightning::ln::channel".to_string(),
-		format!("Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", ::hex::encode(raa_msg.channel_id)), 1);
+		format!("Attempting to fail HTLC due to fee spike buffer violation in channel {}. Rebalancing is required.", ::hex::encode(raa_msg.channel_id.0)), 1);
 
 	check_added_monitors!(nodes[1], 2);
 }
@@ -5736,7 +5737,7 @@ fn test_fail_holding_cell_htlc_upon_free() {
 	// us to surface its failure to the user.
 	chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2);
 	assert_eq!(chan_stat.holding_cell_outbound_amount_msat, 0);
-	nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Freeing holding cell with 1 HTLC updates in channel {}", hex::encode(chan.2)), 1);
+	nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Freeing holding cell with 1 HTLC updates in channel {}", hex::encode(chan.2.0)), 1);
 
 	// Check that the payment failed to be sent out.
 	let events = nodes[0].node.get_and_clear_pending_events();
@@ -5824,7 +5825,7 @@ fn test_free_and_fail_holding_cell_htlcs() {
 	// to surface its failure to the user. The first payment should succeed.
 	chan_stat = get_channel_value_stat!(nodes[0], nodes[1], chan.2);
 	assert_eq!(chan_stat.holding_cell_outbound_amount_msat, 0);
-	nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Freeing holding cell with 2 HTLC updates in channel {}", hex::encode(chan.2)), 1);
+	nodes[0].logger.assert_log("lightning::ln::channel".to_string(), format!("Freeing holding cell with 2 HTLC updates in channel {}", hex::encode(chan.2.0)), 1);
 
 	// Check that the second payment failed to be sent out.
 	let events = nodes[0].node.get_and_clear_pending_events();
@@ -7963,11 +7964,11 @@ fn test_can_not_accept_unknown_inbound_channel() {
 	let node_chanmgr = create_node_chanmgrs(2, &node_cfg, &[None, None]);
 	let nodes = create_network(2, &node_cfg, &node_chanmgr);
 
-	let unknown_channel_id = [0; 32];
+	let unknown_channel_id = ChannelId([0; 32]);
 	let api_res = nodes[0].node.accept_inbound_channel(&unknown_channel_id, &nodes[1].node.get_our_node_id(), 0);
 	match api_res {
 		Err(APIError::ChannelUnavailable { err }) => {
-			assert_eq!(err, format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(unknown_channel_id), nodes[1].node.get_our_node_id()));
+			assert_eq!(err, format!("Channel with id {} not found for the passed counterparty node_id {}", log_bytes!(unknown_channel_id.0), nodes[1].node.get_our_node_id()));
 		},
 		Ok(_) => panic!("It shouldn't be possible to accept an unkown channel"),
 		Err(_) => panic!("Unexpected Error"),
@@ -8972,7 +8973,7 @@ fn test_error_chans_closed() {
 
 	// A null channel ID should close all channels
 	let _chan_4 = create_announced_chan_between_nodes_with_value(&nodes, 0, 1, 100000, 10001);
-	nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: [0; 32], data: "ERR".to_owned() });
+	nodes[0].node.handle_error(&nodes[1].node.get_our_node_id(), &msgs::ErrorMessage { channel_id: ChannelId([0; 32]), data: "ERR".to_owned() });
 	check_added_monitors!(nodes[0], 2);
 	check_closed_event!(nodes[0], 2, ClosureReason::CounterpartyForceClosed { peer_msg: UntrustedString("ERR".to_string()) });
 	let events = nodes[0].node.get_and_clear_pending_msg_events();
diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs
index d06aa26ee7c..390143da853 100644
--- a/lightning/src/ln/msgs.rs
+++ b/lightning/src/ln/msgs.rs
@@ -2447,6 +2447,7 @@ mod tests {
 	use bitcoin::{Transaction, PackedLockTime, TxIn, Script, Sequence, Witness, TxOut};
 	use hex;
 	use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+	use crate::ln::channel::ChannelId;
 	use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 	use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, OnionHopDataFormat};
 	use crate::routing::gossip::{NodeAlias, NodeId};
@@ -2477,7 +2478,7 @@ mod tests {
 		};
 
 		let cr = msgs::ChannelReestablish {
-			channel_id: [4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
+			channel_id: ChannelId([4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0]),
 			next_local_commitment_number: 3,
 			next_remote_commitment_number: 4,
 			your_last_per_commitment_secret: [9;32],
@@ -2506,7 +2507,7 @@ mod tests {
 		};
 
 		let cr = msgs::ChannelReestablish {
-			channel_id: [4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
+			channel_id: ChannelId([4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0]),
 			next_local_commitment_number: 3,
 			next_remote_commitment_number: 4,
 			your_last_per_commitment_secret: [9;32],
@@ -2558,7 +2559,7 @@ mod tests {
 		let sig_1 = get_sig_on!(privkey, secp_ctx, String::from("01010101010101010101010101010101"));
 		let sig_2 = get_sig_on!(privkey, secp_ctx, String::from("02020202020202020202020202020202"));
 		let announcement_signatures = msgs::AnnouncementSignatures {
-			channel_id: [4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0],
+			channel_id: ChannelId([4, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 0, 0, 6, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0]),
 			short_channel_id: 2316138423780173,
 			node_signature: sig_1,
 			bitcoin_signature: sig_2,
@@ -2794,7 +2795,7 @@ mod tests {
 		let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
 		let open_channel = msgs::OpenChannel {
 			chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
-			temporary_channel_id: [2; 32],
+			temporary_channel_id: ChannelId([2; 32]),
 			funding_satoshis: 1311768467284833366,
 			push_msat: 2536655962884945560,
 			dust_limit_satoshis: 3608586615801332854,
@@ -2855,7 +2856,7 @@ mod tests {
 		let (_, pubkey_7) = get_keys_from!("0707070707070707070707070707070707070707070707070707070707070707", secp_ctx);
 		let open_channelv2 = msgs::OpenChannelV2 {
 			chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(),
-			temporary_channel_id: [2; 32],
+			temporary_channel_id: ChannelId([2; 32]),
 			funding_feerate_sat_per_1000_weight: 821716,
 			commitment_feerate_sat_per_1000_weight: 821716,
 			funding_satoshis: 1311768467284833366,
@@ -2945,7 +2946,7 @@ mod tests {
 		let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx);
 		let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
 		let accept_channel = msgs::AcceptChannel {
-			temporary_channel_id: [2; 32],
+			temporary_channel_id: ChannelId([2; 32]),
 			dust_limit_satoshis: 1311768467284833366,
 			max_htlc_value_in_flight_msat: 2536655962884945560,
 			channel_reserve_satoshis: 3608586615801332854,
@@ -2988,7 +2989,7 @@ mod tests {
 		let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx);
 		let (_, pubkey_7) = get_keys_from!("0707070707070707070707070707070707070707070707070707070707070707", secp_ctx);
 		let accept_channelv2 = msgs::AcceptChannelV2 {
-			temporary_channel_id: [2; 32],
+			temporary_channel_id: ChannelId([2; 32]),
 			funding_satoshis: 1311768467284833366,
 			dust_limit_satoshis: 1311768467284833366,
 			max_htlc_value_in_flight_msat: 2536655962884945560,
@@ -3042,7 +3043,7 @@ mod tests {
 		let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
 		let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
 		let funding_created = msgs::FundingCreated {
-			temporary_channel_id: [2; 32],
+			temporary_channel_id: ChannelId([2; 32]),
 			funding_txid: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
 			funding_output_index: 255,
 			signature: sig_1,
@@ -3062,7 +3063,7 @@ mod tests {
 		let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
 		let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
 		let funding_signed = msgs::FundingSigned {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			signature: sig_1,
 			#[cfg(taproot)]
 			partial_signature_with_nonce: None,
@@ -3077,7 +3078,7 @@ mod tests {
 		let secp_ctx = Secp256k1::new();
 		let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
 		let channel_ready = msgs::ChannelReady {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			next_per_commitment_point: pubkey_1,
 			short_channel_id_alias: None,
 		};
@@ -3089,7 +3090,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_add_input() {
 		let tx_add_input = msgs::TxAddInput {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			serial_id: 4886718345,
 			prevtx: TransactionU16LenLimited::new(Transaction {
 				version: 2,
@@ -3124,7 +3125,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_add_output() {
 		let tx_add_output = msgs::TxAddOutput {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			serial_id: 4886718345,
 			sats: 4886718345,
 			script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().script_pubkey(),
@@ -3137,7 +3138,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_remove_input() {
 		let tx_remove_input = msgs::TxRemoveInput {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			serial_id: 4886718345,
 		};
 		let encoded_value = tx_remove_input.encode();
@@ -3148,7 +3149,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_remove_output() {
 		let tx_remove_output = msgs::TxRemoveOutput {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			serial_id: 4886718345,
 		};
 		let encoded_value = tx_remove_output.encode();
@@ -3159,7 +3160,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_complete() {
 		let tx_complete = msgs::TxComplete {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 		};
 		let encoded_value = tx_complete.encode();
 		let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap();
@@ -3169,7 +3170,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_signatures() {
 		let tx_signatures = msgs::TxSignatures {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			tx_hash: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
 			witnesses: vec![
 				Witness::from_vec(vec![
@@ -3203,7 +3204,7 @@ mod tests {
 
 	fn do_encoding_tx_init_rbf(funding_value_with_hex_target: Option<(i64, &str)>) {
 		let tx_init_rbf = msgs::TxInitRbf {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			locktime: 305419896,
 			feerate_sat_per_1000_weight: 20190119,
 			funding_output_contribution: if let Some((value, _)) = funding_value_with_hex_target { Some(value) } else { None },
@@ -3229,7 +3230,7 @@ mod tests {
 
 	fn do_encoding_tx_ack_rbf(funding_value_with_hex_target: Option<(i64, &str)>) {
 		let tx_ack_rbf = msgs::TxAckRbf {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			funding_output_contribution: if let Some((value, _)) = funding_value_with_hex_target { Some(value) } else { None },
 		};
 		let encoded_value = tx_ack_rbf.encode();
@@ -3252,7 +3253,7 @@ mod tests {
 	#[test]
 	fn encoding_tx_abort() {
 		let tx_abort = msgs::TxAbort {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			data: hex::decode("54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F672E").unwrap(),
 		};
 		let encoded_value = tx_abort.encode();
@@ -3265,7 +3266,7 @@ mod tests {
 		let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
 		let script = Builder::new().push_opcode(opcodes::OP_TRUE).into_script();
 		let shutdown = msgs::Shutdown {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			scriptpubkey:
 				     if script_type == 1 { Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey() }
 				else if script_type == 2 { Address::p2sh(&script, Network::Testnet).unwrap().script_pubkey() }
@@ -3300,7 +3301,7 @@ mod tests {
 		let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
 		let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101"));
 		let closing_signed = msgs::ClosingSigned {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			fee_satoshis: 2316138423780173,
 			signature: sig_1,
 			fee_range: None,
@@ -3311,7 +3312,7 @@ mod tests {
 		assert_eq!(msgs::ClosingSigned::read(&mut Cursor::new(&target_value)).unwrap(), closing_signed);
 
 		let closing_signed_with_range = msgs::ClosingSigned {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			fee_satoshis: 2316138423780173,
 			signature: sig_1,
 			fee_range: Some(msgs::ClosingSignedFeeRange {
@@ -3337,7 +3338,7 @@ mod tests {
 			hmac: [2; 32]
 		};
 		let update_add_htlc = msgs::UpdateAddHTLC {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			htlc_id: 2316138423780173,
 			amount_msat: 3608586615801332854,
 			payment_hash: PaymentHash([1; 32]),
@@ -3353,7 +3354,7 @@ mod tests {
 	#[test]
 	fn encoding_update_fulfill_htlc() {
 		let update_fulfill_htlc = msgs::UpdateFulfillHTLC {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			htlc_id: 2316138423780173,
 			payment_preimage: PaymentPreimage([1; 32]),
 		};
@@ -3368,7 +3369,7 @@ mod tests {
 			data: [1; 32].to_vec(),
 		};
 		let update_fail_htlc = msgs::UpdateFailHTLC {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			htlc_id: 2316138423780173,
 			reason
 		};
@@ -3380,7 +3381,7 @@ mod tests {
 	#[test]
 	fn encoding_update_fail_malformed_htlc() {
 		let update_fail_malformed_htlc = msgs::UpdateFailMalformedHTLC {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			htlc_id: 2316138423780173,
 			sha256_of_onion: [1; 32],
 			failure_code: 255
@@ -3401,7 +3402,7 @@ mod tests {
 		let sig_3 = get_sig_on!(privkey_3, secp_ctx, String::from("01010101010101010101010101010101"));
 		let sig_4 = get_sig_on!(privkey_4, secp_ctx, String::from("01010101010101010101010101010101"));
 		let commitment_signed = msgs::CommitmentSigned {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			signature: sig_1,
 			htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
 			#[cfg(taproot)]
@@ -3428,7 +3429,7 @@ mod tests {
 		let secp_ctx = Secp256k1::new();
 		let (_, pubkey_1) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx);
 		let raa = msgs::RevokeAndACK {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			per_commitment_secret: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
 			next_per_commitment_point: pubkey_1,
 			#[cfg(taproot)]
@@ -3442,7 +3443,7 @@ mod tests {
 	#[test]
 	fn encoding_update_fee() {
 		let update_fee = msgs::UpdateFee {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			feerate_per_kw: 20190119,
 		};
 		let encoded_value = update_fee.encode();
@@ -3489,7 +3490,7 @@ mod tests {
 	#[test]
 	fn encoding_error() {
 		let error = msgs::ErrorMessage {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			data: String::from("rust-lightning"),
 		};
 		let encoded_value = error.encode();
@@ -3500,7 +3501,7 @@ mod tests {
 	#[test]
 	fn encoding_warning() {
 		let error = msgs::WarningMessage {
-			channel_id: [2; 32],
+			channel_id: ChannelId([2; 32]),
 			data: String::from("rust-lightning"),
 		};
 		let encoded_value = error.encode();
diff --git a/lightning/src/ln/payment_tests.rs b/lightning/src/ln/payment_tests.rs
index 2ae606106c9..59727b43679 100644
--- a/lightning/src/ln/payment_tests.rs
+++ b/lightning/src/ln/payment_tests.rs
@@ -16,7 +16,7 @@ use crate::chain::channelmonitor::{ANTI_REORG_DELAY, HTLC_FAIL_BACK_BUFFER, LATE
 use crate::sign::EntropySource;
 use crate::chain::transaction::OutPoint;
 use crate::events::{ClosureReason, Event, HTLCDestination, MessageSendEvent, MessageSendEventsProvider, PathFailure, PaymentFailureReason};
-use crate::ln::channel::EXPIRE_PREV_CONFIG_TICKS;
+use crate::ln::channel::{ChannelId, EXPIRE_PREV_CONFIG_TICKS};
 use crate::ln::channelmanager::{BREAKDOWN_TIMEOUT, ChannelManager, MPP_TIMEOUT_TICKS, MIN_CLTV_EXPIRY_DELTA, PaymentId, PaymentSendFailure, IDEMPOTENCY_TIMEOUT_TICKS, RecentPaymentDetails, RecipientOnionFields, HTLCForwardInfo, PendingHTLCRouting, PendingAddHTLCInfo};
 use crate::ln::features::Bolt11InvoiceFeatures;
 use crate::ln::{msgs, PaymentSecret, PaymentPreimage};
@@ -1634,7 +1634,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
 	};
 
 	// Check for unknown channel id error.
-	let unknown_chan_id_err = nodes[1].node.forward_intercepted_htlc(intercept_id, &[42; 32], nodes[2].node.get_our_node_id(), expected_outbound_amount_msat).unwrap_err();
+	let unknown_chan_id_err = nodes[1].node.forward_intercepted_htlc(intercept_id, &ChannelId([42; 32]), nodes[2].node.get_our_node_id(), expected_outbound_amount_msat).unwrap_err();
 	assert_eq!(unknown_chan_id_err , APIError::ChannelUnavailable  {
 		err: format!("Funded channel with id {} not found for the passed counterparty node_id {}. Channel may still be opening.",
 			log_bytes!([42; 32]), nodes[2].node.get_our_node_id()) });
@@ -1663,7 +1663,7 @@ fn do_test_intercepted_payment(test: InterceptTest) {
 		let unusable_chan_err = nodes[1].node.forward_intercepted_htlc(intercept_id, &temp_chan_id, nodes[2].node.get_our_node_id(), expected_outbound_amount_msat).unwrap_err();
 		assert_eq!(unusable_chan_err , APIError::ChannelUnavailable {
 			err: format!("Funded channel with id {} not found for the passed counterparty node_id {}. Channel may still be opening.",
-				log_bytes!(temp_chan_id), nodes[2].node.get_our_node_id()) });
+				log_bytes!(temp_chan_id.0), nodes[2].node.get_our_node_id()) });
 		assert_eq!(nodes[1].node.get_and_clear_pending_msg_events().len(), 1);
 
 		// Open the just-in-time channel so the payment can then be forwarded.
diff --git a/lightning/src/ln/peer_handler.rs b/lightning/src/ln/peer_handler.rs
index bc3eb720c07..10ce8e00abc 100644
--- a/lightning/src/ln/peer_handler.rs
+++ b/lightning/src/ln/peer_handler.rs
@@ -1421,13 +1421,13 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 												}
 												(msgs::DecodeError::UnsupportedCompression, _) => {
 													log_gossip!(self.logger, "We don't support zlib-compressed message fields, sending a warning and ignoring message");
-													self.enqueue_message(peer, &msgs::WarningMessage { channel_id: [0; 32], data: "Unsupported message compression: zlib".to_owned() });
+													self.enqueue_message(peer, &msgs::WarningMessage { channel_id: ChannelId([0; 32]), data: "Unsupported message compression: zlib".to_owned() });
 													continue;
 												}
 												(_, Some(ty)) if is_gossip_msg(ty) => {
 													log_gossip!(self.logger, "Got an invalid value while deserializing a gossip message");
 													self.enqueue_message(peer, &msgs::WarningMessage {
-														channel_id: [0; 32],
+														channel_id: ChannelId([0; 32]),
 														data: format!("Unreadable/bogus gossip message of type {}", ty),
 													});
 													continue;
@@ -1593,7 +1593,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 			wire::Message::Error(msg) => {
 				log_debug!(self.logger, "Got Err message from {}: {}", log_pubkey!(their_node_id), PrintableString(&msg.data));
 				self.message_handler.chan_handler.handle_error(&their_node_id, &msg);
-				if msg.channel_id == [0; 32] {
+				if msg.channel_id.0 == [0; 32] {
 					return Err(PeerHandleError { }.into());
 				}
 			},
@@ -1914,31 +1914,31 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 						MessageSendEvent::SendAcceptChannel { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendAcceptChannel event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.temporary_channel_id));
+									log_bytes!(msg.temporary_channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendAcceptChannelV2 { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendAcceptChannelV2 event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.temporary_channel_id));
+									log_bytes!(msg.temporary_channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendOpenChannel { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendOpenChannel event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.temporary_channel_id));
+									log_bytes!(msg.temporary_channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendOpenChannelV2 { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendOpenChannelV2 event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.temporary_channel_id));
+									log_bytes!(msg.temporary_channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendFundingCreated { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendFundingCreated event in peer_handler for node {} for channel {} (which becomes {})",
 									log_pubkey!(node_id),
-									log_bytes!(msg.temporary_channel_id),
+									log_bytes!(msg.temporary_channel_id.0),
 									log_funding_channel_id!(msg.funding_txid, msg.funding_output_index));
 							// TODO: If the peer is gone we should generate a DiscardFunding event
 							// indicating to the wallet that they should just throw away this funding transaction
@@ -1947,73 +1947,73 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 						MessageSendEvent::SendFundingSigned { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendFundingSigned event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendChannelReady { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendChannelReady event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxAddInput { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxAddInput event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxAddOutput { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxAddOutput event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxRemoveInput { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxRemoveInput event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxRemoveOutput { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxRemoveOutput event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxComplete { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxComplete event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxSignatures { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxSignatures event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxInitRbf { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxInitRbf event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxAckRbf { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxAckRbf event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendTxAbort { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendTxAbort event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendAnnouncementSignatures { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendAnnouncementSignatures event in peer_handler for node {} for channel {})",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::UpdateHTLCs { ref node_id, updates: msgs::CommitmentUpdate { ref update_add_htlcs, ref update_fulfill_htlcs, ref update_fail_htlcs, ref update_fail_malformed_htlcs, ref update_fee, ref commitment_signed } } => {
@@ -2022,7 +2022,7 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 									update_add_htlcs.len(),
 									update_fulfill_htlcs.len(),
 									update_fail_htlcs.len(),
-									log_bytes!(commitment_signed.channel_id));
+									log_bytes!(commitment_signed.channel_id.0));
 							let mut peer = get_peer_for_forwarding!(node_id);
 							for msg in update_add_htlcs {
 								self.enqueue_message(&mut *peer, msg);
@@ -2044,25 +2044,25 @@ impl<Descriptor: SocketDescriptor, CM: Deref, RM: Deref, OM: Deref, L: Deref, CM
 						MessageSendEvent::SendRevokeAndACK { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendRevokeAndACK event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendClosingSigned { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendClosingSigned event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendShutdown { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling Shutdown event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendChannelReestablish { ref node_id, ref msg } => {
 							log_debug!(self.logger, "Handling SendChannelReestablish event in peer_handler for node {} for channel {}",
 									log_pubkey!(node_id),
-									log_bytes!(msg.channel_id));
+									log_bytes!(msg.channel_id.0));
 							self.enqueue_message(&mut *get_peer_for_forwarding!(node_id), msg);
 						},
 						MessageSendEvent::SendChannelAnnouncement { ref node_id, ref msg, ref update_msg } => {
@@ -2483,6 +2483,7 @@ mod tests {
 	use crate::sign::{NodeSigner, Recipient};
 	use crate::events;
 	use crate::io;
+	use crate::ln::channel::ChannelId;
 	use crate::ln::features::{InitFeatures, NodeFeatures};
 	use crate::ln::peer_channel_encryptor::PeerChannelEncryptor;
 	use crate::ln::peer_handler::{CustomMessageHandler, PeerManager, MessageHandler, SocketDescriptor, IgnoringMessageHandler, filter_addresses};
@@ -2722,7 +2723,7 @@ mod tests {
 							.push(crate::events::MessageSendEvent::SendShutdown {
 								node_id: peers[1].node_signer.get_node_id(Recipient::Node).unwrap(),
 								msg: msgs::Shutdown {
-									channel_id: [0; 32],
+									channel_id: ChannelId([0; 32]),
 									scriptpubkey: bitcoin::Script::new(),
 								},
 							});
@@ -2730,7 +2731,7 @@ mod tests {
 							.push(crate::events::MessageSendEvent::SendShutdown {
 								node_id: peers[0].node_signer.get_node_id(Recipient::Node).unwrap(),
 								msg: msgs::Shutdown {
-									channel_id: [0; 32],
+									channel_id: ChannelId([0; 32]),
 									scriptpubkey: bitcoin::Script::new(),
 								},
 							});
@@ -2859,7 +2860,7 @@ mod tests {
 
 		let their_id = peers[1].node_signer.get_node_id(Recipient::Node).unwrap();
 
-		let msg = msgs::Shutdown { channel_id: [42; 32], scriptpubkey: bitcoin::Script::new() };
+		let msg = msgs::Shutdown { channel_id: ChannelId([42; 32]), scriptpubkey: bitcoin::Script::new() };
 		a_chan_handler.pending_events.lock().unwrap().push(events::MessageSendEvent::SendShutdown {
 			node_id: their_id, msg: msg.clone()
 		});
diff --git a/lightning/src/routing/gossip.rs b/lightning/src/routing/gossip.rs
index b9b70e0a031..98e1e98a95e 100644
--- a/lightning/src/routing/gossip.rs
+++ b/lightning/src/routing/gossip.rs
@@ -23,6 +23,7 @@ use bitcoin::network::constants::Network;
 use bitcoin::blockdata::constants::genesis_block;
 
 use crate::events::{MessageSendEvent, MessageSendEventsProvider};
+use crate::ln::channel::ChannelId;
 use crate::ln::features::{ChannelFeatures, NodeFeatures, InitFeatures};
 use crate::ln::msgs::{DecodeError, ErrorAction, Init, LightningError, RoutingMessageHandler, NetAddress, MAX_VALUE_MSAT};
 use crate::ln::msgs::{ChannelAnnouncement, ChannelUpdate, NodeAnnouncement, GossipTimestampFilter};
@@ -382,7 +383,7 @@ macro_rules! secp_verify_sig {
 					err: format!("Invalid signature on {} message", $msg_type),
 					action: ErrorAction::SendWarningMessage {
 						msg: msgs::WarningMessage {
-							channel_id: [0; 32],
+							channel_id: ChannelId([0; 32]),
 							data: format!("Invalid signature on {} message", $msg_type),
 						},
 						log_level: Level::Trace,
@@ -400,7 +401,7 @@ macro_rules! get_pubkey_from_node_id {
 				err: format!("Invalid public key on {} message", $msg_type),
 				action: ErrorAction::SendWarningMessage {
 					msg: msgs::WarningMessage {
-						channel_id: [0; 32],
+						channel_id: ChannelId([0; 32]),
 						data: format!("Invalid public key on {} message", $msg_type),
 					},
 					log_level: Level::Trace
diff --git a/lightning/src/routing/router.rs b/lightning/src/routing/router.rs
index 3419f122e7d..5a09988d832 100644
--- a/lightning/src/routing/router.rs
+++ b/lightning/src/routing/router.rs
@@ -2676,6 +2676,7 @@ mod tests {
 	use crate::routing::test_utils::{add_channel, add_or_update_node, build_graph, build_line_graph, id_to_feature_flags, get_nodes, update_channel};
 	use crate::chain::transaction::OutPoint;
 	use crate::sign::EntropySource;
+	use crate::ln::channel::ChannelId;
 	use crate::ln::features::{BlindedHopFeatures, Bolt12InvoiceFeatures, ChannelFeatures, InitFeatures, NodeFeatures};
 	use crate::ln::msgs::{ErrorAction, LightningError, UnsignedChannelUpdate, MAX_VALUE_MSAT};
 	use crate::ln::channelmanager;
@@ -2708,7 +2709,7 @@ mod tests {
 	fn get_channel_details(short_channel_id: Option<u64>, node_id: PublicKey,
 			features: InitFeatures, outbound_capacity_msat: u64) -> channelmanager::ChannelDetails {
 		channelmanager::ChannelDetails {
-			channel_id: [0; 32],
+			channel_id: ChannelId([0; 32]),
 			counterparty: channelmanager::ChannelCounterparty {
 				features,
 				node_id,
@@ -6722,6 +6723,7 @@ pub(crate) mod bench_utils {
 
 	use crate::chain::transaction::OutPoint;
 	use crate::sign::{EntropySource, KeysManager};
+	use crate::ln::channel::ChannelId;
 	use crate::ln::channelmanager::{self, ChannelCounterparty, ChannelDetails};
 	use crate::ln::features::Bolt11InvoiceFeatures;
 	use crate::routing::gossip::NetworkGraph;
@@ -6775,7 +6777,7 @@ pub(crate) mod bench_utils {
 	#[inline]
 	pub(crate) fn first_hop(node_id: PublicKey) -> ChannelDetails {
 		ChannelDetails {
-			channel_id: [0; 32],
+			channel_id: ChannelId([0; 32]),
 			counterparty: ChannelCounterparty {
 				features: channelmanager::provided_init_features(&UserConfig::default()),
 				node_id,
diff --git a/lightning/src/util/macro_logger.rs b/lightning/src/util/macro_logger.rs
index e7998037034..5da15934535 100644
--- a/lightning/src/util/macro_logger.rs
+++ b/lightning/src/util/macro_logger.rs
@@ -42,7 +42,7 @@ macro_rules! log_bytes {
 pub(crate) struct DebugFundingChannelId<'a>(pub &'a Txid, pub u16);
 impl<'a> core::fmt::Display for DebugFundingChannelId<'a> {
 	fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
-		for i in (OutPoint { txid: self.0.clone(), index: self.1 }).to_channel_id().iter() {
+		for i in (OutPoint { txid: self.0.clone(), index: self.1 }).to_channel_id().0.iter() {
 			write!(f, "{:02x}", i)?;
 		}
 		Ok(())
@@ -57,7 +57,7 @@ macro_rules! log_funding_channel_id {
 pub(crate) struct DebugFundingInfo<'a, T: 'a>(pub &'a (OutPoint, T));
 impl<'a, T> core::fmt::Display for DebugFundingInfo<'a, T> {
 	fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
-		DebugBytes(&(self.0).0.to_channel_id()[..]).fmt(f)
+		DebugBytes(&(self.0).0.to_channel_id().0[..]).fmt(f)
 	}
 }
 macro_rules! log_funding_info {
diff --git a/lightning/src/util/test_utils.rs b/lightning/src/util/test_utils.rs
index ee3f19c6581..90353bc42ae 100644
--- a/lightning/src/util/test_utils.rs
+++ b/lightning/src/util/test_utils.rs
@@ -192,14 +192,14 @@ impl SignerProvider for OnlyReadsKeysInterface {
 
 pub struct TestChainMonitor<'a> {
 	pub added_monitors: Mutex<Vec<(OutPoint, channelmonitor::ChannelMonitor<EnforcingSigner>)>>,
-	pub monitor_updates: Mutex<HashMap<[u8; 32], Vec<channelmonitor::ChannelMonitorUpdate>>>,
-	pub latest_monitor_update_id: Mutex<HashMap<[u8; 32], (OutPoint, u64, MonitorUpdateId)>>,
+	pub monitor_updates: Mutex<HashMap<ChannelId, Vec<channelmonitor::ChannelMonitorUpdate>>>,
+	pub latest_monitor_update_id: Mutex<HashMap<ChannelId, (OutPoint, u64, MonitorUpdateId)>>,
 	pub chain_monitor: chainmonitor::ChainMonitor<EnforcingSigner, &'a TestChainSource, &'a chaininterface::BroadcasterInterface, &'a TestFeeEstimator, &'a TestLogger, &'a chainmonitor::Persist<EnforcingSigner>>,
 	pub keys_manager: &'a TestKeysInterface,
 	/// If this is set to Some(), the next update_channel call (not watch_channel) must be a
 	/// ChannelForceClosed event for the given channel_id with should_broadcast set to the given
 	/// boolean.
-	pub expect_channel_force_closed: Mutex<Option<([u8; 32], bool)>>,
+	pub expect_channel_force_closed: Mutex<Option<(ChannelId, bool)>>,
 }
 impl<'a> TestChainMonitor<'a> {
 	pub fn new(chain_source: Option<&'a TestChainSource>, broadcaster: &'a chaininterface::BroadcasterInterface, logger: &'a TestLogger, fee_estimator: &'a TestFeeEstimator, persister: &'a chainmonitor::Persist<EnforcingSigner>, keys_manager: &'a TestKeysInterface) -> Self {

From 22e915f9338c9a0a61639a860f3f2d65f4052db1 Mon Sep 17 00:00:00 2001
From: optout <13562139+optout21@users.noreply.github.com>
Date: Tue, 25 Jul 2023 16:51:55 +0200
Subject: [PATCH 3/5] Test compile fix

---
 lightning/src/ln/channelmanager.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs
index efd846f59d7..eab85c28d7e 100644
--- a/lightning/src/ln/channelmanager.rs
+++ b/lightning/src/ln/channelmanager.rs
@@ -10242,7 +10242,7 @@ mod tests {
 
 		// If we provide a channel_id not associated with the peer, we should get an error and no updates
 		// should be applied to ensure update atomicity as specified in the API docs.
-		let bad_channel_id = [10; 32];
+		let bad_channel_id = ChannelId([10; 32]);
 		let current_fee = nodes[0].node.list_channels()[0].config.unwrap().forwarding_fee_proportional_millionths;
 		let new_fee = current_fee + 100;
 		assert!(

From 736a7b11990ab919aad56af85179cf852718f9e6 Mon Sep 17 00:00:00 2001
From: optout <13562139+optout21@users.noreply.github.com>
Date: Tue, 25 Jul 2023 17:32:24 +0200
Subject: [PATCH 4/5] Fix for 'use std::'

---
 lightning/src/ln/channel.rs | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/lightning/src/ln/channel.rs b/lightning/src/ln/channel.rs
index 2f56e53b4e6..ab8ad10f6c9 100644
--- a/lightning/src/ln/channel.rs
+++ b/lightning/src/ln/channel.rs
@@ -51,7 +51,6 @@ use core::ops::Deref;
 #[cfg(any(test, fuzzing, debug_assertions))]
 use crate::sync::Mutex;
 use bitcoin::hashes::hex::ToHex;
-use std::io::Read;
 
 #[cfg(test)]
 pub struct ChannelValueStat {
@@ -623,7 +622,7 @@ impl Writeable for ChannelId {
 }
 
 impl Readable for ChannelId {
-	fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+	fn read<R: io::Read>(r: &mut R) -> Result<Self, DecodeError> {
 		let buf: [u8; 32] = Readable::read(r)?;
 		Ok(ChannelId(buf))
 	}

From 7d6eed2b1d15b3059f344aee5094e77fe8ac9969 Mon Sep 17 00:00:00 2001
From: optout <13562139+optout21@users.noreply.github.com>
Date: Tue, 25 Jul 2023 18:46:56 +0200
Subject: [PATCH 5/5] Fix for fuzz

---
 fuzz/src/full_stack.rs | 3 ++-
 fuzz/src/router.rs     | 1 +
 2 files changed, 3 insertions(+), 1 deletion(-)

diff --git a/fuzz/src/full_stack.rs b/fuzz/src/full_stack.rs
index 1fbd7dbec88..ff8775395d1 100644
--- a/fuzz/src/full_stack.rs
+++ b/fuzz/src/full_stack.rs
@@ -35,6 +35,7 @@ use lightning::chain::transaction::OutPoint;
 use lightning::sign::{InMemorySigner, Recipient, KeyMaterial, EntropySource, NodeSigner, SignerProvider};
 use lightning::events::Event;
 use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
+use lightning::ln::channel::ChannelId;
 use lightning::ln::channelmanager::{ChainParameters, ChannelDetails, ChannelManager, PaymentId, RecipientOnionFields, Retry};
 use lightning::ln::peer_handler::{MessageHandler,PeerManager,SocketDescriptor,IgnoringMessageHandler};
 use lightning::ln::msgs::{self, DecodeError};
@@ -466,7 +467,7 @@ pub fn do_test(data: &[u8], logger: &Arc<dyn Logger>) {
 	let mut should_forward = false;
 	let mut payments_received: Vec<PaymentHash> = Vec::new();
 	let mut payments_sent = 0;
-	let mut pending_funding_generation: Vec<([u8; 32], PublicKey, u64, Script)> = Vec::new();
+	let mut pending_funding_generation: Vec<(ChannelId, PublicKey, u64, Script)> = Vec::new();
 	let mut pending_funding_signatures = HashMap::new();
 
 	loop {
diff --git a/fuzz/src/router.rs b/fuzz/src/router.rs
index 5fa505b5395..abcb969623b 100644
--- a/fuzz/src/router.rs
+++ b/fuzz/src/router.rs
@@ -12,6 +12,7 @@ use bitcoin::blockdata::transaction::TxOut;
 use bitcoin::hash_types::BlockHash;
 
 use lightning::chain::transaction::OutPoint;
+use lightning::ln::channel::ChannelId;
 use lightning::ln::channelmanager::{self, ChannelDetails, ChannelCounterparty};
 use lightning::ln::msgs;
 use lightning::routing::gossip::{NetworkGraph, RoutingFees};