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.
This commit is contained in:
Jeffrey Czyz 2024-02-25 14:58:07 -06:00
parent 3a92c7b08a
commit 07d628e0fa
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5
3 changed files with 130 additions and 111 deletions

View file

@ -169,7 +169,7 @@ pub struct DerivedSigningPubkey(KeyPair);
impl SigningPubkeyStrategy for ExplicitSigningPubkey {} impl SigningPubkeyStrategy for ExplicitSigningPubkey {}
impl SigningPubkeyStrategy for DerivedSigningPubkey {} impl SigningPubkeyStrategy for DerivedSigningPubkey {}
impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> { macro_rules! invoice_explicit_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
pub(super) fn for_offer( pub(super) fn for_offer(
invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
created_at: Duration, payment_hash: PaymentHash created_at: Duration, payment_hash: PaymentHash
@ -203,25 +203,25 @@ impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
/// Builds an unsigned [`Bolt12Invoice`] after checking for valid semantics. It can be signed by /// Builds an unsigned [`Bolt12Invoice`] after checking for valid semantics. It can be signed by
/// [`UnsignedBolt12Invoice::sign`]. /// [`UnsignedBolt12Invoice::sign`].
pub fn build(self) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> { pub fn build($self: $self_type) -> Result<UnsignedBolt12Invoice, Bolt12SemanticError> {
#[cfg(feature = "std")] { #[cfg(feature = "std")] {
if self.invoice.is_offer_or_refund_expired() { if $self.invoice.is_offer_or_refund_expired() {
return Err(Bolt12SemanticError::AlreadyExpired); return Err(Bolt12SemanticError::AlreadyExpired);
} }
} }
#[cfg(not(feature = "std"))] { #[cfg(not(feature = "std"))] {
if self.invoice.is_offer_or_refund_expired_no_std(self.invoice.created_at()) { if $self.invoice.is_offer_or_refund_expired_no_std($self.invoice.created_at()) {
return Err(Bolt12SemanticError::AlreadyExpired); return Err(Bolt12SemanticError::AlreadyExpired);
} }
} }
let InvoiceBuilder { invreq_bytes, invoice, .. } = self; let InvoiceBuilder { invreq_bytes, invoice, .. } = $self;
Ok(UnsignedBolt12Invoice::new(invreq_bytes, invoice)) Ok(UnsignedBolt12Invoice::new(invreq_bytes, invoice))
} }
} } }
impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> { macro_rules! invoice_derived_signing_pubkey_builder_methods { ($self: ident, $self_type: ty) => {
pub(super) fn for_offer_using_keys( pub(super) fn for_offer_using_keys(
invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
created_at: Duration, payment_hash: PaymentHash, keys: KeyPair created_at: Duration, payment_hash: PaymentHash, keys: KeyPair
@ -256,23 +256,23 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
/// Builds a signed [`Bolt12Invoice`] after checking for valid semantics. /// Builds a signed [`Bolt12Invoice`] after checking for valid semantics.
pub fn build_and_sign<T: secp256k1::Signing>( pub fn build_and_sign<T: secp256k1::Signing>(
self, secp_ctx: &Secp256k1<T> $self: $self_type, secp_ctx: &Secp256k1<T>
) -> Result<Bolt12Invoice, Bolt12SemanticError> { ) -> Result<Bolt12Invoice, Bolt12SemanticError> {
#[cfg(feature = "std")] { #[cfg(feature = "std")] {
if self.invoice.is_offer_or_refund_expired() { if $self.invoice.is_offer_or_refund_expired() {
return Err(Bolt12SemanticError::AlreadyExpired); return Err(Bolt12SemanticError::AlreadyExpired);
} }
} }
#[cfg(not(feature = "std"))] { #[cfg(not(feature = "std"))] {
if self.invoice.is_offer_or_refund_expired_no_std(self.invoice.created_at()) { if $self.invoice.is_offer_or_refund_expired_no_std($self.invoice.created_at()) {
return Err(Bolt12SemanticError::AlreadyExpired); return Err(Bolt12SemanticError::AlreadyExpired);
} }
} }
let InvoiceBuilder { let InvoiceBuilder {
invreq_bytes, invoice, signing_pubkey_strategy: DerivedSigningPubkey(keys) invreq_bytes, invoice, signing_pubkey_strategy: DerivedSigningPubkey(keys)
} = self; } = $self;
let unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice); let unsigned_invoice = UnsignedBolt12Invoice::new(invreq_bytes, invoice);
let invoice = unsigned_invoice let invoice = unsigned_invoice
@ -282,9 +282,11 @@ impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
.unwrap(); .unwrap();
Ok(invoice) Ok(invoice)
} }
} } }
impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> { macro_rules! invoice_builder_methods { (
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
) => {
pub(crate) fn amount_msats( pub(crate) fn amount_msats(
invoice_request: &InvoiceRequest invoice_request: &InvoiceRequest
) -> Result<u64, Bolt12SemanticError> { ) -> Result<u64, Bolt12SemanticError> {
@ -326,57 +328,69 @@ impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
/// [`Bolt12Invoice::is_expired`]. /// [`Bolt12Invoice::is_expired`].
/// ///
/// Successive calls to this method will override the previous setting. /// Successive calls to this method will override the previous setting.
pub fn relative_expiry(mut self, relative_expiry_secs: u32) -> Self { pub fn relative_expiry(mut $self: $self_type, relative_expiry_secs: u32) -> $return_type {
let relative_expiry = Duration::from_secs(relative_expiry_secs as u64); let relative_expiry = Duration::from_secs(relative_expiry_secs as u64);
self.invoice.fields_mut().relative_expiry = Some(relative_expiry); $self.invoice.fields_mut().relative_expiry = Some(relative_expiry);
self $return_value
} }
/// Adds a P2WSH address to [`Bolt12Invoice::fallbacks`]. /// Adds a P2WSH address to [`Bolt12Invoice::fallbacks`].
/// ///
/// Successive calls to this method will add another address. Caller is responsible for not /// Successive calls to this method will add another address. Caller is responsible for not
/// adding duplicate addresses and only calling if capable of receiving to P2WSH addresses. /// adding duplicate addresses and only calling if capable of receiving to P2WSH addresses.
pub fn fallback_v0_p2wsh(mut self, script_hash: &WScriptHash) -> Self { pub fn fallback_v0_p2wsh(mut $self: $self_type, script_hash: &WScriptHash) -> $return_type {
let address = FallbackAddress { let address = FallbackAddress {
version: WitnessVersion::V0.to_num(), version: WitnessVersion::V0.to_num(),
program: Vec::from(script_hash.to_byte_array()), program: Vec::from(script_hash.to_byte_array()),
}; };
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address); $self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
self $return_value
} }
/// Adds a P2WPKH address to [`Bolt12Invoice::fallbacks`]. /// Adds a P2WPKH address to [`Bolt12Invoice::fallbacks`].
/// ///
/// Successive calls to this method will add another address. Caller is responsible for not /// Successive calls to this method will add another address. Caller is responsible for not
/// adding duplicate addresses and only calling if capable of receiving to P2WPKH addresses. /// adding duplicate addresses and only calling if capable of receiving to P2WPKH addresses.
pub fn fallback_v0_p2wpkh(mut self, pubkey_hash: &WPubkeyHash) -> Self { pub fn fallback_v0_p2wpkh(mut $self: $self_type, pubkey_hash: &WPubkeyHash) -> $return_type {
let address = FallbackAddress { let address = FallbackAddress {
version: WitnessVersion::V0.to_num(), version: WitnessVersion::V0.to_num(),
program: Vec::from(pubkey_hash.to_byte_array()), program: Vec::from(pubkey_hash.to_byte_array()),
}; };
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address); $self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
self $return_value
} }
/// Adds a P2TR address to [`Bolt12Invoice::fallbacks`]. /// Adds a P2TR address to [`Bolt12Invoice::fallbacks`].
/// ///
/// Successive calls to this method will add another address. Caller is responsible for not /// Successive calls to this method will add another address. Caller is responsible for not
/// adding duplicate addresses and only calling if capable of receiving to P2TR addresses. /// adding duplicate addresses and only calling if capable of receiving to P2TR addresses.
pub fn fallback_v1_p2tr_tweaked(mut self, output_key: &TweakedPublicKey) -> Self { pub fn fallback_v1_p2tr_tweaked(mut $self: $self_type, output_key: &TweakedPublicKey) -> $return_type {
let address = FallbackAddress { let address = FallbackAddress {
version: WitnessVersion::V1.to_num(), version: WitnessVersion::V1.to_num(),
program: Vec::from(&output_key.serialize()[..]), program: Vec::from(&output_key.serialize()[..]),
}; };
self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address); $self.invoice.fields_mut().fallbacks.get_or_insert_with(Vec::new).push(address);
self $return_value
} }
/// Sets [`Bolt12Invoice::invoice_features`] to indicate MPP may be used. Otherwise, MPP is /// Sets [`Bolt12Invoice::invoice_features`] to indicate MPP may be used. Otherwise, MPP is
/// disallowed. /// disallowed.
pub fn allow_mpp(mut self) -> Self { pub fn allow_mpp(mut $self: $self_type) -> $return_type {
self.invoice.fields_mut().features.set_basic_mpp_optional(); $self.invoice.fields_mut().features.set_basic_mpp_optional();
self $return_value
} }
} }
impl<'a> InvoiceBuilder<'a, ExplicitSigningPubkey> {
invoice_explicit_signing_pubkey_builder_methods!(self, Self);
}
impl<'a> InvoiceBuilder<'a, DerivedSigningPubkey> {
invoice_derived_signing_pubkey_builder_methods!(self, Self);
}
impl<'a, S: SigningPubkeyStrategy> InvoiceBuilder<'a, S> {
invoice_builder_methods!(self, Self, Self, self);
} }
/// A semantically valid [`Bolt12Invoice`] that hasn't been signed. /// A semantically valid [`Bolt12Invoice`] that hasn't been signed.
@ -412,32 +426,38 @@ impl UnsignedBolt12Invoice {
pub fn tagged_hash(&self) -> &TaggedHash { pub fn tagged_hash(&self) -> &TaggedHash {
&self.tagged_hash &self.tagged_hash
} }
}
macro_rules! unsigned_invoice_sign_method { ($self: ident, $self_type: ty) => {
/// Signs the [`TaggedHash`] of the invoice using the given function. /// Signs the [`TaggedHash`] of the invoice using the given function.
/// ///
/// Note: The hash computation may have included unknown, odd TLV records. /// Note: The hash computation may have included unknown, odd TLV records.
/// ///
/// This is not exported to bindings users as functions aren't currently mapped. /// This is not exported to bindings users as functions aren't currently mapped.
pub fn sign<F, E>(mut self, sign: F) -> Result<Bolt12Invoice, SignError<E>> pub fn sign<F, E>(mut $self: $self_type, sign: F) -> Result<Bolt12Invoice, SignError<E>>
where where
F: FnOnce(&Self) -> Result<Signature, E> F: FnOnce(&Self) -> Result<Signature, E>
{ {
let pubkey = self.contents.fields().signing_pubkey; let pubkey = $self.contents.fields().signing_pubkey;
let signature = merkle::sign_message(sign, &self, pubkey)?; let signature = merkle::sign_message(sign, &$self, pubkey)?;
// Append the signature TLV record to the bytes. // Append the signature TLV record to the bytes.
let signature_tlv_stream = SignatureTlvStreamRef { let signature_tlv_stream = SignatureTlvStreamRef {
signature: Some(&signature), signature: Some(&signature),
}; };
signature_tlv_stream.write(&mut self.bytes).unwrap(); signature_tlv_stream.write(&mut $self.bytes).unwrap();
Ok(Bolt12Invoice { Ok(Bolt12Invoice {
bytes: self.bytes, bytes: $self.bytes,
contents: self.contents, contents: $self.contents,
signature, signature,
tagged_hash: self.tagged_hash, tagged_hash: $self.tagged_hash,
}) })
} }
} }
impl UnsignedBolt12Invoice {
unsigned_invoice_sign_method!(self, Self);
} }
impl AsRef<TaggedHash> for UnsignedBolt12Invoice { impl AsRef<TaggedHash> for UnsignedBolt12Invoice {

View file

@ -662,17 +662,9 @@ impl UnsignedInvoiceRequest {
invoice_request_accessors!(self, self.contents); invoice_request_accessors!(self, self.contents);
} }
impl InvoiceRequest { macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { (
offer_accessors!(self, self.contents.inner.offer); $self: ident, $contents: expr, $builder: ty
invoice_request_accessors!(self, self.contents); ) => {
/// Signature of the invoice request using [`payer_id`].
///
/// [`payer_id`]: Self::payer_id
pub fn signature(&self) -> Signature {
self.signature
}
/// Creates an [`InvoiceBuilder`] for the request with the given required fields and using the /// Creates an [`InvoiceBuilder`] for the request with the given required fields and using the
/// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time. /// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time.
/// ///
@ -684,13 +676,13 @@ impl InvoiceRequest {
/// [`Duration`]: core::time::Duration /// [`Duration`]: core::time::Duration
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn respond_with( pub fn respond_with(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
let created_at = std::time::SystemTime::now() let created_at = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH) .duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"); .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
self.respond_with_no_std(payment_paths, payment_hash, created_at) $contents.respond_with_no_std(payment_paths, payment_hash, created_at)
} }
/// Creates an [`InvoiceBuilder`] for the request with the given required fields. /// Creates an [`InvoiceBuilder`] for the request with the given required fields.
@ -719,31 +711,48 @@ impl InvoiceRequest {
/// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
/// [`OfferBuilder::deriving_signing_pubkey`]: crate::offers::offer::OfferBuilder::deriving_signing_pubkey /// [`OfferBuilder::deriving_signing_pubkey`]: crate::offers::offer::OfferBuilder::deriving_signing_pubkey
pub fn respond_with_no_std( pub fn respond_with_no_std(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration created_at: core::time::Duration
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
if self.invoice_request_features().requires_unknown_bits() { if $contents.invoice_request_features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures); return Err(Bolt12SemanticError::UnknownRequiredFeatures);
} }
InvoiceBuilder::for_offer(self, payment_paths, created_at, payment_hash) <$builder>::for_offer(&$contents, payment_paths, created_at, payment_hash)
} }
} }
macro_rules! invoice_request_verify_method { ($self: ident, $self_type: ty) => {
/// Verifies that the request was for an offer created using the given key. Returns the verified /// Verifies that the request was for an offer created using the given key. Returns the verified
/// request which contains the derived keys needed to sign a [`Bolt12Invoice`] for the request /// request which contains the derived keys needed to sign a [`Bolt12Invoice`] for the request
/// if they could be extracted from the metadata. /// if they could be extracted from the metadata.
/// ///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn verify<T: secp256k1::Signing>( pub fn verify<T: secp256k1::Signing>(
self, key: &ExpandedKey, secp_ctx: &Secp256k1<T> $self: $self_type, key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<VerifiedInvoiceRequest, ()> { ) -> Result<VerifiedInvoiceRequest, ()> {
let keys = self.contents.inner.offer.verify(&self.bytes, key, secp_ctx)?; let keys = $self.contents.inner.offer.verify(&$self.bytes, key, secp_ctx)?;
Ok(VerifiedInvoiceRequest { Ok(VerifiedInvoiceRequest {
inner: self, inner: $self,
keys, keys,
}) })
} }
} }
impl InvoiceRequest {
offer_accessors!(self, self.contents.inner.offer);
invoice_request_accessors!(self, self.contents);
invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self, InvoiceBuilder<ExplicitSigningPubkey>);
invoice_request_verify_method!(self, Self);
/// Signature of the invoice request using [`payer_id`].
///
/// [`payer_id`]: Self::payer_id
pub fn signature(&self) -> Signature {
self.signature
}
pub(crate) fn as_tlv_stream(&self) -> FullInvoiceRequestTlvStreamRef { pub(crate) fn as_tlv_stream(&self) -> FullInvoiceRequestTlvStreamRef {
let (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) = let (payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream) =
self.contents.as_tlv_stream(); self.contents.as_tlv_stream();
@ -754,37 +763,9 @@ impl InvoiceRequest {
} }
} }
impl VerifiedInvoiceRequest { macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { (
offer_accessors!(self, self.inner.contents.inner.offer); $self: ident, $contents: expr, $builder: ty
invoice_request_accessors!(self, self.inner.contents); ) => {
/// Creates an [`InvoiceBuilder`] for the request with the given required fields and using the
/// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time.
///
/// See [`InvoiceRequest::respond_with_no_std`] for further details.
///
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
///
/// [`Duration`]: core::time::Duration
#[cfg(feature = "std")]
pub fn respond_with(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
self.inner.respond_with(payment_paths, payment_hash)
}
/// Creates an [`InvoiceBuilder`] for the request with the given required fields.
///
/// See [`InvoiceRequest::respond_with_no_std`] for further details.
///
/// This is not exported to bindings users as builder patterns don't map outside of move semantics.
pub fn respond_with_no_std(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
self.inner.respond_with_no_std(payment_paths, payment_hash, created_at)
}
/// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
/// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use /// derived signing keys from the originating [`Offer`] to sign the [`Bolt12Invoice`]. Must use
/// the same [`ExpandedKey`] as the one used to create the offer. /// the same [`ExpandedKey`] as the one used to create the offer.
@ -796,13 +777,13 @@ impl VerifiedInvoiceRequest {
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn respond_using_derived_keys( pub fn respond_using_derived_keys(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash
) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
let created_at = std::time::SystemTime::now() let created_at = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH) .duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"); .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
self.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at) $self.respond_using_derived_keys_no_std(payment_paths, payment_hash, created_at)
} }
/// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses /// Creates an [`InvoiceBuilder`] for the request using the given required fields and that uses
@ -815,22 +796,29 @@ impl VerifiedInvoiceRequest {
/// ///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn respond_using_derived_keys_no_std( pub fn respond_using_derived_keys_no_std(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration created_at: core::time::Duration
) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
if self.inner.invoice_request_features().requires_unknown_bits() { if $self.inner.invoice_request_features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures); return Err(Bolt12SemanticError::UnknownRequiredFeatures);
} }
let keys = match self.keys { let keys = match $self.keys {
None => return Err(Bolt12SemanticError::InvalidMetadata), None => return Err(Bolt12SemanticError::InvalidMetadata),
Some(keys) => keys, Some(keys) => keys,
}; };
InvoiceBuilder::for_offer_using_keys( <$builder>::for_offer_using_keys(
&self.inner, payment_paths, created_at, payment_hash, keys &$self.inner, payment_paths, created_at, payment_hash, keys
) )
} }
} }
impl VerifiedInvoiceRequest {
offer_accessors!(self, self.inner.contents.inner.offer);
invoice_request_accessors!(self, self.inner.contents);
invoice_request_respond_with_explicit_signing_pubkey_methods!(self, self.inner, InvoiceBuilder<ExplicitSigningPubkey>);
invoice_request_respond_with_derived_signing_pubkey_methods!(self, self.inner, InvoiceBuilder<DerivedSigningPubkey>);
} }
impl InvoiceRequestContents { impl InvoiceRequestContents {

View file

@ -480,7 +480,9 @@ impl Refund {
pub fn payer_note(&self) -> Option<PrintableString> { pub fn payer_note(&self) -> Option<PrintableString> {
self.contents.payer_note() self.contents.payer_note()
} }
}
macro_rules! respond_with_explicit_signing_pubkey_methods { ($self: ident, $builder: ty) => {
/// Creates an [`InvoiceBuilder`] for the refund with the given required fields and using the /// Creates an [`InvoiceBuilder`] for the refund with the given required fields and using the
/// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time. /// [`Duration`] since [`std::time::SystemTime::UNIX_EPOCH`] as the creation time.
/// ///
@ -492,14 +494,14 @@ impl Refund {
/// [`Duration`]: core::time::Duration /// [`Duration`]: core::time::Duration
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn respond_with( pub fn respond_with(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
signing_pubkey: PublicKey, signing_pubkey: PublicKey,
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
let created_at = std::time::SystemTime::now() let created_at = std::time::SystemTime::now()
.duration_since(std::time::SystemTime::UNIX_EPOCH) .duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"); .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
self.respond_with_no_std(payment_paths, payment_hash, signing_pubkey, created_at) $self.respond_with_no_std(payment_paths, payment_hash, signing_pubkey, created_at)
} }
/// Creates an [`InvoiceBuilder`] for the refund with the given required fields. /// Creates an [`InvoiceBuilder`] for the refund with the given required fields.
@ -525,16 +527,18 @@ impl Refund {
/// ///
/// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at /// [`Bolt12Invoice::created_at`]: crate::offers::invoice::Bolt12Invoice::created_at
pub fn respond_with_no_std( pub fn respond_with_no_std(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
signing_pubkey: PublicKey, created_at: Duration signing_pubkey: PublicKey, created_at: Duration
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> { ) -> Result<$builder, Bolt12SemanticError> {
if self.features().requires_unknown_bits() { if $self.features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures); return Err(Bolt12SemanticError::UnknownRequiredFeatures);
} }
InvoiceBuilder::for_refund(self, payment_paths, created_at, payment_hash, signing_pubkey) <$builder>::for_refund($self, payment_paths, created_at, payment_hash, signing_pubkey)
} }
} }
macro_rules! respond_with_derived_signing_pubkey_methods { ($self: ident, $builder: ty) => {
/// Creates an [`InvoiceBuilder`] for the refund using the given required fields and that uses /// Creates an [`InvoiceBuilder`] for the refund using the given required fields and that uses
/// derived signing keys to sign the [`Bolt12Invoice`]. /// derived signing keys to sign the [`Bolt12Invoice`].
/// ///
@ -545,9 +549,9 @@ impl Refund {
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn respond_using_derived_keys<ES: Deref>( pub fn respond_using_derived_keys<ES: Deref>(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
expanded_key: &ExpandedKey, entropy_source: ES expanded_key: &ExpandedKey, entropy_source: ES
) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> ) -> Result<$builder, Bolt12SemanticError>
where where
ES::Target: EntropySource, ES::Target: EntropySource,
{ {
@ -555,7 +559,7 @@ impl Refund {
.duration_since(std::time::SystemTime::UNIX_EPOCH) .duration_since(std::time::SystemTime::UNIX_EPOCH)
.expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH"); .expect("SystemTime::now() should come after SystemTime::UNIX_EPOCH");
self.respond_using_derived_keys_no_std( $self.respond_using_derived_keys_no_std(
payment_paths, payment_hash, created_at, expanded_key, entropy_source payment_paths, payment_hash, created_at, expanded_key, entropy_source
) )
} }
@ -569,22 +573,29 @@ impl Refund {
/// ///
/// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice /// [`Bolt12Invoice`]: crate::offers::invoice::Bolt12Invoice
pub fn respond_using_derived_keys_no_std<ES: Deref>( pub fn respond_using_derived_keys_no_std<ES: Deref>(
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash, &$self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration, expanded_key: &ExpandedKey, entropy_source: ES created_at: core::time::Duration, expanded_key: &ExpandedKey, entropy_source: ES
) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> ) -> Result<$builder, Bolt12SemanticError>
where where
ES::Target: EntropySource, ES::Target: EntropySource,
{ {
if self.features().requires_unknown_bits() { if $self.features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures); return Err(Bolt12SemanticError::UnknownRequiredFeatures);
} }
let nonce = Nonce::from_entropy_source(entropy_source); let nonce = Nonce::from_entropy_source(entropy_source);
let keys = signer::derive_keys(nonce, expanded_key); let keys = signer::derive_keys(nonce, expanded_key);
InvoiceBuilder::for_refund_using_keys(self, payment_paths, created_at, payment_hash, keys) <$builder>::for_refund_using_keys($self, payment_paths, created_at, payment_hash, keys)
} }
} }
#[cfg(test)] impl Refund {
respond_with_explicit_signing_pubkey_methods!(self, InvoiceBuilder<ExplicitSigningPubkey>);
respond_with_derived_signing_pubkey_methods!(self, InvoiceBuilder<DerivedSigningPubkey>);
}
#[cfg(test)]
impl Refund {
fn as_tlv_stream(&self) -> RefundTlvStreamRef { fn as_tlv_stream(&self) -> RefundTlvStreamRef {
self.contents.as_tlv_stream() self.contents.as_tlv_stream()
} }