Self { bytes, contents, tagged_hash }
}
+ /// Returns the [`TaggedHash`] of the invoice to sign.
+ pub fn tagged_hash(&self) -> &TaggedHash {
+ &self.tagged_hash
+ }
+
/// Signs the [`TaggedHash`] of the invoice request using the given function.
///
/// Note: The hash computation may have included unknown, odd TLV records.
payer_note: Option<String>,
}
-impl InvoiceRequest {
+macro_rules! invoice_request_accessors { ($self: ident, $contents: expr) => {
/// An unpredictable series of bytes, typically containing information about the derivation of
/// [`payer_id`].
///
/// [`payer_id`]: Self::payer_id
- pub fn metadata(&self) -> &[u8] {
- self.contents.metadata()
+ pub fn payer_metadata(&$self) -> &[u8] {
+ $contents.metadata()
}
/// A chain from [`Offer::chains`] that the offer is valid for.
- pub fn chain(&self) -> ChainHash {
- self.contents.chain()
+ pub fn chain(&$self) -> ChainHash {
+ $contents.chain()
}
/// The amount to pay in msats (i.e., the minimum lightning-payable unit for [`chain`]), which
/// must be greater than or equal to [`Offer::amount`], converted if necessary.
///
/// [`chain`]: Self::chain
- pub fn amount_msats(&self) -> Option<u64> {
- self.contents.amount_msats()
+ pub fn amount_msats(&$self) -> Option<u64> {
+ $contents.amount_msats()
}
/// Features pertaining to requesting an invoice.
- pub fn features(&self) -> &InvoiceRequestFeatures {
- &self.contents.features()
+ pub fn invoice_request_features(&$self) -> &InvoiceRequestFeatures {
+ &$contents.features()
}
/// The quantity of the offer's item conforming to [`Offer::is_valid_quantity`].
- pub fn quantity(&self) -> Option<u64> {
- self.contents.quantity()
+ pub fn quantity(&$self) -> Option<u64> {
+ $contents.quantity()
}
/// A possibly transient pubkey used to sign the invoice request.
- pub fn payer_id(&self) -> PublicKey {
- self.contents.payer_id()
+ pub fn payer_id(&$self) -> PublicKey {
+ $contents.payer_id()
}
/// A payer-provided note which will be seen by the recipient and reflected back in the invoice
/// response.
- pub fn payer_note(&self) -> Option<PrintableString> {
- self.contents.payer_note()
+ pub fn payer_note(&$self) -> Option<PrintableString> {
+ $contents.payer_note()
}
+} }
+
+impl UnsignedInvoiceRequest {
+ offer_accessors!(self, self.contents.inner.offer);
+ invoice_request_accessors!(self, self.contents);
+}
+
+impl InvoiceRequest {
+ offer_accessors!(self, self.contents.inner.offer);
+ invoice_request_accessors!(self, self.contents);
/// Signature of the invoice request using [`payer_id`].
///
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration
) -> Result<InvoiceBuilder<ExplicitSigningPubkey>, Bolt12SemanticError> {
- if self.features().requires_unknown_bits() {
+ if self.invoice_request_features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
&self, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>, payment_hash: PaymentHash,
created_at: core::time::Duration, expanded_key: &ExpandedKey, secp_ctx: &Secp256k1<T>
) -> Result<InvoiceBuilder<DerivedSigningPubkey>, Bolt12SemanticError> {
- if self.features().requires_unknown_bits() {
+ if self.invoice_request_features().requires_unknown_bits() {
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
self.inner.chain()
}
- fn amount_msats(&self) -> Option<u64> {
+ pub(super) fn amount_msats(&self) -> Option<u64> {
self.inner.amount_msats
}
- fn features(&self) -> &InvoiceRequestFeatures {
+ pub(super) fn features(&self) -> &InvoiceRequestFeatures {
&self.inner.features
}
- fn quantity(&self) -> Option<u64> {
+ pub(super) fn quantity(&self) -> Option<u64> {
self.inner.quantity
}
self.payer_id
}
- fn payer_note(&self) -> Option<PrintableString> {
+ pub(super) fn payer_note(&self) -> Option<PrintableString> {
self.inner.payer_note.as_ref()
.map(|payer_note| PrintableString(payer_note.as_str()))
}
None => return Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSignature)),
Some(signature) => signature,
};
- merkle::verify_signature(&signature, SIGNATURE_TAG, &bytes, contents.payer_id)?;
+ let message = TaggedHash::new(SIGNATURE_TAG, &bytes);
+ merkle::verify_signature(&signature, message, contents.payer_id)?;
Ok(InvoiceRequest { bytes, contents, signature })
}
#[cfg(feature = "std")]
use core::time::Duration;
use crate::sign::KeyMaterial;
- use crate::ln::features::InvoiceRequestFeatures;
+ use crate::ln::features::{InvoiceRequestFeatures, OfferFeatures};
use crate::ln::inbound_payment::ExpandedKey;
use crate::ln::msgs::{DecodeError, MAX_VALUE_MSAT};
use crate::offers::invoice::{Bolt12Invoice, SIGNATURE_TAG as INVOICE_SIGNATURE_TAG};
let mut buffer = Vec::new();
unsigned_invoice_request.write(&mut buffer).unwrap();
+ assert_eq!(unsigned_invoice_request.bytes, buffer.as_slice());
+ assert_eq!(unsigned_invoice_request.payer_metadata(), &[1; 32]);
+ assert_eq!(unsigned_invoice_request.chains(), vec![ChainHash::using_genesis_block(Network::Bitcoin)]);
+ assert_eq!(unsigned_invoice_request.metadata(), None);
+ assert_eq!(unsigned_invoice_request.amount(), Some(&Amount::Bitcoin { amount_msats: 1000 }));
+ assert_eq!(unsigned_invoice_request.description(), PrintableString("foo"));
+ assert_eq!(unsigned_invoice_request.offer_features(), &OfferFeatures::empty());
+ assert_eq!(unsigned_invoice_request.absolute_expiry(), None);
+ assert_eq!(unsigned_invoice_request.paths(), &[]);
+ assert_eq!(unsigned_invoice_request.issuer(), None);
+ assert_eq!(unsigned_invoice_request.supported_quantity(), Quantity::One);
+ assert_eq!(unsigned_invoice_request.signing_pubkey(), recipient_pubkey());
+ assert_eq!(unsigned_invoice_request.chain(), ChainHash::using_genesis_block(Network::Bitcoin));
+ assert_eq!(unsigned_invoice_request.amount_msats(), None);
+ assert_eq!(unsigned_invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
+ assert_eq!(unsigned_invoice_request.quantity(), None);
+ assert_eq!(unsigned_invoice_request.payer_id(), payer_pubkey());
+ assert_eq!(unsigned_invoice_request.payer_note(), None);
+
match UnsignedInvoiceRequest::try_from(buffer) {
Err(e) => panic!("error parsing unsigned invoice request: {:?}", e),
Ok(parsed) => {
invoice_request.write(&mut buffer).unwrap();
assert_eq!(invoice_request.bytes, buffer.as_slice());
- assert_eq!(invoice_request.metadata(), &[1; 32]);
+ assert_eq!(invoice_request.payer_metadata(), &[1; 32]);
+ assert_eq!(invoice_request.chains(), vec![ChainHash::using_genesis_block(Network::Bitcoin)]);
+ assert_eq!(invoice_request.metadata(), None);
+ assert_eq!(invoice_request.amount(), Some(&Amount::Bitcoin { amount_msats: 1000 }));
+ assert_eq!(invoice_request.description(), PrintableString("foo"));
+ assert_eq!(invoice_request.offer_features(), &OfferFeatures::empty());
+ assert_eq!(invoice_request.absolute_expiry(), None);
+ assert_eq!(invoice_request.paths(), &[]);
+ assert_eq!(invoice_request.issuer(), None);
+ assert_eq!(invoice_request.supported_quantity(), Quantity::One);
+ assert_eq!(invoice_request.signing_pubkey(), recipient_pubkey());
assert_eq!(invoice_request.chain(), ChainHash::using_genesis_block(Network::Bitcoin));
assert_eq!(invoice_request.amount_msats(), None);
- assert_eq!(invoice_request.features(), &InvoiceRequestFeatures::empty());
+ assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
assert_eq!(invoice_request.quantity(), None);
assert_eq!(invoice_request.payer_id(), payer_pubkey());
assert_eq!(invoice_request.payer_note(), None);
- assert!(
- merkle::verify_signature(
- &invoice_request.signature, SIGNATURE_TAG, &invoice_request.bytes, payer_pubkey()
- ).is_ok()
- );
+
+ let message = TaggedHash::new(SIGNATURE_TAG, &invoice_request.bytes);
+ assert!(merkle::verify_signature(&invoice_request.signature, message, payer_pubkey()).is_ok());
assert_eq!(
invoice_request.as_tlv_stream(),
.build().unwrap()
.sign(payer_sign).unwrap();
let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
- assert_eq!(invoice_request.features(), &InvoiceRequestFeatures::unknown());
+ assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::unknown());
assert_eq!(tlv_stream.features, Some(&InvoiceRequestFeatures::unknown()));
let invoice_request = OfferBuilder::new("foo".into(), recipient_pubkey())
.build().unwrap()
.sign(payer_sign).unwrap();
let (_, _, tlv_stream, _) = invoice_request.as_tlv_stream();
- assert_eq!(invoice_request.features(), &InvoiceRequestFeatures::empty());
+ assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
assert_eq!(tlv_stream.features, None);
}