X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fblinded_path%2Fpayment.rs;h=dfe89e0ebc6c34e6579fa1cea0ca79f4dc0b7672;hb=b8d4ac1371bf0db3b28339d4e12fadf02f6add3d;hp=6467af568886bd1891a7e8c52ae6b5956736f6bd;hpb=e4b6a5004edb566fda341e1710950ff2b3fe241e;p=rust-lightning diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 6467af56..dfe89e0e 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -7,15 +7,17 @@ use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; use crate::blinded_path::BlindedHop; use crate::blinded_path::utils; use crate::io; -use crate::ln::PaymentSecret; +use crate::ln::types::PaymentSecret; use crate::ln::channelmanager::CounterpartyForwardingInfo; use crate::ln::features::BlindedHopFeatures; use crate::ln::msgs::DecodeError; use crate::offers::invoice::BlindedPayInfo; -use crate::prelude::*; +use crate::offers::invoice_request::InvoiceRequestFields; +use crate::offers::offer::OfferId; use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, Writeable, Writer}; -use core::convert::TryFrom; +#[allow(unused_imports)] +use crate::prelude::*; /// An intermediate node, its outbound channel, and relay parameters. #[derive(Clone, Debug)] @@ -53,6 +55,8 @@ pub struct ReceiveTlvs { pub payment_secret: PaymentSecret, /// Constraints for the receiver of this payment. pub payment_constraints: PaymentConstraints, + /// Context for the receiver of this payment. + pub payment_context: PaymentContext, } /// Data to construct a [`BlindedHop`] for sending a payment over. @@ -97,6 +101,66 @@ pub struct PaymentConstraints { pub htlc_minimum_msat: u64, } +/// The context of an inbound payment, which is included in a [`BlindedPath`] via [`ReceiveTlvs`] +/// and surfaced in [`PaymentPurpose`]. +/// +/// [`BlindedPath`]: crate::blinded_path::BlindedPath +/// [`PaymentPurpose`]: crate::events::PaymentPurpose +#[derive(Clone, Debug, Eq, PartialEq)] +pub enum PaymentContext { + /// The payment context was unknown. + Unknown(UnknownPaymentContext), + + /// The payment was made for an invoice requested from a BOLT 12 [`Offer`]. + /// + /// [`Offer`]: crate::offers::offer::Offer + Bolt12Offer(Bolt12OfferContext), + + /// The payment was made for an invoice sent for a BOLT 12 [`Refund`]. + /// + /// [`Refund`]: crate::offers::refund::Refund + Bolt12Refund(Bolt12RefundContext), +} + +// Used when writing PaymentContext in Event::PaymentClaimable to avoid cloning. +pub(crate) enum PaymentContextRef<'a> { + Bolt12Offer(&'a Bolt12OfferContext), + Bolt12Refund(&'a Bolt12RefundContext), +} + +/// An unknown payment context. +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct UnknownPaymentContext(()); + +/// The context of a payment made for an invoice requested from a BOLT 12 [`Offer`]. +/// +/// [`Offer`]: crate::offers::offer::Offer +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Bolt12OfferContext { + /// The identifier of the [`Offer`]. + /// + /// [`Offer`]: crate::offers::offer::Offer + pub offer_id: OfferId, + + /// Fields from an [`InvoiceRequest`] sent for a [`Bolt12Invoice`]. + /// + /// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest + /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice + pub invoice_request: InvoiceRequestFields, +} + +/// The context of a payment made for an invoice sent for a BOLT 12 [`Refund`]. +/// +/// [`Refund`]: crate::offers::refund::Refund +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Bolt12RefundContext {} + +impl PaymentContext { + pub(crate) fn unknown() -> Self { + PaymentContext::Unknown(UnknownPaymentContext(())) + } +} + impl TryFrom for PaymentRelay { type Error = (); @@ -137,7 +201,8 @@ impl Writeable for ReceiveTlvs { fn write(&self, w: &mut W) -> Result<(), io::Error> { encode_tlv_stream!(w, { (12, self.payment_constraints, required), - (65536, self.payment_secret, required) + (65536, self.payment_secret, required), + (65537, self.payment_context, required) }); Ok(()) } @@ -163,11 +228,14 @@ impl Readable for BlindedPaymentTlvs { (12, payment_constraints, required), (14, features, option), (65536, payment_secret, option), + (65537, payment_context, (default_value, PaymentContext::unknown())), }); let _padding: Option = _padding; if let Some(short_channel_id) = scid { - if payment_secret.is_some() { return Err(DecodeError::InvalidValue) } + if payment_secret.is_some() { + return Err(DecodeError::InvalidValue) + } Ok(BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, payment_relay: payment_relay.ok_or(DecodeError::InvalidValue)?, @@ -179,6 +247,7 @@ impl Readable for BlindedPaymentTlvs { Ok(BlindedPaymentTlvs::Receive(ReceiveTlvs { payment_secret: payment_secret.ok_or(DecodeError::InvalidValue)?, payment_constraints: payment_constraints.0.unwrap(), + payment_context: payment_context.0.unwrap(), })) } } @@ -309,11 +378,54 @@ impl Readable for PaymentConstraints { } } +impl_writeable_tlv_based_enum!(PaymentContext, + ; + (0, Unknown), + (1, Bolt12Offer), + (2, Bolt12Refund), +); + +impl<'a> Writeable for PaymentContextRef<'a> { + fn write(&self, w: &mut W) -> Result<(), io::Error> { + match self { + PaymentContextRef::Bolt12Offer(context) => { + 1u8.write(w)?; + context.write(w)?; + }, + PaymentContextRef::Bolt12Refund(context) => { + 2u8.write(w)?; + context.write(w)?; + }, + } + + Ok(()) + } +} + +impl Writeable for UnknownPaymentContext { + fn write(&self, _w: &mut W) -> Result<(), io::Error> { + Ok(()) + } +} + +impl Readable for UnknownPaymentContext { + fn read(_r: &mut R) -> Result { + Ok(UnknownPaymentContext(())) + } +} + +impl_writeable_tlv_based!(Bolt12OfferContext, { + (0, offer_id, required), + (2, invoice_request, required), +}); + +impl_writeable_tlv_based!(Bolt12RefundContext, {}); + #[cfg(test)] mod tests { use bitcoin::secp256k1::PublicKey; - use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, ReceiveTlvs, PaymentConstraints, PaymentRelay}; - use crate::ln::PaymentSecret; + use crate::blinded_path::payment::{ForwardNode, ForwardTlvs, ReceiveTlvs, PaymentConstraints, PaymentContext, PaymentRelay}; + use crate::ln::types::PaymentSecret; use crate::ln::features::BlindedHopFeatures; use crate::ln::functional_test_utils::TEST_FINAL_CLTV; @@ -361,6 +473,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + payment_context: PaymentContext::unknown(), }; let htlc_maximum_msat = 100_000; let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, 12).unwrap(); @@ -379,6 +492,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + payment_context: PaymentContext::unknown(), }; let blinded_payinfo = super::compute_payinfo(&[], &recv_tlvs, 4242, TEST_FINAL_CLTV as u16).unwrap(); assert_eq!(blinded_payinfo.fee_base_msat, 0); @@ -432,6 +546,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 3, }, + payment_context: PaymentContext::unknown(), }; let htlc_maximum_msat = 100_000; let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_maximum_msat, TEST_FINAL_CLTV as u16).unwrap(); @@ -482,6 +597,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + payment_context: PaymentContext::unknown(), }; let htlc_minimum_msat = 3798; assert!(super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, htlc_minimum_msat - 1, TEST_FINAL_CLTV as u16).is_err()); @@ -536,6 +652,7 @@ mod tests { max_cltv_expiry: 0, htlc_minimum_msat: 1, }, + payment_context: PaymentContext::unknown(), }; let blinded_payinfo = super::compute_payinfo(&intermediate_nodes[..], &recv_tlvs, 10_000, TEST_FINAL_CLTV as u16).unwrap();