Expand the Route object to include multiple paths.
[rust-lightning] / lightning / src / ln / msgs.rs
index 875354251c5022c760d2ebe301a17478d90e3ea0..cd93e236a00a5d662c2ebf564a439eb60142fea4 100644 (file)
@@ -29,17 +29,20 @@ use std::io::Read;
 use std::result::Result;
 
 use util::events;
-use util::ser::{Readable, Writeable, Writer};
+use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt};
 
 use ln::channelmanager::{PaymentPreimage, PaymentHash};
 
+/// 21 million * 10^8 * 1000
+pub(crate) const MAX_VALUE_MSAT: u64 = 21_000_000_0000_0000_000;
+
 /// An error in decoding a message or struct.
 #[derive(Debug)]
 pub enum DecodeError {
        /// A version byte specified something we don't know how to handle.
        /// Includes unknown realm byte in an OnionHopData packet
        UnknownVersion,
-       /// Unknown feature mandating we fail to parse message
+       /// Unknown feature mandating we fail to parse message (eg TLV with an even, unknown type)
        UnknownRequiredFeature,
        /// Value was invalid, eg a byte which was supposed to be a bool was something other than a 0
        /// or 1, a public key/private key/signature was invalid, text wasn't UTF-8, etc
@@ -56,7 +59,10 @@ pub enum DecodeError {
 
 /// An init message to be sent or received from a peer
 pub struct Init {
+       #[cfg(not(feature = "fuzztarget"))]
        pub(crate) features: InitFeatures,
+       #[cfg(feature = "fuzztarget")]
+       pub features: InitFeatures,
 }
 
 /// An error message to be sent or received from a peer
@@ -302,6 +308,58 @@ impl NetAddress {
        }
 }
 
+/// A "set" of addresses which enforces that there can be only up to one of each net address type.
+pub struct NetAddressSet {
+       v4: Option<NetAddress>,
+       v6: Option<NetAddress>,
+       onion2: Option<NetAddress>,
+       onion3: Option<NetAddress>,
+}
+impl NetAddressSet {
+       /// Creates a new, empty, NetAddressSet
+       pub fn new() -> Self {
+               NetAddressSet { v4: None, v6: None, onion2: None, onion3: None }
+       }
+
+       /// Sets the IPv4 socket address in this set, overwriting any previous IPv4 socket addresses
+       /// (if any).
+       pub fn set_v4(&mut self, addr: [u8; 4], port: u16) {
+               self.v4 = Some(NetAddress::IPv4 { addr, port });
+       }
+       /// Sets the IPv6 socket address in this set, overwriting any previous IPv4 socket addresses
+       /// (if any).
+       pub fn set_v6(&mut self, addr: [u8; 16], port: u16) {
+               self.v6 = Some(NetAddress::IPv6 { addr, port });
+       }
+       /// Sets the Tor Onion v2 socket address in this set, overwriting any previous IPv4 socket
+       /// address (if any).
+       pub fn set_onion_v2(&mut self, addr: [u8; 10], port: u16) {
+               self.onion2 = Some(NetAddress::OnionV2 { addr, port });
+       }
+       /// Sets the Tor Onion v3 socket address in this set, overwriting any previous IPv4 socket
+       /// address (if any).
+       pub fn set_onion_v3(&mut self, ed25519_pubkey: [u8; 32], checksum: u16, version: u8, port: u16) {
+               self.onion3 = Some(NetAddress::OnionV3 { ed25519_pubkey, checksum, version, port });
+       }
+
+       pub(crate) fn to_vec(mut self) -> Vec<NetAddress> {
+               let mut res = Vec::new();
+               if let Some(addr) = self.v4.take() {
+                       res.push(addr);
+               }
+               if let Some(addr) = self.v6.take() {
+                       res.push(addr);
+               }
+               if let Some(addr) = self.onion2.take() {
+                       res.push(addr);
+               }
+               if let Some(addr) = self.onion3.take() {
+                       res.push(addr);
+               }
+               res
+       }
+}
+
 impl Writeable for NetAddress {
        fn write<W: Writer>(&self, writer: &mut W) -> Result<(), ::std::io::Error> {
                match self {
@@ -571,7 +629,7 @@ pub trait ChannelMessageHandler : events::MessageSendEventsProvider + Send + Syn
        fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
 
        /// Handle a peer reconnecting, possibly generating channel_reestablish message(s).
-       fn peer_connected(&self, their_node_id: &PublicKey);
+       fn peer_connected(&self, their_node_id: &PublicKey, msg: &Init);
        /// Handle an incoming channel_reestablish message from the given peer.
        fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish);
 
@@ -603,22 +661,32 @@ pub trait RoutingMessageHandler : Send + Sync {
        fn get_next_node_announcements(&self, starting_point: Option<&PublicKey>, batch_amount: u8) -> Vec<NodeAnnouncement>;
 }
 
-pub(crate) struct OnionRealm0HopData {
-       pub(crate) short_channel_id: u64,
-       pub(crate) amt_to_forward: u64,
-       pub(crate) outgoing_cltv_value: u32,
-       // 12 bytes of 0-padding
-}
-
 mod fuzzy_internal_msgs {
        // These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
        // them from untrusted input):
+       #[derive(Clone)]
+       pub(crate) struct FinalOnionHopData {
+               pub(crate) payment_secret: [u8; 32],
+               pub(crate) total_msat: u64,
+       }
+
+       pub(crate) enum OnionHopDataFormat {
+               Legacy { // aka Realm-0
+                       short_channel_id: u64,
+               },
+               NonFinalNode {
+                       short_channel_id: u64,
+               },
+               FinalNode {
+                       payment_data: Option<FinalOnionHopData>,
+               },
+       }
 
-       use super::OnionRealm0HopData;
        pub struct OnionHopData {
-               pub(crate) realm: u8,
-               pub(crate) data: OnionRealm0HopData,
-               pub(crate) hmac: [u8; 32],
+               pub(crate) format: OnionHopDataFormat,
+               pub(crate) amt_to_forward: u64,
+               pub(crate) outgoing_cltv_value: u32,
+               // 12 bytes of 0-padding for Legacy format
        }
 
        pub struct DecodedOnionErrorPacket {
@@ -955,53 +1023,108 @@ impl_writeable!(UpdateAddHTLC, 32+8+8+32+4+1366, {
        onion_routing_packet
 });
 
-impl Writeable for OnionRealm0HopData {
-       fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
-               w.size_hint(32);
-               self.short_channel_id.write(w)?;
-               self.amt_to_forward.write(w)?;
-               self.outgoing_cltv_value.write(w)?;
-               w.write_all(&[0;12])?;
-               Ok(())
-       }
-}
-
-impl<R: Read> Readable<R> for OnionRealm0HopData {
-       fn read(r: &mut R) -> Result<Self, DecodeError> {
-               Ok(OnionRealm0HopData {
-                       short_channel_id: Readable::read(r)?,
-                       amt_to_forward: Readable::read(r)?,
-                       outgoing_cltv_value: {
-                               let v: u32 = Readable::read(r)?;
-                               r.read_exact(&mut [0; 12])?;
-                               v
-                       }
-               })
-       }
-}
+impl_writeable!(FinalOnionHopData, 32+8, {
+       payment_secret,
+       total_msat
+});
 
 impl Writeable for OnionHopData {
        fn write<W: Writer>(&self, w: &mut W) -> Result<(), ::std::io::Error> {
-               w.size_hint(65);
-               self.realm.write(w)?;
-               self.data.write(w)?;
-               self.hmac.write(w)?;
+               w.size_hint(33);
+               match self.format {
+                       OnionHopDataFormat::Legacy { short_channel_id } => {
+                               0u8.write(w)?;
+                               short_channel_id.write(w)?;
+                               self.amt_to_forward.write(w)?;
+                               self.outgoing_cltv_value.write(w)?;
+                       },
+                       OnionHopDataFormat::NonFinalNode { short_channel_id } => {
+                               encode_varint_length_prefixed_tlv!(w, {
+                                       (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
+                                       (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)),
+                                       (6, short_channel_id)
+                               });
+                       },
+                       OnionHopDataFormat::FinalNode { ref payment_data } => {
+                               if let &Some(ref final_data) = payment_data {
+                                       encode_varint_length_prefixed_tlv!(w, {
+                                               (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
+                                               (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value)),
+                                               (8, final_data)
+                                       });
+                               } else {
+                                       encode_varint_length_prefixed_tlv!(w, {
+                                               (2, HighZeroBytesDroppedVarInt(self.amt_to_forward)),
+                                               (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value))
+                                       });
+                               }
+                       },
+               }
+               match self.format {
+                       OnionHopDataFormat::Legacy { .. } => {
+                               w.write_all(&[0;12])?;
+                       },
+                       _ => {},
+               }
                Ok(())
        }
 }
 
 impl<R: Read> Readable<R> for OnionHopData {
-       fn read(r: &mut R) -> Result<Self, DecodeError> {
-               Ok(OnionHopData {
-                       realm: {
-                               let r: u8 = Readable::read(r)?;
-                               if r != 0 {
-                                       return Err(DecodeError::UnknownVersion);
+       fn read(mut r: &mut R) -> Result<Self, DecodeError> {
+               use bitcoin::consensus::encode::{Decodable, Error, VarInt};
+               let v: VarInt = Decodable::consensus_decode(&mut r)
+                       .map_err(|e| match e {
+                               Error::Io(ioe) => DecodeError::from(ioe),
+                               _ => DecodeError::InvalidValue
+                       })?;
+               let (format, amt, cltv_value) = if v.0 != 0 {
+                       let mut rd = FixedLengthReader::new(r, v.0);
+                       let mut amt = HighZeroBytesDroppedVarInt(0u64);
+                       let mut cltv_value = HighZeroBytesDroppedVarInt(0u32);
+                       let mut short_id: Option<u64> = None;
+                       let mut payment_data: Option<FinalOnionHopData> = None;
+                       decode_tlv!(&mut rd, {
+                               (2, amt),
+                               (4, cltv_value)
+                       }, {
+                               (6, short_id),
+                               (8, payment_data)
+                       });
+                       rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?;
+                       let format = if let Some(short_channel_id) = short_id {
+                               if payment_data.is_some() { return Err(DecodeError::InvalidValue); }
+                               OnionHopDataFormat::NonFinalNode {
+                                       short_channel_id,
                                }
-                               r
-                       },
-                       data: Readable::read(r)?,
-                       hmac: Readable::read(r)?,
+                       } else {
+                               if let &Some(ref data) = &payment_data {
+                                       if data.total_msat > MAX_VALUE_MSAT {
+                                               return Err(DecodeError::InvalidValue);
+                                       }
+                               }
+                               OnionHopDataFormat::FinalNode {
+                                       payment_data
+                               }
+                       };
+                       (format, amt.0, cltv_value.0)
+               } else {
+                       let format = OnionHopDataFormat::Legacy {
+                               short_channel_id: Readable::read(r)?,
+                       };
+                       let amt: u64 = Readable::read(r)?;
+                       let cltv_value: u32 = Readable::read(r)?;
+                       if amt > MAX_VALUE_MSAT {
+                               return Err(DecodeError::InvalidValue);
+                       }
+                       r.read_exact(&mut [0; 12])?;
+                       (format, amt, cltv_value)
+               };
+
+               Ok(OnionHopData {
+                       format,
+                       amt_to_forward: amt,
+                       outgoing_cltv_value: cltv_value,
                })
        }
 }
@@ -1287,9 +1410,9 @@ impl_writeable_len_match!(NodeAnnouncement, {
 mod tests {
        use hex;
        use ln::msgs;
-       use ln::msgs::{ChannelFeatures, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket};
+       use ln::msgs::{ChannelFeatures, InitFeatures, NodeFeatures, OptionalField, OnionErrorPacket, OnionHopDataFormat};
        use ln::channelmanager::{PaymentPreimage, PaymentHash};
-       use util::ser::Writeable;
+       use util::ser::{Writeable, Readable};
 
        use bitcoin_hashes::sha256d::Hash as Sha256dHash;
        use bitcoin_hashes::hex::FromHex;
@@ -1301,6 +1424,8 @@ mod tests {
        use secp256k1::key::{PublicKey,SecretKey};
        use secp256k1::{Secp256k1, Message};
 
+       use std::io::Cursor;
+
        #[test]
        fn encoding_channel_reestablish_no_secret() {
                let cr = msgs::ChannelReestablish {
@@ -1940,4 +2065,56 @@ mod tests {
                let target_value = hex::decode("004000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000").unwrap();
                assert_eq!(encoded_value, target_value);
        }
+
+       #[test]
+       fn encoding_legacy_onion_hop_data() {
+               let msg = msgs::OnionHopData {
+                       format: OnionHopDataFormat::Legacy {
+                               short_channel_id: 0xdeadbeef1bad1dea,
+                       },
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("00deadbeef1bad1dea0badf00d01020304ffffffff000000000000000000000000").unwrap();
+               assert_eq!(encoded_value, target_value);
+       }
+
+       #[test]
+       fn encoding_nonfinal_onion_hop_data() {
+               let mut msg = msgs::OnionHopData {
+                       format: OnionHopDataFormat::NonFinalNode {
+                               short_channel_id: 0xdeadbeef1bad1dea,
+                       },
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("1a02080badf00d010203040404ffffffff0608deadbeef1bad1dea").unwrap();
+               assert_eq!(encoded_value, target_value);
+               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let OnionHopDataFormat::NonFinalNode { short_channel_id } = msg.format {
+                       assert_eq!(short_channel_id, 0xdeadbeef1bad1dea);
+               } else { panic!(); }
+               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
+               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
+       }
+
+       #[test]
+       fn encoding_final_onion_hop_data() {
+               let mut msg = msgs::OnionHopData {
+                       format: OnionHopDataFormat::FinalNode {
+                               payment_data: None,
+                       },
+                       amt_to_forward: 0x0badf00d01020304,
+                       outgoing_cltv_value: 0xffffffff,
+               };
+               let encoded_value = msg.encode();
+               let target_value = hex::decode("1002080badf00d010203040404ffffffff").unwrap();
+               assert_eq!(encoded_value, target_value);
+               msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+               if let OnionHopDataFormat::FinalNode { payment_data: None } = msg.format { } else { panic!(); }
+               assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
+               assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
+       }
 }