Support receiving multiple funding_locked messages
[rust-lightning] / lightning / src / ln / msgs.rs
index 9662ffa7d48078f33eef4516f26ce8ffcb7d11d9..fab396e3c7112af934021041abfcf2e1f4d609af 100644 (file)
@@ -33,7 +33,7 @@ use bitcoin::hash_types::{Txid, BlockHash};
 use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
 
 use prelude::*;
-use core::{cmp, fmt};
+use core::fmt;
 use core::fmt::Debug;
 use io::{self, Read};
 use io_extras::read_to_end;
@@ -80,12 +80,29 @@ pub struct Init {
 /// An error message to be sent or received from a peer
 #[derive(Clone, Debug, PartialEq)]
 pub struct ErrorMessage {
-       /// The channel ID involved in the error
+       /// The channel ID involved in the error.
+       ///
+       /// 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],
        /// A possibly human-readable error description.
-       /// The string should be sanitized before it is used (e.g. emitted to logs
-       /// or printed to stdout).  Otherwise, a well crafted error message may trigger a security
-       /// vulnerability in the terminal emulator or the logging subsystem.
+       /// The string should be sanitized before it is used (e.g. emitted to logs or printed to
+       /// stdout). Otherwise, a well crafted error message may trigger a security vulnerability in
+       /// the terminal emulator or the logging subsystem.
+       pub data: String,
+}
+
+/// A warning message to be sent or received from a peer
+#[derive(Clone, Debug, PartialEq)]
+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],
+       /// A possibly human-readable warning description.
+       /// The string should be sanitized before it is used (e.g. emitted to logs or printed to
+       /// stdout). Otherwise, a well crafted error message may trigger a security vulnerability in
+       /// the terminal emulator or the logging subsystem.
        pub data: String,
 }
 
@@ -187,6 +204,12 @@ pub struct AcceptChannel {
        pub first_per_commitment_point: PublicKey,
        /// Optionally, a request to pre-set the to-sender output's scriptPubkey for when we collaboratively close
        pub shutdown_scriptpubkey: OptionalField<Script>,
+       /// The channel type that this channel will represent. If none is set, we derive the channel
+       /// type from the intersection of our feature bits with our counterparty's feature bits from
+       /// the Init message.
+       ///
+       /// This is required to match the equivalent field in [`OpenChannel::channel_type`].
+       pub channel_type: Option<ChannelTypeFeatures>,
 }
 
 /// A funding_created message to be sent or received from a peer
@@ -218,6 +241,9 @@ pub struct FundingLocked {
        pub channel_id: [u8; 32],
        /// 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. The sender will accept payments
+       /// to be forwarded over this SCID and forward them to this messages' recipient.
+       pub short_channel_id_alias: Option<u64>,
 }
 
 /// A shutdown message to be sent or received from a peer
@@ -394,12 +420,10 @@ pub enum NetAddress {
                port: u16,
        },
        /// An old-style Tor onion address/port on which the peer is listening.
-       OnionV2 {
-               /// The bytes (usually encoded in base32 with ".onion" appended)
-               addr: [u8; 10],
-               /// The port on which the node is listening
-               port: u16,
-       },
+       ///
+       /// This field is deprecated and the Tor network generally no longer supports V2 Onion
+       /// addresses. Thus, the details are not parsed here.
+       OnionV2([u8; 12]),
        /// A new-style Tor onion address/port on which the peer is listening.
        /// To create the human-readable "hostname", concatenate ed25519_pubkey, checksum, and version,
        /// wrap as base32 and append ".onion".
@@ -421,7 +445,7 @@ impl NetAddress {
                match self {
                        &NetAddress::IPv4 {..} => { 1 },
                        &NetAddress::IPv6 {..} => { 2 },
-                       &NetAddress::OnionV2 {..} => { 3 },
+                       &NetAddress::OnionV2(_) => { 3 },
                        &NetAddress::OnionV3 {..} => { 4 },
                }
        }
@@ -431,7 +455,7 @@ impl NetAddress {
                match self {
                        &NetAddress::IPv4 { .. } => { 6 },
                        &NetAddress::IPv6 { .. } => { 18 },
-                       &NetAddress::OnionV2 { .. } => { 12 },
+                       &NetAddress::OnionV2(_) => { 12 },
                        &NetAddress::OnionV3 { .. } => { 37 },
                }
        }
@@ -453,10 +477,9 @@ impl Writeable for NetAddress {
                                addr.write(writer)?;
                                port.write(writer)?;
                        },
-                       &NetAddress::OnionV2 { ref addr, ref port } => {
+                       &NetAddress::OnionV2(bytes) => {
                                3u8.write(writer)?;
-                               addr.write(writer)?;
-                               port.write(writer)?;
+                               bytes.write(writer)?;
                        },
                        &NetAddress::OnionV3 { ref ed25519_pubkey, ref checksum, ref version, ref port } => {
                                4u8.write(writer)?;
@@ -486,12 +509,7 @@ impl Readable for Result<NetAddress, u8> {
                                        port: Readable::read(reader)?,
                                }))
                        },
-                       3 => {
-                               Ok(Ok(NetAddress::OnionV2 {
-                                       addr: Readable::read(reader)?,
-                                       port: Readable::read(reader)?,
-                               }))
-                       },
+                       3 => Ok(Ok(NetAddress::OnionV2(Readable::read(reader)?))),
                        4 => {
                                Ok(Ok(NetAddress::OnionV3 {
                                        ed25519_pubkey: Readable::read(reader)?,
@@ -722,7 +740,16 @@ pub enum ErrorAction {
        /// The peer did something incorrect. Tell them.
        SendErrorMessage {
                /// The message to send.
-               msg: ErrorMessage
+               msg: ErrorMessage,
+       },
+       /// The peer did something incorrect. Tell them without closing any channels.
+       SendWarningMessage {
+               /// The message to send.
+               msg: WarningMessage,
+               /// The peer may have done something harmless that we weren't able to meaningfully process,
+               /// though we should still tell them about it.
+               /// If this event is logged, log it at the given level.
+               log_level: logger::Level,
        },
 }
 
@@ -919,9 +946,9 @@ mod fuzzy_internal_msgs {
                pub(crate) pad: Vec<u8>,
        }
 }
-#[cfg(feature = "fuzztarget")]
+#[cfg(fuzzing)]
 pub use self::fuzzy_internal_msgs::*;
-#[cfg(not(feature = "fuzztarget"))]
+#[cfg(not(fuzzing))]
 pub(crate) use self::fuzzy_internal_msgs::*;
 
 #[derive(Clone)]
@@ -967,7 +994,7 @@ impl fmt::Display for DecodeError {
                        DecodeError::InvalidValue => f.write_str("Nonsense bytes didn't map to the type they were interpreted as"),
                        DecodeError::ShortRead => f.write_str("Packet extended beyond the provided bytes"),
                        DecodeError::BadLengthDescriptor => f.write_str("A length descriptor in the packet didn't describe the later data correctly"),
-                       DecodeError::Io(ref e) => e.fmt(f),
+                       DecodeError::Io(ref e) => fmt::Debug::fmt(e, f),
                        DecodeError::UnsupportedCompression => f.write_str("We don't support receiving messages with zlib-compressed fields"),
                }
        }
@@ -1046,7 +1073,9 @@ impl_writeable_msg!(AcceptChannel, {
        htlc_basepoint,
        first_per_commitment_point,
        shutdown_scriptpubkey
-}, {});
+}, {
+       (1, channel_type, option),
+});
 
 impl_writeable_msg!(AnnouncementSignatures, {
        channel_id,
@@ -1129,7 +1158,9 @@ impl_writeable_msg!(FundingSigned, {
 impl_writeable_msg!(FundingLocked, {
        channel_id,
        next_per_commitment_point,
-}, {});
+}, {
+       (1, short_channel_id_alias, option),
+});
 
 impl Writeable for Init {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
@@ -1273,10 +1304,6 @@ impl Readable for FinalOnionHopData {
 
 impl Writeable for OnionHopData {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
-               // Note that this should never be reachable if Rust-Lightning generated the message, as we
-               // check values are sane long before we get here, though its possible in the future
-               // user-generated messages may hit this.
-               if self.amt_to_forward > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
                match self.format {
                        OnionHopDataFormat::Legacy { short_channel_id } => {
                                0u8.write(w)?;
@@ -1293,9 +1320,6 @@ impl Writeable for OnionHopData {
                                });
                        },
                        OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => {
-                               if let Some(final_data) = payment_data {
-                                       if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); }
-                               }
                                encode_varint_length_prefixed_tlv!(w, {
                                        (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required),
                                        (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required),
@@ -1511,10 +1535,38 @@ impl Readable for ErrorMessage {
                Ok(Self {
                        channel_id: Readable::read(r)?,
                        data: {
-                               let mut sz: usize = <u16 as Readable>::read(r)? as usize;
-                               let data = read_to_end(r)?;
-                               sz = cmp::min(data.len(), sz);
-                               match String::from_utf8(data[..sz as usize].to_vec()) {
+                               let sz: usize = <u16 as Readable>::read(r)? as usize;
+                               let mut data = Vec::with_capacity(sz);
+                               data.resize(sz, 0);
+                               r.read_exact(&mut data)?;
+                               match String::from_utf8(data) {
+                                       Ok(s) => s,
+                                       Err(_) => return Err(DecodeError::InvalidValue),
+                               }
+                       }
+               })
+       }
+}
+
+impl Writeable for WarningMessage {
+       fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
+               self.channel_id.write(w)?;
+               (self.data.len() as u16).write(w)?;
+               w.write_all(self.data.as_bytes())?;
+               Ok(())
+       }
+}
+
+impl Readable for WarningMessage {
+       fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+               Ok(Self {
+                       channel_id: Readable::read(r)?,
+                       data: {
+                               let sz: usize = <u16 as Readable>::read(r)? as usize;
+                               let mut data = Vec::with_capacity(sz);
+                               data.resize(sz, 0);
+                               r.read_exact(&mut data)?;
+                               match String::from_utf8(data) {
                                        Ok(s) => s,
                                        Err(_) => return Err(DecodeError::InvalidValue),
                                }
@@ -1926,10 +1978,9 @@ mod tests {
                        });
                }
                if onionv2 {
-                       addresses.push(msgs::NetAddress::OnionV2 {
-                               addr: [255, 254, 253, 252, 251, 250, 249, 248, 247, 246],
-                               port: 9735
-                       });
+                       addresses.push(msgs::NetAddress::OnionV2(
+                               [255, 254, 253, 252, 251, 250, 249, 248, 247, 246, 38, 7]
+                       ));
                }
                if onionv3 {
                        addresses.push(msgs::NetAddress::OnionV3 {
@@ -2146,7 +2197,8 @@ mod tests {
                        delayed_payment_basepoint: pubkey_4,
                        htlc_basepoint: pubkey_5,
                        first_per_commitment_point: pubkey_6,
-                       shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent }
+                       shutdown_scriptpubkey: if shutdown { OptionalField::Present(Address::p2pkh(&::bitcoin::PublicKey{compressed: true, key: pubkey_1}, Network::Testnet).script_pubkey()) } else { OptionalField::Absent },
+                       channel_type: None,
                };
                let encoded_value = accept_channel.encode();
                let mut target_value = hex::decode("020202020202020202020202020202020202020202020202020202020202020212345678901234562334032891223698321446687011447600083a840000034d000c89d4c0bcc0bc031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f024d4b6cd1361032ca9bd2aeb9d900aa4d45d9ead80ac9423374c451a7254d076602531fe6068134503d2723133227c867ac8fa6c83c537e9a44c3c5bdbdcb1fe33703462779ad4aad39514614751a71085f2f10e1c7a593e4e030efb5b8721ce55b0b0362c0a046dacce86ddd0343c6d3c7c79c2208ba0d9c9cf24a6d046d21d21f90f703f006a18d5653c4edf5391ff23a61f03ff83d237e880ee61187fa9f379a028e0a").unwrap();
@@ -2199,6 +2251,7 @@ mod tests {
                let funding_locked = msgs::FundingLocked {
                        channel_id: [2; 32],
                        next_per_commitment_point: pubkey_1,
+                       short_channel_id_alias: None,
                };
                let encoded_value = funding_locked.encode();
                let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f").unwrap();
@@ -2414,6 +2467,17 @@ mod tests {
                assert_eq!(encoded_value, target_value);
        }
 
+       #[test]
+       fn encoding_warning() {
+               let error = msgs::WarningMessage {
+                       channel_id: [2; 32],
+                       data: String::from("rust-lightning"),
+               };
+               let encoded_value = error.encode();
+               let target_value = hex::decode("0202020202020202020202020202020202020202020202020202020202020202000e727573742d6c696768746e696e67").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
        #[test]
        fn encoding_ping() {
                let ping = msgs::Ping {