X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fln%2Fmsgs.rs;h=515dcbba2d2e136846697dc990d582270e07e1d4;hb=83f0dbc0021335dce183450d7dce7e9f284ff0b6;hp=76ed56635ac6a57bd22cb82f5bba93e4c210b5c6;hpb=bada71394e96971bcf29fe997ecc9602ec305da4;p=rust-lightning diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 76ed5663..515dcbba 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -24,6 +24,7 @@ //! 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}; @@ -42,7 +43,7 @@ use crate::io_extras::read_to_end; 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}; @@ -88,6 +89,10 @@ pub enum DecodeError { 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>, /// The receipient's network address. /// /// This adds the option to report a remote IP address back to a connecting peer using the init @@ -605,6 +610,11 @@ pub struct UpdateAddHTLC { 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, pub(crate) onion_routing_packet: OnionPacket, } @@ -963,7 +973,11 @@ pub struct UnsignedChannelAnnouncement { pub bitcoin_key_1: NodeId, /// The funding key for the second node pub bitcoin_key_2: NodeId, - pub(crate) excess_data: Vec, + /// 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, } /// A [`channel_announcement`] message to be sent to or received from a peer. /// @@ -1137,6 +1151,11 @@ pub enum ErrorAction { /// An error message which we should make an effort to send before we disconnect. msg: Option }, + /// 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, @@ -1290,6 +1309,12 @@ pub trait ChannelMessageHandler : MessageSendEventsProvider { /// /// 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>; } /// A trait to describe an object which can receive routing messages. @@ -1398,30 +1423,45 @@ 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: 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, payment_metadata: Option>, keysend_preimage: Option, + custom_tlvs: Vec<(u64, Vec)>, + 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, + payment_metadata: Option>, + keysend_preimage: Option, + custom_tlvs: Vec<(u64, Vec)>, + amt_msat: u64, + outgoing_cltv_value: u32, + }, } pub struct DecodedOnionErrorPacket { @@ -1723,7 +1763,8 @@ impl Writeable for Init { 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(()) } @@ -1734,11 +1775,14 @@ impl Readable for Init { let global_features: InitFeatures = Readable::read(r)?; let features: InitFeatures = Readable::read(r)?; let mut remote_network_address: Option = None; + let mut networks: Option>> = 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, }) } @@ -1883,8 +1927,10 @@ impl_writeable_msg!(UpdateAddHTLC, { amount_msat, payment_hash, cltv_expiry, - onion_routing_packet -}, {}); + onion_routing_packet, +}, { + (65537, skimmed_fee_msat, option) +}); impl Readable for OnionMessage { fn read(r: &mut R) -> Result { @@ -1924,31 +1970,39 @@ impl Readable for FinalOnionHopData { } } -impl Writeable for OnionHopData { +impl Writeable for OutboundOnionPayload { fn write(&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)> = 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: &mut R) -> Result { let mut amt = HighZeroBytesDroppedBigSize(0u64); let mut cltv_value = HighZeroBytesDroppedBigSize(0u32); @@ -1956,7 +2010,11 @@ impl Readable for OnionHopData { let mut payment_data: Option = None; let mut payment_metadata: Option>> = None; let mut keysend_preimage: Option = 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), @@ -1964,41 +2022,44 @@ impl Readable for OnionHopData { (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 { + 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: &mut R, _arg: ()) -> Result { ::read(r) } @@ -2411,11 +2472,12 @@ impl_writeable_msg!(GossipTimestampFilter, { #[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}; @@ -3309,7 +3371,8 @@ mod tests { 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(); @@ -3418,27 +3481,36 @@ mod tests { #[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); } @@ -3488,75 +3560,144 @@ mod tests { #[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] @@ -3706,25 +3847,23 @@ mod tests { // 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(); + ::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 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) }); }