Skip to content

Commit

Permalink
Merge pull request #2903 from jkczyz/2024-02-bindings-builders
Browse files Browse the repository at this point in the history
Offers builders for C-bindings
  • Loading branch information
valentinewallace authored Mar 8, 2024
2 parents 07059ec + 9277166 commit 670b41a
Show file tree
Hide file tree
Showing 11 changed files with 1,126 additions and 476 deletions.
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 @@ -58,10 +58,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 @@ -77,11 +78,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 @@ -7633,7 +7640,9 @@ where
self.finish_close_channel(failure);
}
}
}

macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
/// 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 @@ -7662,23 +7671,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 @@ -7728,31 +7739,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 @@ -7816,9 +7849,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 @@ -7912,6 +7947,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 @@ -9424,6 +9460,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 @@ -9435,18 +9473,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

0 comments on commit 670b41a

Please sign in to comment.