Skip to content

Commit c7b877e

Browse files
committed
Macro-ize InvoiceRequestBuilder
InvoiceRequestBuilder 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 702a003 commit c7b877e

File tree

2 files changed

+124
-92
lines changed

2 files changed

+124
-92
lines changed

lightning/src/offers/invoice_request.rs

Lines changed: 100 additions & 75 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ pub struct DerivedPayerId {}
117117
impl PayerIdStrategy for ExplicitPayerId {}
118118
impl PayerIdStrategy for DerivedPayerId {}
119119

120-
impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerId, T> {
120+
macro_rules! invoice_request_explicit_payer_id_builder_methods { ($self: ident, $self_type: ty) => {
121121
pub(super) fn new(offer: &'a Offer, metadata: Vec<u8>, payer_id: PublicKey) -> Self {
122122
Self {
123123
offer,
@@ -147,14 +147,14 @@ impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerI
147147

148148
/// Builds an unsigned [`InvoiceRequest`] after checking for valid semantics. It can be signed
149149
/// by [`UnsignedInvoiceRequest::sign`].
150-
pub fn build(self) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
151-
let (unsigned_invoice_request, keys, _) = self.build_with_checks()?;
150+
pub fn build($self: $self_type) -> Result<UnsignedInvoiceRequest, Bolt12SemanticError> {
151+
let (unsigned_invoice_request, keys, _) = $self.build_with_checks()?;
152152
debug_assert!(keys.is_none());
153153
Ok(unsigned_invoice_request)
154154
}
155-
}
155+
} }
156156

157-
impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T> {
157+
macro_rules! invoice_request_derived_payer_id_builder_methods { ($self: ident, $self_type: ty) => {
158158
pub(super) fn deriving_payer_id<ES: Deref>(
159159
offer: &'a Offer, expanded_key: &ExpandedKey, entropy_source: ES,
160160
secp_ctx: &'b Secp256k1<T>, payment_id: PaymentId
@@ -173,8 +173,8 @@ impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerId
173173
}
174174

175175
/// Builds a signed [`InvoiceRequest`] after checking for valid semantics.
176-
pub fn build_and_sign(self) -> Result<InvoiceRequest, Bolt12SemanticError> {
177-
let (unsigned_invoice_request, keys, secp_ctx) = self.build_with_checks()?;
176+
pub fn build_and_sign($self: $self_type) -> Result<InvoiceRequest, Bolt12SemanticError> {
177+
let (unsigned_invoice_request, keys, secp_ctx) = $self.build_with_checks()?;
178178
debug_assert!(keys.is_some());
179179

180180
let secp_ctx = secp_ctx.unwrap();
@@ -186,9 +186,11 @@ impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerId
186186
.unwrap();
187187
Ok(invoice_request)
188188
}
189-
}
189+
} }
190190

191-
impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, P, T> {
191+
macro_rules! invoice_request_builder_methods { (
192+
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
193+
) => {
192194
fn create_contents(offer: &Offer, metadata: Metadata) -> InvoiceRequestContentsWithoutPayerId {
193195
let offer = offer.contents.clone();
194196
InvoiceRequestContentsWithoutPayerId {
@@ -202,22 +204,22 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
202204
/// by the offer.
203205
///
204206
/// Successive calls to this method will override the previous setting.
205-
pub fn chain(self, network: Network) -> Result<Self, Bolt12SemanticError> {
206-
self.chain_hash(ChainHash::using_genesis_block(network))
207+
pub fn chain($self: $self_type, network: Network) -> Result<$return_type, Bolt12SemanticError> {
208+
$self.chain_hash(ChainHash::using_genesis_block(network))
207209
}
208210

209211
/// Sets the [`InvoiceRequest::chain`] for paying an invoice. If not called, the chain hash of
210212
/// [`Network::Bitcoin`] is assumed. Errors if the chain for `network` is not supported by the
211213
/// offer.
212214
///
213215
/// Successive calls to this method will override the previous setting.
214-
pub(crate) fn chain_hash(mut self, chain: ChainHash) -> Result<Self, Bolt12SemanticError> {
215-
if !self.offer.supports_chain(chain) {
216+
pub(crate) fn chain_hash(mut $self: $self_type, chain: ChainHash) -> Result<$return_type, Bolt12SemanticError> {
217+
if !$self.offer.supports_chain(chain) {
216218
return Err(Bolt12SemanticError::UnsupportedChain);
217219
}
218220

219-
self.invoice_request.chain = Some(chain);
220-
Ok(self)
221+
$self.invoice_request.chain = Some(chain);
222+
Ok($return_value)
221223
}
222224

223225
/// Sets the [`InvoiceRequest::amount_msats`] for paying an invoice. Errors if `amount_msats` is
@@ -226,130 +228,147 @@ impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a
226228
/// Successive calls to this method will override the previous setting.
227229
///
228230
/// [`quantity`]: Self::quantity
229-
pub fn amount_msats(mut self, amount_msats: u64) -> Result<Self, Bolt12SemanticError> {
230-
self.invoice_request.offer.check_amount_msats_for_quantity(
231-
Some(amount_msats), self.invoice_request.quantity
231+
pub fn amount_msats(mut $self: $self_type, amount_msats: u64) -> Result<$return_type, Bolt12SemanticError> {
232+
$self.invoice_request.offer.check_amount_msats_for_quantity(
233+
Some(amount_msats), $self.invoice_request.quantity
232234
)?;
233-
self.invoice_request.amount_msats = Some(amount_msats);
234-
Ok(self)
235+
$self.invoice_request.amount_msats = Some(amount_msats);
236+
Ok($return_value)
235237
}
236238

237239
/// Sets [`InvoiceRequest::quantity`] of items. If not set, `1` is assumed. Errors if `quantity`
238240
/// does not conform to [`Offer::is_valid_quantity`].
239241
///
240242
/// Successive calls to this method will override the previous setting.
241-
pub fn quantity(mut self, quantity: u64) -> Result<Self, Bolt12SemanticError> {
242-
self.invoice_request.offer.check_quantity(Some(quantity))?;
243-
self.invoice_request.quantity = Some(quantity);
244-
Ok(self)
243+
pub fn quantity(mut $self: $self_type, quantity: u64) -> Result<$return_type, Bolt12SemanticError> {
244+
$self.invoice_request.offer.check_quantity(Some(quantity))?;
245+
$self.invoice_request.quantity = Some(quantity);
246+
Ok($return_value)
245247
}
246248

247249
/// Sets the [`InvoiceRequest::payer_note`].
248250
///
249251
/// Successive calls to this method will override the previous setting.
250-
pub fn payer_note(mut self, payer_note: String) -> Self {
251-
self.invoice_request.payer_note = Some(payer_note);
252-
self
252+
pub fn payer_note(mut $self: $self_type, payer_note: String) -> $return_type {
253+
$self.invoice_request.payer_note = Some(payer_note);
254+
$return_value
253255
}
254256

255-
fn build_with_checks(mut self) -> Result<
257+
fn build_with_checks(mut $self: $self_type) -> Result<
256258
(UnsignedInvoiceRequest, Option<KeyPair>, Option<&'b Secp256k1<T>>),
257259
Bolt12SemanticError
258260
> {
259261
#[cfg(feature = "std")] {
260-
if self.offer.is_expired() {
262+
if $self.offer.is_expired() {
261263
return Err(Bolt12SemanticError::AlreadyExpired);
262264
}
263265
}
264266

265-
let chain = self.invoice_request.chain();
266-
if !self.offer.supports_chain(chain) {
267+
let chain = $self.invoice_request.chain();
268+
if !$self.offer.supports_chain(chain) {
267269
return Err(Bolt12SemanticError::UnsupportedChain);
268270
}
269271

270-
if chain == self.offer.implied_chain() {
271-
self.invoice_request.chain = None;
272+
if chain == $self.offer.implied_chain() {
273+
$self.invoice_request.chain = None;
272274
}
273275

274-
if self.offer.amount().is_none() && self.invoice_request.amount_msats.is_none() {
276+
if $self.offer.amount().is_none() && $self.invoice_request.amount_msats.is_none() {
275277
return Err(Bolt12SemanticError::MissingAmount);
276278
}
277279

278-
self.invoice_request.offer.check_quantity(self.invoice_request.quantity)?;
279-
self.invoice_request.offer.check_amount_msats_for_quantity(
280-
self.invoice_request.amount_msats, self.invoice_request.quantity
280+
$self.invoice_request.offer.check_quantity($self.invoice_request.quantity)?;
281+
$self.invoice_request.offer.check_amount_msats_for_quantity(
282+
$self.invoice_request.amount_msats, $self.invoice_request.quantity
281283
)?;
282284

283-
Ok(self.build_without_checks())
285+
Ok($self.build_without_checks())
284286
}
285287

286-
fn build_without_checks(mut self) ->
288+
fn build_without_checks(mut $self: $self_type) ->
287289
(UnsignedInvoiceRequest, Option<KeyPair>, Option<&'b Secp256k1<T>>)
288290
{
289291
// Create the metadata for stateless verification of a Bolt12Invoice.
290292
let mut keys = None;
291-
let secp_ctx = self.secp_ctx.clone();
292-
if self.invoice_request.payer.0.has_derivation_material() {
293-
let mut metadata = core::mem::take(&mut self.invoice_request.payer.0);
293+
let secp_ctx = $self.secp_ctx.clone();
294+
if $self.invoice_request.payer.0.has_derivation_material() {
295+
let mut metadata = core::mem::take(&mut $self.invoice_request.payer.0);
294296

295-
let mut tlv_stream = self.invoice_request.as_tlv_stream();
297+
let mut tlv_stream = $self.invoice_request.as_tlv_stream();
296298
debug_assert!(tlv_stream.2.payer_id.is_none());
297299
tlv_stream.0.metadata = None;
298300
if !metadata.derives_payer_keys() {
299-
tlv_stream.2.payer_id = self.payer_id.as_ref();
301+
tlv_stream.2.payer_id = $self.payer_id.as_ref();
300302
}
301303

302-
let (derived_metadata, derived_keys) = metadata.derive_from(tlv_stream, self.secp_ctx);
304+
let (derived_metadata, derived_keys) = metadata.derive_from(tlv_stream, $self.secp_ctx);
303305
metadata = derived_metadata;
304306
keys = derived_keys;
305307
if let Some(keys) = keys {
306-
debug_assert!(self.payer_id.is_none());
307-
self.payer_id = Some(keys.public_key());
308+
debug_assert!($self.payer_id.is_none());
309+
$self.payer_id = Some(keys.public_key());
308310
}
309311

310-
self.invoice_request.payer.0 = metadata;
312+
$self.invoice_request.payer.0 = metadata;
311313
}
312314

313-
debug_assert!(self.invoice_request.payer.0.as_bytes().is_some());
314-
debug_assert!(self.payer_id.is_some());
315-
let payer_id = self.payer_id.unwrap();
315+
debug_assert!($self.invoice_request.payer.0.as_bytes().is_some());
316+
debug_assert!($self.payer_id.is_some());
317+
let payer_id = $self.payer_id.unwrap();
316318

317319
let invoice_request = InvoiceRequestContents {
318-
inner: self.invoice_request,
320+
inner: $self.invoice_request,
319321
payer_id,
320322
};
321-
let unsigned_invoice_request = UnsignedInvoiceRequest::new(self.offer, invoice_request);
323+
let unsigned_invoice_request = UnsignedInvoiceRequest::new($self.offer, invoice_request);
322324

323325
(unsigned_invoice_request, keys, secp_ctx)
324326
}
325-
}
327+
} }
326328

327329
#[cfg(test)]
328-
impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, P, T> {
329-
fn chain_unchecked(mut self, network: Network) -> Self {
330+
macro_rules! invoice_request_builder_test_methods { (
331+
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
332+
) => {
333+
fn chain_unchecked(mut $self: $self_type, network: Network) -> $return_type {
330334
let chain = ChainHash::using_genesis_block(network);
331-
self.invoice_request.chain = Some(chain);
332-
self
335+
$self.invoice_request.chain = Some(chain);
336+
$return_value
333337
}
334338

335-
fn amount_msats_unchecked(mut self, amount_msats: u64) -> Self {
336-
self.invoice_request.amount_msats = Some(amount_msats);
337-
self
339+
fn amount_msats_unchecked(mut $self: $self_type, amount_msats: u64) -> $return_type {
340+
$self.invoice_request.amount_msats = Some(amount_msats);
341+
$return_value
338342
}
339343

340-
fn features_unchecked(mut self, features: InvoiceRequestFeatures) -> Self {
341-
self.invoice_request.features = features;
342-
self
344+
fn features_unchecked(mut $self: $self_type, features: InvoiceRequestFeatures) -> $return_type {
345+
$self.invoice_request.features = features;
346+
$return_value
343347
}
344348

345-
fn quantity_unchecked(mut self, quantity: u64) -> Self {
346-
self.invoice_request.quantity = Some(quantity);
347-
self
349+
fn quantity_unchecked(mut $self: $self_type, quantity: u64) -> $return_type {
350+
$self.invoice_request.quantity = Some(quantity);
351+
$return_value
348352
}
349353

350-
pub(super) fn build_unchecked(self) -> UnsignedInvoiceRequest {
351-
self.build_without_checks().0
354+
pub(super) fn build_unchecked($self: $self_type) -> UnsignedInvoiceRequest {
355+
$self.build_without_checks().0
352356
}
357+
} }
358+
359+
impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, ExplicitPayerId, T> {
360+
invoice_request_explicit_payer_id_builder_methods!(self, Self);
361+
}
362+
363+
impl<'a, 'b, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, DerivedPayerId, T> {
364+
invoice_request_derived_payer_id_builder_methods!(self, Self);
365+
}
366+
367+
impl<'a, 'b, P: PayerIdStrategy, T: secp256k1::Signing> InvoiceRequestBuilder<'a, 'b, P, T> {
368+
invoice_request_builder_methods!(self, Self, Self, self);
369+
370+
#[cfg(test)]
371+
invoice_request_builder_test_methods!(self, Self, Self, self);
353372
}
354373

355374
/// A semantically valid [`InvoiceRequest`] that hasn't been signed.
@@ -385,31 +404,37 @@ impl UnsignedInvoiceRequest {
385404
pub fn tagged_hash(&self) -> &TaggedHash {
386405
&self.tagged_hash
387406
}
407+
}
388408

409+
macro_rules! unsigned_invoice_request_sign_method { ($self: ident, $self_type: ty) => {
389410
/// Signs the [`TaggedHash`] of the invoice request using the given function.
390411
///
391412
/// Note: The hash computation may have included unknown, odd TLV records.
392413
///
393414
/// This is not exported to bindings users as functions are not yet mapped.
394-
pub fn sign<F, E>(mut self, sign: F) -> Result<InvoiceRequest, SignError<E>>
415+
pub fn sign<F, E>(mut $self: $self_type, sign: F) -> Result<InvoiceRequest, SignError<E>>
395416
where
396417
F: FnOnce(&Self) -> Result<Signature, E>
397418
{
398-
let pubkey = self.contents.payer_id;
399-
let signature = merkle::sign_message(sign, &self, pubkey)?;
419+
let pubkey = $self.contents.payer_id;
420+
let signature = merkle::sign_message(sign, &$self, pubkey)?;
400421

401422
// Append the signature TLV record to the bytes.
402423
let signature_tlv_stream = SignatureTlvStreamRef {
403424
signature: Some(&signature),
404425
};
405-
signature_tlv_stream.write(&mut self.bytes).unwrap();
426+
signature_tlv_stream.write(&mut $self.bytes).unwrap();
406427

407428
Ok(InvoiceRequest {
408-
bytes: self.bytes,
409-
contents: self.contents,
429+
bytes: $self.bytes,
430+
contents: $self.contents,
410431
signature,
411432
})
412433
}
434+
} }
435+
436+
impl UnsignedInvoiceRequest {
437+
unsigned_invoice_request_sign_method!(self, Self);
413438
}
414439

415440
impl AsRef<TaggedHash> for UnsignedInvoiceRequest {

0 commit comments

Comments
 (0)