Skip to content

Commit 07d628e

Browse files
committed
Macro-ize InvoiceBuilder
InvoiceBuilder is not exported to bindings because it has methods that take `self` by value and are only implemented for certain type parameterizations. Define these methods using macros such that different builders and related methods can be defined for c_bindings.
1 parent 3a92c7b commit 07d628e

File tree

3 files changed

+130
-111
lines changed

3 files changed

+130
-111
lines changed

lightning/src/offers/invoice.rs

Lines changed: 55 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ pub struct DerivedSigningPubkey(KeyPair);
169169
impl SigningPubkeyStrategy for ExplicitSigningPubkey {}
170170
impl SigningPubkeyStrategy for DerivedSigningPubkey {}
171171

172-
impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
172+
macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
173173
pub(super) fn for_offer(
174174
invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
175175
created_at: Duration, payment_hash: PaymentHash
@@ -203,25 +203,25 @@ impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
203203

204204
/// Builds an unsigned [`Bolt12Invoice`] after checking for valid semantics. It can be signed by
205205
/// [`UnsignedBolt12Invoice::sign`].
206-
pub fn build(self) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
206+
pub fn build($self: $self_type) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
207207
#[cfg(feature = "std")] {
208-
if self.invoice.is_offer_or_refund_expired() {
208+
if $self.invoice.is_offer_or_refund_expired() {
209209
return Err(Bolt12SemanticError::AlreadyExpired);
210210
}
211211
}
212212

213213
#[cfg(not(feature = "std"))] {
214-
if self.invoice.is_offer_or_refund_expired_no_std(self.invoice.created_at()) {
214+
if $self.invoice.is_offer_or_refund_expired_no_std($self.invoice.created_at()) {
215215
return Err(Bolt12SemanticError::AlreadyExpired);
216216
}
217217
}
218218

219-
let InvoiceBuilder { invreq_bytes, invoice, .. } = self;
219+
let InvoiceBuilder { invreq_bytes, invoice, .. } = $self;
220220
Ok(UnsignedBolt12Invoice::new(invreq_bytes, invoice))
221221
}
222-
}
222+
} }
223223

224-
impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
224+
macro_rules! invoice_derived_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
225225
pub(super) fn for_offer_using_keys(
226226
invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
227227
created_at: Duration, payment_hash: PaymentHash, keys: KeyPair
@@ -256,23 +256,23 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
256256

257257
/// Builds a signed [`Bolt12Invoice`] after checking for valid semantics.
258258
pub fn build_and_sign<T: secp256k1::Signing>(
259-
self, secp_ctx: &Secp256k1<T>
259+
$self: $self_type, secp_ctx: &Secp256k1<T>
260260
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
261261
#[cfg(feature = "std")] {
262-
if self.invoice.is_offer_or_refund_expired() {
262+
if $self.invoice.is_offer_or_refund_expired() {
263263
return Err(Bolt12SemanticError::AlreadyExpired);
264264
}
265265
}
266266

267267
#[cfg(not(feature = "std"))] {
268-
if self.invoice.is_offer_or_refund_expired_no_std(self.invoice.created_at()) {
268+
if $self.invoice.is_offer_or_refund_expired_no_std($self.invoice.created_at()) {
269269
return Err(Bolt12SemanticError::AlreadyExpired);
270270
}
271271
}
272272

273273
let InvoiceBuilder {
274274
invreq_bytes, invoice, signing_pubkey_strategy: DerivedSigningPubkey(keys)
275-
} = self;
275+
} = $self;
276276
let unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice);
277277

278278
let invoice = unsigned_invoice
@@ -282,9 +282,11 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
282282
.unwrap();
283283
Ok(invoice)
284284
}
285-
}
285+
} }
286286

287-
impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
287+
macro_rules! invoice_builder_methods { (
288+
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
289+
) => {
288290
pub(crate) fn amount_msats(
289291
invoice_request: &InvoiceRequest
290292
) -> Result<u64, Bolt12SemanticError> {
@@ -326,57 +328,69 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
326328
/// [`Bolt12Invoice::is_expired`].
327329
///
328330
/// Successive calls to this method will override the previous setting.
329-
pub fn relative_expiry(mut self, relative_expiry_secs: u32) -> Self {
331+
pub fn relative_expiry(mut $self: $self_type, relative_expiry_secs: u32) -> $return_type {
330332
let relative_expiry = Duration::from_secs(relative_expiry_secs as u64);
331-
self.invoice.fields_mut().relative_expiry = Some(relative_expiry);
332-
self
333+
$self.invoice.fields_mut().relative_expiry = Some(relative_expiry);
334+
$return_value
333335
}
334336

335337
/// Adds a P2WSH address to [`Bolt12Invoice::fallbacks`].
336338
///
337339
/// Successive calls to this method will add another address. Caller is responsible for not
338340
/// adding duplicate addresses and only calling if capable of receiving to P2WSH addresses.
339-
pub fn fallback_v0_p2wsh(mut self, script_hash: &WScriptHash) -> Self {
341+
pub fn fallback_v0_p2wsh(mut $self: $self_type, script_hash: &WScriptHash) -> $return_type {
340342
let address = FallbackAddress {
341343
version: WitnessVersion::V0.to_num(),
342344
program: Vec::from(script_hash.to_byte_array()),
343345
};
344-
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
345-
self
346+
$self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
347+
$return_value
346348
}
347349

348350
/// Adds a P2WPKH address to [`Bolt12Invoice::fallbacks`].
349351
///
350352
/// Successive calls to this method will add another address. Caller is responsible for not
351353
/// adding duplicate addresses and only calling if capable of receiving to P2WPKH addresses.
352-
pub fn fallback_v0_p2wpkh(mut self, pubkey_hash: &WPubkeyHash) -> Self {
354+
pub fn fallback_v0_p2wpkh(mut $self: $self_type, pubkey_hash: &WPubkeyHash) -> $return_type {
353355
let address = FallbackAddress {
354356
version: WitnessVersion::V0.to_num(),
355357
program: Vec::from(pubkey_hash.to_byte_array()),
356358
};
357-
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
358-
self
359+
$self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
360+
$return_value
359361
}
360362

361363
/// Adds a P2TR address to [`Bolt12Invoice::fallbacks`].
362364
///
363365
/// Successive calls to this method will add another address. Caller is responsible for not
364366
/// adding duplicate addresses and only calling if capable of receiving to P2TR addresses.
365-
pub fn fallback_v1_p2tr_tweaked(mut self, output_key: &TweakedPublicKey) -> Self {
367+
pub fn fallback_v1_p2tr_tweaked(mut $self: $self_type, output_key: &TweakedPublicKey) -> $return_type {
366368
let address = FallbackAddress {
367369
version: WitnessVersion::V1.to_num(),
368370
program: Vec::from(&output_key.serialize()[..]),
369371
};
370-
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
371-
self
372+
$self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
373+
$return_value
372374
}
373375

374376
/// Sets [`Bolt12Invoice::invoice_features`] to indicate MPP may be used. Otherwise, MPP is
375377
/// disallowed.
376-
pub fn allow_mpp(mut self) -> Self {
377-
self.invoice.fields_mut().features.set_basic_mpp_optional();
378-
self
378+
pub fn allow_mpp(mut $self: $self_type) -> $return_type {
379+
$self.invoice.fields_mut().features.set_basic_mpp_optional();
380+
$return_value
379381
}
382+
} }
383+
384+
impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
385+
invoice_explicit_signing_pubkey_builder_methods!(self, Self);
386+
}
387+
388+
impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
389+
invoice_derived_signing_pubkey_builder_methods!(self, Self);
390+
}
391+
392+
impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
393+
invoice_builder_methods!(self, Self, Self, self);
380394
}
381395

382396
/// A semantically valid [`Bolt12Invoice`] that hasn't been signed.
@@ -412,32 +426,38 @@ impl UnsignedBolt12Invoice {
412426
pub fn tagged_hash(&self) -> &TaggedHash {
413427
&self.tagged_hash
414428
}
429+
}
415430

431+
macro_rules! unsigned_invoice_sign_method { ($self: ident, $self_type: ty) => {
416432
/// Signs the [`TaggedHash`] of the invoice using the given function.
417433
///
418434
/// Note: The hash computation may have included unknown, odd TLV records.
419435
///
420436
/// This is not exported to bindings users as functions aren't currently mapped.
421-
pub fn sign<F, E>(mut self, sign: F) -> Result<Bolt12Invoice, SignError<E>>
437+
pub fn sign<F, E>(mut $self: $self_type, sign: F) -> Result<Bolt12Invoice, SignError<E>>
422438
where
423439
F: FnOnce(&Self) -> Result<Signature, E>
424440
{
425-
let pubkey = self.contents.fields().signing_pubkey;
426-
let signature = merkle::sign_message(sign, &self, pubkey)?;
441+
let pubkey = $self.contents.fields().signing_pubkey;
442+
let signature = merkle::sign_message(sign, &$self, pubkey)?;
427443

428444
// Append the signature TLV record to the bytes.
429445
let signature_tlv_stream = SignatureTlvStreamRef {
430446
signature: Some(&signature),
431447
};
432-
signature_tlv_stream.write(&mut self.bytes).unwrap();
448+
signature_tlv_stream.write(&mut $self.bytes).unwrap();
433449

434450
Ok(Bolt12Invoice {
435-
bytes: self.bytes,
436-
contents: self.contents,
451+
bytes: $self.bytes,
452+
contents: $self.contents,
437453
signature,
438-
tagged_hash: self.tagged_hash,
454+
tagged_hash: $self.tagged_hash,
439455
})
440456
}
457+
} }
458+
459+
impl UnsignedBolt12Invoice {
460+
unsigned_invoice_sign_method!(self, Self);
441461
}
442462

443463
impl AsRef<TaggedHash> for UnsignedBolt12Invoice {

0 commit comments

Comments
 (0)