Skip to content

Commit a24c79e

Browse files
committed
RefundBuilder for c_bindings
RefundBuilder is currently not exported to bindings because it uses move semantics and has impl blocks for specific type parameterizations. Define a macro that defines RefundBuilder methods such that c_bindings versions can be defined. Methods for the c_bindings version use the unit return type, except in tests where they use &mut Self.
1 parent b11d6cf commit a24c79e

File tree

2 files changed

+147
-77
lines changed

2 files changed

+147
-77
lines changed

lightning/src/ln/channelmanager.rs

+53-31
Original file line numberDiff line numberDiff line change
@@ -7586,23 +7586,7 @@ macro_rules! create_offer_builder { ($self: ident, $builder: ty) => {
75867586
}
75877587
} }
75887588

7589-
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>
7590-
where
7591-
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
7592-
T::Target: BroadcasterInterface,
7593-
ES::Target: EntropySource,
7594-
NS::Target: NodeSigner,
7595-
SP::Target: SignerProvider,
7596-
F::Target: FeeEstimator,
7597-
R::Target: Router,
7598-
L::Target: Logger,
7599-
{
7600-
#[cfg(not(c_bindings))]
7601-
create_offer_builder!(self, OfferBuilder<DerivedMetadata, secp256k1::All>);
7602-
7603-
#[cfg(c_bindings)]
7604-
create_offer_builder!(self, OfferWithDerivedMetadataBuilder);
7605-
7589+
macro_rules! create_refund_builder { ($self: ident, $builder: ty) => {
76067590
/// Creates a [`RefundBuilder`] such that the [`Refund`] it builds is recognized by the
76077591
/// [`ChannelManager`] when handling [`Bolt12Invoice`] messages for the refund.
76087592
///
@@ -7652,31 +7636,69 @@ where
76527636
/// [`Bolt12Invoice::payment_paths`]: crate::offers::invoice::Bolt12Invoice::payment_paths
76537637
/// [Avoiding Duplicate Payments]: #avoiding-duplicate-payments
76547638
pub fn create_refund_builder(
7655-
&self, description: String, amount_msats: u64, absolute_expiry: Duration,
7639+
&$self, description: String, amount_msats: u64, absolute_expiry: Duration,
76567640
payment_id: PaymentId, retry_strategy: Retry, max_total_routing_fee_msat: Option<u64>
7657-
) -> Result<RefundBuilder<secp256k1::All>, Bolt12SemanticError> {
7658-
let node_id = self.get_our_node_id();
7659-
let expanded_key = &self.inbound_payment_key;
7660-
let entropy = &*self.entropy_source;
7661-
let secp_ctx = &self.secp_ctx;
7641+
) -> Result<$builder, Bolt12SemanticError> {
7642+
let node_id = $self.get_our_node_id();
7643+
let expanded_key = &$self.inbound_payment_key;
7644+
let entropy = &*$self.entropy_source;
7645+
let secp_ctx = &$self.secp_ctx;
7646+
7647+
let path = $self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
7648+
7649+
#[cfg(not(c_bindings))]
7650+
let builder;
7651+
#[cfg(not(c_bindings))] {
7652+
builder = <$builder>::deriving_payer_id(
7653+
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
7654+
)?
7655+
.chain_hash($self.chain_hash)
7656+
.absolute_expiry(absolute_expiry)
7657+
.path(path);
7658+
}
76627659

7663-
let path = self.create_blinded_path().map_err(|_| Bolt12SemanticError::MissingPaths)?;
7664-
let builder = RefundBuilder::deriving_payer_id(
7665-
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
7666-
)?
7667-
.chain_hash(self.chain_hash)
7668-
.absolute_expiry(absolute_expiry)
7669-
.path(path);
7660+
#[cfg(c_bindings)]
7661+
let mut builder;
7662+
#[cfg(c_bindings)] {
7663+
builder = <$builder>::deriving_payer_id(
7664+
description, node_id, expanded_key, entropy, secp_ctx, amount_msats, payment_id
7665+
)?;
7666+
builder.chain_hash($self.chain_hash);
7667+
builder.absolute_expiry(absolute_expiry);
7668+
builder.path(path);
7669+
}
76707670

76717671
let expiration = StaleExpiration::AbsoluteTimeout(absolute_expiry);
7672-
self.pending_outbound_payments
7672+
$self.pending_outbound_payments
76737673
.add_new_awaiting_invoice(
76747674
payment_id, expiration, retry_strategy, max_total_routing_fee_msat,
76757675
)
76767676
.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
76777677

76787678
Ok(builder)
76797679
}
7680+
} }
7681+
7682+
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>
7683+
where
7684+
M::Target: chain::Watch<<SP::Target as SignerProvider>::EcdsaSigner>,
7685+
T::Target: BroadcasterInterface,
7686+
ES::Target: EntropySource,
7687+
NS::Target: NodeSigner,
7688+
SP::Target: SignerProvider,
7689+
F::Target: FeeEstimator,
7690+
R::Target: Router,
7691+
L::Target: Logger,
7692+
{
7693+
#[cfg(not(c_bindings))]
7694+
create_offer_builder!(self, OfferBuilder<DerivedMetadata, secp256k1::All>);
7695+
#[cfg(not(c_bindings))]
7696+
create_refund_builder!(self, RefundBuilder<secp256k1::All>);
7697+
7698+
#[cfg(c_bindings)]
7699+
create_offer_builder!(self, OfferWithDerivedMetadataBuilder);
7700+
#[cfg(c_bindings)]
7701+
create_refund_builder!(self, RefundBuilder);
76807702

76817703
/// Pays for an [`Offer`] using the given parameters by creating an [`InvoiceRequest`] and
76827704
/// enqueuing it to be sent via an onion message. [`ChannelManager`] will pay the actual

lightning/src/offers/refund.rs

+94-46
Original file line numberDiff line numberDiff line change
@@ -116,15 +116,25 @@ pub(super) const IV_BYTES: &[u8; IV_LEN] = b"LDK Refund ~~~~~";
116116
///
117117
/// See [module-level documentation] for usage.
118118
///
119-
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
120-
///
121119
/// [module-level documentation]: self
120+
#[cfg(not(c_bindings))]
122121
pub struct RefundBuilder<'a, T: secp256k1::Signing> {
123122
refund: RefundContents,
124123
secp_ctx: Option<&'a Secp256k1<T>>,
125124
}
126125

127-
impl<'a> RefundBuilder<'a, secp256k1::SignOnly> {
126+
/// Builds a [`Refund`] for the "offer for money" flow.
127+
///
128+
/// See [module-level documentation] for usage.
129+
///
130+
/// [module-level documentation]: self
131+
#[cfg(c_bindings)]
132+
pub struct RefundBuilder<'a> {
133+
refund: RefundContents,
134+
secp_ctx: Option<&'a Secp256k1<secp256k1::All>>,
135+
}
136+
137+
macro_rules! refund_without_secp256k1_builder_methods { () => {
128138
/// Creates a new builder for a refund using the [`Refund::payer_id`] for the public node id to
129139
/// send to if no [`Refund::paths`] are set. Otherwise, it may be a transient pubkey.
130140
///
@@ -155,9 +165,11 @@ impl<'a> RefundBuilder<'a, secp256k1::SignOnly> {
155165
secp_ctx: None,
156166
})
157167
}
158-
}
168+
} }
159169

160-
impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
170+
macro_rules! refund_builder_methods { (
171+
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
172+
) => {
161173
/// Similar to [`RefundBuilder::new`] except, if [`RefundBuilder::path`] is called, the payer id
162174
/// is derived from the given [`ExpandedKey`] and nonce. This provides sender privacy by using a
163175
/// different payer id for each refund, assuming a different nonce is used. Otherwise, the
@@ -173,7 +185,11 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
173185
/// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
174186
pub fn deriving_payer_id<ES: Deref>(
175187
description: String, node_id: PublicKey, expanded_key: &ExpandedKey, entropy_source: ES,
176-
secp_ctx: &'a Secp256k1<T>, amount_msats: u64, payment_id: PaymentId
188+
#[cfg(not(c_bindings))]
189+
secp_ctx: &'a Secp256k1<T>,
190+
#[cfg(c_bindings)]
191+
secp_ctx: &'a Secp256k1<secp256k1::All>,
192+
amount_msats: u64, payment_id: PaymentId
177193
) -> Result<Self, Bolt12SemanticError> where ES::Target: EntropySource {
178194
if amount_msats > MAX_VALUE_MSAT {
179195
return Err(Bolt12SemanticError::InvalidAmount);
@@ -197,44 +213,44 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
197213
/// already passed is valid and can be checked for using [`Refund::is_expired`].
198214
///
199215
/// Successive calls to this method will override the previous setting.
200-
pub fn absolute_expiry(mut self, absolute_expiry: Duration) -> Self {
201-
self.refund.absolute_expiry = Some(absolute_expiry);
202-
self
216+
pub fn absolute_expiry(mut $self: $self_type, absolute_expiry: Duration) -> $return_type {
217+
$self.refund.absolute_expiry = Some(absolute_expiry);
218+
$return_value
203219
}
204220

205221
/// Sets the [`Refund::issuer`].
206222
///
207223
/// Successive calls to this method will override the previous setting.
208-
pub fn issuer(mut self, issuer: String) -> Self {
209-
self.refund.issuer = Some(issuer);
210-
self
224+
pub fn issuer(mut $self: $self_type, issuer: String) -> $return_type {
225+
$self.refund.issuer = Some(issuer);
226+
$return_value
211227
}
212228

213229
/// Adds a blinded path to [`Refund::paths`]. Must include at least one path if only connected
214230
/// by private channels or if [`Refund::payer_id`] is not a public node id.
215231
///
216232
/// Successive calls to this method will add another blinded path. Caller is responsible for not
217233
/// adding duplicate paths.
218-
pub fn path(mut self, path: BlindedPath) -> Self {
219-
self.refund.paths.get_or_insert_with(Vec::new).push(path);
220-
self
234+
pub fn path(mut $self: $self_type, path: BlindedPath) -> $return_type {
235+
$self.refund.paths.get_or_insert_with(Vec::new).push(path);
236+
$return_value
221237
}
222238

223239
/// Sets the [`Refund::chain`] of the given [`Network`] for paying an invoice. If not
224240
/// called, [`Network::Bitcoin`] is assumed.
225241
///
226242
/// Successive calls to this method will override the previous setting.
227-
pub fn chain(self, network: Network) -> Self {
228-
self.chain_hash(ChainHash::using_genesis_block(network))
243+
pub fn chain($self: $self_type, network: Network) -> $return_type {
244+
$self.chain_hash(ChainHash::using_genesis_block(network))
229245
}
230246

231247
/// Sets the [`Refund::chain`] of the given [`ChainHash`] for paying an invoice. If not called,
232248
/// [`Network::Bitcoin`] is assumed.
233249
///
234250
/// Successive calls to this method will override the previous setting.
235-
pub(crate) fn chain_hash(mut self, chain: ChainHash) -> Self {
236-
self.refund.chain = Some(chain);
237-
self
251+
pub(crate) fn chain_hash(mut $self: $self_type, chain: ChainHash) -> $return_type {
252+
$self.refund.chain = Some(chain);
253+
$return_value
238254
}
239255

240256
/// Sets [`Refund::quantity`] of items. This is purely for informational purposes. It is useful
@@ -246,66 +262,98 @@ impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
246262
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
247263
/// [`InvoiceRequest::quantity`]: crate::offers::invoice_request::InvoiceRequest::quantity
248264
/// [`Offer`]: crate::offers::offer::Offer
249-
pub fn quantity(mut self, quantity: u64) -> Self {
250-
self.refund.quantity = Some(quantity);
251-
self
265+
pub fn quantity(mut $self: $self_type, quantity: u64) -> $return_type {
266+
$self.refund.quantity = Some(quantity);
267+
$return_value
252268
}
253269

254270
/// Sets the [`Refund::payer_note`].
255271
///
256272
/// Successive calls to this method will override the previous setting.
257-
pub fn payer_note(mut self, payer_note: String) -> Self {
258-
self.refund.payer_note = Some(payer_note);
259-
self
273+
pub fn payer_note(mut $self: $self_type, payer_note: String) -> $return_type {
274+
$self.refund.payer_note = Some(payer_note);
275+
$return_value
260276
}
261277

262278
/// Builds a [`Refund`] after checking for valid semantics.
263-
pub fn build(mut self) -> Result<Refund, Bolt12SemanticError> {
264-
if self.refund.chain() == self.refund.implied_chain() {
265-
self.refund.chain = None;
279+
pub fn build(mut $self: $self_type) -> Result<Refund, Bolt12SemanticError> {
280+
if $self.refund.chain() == $self.refund.implied_chain() {
281+
$self.refund.chain = None;
266282
}
267283

268284
// Create the metadata for stateless verification of a Bolt12Invoice.
269-
if self.refund.payer.0.has_derivation_material() {
270-
let mut metadata = core::mem::take(&mut self.refund.payer.0);
285+
if $self.refund.payer.0.has_derivation_material() {
286+
let mut metadata = core::mem::take(&mut $self.refund.payer.0);
271287

272-
if self.refund.paths.is_none() {
288+
if $self.refund.paths.is_none() {
273289
metadata = metadata.without_keys();
274290
}
275291

276-
let mut tlv_stream = self.refund.as_tlv_stream();
292+
let mut tlv_stream = $self.refund.as_tlv_stream();
277293
tlv_stream.0.metadata = None;
278294
if metadata.derives_payer_keys() {
279295
tlv_stream.2.payer_id = None;
280296
}
281297

282-
let (derived_metadata, keys) = metadata.derive_from(tlv_stream, self.secp_ctx);
298+
let (derived_metadata, keys) = metadata.derive_from(tlv_stream, $self.secp_ctx);
283299
metadata = derived_metadata;
284300
if let Some(keys) = keys {
285-
self.refund.payer_id = keys.public_key();
301+
$self.refund.payer_id = keys.public_key();
286302
}
287303

288-
self.refund.payer.0 = metadata;
304+
$self.refund.payer.0 = metadata;
289305
}
290306

291307
let mut bytes = Vec::new();
292-
self.refund.write(&mut bytes).unwrap();
308+
$self.refund.write(&mut bytes).unwrap();
293309

294-
Ok(Refund { bytes, contents: self.refund })
310+
#[cfg(not(c_bindings))] {
311+
Ok(Refund { bytes, contents: $self.refund })
312+
}
313+
#[cfg(c_bindings)] {
314+
Ok(Refund { bytes, contents: $self.refund.clone() })
315+
}
295316
}
296-
}
317+
} }
297318

298319
#[cfg(test)]
299-
impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
300-
pub(crate) fn clear_paths(mut self) -> Self {
301-
self.refund.paths = None;
302-
self
320+
macro_rules! refund_builder_test_methods { (
321+
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
322+
) => {
323+
pub(crate) fn clear_paths(mut $self: $self_type) -> $return_type {
324+
$self.refund.paths = None;
325+
$return_value
303326
}
304327

305-
fn features_unchecked(mut self, features: InvoiceRequestFeatures) -> Self {
306-
self.refund.features = features;
307-
self
328+
fn features_unchecked(mut $self: $self_type, features: InvoiceRequestFeatures) -> $return_type {
329+
$self.refund.features = features;
330+
$return_value
308331
}
332+
} }
333+
334+
#[cfg(not(c_bindings))]
335+
impl<'a> RefundBuilder<'a, secp256k1::SignOnly> {
336+
refund_without_secp256k1_builder_methods!();
337+
}
338+
339+
#[cfg(not(c_bindings))]
340+
impl<'a, T: secp256k1::Signing> RefundBuilder<'a, T> {
341+
refund_builder_methods!(self, Self, Self, self);
342+
343+
#[cfg(test)]
344+
refund_builder_test_methods!(self, Self, Self, self);
345+
}
346+
347+
#[cfg(c_bindings)]
348+
impl<'a> RefundBuilder<'a> {
349+
refund_without_secp256k1_builder_methods!();
350+
#[cfg(not(test))]
351+
refund_builder_methods!(self, &mut Self, (), ());
352+
353+
#[cfg(test)]
354+
refund_builder_methods!(self, &mut Self, &mut Self, self);
355+
#[cfg(test)]
356+
refund_builder_test_methods!(self, &mut Self, &mut Self, self);
309357
}
310358

311359
/// A `Refund` is a request to send an [`Bolt12Invoice`] without a preceding [`Offer`].

0 commit comments

Comments
 (0)