X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=e063c31464fc89a7f93b57c16e18f6f3dc62b8eb;hb=e94e403dda57e1443fdeda9f1d0b2cb8a9e7fb0f;hp=3e44cfcf024034a7de39a614e50cc5a974cfc632;hpb=dcc445fa85e3dd85797d2cab35276f13a0f56184;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 3e44cfcf..e063c314 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -31,6 +31,8 @@ use bitcoin::blockdata::script::Script; use bitcoin::hash_types::{Txid, BlockHash}; use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; +use ln::onion_utils; +use onion_message; use prelude::*; use core::fmt; @@ -38,9 +40,9 @@ use core::fmt::Debug; use io::{self, Read}; use io_extras::read_to_end; -use util::events::MessageSendEventsProvider; +use util::events::{MessageSendEventsProvider, OnionMessageProvider}; use util::logger; -use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, Hostname}; +use util::ser::{BigSize, LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname}; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -304,6 +306,14 @@ pub struct UpdateAddHTLC { pub(crate) onion_routing_packet: OnionPacket, } + /// An onion message to be sent or received from a peer +#[derive(Clone, Debug, PartialEq)] +pub struct OnionMessage { + /// Used in decrypting the onion packet's payload. + pub blinding_point: PublicKey, + pub(crate) onion_routing_packet: onion_message::Packet, +} + /// An update_fulfill_htlc message to be sent or received from a peer #[derive(Clone, Debug, PartialEq)] pub struct UpdateFulfillHTLC { @@ -647,8 +657,8 @@ pub struct UnsignedChannelUpdate { pub cltv_expiry_delta: u16, /// The minimum HTLC size incoming to sender, in milli-satoshi pub htlc_minimum_msat: u64, - /// Optionally, the maximum HTLC value incoming to sender, in milli-satoshi - pub htlc_maximum_msat: OptionalField, + /// The maximum HTLC value incoming to sender, in milli-satoshi. Used to be optional. + pub htlc_maximum_msat: u64, /// The base HTLC fee charged by sender, in milli-satoshi pub fee_base_msat: u32, /// The amount to fee multiplier, in micro-satoshi @@ -886,6 +896,19 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider { // Error: /// Handle an incoming error message from the given peer. fn handle_error(&self, their_node_id: &PublicKey, msg: &ErrorMessage); + + // Handler information: + /// Gets the node feature flags which this handler itself supports. All available handlers are + /// queried similarly and their feature flags are OR'd together to form the [`NodeFeatures`] + /// which are broadcasted in our node_announcement message. + fn provided_node_features(&self) -> NodeFeatures; + + /// Gets the init feature flags which should be sent to the given peer. All available handlers + /// are queried similarly and their feature flags are OR'd together to form the [`InitFeatures`] + /// which are sent in our [`Init`] message. + /// + /// Note that this method is called before [`Self::peer_connected`]. + fn provided_init_features(&self, their_node_id: &PublicKey) -> InitFeatures; } /// A trait to describe an object which can receive routing messages. @@ -905,15 +928,15 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider { /// Handle an incoming channel_update message, returning true if it should be forwarded on, /// false or returning an Err otherwise. fn handle_channel_update(&self, msg: &ChannelUpdate) -> Result; - /// Gets a subset of the channel announcements and updates required to dump our routing table - /// to a remote node, starting at the short_channel_id indicated by starting_point and - /// including the batch_amount entries immediately higher in numerical value than starting_point. - fn get_next_channel_announcements(&self, starting_point: u64, batch_amount: u8) -> Vec<(ChannelAnnouncement, Option, Option)>; - /// Gets a subset of the node announcements required to dump our routing table to a remote node, - /// starting at the node *after* the provided publickey and including batch_amount entries - /// immediately higher (as defined by ::cmp) than starting_point. + /// Gets channel announcements and updates required to dump our routing table to a remote node, + /// starting at the short_channel_id indicated by starting_point and including announcements + /// for a single channel. + fn get_next_channel_announcement(&self, starting_point: u64) -> Option<(ChannelAnnouncement, Option, Option)>; + /// Gets a node announcement required to dump our routing table to a remote node, starting at + /// the node *after* the provided pubkey and including up to one announcement immediately + /// higher (as defined by ::cmp) than starting_point. /// If None is provided for starting_point, we start at the first node. - fn get_next_node_announcements(&self, starting_point: Option<&PublicKey>, batch_amount: u8) -> Vec; + fn get_next_node_announcement(&self, starting_point: Option<&PublicKey>) -> Option; /// Called when a connection is established with a peer. This can be used to /// perform routing table synchronization using a strategy defined by the /// implementor. @@ -933,6 +956,26 @@ pub trait RoutingMessageHandler : MessageSendEventsProvider { /// Handles when a peer asks us to send routing gossip messages for a /// list of short_channel_ids. fn handle_query_short_channel_ids(&self, their_node_id: &PublicKey, msg: QueryShortChannelIds) -> Result<(), LightningError>; + + // Handler information: + /// Gets the init feature flags which should be sent to the given peer. All available handlers + /// are queried similarly and their feature flags are OR'd together to form the [`InitFeatures`] + /// which are sent in our [`Init`] message. + /// + /// Note that this method is called before [`Self::peer_connected`]. + 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 { + /// Handle an incoming onion_message message from the given peer. + fn handle_onion_message(&self, peer_node_id: &PublicKey, msg: &OnionMessage); + /// Called when a connection is established with a peer. Can be used to track which peers + /// advertise onion message support and are online. + fn peer_connected(&self, their_node_id: &PublicKey, init: &Init); + /// 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, no_connection_possible: bool); } mod fuzzy_internal_msgs { @@ -993,6 +1036,18 @@ pub(crate) struct OnionPacket { pub(crate) hmac: [u8; 32], } +impl onion_utils::Packet for OnionPacket { + type Data = onion_utils::FixedSizeOnionPacket; + fn new(pubkey: PublicKey, hop_data: onion_utils::FixedSizeOnionPacket, hmac: [u8; 32]) -> Self { + Self { + version: 0, + public_key: Ok(pubkey), + hop_data: hop_data.0, + hmac, + } + } +} + impl PartialEq for OnionPacket { fn eq(&self, other: &OnionPacket) -> bool { for (i, j) in self.hop_data.iter().zip(other.hop_data.iter()) { @@ -1327,17 +1382,40 @@ impl_writeable_msg!(UpdateAddHTLC, { onion_routing_packet }, {}); +impl Readable for OnionMessage { + fn read(r: &mut R) -> Result { + let blinding_point: PublicKey = Readable::read(r)?; + let len: u16 = Readable::read(r)?; + let mut packet_reader = FixedLengthReader::new(r, len as u64); + let onion_routing_packet: onion_message::Packet = ::read(&mut packet_reader)?; + Ok(Self { + blinding_point, + onion_routing_packet, + }) + } +} + +impl Writeable for OnionMessage { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + self.blinding_point.write(w)?; + let onion_packet_len = self.onion_routing_packet.serialized_length(); + (onion_packet_len as u16).write(w)?; + self.onion_routing_packet.write(w)?; + Ok(()) + } +} + impl Writeable for FinalOnionHopData { fn write(&self, w: &mut W) -> Result<(), io::Error> { self.payment_secret.0.write(w)?; - HighZeroBytesDroppedVarInt(self.total_msat).write(w) + HighZeroBytesDroppedBigSize(self.total_msat).write(w) } } impl Readable for FinalOnionHopData { fn read(r: &mut R) -> Result { let secret: [u8; 32] = Readable::read(r)?; - let amt: HighZeroBytesDroppedVarInt = Readable::read(r)?; + let amt: HighZeroBytesDroppedBigSize = Readable::read(r)?; Ok(Self { payment_secret: PaymentSecret(secret), total_msat: amt.0 }) } } @@ -1354,15 +1432,15 @@ impl Writeable for OnionHopData { }, OnionHopDataFormat::NonFinalNode { short_channel_id } => { encode_varint_length_prefixed_tlv!(w, { - (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required), - (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required), + (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required), + (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required), (6, short_channel_id, required) }); }, OnionHopDataFormat::FinalNode { ref payment_data, ref keysend_preimage } => { encode_varint_length_prefixed_tlv!(w, { - (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required), - (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required), + (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required), + (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required), (8, payment_data, option), (5482373484, keysend_preimage, option) }); @@ -1373,27 +1451,22 @@ impl Writeable for OnionHopData { } impl Readable for OnionHopData { - fn read(mut r: &mut R) -> Result { - 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 - })?; + fn read(r: &mut R) -> Result { + let b: BigSize = Readable::read(r)?; const LEGACY_ONION_HOP_FLAG: u64 = 0; - let (format, amt, cltv_value) = if v.0 != LEGACY_ONION_HOP_FLAG { - let mut rd = FixedLengthReader::new(r, v.0); - let mut amt = HighZeroBytesDroppedVarInt(0u64); - let mut cltv_value = HighZeroBytesDroppedVarInt(0u32); + let (format, amt, cltv_value) = if b.0 != LEGACY_ONION_HOP_FLAG { + let mut rd = FixedLengthReader::new(r, b.0); + let mut amt = HighZeroBytesDroppedBigSize(0u64); + let mut cltv_value = HighZeroBytesDroppedBigSize(0u32); let mut short_id: Option = None; let mut payment_data: Option = None; let mut keysend_preimage: Option = None; - // The TLV type is chosen to be compatible with lnd and c-lightning. decode_tlv_stream!(&mut rd, { (2, amt, required), (4, cltv_value, required), (6, short_id, option), (8, payment_data, option), + // See https://github.com/lightning/blips/blob/master/blip-0003.md (5482373484, keysend_preimage, option) }); rd.eat_remaining().map_err(|_| DecodeError::ShortRead)?; @@ -1435,6 +1508,14 @@ impl Readable for OnionHopData { } } +// ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and +// onion message packets. +impl ReadableArgs<()> for OnionHopData { + fn read(r: &mut R, _arg: ()) -> Result { + ::read(r) + } +} + impl Writeable for Ping { fn write(&self, w: &mut W) -> Result<(), io::Error> { self.ponglen.write(w)?; @@ -1514,14 +1595,12 @@ impl_writeable!(ChannelAnnouncement, { impl Writeable for UnsignedChannelUpdate { fn write(&self, w: &mut W) -> Result<(), io::Error> { - let mut message_flags: u8 = 0; - if let OptionalField::Present(_) = self.htlc_maximum_msat { - message_flags = 1; - } + // `message_flags` used to indicate presence of `htlc_maximum_msat`, but was deprecated in the spec. + const MESSAGE_FLAGS: u8 = 1; self.chain_hash.write(w)?; self.short_channel_id.write(w)?; self.timestamp.write(w)?; - let all_flags = self.flags as u16 | ((message_flags as u16) << 8); + let all_flags = self.flags as u16 | ((MESSAGE_FLAGS as u16) << 8); all_flags.write(w)?; self.cltv_expiry_delta.write(w)?; self.htlc_minimum_msat.write(w)?; @@ -1535,22 +1614,20 @@ impl Writeable for UnsignedChannelUpdate { impl Readable for UnsignedChannelUpdate { fn read(r: &mut R) -> Result { - let has_htlc_maximum_msat; Ok(Self { chain_hash: Readable::read(r)?, short_channel_id: Readable::read(r)?, timestamp: Readable::read(r)?, flags: { let flags: u16 = Readable::read(r)?; - let message_flags = flags >> 8; - has_htlc_maximum_msat = (message_flags as i32 & 1) == 1; + // Note: we ignore the `message_flags` for now, since it was deprecated by the spec. flags as u8 }, cltv_expiry_delta: Readable::read(r)?, htlc_minimum_msat: Readable::read(r)?, fee_base_msat: Readable::read(r)?, fee_proportional_millionths: Readable::read(r)?, - htlc_maximum_msat: if has_htlc_maximum_msat { Readable::read(r)? } else { OptionalField::Absent }, + htlc_maximum_msat: Readable::read(r)?, excess_data: read_to_end(r)?, }) } @@ -1864,7 +1941,7 @@ mod tests { use bitcoin::secp256k1::{PublicKey,SecretKey}; use bitcoin::secp256k1::{Secp256k1, Message}; - use io::Cursor; + use io::{self, Cursor}; use prelude::*; use core::convert::TryFrom; @@ -2103,7 +2180,7 @@ mod tests { do_encoding_node_announcement(false, false, true, false, true, false, false, false); } - fn do_encoding_channel_update(direction: bool, disable: bool, htlc_maximum_msat: bool, excess_data: bool) { + fn do_encoding_channel_update(direction: bool, disable: bool, excess_data: bool) { let secp_ctx = Secp256k1::new(); let (privkey_1, _) = get_keys_from!("0101010101010101010101010101010101010101010101010101010101010101", secp_ctx); let sig_1 = get_sig_on!(privkey_1, secp_ctx, String::from("01010101010101010101010101010101")); @@ -2114,7 +2191,7 @@ mod tests { flags: if direction { 1 } else { 0 } | if disable { 1 << 1 } else { 0 }, cltv_expiry_delta: 144, htlc_minimum_msat: 1000000, - htlc_maximum_msat: if htlc_maximum_msat { OptionalField::Present(131355275467161) } else { OptionalField::Absent }, + htlc_maximum_msat: 131355275467161, fee_base_msat: 10000, fee_proportional_millionths: 20, excess_data: if excess_data { vec![0, 0, 0, 0, 59, 154, 202, 0] } else { Vec::new() } @@ -2127,11 +2204,7 @@ mod tests { let mut target_value = hex::decode("d977cb9b53d93a6ff64bb5f1e158b4094b66e798fb12911168a3ccdf80a83096340a6a95da0ae8d9f776528eecdbb747eb6b545495a4319ed5378e35b21e073a").unwrap(); target_value.append(&mut hex::decode("000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f").unwrap()); target_value.append(&mut hex::decode("00083a840000034d013413a7").unwrap()); - if htlc_maximum_msat { - target_value.append(&mut hex::decode("01").unwrap()); - } else { - target_value.append(&mut hex::decode("00").unwrap()); - } + target_value.append(&mut hex::decode("01").unwrap()); target_value.append(&mut hex::decode("00").unwrap()); if direction { let flag = target_value.last_mut().unwrap(); @@ -2142,9 +2215,7 @@ mod tests { *flag = *flag | 1 << 1; } target_value.append(&mut hex::decode("009000000000000f42400000271000000014").unwrap()); - if htlc_maximum_msat { - target_value.append(&mut hex::decode("0000777788889999").unwrap()); - } + target_value.append(&mut hex::decode("0000777788889999").unwrap()); if excess_data { target_value.append(&mut hex::decode("000000003b9aca00").unwrap()); } @@ -2153,16 +2224,14 @@ mod tests { #[test] fn encoding_channel_update() { - do_encoding_channel_update(false, false, false, false); - do_encoding_channel_update(false, false, false, true); - do_encoding_channel_update(true, false, false, false); - do_encoding_channel_update(true, false, false, true); - do_encoding_channel_update(false, true, false, false); - do_encoding_channel_update(false, true, false, true); - do_encoding_channel_update(false, false, true, false); - do_encoding_channel_update(false, false, true, true); - do_encoding_channel_update(true, true, true, false); - do_encoding_channel_update(true, true, true, true); + do_encoding_channel_update(false, false, false); + do_encoding_channel_update(false, false, true); + do_encoding_channel_update(true, false, false); + do_encoding_channel_update(true, false, true); + do_encoding_channel_update(false, true, false); + do_encoding_channel_update(false, true, true); + do_encoding_channel_update(true, true, false); + do_encoding_channel_update(true, true, true); } fn do_encoding_open_channel(random_bit: bool, shutdown: bool, incl_chan_type: bool) { @@ -2783,4 +2852,40 @@ mod tests { assert_eq!(gossip_timestamp_filter.first_timestamp, 1590000000); assert_eq!(gossip_timestamp_filter.timestamp_range, 0xffff_ffff); } + + #[test] + fn decode_onion_hop_data_len_as_bigsize() { + // Tests that we can decode an onion payload that is >253 bytes. + // Previously, receiving a payload of this size could've caused us to fail to decode a valid + // payload, because we were decoding the length (a BigSize, big-endian) as a VarInt + // (little-endian). + + // Encode a test onion payload with a big custom TLV such that it's >253 bytes, forcing the + // payload length to be encoded over multiple bytes rather than a single u8. + let big_payload = encode_big_payload().unwrap(); + let mut rd = Cursor::new(&big_payload[..]); + ::read(&mut rd).unwrap(); + } + // see above test, needs to be a separate method for use of the serialization macros. + fn encode_big_payload() -> Result, io::Error> { + use util::ser::HighZeroBytesDroppedBigSize; + let payload = msgs::OnionHopData { + format: OnionHopDataFormat::NonFinalNode { + short_channel_id: 0xdeadbeef1bad1dea, + }, + amt_to_forward: 1000, + outgoing_cltv_value: 0xffffffff, + }; + let mut encoded_payload = Vec::new(); + let test_bytes = vec![42u8; 1000]; + if let OnionHopDataFormat::NonFinalNode { short_channel_id } = payload.format { + encode_varint_length_prefixed_tlv!(&mut encoded_payload, { + (1, test_bytes, vec_type), + (2, HighZeroBytesDroppedBigSize(payload.amt_to_forward), required), + (4, HighZeroBytesDroppedBigSize(payload.outgoing_cltv_value), required), + (6, short_channel_id, required) + }); + } + Ok(encoded_payload) + } }