Skip to content

Commit 5693660

Browse files
blip42: add the possibility to inject conctact secret inside the pay for offer
Signed-off-by: Vincenzo Palazzo <vincenzopalazzodev@gmail.com>
1 parent a54d2ba commit 5693660

File tree

3 files changed

+50
-18
lines changed

3 files changed

+50
-18
lines changed

lightning/src/ln/channelmanager.rs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,7 @@ use crate::ln::outbound_payment::{
9292
};
9393
use crate::ln::types::ChannelId;
9494
use crate::offers::async_receive_offer_cache::AsyncReceiveOfferCache;
95+
use crate::offers::contacts::ContactSecrets;
9596
use crate::offers::flow::{HeldHtlcReplyPath, InvreqResponseInstructions, OffersMessageFlow};
9697
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
9798
use crate::offers::invoice_error::InvoiceError;
@@ -728,6 +729,9 @@ pub struct OptionalOfferPaymentParams {
728729
/// will ultimately fail once all pending paths have failed (generating an
729730
/// [`Event::PaymentFailed`]).
730731
pub retry_strategy: Retry,
732+
/// Contact secrets to include in the invoice request for BLIP-42 contact management.
733+
/// If provided, these secrets will be used to establish a contact relationship with the recipient.
734+
pub contact_secrects: Option<ContactSecrets>,
731735
}
732736

733737
impl Default for OptionalOfferPaymentParams {
@@ -739,6 +743,7 @@ impl Default for OptionalOfferPaymentParams {
739743
retry_strategy: Retry::Timeout(core::time::Duration::from_secs(2)),
740744
#[cfg(not(feature = "std"))]
741745
retry_strategy: Retry::Attempts(3),
746+
contact_secrects: None,
742747
}
743748
}
744749
}
@@ -12944,6 +12949,7 @@ where
1294412949
payment_id,
1294512950
None,
1294612951
create_pending_payment_fn,
12952+
optional_params.contact_secrects,
1294712953
)
1294812954
}
1294912955

@@ -12973,6 +12979,7 @@ where
1297312979
payment_id,
1297412980
Some(offer.hrn),
1297512981
create_pending_payment_fn,
12982+
optional_params.contact_secrects,
1297612983
)
1297712984
}
1297812985

@@ -13015,6 +13022,7 @@ where
1301513022
payment_id,
1301613023
None,
1301713024
create_pending_payment_fn,
13025+
optional_params.contact_secrects,
1301813026
)
1301913027
}
1302013028

@@ -13023,6 +13031,7 @@ where
1302313031
&self, offer: &Offer, quantity: Option<u64>, amount_msats: Option<u64>,
1302413032
payer_note: Option<String>, payment_id: PaymentId,
1302513033
human_readable_name: Option<HumanReadableName>, create_pending_payment: CPP,
13034+
contacts: Option<ContactSecrets>,
1302613035
) -> Result<(), Bolt12SemanticError> {
1302713036
let entropy = &*self.entropy_source;
1302813037
let nonce = Nonce::from_entropy_source(entropy);
@@ -13048,6 +13057,12 @@ where
1304813057
Some(hrn) => builder.sourced_from_human_readable_name(hrn),
1304913058
};
1305013059

13060+
let contacts = match contacts {
13061+
None => ContactSecrets::new(self.entropy_source.get_secure_random_bytes()),
13062+
Some(c) => c,
13063+
};
13064+
let builder = builder.contact_secrets(contacts.clone());
13065+
1305113066
let invoice_request = builder.build_and_sign()?;
1305213067
let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);
1305313068

@@ -15649,7 +15664,7 @@ where
1564915664
self.pending_outbound_payments
1565015665
.received_offer(payment_id, Some(retryable_invoice_request))
1565115666
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)
15652-
});
15667+
}, None);
1565315668
if offer_pay_res.is_err() {
1565415669
// The offer we tried to pay is the canonical current offer for the name we
1565515670
// wanted to pay. If we can't pay it, there's no way to recover so fail the

lightning/src/ln/offers_tests.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2521,10 +2521,6 @@ fn no_double_pay_with_stale_channelmanager() {
25212521
// Pay and offer while adding the contacts information the invoice request!
25222522
#[test]
25232523
fn pay_offer_and_add_contacts_info_blip42() {
2524-
let mut features = channelmanager::provided_init_features(&accept_forward_cfg);
2525-
features.set_onion_messages_optional();
2526-
features.set_route_blinding_optional();
2527-
25282524
let chanmon_cfgs = create_chanmon_cfgs(2);
25292525
let node_cfgs = create_node_cfgs(2, &chanmon_cfgs);
25302526

@@ -2559,10 +2555,10 @@ fn pay_offer_and_add_contacts_info_blip42() {
25592555
// Probably a good place to add the information that we use for the contact secret.
25602556
// but need to double check if the sender of the invoice request still need to ask anything.
25612557
expect_recent_payment!(bob, RecentPaymentDetails::AwaitingInvoice, payment_id);
2562-
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
2558+
let onion_message = bob.onion_messenger.next_onion_message_for_peer(alice_id).unwrap();
2559+
alice.onion_messenger.handle_onion_message(bob_id, &onion_message);
25632560

2564-
let (invoice_request, reply_path) = extract_invoice_request(alice, &onion_message);
2565-
// TODO: check if the invoice request contains the contact information.
2561+
let (invoice_request, _reply_path) = extract_invoice_request(alice, &onion_message);
25662562

25672563
let payment_context = PaymentContext::Bolt12Offer(Bolt12OfferContext {
25682564
offer_id: offer.id(),
@@ -2575,21 +2571,19 @@ fn pay_offer_and_add_contacts_info_blip42() {
25752571
});
25762572
assert_eq!(invoice_request.amount_msats(), Some(10_000_000));
25772573
assert_ne!(invoice_request.payer_signing_pubkey(), bob_id);
2578-
assert!(check_compact_path_introduction_node(&reply_path, alice, bob_id));
2574+
// Now we check that there are the contact secret and the
2575+
// contact secret is the same that we inject by bob.
2576+
assert!(invoice_request.contact_secret().is_some());
2577+
// TODO: we should check also if the contact secret is the same that we inject by bob.
25792578

25802579
let onion_message = alice.onion_messenger.next_onion_message_for_peer(bob_id).unwrap();
25812580
bob.onion_messenger.handle_onion_message(alice_id, &onion_message);
25822581

2583-
let (invoice, reply_path) = extract_invoice(bob, &onion_message);
2582+
let (invoice, _reply_path) = extract_invoice(bob, &onion_message);
25842583
assert_eq!(invoice.amount_msats(), 10_000_000);
25852584
assert_ne!(invoice.signing_pubkey(), alice_id);
25862585
assert!(!invoice.payment_paths().is_empty());
25872586

2588-
for path in invoice.payment_paths() {
2589-
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
2590-
}
2591-
assert!(check_compact_path_introduction_node(&reply_path, bob, alice_id));
2592-
25932587
route_bolt12_payment(bob, &[alice], &invoice);
25942588
expect_recent_payment!(bob, RecentPaymentDetails::Pending, payment_id);
25952589

lightning/src/offers/invoice_request.rs

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,7 @@ macro_rules! invoice_request_builder_methods { (
187187
InvoiceRequestContentsWithoutPayerSigningPubkey {
188188
payer: PayerContents(metadata), offer, chain: None, amount_msats: None,
189189
features: InvoiceRequestFeatures::empty(), quantity: None, payer_note: None,
190-
offer_from_hrn: None,
190+
offer_from_hrn: None, invreq_contact_secret: None,
191191
#[cfg(test)]
192192
experimental_bar: None,
193193
}
@@ -256,6 +256,18 @@ macro_rules! invoice_request_builder_methods { (
256256
$return_value
257257
}
258258

259+
/// Sets the contact secret for BLIP-42 contact authentication.
260+
///
261+
/// This will include the primary secret from the [`ContactSecrets`] in the invoice request.
262+
///
263+
/// Successive calls to this method will override the previous setting.
264+
///
265+
/// [`ContactSecrets`]: crate::offers::contacts::ContactSecrets
266+
pub fn contact_secrets($($self_mut)* $self: $self_type, contact_secrets: crate::offers::contacts::ContactSecrets) -> $return_type {
267+
$self.invoice_request.invreq_contact_secret = Some(contact_secrets.primary_secret().to_vec());
268+
$return_value
269+
}
270+
259271
fn build_with_checks($($self_mut)* $self: $self_type) -> Result<
260272
(UnsignedInvoiceRequest, Option<Keypair>, Option<&'b Secp256k1<$secp_context>>),
261273
Bolt12SemanticError
@@ -691,6 +703,7 @@ pub(super) struct InvoiceRequestContentsWithoutPayerSigningPubkey {
691703
quantity: Option<u64>,
692704
payer_note: Option<String>,
693705
offer_from_hrn: Option<HumanReadableName>,
706+
invreq_contact_secret: Option<Vec<u8>>,
694707
#[cfg(test)]
695708
experimental_bar: Option<u64>,
696709
}
@@ -752,6 +765,11 @@ macro_rules! invoice_request_accessors { ($self: ident, $contents: expr) => {
752765
pub fn offer_from_hrn(&$self) -> &Option<HumanReadableName> {
753766
$contents.offer_from_hrn()
754767
}
768+
769+
/// Returns the contact secret if present in the invoice request.
770+
pub fn contact_secret(&$self) -> Option<&[u8]> {
771+
$contents.contact_secret()
772+
}
755773
} }
756774

757775
impl UnsignedInvoiceRequest {
@@ -1184,6 +1202,10 @@ impl InvoiceRequestContents {
11841202
&self.inner.offer_from_hrn
11851203
}
11861204

1205+
pub(super) fn contact_secret(&self) -> Option<&[u8]> {
1206+
self.inner.invreq_contact_secret.as_ref().map(|secret| secret.as_slice())
1207+
}
1208+
11871209
pub(super) fn as_tlv_stream(&self) -> PartialInvoiceRequestTlvStreamRef<'_> {
11881210
let (payer, offer, mut invoice_request, experimental_offer, experimental_invoice_request) =
11891211
self.inner.as_tlv_stream();
@@ -1230,7 +1252,7 @@ impl InvoiceRequestContentsWithoutPayerSigningPubkey {
12301252
};
12311253

12321254
let experimental_invoice_request = ExperimentalInvoiceRequestTlvStreamRef {
1233-
invreq_contact_secret: None,
1255+
invreq_contact_secret: self.invreq_contact_secret.as_ref(),
12341256
invreq_payer_offer: None,
12351257
invreq_payer_bip_353_name: None,
12361258
#[cfg(test)]
@@ -1471,7 +1493,7 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
14711493
},
14721494
experimental_offer_tlv_stream,
14731495
ExperimentalInvoiceRequestTlvStream {
1474-
invreq_contact_secret: _,
1496+
invreq_contact_secret,
14751497
invreq_payer_offer: _,
14761498
invreq_payer_bip_353_name: _,
14771499
#[cfg(test)]
@@ -1517,6 +1539,7 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
15171539
quantity,
15181540
payer_note,
15191541
offer_from_hrn,
1542+
invreq_contact_secret,
15201543
#[cfg(test)]
15211544
experimental_bar,
15221545
},

0 commit comments

Comments
 (0)