Deserialize payment metadata fields in the onion final hop data
authorMatt Corallo <git@bluematt.me>
Wed, 22 Dec 2021 03:23:07 +0000 (03:23 +0000)
committerMatt Corallo <git@bluematt.me>
Wed, 26 Jan 2022 19:09:13 +0000 (19:09 +0000)
lightning/src/ln/channelmanager.rs
lightning/src/ln/msgs.rs
lightning/src/ln/onion_utils.rs

index fbb5c76ff1bbc6fa1e2d1d218f0525631af2b886..3817fcdb73e2985ba704f503cd491a943285bc85 100644 (file)
@@ -3181,6 +3181,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> 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,
                };
 
index 9007f3f2ea7d59aaa820c0999e5c069be3718935..190532202a4e61b5e89ae4d2e4dab8c6010bb817 100644 (file)
@@ -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<Vec<u8>>,
                /// 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<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
                self.payment_secret.0.write(w)?;
@@ -1285,7 +1291,7 @@ 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)?;
-               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<u64> = None;
                        let mut payment_data: Option<FinalOnionHopData> = None;
+                       let mut payment_metadata: Option<VecReadWrapper<u8>> = 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, {
@@ -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,
index ec668045eb00614ba9ceef4df949d60572e962c4..32085989d678284b212528c2a8aa8239d91e5c24 100644 (file)
@@ -139,6 +139,7 @@ pub(super) fn build_onion_payloads(path: &Vec<RouteHop>, 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 },