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 crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
+use crate::ln::onion_utils;
+use crate::onion_message;
-use prelude::*;
+use crate::prelude::*;
use core::fmt;
use core::fmt::Debug;
-use io::{self, Read};
-use io_extras::read_to_end;
+use crate::io::{self, Read};
+use crate::io_extras::read_to_end;
-use util::events::MessageSendEventsProvider;
-use util::logger;
-use util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt, Hostname};
+use crate::util::events::{MessageSendEventsProvider, OnionMessageProvider};
+use crate::util::logger;
+use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname};
-use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
/// 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(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum DecodeError {
/// A version byte specified something we don't know how to handle.
/// Includes unknown realm byte in an OnionHopData packet
/// A length descriptor in the packet didn't describe the later data correctly
BadLengthDescriptor,
/// Error from std::io
- Io(/// (C-not exported) as ErrorKind doesn't have a reasonable mapping
- io::ErrorKind),
+ Io(io::ErrorKind),
/// The message included zlib-compressed values, which we don't support.
UnsupportedCompression,
}
/// An init message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Init {
/// The relevant features which the sender supports
pub features: InitFeatures,
}
/// An error message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ErrorMessage {
/// The channel ID involved in the error.
///
}
/// A warning message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct WarningMessage {
/// The channel ID involved in the warning.
///
}
/// A ping message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Ping {
/// The desired response length
pub ponglen: u16,
}
/// A pong message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Pong {
/// The pong packet size.
/// This field is not sent on the wire. byteslen zeros are sent.
}
/// An open_channel message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OpenChannel {
/// The genesis hash of the blockchain where the channel is to be opened
pub chain_hash: BlockHash,
}
/// An accept_channel message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AcceptChannel {
/// A temporary channel ID, until the funding outpoint is announced
pub temporary_channel_id: [u8; 32],
}
/// A funding_created message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FundingCreated {
/// A temporary channel ID, until the funding is established
pub temporary_channel_id: [u8; 32],
}
/// A funding_signed message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct FundingSigned {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A channel_ready message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelReady {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A shutdown message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct Shutdown {
/// The channel ID
pub channel_id: [u8; 32],
/// The minimum and maximum fees which the sender is willing to place on the closing transaction.
/// This is provided in [`ClosingSigned`] by both sides to indicate the fee range they are willing
/// to use.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosingSignedFeeRange {
/// The minimum absolute fee, in satoshis, which the sender is willing to place on the closing
/// transaction.
}
/// A closing_signed message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ClosingSigned {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_add_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateAddHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An onion message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct OnionMessage {
/// Used in decrypting the onion packet's payload.
pub blinding_point: PublicKey,
}
/// An update_fulfill_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFulfillHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_fail_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFailHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_fail_malformed_htlc message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFailMalformedHTLC {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A commitment_signed message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommitmentSigned {
/// The channel ID
pub channel_id: [u8; 32],
}
/// A revoke_and_ack message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RevokeAndACK {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An update_fee message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UpdateFee {
/// The channel ID
pub channel_id: [u8; 32],
pub feerate_per_kw: u32,
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// Proof that the sender knows the per-commitment secret of the previous commitment transaction.
/// This is used to convince the recipient that the channel is at a certain commitment
/// number even if they lost that data due to a local failure. Of course, the peer may lie
}
/// A channel_reestablish message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelReestablish {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An announcement_signatures message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct AnnouncementSignatures {
/// The channel ID
pub channel_id: [u8; 32],
}
/// An address which can be used to connect to a remote peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum NetAddress {
/// An IPv4 address/port on which the peer is listening.
IPv4 {
/// The unsigned part of a node_announcement
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsignedNodeAnnouncement {
/// The advertised features
pub features: NodeFeatures,
pub(crate) excess_address_data: Vec<u8>,
pub(crate) excess_data: Vec<u8>,
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
/// A node_announcement message to be sent or received from a peer
pub struct NodeAnnouncement {
/// The signature by the node key
}
/// The unsigned part of a channel_announcement
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsignedChannelAnnouncement {
/// The advertised channel features
pub features: ChannelFeatures,
pub(crate) excess_data: Vec<u8>,
}
/// A channel_announcement message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelAnnouncement {
/// Authentication of the announcement by the first public node
pub node_signature_1: Signature,
}
/// The unsigned part of a channel_update
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UnsignedChannelUpdate {
/// The genesis hash of the blockchain where the channel is to be opened
pub chain_hash: BlockHash,
pub excess_data: Vec<u8>,
}
/// A channel_update message to be sent or received from a peer
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ChannelUpdate {
/// A signature of the channel update
pub signature: Signature,
/// UTXOs in a range of blocks. The recipient of a query makes a best
/// effort to reply to the query using one or more reply_channel_range
/// messages.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryChannelRange {
/// The genesis hash of the blockchain being queried
pub chain_hash: BlockHash,
/// not be a perfect view of the network. The short_channel_ids in the
/// reply are encoded. We only support encoding_type=0 uncompressed
/// serialization and do not support encoding_type=1 zlib serialization.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReplyChannelRange {
/// The genesis hash of the blockchain being queried
pub chain_hash: BlockHash,
/// reply_short_channel_ids_end message. The short_channel_ids sent in
/// this query are encoded. We only support encoding_type=0 uncompressed
/// serialization and do not support encoding_type=1 zlib serialization.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct QueryShortChannelIds {
/// The genesis hash of the blockchain being queried
pub chain_hash: BlockHash,
/// query_short_channel_ids message. The query recipient makes a best
/// effort to respond based on their local network view which may not be
/// a perfect view of the network.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ReplyShortChannelIdsEnd {
/// The genesis hash of the blockchain that was queried
pub chain_hash: BlockHash,
/// A gossip_timestamp_filter message is used by a node to request
/// gossip relay for messages in the requested time range when the
/// gossip_queries feature has been negotiated.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct GossipTimestampFilter {
/// The genesis hash of the blockchain for channel and node information
pub chain_hash: BlockHash,
/// Struct used to return values from revoke_and_ack messages, containing a bunch of commitment
/// transaction updates if they were pending.
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CommitmentUpdate {
/// update_add_htlc messages which should be sent
pub update_add_htlcs: Vec<UpdateAddHTLC>,
/// OptionalFeild simply gets Present if there are enough bytes to read into it), we have a
/// separate enum type for them.
/// (C-not exported) due to a free generic in T
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
pub enum OptionalField<T> {
/// Optional field is included in message
Present(T),
/// is believed to be possible in the future (eg they're sending us messages we don't
/// understand or indicate they require unknown feature bits), no_connection_possible is set
/// and any outstanding channels should be failed.
+ ///
+ /// Note that in some rare cases this may be called without a corresponding
+ /// [`Self::peer_connected`].
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, msg: &Init);
+ ///
+ /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
+ /// 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, msg: &Init) -> Result<(), ()>;
/// Handle an incoming channel_reestablish message from the given peer.
fn handle_channel_reestablish(&self, their_node_id: &PublicKey, msg: &ChannelReestablish);
// 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 [`NodeAnnouncement`] 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.
/// 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.
- fn peer_connected(&self, their_node_id: &PublicKey, init: &Init);
+ ///
+ /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
+ /// 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) -> Result<(), ()>;
/// Handles the reply of a query we initiated to learn about channels
/// for a given range of blocks. We can expect to receive one or more
/// replies to a single query.
/// 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 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 [`NodeAnnouncement`] 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 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.
+ ///
+ /// May return an `Err(())` if the features the peer supports are not sufficient to communicate
+ /// 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) -> 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.
+ ///
+ /// Note that in some rare cases this may be called without a corresponding
+ /// [`Self::peer_connected`].
+ fn peer_disconnected(&self, their_node_id: &PublicKey, no_connection_possible: bool);
+
+ // 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 [`NodeAnnouncement`] 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;
}
mod fuzzy_internal_msgs {
- use prelude::*;
- use ln::{PaymentPreimage, PaymentSecret};
+ use crate::prelude::*;
+ use crate::ln::{PaymentPreimage, PaymentSecret};
// These types aren't intended to be pub, but are exposed for direct fuzzing (as we deserialize
// them from untrusted input):
}
pub(crate) enum OnionHopDataFormat {
- Legacy { // aka Realm-0
- short_channel_id: u64,
- },
NonFinalNode {
short_channel_id: u64,
},
/// Message serialization may panic if this value is more than 21 million Bitcoin.
pub(crate) amt_to_forward: u64,
pub(crate) outgoing_cltv_value: u32,
- // 12 bytes of 0-padding for Legacy format
}
pub struct DecodedOnionErrorPacket {
}
}
+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()) {
}
}
-#[derive(Clone, Debug, PartialEq)]
+#[derive(Clone, Debug, 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...
impl Writeable for FinalOnionHopData {
fn write<W: Writer>(&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: Read>(r: &mut R) -> Result<Self, DecodeError> {
let secret: [u8; 32] = Readable::read(r)?;
- let amt: HighZeroBytesDroppedVarInt<u64> = Readable::read(r)?;
+ let amt: HighZeroBytesDroppedBigSize<u64> = Readable::read(r)?;
Ok(Self { payment_secret: PaymentSecret(secret), total_msat: amt.0 })
}
}
impl Writeable for OnionHopData {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
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)?;
- w.write_all(&[0;12])?;
- },
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)
});
}
}
-// ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
-// onion message packets.
-impl ReadableArgs<()> for OnionHopData {
- fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
- <Self as Readable>::read(r)
- }
-}
-
impl Readable for OnionHopData {
- fn read<R: 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
- })?;
- 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 mut short_id: Option<u64> = None;
- let mut payment_data: Option<FinalOnionHopData> = None;
- let mut keysend_preimage: Option<PaymentPreimage> = 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),
- (5482373484, keysend_preimage, option)
- });
- 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,
- }
- } else {
- if let &Some(ref data) = &payment_data {
- if data.total_msat > MAX_VALUE_MSAT {
- return Err(DecodeError::InvalidValue);
- }
- }
- OnionHopDataFormat::FinalNode {
- payment_data,
- keysend_preimage,
- }
- };
- (format, amt.0, cltv_value.0)
+ fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
+ let mut amt = HighZeroBytesDroppedBigSize(0u64);
+ let mut cltv_value = HighZeroBytesDroppedBigSize(0u32);
+ let mut short_id: Option<u64> = None;
+ let mut payment_data: Option<FinalOnionHopData> = None;
+ let mut keysend_preimage: Option<PaymentPreimage> = None;
+ read_tlv_fields!(r, {
+ (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)
+ });
+
+ let format = if let Some(short_channel_id) = short_id {
+ if payment_data.is_some() { return Err(DecodeError::InvalidValue); }
+ OnionHopDataFormat::NonFinalNode {
+ short_channel_id,
+ }
} else {
- let format = OnionHopDataFormat::Legacy {
- short_channel_id: Readable::read(r)?,
- };
- let amt: u64 = Readable::read(r)?;
- let cltv_value: u32 = Readable::read(r)?;
- r.read_exact(&mut [0; 12])?;
- (format, amt, cltv_value)
+ if let &Some(ref data) = &payment_data {
+ if data.total_msat > MAX_VALUE_MSAT {
+ return Err(DecodeError::InvalidValue);
+ }
+ }
+ OnionHopDataFormat::FinalNode {
+ payment_data,
+ keysend_preimage,
+ }
};
- if amt > MAX_VALUE_MSAT {
+ if amt.0 > MAX_VALUE_MSAT {
return Err(DecodeError::InvalidValue);
}
Ok(OnionHopData {
format,
- amt_to_forward: amt,
- outgoing_cltv_value: cltv_value,
+ amt_to_forward: amt.0,
+ outgoing_cltv_value: cltv_value.0,
})
}
}
+// ReadableArgs because we need onion_utils::decode_next_hop to accommodate payment packets and
+// onion message packets.
+impl ReadableArgs<()> for OnionHopData {
+ fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
+ <Self as Readable>::read(r)
+ }
+}
+
impl Writeable for Ping {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
self.ponglen.write(w)?;
#[cfg(test)]
mod tests {
use hex;
- use ln::{PaymentPreimage, PaymentHash, PaymentSecret};
- use ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
- use ln::msgs;
- use ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat};
- use util::ser::{Writeable, Readable, Hostname};
+ use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
+ use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
+ use crate::ln::msgs;
+ use crate::ln::msgs::{FinalOnionHopData, OptionalField, OnionErrorPacket, OnionHopDataFormat};
+ use crate::util::ser::{Writeable, Readable, Hostname};
use bitcoin::hashes::hex::FromHex;
use bitcoin::util::address::Address;
use bitcoin::secp256k1::{PublicKey,SecretKey};
use bitcoin::secp256k1::{Secp256k1, Message};
- use io::Cursor;
- use prelude::*;
+ use crate::io::{self, Cursor};
+ use crate::prelude::*;
use core::convert::TryFrom;
#[test]
let sig_2 = get_sig_on!(privkey_2, secp_ctx, String::from("01010101010101010101010101010101"));
let sig_3 = get_sig_on!(privkey_3, secp_ctx, String::from("01010101010101010101010101010101"));
let sig_4 = get_sig_on!(privkey_4, secp_ctx, String::from("01010101010101010101010101010101"));
- let mut features = ChannelFeatures::known();
+ let mut features = ChannelFeatures::empty();
if unknown_features_bits {
features = ChannelFeatures::from_le_bytes(vec![0xFF, 0xFF]);
}
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 {
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[..]);
+ <msgs::OnionHopData as Readable>::read(&mut rd).unwrap();
+ }
+ // see above test, needs to be a separate method for use of the serialization macros.
+ fn encode_big_payload() -> Result<Vec<u8>, io::Error> {
+ use crate::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)
+ }
}