From: Jeffrey Czyz Date: Tue, 26 Mar 2024 18:10:04 +0000 (-0500) Subject: Pass PaymentContext through HTLC processing X-Git-Tag: v0.0.123-beta~7^2~11 X-Git-Url: http://git.bitcoin.ninja/index.cgi?p=rust-lightning;a=commitdiff_plain;h=9be364f60ea1ed348a94ea93e9e4d90394a4c1cb Pass PaymentContext through HTLC processing PendingInboundPayment::BlindedReceive includes a PaymentContext, which the recipient includes in each blinded path. Included this when processing HTLCs in ChannelManager, first into PendingHTLCRouting and then to OnionPayload. Later, this will be included in the PaymentPurpose when surfaced to user in PaymentClaimable and PaymentClaimed events. --- diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index b722a441..39f7c7f1 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -104,14 +104,14 @@ pub struct PaymentConstraints { /// /// [`BlindedPath`]: crate::blinded_path::BlindedPath /// [`PaymentPurpose`]: crate::events::PaymentPurpose -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub enum PaymentContext { /// The payment context was unknown. Unknown(UnknownPaymentContext), } /// An unknown payment context. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct UnknownPaymentContext(()); impl PaymentContext { diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index 6a33b2d5..ef10717a 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -155,6 +155,11 @@ pub enum PendingHTLCRouting { /// [`Event::PaymentClaimable::onion_fields`] as /// [`RecipientOnionFields::payment_metadata`]. payment_metadata: Option>, + /// The context of the payment included by the recipient in a blinded path, or `None` if a + /// blinded path was not used. + /// + /// Used in part to determine the [`events::PaymentPurpose`]. + payment_context: Option, /// CLTV expiry of the received HTLC. /// /// Used to track when we should expire pending HTLCs that go unclaimed. @@ -352,6 +357,11 @@ enum OnionPayload { /// This is only here for backwards-compatibility in serialization, in the future it can be /// removed, breaking clients running 0.0.106 and earlier. _legacy_hop_data: Option, + /// The context of the payment included by the recipient in a blinded path, or `None` if a + /// blinded path was not used. + /// + /// Used in part to determine the [`events::PaymentPurpose`]. + payment_context: Option, }, /// Contains the payer-provided preimage. Spontaneous(PaymentPreimage), @@ -5336,13 +5346,14 @@ where let blinded_failure = routing.blinded_failure(); let (cltv_expiry, onion_payload, payment_data, phantom_shared_secret, mut onion_fields) = match routing { PendingHTLCRouting::Receive { - payment_data, payment_metadata, incoming_cltv_expiry, phantom_shared_secret, - custom_tlvs, requires_blinded_error: _ + payment_data, payment_metadata, payment_context, + incoming_cltv_expiry, phantom_shared_secret, custom_tlvs, + requires_blinded_error: _ } => { let _legacy_hop_data = Some(payment_data.clone()); let onion_fields = RecipientOnionFields { payment_secret: Some(payment_data.payment_secret), payment_metadata, custom_tlvs }; - (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data }, + (incoming_cltv_expiry, OnionPayload::Invoice { _legacy_hop_data, payment_context }, Some(payment_data), phantom_shared_secret, onion_fields) }, PendingHTLCRouting::ReceiveKeysend { @@ -10677,6 +10688,7 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (3, payment_metadata, option), (5, custom_tlvs, optional_vec), (7, requires_blinded_error, (default_value, false)), + (9, payment_context, option), }, (2, ReceiveKeysend) => { (0, payment_preimage, required), @@ -10791,9 +10803,11 @@ impl_writeable_tlv_based!(HTLCPreviousHopData, { impl Writeable for ClaimableHTLC { fn write(&self, writer: &mut W) -> Result<(), io::Error> { - let (payment_data, keysend_preimage) = match &self.onion_payload { - OnionPayload::Invoice { _legacy_hop_data } => (_legacy_hop_data.as_ref(), None), - OnionPayload::Spontaneous(preimage) => (None, Some(preimage)), + let (payment_data, keysend_preimage, payment_context) = match &self.onion_payload { + OnionPayload::Invoice { _legacy_hop_data, payment_context } => { + (_legacy_hop_data.as_ref(), None, payment_context.as_ref()) + }, + OnionPayload::Spontaneous(preimage) => (None, Some(preimage), None), }; write_tlv_fields!(writer, { (0, self.prev_hop, required), @@ -10805,6 +10819,7 @@ impl Writeable for ClaimableHTLC { (6, self.cltv_expiry, required), (8, keysend_preimage, option), (10, self.counterparty_skimmed_fee_msat, option), + (11, payment_context, option), }); Ok(()) } @@ -10822,6 +10837,7 @@ impl Readable for ClaimableHTLC { (6, cltv_expiry, required), (8, keysend_preimage, option), (10, counterparty_skimmed_fee_msat, option), + (11, payment_context, option), }); let payment_data: Option = payment_data_opt; let value = value_ser.0.unwrap(); @@ -10842,7 +10858,7 @@ impl Readable for ClaimableHTLC { } total_msat = Some(payment_data.as_ref().unwrap().total_msat); } - OnionPayload::Invoice { _legacy_hop_data: payment_data } + OnionPayload::Invoice { _legacy_hop_data: payment_data, payment_context } }, }; Ok(Self { @@ -12079,7 +12095,7 @@ where return Err(DecodeError::InvalidValue); } let purpose = match &htlcs[0].onion_payload { - OnionPayload::Invoice { _legacy_hop_data } => { + OnionPayload::Invoice { _legacy_hop_data, payment_context: _ } => { if let Some(hop_data) = _legacy_hop_data { events::PaymentPurpose::InvoicePayment { payment_preimage: match pending_inbound_payments.get(&payment_hash) { diff --git a/lightning/src/ln/msgs.rs b/lightning/src/ln/msgs.rs index 4d1f6985..d688a38b 100644 --- a/lightning/src/ln/msgs.rs +++ b/lightning/src/ln/msgs.rs @@ -1672,7 +1672,7 @@ pub struct FinalOnionHopData { mod fuzzy_internal_msgs { use bitcoin::secp256k1::PublicKey; - use crate::blinded_path::payment::{PaymentConstraints, PaymentRelay}; + use crate::blinded_path::payment::{PaymentConstraints, PaymentContext, PaymentRelay}; use crate::ln::{PaymentPreimage, PaymentSecret}; use crate::ln::features::BlindedHopFeatures; use super::{FinalOnionHopData, TrampolineOnionPacket}; @@ -1711,6 +1711,7 @@ mod fuzzy_internal_msgs { cltv_expiry_height: u32, payment_secret: PaymentSecret, payment_constraints: PaymentConstraints, + payment_context: PaymentContext, intro_node_blinding_point: Option, keysend_preimage: Option, custom_tlvs: Vec<(u64, Vec)>, @@ -2713,7 +2714,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w }) }, ChaChaPolyReadAdapter { readable: BlindedPaymentTlvs::Receive(ReceiveTlvs { - payment_secret, payment_constraints, payment_context: _ + payment_secret, payment_constraints, payment_context })} => { if total_msat.unwrap_or(0) > MAX_VALUE_MSAT { return Err(DecodeError::InvalidValue) } Ok(Self::BlindedReceive { @@ -2722,6 +2723,7 @@ impl ReadableArgs<(Option, &NS)> for InboundOnionPayload w cltv_expiry_height: cltv_value.ok_or(DecodeError::InvalidValue)?, payment_secret, payment_constraints, + payment_context, intro_node_blinding_point, keysend_preimage, custom_tlvs, diff --git a/lightning/src/ln/onion_payment.rs b/lightning/src/ln/onion_payment.rs index aa8ee0ce..db8c4cd0 100644 --- a/lightning/src/ln/onion_payment.rs +++ b/lightning/src/ln/onion_payment.rs @@ -131,17 +131,18 @@ pub(super) fn create_recv_pending_htlc_info( ) -> Result { let ( payment_data, keysend_preimage, custom_tlvs, onion_amt_msat, onion_cltv_expiry, - payment_metadata, requires_blinded_error + payment_metadata, payment_context, requires_blinded_error ) = match hop_data { msgs::InboundOnionPayload::Receive { payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat, cltv_expiry_height, payment_metadata, .. } => (payment_data, keysend_preimage, custom_tlvs, sender_intended_htlc_amt_msat, - cltv_expiry_height, payment_metadata, false), + cltv_expiry_height, payment_metadata, None, false), msgs::InboundOnionPayload::BlindedReceive { sender_intended_htlc_amt_msat, total_msat, cltv_expiry_height, payment_secret, - intro_node_blinding_point, payment_constraints, keysend_preimage, custom_tlvs + intro_node_blinding_point, payment_constraints, payment_context, keysend_preimage, + custom_tlvs } => { check_blinded_payment_constraints( sender_intended_htlc_amt_msat, cltv_expiry, &payment_constraints @@ -155,7 +156,7 @@ pub(super) fn create_recv_pending_htlc_info( })?; let payment_data = msgs::FinalOnionHopData { payment_secret, total_msat }; (Some(payment_data), keysend_preimage, custom_tlvs, - sender_intended_htlc_amt_msat, cltv_expiry_height, None, + sender_intended_htlc_amt_msat, cltv_expiry_height, None, Some(payment_context), intro_node_blinding_point.is_none()) } msgs::InboundOnionPayload::Forward { .. } => { @@ -241,6 +242,7 @@ pub(super) fn create_recv_pending_htlc_info( PendingHTLCRouting::Receive { payment_data: data, payment_metadata, + payment_context, incoming_cltv_expiry: onion_cltv_expiry, phantom_shared_secret, custom_tlvs,