X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=blobdiff_plain;f=lightning%2Fsrc%2Fblinded_path%2Fpayment.rs;h=7df7d1c63edd1ed8222b2b9e470b235671d14d82;hb=07d991c82fadf10f59ae01b2b5aef6bc8797fd9a;hp=39f7c7f11088c51bdb5a55393084274d96631820;hpb=9be364f60ea1ed348a94ea93e9e4d90394a4c1cb;p=rust-lightning diff --git a/lightning/src/blinded_path/payment.rs b/lightning/src/blinded_path/payment.rs index 39f7c7f1..7df7d1c6 100644 --- a/lightning/src/blinded_path/payment.rs +++ b/lightning/src/blinded_path/payment.rs @@ -1,18 +1,36 @@ +// This file is Copyright its original authors, visible in version control +// history. +// +// This file is licensed under the Apache License, Version 2.0 or the MIT license +// , at your option. +// You may not use this file except in accordance with one or both of these +// licenses. + //! Data structures and methods for constructing [`BlindedPath`]s to send a payment over. //! //! [`BlindedPath`]: crate::blinded_path::BlindedPath use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey}; -use crate::blinded_path::BlindedHop; +use crate::blinded_path::{BlindedHop, BlindedPath, IntroductionNode, NodeIdLookUp}; use crate::blinded_path::utils; +use crate::crypto::streams::ChaChaPolyReadAdapter; use crate::io; -use crate::ln::PaymentSecret; -use crate::ln::channelmanager::CounterpartyForwardingInfo; +use crate::io::Cursor; +use crate::ln::types::PaymentSecret; +use crate::ln::channel_state::CounterpartyForwardingInfo; use crate::ln::features::BlindedHopFeatures; use crate::ln::msgs::DecodeError; +use crate::ln::onion_utils; use crate::offers::invoice::BlindedPayInfo; -use crate::util::ser::{HighZeroBytesDroppedBigSize, Readable, Writeable, Writer}; +use crate::offers::invoice_request::InvoiceRequestFields; +use crate::offers::offer::OfferId; +use crate::sign::{NodeSigner, Recipient}; +use crate::util::ser::{FixedLengthReader, LengthReadableArgs, HighZeroBytesDroppedBigSize, Readable, Writeable, Writer}; + +use core::mem; +use core::ops::Deref; #[allow(unused_imports)] use crate::prelude::*; @@ -108,12 +126,51 @@ pub struct PaymentConstraints { 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(())) @@ -224,6 +281,43 @@ pub(super) fn blinded_hops( utils::construct_blinded_hops(secp_ctx, pks, tlvs, session_priv) } +// Advance the blinded onion payment path by one hop, so make the second hop into the new +// introduction node. +// +// Will only modify `path` when returning `Ok`. +pub(crate) fn advance_path_by_one( + path: &mut BlindedPath, node_signer: &NS, node_id_lookup: &NL, secp_ctx: &Secp256k1 +) -> Result<(), ()> +where + NS::Target: NodeSigner, + NL::Target: NodeIdLookUp, + T: secp256k1::Signing + secp256k1::Verification, +{ + let control_tlvs_ss = node_signer.ecdh(Recipient::Node, &path.blinding_point, None)?; + let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes()); + let encrypted_control_tlvs = &path.blinded_hops.get(0).ok_or(())?.encrypted_payload; + let mut s = Cursor::new(encrypted_control_tlvs); + let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64); + match ChaChaPolyReadAdapter::read(&mut reader, rho) { + Ok(ChaChaPolyReadAdapter { + readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }) + }) => { + let next_node_id = match node_id_lookup.next_node_id(short_channel_id) { + Some(node_id) => node_id, + None => return Err(()), + }; + let mut new_blinding_point = onion_utils::next_hop_pubkey( + secp_ctx, path.blinding_point, control_tlvs_ss.as_ref() + ).map_err(|_| ())?; + mem::swap(&mut path.blinding_point, &mut new_blinding_point); + path.introduction_node = IntroductionNode::NodeId(next_node_id); + path.blinded_hops.remove(0); + Ok(()) + }, + _ => Err(()) + } +} + /// `None` if underflow occurs. pub(crate) fn amt_to_forward_msat(inbound_amt_msat: u64, payment_relay: &PaymentRelay) -> Option { let inbound_amt = inbound_amt_msat as u128; @@ -340,8 +434,27 @@ 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(()) @@ -354,11 +467,18 @@ impl Readable for 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, PaymentContext, PaymentRelay}; - use crate::ln::PaymentSecret; + use crate::ln::types::PaymentSecret; use crate::ln::features::BlindedHopFeatures; use crate::ln::functional_test_utils::TEST_FINAL_CLTV;