//! raw socket events into your non-internet-facing system and then send routing events back to
//! track the network on the less-secure system.
+use bitcoin::blockdata::constants::ChainHash;
use bitcoin::secp256k1::PublicKey;
use bitcoin::secp256k1::ecdsa::Signature;
use bitcoin::{secp256k1, Witness};
use crate::events::{MessageSendEventsProvider, OnionMessageProvider};
use crate::util::logger;
-use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited};
+use crate::util::ser::{LengthReadable, Readable, ReadableArgs, Writeable, Writer, WithoutLength, FixedLengthReader, HighZeroBytesDroppedBigSize, Hostname, TransactionU16LenLimited, BigSize};
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
pub struct Init {
/// The relevant features which the sender supports.
pub features: InitFeatures,
+ /// Indicates chains the sender is interested in.
+ ///
+ /// If there are no common chains, the connection will be closed.
+ pub networks: Option<Vec<ChainHash>>,
/// The receipient's network address.
///
/// This adds the option to report a remote IP address back to a connecting peer using the init
pub payment_hash: PaymentHash,
/// The expiry height of the HTLC
pub cltv_expiry: u32,
+ /// The extra fee skimmed by the sender of this message. See
+ /// [`ChannelConfig::accept_underpaying_htlcs`].
+ ///
+ /// [`ChannelConfig::accept_underpaying_htlcs`]: crate::util::config::ChannelConfig::accept_underpaying_htlcs
+ pub skimmed_fee_msat: Option<u64>,
pub(crate) onion_routing_packet: OnionPacket,
}
pub bitcoin_key_1: NodeId,
/// The funding key for the second node
pub bitcoin_key_2: NodeId,
- pub(crate) excess_data: Vec<u8>,
+ /// Excess data which was signed as a part of the message which we do not (yet) understand how
+ /// to decode.
+ ///
+ /// This is stored to ensure forward-compatibility as new fields are added to the lightning gossip protocol.
+ pub excess_data: Vec<u8>,
}
/// A [`channel_announcement`] message to be sent to or received from a peer.
///
}
/// Used to put an error message in a [`LightningError`].
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, PartialEq)]
pub enum ErrorAction {
/// The peer took some action which made us think they were useless. Disconnect them.
DisconnectPeer {
/// An error message which we should make an effort to send before we disconnect.
msg: Option<ErrorMessage>
},
+ /// The peer did something incorrect. Tell them without closing any channels and disconnect them.
+ DisconnectPeerWithWarning {
+ /// A warning message which we should make an effort to send before we disconnect.
+ msg: WarningMessage,
+ },
/// The peer did something harmless that we weren't able to process, just log and ignore
// New code should *not* use this. New code must use IgnoreAndLog, below!
IgnoreError,
///
/// 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.
+ ///
+ /// If it's `None`, then no particular network chain hash compatibility will be enforced when
+ /// connecting to peers.
+ fn get_genesis_hashes(&self) -> Option<Vec<ChainHash>>;
}
/// A trait to describe an object which can receive routing messages.
// 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: PaymentSecret,
+ pub struct FinalOnionHopData {
+ pub payment_secret: PaymentSecret,
/// The total value, in msat, of the payment as received by the ultimate recipient.
/// Message serialization may panic if this value is more than 21 million Bitcoin.
- pub(crate) total_msat: u64,
+ pub total_msat: u64,
}
- pub(crate) enum OnionHopDataFormat {
- NonFinalNode {
+ pub enum InboundOnionPayload {
+ Forward {
short_channel_id: u64,
+ /// The value, in msat, of the payment after this hop's fee is deducted.
+ amt_to_forward: u64,
+ outgoing_cltv_value: u32,
},
- FinalNode {
+ Receive {
payment_data: Option<FinalOnionHopData>,
payment_metadata: Option<Vec<u8>>,
keysend_preimage: Option<PaymentPreimage>,
+ custom_tlvs: Vec<(u64, Vec<u8>)>,
+ amt_msat: u64,
+ outgoing_cltv_value: u32,
},
}
- pub struct OnionHopData {
- pub(crate) format: OnionHopDataFormat,
- /// The value, in msat, of the payment after this hop's fee is deducted.
- /// 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,
+ pub(crate) enum OutboundOnionPayload {
+ Forward {
+ short_channel_id: u64,
+ /// The value, in msat, of the payment after this hop's fee is deducted.
+ amt_to_forward: u64,
+ outgoing_cltv_value: u32,
+ },
+ Receive {
+ payment_data: Option<FinalOnionHopData>,
+ payment_metadata: Option<Vec<u8>>,
+ keysend_preimage: Option<PaymentPreimage>,
+ custom_tlvs: Vec<(u64, Vec<u8>)>,
+ amt_msat: u64,
+ outgoing_cltv_value: u32,
+ },
}
pub struct DecodedOnionErrorPacket {
self.features.write_up_to_13(w)?;
self.features.write(w)?;
encode_tlv_stream!(w, {
- (3, self.remote_network_address, option)
+ (1, self.networks.as_ref().map(|n| WithoutLength(n)), option),
+ (3, self.remote_network_address, option),
});
Ok(())
}
let global_features: InitFeatures = Readable::read(r)?;
let features: InitFeatures = Readable::read(r)?;
let mut remote_network_address: Option<NetAddress> = None;
+ let mut networks: Option<WithoutLength<Vec<ChainHash>>> = None;
decode_tlv_stream!(r, {
+ (1, networks, option),
(3, remote_network_address, option)
});
Ok(Init {
features: features | global_features,
+ networks: networks.map(|n| n.0),
remote_network_address,
})
}
amount_msat,
payment_hash,
cltv_expiry,
- onion_routing_packet
-}, {});
+ onion_routing_packet,
+}, {
+ (65537, skimmed_fee_msat, option)
+});
impl Readable for OnionMessage {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
}
}
-impl Writeable for OnionHopData {
+impl Writeable for OutboundOnionPayload {
fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
- match self.format {
- OnionHopDataFormat::NonFinalNode { short_channel_id } => {
+ match self {
+ Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } => {
_encode_varint_length_prefixed_tlv!(w, {
- (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
- (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
+ (2, HighZeroBytesDroppedBigSize(*amt_to_forward), required),
+ (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(6, short_channel_id, required)
});
},
- OnionHopDataFormat::FinalNode { ref payment_data, ref payment_metadata, ref keysend_preimage } => {
+ Self::Receive {
+ ref payment_data, ref payment_metadata, ref keysend_preimage, amt_msat,
+ outgoing_cltv_value, ref custom_tlvs,
+ } => {
+ // We need to update [`ln::outbound_payment::RecipientOnionFields::with_custom_tlvs`]
+ // to reject any reserved types in the experimental range if new ones are ever
+ // standardized.
+ let keysend_tlv = keysend_preimage.map(|preimage| (5482373484, preimage.encode()));
+ let mut custom_tlvs: Vec<&(u64, Vec<u8>)> = custom_tlvs.iter().chain(keysend_tlv.iter()).collect();
+ custom_tlvs.sort_unstable_by_key(|(typ, _)| *typ);
_encode_varint_length_prefixed_tlv!(w, {
- (2, HighZeroBytesDroppedBigSize(self.amt_to_forward), required),
- (4, HighZeroBytesDroppedBigSize(self.outgoing_cltv_value), required),
+ (2, HighZeroBytesDroppedBigSize(*amt_msat), required),
+ (4, HighZeroBytesDroppedBigSize(*outgoing_cltv_value), required),
(8, payment_data, option),
- (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option),
- (5482373484, keysend_preimage, option)
- });
+ (16, payment_metadata.as_ref().map(|m| WithoutLength(m)), option)
+ }, custom_tlvs.iter());
},
}
Ok(())
}
}
-impl Readable for OnionHopData {
+impl Readable for InboundOnionPayload {
fn read<R: Read>(r: &mut R) -> Result<Self, DecodeError> {
let mut amt = HighZeroBytesDroppedBigSize(0u64);
let mut cltv_value = HighZeroBytesDroppedBigSize(0u32);
let mut payment_data: Option<FinalOnionHopData> = None;
let mut payment_metadata: Option<WithoutLength<Vec<u8>>> = None;
let mut keysend_preimage: Option<PaymentPreimage> = None;
- read_tlv_fields!(r, {
+ let mut custom_tlvs = Vec::new();
+
+ let tlv_len = BigSize::read(r)?;
+ let rd = FixedLengthReader::new(r, tlv_len.0);
+ decode_tlv_stream_with_custom_tlv_decode!(rd, {
(2, amt, required),
(4, cltv_value, required),
(6, short_id, option),
(16, payment_metadata, option),
// See https://github.com/lightning/blips/blob/master/blip-0003.md
(5482373484, keysend_preimage, option)
+ }, |msg_type: u64, msg_reader: &mut FixedLengthReader<_>| -> Result<bool, DecodeError> {
+ if msg_type < 1 << 16 { return Ok(false) }
+ let mut value = Vec::new();
+ msg_reader.read_to_end(&mut value)?;
+ custom_tlvs.push((msg_type, value));
+ Ok(true)
});
- let format = if let Some(short_channel_id) = short_id {
- if payment_data.is_some() { return Err(DecodeError::InvalidValue); }
+ if amt.0 > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) }
+ if let Some(short_channel_id) = short_id {
+ if payment_data.is_some() { return Err(DecodeError::InvalidValue) }
if payment_metadata.is_some() { return Err(DecodeError::InvalidValue); }
- OnionHopDataFormat::NonFinalNode {
+ Ok(Self::Forward {
short_channel_id,
- }
+ amt_to_forward: amt.0,
+ outgoing_cltv_value: cltv_value.0,
+ })
} else {
if let Some(data) = &payment_data {
if data.total_msat > MAX_VALUE_MSAT {
return Err(DecodeError::InvalidValue);
}
}
- OnionHopDataFormat::FinalNode {
+ Ok(Self::Receive {
payment_data,
payment_metadata: payment_metadata.map(|w| w.0),
keysend_preimage,
- }
- };
-
- if amt.0 > MAX_VALUE_MSAT {
- return Err(DecodeError::InvalidValue);
+ amt_msat: amt.0,
+ outgoing_cltv_value: cltv_value.0,
+ custom_tlvs,
+ })
}
- Ok(OnionHopData {
- format,
- 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 {
+impl ReadableArgs<()> for InboundOnionPayload {
fn read<R: Read>(r: &mut R, _arg: ()) -> Result<Self, DecodeError> {
<Self as Readable>::read(r)
}
#[cfg(test)]
mod tests {
+ use bitcoin::blockdata::constants::ChainHash;
use bitcoin::{Transaction, PackedLockTime, TxIn, Script, Sequence, Witness, TxOut};
use hex;
use crate::ln::{PaymentPreimage, PaymentHash, PaymentSecret};
use crate::ln::features::{ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures};
- use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket, OnionHopDataFormat};
+ use crate::ln::msgs::{self, FinalOnionHopData, OnionErrorPacket};
use crate::routing::gossip::{NodeAlias, NodeId};
use crate::util::ser::{Writeable, Readable, Hostname, TransactionU16LenLimited};
amount_msat: 3608586615801332854,
payment_hash: PaymentHash([1; 32]),
cltv_expiry: 821716,
- onion_routing_packet
+ onion_routing_packet,
+ skimmed_fee_msat: None,
};
let encoded_value = update_add_htlc.encode();
let target_value = hex::decode("020202020202020202020202020202020202020202020202020202020202020200083a840000034d32144668701144760101010101010101010101010101010101010101010101010101010101010101000c89d4ff031b84c5567b126440995d3ed5aaba0565d71e1834604819ff9c17f5e9d5dd078f010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap();
#[test]
fn encoding_init() {
+ let mainnet_hash = ChainHash::from_hex("6fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap();
assert_eq!(msgs::Init {
features: InitFeatures::from_le_bytes(vec![0xFF, 0xFF, 0xFF]),
+ networks: Some(vec![mainnet_hash]),
remote_network_address: None,
- }.encode(), hex::decode("00023fff0003ffffff").unwrap());
+ }.encode(), hex::decode("00023fff0003ffffff01206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap());
assert_eq!(msgs::Init {
features: InitFeatures::from_le_bytes(vec![0xFF]),
+ networks: None,
remote_network_address: None,
}.encode(), hex::decode("0001ff0001ff").unwrap());
assert_eq!(msgs::Init {
features: InitFeatures::from_le_bytes(vec![]),
+ networks: Some(vec![mainnet_hash]),
remote_network_address: None,
- }.encode(), hex::decode("00000000").unwrap());
-
+ }.encode(), hex::decode("0000000001206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d6190000000000").unwrap());
+ assert_eq!(msgs::Init {
+ features: InitFeatures::from_le_bytes(vec![]),
+ networks: Some(vec![ChainHash::from(&[1; 32][..]), ChainHash::from(&[2; 32][..])]),
+ remote_network_address: None,
+ }.encode(), hex::decode("00000000014001010101010101010101010101010101010101010101010101010101010101010202020202020202020202020202020202020202020202020202020202020202").unwrap());
let init_msg = msgs::Init { features: InitFeatures::from_le_bytes(vec![]),
+ networks: Some(vec![mainnet_hash]),
remote_network_address: Some(msgs::NetAddress::IPv4 {
addr: [127, 0, 0, 1],
port: 1000,
}),
};
let encoded_value = init_msg.encode();
- let target_value = hex::decode("000000000307017f00000103e8").unwrap();
+ let target_value = hex::decode("0000000001206fe28c0ab6f1b372c1a6a246ae63f74f931e8365e15a089c68d61900000000000307017f00000103e8").unwrap();
assert_eq!(encoded_value, target_value);
assert_eq!(msgs::Init::read(&mut Cursor::new(&target_value)).unwrap(), init_msg);
}
#[test]
fn encoding_nonfinal_onion_hop_data() {
- let mut msg = msgs::OnionHopData {
- format: OnionHopDataFormat::NonFinalNode {
- short_channel_id: 0xdeadbeef1bad1dea,
- },
+ let outbound_msg = msgs::OutboundOnionPayload::Forward {
+ short_channel_id: 0xdeadbeef1bad1dea,
amt_to_forward: 0x0badf00d01020304,
outgoing_cltv_value: 0xffffffff,
};
- let encoded_value = msg.encode();
+ let encoded_value = outbound_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 {
+
+ let inbound_msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+ if let msgs::InboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } = inbound_msg {
assert_eq!(short_channel_id, 0xdeadbeef1bad1dea);
+ assert_eq!(amt_to_forward, 0x0badf00d01020304);
+ assert_eq!(outgoing_cltv_value, 0xffffffff);
} 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,
- payment_metadata: None,
- keysend_preimage: None,
- },
- amt_to_forward: 0x0badf00d01020304,
+ let outbound_msg = msgs::OutboundOnionPayload::Receive {
+ payment_data: None,
+ payment_metadata: None,
+ keysend_preimage: None,
+ amt_msat: 0x0badf00d01020304,
outgoing_cltv_value: 0xffffffff,
+ custom_tlvs: vec![],
};
- let encoded_value = msg.encode();
+ let encoded_value = outbound_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);
+
+ let inbound_msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+ if let msgs::InboundOnionPayload::Receive { payment_data: None, amt_msat, outgoing_cltv_value, .. } = inbound_msg {
+ assert_eq!(amt_msat, 0x0badf00d01020304);
+ assert_eq!(outgoing_cltv_value, 0xffffffff);
+ } else { panic!(); }
}
#[test]
fn encoding_final_onion_hop_data_with_secret() {
let expected_payment_secret = PaymentSecret([0x42u8; 32]);
- let mut msg = msgs::OnionHopData {
- format: OnionHopDataFormat::FinalNode {
- payment_data: Some(FinalOnionHopData {
- payment_secret: expected_payment_secret,
- total_msat: 0x1badca1f
- }),
- payment_metadata: None,
- keysend_preimage: None,
- },
- amt_to_forward: 0x0badf00d01020304,
+ let outbound_msg = msgs::OutboundOnionPayload::Receive {
+ payment_data: Some(FinalOnionHopData {
+ payment_secret: expected_payment_secret,
+ total_msat: 0x1badca1f
+ }),
+ payment_metadata: None,
+ keysend_preimage: None,
+ amt_msat: 0x0badf00d01020304,
outgoing_cltv_value: 0xffffffff,
+ custom_tlvs: vec![],
};
- let encoded_value = msg.encode();
+ let encoded_value = outbound_msg.encode();
let target_value = hex::decode("3602080badf00d010203040404ffffffff082442424242424242424242424242424242424242424242424242424242424242421badca1f").unwrap();
assert_eq!(encoded_value, target_value);
- msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
- if let OnionHopDataFormat::FinalNode {
+
+ let inbound_msg = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+ if let msgs::InboundOnionPayload::Receive {
payment_data: Some(FinalOnionHopData {
payment_secret,
total_msat: 0x1badca1f
}),
+ amt_msat, outgoing_cltv_value,
payment_metadata: None,
keysend_preimage: None,
- } = msg.format {
+ custom_tlvs,
+ } = inbound_msg {
assert_eq!(payment_secret, expected_payment_secret);
+ assert_eq!(amt_msat, 0x0badf00d01020304);
+ assert_eq!(outgoing_cltv_value, 0xffffffff);
+ assert_eq!(custom_tlvs, vec![]);
+ } else { panic!(); }
+ }
+
+ #[test]
+ fn encoding_final_onion_hop_data_with_bad_custom_tlvs() {
+ // If custom TLVs have type number within the range reserved for protocol, treat them as if
+ // they're unknown
+ let bad_type_range_tlvs = vec![
+ ((1 << 16) - 4, vec![42]),
+ ((1 << 16) - 2, vec![42; 32]),
+ ];
+ let mut msg = msgs::OutboundOnionPayload::Receive {
+ payment_data: None,
+ payment_metadata: None,
+ keysend_preimage: None,
+ custom_tlvs: bad_type_range_tlvs,
+ amt_msat: 0x0badf00d01020304,
+ outgoing_cltv_value: 0xffffffff,
+ };
+ let encoded_value = msg.encode();
+ assert!(msgs::InboundOnionPayload::read(&mut Cursor::new(&encoded_value[..])).is_err());
+ let good_type_range_tlvs = vec![
+ ((1 << 16) - 3, vec![42]),
+ ((1 << 16) - 1, vec![42; 32]),
+ ];
+ if let msgs::OutboundOnionPayload::Receive { ref mut custom_tlvs, .. } = msg {
+ *custom_tlvs = good_type_range_tlvs.clone();
+ }
+ let encoded_value = msg.encode();
+ let inbound_msg = Readable::read(&mut Cursor::new(&encoded_value[..])).unwrap();
+ match inbound_msg {
+ msgs::InboundOnionPayload::Receive { custom_tlvs, .. } => assert!(custom_tlvs.is_empty()),
+ _ => panic!(),
+ }
+ }
+
+ #[test]
+ fn encoding_final_onion_hop_data_with_custom_tlvs() {
+ let expected_custom_tlvs = vec![
+ (5482373483, vec![0x12, 0x34]),
+ (5482373487, vec![0x42u8; 8]),
+ ];
+ let msg = msgs::OutboundOnionPayload::Receive {
+ payment_data: None,
+ payment_metadata: None,
+ keysend_preimage: None,
+ custom_tlvs: expected_custom_tlvs.clone(),
+ amt_msat: 0x0badf00d01020304,
+ outgoing_cltv_value: 0xffffffff,
+ };
+ let encoded_value = msg.encode();
+ let target_value = hex::decode("2e02080badf00d010203040404ffffffffff0000000146c6616b021234ff0000000146c6616f084242424242424242").unwrap();
+ assert_eq!(encoded_value, target_value);
+ let inbound_msg: msgs::InboundOnionPayload = Readable::read(&mut Cursor::new(&target_value[..])).unwrap();
+ if let msgs::InboundOnionPayload::Receive {
+ payment_data: None,
+ payment_metadata: None,
+ keysend_preimage: None,
+ custom_tlvs,
+ amt_msat,
+ outgoing_cltv_value,
+ ..
+ } = inbound_msg {
+ assert_eq!(custom_tlvs, expected_custom_tlvs);
+ assert_eq!(amt_msat, 0x0badf00d01020304);
+ assert_eq!(outgoing_cltv_value, 0xffffffff);
} else { panic!(); }
- assert_eq!(msg.amt_to_forward, 0x0badf00d01020304);
- assert_eq!(msg.outgoing_cltv_value, 0xffffffff);
}
#[test]
// 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();
+ <msgs::InboundOnionPayload 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,
- },
+ let payload = msgs::OutboundOnionPayload::Forward {
+ 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 {
+ if let msgs::OutboundOnionPayload::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value } = payload {
_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),
+ (1, test_bytes, required_vec),
+ (2, HighZeroBytesDroppedBigSize(amt_to_forward), required),
+ (4, HighZeroBytesDroppedBigSize(outgoing_cltv_value), required),
(6, short_channel_id, required)
});
}