.map_err(|_| Bolt12SemanticError::DuplicatePaymentId)?;
let mut pending_offers_messages = self.pending_offers_messages.lock().unwrap();
- if offer.paths().is_empty() {
- let message = new_pending_onion_message(
- OffersMessage::InvoiceRequest(invoice_request),
- Destination::Node(offer.signing_pubkey()),
- Some(reply_path),
- );
- pending_offers_messages.push(message);
- } else {
+ if !offer.paths().is_empty() {
// Send as many invoice requests as there are paths in the offer (with an upper bound).
// Using only one path could result in a failure if the path no longer exists. But only
// one invoice for a given payment id will be paid, even if more than one is received.
);
pending_offers_messages.push(message);
}
+ } else if let Some(signing_pubkey) = offer.signing_pubkey() {
+ let message = new_pending_onion_message(
+ OffersMessage::InvoiceRequest(invoice_request),
+ Destination::Node(signing_pubkey),
+ Some(reply_path),
+ );
+ pending_offers_messages.push(message);
+ } else {
+ debug_assert!(false);
+ return Err(Bolt12SemanticError::MissingSigningPubkey);
}
Ok(())
.create_offer_builder("coffee".to_string()).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
- assert_ne!(offer.signing_pubkey(), bob_id);
+ assert_ne!(offer.signing_pubkey(), Some(bob_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_ne!(path.introduction_node, IntroductionNode::NodeId(bob_id));
.create_offer_builder("coffee".to_string()).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
- assert_ne!(offer.signing_pubkey(), bob_id);
+ assert_ne!(offer.signing_pubkey(), Some(bob_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
.create_offer_builder("coffee".to_string()).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
- assert_ne!(offer.signing_pubkey(), bob_id);
+ assert_ne!(offer.signing_pubkey(), Some(bob_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node, IntroductionNode::NodeId(nodes[4].node.get_our_node_id()));
.unwrap()
.amount_msats(10_000_000)
.build().unwrap();
- assert_ne!(offer.signing_pubkey(), alice_id);
+ assert_ne!(offer.signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node, IntroductionNode::NodeId(bob_id));
.create_offer_builder("coffee".to_string()).unwrap()
.amount_msats(10_000_000)
.build().unwrap();
- assert_ne!(offer.signing_pubkey(), alice_id);
+ assert_ne!(offer.signing_pubkey(), Some(alice_id));
assert!(!offer.paths().is_empty());
for path in offer.paths() {
assert_eq!(path.introduction_node, IntroductionNode::NodeId(alice_id));
.clear_paths()
.amount_msats(10_000_000)
.build().unwrap();
- assert_eq!(offer.signing_pubkey(), alice_id);
+ assert_eq!(offer.signing_pubkey(), Some(alice_id));
assert!(offer.paths().is_empty());
let payment_id = PaymentId([1; 32]);
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn for_offer(
invoice_request: &'a InvoiceRequest, payment_paths: Vec<(BlindedPayInfo, BlindedPath)>,
- created_at: Duration, payment_hash: PaymentHash
+ created_at: Duration, payment_hash: PaymentHash, signing_pubkey: PublicKey
) -> Result<Self, Bolt12SemanticError> {
let amount_msats = Self::amount_msats(invoice_request)?;
- let signing_pubkey = invoice_request.contents.inner.offer.signing_pubkey();
let contents = InvoiceContents::ForOffer {
invoice_request: invoice_request.contents.clone(),
fields: Self::fields(
created_at: Duration, payment_hash: PaymentHash, keys: KeyPair
) -> Result<Self, Bolt12SemanticError> {
let amount_msats = Self::amount_msats(invoice_request)?;
- let signing_pubkey = invoice_request.contents.inner.offer.signing_pubkey();
+ let signing_pubkey = keys.public_key();
let contents = InvoiceContents::ForOffer {
invoice_request: invoice_request.contents.clone(),
fields: Self::fields(
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
}
- <$builder>::for_offer(&$contents, payment_paths, created_at, payment_hash)
+ let signing_pubkey = match $contents.contents.inner.offer.signing_pubkey() {
+ Some(signing_pubkey) => signing_pubkey,
+ None => return Err(Bolt12SemanticError::MissingSigningPubkey),
+ };
+
+ <$builder>::for_offer(&$contents, payment_paths, created_at, payment_hash, signing_pubkey)
}
} }
Some(keys) => keys,
};
+ match $contents.contents.inner.offer.signing_pubkey() {
+ Some(signing_pubkey) => debug_assert_eq!(signing_pubkey, keys.public_key()),
+ None => return Err(Bolt12SemanticError::MissingSigningPubkey),
+ }
+
<$builder>::for_offer_using_keys(
&$self.inner, payment_paths, created_at, payment_hash, keys
)
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.signing_pubkey(), Some(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!(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.signing_pubkey(), Some(recipient_pubkey()));
assert_eq!(invoice_request.chain(), ChainHash::using_genesis_block(Network::Bitcoin));
assert_eq!(invoice_request.amount_msats(), None);
assert_eq!(invoice_request.invoice_request_features(), &InvoiceRequestFeatures::empty());
.amount_msats(1000)
.supported_quantity(Quantity::Unbounded)
.build().unwrap();
- assert_eq!(offer.signing_pubkey(), node_id);
+ assert_eq!(offer.signing_pubkey(), Some(node_id));
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.chain(Network::Testnet).unwrap()
offer: OfferContents {
chains: None, metadata: None, amount: None, description,
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
- supported_quantity: Quantity::One, signing_pubkey,
+ supported_quantity: Quantity::One, signing_pubkey: Some(signing_pubkey),
},
metadata_strategy: core::marker::PhantomData,
secp_ctx: None,
offer: OfferContents {
chains: None, metadata: Some(metadata), amount: None, description,
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
- supported_quantity: Quantity::One, signing_pubkey: node_id,
+ supported_quantity: Quantity::One, signing_pubkey: Some(node_id),
},
metadata_strategy: core::marker::PhantomData,
secp_ctx: Some(secp_ctx),
let (derived_metadata, keys) = metadata.derive_from(tlv_stream, $self.secp_ctx);
metadata = derived_metadata;
if let Some(keys) = keys {
- $self.offer.signing_pubkey = keys.public_key();
+ $self.offer.signing_pubkey = Some(keys.public_key());
}
}
issuer: Option<String>,
paths: Option<Vec<BlindedPath>>,
supported_quantity: Quantity,
- signing_pubkey: PublicKey,
+ signing_pubkey: Option<PublicKey>,
}
macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
}
/// The public key used by the recipient to sign invoices.
- pub fn signing_pubkey(&$self) -> bitcoin::secp256k1::PublicKey {
+ pub fn signing_pubkey(&$self) -> Option<bitcoin::secp256k1::PublicKey> {
$contents.signing_pubkey()
}
} }
}
}
- pub(super) fn signing_pubkey(&self) -> PublicKey {
+ pub(super) fn signing_pubkey(&self) -> Option<PublicKey> {
self.signing_pubkey
}
_ => true,
}
});
+ let signing_pubkey = match self.signing_pubkey() {
+ Some(signing_pubkey) => signing_pubkey,
+ None => return Err(()),
+ };
let keys = signer::verify_recipient_metadata(
- metadata, key, IV_BYTES, self.signing_pubkey(), tlv_stream, secp_ctx
+ metadata, key, IV_BYTES, signing_pubkey, tlv_stream, secp_ctx
)?;
let offer_id = OfferId::from_valid_invreq_tlv_stream(bytes);
paths: self.paths.as_ref(),
issuer: self.issuer.as_ref(),
quantity_max: self.supported_quantity.to_tlv_record(),
- node_id: Some(&self.signing_pubkey),
+ node_id: self.signing_pubkey.as_ref(),
}
}
}
let signing_pubkey = match node_id {
None => return Err(Bolt12SemanticError::MissingSigningPubkey),
- Some(node_id) => node_id,
+ Some(node_id) => Some(node_id),
};
Ok(OfferContents {
assert_eq!(offer.paths(), &[]);
assert_eq!(offer.issuer(), None);
assert_eq!(offer.supported_quantity(), Quantity::One);
- assert_eq!(offer.signing_pubkey(), pubkey(42));
+ assert_eq!(offer.signing_pubkey(), Some(pubkey(42)));
assert_eq!(
offer.as_tlv_stream(),
::deriving_signing_pubkey(desc, node_id, &expanded_key, &entropy, &secp_ctx)
.amount_msats(1000)
.build().unwrap();
- assert_eq!(offer.signing_pubkey(), node_id);
+ assert_eq!(offer.signing_pubkey(), Some(node_id));
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.amount_msats(1000)
.path(blinded_path)
.build().unwrap();
- assert_ne!(offer.signing_pubkey(), node_id);
+ assert_ne!(offer.signing_pubkey(), Some(node_id));
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
.build().unwrap()
.unwrap();
let tlv_stream = offer.as_tlv_stream();
assert_eq!(offer.paths(), paths.as_slice());
- assert_eq!(offer.signing_pubkey(), pubkey(42));
+ assert_eq!(offer.signing_pubkey(), Some(pubkey(42)));
assert_ne!(pubkey(42), pubkey(44));
assert_eq!(tlv_stream.paths, Some(&paths));
assert_eq!(tlv_stream.node_id, Some(&pubkey(42)));