Merge pull request #2371 from jkczyz/2023-06-offer-message-handling
[rust-lightning] / lightning / src / ln / msgs.rs
index 515dcbba2d2e136846697dc990d582270e07e1d4..d12dafb65af8e92780373b4b1f7c4b03fd8ee154 100644 (file)
@@ -31,21 +31,23 @@ use bitcoin::{secp256k1, Witness};
 use bitcoin::blockdata::script::Script;
 use bitcoin::hash_types::{Txid, BlockHash};
 
+use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret};
 use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 use crate::ln::onion_utils;
 use crate::onion_message;
 
 use crate::prelude::*;
+use core::convert::TryFrom;
 use core::fmt;
 use core::fmt::Debug;
+use core::str::FromStr;
 use crate::io::{self, Read};
 use crate::io_extras::read_to_end;
 
 use crate::events::{MessageSendEventsProvider, OnionMessageProvider};
 use crate::util::logger;
 use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
-
-use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+use crate::util::base32;
 
 use crate::routing::gossip::{NodeAlias, NodeId};
 
@@ -111,7 +113,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 +130,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 +173,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 +227,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 +284,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 +332,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 +385,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 +408,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 +422,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 +438,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 +457,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 +473,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 +484,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 +496,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 +506,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 +520,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 +537,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 +549,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 +560,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 +587,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 +603,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 +636,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 +649,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 +661,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 +675,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 +691,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 +707,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 +718,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 +738,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
@@ -900,6 +902,104 @@ impl Readable for NetAddress {
        }
 }
 
+/// [`NetAddress`] error variants
+#[derive(Debug, Eq, PartialEq, Clone)]
+pub enum NetAddressParseError {
+       /// Socket address (IPv4/IPv6) parsing error
+       SocketAddrParse,
+       /// Invalid input format
+       InvalidInput,
+       /// Invalid port
+       InvalidPort,
+       /// Invalid onion v3 address
+       InvalidOnionV3,
+}
+
+impl fmt::Display for NetAddressParseError {
+       fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+               match self {
+                       NetAddressParseError::SocketAddrParse => write!(f, "Socket address (IPv4/IPv6) parsing error"),
+                       NetAddressParseError::InvalidInput => write!(f, "Invalid input format. \
+                               Expected: \"<ipv4>:<port>\", \"[<ipv6>]:<port>\", \"<onion address>.onion:<port>\" or \"<hostname>:<port>\""),
+                       NetAddressParseError::InvalidPort => write!(f, "Invalid port"),
+                       NetAddressParseError::InvalidOnionV3 => write!(f, "Invalid onion v3 address"),
+               }
+       }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddrV4> for NetAddress {
+               fn from(addr: std::net::SocketAddrV4) -> Self {
+                       NetAddress::IPv4 { addr: addr.ip().octets(), port: addr.port() }
+               }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddrV6> for NetAddress {
+               fn from(addr: std::net::SocketAddrV6) -> Self {
+                       NetAddress::IPv6 { addr: addr.ip().octets(), port: addr.port() }
+               }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddr> for NetAddress {
+               fn from(addr: std::net::SocketAddr) -> Self {
+                       match addr {
+                               std::net::SocketAddr::V4(addr) => addr.into(),
+                               std::net::SocketAddr::V6(addr) => addr.into(),
+                       }
+               }
+}
+
+fn parse_onion_address(host: &str, port: u16) -> Result<NetAddress, NetAddressParseError> {
+       if host.ends_with(".onion") {
+               let domain = &host[..host.len() - ".onion".len()];
+               if domain.len() != 56 {
+                       return Err(NetAddressParseError::InvalidOnionV3);
+               }
+               let onion =  base32::Alphabet::RFC4648 { padding: false }.decode(&domain).map_err(|_| NetAddressParseError::InvalidOnionV3)?;
+               if onion.len() != 35 {
+                       return Err(NetAddressParseError::InvalidOnionV3);
+               }
+               let version = onion[0];
+               let first_checksum_flag = onion[1];
+               let second_checksum_flag = onion[2];
+               let mut ed25519_pubkey = [0; 32];
+               ed25519_pubkey.copy_from_slice(&onion[3..35]);
+               let checksum = u16::from_be_bytes([first_checksum_flag, second_checksum_flag]);
+               return Ok(NetAddress::OnionV3 { ed25519_pubkey, checksum, version, port });
+
+       } else {
+               return Err(NetAddressParseError::InvalidInput);
+       }
+}
+
+#[cfg(feature = "std")]
+impl FromStr for NetAddress {
+       type Err = NetAddressParseError;
+
+       fn from_str(s: &str) -> Result<Self, Self::Err> {
+               match std::net::SocketAddr::from_str(s) {
+                       Ok(addr) => Ok(addr.into()),
+                       Err(_) => {
+                               let trimmed_input = match s.rfind(":") {
+                                       Some(pos) => pos,
+                                       None => return Err(NetAddressParseError::InvalidInput),
+                               };
+                               let host = &s[..trimmed_input];
+                               let port: u16 = s[trimmed_input + 1..].parse().map_err(|_| NetAddressParseError::InvalidPort)?;
+                               if host.ends_with(".onion") {
+                                       return parse_onion_address(host, port);
+                               };
+                               if let Ok(hostname) = Hostname::try_from(s[..trimmed_input].to_string()) {
+                                       return Ok(NetAddress::Hostname { hostname, port });
+                               };
+                               return Err(NetAddressParseError::SocketAddrParse)
+                       },
+               }
+       }
+}
+
 /// Represents the set of gossip messages that require a signature from a node's identity key.
 pub enum UnsignedGossipMessage<'a> {
        /// An unsigned channel announcement.
@@ -1144,7 +1244,7 @@ enum EncodingType {
 }
 
 /// Used to put an error message in a [`LightningError`].
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
 pub enum ErrorAction {
        /// The peer took some action which made us think they were useless. Disconnect them.
        DisconnectPeer {
@@ -1230,7 +1330,7 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider {
        /// Handle an incoming `channel_ready` message from the given peer.
        fn handle_channel_ready(&self, their_node_id: &PublicKey, msg: &ChannelReady);
 
-       // Channl close:
+       // Channel close:
        /// Handle an incoming `shutdown` message from the given peer.
        fn handle_shutdown(&self, their_node_id: &PublicKey, msg: &Shutdown);
        /// Handle an incoming `closing_signed` message from the given peer.
@@ -2472,12 +2572,15 @@ impl_writeable_msg!(GossipTimestampFilter, {
 
 #[cfg(test)]
 mod tests {
+       use std::convert::TryFrom;
        use bitcoin::blockdata::constants::ChainHash;
        use bitcoin::{Transaction, PackedLockTime, TxIn, Script, Sequence, Witness, TxOut};
        use hex;
        use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+       use crate::ln::ChannelId;
        use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
        use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket};
+       use crate::ln::msgs::NetAddress;
        use crate::routing::gossip::{NodeAlias, NodeId};
        use crate::util::ser::{Writeable, Readable, Hostname, TransactionU16LenLimited};
 
@@ -2493,11 +2596,13 @@ mod tests {
 
        use crate::io::{self, Cursor};
        use crate::prelude::*;
-       use core::convert::TryFrom;
        use core::str::FromStr;
-
        use crate::chain::transaction::OutPoint;
 
+       #[cfg(feature = "std")]
+       use std::net::{Ipv4Addr, Ipv6Addr};
+       use crate::ln::msgs::NetAddressParseError;
+
        #[test]
        fn encoding_channel_reestablish() {
                let public_key = {
@@ -2506,7 +2611,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::from_bytes([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],
@@ -2535,7 +2640,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::from_bytes([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],
@@ -2587,7 +2692,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::from_bytes([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,
@@ -2663,24 +2768,24 @@ mod tests {
                };
                let mut addresses = Vec::new();
                if ipv4 {
-                       addresses.push(msgs::NetAddress::IPv4 {
+                       addresses.push(NetAddress::IPv4 {
                                addr: [255, 254, 253, 252],
                                port: 9735
                        });
                }
                if ipv6 {
-                       addresses.push(msgs::NetAddress::IPv6 {
+                       addresses.push(NetAddress::IPv6 {
                                addr: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240],
                                port: 9735
                        });
                }
                if onionv2 {
-                       addresses.push(msgs::NetAddress::OnionV2(
+                       addresses.push(NetAddress::OnionV2(
                                [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]
                        ));
                }
                if onionv3 {
-                       addresses.push(msgs::NetAddress::OnionV3 {
+                       addresses.push(NetAddress::OnionV3 {
                                ed25519_pubkey: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 245, 244, 243, 242, 241, 240, 239, 238, 237, 236, 235, 234, 233, 232, 231, 230, 229, 228, 227, 226, 225, 224],
                                checksum: 32,
                                version: 16,
@@ -2688,7 +2793,7 @@ mod tests {
                        });
                }
                if hostname {
-                       addresses.push(msgs::NetAddress::Hostname {
+                       addresses.push(NetAddress::Hostname {
                                hostname: Hostname::try_from(String::from("host")).unwrap(),
                                port: 9735,
                        });
@@ -2823,7 +2928,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::from_bytes([2; 32]),
                        funding_satoshis: 1311768467284833366,
                        push_msat: 2536655962884945560,
                        dust_limit_satoshis: 3608586615801332854,
@@ -2884,7 +2989,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::from_bytes([2; 32]),
                        funding_feerate_sat_per_1000_weight: 821716,
                        commitment_feerate_sat_per_1000_weight: 821716,
                        funding_satoshis: 1311768467284833366,
@@ -2974,7 +3079,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::from_bytes([2; 32]),
                        dust_limit_satoshis: 1311768467284833366,
                        max_htlc_value_in_flight_msat: 2536655962884945560,
                        channel_reserve_satoshis: 3608586615801332854,
@@ -3017,7 +3122,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::from_bytes([2; 32]),
                        funding_satoshis: 1311768467284833366,
                        dust_limit_satoshis: 1311768467284833366,
                        max_htlc_value_in_flight_msat: 2536655962884945560,
@@ -3071,7 +3176,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::from_bytes([2; 32]),
                        funding_txid: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
                        funding_output_index: 255,
                        signature: sig_1,
@@ -3091,7 +3196,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::from_bytes([2; 32]),
                        signature: sig_1,
                        #[cfg(taproot)]
                        partial_signature_with_nonce: None,
@@ -3106,7 +3211,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::from_bytes([2; 32]),
                        next_per_commitment_point: pubkey_1,
                        short_channel_id_alias: None,
                };
@@ -3118,7 +3223,7 @@ mod tests {
        #[test]
        fn encoding_tx_add_input() {
                let tx_add_input = msgs::TxAddInput {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        serial_id: 4886718345,
                        prevtx: TransactionU16LenLimited::new(Transaction {
                                version: 2,
@@ -3153,7 +3258,7 @@ mod tests {
        #[test]
        fn encoding_tx_add_output() {
                let tx_add_output = msgs::TxAddOutput {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        serial_id: 4886718345,
                        sats: 4886718345,
                        script: Address::from_str("bc1qxmk834g5marzm227dgqvynd23y2nvt2ztwcw2z").unwrap().script_pubkey(),
@@ -3166,7 +3271,7 @@ mod tests {
        #[test]
        fn encoding_tx_remove_input() {
                let tx_remove_input = msgs::TxRemoveInput {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        serial_id: 4886718345,
                };
                let encoded_value = tx_remove_input.encode();
@@ -3177,7 +3282,7 @@ mod tests {
        #[test]
        fn encoding_tx_remove_output() {
                let tx_remove_output = msgs::TxRemoveOutput {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        serial_id: 4886718345,
                };
                let encoded_value = tx_remove_output.encode();
@@ -3188,7 +3293,7 @@ mod tests {
        #[test]
        fn encoding_tx_complete() {
                let tx_complete = msgs::TxComplete {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                };
                let encoded_value = tx_complete.encode();
                let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap();
@@ -3198,7 +3303,7 @@ mod tests {
        #[test]
        fn encoding_tx_signatures() {
                let tx_signatures = msgs::TxSignatures {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        tx_hash: Txid::from_hex("c2d4449afa8d26140898dd54d3390b057ba2a5afcf03ba29d7dc0d8b9ffe966e").unwrap(),
                        witnesses: vec![
                                Witness::from_vec(vec![
@@ -3232,7 +3337,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::from_bytes([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 },
@@ -3258,7 +3363,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::from_bytes([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();
@@ -3281,7 +3386,7 @@ mod tests {
        #[test]
        fn encoding_tx_abort() {
                let tx_abort = msgs::TxAbort {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        data: hex::decode("54686520717569636B2062726F776E20666F78206A756D7073206F76657220746865206C617A7920646F672E").unwrap(),
                };
                let encoded_value = tx_abort.encode();
@@ -3294,12 +3399,12 @@ 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::from_bytes([2; 32]),
                        scriptpubkey:
-                                    if script_type == 1 { Address::p2pkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).script_pubkey() }
+                               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() }
                                else if script_type == 3 { Address::p2wpkh(&::bitcoin::PublicKey{compressed: true, inner: pubkey_1}, Network::Testnet).unwrap().script_pubkey() }
-                               else                     { Address::p2wsh(&script, Network::Testnet).script_pubkey() },
+                               else { Address::p2wsh(&script, Network::Testnet).script_pubkey() },
                };
                let encoded_value = shutdown.encode();
                let mut target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap();
@@ -3329,7 +3434,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::from_bytes([2; 32]),
                        fee_satoshis: 2316138423780173,
                        signature: sig_1,
                        fee_range: None,
@@ -3340,7 +3445,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::from_bytes([2; 32]),
                        fee_satoshis: 2316138423780173,
                        signature: sig_1,
                        fee_range: Some(msgs::ClosingSignedFeeRange {
@@ -3366,7 +3471,7 @@ mod tests {
                        hmac: [2; 32]
                };
                let update_add_htlc = msgs::UpdateAddHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        amount_msat: 3608586615801332854,
                        payment_hash: PaymentHash([1; 32]),
@@ -3382,7 +3487,7 @@ mod tests {
        #[test]
        fn encoding_update_fulfill_htlc() {
                let update_fulfill_htlc = msgs::UpdateFulfillHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        payment_preimage: PaymentPreimage([1; 32]),
                };
@@ -3397,7 +3502,7 @@ mod tests {
                        data: [1; 32].to_vec(),
                };
                let update_fail_htlc = msgs::UpdateFailHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        reason
                };
@@ -3409,7 +3514,7 @@ mod tests {
        #[test]
        fn encoding_update_fail_malformed_htlc() {
                let update_fail_malformed_htlc = msgs::UpdateFailMalformedHTLC {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        htlc_id: 2316138423780173,
                        sha256_of_onion: [1; 32],
                        failure_code: 255
@@ -3430,7 +3535,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::from_bytes([2; 32]),
                        signature: sig_1,
                        htlc_signatures: if htlcs { vec![sig_2, sig_3, sig_4] } else { Vec::new() },
                        #[cfg(taproot)]
@@ -3457,7 +3562,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::from_bytes([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)]
@@ -3471,7 +3576,7 @@ mod tests {
        #[test]
        fn encoding_update_fee() {
                let update_fee = msgs::UpdateFee {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        feerate_per_kw: 20190119,
                };
                let encoded_value = update_fee.encode();
@@ -3504,7 +3609,7 @@ mod tests {
                }.encode(), hex::decode("00000000014001010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap());
                let init_msg = msgs::Init { features: InitFeatures::from_le_bytes(vec![]),
                        networks: Some(vec![mainnet_hash]),
-                       remote_network_address: Some(msgs::NetAddress::IPv4 {
+                       remote_network_address: Some(NetAddress::IPv4 {
                                addr: [127, 0, 0, 1],
                                port: 1000,
                        }),
@@ -3518,7 +3623,7 @@ mod tests {
        #[test]
        fn encoding_error() {
                let error = msgs::ErrorMessage {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        data: String::from("rust-lightning"),
                };
                let encoded_value = error.encode();
@@ -3529,7 +3634,7 @@ mod tests {
        #[test]
        fn encoding_warning() {
                let error = msgs::WarningMessage {
-                       channel_id: [2; 32],
+                       channel_id: ChannelId::from_bytes([2; 32]),
                        data: String::from("rust-lightning"),
                };
                let encoded_value = error.encode();
@@ -3869,4 +3974,47 @@ mod tests {
                }
                Ok(encoded_payload)
        }
+
+       #[test]
+       #[cfg(feature = "std")]
+       fn test_net_address_from_str() {
+               assert_eq!(NetAddress::IPv4 {
+                       addr: Ipv4Addr::new(127, 0, 0, 1).octets(),
+                       port: 1234,
+               }, NetAddress::from_str("127.0.0.1:1234").unwrap());
+
+               assert_eq!(NetAddress::IPv6 {
+                       addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).octets(),
+                       port: 1234,
+               }, NetAddress::from_str("[0:0:0:0:0:0:0:1]:1234").unwrap());
+               assert_eq!(
+                       NetAddress::Hostname {
+                               hostname: Hostname::try_from("lightning-node.mydomain.com".to_string()).unwrap(),
+                               port: 1234,
+                       }, NetAddress::from_str("lightning-node.mydomain.com:1234").unwrap());
+               assert_eq!(
+                       NetAddress::Hostname {
+                               hostname: Hostname::try_from("example.com".to_string()).unwrap(),
+                               port: 1234,
+                       }, NetAddress::from_str("example.com:1234").unwrap());
+               assert_eq!(NetAddress::OnionV3 {
+                       ed25519_pubkey: [37, 24, 75, 5, 25, 73, 117, 194, 139, 102, 182, 107, 4, 105, 247, 246, 85,
+                       111, 177, 172, 49, 137, 167, 155, 64, 221, 163, 47, 31, 33, 71, 3],
+                       checksum: 48326,
+                       version: 121,
+                       port: 1234
+               }, NetAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap());
+               assert_eq!(Err(NetAddressParseError::InvalidOnionV3), NetAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234"));
+               assert_eq!(Err(NetAddressParseError::InvalidInput), NetAddress::from_str("127.0.0.1@1234"));
+               assert_eq!(Err(NetAddressParseError::InvalidInput), "".parse::<NetAddress>());
+               assert!(NetAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94").is_err());
+               assert!(NetAddress::from_str("wrong$%#.com:1234").is_err());
+               assert_eq!(Err(NetAddressParseError::InvalidPort), NetAddress::from_str("example.com:wrong"));
+               assert!("localhost".parse::<NetAddress>().is_err());
+               assert!("localhost:invalid-port".parse::<NetAddress>().is_err());
+               assert!( "invalid-onion-v3-hostname.onion:8080".parse::<NetAddress>().is_err());
+               assert!("b32.example.onion:invalid-port".parse::<NetAddress>().is_err());
+               assert!("invalid-address".parse::<NetAddress>().is_err());
+               assert!(NetAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:1234").is_err());
+       }
 }