X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=9d872a6f53d999ac817cfaf9b6e4aa2a444814d2;hb=0456b0e311a4996b00d715f9211adcabc06b37c7;hp=c617d97fe52705c8673c6f4a68f331bb8ed644a6;hpb=36af1f06fab3aadf186b72ab31a61a9f1eb6a70d;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index c617d97f..9d872a6f 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -29,7 +29,7 @@ use bitcoin::secp256k1::PublicKey; use bitcoin::secp256k1::ecdsa::Signature; use bitcoin::{secp256k1, Witness}; use bitcoin::blockdata::script::Script; -use bitcoin::hash_types::{Txid, BlockHash}; +use bitcoin::hash_types::Txid; use crate::blinded_path::payment::ReceiveTlvs; use crate::ln::{ChannelId, PaymentPreimage, PaymentHash, PaymentSecret}; @@ -39,15 +39,20 @@ use crate::onion_message; use crate::sign::{NodeSigner, Recipient}; use crate::prelude::*; +#[cfg(feature = "std")] use core::convert::TryFrom; use core::fmt; use core::fmt::Debug; use core::ops::Deref; +#[cfg(feature = "std")] use core::str::FromStr; +#[cfg(feature = "std")] +use std::net::SocketAddr; +use core::fmt::Display; use crate::io::{self, Cursor, Read}; use crate::io_extras::read_to_end; -use crate::events::{MessageSendEventsProvider, OnionMessageProvider}; +use crate::events::MessageSendEventsProvider; use crate::util::chacha20poly1305rfc::ChaChaPolyReadAdapter; use crate::util::logger; use crate::util::ser::{LengthReadable, LengthReadableArgs, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize}; @@ -60,11 +65,11 @@ pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000; #[cfg(taproot)] /// A partial signature that also contains the Musig2 nonce its signer used -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct PartialSignatureWithNonce(pub musig2::types::PartialSignature, pub musig2::types::PublicNonce); /// An error in decoding a message or struct. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum DecodeError { /// A version byte specified something we don't know how to handle. /// @@ -91,7 +96,7 @@ pub enum DecodeError { /// An [`init`] message to be sent to or received from a peer. /// /// [`init`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-init-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Init { /// The relevant features which the sender supports. pub features: InitFeatures, @@ -111,7 +116,7 @@ pub struct Init { /// An [`error`] message to be sent to or received from a peer. /// /// [`error`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-error-and-warning-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ErrorMessage { /// The channel ID involved in the error. /// @@ -129,7 +134,7 @@ pub struct ErrorMessage { /// A [`warning`] message to be sent to or received from a peer. /// /// [`warning`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-error-and-warning-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct WarningMessage { /// The channel ID involved in the warning. /// @@ -146,7 +151,7 @@ pub struct WarningMessage { /// A [`ping`] message to be sent to or received from a peer. /// /// [`ping`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-ping-and-pong-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Ping { /// The desired response length. pub ponglen: u16, @@ -159,7 +164,7 @@ pub struct Ping { /// A [`pong`] message to be sent to or received from a peer. /// /// [`pong`]: https://github.com/lightning/bolts/blob/master/01-messaging.md#the-ping-and-pong-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Pong { /// The pong packet size. /// @@ -172,10 +177,10 @@ pub struct Pong { /// Used in V1 channel establishment /// /// [`open_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-open_channel-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct OpenChannel { /// The genesis hash of the blockchain where the channel is to be opened - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// A temporary channel ID, until the funding outpoint is announced pub temporary_channel_id: ChannelId, /// The channel value @@ -226,10 +231,10 @@ pub struct OpenChannel { /// Used in V2 channel establishment /// // TODO(dual_funding): Add spec link for `open_channel2`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct OpenChannelV2 { /// The genesis hash of the blockchain where the channel is to be opened - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// A temporary channel ID derived using a zeroed out value for the channel acceptor's revocation basepoint pub temporary_channel_id: ChannelId, /// The feerate for the funding transaction set by the channel initiator @@ -285,7 +290,7 @@ pub struct OpenChannelV2 { /// Used in V1 channel establishment /// /// [`accept_channel`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-accept_channel-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct AcceptChannel { /// A temporary channel ID, until the funding outpoint is announced pub temporary_channel_id: ChannelId, @@ -333,7 +338,7 @@ pub struct AcceptChannel { /// Used in V2 channel establishment /// // TODO(dual_funding): Add spec link for `accept_channel2`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct AcceptChannelV2 { /// The same `temporary_channel_id` received from the initiator's `open_channel2` message. pub temporary_channel_id: ChannelId, @@ -386,7 +391,7 @@ pub struct AcceptChannelV2 { /// Used in V1 channel establishment /// /// [`funding_created`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-funding_created-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct FundingCreated { /// A temporary channel ID, until the funding is established pub temporary_channel_id: ChannelId, @@ -409,7 +414,7 @@ pub struct FundingCreated { /// Used in V1 channel establishment /// /// [`funding_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-funding_signed-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct FundingSigned { /// The channel ID pub channel_id: ChannelId, @@ -423,7 +428,7 @@ pub struct FundingSigned { /// A [`channel_ready`] message to be sent to or received from a peer. /// /// [`channel_ready`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#the-channel_ready-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ChannelReady { /// The channel ID pub channel_id: ChannelId, @@ -436,10 +441,64 @@ pub struct ChannelReady { pub short_channel_id_alias: Option, } +/// An stfu (quiescence) message to be sent by or received from the stfu initiator. +// TODO(splicing): Add spec link for `stfu`; still in draft, using from https://github.com/lightning/bolts/pull/863 +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Stfu { + /// The channel ID where quiescence is intended + pub channel_id: ChannelId, + /// Initiator flag, 1 if initiating, 0 if replying to an stfu. + pub initiator: u8, +} + +/// A splice message to be sent by or received from the stfu initiator (splice initiator). +// TODO(splicing): Add spec link for `splice`; still in draft, using from https://github.com/lightning/bolts/pull/863 +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct Splice { + /// The channel ID where splicing is intended + pub channel_id: ChannelId, + /// The genesis hash of the blockchain where the channel is intended to be spliced + pub chain_hash: ChainHash, + /// The intended change in channel capacity: the amount to be added (positive value) + /// or removed (negative value) by the sender (splice initiator) by splicing into/from the channel. + pub relative_satoshis: i64, + /// The feerate for the new funding transaction, set by the splice initiator + pub funding_feerate_perkw: u32, + /// The locktime for the new funding transaction + pub locktime: u32, + /// The key of the sender (splice initiator) controlling the new funding transaction + pub funding_pubkey: PublicKey, +} + +/// A splice_ack message to be received by or sent to the splice initiator. +/// +// TODO(splicing): Add spec link for `splice_ack`; still in draft, using from https://github.com/lightning/bolts/pull/863 +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SpliceAck { + /// The channel ID where splicing is intended + pub channel_id: ChannelId, + /// The genesis hash of the blockchain where the channel is intended to be spliced + pub chain_hash: ChainHash, + /// The intended change in channel capacity: the amount to be added (positive value) + /// or removed (negative value) by the sender (splice acceptor) by splicing into/from the channel. + pub relative_satoshis: i64, + /// The key of the sender (splice acceptor) controlling the new funding transaction + pub funding_pubkey: PublicKey, +} + +/// A splice_locked message to be sent to or received from a peer. +/// +// TODO(splicing): Add spec link for `splice_locked`; still in draft, using from https://github.com/lightning/bolts/pull/863 +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SpliceLocked { + /// The channel ID + pub channel_id: ChannelId, +} + /// A tx_add_input message for adding an input during interactive transaction construction /// // TODO(dual_funding): Add spec link for `tx_add_input`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxAddInput { /// The channel ID pub channel_id: ChannelId, @@ -458,7 +517,7 @@ pub struct TxAddInput { /// A tx_add_output message for adding an output during interactive transaction construction. /// // TODO(dual_funding): Add spec link for `tx_add_output`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxAddOutput { /// The channel ID pub channel_id: ChannelId, @@ -474,7 +533,7 @@ pub struct TxAddOutput { /// A tx_remove_input message for removing an input during interactive transaction construction. /// // TODO(dual_funding): Add spec link for `tx_remove_input`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxRemoveInput { /// The channel ID pub channel_id: ChannelId, @@ -485,7 +544,7 @@ pub struct TxRemoveInput { /// A tx_remove_output message for removing an output during interactive transaction construction. /// // TODO(dual_funding): Add spec link for `tx_remove_output`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxRemoveOutput { /// The channel ID pub channel_id: ChannelId, @@ -497,7 +556,7 @@ pub struct TxRemoveOutput { /// interactive transaction construction. /// // TODO(dual_funding): Add spec link for `tx_complete`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxComplete { /// The channel ID pub channel_id: ChannelId, @@ -507,7 +566,7 @@ pub struct TxComplete { /// interactive transaction construction. /// // TODO(dual_funding): Add spec link for `tx_signatures`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxSignatures { /// The channel ID pub channel_id: ChannelId, @@ -521,7 +580,7 @@ pub struct TxSignatures { /// completed. /// // TODO(dual_funding): Add spec link for `tx_init_rbf`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxInitRbf { /// The channel ID pub channel_id: ChannelId, @@ -538,7 +597,7 @@ pub struct TxInitRbf { /// completed. /// // TODO(dual_funding): Add spec link for `tx_ack_rbf`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxAckRbf { /// The channel ID pub channel_id: ChannelId, @@ -550,7 +609,7 @@ pub struct TxAckRbf { /// A tx_abort message which signals the cancellation of an in-progress transaction negotiation. /// // TODO(dual_funding): Add spec link for `tx_abort`. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct TxAbort { /// The channel ID pub channel_id: ChannelId, @@ -561,7 +620,7 @@ pub struct TxAbort { /// A [`shutdown`] message to be sent to or received from a peer. /// /// [`shutdown`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#closing-initiation-shutdown -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Shutdown { /// The channel ID pub channel_id: ChannelId, @@ -575,7 +634,7 @@ pub struct Shutdown { /// /// This is provided in [`ClosingSigned`] by both sides to indicate the fee range they are willing /// to use. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ClosingSignedFeeRange { /// The minimum absolute fee, in satoshis, which the sender is willing to place on the closing /// transaction. @@ -588,7 +647,7 @@ pub struct ClosingSignedFeeRange { /// A [`closing_signed`] message to be sent to or received from a peer. /// /// [`closing_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#closing-negotiation-closing_signed -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ClosingSigned { /// The channel ID pub channel_id: ChannelId, @@ -604,7 +663,7 @@ pub struct ClosingSigned { /// An [`update_add_htlc`] message to be sent to or received from a peer. /// /// [`update_add_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#adding-an-htlc-update_add_htlc -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UpdateAddHTLC { /// The channel ID pub channel_id: ChannelId, @@ -627,17 +686,18 @@ pub struct UpdateAddHTLC { /// An onion message to be sent to or received from a peer. /// // TODO: update with link to OM when they are merged into the BOLTs -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct OnionMessage { /// Used in decrypting the onion packet's payload. pub blinding_point: PublicKey, - pub(crate) onion_routing_packet: onion_message::Packet, + /// The full onion packet including hop data, pubkey, and hmac + pub onion_routing_packet: onion_message::Packet, } /// An [`update_fulfill_htlc`] message to be sent to or received from a peer. /// /// [`update_fulfill_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UpdateFulfillHTLC { /// The channel ID pub channel_id: ChannelId, @@ -650,7 +710,7 @@ pub struct UpdateFulfillHTLC { /// An [`update_fail_htlc`] message to be sent to or received from a peer. /// /// [`update_fail_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UpdateFailHTLC { /// The channel ID pub channel_id: ChannelId, @@ -662,7 +722,7 @@ pub struct UpdateFailHTLC { /// An [`update_fail_malformed_htlc`] message to be sent to or received from a peer. /// /// [`update_fail_malformed_htlc`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#removing-an-htlc-update_fulfill_htlc-update_fail_htlc-and-update_fail_malformed_htlc -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UpdateFailMalformedHTLC { /// The channel ID pub channel_id: ChannelId, @@ -676,7 +736,7 @@ pub struct UpdateFailMalformedHTLC { /// A [`commitment_signed`] message to be sent to or received from a peer. /// /// [`commitment_signed`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#committing-updates-so-far-commitment_signed -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct CommitmentSigned { /// The channel ID pub channel_id: ChannelId, @@ -692,7 +752,7 @@ pub struct CommitmentSigned { /// A [`revoke_and_ack`] message to be sent to or received from a peer. /// /// [`revoke_and_ack`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#completing-the-transition-to-the-updated-state-revoke_and_ack -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct RevokeAndACK { /// The channel ID pub channel_id: ChannelId, @@ -708,7 +768,7 @@ pub struct RevokeAndACK { /// An [`update_fee`] message to be sent to or received from a peer /// /// [`update_fee`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#updating-fees-update_fee -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UpdateFee { /// The channel ID pub channel_id: ChannelId, @@ -719,7 +779,7 @@ pub struct UpdateFee { /// A [`channel_reestablish`] message to be sent to or received from a peer. /// /// [`channel_reestablish`]: https://github.com/lightning/bolts/blob/master/02-peer-protocol.md#message-retransmission -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ChannelReestablish { /// The channel ID pub channel_id: ChannelId, @@ -739,7 +799,7 @@ pub struct ChannelReestablish { /// An [`announcement_signatures`] message to be sent to or received from a peer. /// /// [`announcement_signatures`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-announcement_signatures-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct AnnouncementSignatures { /// The channel ID pub channel_id: ChannelId, @@ -752,7 +812,7 @@ pub struct AnnouncementSignatures { } /// An address which can be used to connect to a remote peer. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum SocketAddress { /// An IPv4 address and port on which the peer is listening. TcpIpV4 { @@ -907,7 +967,7 @@ impl Readable for SocketAddress { } /// [`SocketAddress`] error variants -#[derive(Debug, Eq, PartialEq, Clone)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub enum SocketAddressParseError { /// Socket address (IPv4/IPv6) parsing error SocketAddrParse, @@ -955,7 +1015,41 @@ impl From for SocketAddress { } } -fn parse_onion_address(host: &str, port: u16) -> Result { +#[cfg(feature = "std")] +impl std::net::ToSocketAddrs for SocketAddress { + type Iter = std::vec::IntoIter; + + fn to_socket_addrs(&self) -> std::io::Result { + match self { + SocketAddress::TcpIpV4 { addr, port } => { + let ip_addr = std::net::Ipv4Addr::from(*addr); + let socket_addr = SocketAddr::new(ip_addr.into(), *port); + Ok(vec![socket_addr].into_iter()) + } + SocketAddress::TcpIpV6 { addr, port } => { + let ip_addr = std::net::Ipv6Addr::from(*addr); + let socket_addr = SocketAddr::new(ip_addr.into(), *port); + Ok(vec![socket_addr].into_iter()) + } + SocketAddress::Hostname { ref hostname, port } => { + (hostname.as_str(), *port).to_socket_addrs() + } + SocketAddress::OnionV2(..) => { + Err(std::io::Error::new(std::io::ErrorKind::Other, "Resolution of OnionV2 \ + addresses is currently unsupported.")) + } + SocketAddress::OnionV3 { .. } => { + Err(std::io::Error::new(std::io::ErrorKind::Other, "Resolution of OnionV3 \ + addresses is currently unsupported.")) + } + } + } +} + +/// Parses an OnionV3 host and port into a [`SocketAddress::OnionV3`]. +/// +/// The host part must end with ".onion". +pub fn parse_onion_address(host: &str, port: u16) -> Result { if host.ends_with(".onion") { let domain = &host[..host.len() - ".onion".len()]; if domain.len() != 56 { @@ -978,6 +1072,35 @@ fn parse_onion_address(host: &str, port: u16) -> Result) -> core::fmt::Result { + match self { + SocketAddress::TcpIpV4{addr, port} => write!( + f, "{}.{}.{}.{}:{}", addr[0], addr[1], addr[2], addr[3], port)?, + SocketAddress::TcpIpV6{addr, port} => write!( + f, + "[{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}:{:02x}{:02x}]:{}", + addr[0], addr[1], addr[2], addr[3], addr[4], addr[5], addr[6], addr[7], addr[8], addr[9], addr[10], addr[11], addr[12], addr[13], addr[14], addr[15], port + )?, + SocketAddress::OnionV2(bytes) => write!(f, "OnionV2({:?})", bytes)?, + SocketAddress::OnionV3 { + ed25519_pubkey, + checksum, + version, + port, + } => { + let [first_checksum_flag, second_checksum_flag] = checksum.to_be_bytes(); + let mut addr = vec![*version, first_checksum_flag, second_checksum_flag]; + addr.extend_from_slice(ed25519_pubkey); + let onion = base32::Alphabet::RFC4648 { padding: false }.encode(&addr); + write!(f, "{}.onion:{}", onion, port)? + }, + SocketAddress::Hostname { hostname, port } => write!(f, "{}:{}", hostname, port)?, + } + Ok(()) + } +} + #[cfg(feature = "std")] impl FromStr for SocketAddress { type Err = SocketAddressParseError; @@ -1027,7 +1150,7 @@ impl<'a> Writeable for UnsignedGossipMessage<'a> { /// The unsigned part of a [`node_announcement`] message. /// /// [`node_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-node_announcement-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UnsignedNodeAnnouncement { /// The advertised features pub features: NodeFeatures, @@ -1047,7 +1170,7 @@ pub struct UnsignedNodeAnnouncement { pub(crate) excess_address_data: Vec, pub(crate) excess_data: Vec, } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] /// A [`node_announcement`] message to be sent to or received from a peer. /// /// [`node_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-node_announcement-message @@ -1061,12 +1184,12 @@ pub struct NodeAnnouncement { /// The unsigned part of a [`channel_announcement`] message. /// /// [`channel_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_announcement-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UnsignedChannelAnnouncement { /// The advertised channel features pub features: ChannelFeatures, /// The genesis hash of the blockchain where the channel is to be opened - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// The short channel ID pub short_channel_id: u64, /// One of the two `node_id`s which are endpoints of this channel @@ -1086,7 +1209,7 @@ pub struct UnsignedChannelAnnouncement { /// A [`channel_announcement`] message to be sent to or received from a peer. /// /// [`channel_announcement`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_announcement-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ChannelAnnouncement { /// Authentication of the announcement by the first public node pub node_signature_1: Signature, @@ -1103,10 +1226,10 @@ pub struct ChannelAnnouncement { /// The unsigned part of a [`channel_update`] message. /// /// [`channel_update`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_update-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct UnsignedChannelUpdate { /// The genesis hash of the blockchain where the channel is to be opened - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// The short channel ID pub short_channel_id: u64, /// A strictly monotonic announcement counter, with gaps allowed, specific to this channel @@ -1141,7 +1264,7 @@ pub struct UnsignedChannelUpdate { /// A [`channel_update`] message to be sent to or received from a peer. /// /// [`channel_update`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-channel_update-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ChannelUpdate { /// A signature of the channel update pub signature: Signature, @@ -1155,10 +1278,10 @@ pub struct ChannelUpdate { /// messages. /// /// [`query_channel_range`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_channel_range-and-reply_channel_range-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct QueryChannelRange { /// The genesis hash of the blockchain being queried - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// The height of the first block for the channel UTXOs being queried pub first_blocknum: u32, /// The number of blocks to include in the query results @@ -1176,10 +1299,10 @@ pub struct QueryChannelRange { /// serialization and do not support `encoding_type=1` zlib serialization. /// /// [`reply_channel_range`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_channel_range-and-reply_channel_range-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ReplyChannelRange { /// The genesis hash of the blockchain being queried - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// The height of the first block in the range of the reply pub first_blocknum: u32, /// The number of blocks included in the range of the reply @@ -1201,10 +1324,10 @@ pub struct ReplyChannelRange { /// serialization and do not support `encoding_type=1` zlib serialization. /// /// [`query_short_channel_ids`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_short_channel_idsreply_short_channel_ids_end-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct QueryShortChannelIds { /// The genesis hash of the blockchain being queried - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// The short_channel_ids that are being queried pub short_channel_ids: Vec, } @@ -1215,10 +1338,10 @@ pub struct QueryShortChannelIds { /// a perfect view of the network. /// /// [`reply_short_channel_ids_end`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-query_short_channel_idsreply_short_channel_ids_end-messages -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct ReplyShortChannelIdsEnd { /// The genesis hash of the blockchain that was queried - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// Indicates if the query recipient maintains up-to-date channel /// information for the `chain_hash` pub full_information: bool, @@ -1229,10 +1352,10 @@ pub struct ReplyShortChannelIdsEnd { /// `gossip_queries` feature has been negotiated. /// /// [`gossip_timestamp_filter`]: https://github.com/lightning/bolts/blob/master/07-routing-gossip.md#the-gossip_timestamp_filter-message -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct GossipTimestampFilter { /// The genesis hash of the blockchain for channel and node information - pub chain_hash: BlockHash, + pub chain_hash: ChainHash, /// The starting unix timestamp pub first_timestamp: u32, /// The range of information in seconds @@ -1248,7 +1371,7 @@ enum EncodingType { } /// Used to put an error message in a [`LightningError`]. -#[derive(Clone, Debug, PartialEq)] +#[derive(Clone, Debug, Hash, PartialEq)] pub enum ErrorAction { /// The peer took some action which made us think they were useless. Disconnect them. DisconnectPeer { @@ -1297,7 +1420,7 @@ pub struct LightningError { /// Struct used to return values from [`RevokeAndACK`] messages, containing a bunch of commitment /// transaction updates if they were pending. -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct CommitmentUpdate { /// `update_add_htlc` messages which should be sent pub update_add_htlcs: Vec, @@ -1340,6 +1463,18 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider { /// Handle an incoming `closing_signed` message from the given peer. fn handle_closing_signed(&self, their_node_id: &PublicKey, msg: &ClosingSigned); + // Quiescence + /// Handle an incoming `stfu` message from the given peer. + fn handle_stfu(&self, their_node_id: &PublicKey, msg: &Stfu); + + // Splicing + /// Handle an incoming `splice` message from the given peer. + fn handle_splice(&self, their_node_id: &PublicKey, msg: &Splice); + /// Handle an incoming `splice_ack` message from the given peer. + fn handle_splice_ack(&self, their_node_id: &PublicKey, msg: &SpliceAck); + /// Handle an incoming `splice_locked` message from the given peer. + fn handle_splice_locked(&self, their_node_id: &PublicKey, msg: &SpliceLocked); + // Interactive channel construction /// Handle an incoming `tx_add_input message` from the given peer. fn handle_tx_add_input(&self, their_node_id: &PublicKey, msg: &TxAddInput); @@ -1414,11 +1549,11 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider { /// Note that this method is called before [`Self::peer_connected`]. fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures; - /// Gets the genesis hashes for this `ChannelMessageHandler` indicating which chains it supports. + /// Gets the chain hashes for this `ChannelMessageHandler` indicating which chains it supports. /// /// If it's `None`, then no particular network chain hash compatibility will be enforced when /// connecting to peers. - fn get_genesis_hashes(&self) -> Option>; + fn get_chain_hashes(&self) -> Option>; } /// A trait to describe an object which can receive routing messages. @@ -1491,10 +1626,14 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider { fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures; } -/// A trait to describe an object that can receive onion messages. -pub trait OnionMessageHandler : OnionMessageProvider { +/// A handler for received [`OnionMessage`]s and for providing generated ones to send. +pub trait OnionMessageHandler { /// Handle an incoming `onion_message` message from the given peer. fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage); + + /// Returns the next pending onion message for the peer with the given node id. + fn next_onion_message_for_peer(&self, peer_node_id: PublicKey) -> Option; + /// Called when a connection is established with a peer. Can be used to track which peers /// advertise onion message support and are online. /// @@ -1502,6 +1641,7 @@ pub trait OnionMessageHandler : OnionMessageProvider { /// with us. Implementors should be somewhat conservative about doing so, however, as other /// message handlers may still wish to communicate with this peer. fn peer_connected(&self, their_node_id: &PublicKey, init: &Init, inbound: bool) -> Result<(), ()>; + /// Indicates a connection to the peer failed/an existing connection was lost. Allows handlers to /// drop and refuse to forward onion messages to this peer. fn peer_disconnected(&self, their_node_id: &PublicKey); @@ -1600,17 +1740,21 @@ pub use self::fuzzy_internal_msgs::*; #[cfg(not(fuzzing))] pub(crate) use self::fuzzy_internal_msgs::*; -#[derive(Clone)] -pub(crate) struct OnionPacket { - pub(crate) version: u8, +/// BOLT 4 onion packet including hop data for the next peer. +#[derive(Clone, Hash, PartialEq, Eq)] +pub struct OnionPacket { + /// BOLT 4 version number. + pub version: u8, /// In order to ensure we always return an error on onion decode in compliance with [BOLT /// #4](https://github.com/lightning/bolts/blob/master/04-onion-routing.md), we have to /// deserialize `OnionPacket`s contained in [`UpdateAddHTLC`] messages even if the ephemeral /// public key (here) is bogus, so we hold a [`Result`] instead of a [`PublicKey`] as we'd /// like. - pub(crate) public_key: Result, - pub(crate) hop_data: [u8; 20*65], - pub(crate) hmac: [u8; 32], + pub public_key: Result, + /// 1300 bytes encrypted payload for the next hop. + pub hop_data: [u8; 20*65], + /// HMAC to verify the integrity of hop_data. + pub hmac: [u8; 32], } impl onion_utils::Packet for OnionPacket { @@ -1625,25 +1769,13 @@ impl onion_utils::Packet for OnionPacket { } } -impl Eq for OnionPacket { } -impl PartialEq for OnionPacket { - fn eq(&self, other: &OnionPacket) -> bool { - for (i, j) in self.hop_data.iter().zip(other.hop_data.iter()) { - if i != j { return false; } - } - self.version == other.version && - self.public_key == other.public_key && - self.hmac == other.hmac - } -} - impl fmt::Debug for OnionPacket { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { f.write_fmt(format_args!("OnionPacket version {} with hmac {:?}", self.version, &self.hmac[..])) } } -#[derive(Clone, Debug, PartialEq, Eq)] +#[derive(Clone, Debug, Hash, PartialEq, Eq)] pub(crate) struct OnionErrorPacket { // This really should be a constant size slice, but the spec lets these things be up to 128KB? // (TODO) We limit it in decode to much lower... @@ -1739,6 +1871,31 @@ impl_writeable_msg!(AcceptChannelV2, { (2, require_confirmed_inputs, option), }); +impl_writeable_msg!(Stfu, { + channel_id, + initiator, +}, {}); + +impl_writeable_msg!(Splice, { + channel_id, + chain_hash, + relative_satoshis, + funding_feerate_perkw, + locktime, + funding_pubkey, +}, {}); + +impl_writeable_msg!(SpliceAck, { + channel_id, + chain_hash, + relative_satoshis, + funding_pubkey, +}, {}); + +impl_writeable_msg!(SpliceLocked, { + channel_id, +}, {}); + impl_writeable_msg!(TxAddInput, { channel_id, serial_id, @@ -2501,7 +2658,7 @@ impl_writeable!(NodeAnnouncement, { impl Readable for QueryShortChannelIds { fn read(r: &mut R) -> Result { - let chain_hash: BlockHash = Readable::read(r)?; + let chain_hash: ChainHash = Readable::read(r)?; let encoding_len: u16 = Readable::read(r)?; let encoding_type: u8 = Readable::read(r)?; @@ -2577,7 +2734,7 @@ impl_writeable_msg!(QueryChannelRange, { impl Readable for ReplyChannelRange { fn read(r: &mut R) -> Result { - let chain_hash: BlockHash = Readable::read(r)?; + let chain_hash: ChainHash = Readable::read(r)?; let first_blocknum: u32 = Readable::read(r)?; let number_of_blocks: u32 = Readable::read(r)?; let sync_complete: bool = Readable::read(r)?; @@ -2642,7 +2799,6 @@ 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}; @@ -2657,9 +2813,10 @@ mod tests { use bitcoin::hashes::hex::FromHex; use bitcoin::util::address::Address; use bitcoin::network::constants::Network; + use bitcoin::blockdata::constants::ChainHash; use bitcoin::blockdata::script::Builder; use bitcoin::blockdata::opcodes; - use bitcoin::hash_types::{Txid, BlockHash}; + use bitcoin::hash_types::Txid; use bitcoin::secp256k1::{PublicKey,SecretKey}; use bitcoin::secp256k1::{Secp256k1, Message}; @@ -2670,7 +2827,8 @@ mod tests { use crate::chain::transaction::OutPoint; #[cfg(feature = "std")] - use std::net::{Ipv4Addr, Ipv6Addr}; + use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6, ToSocketAddrs}; + #[cfg(feature = "std")] use crate::ln::msgs::SocketAddressParseError; #[test] @@ -2788,7 +2946,7 @@ mod tests { } let unsigned_channel_announcement = msgs::UnsignedChannelAnnouncement { features, - chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + chain_hash: ChainHash::using_genesis_block(Network::Bitcoin), short_channel_id: 2316138423780173, node_id_1: NodeId::from_pubkey(&pubkey_1), node_id_2: NodeId::from_pubkey(&pubkey_2), @@ -2810,7 +2968,7 @@ mod tests { } else { target_value.append(&mut hex::decode("0000").unwrap()); } - target_value.append(&mut hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap()); + target_value.append(&mut hex::decode("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap()); target_value.append(&mut hex::decode("00083a840000034d031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d076602531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe33703462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b").unwrap()); if excess_data { target_value.append(&mut hex::decode("0a00001400001e000028").unwrap()); @@ -2939,7 +3097,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 unsigned_channel_update = msgs::UnsignedChannelUpdate { - chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + chain_hash: ChainHash::using_genesis_block(Network::Bitcoin), short_channel_id: 2316138423780173, timestamp: 20190119, flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 }, @@ -2956,7 +3114,7 @@ mod tests { }; let encoded_value = channel_update.encode(); let mut target_value = hex::decode("d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap(); - target_value.append(&mut hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap()); + target_value.append(&mut hex::decode("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap()); target_value.append(&mut hex::decode("00083a840000034d013413a7").unwrap()); target_value.append(&mut hex::decode("01").unwrap()); target_value.append(&mut hex::decode("00").unwrap()); @@ -2997,7 +3155,7 @@ mod tests { let (_, pubkey_5) = get_keys_from!("0505050505050505050505050505050505050505050505050505050505050505", secp_ctx); let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx); let open_channel = msgs::OpenChannel { - chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + chain_hash: ChainHash::using_genesis_block(Network::Bitcoin), temporary_channel_id: ChannelId::from_bytes([2; 32]), funding_satoshis: 1311768467284833366, push_msat: 2536655962884945560, @@ -3020,7 +3178,7 @@ mod tests { }; let encoded_value = open_channel.encode(); let mut target_value = Vec::new(); - target_value.append(&mut hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap()); + target_value.append(&mut hex::decode("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap()); target_value.append(&mut hex::decode("02020202020202020202020202020202020202020202020202020202020202021234567890123456233403289122369832144668701144767633030896203198784335490624111800083a840000034d000c89d4c0bcc0bc031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d076602531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe33703462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f703f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap()); if random_bit { target_value.append(&mut hex::decode("20").unwrap()); @@ -3058,7 +3216,7 @@ mod tests { let (_, pubkey_6) = get_keys_from!("0606060606060606060606060606060606060606060606060606060606060606", secp_ctx); let (_, pubkey_7) = get_keys_from!("0707070707070707070707070707070707070707070707070707070707070707", secp_ctx); let open_channelv2 = msgs::OpenChannelV2 { - chain_hash: BlockHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + chain_hash: ChainHash::using_genesis_block(Network::Bitcoin), temporary_channel_id: ChannelId::from_bytes([2; 32]), funding_feerate_sat_per_1000_weight: 821716, commitment_feerate_sat_per_1000_weight: 821716, @@ -3083,7 +3241,7 @@ mod tests { }; let encoded_value = open_channelv2.encode(); let mut target_value = Vec::new(); - target_value.append(&mut hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap()); + target_value.append(&mut hex::decode("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap()); target_value.append(&mut hex::decode("0202020202020202020202020202020202020202020202020202020202020202").unwrap()); target_value.append(&mut hex::decode("000c89d4").unwrap()); target_value.append(&mut hex::decode("000c89d4").unwrap()); @@ -3290,6 +3448,55 @@ mod tests { assert_eq!(encoded_value, target_value); } + #[test] + fn encoding_splice() { + let secp_ctx = Secp256k1::new(); + let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx); + let splice = msgs::Splice { + chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + channel_id: ChannelId::from_bytes([2; 32]), + relative_satoshis: 123456, + funding_feerate_perkw: 2000, + locktime: 0, + funding_pubkey: pubkey_1, + }; + let encoded_value = splice.encode(); + assert_eq!(hex::encode(encoded_value), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240000007d000000000031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"); + } + + #[test] + fn encoding_stfu() { + let stfu = msgs::Stfu { + channel_id: ChannelId::from_bytes([2; 32]), + initiator: 1, + }; + let encoded_value = stfu.encode(); + assert_eq!(hex::encode(encoded_value), "020202020202020202020202020202020202020202020202020202020202020201"); + } + + #[test] + fn encoding_splice_ack() { + let secp_ctx = Secp256k1::new(); + let (_, pubkey_1,) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx); + let splice = msgs::SpliceAck { + chain_hash: ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(), + channel_id: ChannelId::from_bytes([2; 32]), + relative_satoshis: 123456, + funding_pubkey: pubkey_1, + }; + let encoded_value = splice.encode(); + assert_eq!(hex::encode(encoded_value), "02020202020202020202020202020202020202020202020202020202020202026fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000000000000001e240031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f"); + } + + #[test] + fn encoding_splice_locked() { + let splice = msgs::SpliceLocked { + channel_id: ChannelId::from_bytes([2; 32]), + }; + let encoded_value = splice.encode(); + assert_eq!(hex::encode(encoded_value), "0202020202020202020202020202020202020202020202020202020202020202"); + } + #[test] fn encoding_tx_add_input() { let tx_add_input = msgs::TxAddInput { @@ -3656,7 +3863,7 @@ mod tests { #[test] fn encoding_init() { - let mainnet_hash = ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap(); + let mainnet_hash = ChainHash::using_genesis_block(Network::Bitcoin); assert_eq!(msgs::Init { features: InitFeatures::from_le_bytes(vec![0xFF, 0xFF, 0xFF]), networks: Some(vec![mainnet_hash]), @@ -3894,7 +4101,7 @@ mod tests { for (first_blocknum, number_of_blocks, expected) in tests.into_iter() { let sut = msgs::QueryChannelRange { - chain_hash: BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(), + chain_hash: ChainHash::using_genesis_block(Network::Regtest), first_blocknum, number_of_blocks, }; @@ -3905,12 +4112,12 @@ mod tests { #[test] fn encoding_query_channel_range() { let mut query_channel_range = msgs::QueryChannelRange { - chain_hash: BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(), + chain_hash: ChainHash::using_genesis_block(Network::Regtest), first_blocknum: 100000, number_of_blocks: 1500, }; let encoded_value = query_channel_range.encode(); - let target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000186a0000005dc").unwrap(); + let target_value = hex::decode("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000186a0000005dc").unwrap(); assert_eq!(encoded_value, target_value); query_channel_range = Readable::read(&mut Cursor::new(&target_value[..])).unwrap(); @@ -3925,8 +4132,8 @@ mod tests { } fn do_encoding_reply_channel_range(encoding_type: u8) { - let mut target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206000b8a06000005dc01").unwrap(); - let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(); + let mut target_value = hex::decode("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f000b8a06000005dc01").unwrap(); + let expected_chain_hash = ChainHash::using_genesis_block(Network::Regtest); let mut reply_channel_range = msgs::ReplyChannelRange { chain_hash: expected_chain_hash, first_blocknum: 756230, @@ -3962,8 +4169,8 @@ mod tests { } fn do_encoding_query_short_channel_ids(encoding_type: u8) { - let mut target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e2206").unwrap(); - let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(); + let mut target_value = hex::decode("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(); + let expected_chain_hash = ChainHash::using_genesis_block(Network::Regtest); let mut query_short_channel_ids = msgs::QueryShortChannelIds { chain_hash: expected_chain_hash, short_channel_ids: vec![0x0000000000008e, 0x0000000000003c69, 0x000000000045a6c4], @@ -3988,13 +4195,13 @@ mod tests { #[test] fn encoding_reply_short_channel_ids_end() { - let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(); + let expected_chain_hash = ChainHash::using_genesis_block(Network::Regtest); let mut reply_short_channel_ids_end = msgs::ReplyShortChannelIdsEnd { chain_hash: expected_chain_hash, full_information: true, }; let encoded_value = reply_short_channel_ids_end.encode(); - let target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e220601").unwrap(); + let target_value = hex::decode("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f01").unwrap(); assert_eq!(encoded_value, target_value); reply_short_channel_ids_end = Readable::read(&mut Cursor::new(&target_value[..])).unwrap(); @@ -4004,14 +4211,14 @@ mod tests { #[test] fn encoding_gossip_timestamp_filter(){ - let expected_chain_hash = BlockHash::from_hex("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f").unwrap(); + let expected_chain_hash = ChainHash::using_genesis_block(Network::Regtest); let mut gossip_timestamp_filter = msgs::GossipTimestampFilter { chain_hash: expected_chain_hash, first_timestamp: 1590000000, timestamp_range: 0xffff_ffff, }; let encoded_value = gossip_timestamp_filter.encode(); - let target_value = hex::decode("0f9188f13cb7b2c71f2a335e3a4fc328bf5beb436012afca590b1a11466e22065ec57980ffffffff").unwrap(); + let target_value = hex::decode("06226e46111a0b59caaf126043eb5bbf28c34f3a5e332a1fc7b2b73cf188910f5ec57980ffffffff").unwrap(); assert_eq!(encoded_value, target_value); gossip_timestamp_filter = Readable::read(&mut Cursor::new(&target_value[..])).unwrap(); @@ -4060,32 +4267,41 @@ mod tests { #[test] #[cfg(feature = "std")] fn test_socket_address_from_str() { - assert_eq!(SocketAddress::TcpIpV4 { + let tcpip_v4 = SocketAddress::TcpIpV4 { addr: Ipv4Addr::new(127, 0, 0, 1).octets(), port: 1234, - }, SocketAddress::from_str("127.0.0.1:1234").unwrap()); + }; + assert_eq!(tcpip_v4, SocketAddress::from_str("127.0.0.1:1234").unwrap()); + assert_eq!(tcpip_v4, SocketAddress::from_str(&tcpip_v4.to_string()).unwrap()); - assert_eq!(SocketAddress::TcpIpV6 { + let tcpip_v6 = 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 { + }; + assert_eq!(tcpip_v6, SocketAddress::from_str("[0:0:0:0:0:0:0:1]:1234").unwrap()); + assert_eq!(tcpip_v6, SocketAddress::from_str(&tcpip_v6.to_string()).unwrap()); + + let hostname = 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 { + }; + assert_eq!(hostname, SocketAddress::from_str("lightning-node.mydomain.com:1234").unwrap()); + assert_eq!(hostname, SocketAddress::from_str(&hostname.to_string()).unwrap()); + + let onion_v2 = SocketAddress::OnionV2 ([40, 4, 64, 185, 202, 19, 162, 75, 90, 200, 38, 7],); + assert_eq!("OnionV2([40, 4, 64, 185, 202, 19, 162, 75, 90, 200, 38, 7])", &onion_v2.to_string()); + assert_eq!(Err(SocketAddressParseError::InvalidOnionV3), SocketAddress::from_str("FACEBOOKCOREWWWI.onion:9735")); + + let onion_v3 = 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!(onion_v3, SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion:1234").unwrap()); + assert_eq!(onion_v3, SocketAddress::from_str(&onion_v3.to_string()).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::()); @@ -4099,4 +4315,22 @@ mod tests { assert!("invalid-address".parse::().is_err()); assert!(SocketAddress::from_str("pg6mmjiyjmcrsslvykfwnntlaru7p5svn6y2ymmju6nubxndf4pscryd.onion.onion:1234").is_err()); } + + #[test] + #[cfg(feature = "std")] + fn test_socket_address_to_socket_addrs() { + assert_eq!(SocketAddress::TcpIpV4 {addr:[0u8; 4], port: 1337,}.to_socket_addrs().unwrap().next().unwrap(), + SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(0,0,0,0), 1337))); + assert_eq!(SocketAddress::TcpIpV6 {addr:[0u8; 16], port: 1337,}.to_socket_addrs().unwrap().next().unwrap(), + SocketAddr::V6(SocketAddrV6::new(Ipv6Addr::from([0u8; 16]), 1337, 0, 0))); + assert_eq!(SocketAddress::Hostname { hostname: Hostname::try_from("0.0.0.0".to_string()).unwrap(), port: 0 } + .to_socket_addrs().unwrap().next().unwrap(), SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::from([0u8; 4]),0))); + assert!(SocketAddress::OnionV2([0u8; 12]).to_socket_addrs().is_err()); + assert!(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 }.to_socket_addrs().is_err()); + } }