Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Offers builders for C-bindings #2903

Merged
10 changes: 5 additions & 5 deletions fuzz/src/invoice_request_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use bitcoin::secp256k1::{KeyPair, Parity, PublicKey, Secp256k1, SecretKey, self};
use crate::utils::test_logger;
use core::convert::{Infallible, TryFrom};
use core::convert::TryFrom;
use lightning::blinded_path::BlindedPath;
use lightning::sign::EntropySource;
use lightning::ln::PaymentHash;
Expand Down Expand Up @@ -37,16 +37,16 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {
let even_pubkey = x_only_pubkey.public_key(Parity::Even);
if signing_pubkey == odd_pubkey || signing_pubkey == even_pubkey {
unsigned_invoice
.sign::<_, Infallible>(
|message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
.sign(|message: &UnsignedBolt12Invoice|
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
)
.unwrap()
.write(&mut buffer)
.unwrap();
} else {
unsigned_invoice
.sign::<_, Infallible>(
|message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
.sign(|message: &UnsignedBolt12Invoice|
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
)
.unwrap_err();
}
Expand Down
6 changes: 3 additions & 3 deletions fuzz/src/offer_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey};
use crate::utils::test_logger;
use core::convert::{Infallible, TryFrom};
use core::convert::TryFrom;
use lightning::offers::invoice_request::UnsignedInvoiceRequest;
use lightning::offers::offer::{Amount, Offer, Quantity};
use lightning::offers::parse::Bolt12SemanticError;
Expand All @@ -29,8 +29,8 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {

if let Ok(invoice_request) = build_response(&offer, pubkey) {
invoice_request
.sign::<_, Infallible>(
|message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
.sign(|message: &UnsignedInvoiceRequest|
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
)
.unwrap()
.write(&mut buffer)
Expand Down
6 changes: 3 additions & 3 deletions fuzz/src/refund_deser.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

use bitcoin::secp256k1::{KeyPair, PublicKey, Secp256k1, SecretKey, self};
use crate::utils::test_logger;
use core::convert::{Infallible, TryFrom};
use core::convert::TryFrom;
use lightning::blinded_path::BlindedPath;
use lightning::sign::EntropySource;
use lightning::ln::PaymentHash;
Expand All @@ -33,8 +33,8 @@ pub fn do_test<Out: test_logger::Output>(data: &[u8], _out: Out) {

if let Ok(invoice) = build_response(&refund, pubkey, &secp_ctx) {
invoice
.sign::<_, Infallible>(
|message| Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
.sign(|message: &UnsignedBolt12Invoice|
Ok(secp_ctx.sign_schnorr_no_aux_rand(message.as_ref().as_digest(), &keys))
)
.unwrap()
.write(&mut buffer)
Expand Down
1 change: 1 addition & 0 deletions lightning/src/crypto/mod.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
#[cfg(not(fuzzing))]
use bitcoin::hashes::cmp::fixed_time_eq;

pub(crate) mod chacha20;
Expand Down
101 changes: 73 additions & 28 deletions lightning/src/ln/channelmanager.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,10 +57,11 @@ use crate::ln::msgs::{ChannelMessageHandler, DecodeError, LightningError};
use crate::ln::outbound_payment;
use crate::ln::outbound_payment::{Bolt12PaymentError, OutboundPayments, PaymentAttempts, PendingOutboundPayment, SendAlongPathArgs, StaleExpiration};
use crate::ln::wire::Encode;
use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, InvoiceBuilder};
use crate::offers::invoice::{BlindedPayInfo, Bolt12Invoice, DEFAULT_RELATIVE_EXPIRY, DerivedSigningPubkey, ExplicitSigningPubkey, InvoiceBuilder, UnsignedBolt12Invoice};
use crate::offers::invoice_error::InvoiceError;
use crate::offers::invoice_request::{DerivedPayerId, InvoiceRequestBuilder};
use crate::offers::merkle::SignError;
use crate::offers::offer::{DerivedMetadata, Offer, OfferBuilder};
use crate::offers::offer::{Offer, OfferBuilder};
use crate::offers::parse::Bolt12SemanticError;
use crate::offers::refund::{Refund, RefundBuilder};
use crate::onion_message::messenger::{Destination, MessageRouter, PendingOnionMessage, new_pending_onion_message};
Expand All @@ -76,11 +77,17 @@ use crate::util::logger::{Level, Logger, WithContext};
use crate::util::errors::APIError;
#[cfg(not(c_bindings))]
use {
crate::offers::offer::DerivedMetadata,
crate::routing::router::DefaultRouter,
crate::routing::gossip::NetworkGraph,
crate::routing::scoring::{ProbabilisticScorer, ProbabilisticScoringFeeParameters},
crate::sign::KeysManager,
};
#[cfg(c_bindings)]
use {
crate::offers::offer::OfferWithDerivedMetadataBuilder,
crate::offers::refund::RefundMaybeWithDerivedMetadataBuilder,
};

use alloc::collections::{btree_map, BTreeMap};

Expand Down Expand Up @@ -7520,7 +7527,9 @@ where
self.finish_close_channel(failure);
}
}
}

macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The macro create_offer_builder is a clever way to abstract the creation of OfferBuilder instances with different configurations. However, ensure that the documentation comments (///) are correctly placed and provide sufficient information for users of this macro. Additionally, consider adding error handling documentation if Bolt12SemanticError::MissingPaths is not the only possible error.

+ /// Error handling documentation if applicable.

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
/// Error handling documentation if applicable.

/// Creates an [`OfferBuilder`] such that the [`Offer`] it builds is recognized by the
/// [`ChannelManager`] when handling [`InvoiceRequest`] messages for the offer. The offer will
/// not have an expiration unless otherwise set on the builder.
Expand Down Expand Up @@ -7549,23 +7558,25 @@ where
/// [`Offer`]: crate::offers::offer::Offer
/// [`InvoiceRequest`]: crate::offers::invoice_request::InvoiceRequest
pub fn create_offer_builder(
&self, description: String
) -> Result<OfferBuilder<DerivedMetadata, secp256k1::All>, Bolt12SemanticError> {
let node_id = self.get_our_node_id();
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;

let path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
&$self, description: String
) -> Result<$builder, Bolt12SemanticError> {
let node_id = $self.get_our_node_id();
let expanded_key = &$self.inbound_payment_key;
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;

let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let builder = OfferBuilder::deriving_signing_pubkey(
description, node_id, expanded_key, entropy, secp_ctx
)
.chain_hash(self.chain_hash)
.chain_hash($self.chain_hash)
.path(path);

Ok(builder)
Ok(builder.into())
}
} }

macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
///
Expand Down Expand Up @@ -7615,31 +7626,53 @@ where
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
pub fn create_refund_builder(
&self, description: String, amount_msats: u64, absolute_expiry: Duration,
&$self, description: String, amount_msats: u64, absolute_expiry: Duration,
payment_id: PaymentId, retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>
) -> Result<RefundBuilder<secp256k1::All>, Bolt12SemanticError> {
let node_id = self.get_our_node_id();
let expanded_key = &self.inbound_payment_key;
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;
) -> Result<$builder, Bolt12SemanticError> {
let node_id = $self.get_our_node_id();
let expanded_key = &$self.inbound_payment_key;
let entropy = &*$self.entropy_source;
let secp_ctx = &$self.secp_ctx;

let path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
let builder = RefundBuilder::deriving_payer_id(
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
)?
.chain_hash(self.chain_hash)
.chain_hash($self.chain_hash)
.absolute_expiry(absolute_expiry)
.path(path);

let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
self.pending_outbound_payments
$self.pending_outbound_payments
.add_new_awaiting_invoice(
payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
)
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;

Ok(builder)
Ok(builder.into())
}
} }

impl<M: Deref, T: Deref, ES: Deref, NS: Deref, SP: Deref, F: Deref, R: Deref, L: Deref> ChannelManager<M, T, ES, NS, SP, F, R, L>
where
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
T::Target: BroadcasterInterface,
ES::Target: EntropySource,
NS::Target: NodeSigner,
SP::Target: SignerProvider,
F::Target: FeeEstimator,
R::Target: Router,
L::Target: Logger,
{
#[cfg(not(c_bindings))]
create_offer_builder!(self, OfferBuilder<DerivedMetadata, secp256k1::All>);
#[cfg(not(c_bindings))]
create_refund_builder!(self, RefundBuilder<secp256k1::All>);

#[cfg(c_bindings)]
create_offer_builder!(self, OfferWithDerivedMetadataBuilder);
#[cfg(c_bindings)]
create_refund_builder!(self, RefundMaybeWithDerivedMetadataBuilder);

/// Pays for an [`Offer`] using the given parameters by creating an [`InvoiceRequest`] and
/// enqueuing it to be sent via an onion message. [`ChannelManager`] will pay the actual
Expand Down Expand Up @@ -7703,9 +7736,11 @@ where
let entropy = &*self.entropy_source;
let secp_ctx = &self.secp_ctx;

let builder = offer
let builder: InvoiceRequestBuilder<DerivedPayerId, secp256k1::All> = offer
.request_invoice_deriving_payer_id(expanded_key, entropy, secp_ctx, payment_id)?
.chain_hash(self.chain_hash)?;
.into();
let builder = builder.chain_hash(self.chain_hash)?;

let builder = match quantity {
None => builder,
Some(quantity) => builder.quantity(quantity)?,
Expand Down Expand Up @@ -7799,6 +7834,7 @@ where
let builder = refund.respond_using_derived_keys_no_std(
payment_paths, payment_hash, created_at, expanded_key, entropy
)?;
let builder: InvoiceBuilder<DerivedSigningPubkey> = builder.into();
let invoice = builder.allow_mpp().build_and_sign(secp_ctx)?;
let reply_path = self.create_blinded_path()
.map_err(|_| Bolt12SemanticError::MissingPaths)?;
Expand Down Expand Up @@ -9246,6 +9282,8 @@ where
let builder = invoice_request.respond_using_derived_keys_no_std(
payment_paths, payment_hash, created_at
);
let builder: Result<InvoiceBuilder<DerivedSigningPubkey>, _> =
builder.map(|b| b.into());
match builder.and_then(|b| b.allow_mpp().build_and_sign(secp_ctx)) {
Ok(invoice) => Some(OffersMessage::Invoice(invoice)),
Err(error) => Some(OffersMessage::InvoiceError(error.into())),
Expand All @@ -9257,18 +9295,25 @@ where
let builder = invoice_request.respond_with_no_std(
payment_paths, payment_hash, created_at
);
let builder: Result<InvoiceBuilder<ExplicitSigningPubkey>, _> =
builder.map(|b| b.into());
let response = builder.and_then(|builder| builder.allow_mpp().build())
.map_err(|e| OffersMessage::InvoiceError(e.into()))
.and_then(|invoice|
match invoice.sign(|invoice| self.node_signer.sign_bolt12_invoice(invoice)) {
.and_then(|invoice| {
#[cfg(c_bindings)]
let mut invoice = invoice;
match invoice.sign(|invoice: &UnsignedBolt12Invoice|
self.node_signer.sign_bolt12_invoice(invoice)
) {
Ok(invoice) => Ok(OffersMessage::Invoice(invoice)),
Err(SignError::Signing(())) => Err(OffersMessage::InvoiceError(
Err(SignError::Signing) => Err(OffersMessage::InvoiceError(
InvoiceError::from_string("Failed signing invoice".to_string())
)),
Err(SignError::Verification(_)) => Err(OffersMessage::InvoiceError(
InvoiceError::from_string("Failed invoice signature verification".to_string())
)),
});
}
});
match response {
Ok(invoice) => Some(invoice),
Err(error) => Some(error),
Expand Down
Loading
Loading