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};
/// message. A node can decide to use that information to discover a potential update to its
/// public IPv4 address (NAT) and use that for a [`NodeAnnouncement`] update message containing
/// the new address.
- pub remote_network_address: Option<NetAddress>,
+ pub remote_network_address: Option<SocketAddress>,
}
/// An [`error`] message to be sent to or received from a peer.
///
/// 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
/// 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
/// 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
/// 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
#[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
#[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
#[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
#[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)]
#[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.
#[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,
#[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,
#[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,
}
#[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,
}
#[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
#[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
#[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
#[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>,
#[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>,
}
#[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.
#[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
#[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
#[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
#[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,
#[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],
#[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
#[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
#[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,
}
#[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
#[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
/// An address which can be used to connect to a remote peer.
#[derive(Clone, Debug, PartialEq, Eq)]
-pub enum NetAddress {
- /// An IPv4 address/port on which the peer is listening.
- IPv4 {
+pub enum SocketAddress {
+ /// An IPv4 address and port on which the peer is listening.
+ TcpIpV4 {
/// The 4-byte IPv4 address
addr: [u8; 4],
/// The port on which the node is listening
port: u16,
},
- /// An IPv6 address/port on which the peer is listening.
- IPv6 {
+ /// An IPv6 address and port on which the peer is listening.
+ TcpIpV6 {
/// The 16-byte IPv6 address
addr: [u8; 16],
/// The port on which the node is listening
port: u16,
},
}
-impl NetAddress {
+impl SocketAddress {
/// Gets the ID of this address type. Addresses in [`NodeAnnouncement`] messages should be sorted
/// by this.
pub(crate) fn get_id(&self) -> u8 {
match self {
- &NetAddress::IPv4 {..} => { 1 },
- &NetAddress::IPv6 {..} => { 2 },
- &NetAddress::OnionV2(_) => { 3 },
- &NetAddress::OnionV3 {..} => { 4 },
- &NetAddress::Hostname {..} => { 5 },
+ &SocketAddress::TcpIpV4 {..} => { 1 },
+ &SocketAddress::TcpIpV6 {..} => { 2 },
+ &SocketAddress::OnionV2(_) => { 3 },
+ &SocketAddress::OnionV3 {..} => { 4 },
+ &SocketAddress::Hostname {..} => { 5 },
}
}
/// Strict byte-length of address descriptor, 1-byte type not recorded
fn len(&self) -> u16 {
match self {
- &NetAddress::IPv4 { .. } => { 6 },
- &NetAddress::IPv6 { .. } => { 18 },
- &NetAddress::OnionV2(_) => { 12 },
- &NetAddress::OnionV3 { .. } => { 37 },
+ &SocketAddress::TcpIpV4 { .. } => { 6 },
+ &SocketAddress::TcpIpV6 { .. } => { 18 },
+ &SocketAddress::OnionV2(_) => { 12 },
+ &SocketAddress::OnionV3 { .. } => { 37 },
// Consists of 1-byte hostname length, hostname bytes, and 2-byte port.
- &NetAddress::Hostname { ref hostname, .. } => { u16::from(hostname.len()) + 3 },
+ &SocketAddress::Hostname { ref hostname, .. } => { u16::from(hostname.len()) + 3 },
}
}
pub(crate) const MAX_LEN: u16 = 258;
}
-impl Writeable for NetAddress {
+impl Writeable for SocketAddress {
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
match self {
- &NetAddress::IPv4 { ref addr, ref port } => {
+ &SocketAddress::TcpIpV4 { ref addr, ref port } => {
1u8.write(writer)?;
addr.write(writer)?;
port.write(writer)?;
},
- &NetAddress::IPv6 { ref addr, ref port } => {
+ &SocketAddress::TcpIpV6 { ref addr, ref port } => {
2u8.write(writer)?;
addr.write(writer)?;
port.write(writer)?;
},
- &NetAddress::OnionV2(bytes) => {
+ &SocketAddress::OnionV2(bytes) => {
3u8.write(writer)?;
bytes.write(writer)?;
},
- &NetAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
+ &SocketAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
4u8.write(writer)?;
ed25519_pubkey.write(writer)?;
checksum.write(writer)?;
version.write(writer)?;
port.write(writer)?;
},
- &NetAddress::Hostname { ref hostname, ref port } => {
+ &SocketAddress::Hostname { ref hostname, ref port } => {
5u8.write(writer)?;
hostname.write(writer)?;
port.write(writer)?;
}
}
-impl Readable for Result<NetAddress, u8> {
- fn read<R: Read>(reader: &mut R) -> Result<Result<NetAddress, u8>, DecodeError> {
+impl Readable for Result<SocketAddress, u8> {
+ fn read<R: Read>(reader: &mut R) -> Result<Result<SocketAddress, u8>, DecodeError> {
let byte = <u8 as Readable>::read(reader)?;
match byte {
1 => {
- Ok(Ok(NetAddress::IPv4 {
+ Ok(Ok(SocketAddress::TcpIpV4 {
addr: Readable::read(reader)?,
port: Readable::read(reader)?,
}))
},
2 => {
- Ok(Ok(NetAddress::IPv6 {
+ Ok(Ok(SocketAddress::TcpIpV6 {
addr: Readable::read(reader)?,
port: Readable::read(reader)?,
}))
},
- 3 => Ok(Ok(NetAddress::OnionV2(Readable::read(reader)?))),
+ 3 => Ok(Ok(SocketAddress::OnionV2(Readable::read(reader)?))),
4 => {
- Ok(Ok(NetAddress::OnionV3 {
+ Ok(Ok(SocketAddress::OnionV3 {
ed25519_pubkey: Readable::read(reader)?,
checksum: Readable::read(reader)?,
version: Readable::read(reader)?,
}))
},
5 => {
- Ok(Ok(NetAddress::Hostname {
+ Ok(Ok(SocketAddress::Hostname {
hostname: Readable::read(reader)?,
port: Readable::read(reader)?,
}))
}
}
-impl Readable for NetAddress {
- fn read<R: Read>(reader: &mut R) -> Result<NetAddress, DecodeError> {
+impl Readable for SocketAddress {
+ fn read<R: Read>(reader: &mut R) -> Result<SocketAddress, DecodeError> {
match Readable::read(reader) {
Ok(Ok(res)) => Ok(res),
Ok(Err(_)) => Err(DecodeError::UnknownVersion),
}
}
+/// [`SocketAddress`] error variants
+#[derive(Debug, Eq, PartialEq, Clone)]
+pub enum SocketAddressParseError {
+ /// Socket address (IPv4/IPv6) parsing error
+ SocketAddrParse,
+ /// Invalid input format
+ InvalidInput,
+ /// Invalid port
+ InvalidPort,
+ /// Invalid onion v3 address
+ InvalidOnionV3,
+}
+
+impl fmt::Display for SocketAddressParseError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ match self {
+ SocketAddressParseError::SocketAddrParse => write!(f, "Socket address (IPv4/IPv6) parsing error"),
+ SocketAddressParseError::InvalidInput => write!(f, "Invalid input format. \
+ Expected: \"<ipv4>:<port>\", \"[<ipv6>]:<port>\", \"<onion address>.onion:<port>\" or \"<hostname>:<port>\""),
+ SocketAddressParseError::InvalidPort => write!(f, "Invalid port"),
+ SocketAddressParseError::InvalidOnionV3 => write!(f, "Invalid onion v3 address"),
+ }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddrV4> for SocketAddress {
+ fn from(addr: std::net::SocketAddrV4) -> Self {
+ SocketAddress::TcpIpV4 { addr: addr.ip().octets(), port: addr.port() }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddrV6> for SocketAddress {
+ fn from(addr: std::net::SocketAddrV6) -> Self {
+ SocketAddress::TcpIpV6 { addr: addr.ip().octets(), port: addr.port() }
+ }
+}
+
+#[cfg(feature = "std")]
+impl From<std::net::SocketAddr> for SocketAddress {
+ 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<SocketAddress, SocketAddressParseError> {
+ if host.ends_with(".onion") {
+ let domain = &host[..host.len() - ".onion".len()];
+ if domain.len() != 56 {
+ return Err(SocketAddressParseError::InvalidOnionV3);
+ }
+ let onion = base32::Alphabet::RFC4648 { padding: false }.decode(&domain).map_err(|_| SocketAddressParseError::InvalidOnionV3)?;
+ if onion.len() != 35 {
+ return Err(SocketAddressParseError::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(SocketAddress::OnionV3 { ed25519_pubkey, checksum, version, port });
+
+ } else {
+ return Err(SocketAddressParseError::InvalidInput);
+ }
+}
+
+#[cfg(feature = "std")]
+impl FromStr for SocketAddress {
+ type Err = SocketAddressParseError;
+
+ 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(SocketAddressParseError::InvalidInput),
+ };
+ let host = &s[..trimmed_input];
+ let port: u16 = s[trimmed_input + 1..].parse().map_err(|_| SocketAddressParseError::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(SocketAddress::Hostname { hostname, port });
+ };
+ return Err(SocketAddressParseError::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.
/// This should be sanitized before use. There is no guarantee of uniqueness.
pub alias: NodeAlias,
/// List of addresses on which this node is reachable
- pub addresses: Vec<NetAddress>,
+ pub addresses: Vec<SocketAddress>,
pub(crate) excess_address_data: Vec<u8>,
pub(crate) excess_data: Vec<u8>,
}
}
/// 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 {
/// 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.
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let global_features: InitFeatures = Readable::read(r)?;
let features: InitFeatures = Readable::read(r)?;
- let mut remote_network_address: Option<NetAddress> = None;
+ let mut remote_network_address: Option<SocketAddress> = None;
let mut networks: Option<WithoutLength<Vec<ChainHash>>> = None;
decode_tlv_stream!(r, {
(1, networks, option),
let alias: NodeAlias = Readable::read(r)?;
let addr_len: u16 = Readable::read(r)?;
- let mut addresses: Vec<NetAddress> = Vec::new();
+ let mut addresses: Vec<SocketAddress> = Vec::new();
let mut addr_readpos = 0;
let mut excess = false;
let mut excess_byte = 0;
#[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::SocketAddress;
use crate::routing::gossip::{NodeAlias, NodeId};
use crate::util::ser::{Writeable, Readable, Hostname, TransactionU16LenLimited};
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::SocketAddressParseError;
+
#[test]
fn encoding_channel_reestablish() {
let public_key = {
};
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],
};
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],
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,
};
let mut addresses = Vec::new();
if ipv4 {
- addresses.push(msgs::NetAddress::IPv4 {
+ addresses.push(SocketAddress::TcpIpV4 {
addr: [255, 254, 253, 252],
port: 9735
});
}
if ipv6 {
- addresses.push(msgs::NetAddress::IPv6 {
+ addresses.push(SocketAddress::TcpIpV6 {
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(msgs::SocketAddress::OnionV2(
[255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]
));
}
if onionv3 {
- addresses.push(msgs::NetAddress::OnionV3 {
+ addresses.push(msgs::SocketAddress::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,
});
}
if hostname {
- addresses.push(msgs::NetAddress::Hostname {
+ addresses.push(SocketAddress::Hostname {
hostname: Hostname::try_from(String::from("host")).unwrap(),
port: 9735,
});
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,
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,
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,
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,
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,
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,
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,
};
#[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,
#[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(),
#[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();
#[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();
#[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();
#[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![
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 },
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();
#[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();
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();
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,
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 {
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]),
#[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]),
};
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
};
#[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
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)]
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)]
#[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();
}.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(SocketAddress::TcpIpV4 {
addr: [127, 0, 0, 1],
port: 1000,
}),
#[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();
#[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();
}
Ok(encoded_payload)
}
+
+ #[test]
+ #[cfg(feature = "std")]
+ fn test_socket_address_from_str() {
+ assert_eq!(SocketAddress::TcpIpV4 {
+ addr: Ipv4Addr::new(127, 0, 0, 1).octets(),
+ port: 1234,
+ }, SocketAddress::from_str("127.0.0.1:1234").unwrap());
+
+ assert_eq!(SocketAddress::TcpIpV6 {
+ addr: Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).octets(),
+ port: 1234,
+ }, SocketAddress::from_str("[0:0:0:0:0:0:0:1]:1234").unwrap());
+ assert_eq!(
+ SocketAddress::Hostname {
+ hostname: Hostname::try_from("lightning-node.mydomain.com".to_string()).unwrap(),
+ port: 1234,
+ }, SocketAddress::from_str("lightning-node.mydomain.com:1234").unwrap());
+ assert_eq!(
+ SocketAddress::Hostname {
+ hostname: Hostname::try_from("example.com".to_string()).unwrap(),
+ port: 1234,
+ }, SocketAddress::from_str("example.com:1234").unwrap());
+ assert_eq!(SocketAddress::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
+ }, SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap());
+ assert_eq!(Err(SocketAddressParseError::InvalidOnionV3), SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6.onion:1234"));
+ assert_eq!(Err(SocketAddressParseError::InvalidInput), SocketAddress::from_str("127.0.0.1@1234"));
+ assert_eq!(Err(SocketAddressParseError::InvalidInput), "".parse::<SocketAddress>());
+ assert!(SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:9735:94").is_err());
+ assert!(SocketAddress::from_str("wrong$%#.com:1234").is_err());
+ assert_eq!(Err(SocketAddressParseError::InvalidPort), SocketAddress::from_str("example.com:wrong"));
+ assert!("localhost".parse::<SocketAddress>().is_err());
+ assert!("localhost:invalid-port".parse::<SocketAddress>().is_err());
+ assert!( "invalid-onion-v3-hostname.onion:8080".parse::<SocketAddress>().is_err());
+ assert!("b32.example.onion:invalid-port".parse::<SocketAddress>().is_err());
+ assert!("invalid-address".parse::<SocketAddress>().is_err());
+ assert!(SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:1234").is_err());
+ }
}