Skip to content

Commit f5c0433

Browse files
authored
Merge pull request #3440 from valentinewallace/2024-12-async-payment-receive
Support receiving async payments
2 parents 7869953 + 1f53a31 commit f5c0433

11 files changed

+857
-121
lines changed

lightning/src/blinded_path/message.rs

+5
Original file line numberDiff line numberDiff line change
@@ -434,6 +434,10 @@ pub enum AsyncPaymentsContext {
434434
///
435435
/// [`HeldHtlcAvailable`]: crate::onion_message::async_payments::HeldHtlcAvailable
436436
hmac: Hmac<Sha256>,
437+
/// The time as duration since the Unix epoch at which this path expires and messages sent over
438+
/// it should be ignored. Without this, anyone with the path corresponding to this context is
439+
/// able to trivially ask if we're online forever.
440+
path_absolute_expiry: core::time::Duration,
437441
},
438442
}
439443

@@ -469,6 +473,7 @@ impl_writeable_tlv_based_enum!(AsyncPaymentsContext,
469473
(1, InboundPayment) => {
470474
(0, nonce, required),
471475
(2, hmac, required),
476+
(4, path_absolute_expiry, required),
472477
},
473478
);
474479

lightning/src/blinded_path/payment.rs

+25-11
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
1212
use bitcoin::hashes::hmac::Hmac;
1313
use bitcoin::hashes::sha256::Hash as Sha256;
14+
use bitcoin::secp256k1::ecdh::SharedSecret;
1415
use bitcoin::secp256k1::{self, PublicKey, Secp256k1, SecretKey};
1516

1617
use crate::blinded_path::utils;
@@ -193,17 +194,11 @@ impl BlindedPaymentPath {
193194
NL::Target: NodeIdLookUp,
194195
T: secp256k1::Signing + secp256k1::Verification,
195196
{
196-
let control_tlvs_ss =
197-
node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?;
198-
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
199-
let encrypted_control_tlvs =
200-
&self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
201-
let mut s = Cursor::new(encrypted_control_tlvs);
202-
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
203-
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
204-
Ok(ChaChaPolyReadAdapter {
205-
readable: BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }),
206-
}) => {
197+
match self.decrypt_intro_payload::<NS>(node_signer) {
198+
Ok((
199+
BlindedPaymentTlvs::Forward(ForwardTlvs { short_channel_id, .. }),
200+
control_tlvs_ss,
201+
)) => {
207202
let next_node_id = match node_id_lookup.next_node_id(short_channel_id) {
208203
Some(node_id) => node_id,
209204
None => return Err(()),
@@ -223,6 +218,25 @@ impl BlindedPaymentPath {
223218
}
224219
}
225220

221+
pub(crate) fn decrypt_intro_payload<NS: Deref>(
222+
&self, node_signer: &NS,
223+
) -> Result<(BlindedPaymentTlvs, SharedSecret), ()>
224+
where
225+
NS::Target: NodeSigner,
226+
{
227+
let control_tlvs_ss =
228+
node_signer.ecdh(Recipient::Node, &self.inner_path.blinding_point, None)?;
229+
let rho = onion_utils::gen_rho_from_shared_secret(&control_tlvs_ss.secret_bytes());
230+
let encrypted_control_tlvs =
231+
&self.inner_path.blinded_hops.get(0).ok_or(())?.encrypted_payload;
232+
let mut s = Cursor::new(encrypted_control_tlvs);
233+
let mut reader = FixedLengthReader::new(&mut s, encrypted_control_tlvs.len() as u64);
234+
match ChaChaPolyReadAdapter::read(&mut reader, rho) {
235+
Ok(ChaChaPolyReadAdapter { readable, .. }) => Ok((readable, control_tlvs_ss)),
236+
_ => Err(()),
237+
}
238+
}
239+
226240
pub(crate) fn inner_blinded_path(&self) -> &BlindedPath {
227241
&self.inner_path
228242
}

lightning/src/events/mod.rs

+9-7
Original file line numberDiff line numberDiff line change
@@ -178,9 +178,10 @@ impl PaymentPurpose {
178178
}
179179
}
180180

181+
/// Errors when provided an `AsyncBolt12OfferContext`, see below.
181182
pub(crate) fn from_parts(
182183
payment_preimage: Option<PaymentPreimage>, payment_secret: PaymentSecret,
183-
payment_context: Option<PaymentContext>,
184+
payment_context: Option<PaymentContext>
184185
) -> Result<Self, ()> {
185186
match payment_context {
186187
None => {
@@ -203,11 +204,12 @@ impl PaymentPurpose {
203204
payment_context: context,
204205
})
205206
},
206-
Some(PaymentContext::AsyncBolt12Offer(_context)) => {
207-
// This code will change to return Self::Bolt12OfferPayment when we add support for async
208-
// receive.
207+
Some(PaymentContext::AsyncBolt12Offer(_)) => {
208+
// Callers are expected to convert from `AsyncBolt12OfferContext` to `Bolt12OfferContext`
209+
// using the invoice request provided in the payment onion prior to calling this method.
210+
debug_assert!(false);
209211
Err(())
210-
},
212+
}
211213
}
212214
}
213215
}
@@ -1190,12 +1192,12 @@ pub enum Event {
11901192
/// events generated or serialized by versions prior to 0.0.122.
11911193
next_user_channel_id: Option<u128>,
11921194
/// The node id of the previous node.
1193-
///
1195+
///
11941196
/// This is only `None` for HTLCs received prior to 0.1 or for events serialized by
11951197
/// versions prior to 0.1
11961198
prev_node_id: Option<PublicKey>,
11971199
/// The node id of the next node.
1198-
///
1200+
///
11991201
/// This is only `None` for HTLCs received prior to 0.1 or for events serialized by
12001202
/// versions prior to 0.1
12011203
next_node_id: Option<PublicKey>,

0 commit comments

Comments
 (0)