Skip to content

Commit 5d7cfa4

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 a68b83e commit 5d7cfa4

File tree

3 files changed

+132
-111
lines changed

3 files changed

+132
-111
lines changed

lightning/src/offers/invoice.rs

Lines changed: 57 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,27 @@ 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 { (
225+
$self: ident, $self_type: ty, $secp_context: ty
226+
) => {
225227
pub(super) fn for_offer_using_keys(
226228
invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
227229
created_at: Duration, payment_hash: PaymentHash, keys: KeyPair
@@ -256,23 +258,23 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
256258

257259
/// Builds a signed [`Bolt12Invoice`] after checking for valid semantics.
258260
pub fn build_and_sign<T: secp256k1::Signing>(
259-
self, secp_ctx: &Secp256k1<T>
261+
$self: $self_type, secp_ctx: &Secp256k1<$secp_context>
260262
) -> Result<Bolt12Invoice, Bolt12SemanticError> {
261263
#[cfg(feature = "std")] {
262-
if self.invoice.is_offer_or_refund_expired() {
264+
if $self.invoice.is_offer_or_refund_expired() {
263265
return Err(Bolt12SemanticError::AlreadyExpired);
264266
}
265267
}
266268

267269
#[cfg(not(feature = "std"))] {
268-
if self.invoice.is_offer_or_refund_expired_no_std(self.invoice.created_at()) {
270+
if $self.invoice.is_offer_or_refund_expired_no_std($self.invoice.created_at()) {
269271
return Err(Bolt12SemanticError::AlreadyExpired);
270272
}
271273
}
272274

273275
let InvoiceBuilder {
274276
invreq_bytes, invoice, signing_pubkey_strategy: DerivedSigningPubkey(keys)
275-
} = self;
277+
} = $self;
276278
let unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice);
277279

278280
let invoice = unsigned_invoice
@@ -282,9 +284,11 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
282284
.unwrap();
283285
Ok(invoice)
284286
}
285-
}
287+
} }
286288

287-
impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
289+
macro_rules! invoice_builder_methods { (
290+
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
291+
) => {
288292
pub(crate) fn amount_msats(
289293
invoice_request: &InvoiceRequest
290294
) -> Result<u64, Bolt12SemanticError> {
@@ -326,57 +330,69 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
326330
/// [`Bolt12Invoice::is_expired`].
327331
///
328332
/// Successive calls to this method will override the previous setting.
329-
pub fn relative_expiry(mut self, relative_expiry_secs: u32) -> Self {
333+
pub fn relative_expiry(mut $self: $self_type, relative_expiry_secs: u32) -> $return_type {
330334
let relative_expiry = Duration::from_secs(relative_expiry_secs as u64);
331-
self.invoice.fields_mut().relative_expiry = Some(relative_expiry);
332-
self
335+
$self.invoice.fields_mut().relative_expiry = Some(relative_expiry);
336+
$return_value
333337
}
334338

335339
/// Adds a P2WSH address to [`Bolt12Invoice::fallbacks`].
336340
///
337341
/// Successive calls to this method will add another address. Caller is responsible for not
338342
/// 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 {
343+
pub fn fallback_v0_p2wsh(mut $self: $self_type, script_hash: &WScriptHash) -> $return_type {
340344
let address = FallbackAddress {
341345
version: WitnessVersion::V0.to_num(),
342346
program: Vec::from(script_hash.to_byte_array()),
343347
};
344-
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
345-
self
348+
$self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
349+
$return_value
346350
}
347351

348352
/// Adds a P2WPKH address to [`Bolt12Invoice::fallbacks`].
349353
///
350354
/// Successive calls to this method will add another address. Caller is responsible for not
351355
/// 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 {
356+
pub fn fallback_v0_p2wpkh(mut $self: $self_type, pubkey_hash: &WPubkeyHash) -> $return_type {
353357
let address = FallbackAddress {
354358
version: WitnessVersion::V0.to_num(),
355359
program: Vec::from(pubkey_hash.to_byte_array()),
356360
};
357-
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
358-
self
361+
$self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
362+
$return_value
359363
}
360364

361365
/// Adds a P2TR address to [`Bolt12Invoice::fallbacks`].
362366
///
363367
/// Successive calls to this method will add another address. Caller is responsible for not
364368
/// 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 {
369+
pub fn fallback_v1_p2tr_tweaked(mut $self: $self_type, output_key: &TweakedPublicKey) -> $return_type {
366370
let address = FallbackAddress {
367371
version: WitnessVersion::V1.to_num(),
368372
program: Vec::from(&output_key.serialize()[..]),
369373
};
370-
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
371-
self
374+
$self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
375+
$return_value
372376
}
373377

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

382398
/// A semantically valid [`Bolt12Invoice`] that hasn't been signed.
@@ -412,32 +428,38 @@ impl UnsignedBolt12Invoice {
412428
pub fn tagged_hash(&self) -> &TaggedHash {
413429
&self.tagged_hash
414430
}
431+
}
415432

433+
macro_rules! unsigned_invoice_sign_method { ($self: ident, $self_type: ty) => {
416434
/// Signs the [`TaggedHash`] of the invoice using the given function.
417435
///
418436
/// Note: The hash computation may have included unknown, odd TLV records.
419437
///
420438
/// 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>>
439+
pub fn sign<F, E>(mut $self: $self_type, sign: F) -> Result<Bolt12Invoice, SignError<E>>
422440
where
423441
F: FnOnce(&Self) -> Result<Signature, E>
424442
{
425-
let pubkey = self.contents.fields().signing_pubkey;
426-
let signature = merkle::sign_message(sign, &self, pubkey)?;
443+
let pubkey = $self.contents.fields().signing_pubkey;
444+
let signature = merkle::sign_message(sign, &$self, pubkey)?;
427445

428446
// Append the signature TLV record to the bytes.
429447
let signature_tlv_stream = SignatureTlvStreamRef {
430448
signature: Some(&signature),
431449
};
432-
signature_tlv_stream.write(&mut self.bytes).unwrap();
450+
signature_tlv_stream.write(&mut $self.bytes).unwrap();
433451

434452
Ok(Bolt12Invoice {
435-
bytes: self.bytes,
436-
contents: self.contents,
453+
bytes: $self.bytes,
454+
contents: $self.contents,
437455
signature,
438-
tagged_hash: self.tagged_hash,
456+
tagged_hash: $self.tagged_hash,
439457
})
440458
}
459+
} }
460+
461+
impl UnsignedBolt12Invoice {
462+
unsigned_invoice_sign_method!(self, Self);
441463
}
442464

443465
impl AsRef<TaggedHash> for UnsignedBolt12Invoice {

0 commit comments

Comments
 (0)