Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion fuzz/src/full_stack.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,9 +80,9 @@ use bitcoin::secp256k1::{self, Message, PublicKey, Scalar, Secp256k1, SecretKey}

use lightning::util::dyn_signer::DynSigner;

use std::collections::VecDeque;
use std::cell::RefCell;
use std::cmp;
use std::collections::VecDeque;
use std::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
use std::sync::{Arc, Mutex};

Expand Down
137 changes: 90 additions & 47 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -93,11 +93,9 @@ use crate::ln::outbound_payment::{
use crate::ln::types::ChannelId;
use crate::offers::async_receive_offer_cache::AsyncReceiveOfferCache;
use crate::offers::flow::{InvreqResponseInstructions, OffersMessageFlow};
use crate::offers::invoice::{
Bolt12Invoice, DerivedSigningPubkey, InvoiceBuilder, DEFAULT_RELATIVE_EXPIRY,
};
use crate::offers::invoice::{Bolt12Invoice, UnsignedBolt12Invoice};
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::InvoiceRequest;
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestVerifiedFromOffer};
use crate::offers::nonce::Nonce;
use crate::offers::offer::Offer;
use crate::offers::parse::Bolt12SemanticError;
Expand Down Expand Up @@ -7422,7 +7420,7 @@ where
};
let payment_purpose_context =
PaymentContext::Bolt12Offer(Bolt12OfferContext {
offer_id: verified_invreq.offer_id,
offer_id: verified_invreq.offer_id(),
invoice_request: verified_invreq.fields(),
});
let from_parts_res = events::PaymentPurpose::from_parts(
Expand Down Expand Up @@ -12233,33 +12231,29 @@ where
///
/// [`BlindedPaymentPath`]: crate::blinded_path::payment::BlindedPaymentPath
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[rustfmt::skip]
pub fn request_refund_payment(
&self, refund: &Refund
&self, refund: &Refund,
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
let secp_ctx = &self.secp_ctx;

let amount_msats = refund.amount_msats();
let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
let entropy = &*self.entropy_source;

let _persistence_guard = PersistenceNotifierGuard::notify_on_drop(self);

match self.create_inbound_payment(Some(amount_msats), relative_expiry, None) {
Ok((payment_hash, payment_secret)) => {
let entropy = &*self.entropy_source;
let builder = self.flow.create_invoice_builder_from_refund(
&self.router, entropy, refund, payment_hash,
payment_secret, self.list_usable_channels()
)?;

let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
let builder = self.flow.create_invoice_builder_from_refund(
&self.router,
entropy,
refund,
self.list_usable_channels(),
|amount_msats, relative_expiry| {
self.create_inbound_payment(Some(amount_msats), relative_expiry, None)
.map_err(|()| Bolt12SemanticError::InvalidAmount)
},
)?;

self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;

Ok(invoice)
},
Err(()) => Err(Bolt12SemanticError::InvalidAmount),
}
self.flow.enqueue_invoice(invoice.clone(), refund, self.get_peers_for_blinded_path())?;
Ok(invoice)
}

/// Pays for an [`Offer`] looked up using [BIP 353] Human Readable Names resolved by the DNS
Expand Down Expand Up @@ -14329,34 +14323,83 @@ where
Err(_) => return None,
};

let amount_msats = match InvoiceBuilder::<DerivedSigningPubkey>::amount_msats(
&invoice_request.inner
) {
Ok(amount_msats) => amount_msats,
Err(error) => return Some((OffersMessage::InvoiceError(error.into()), responder.respond())),
let get_payment_info = |amount_msats, relative_expiry| {
self.create_inbound_payment(
Some(amount_msats),
relative_expiry,
None
).map_err(|_| Bolt12SemanticError::InvalidAmount)
};

let relative_expiry = DEFAULT_RELATIVE_EXPIRY.as_secs() as u32;
let (payment_hash, payment_secret) = match self.create_inbound_payment(
Some(amount_msats), relative_expiry, None
) {
Ok((payment_hash, payment_secret)) => (payment_hash, payment_secret),
Err(()) => {
let error = Bolt12SemanticError::InvalidAmount;
return Some((OffersMessage::InvoiceError(error.into()), responder.respond()));
let (result, context) = match invoice_request {
InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
let result = self.flow.create_invoice_builder_from_invoice_request_with_keys(
&self.router,
&*self.entropy_source,
&request,
self.list_usable_channels(),
get_payment_info,
);

match result {
Ok((builder, context)) => {
let res = builder
.build_and_sign(&self.secp_ctx)
.map_err(InvoiceError::from);

(res, context)
},
Err(error) => {
return Some((
OffersMessage::InvoiceError(InvoiceError::from(error)),
responder.respond(),
));
},
}
},
};
InvoiceRequestVerifiedFromOffer::ExplicitKeys(request) => {
let result = self.flow.create_invoice_builder_from_invoice_request_without_keys(
&self.router,
&*self.entropy_source,
&request,
self.list_usable_channels(),
get_payment_info,
);

let entropy = &*self.entropy_source;
let (response, context) = self.flow.create_response_for_invoice_request(
&self.node_signer, &self.router, entropy, invoice_request, amount_msats,
payment_hash, payment_secret, self.list_usable_channels()
);
match result {
Ok((builder, context)) => {
let res = builder
.build()
.map_err(InvoiceError::from)
.and_then(|invoice| {
#[cfg(c_bindings)]
let mut invoice = invoice;
invoice
.sign(|invoice: &UnsignedBolt12Invoice| self.node_signer.sign_bolt12_invoice(invoice))
.map_err(InvoiceError::from)
});
(res, context)
},
Err(error) => {
return Some((
OffersMessage::InvoiceError(InvoiceError::from(error)),
responder.respond(),
));
},
}
}
};

match context {
Some(context) => Some((response, responder.respond_with_reply_path(context))),
None => Some((response, responder.respond()))
}
Some(match result {
Ok(invoice) => (
OffersMessage::Invoice(invoice),
responder.respond_with_reply_path(context),
),
Err(error) => (
OffersMessage::InvoiceError(error),
responder.respond(),
),
})
},
OffersMessage::Invoice(invoice) => {
let payment_id = match self.flow.verify_bolt12_invoice(&invoice, context.as_ref()) {
Expand Down
20 changes: 14 additions & 6 deletions lightning/src/ln/offers_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ use crate::ln::msgs::{BaseMessageHandler, ChannelMessageHandler, Init, NodeAnnou
use crate::ln::outbound_payment::IDEMPOTENCY_TIMEOUT_TICKS;
use crate::offers::invoice::Bolt12Invoice;
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields};
use crate::offers::invoice_request::{InvoiceRequest, InvoiceRequestFields, InvoiceRequestVerifiedFromOffer};
use crate::offers::nonce::Nonce;
use crate::offers::parse::Bolt12SemanticError;
use crate::onion_message::messenger::{Destination, MessageSendInstructions, NodeIdMessageRouter, NullMessageRouter, PeeledOnion};
Expand Down Expand Up @@ -2276,11 +2276,19 @@ fn fails_paying_invoice_with_unknown_required_features() {
let secp_ctx = Secp256k1::new();

let created_at = alice.node.duration_since_epoch();
let invoice = invoice_request
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap()
.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
.features_unchecked(Bolt12InvoiceFeatures::unknown())
.build_and_sign(&secp_ctx).unwrap();
let verified_invoice_request = invoice_request
.verify_using_recipient_data(nonce, &expanded_key, &secp_ctx).unwrap();

let invoice = match verified_invoice_request {
InvoiceRequestVerifiedFromOffer::DerivedKeys(request) => {
request.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at).unwrap()
.features_unchecked(Bolt12InvoiceFeatures::unknown())
.build_and_sign(&secp_ctx).unwrap()
},
InvoiceRequestVerifiedFromOffer::ExplicitKeys(_) => {
panic!("Expected invoice request with keys");
},
};

// Enqueue an onion message containing the new invoice.
let instructions = MessageSendInstructions::WithoutReplyPath {
Expand Down
Loading
Loading