From: Matt Corallo Date: Wed, 22 Dec 2021 03:23:07 +0000 (+0000) Subject: Deserialize payment metadata fields in the onion final hop data X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=607cd2e81b6ed6e561673bebb6804068eabb926b;p=rust-lightning Deserialize payment metadata fields in the onion final hop data --- diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index fbb5c76ff..3817fcdb7 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -3181,6 +3181,7 @@ impl ChannelMana PendingHTLCRouting::Receive { payment_data, incoming_cltv_expiry } => { let _legacy_hop_data = msgs::FinalOnionHopData { payment_secret: payment_data.payment_secret, + payment_metadata: None, // Object is only for serialization backwards compat total_msat: payment_data.total_msat }; (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data }, Some(payment_data)) @@ -7137,6 +7138,7 @@ mod tests { let (_, payment_hash, payment_secret) = get_payment_preimage_hash!(&nodes[0]); let payment_data = msgs::FinalOnionHopData { payment_secret, + payment_metadata: None, total_msat: 100_000, }; diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 9007f3f2e..190532202 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -40,7 +40,7 @@ use io_extras::read_to_end; use util::events::MessageSendEventsProvider; use util::logger; -use util::ser::{Readable, Writeable, Writer, FixedLengthReader, HighZeroBytesDroppedVarInt}; +use util::ser::{Readable, Writeable, Writer, VecWriteWrapper, VecReadWrapper, FixedLengthReader, HighZeroBytesDroppedVarInt}; use ln::{PaymentPreimage, PaymentHash, PaymentSecret}; @@ -904,6 +904,7 @@ mod fuzzy_internal_msgs { #[derive(Clone)] pub(crate) struct FinalOnionHopData { pub(crate) payment_secret: PaymentSecret, + pub(crate) payment_metadata: Option>, /// 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, @@ -1274,6 +1275,11 @@ impl_writeable_msg!(UpdateAddHTLC, { onion_routing_packet }, {}); +// The serialization here is really funky - FinalOnionHopData somewhat serves as two different +// things. First, it is *the* object which is written with type 8 in the onion TLV. Second, it is +// the data which a node may expect to receive when we are the recipient of an invoice payment. +// Thus, its serialization doesn't match its in-memory layout - with the payment_metadata included +// in the struct, but serialized separately. impl Writeable for FinalOnionHopData { fn write(&self, w: &mut W) -> Result<(), io::Error> { self.payment_secret.0.write(w)?; @@ -1285,7 +1291,7 @@ impl Readable for FinalOnionHopData { fn read(r: &mut R) -> Result { let secret: [u8; 32] = Readable::read(r)?; let amt: HighZeroBytesDroppedVarInt = Readable::read(r)?; - Ok(Self { payment_secret: PaymentSecret(secret), total_msat: amt.0 }) + Ok(Self { payment_secret: PaymentSecret(secret), total_msat: amt.0, payment_metadata: None, }) } } @@ -1314,10 +1320,15 @@ impl Writeable for OnionHopData { if let Some(final_data) = payment_data { if final_data.total_msat > MAX_VALUE_MSAT { panic!("We should never be sending infinite/overflow onion payments"); } } + let payment_metadata = if let Some(data) = payment_data { + if let Some(ref metadata) = data.payment_metadata { Some(VecWriteWrapper(metadata)) + } else { None } + } else { None }; encode_varint_length_prefixed_tlv!(w, { (2, HighZeroBytesDroppedVarInt(self.amt_to_forward), required), (4, HighZeroBytesDroppedVarInt(self.outgoing_cltv_value), required), (8, payment_data, option), + (16, payment_metadata, option), (5482373484, keysend_preimage, option) }); }, @@ -1341,6 +1352,7 @@ impl Readable for OnionHopData { let mut cltv_value = HighZeroBytesDroppedVarInt(0u32); let mut short_id: Option = None; let mut payment_data: Option = None; + let mut payment_metadata: 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, { @@ -1348,19 +1360,22 @@ impl Readable for OnionHopData { (4, cltv_value, required), (6, short_id, option), (8, payment_data, option), + (16, payment_metadata, 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); } + if payment_metadata.is_some() { return Err(DecodeError::InvalidValue); } OnionHopDataFormat::NonFinalNode { short_channel_id, } } else { - if let &Some(ref data) = &payment_data { + if let Some(ref mut data) = &mut payment_data { if data.total_msat > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue); } + data.payment_metadata = payment_metadata.map(|v| v.0); } OnionHopDataFormat::FinalNode { payment_data, @@ -2551,6 +2566,7 @@ mod tests { format: OnionHopDataFormat::FinalNode { payment_data: Some(FinalOnionHopData { payment_secret: expected_payment_secret, + payment_metadata: None, total_msat: 0x1badca1f }), keysend_preimage: None, @@ -2565,6 +2581,7 @@ mod tests { if let OnionHopDataFormat::FinalNode { payment_data: Some(FinalOnionHopData { payment_secret, + payment_metadata: None, total_msat: 0x1badca1f }), keysend_preimage: None, diff --git a/lightning/src/ln/onion_utils.rs b/lightning/src/ln/onion_utils.rs index ec668045e..32085989d 100644 --- a/lightning/src/ln/onion_utils.rs +++ b/lightning/src/ln/onion_utils.rs @@ -139,6 +139,7 @@ pub(super) fn build_onion_payloads(path: &Vec, total_msat: u64, paymen payment_data: if let &Some(ref payment_secret) = payment_secret_option { Some(msgs::FinalOnionHopData { payment_secret: payment_secret.clone(), + payment_metadata: None, total_msat, }) } else { None },