mirror of
https://github.com/lightningdevkit/rust-lightning.git
synced 2025-02-24 15:02:20 +01:00
Rename Offer::signing_pubkey to Offer::issuer_signing_pubkey
The spec was recently changed to use offer_issuer_id instead of offer_node_id. LDK always used signing_pubkey to avoid confusion with a node_id. Rename it to issuer_signing_pubkey now as InvoiceRequest and Bolt12Invoice will have similarly named methods in upcoming commits.
This commit is contained in:
parent
6662c5c7b9
commit
df58f26ada
9 changed files with 120 additions and 113 deletions
|
@ -9197,7 +9197,7 @@ where
|
|||
/// # Limitations
|
||||
///
|
||||
/// Requires a direct connection to an introduction node in [`Offer::paths`] or to
|
||||
/// [`Offer::signing_pubkey`], if empty. A similar restriction applies to the responding
|
||||
/// [`Offer::issuer_signing_pubkey`], if empty. A similar restriction applies to the responding
|
||||
/// [`Bolt12Invoice::payment_paths`].
|
||||
///
|
||||
/// # Errors
|
||||
|
@ -9288,10 +9288,10 @@ where
|
|||
let message = OffersMessage::InvoiceRequest(invoice_request.clone());
|
||||
pending_offers_messages.push((message, instructions));
|
||||
});
|
||||
} else if let Some(signing_pubkey) = invoice_request.signing_pubkey() {
|
||||
} else if let Some(node_id) = invoice_request.issuer_signing_pubkey() {
|
||||
for reply_path in reply_paths {
|
||||
let instructions = MessageSendInstructions::WithSpecifiedReplyPath {
|
||||
destination: Destination::Node(signing_pubkey),
|
||||
destination: Destination::Node(node_id),
|
||||
reply_path,
|
||||
};
|
||||
let message = OffersMessage::InvoiceRequest(invoice_request.clone());
|
||||
|
@ -9299,7 +9299,7 @@ where
|
|||
}
|
||||
} else {
|
||||
debug_assert!(false);
|
||||
return Err(Bolt12SemanticError::MissingSigningPubkey);
|
||||
return Err(Bolt12SemanticError::MissingIssuerSigningPubkey);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
|
|
@ -305,7 +305,7 @@ fn prefers_non_tor_nodes_in_blinded_paths() {
|
|||
.create_offer_builder(None).unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(bob_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(bob_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
let introduction_node_id = resolve_introduction_node(david, &path);
|
||||
|
@ -321,7 +321,7 @@ fn prefers_non_tor_nodes_in_blinded_paths() {
|
|||
.create_offer_builder(None).unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(bob_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(bob_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
let introduction_node_id = resolve_introduction_node(david, &path);
|
||||
|
@ -372,7 +372,7 @@ fn prefers_more_connected_nodes_in_blinded_paths() {
|
|||
.create_offer_builder(None).unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(bob_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(bob_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
let introduction_node_id = resolve_introduction_node(david, &path);
|
||||
|
@ -541,7 +541,7 @@ fn creates_and_pays_for_offer_using_two_hop_blinded_path() {
|
|||
.unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
|
||||
|
@ -709,7 +709,7 @@ fn creates_and_pays_for_offer_using_one_hop_blinded_path() {
|
|||
.create_offer_builder(None).unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
|
||||
|
@ -832,7 +832,7 @@ fn pays_for_offer_without_blinded_paths() {
|
|||
.clear_paths()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_eq!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_eq!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(offer.paths().is_empty());
|
||||
|
||||
let payment_id = PaymentId([1; 32]);
|
||||
|
@ -955,7 +955,7 @@ fn send_invoice_requests_with_distinct_reply_path() {
|
|||
.unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
|
||||
|
@ -1090,7 +1090,7 @@ fn creates_and_pays_for_offer_with_retry() {
|
|||
.create_offer_builder(None).unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(alice_id));
|
||||
|
@ -1248,7 +1248,7 @@ fn creates_offer_with_blinded_path_using_unannounced_introduction_node() {
|
|||
.create_offer_builder(None).unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
|
||||
|
@ -1379,7 +1379,7 @@ fn fails_authentication_when_handling_invoice_request() {
|
|||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_eq!(offer.metadata(), None);
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
|
||||
|
@ -1490,7 +1490,7 @@ fn fails_authentication_when_handling_invoice_for_offer() {
|
|||
.unwrap()
|
||||
.amount_msats(10_000_000)
|
||||
.build().unwrap();
|
||||
assert_ne!(offer.signing_pubkey(), Some(alice_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(alice_id));
|
||||
assert!(!offer.paths().is_empty());
|
||||
for path in offer.paths() {
|
||||
assert_eq!(path.introduction_node(), &IntroductionNode::NodeId(bob_id));
|
||||
|
|
|
@ -1335,7 +1335,7 @@ impl TryFrom<PartialInvoiceTlvStream> for InvoiceContents {
|
|||
|
||||
check_invoice_signing_pubkey(&fields.signing_pubkey, &offer_tlv_stream)?;
|
||||
|
||||
if offer_tlv_stream.node_id.is_none() && offer_tlv_stream.paths.is_none() {
|
||||
if offer_tlv_stream.issuer_id.is_none() && offer_tlv_stream.paths.is_none() {
|
||||
let refund = RefundContents::try_from(
|
||||
(payer_tlv_stream, offer_tlv_stream, invoice_request_tlv_stream)
|
||||
)?;
|
||||
|
@ -1373,9 +1373,9 @@ pub(super) fn construct_payment_paths(
|
|||
pub(super) fn check_invoice_signing_pubkey(
|
||||
invoice_signing_pubkey: &PublicKey, offer_tlv_stream: &OfferTlvStream
|
||||
) -> Result<(), Bolt12SemanticError> {
|
||||
match (&offer_tlv_stream.node_id, &offer_tlv_stream.paths) {
|
||||
(Some(expected_signing_pubkey), _) => {
|
||||
if invoice_signing_pubkey != expected_signing_pubkey {
|
||||
match (&offer_tlv_stream.issuer_id, &offer_tlv_stream.paths) {
|
||||
(Some(issuer_signing_pubkey), _) => {
|
||||
if invoice_signing_pubkey != issuer_signing_pubkey {
|
||||
return Err(Bolt12SemanticError::InvalidSigningPubkey);
|
||||
}
|
||||
},
|
||||
|
@ -1561,7 +1561,7 @@ mod tests {
|
|||
paths: None,
|
||||
issuer: None,
|
||||
quantity_max: None,
|
||||
node_id: Some(&recipient_pubkey()),
|
||||
issuer_id: Some(&recipient_pubkey()),
|
||||
},
|
||||
InvoiceRequestTlvStreamRef {
|
||||
chain: None,
|
||||
|
@ -1654,7 +1654,7 @@ mod tests {
|
|||
paths: None,
|
||||
issuer: None,
|
||||
quantity_max: None,
|
||||
node_id: None,
|
||||
issuer_id: None,
|
||||
},
|
||||
InvoiceRequestTlvStreamRef {
|
||||
chain: None,
|
||||
|
@ -1791,7 +1791,7 @@ mod tests {
|
|||
|
||||
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
|
||||
.amount_msats(1000)
|
||||
// Omit the path so that node_id is used for the signing pubkey instead of deriving
|
||||
// Omit the path so that node_id is used for the signing pubkey instead of deriving it
|
||||
.build().unwrap();
|
||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
||||
.build().unwrap()
|
||||
|
@ -2359,7 +2359,7 @@ mod tests {
|
|||
};
|
||||
|
||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||
.clear_signing_pubkey()
|
||||
.clear_issuer_signing_pubkey()
|
||||
.amount_msats(1000)
|
||||
.path(paths[0].clone())
|
||||
.path(paths[1].clone())
|
||||
|
@ -2381,7 +2381,7 @@ mod tests {
|
|||
}
|
||||
|
||||
let invoice = OfferBuilder::new(recipient_pubkey())
|
||||
.clear_signing_pubkey()
|
||||
.clear_issuer_signing_pubkey()
|
||||
.amount_msats(1000)
|
||||
.path(paths[0].clone())
|
||||
.path(paths[1].clone())
|
||||
|
|
|
@ -728,7 +728,7 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { (
|
|||
/// The `payment_paths` parameter is useful for maintaining the payment recipient's privacy. It
|
||||
/// must contain one or more elements ordered from most-preferred to least-preferred, if there's
|
||||
/// a preference. Note, however, that any privacy is lost if a public node id was used for
|
||||
/// [`Offer::signing_pubkey`].
|
||||
/// [`Offer::issuer_signing_pubkey`].
|
||||
///
|
||||
/// Errors if the request contains unknown required features.
|
||||
///
|
||||
|
@ -749,9 +749,9 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { (
|
|||
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
|
||||
}
|
||||
|
||||
let signing_pubkey = match $contents.contents.inner.offer.signing_pubkey() {
|
||||
let signing_pubkey = match $contents.contents.inner.offer.issuer_signing_pubkey() {
|
||||
Some(signing_pubkey) => signing_pubkey,
|
||||
None => return Err(Bolt12SemanticError::MissingSigningPubkey),
|
||||
None => return Err(Bolt12SemanticError::MissingIssuerSigningPubkey),
|
||||
};
|
||||
|
||||
<$builder>::for_offer(&$contents, payment_paths, created_at, payment_hash, signing_pubkey)
|
||||
|
@ -763,7 +763,7 @@ macro_rules! invoice_request_respond_with_explicit_signing_pubkey_methods { (
|
|||
&$self, payment_paths: Vec<BlindedPaymentPath>, payment_hash: PaymentHash,
|
||||
created_at: core::time::Duration, signing_pubkey: PublicKey
|
||||
) -> Result<$builder, Bolt12SemanticError> {
|
||||
debug_assert!($contents.contents.inner.offer.signing_pubkey().is_none());
|
||||
debug_assert!($contents.contents.inner.offer.issuer_signing_pubkey().is_none());
|
||||
|
||||
if $contents.invoice_request_features().requires_unknown_bits() {
|
||||
return Err(Bolt12SemanticError::UnknownRequiredFeatures);
|
||||
|
@ -914,9 +914,9 @@ macro_rules! invoice_request_respond_with_derived_signing_pubkey_methods { (
|
|||
Some(keys) => keys,
|
||||
};
|
||||
|
||||
match $contents.contents.inner.offer.signing_pubkey() {
|
||||
match $contents.contents.inner.offer.issuer_signing_pubkey() {
|
||||
Some(signing_pubkey) => debug_assert_eq!(signing_pubkey, keys.public_key()),
|
||||
None => return Err(Bolt12SemanticError::MissingSigningPubkey),
|
||||
None => return Err(Bolt12SemanticError::MissingIssuerSigningPubkey),
|
||||
}
|
||||
|
||||
<$builder>::for_offer_using_keys(
|
||||
|
@ -1297,7 +1297,7 @@ mod tests {
|
|||
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(), Some(recipient_pubkey()));
|
||||
assert_eq!(unsigned_invoice_request.issuer_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());
|
||||
|
@ -1329,7 +1329,7 @@ mod tests {
|
|||
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(), Some(recipient_pubkey()));
|
||||
assert_eq!(invoice_request.issuer_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());
|
||||
|
@ -1355,7 +1355,7 @@ mod tests {
|
|||
paths: None,
|
||||
issuer: None,
|
||||
quantity_max: None,
|
||||
node_id: Some(&recipient_pubkey()),
|
||||
issuer_id: Some(&recipient_pubkey()),
|
||||
},
|
||||
InvoiceRequestTlvStreamRef {
|
||||
chain: None,
|
||||
|
@ -2234,14 +2234,14 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn fails_parsing_invoice_request_without_node_id() {
|
||||
fn fails_parsing_invoice_request_without_issuer_id() {
|
||||
let offer = OfferBuilder::new(recipient_pubkey())
|
||||
.amount_msats(1000)
|
||||
.build().unwrap();
|
||||
let unsigned_invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
||||
.build().unwrap();
|
||||
let mut tlv_stream = unsigned_invoice_request.contents.as_tlv_stream();
|
||||
tlv_stream.1.node_id = None;
|
||||
tlv_stream.1.issuer_id = None;
|
||||
|
||||
let mut buffer = Vec::new();
|
||||
tlv_stream.write(&mut buffer).unwrap();
|
||||
|
@ -2249,7 +2249,7 @@ mod tests {
|
|||
match InvoiceRequest::try_from(buffer) {
|
||||
Ok(_) => panic!("expected error"),
|
||||
Err(e) => {
|
||||
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
|
||||
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingIssuerSigningPubkey));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -2334,7 +2334,7 @@ mod tests {
|
|||
.amount_msats(1000)
|
||||
.supported_quantity(Quantity::Unbounded)
|
||||
.build().unwrap();
|
||||
assert_eq!(offer.signing_pubkey(), Some(node_id));
|
||||
assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
|
||||
|
||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
||||
.chain(Network::Testnet).unwrap()
|
||||
|
|
|
@ -20,11 +20,11 @@ use crate::prelude::*;
|
|||
|
||||
/// A 128-bit number used only once.
|
||||
///
|
||||
/// Needed when constructing [`Offer::metadata`] and deriving [`Offer::signing_pubkey`] from
|
||||
/// Needed when constructing [`Offer::metadata`] and deriving [`Offer::issuer_signing_pubkey`] from
|
||||
/// [`ExpandedKey`]. Must not be reused for any other derivation without first hashing.
|
||||
///
|
||||
/// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
|
||||
/// [`Offer::signing_pubkey`]: crate::offers::offer::Offer::signing_pubkey
|
||||
/// [`Offer::issuer_signing_pubkey`]: crate::offers::offer::Offer::issuer_signing_pubkey
|
||||
/// [`ExpandedKey`]: crate::ln::inbound_payment::ExpandedKey
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||
pub struct Nonce(pub(crate) [u8; Self::LENGTH]);
|
||||
|
|
|
@ -207,8 +207,8 @@ impl MetadataStrategy for DerivedMetadata {}
|
|||
macro_rules! offer_explicit_metadata_builder_methods { (
|
||||
$self: ident, $self_type: ty, $return_type: ty, $return_value: expr
|
||||
) => {
|
||||
/// Creates a new builder for an offer using the [`Offer::signing_pubkey`] for signing invoices.
|
||||
/// The associated secret key must be remembered while the offer is valid.
|
||||
/// Creates a new builder for an offer using the `signing_pubkey` for signing invoices. The
|
||||
/// associated secret key must be remembered while the offer is valid.
|
||||
///
|
||||
/// Use a different pubkey per offer to avoid correlating offers.
|
||||
///
|
||||
|
@ -224,7 +224,7 @@ macro_rules! offer_explicit_metadata_builder_methods { (
|
|||
offer: OfferContents {
|
||||
chains: None, metadata: None, amount: None, description: None,
|
||||
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
|
||||
supported_quantity: Quantity::One, signing_pubkey: Some(signing_pubkey),
|
||||
supported_quantity: Quantity::One, issuer_signing_pubkey: Some(signing_pubkey),
|
||||
},
|
||||
metadata_strategy: core::marker::PhantomData,
|
||||
secp_ctx: None,
|
||||
|
@ -244,7 +244,7 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => {
|
|||
/// Similar to [`OfferBuilder::new`] except, if [`OfferBuilder::path`] is called, the signing
|
||||
/// pubkey is derived from the given [`ExpandedKey`] and [`Nonce`]. This provides recipient
|
||||
/// privacy by using a different signing pubkey for each offer. Otherwise, the provided
|
||||
/// `node_id` is used for the signing pubkey.
|
||||
/// `node_id` is used for [`Offer::issuer_signing_pubkey`].
|
||||
///
|
||||
/// Also, sets the metadata when [`OfferBuilder::build`] is called such that it can be used by
|
||||
/// [`InvoiceRequest::verify_using_metadata`] to determine if the request was produced for the
|
||||
|
@ -265,7 +265,7 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => {
|
|||
offer: OfferContents {
|
||||
chains: None, metadata: Some(metadata), amount: None, description: None,
|
||||
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
|
||||
supported_quantity: Quantity::One, signing_pubkey: Some(node_id),
|
||||
supported_quantity: Quantity::One, issuer_signing_pubkey: Some(node_id),
|
||||
},
|
||||
metadata_strategy: core::marker::PhantomData,
|
||||
secp_ctx: Some(secp_ctx),
|
||||
|
@ -342,7 +342,7 @@ macro_rules! offer_builder_methods { (
|
|||
}
|
||||
|
||||
/// Adds a blinded path to [`Offer::paths`]. Must include at least one path if only connected by
|
||||
/// private channels or if [`Offer::signing_pubkey`] is not a public node id.
|
||||
/// private channels or if [`Offer::issuer_signing_pubkey`] is not a public node id.
|
||||
///
|
||||
/// Successive calls to this method will add another blinded path. Caller is responsible for not
|
||||
/// adding duplicate paths.
|
||||
|
@ -403,7 +403,7 @@ macro_rules! offer_builder_methods { (
|
|||
debug_assert_eq!(tlv_stream.metadata, None);
|
||||
tlv_stream.metadata = None;
|
||||
if metadata.derives_recipient_keys() {
|
||||
tlv_stream.node_id = None;
|
||||
tlv_stream.issuer_id = None;
|
||||
}
|
||||
|
||||
// Either replace the signing pubkey with the derived pubkey or include the metadata
|
||||
|
@ -412,7 +412,7 @@ macro_rules! offer_builder_methods { (
|
|||
let (derived_metadata, keys) =
|
||||
metadata.derive_from(iv_bytes, tlv_stream, $self.secp_ctx);
|
||||
match keys {
|
||||
Some(keys) => $self.offer.signing_pubkey = Some(keys.public_key()),
|
||||
Some(keys) => $self.offer.issuer_signing_pubkey = Some(keys.public_key()),
|
||||
None => $self.offer.metadata = Some(derived_metadata),
|
||||
}
|
||||
} else {
|
||||
|
@ -459,8 +459,8 @@ macro_rules! offer_builder_test_methods { (
|
|||
}
|
||||
|
||||
#[cfg_attr(c_bindings, allow(dead_code))]
|
||||
pub(crate) fn clear_signing_pubkey($($self_mut)* $self: $self_type) -> $return_type {
|
||||
$self.offer.signing_pubkey = None;
|
||||
pub(crate) fn clear_issuer_signing_pubkey($($self_mut)* $self: $self_type) -> $return_type {
|
||||
$self.offer.issuer_signing_pubkey = None;
|
||||
$return_value
|
||||
}
|
||||
|
||||
|
@ -570,7 +570,7 @@ pub(super) struct OfferContents {
|
|||
issuer: Option<String>,
|
||||
paths: Option<Vec<BlindedMessagePath>>,
|
||||
supported_quantity: Quantity,
|
||||
signing_pubkey: Option<PublicKey>,
|
||||
issuer_signing_pubkey: Option<PublicKey>,
|
||||
}
|
||||
|
||||
macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
|
||||
|
@ -632,8 +632,8 @@ macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
|
|||
}
|
||||
|
||||
/// The public key used by the recipient to sign invoices.
|
||||
pub fn signing_pubkey(&$self) -> Option<bitcoin::secp256k1::PublicKey> {
|
||||
$contents.signing_pubkey()
|
||||
pub fn issuer_signing_pubkey(&$self) -> Option<bitcoin::secp256k1::PublicKey> {
|
||||
$contents.issuer_signing_pubkey()
|
||||
}
|
||||
} }
|
||||
|
||||
|
@ -916,8 +916,8 @@ impl OfferContents {
|
|||
}
|
||||
}
|
||||
|
||||
pub(super) fn signing_pubkey(&self) -> Option<PublicKey> {
|
||||
self.signing_pubkey
|
||||
pub(super) fn issuer_signing_pubkey(&self) -> Option<PublicKey> {
|
||||
self.issuer_signing_pubkey
|
||||
}
|
||||
|
||||
pub(super) fn verify_using_metadata<T: secp256k1::Signing>(
|
||||
|
@ -943,11 +943,11 @@ impl OfferContents {
|
|||
let tlv_stream = TlvStream::new(bytes).range(OFFER_TYPES).filter(|record| {
|
||||
match record.r#type {
|
||||
OFFER_METADATA_TYPE => false,
|
||||
OFFER_NODE_ID_TYPE => !metadata.derives_recipient_keys(),
|
||||
OFFER_ISSUER_ID_TYPE => !metadata.derives_recipient_keys(),
|
||||
_ => true,
|
||||
}
|
||||
});
|
||||
let signing_pubkey = match self.signing_pubkey() {
|
||||
let signing_pubkey = match self.issuer_signing_pubkey() {
|
||||
Some(signing_pubkey) => signing_pubkey,
|
||||
None => return Err(()),
|
||||
};
|
||||
|
@ -987,7 +987,7 @@ impl OfferContents {
|
|||
paths: self.paths.as_ref(),
|
||||
issuer: self.issuer.as_ref(),
|
||||
quantity_max: self.supported_quantity.to_tlv_record(),
|
||||
node_id: self.signing_pubkey.as_ref(),
|
||||
issuer_id: self.issuer_signing_pubkey.as_ref(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1063,8 +1063,8 @@ pub(super) const OFFER_TYPES: core::ops::Range<u64> = 1..80;
|
|||
/// TLV record type for [`Offer::metadata`].
|
||||
const OFFER_METADATA_TYPE: u64 = 4;
|
||||
|
||||
/// TLV record type for [`Offer::signing_pubkey`].
|
||||
const OFFER_NODE_ID_TYPE: u64 = 22;
|
||||
/// TLV record type for [`Offer::issuer_signing_pubkey`].
|
||||
const OFFER_ISSUER_ID_TYPE: u64 = 22;
|
||||
|
||||
tlv_stream!(OfferTlvStream, OfferTlvStreamRef, OFFER_TYPES, {
|
||||
(2, chains: (Vec<ChainHash>, WithoutLength)),
|
||||
|
@ -1077,7 +1077,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, OFFER_TYPES, {
|
|||
(16, paths: (Vec<BlindedMessagePath>, WithoutLength)),
|
||||
(18, issuer: (String, WithoutLength)),
|
||||
(20, quantity_max: (u64, HighZeroBytesDroppedBigSize)),
|
||||
(OFFER_NODE_ID_TYPE, node_id: PublicKey),
|
||||
(OFFER_ISSUER_ID_TYPE, issuer_id: PublicKey),
|
||||
});
|
||||
|
||||
impl Bech32Encode for Offer {
|
||||
|
@ -1111,7 +1111,7 @@ impl TryFrom<OfferTlvStream> for OfferContents {
|
|||
fn try_from(tlv_stream: OfferTlvStream) -> Result<Self, Self::Error> {
|
||||
let OfferTlvStream {
|
||||
chains, metadata, currency, amount, description, features, absolute_expiry, paths,
|
||||
issuer, quantity_max, node_id,
|
||||
issuer, quantity_max, issuer_id,
|
||||
} = tlv_stream;
|
||||
|
||||
let metadata = metadata.map(|metadata| Metadata::Bytes(metadata));
|
||||
|
@ -1141,15 +1141,15 @@ impl TryFrom<OfferTlvStream> for OfferContents {
|
|||
Some(n) => Quantity::Bounded(NonZeroU64::new(n).unwrap()),
|
||||
};
|
||||
|
||||
let (signing_pubkey, paths) = match (node_id, paths) {
|
||||
(None, None) => return Err(Bolt12SemanticError::MissingSigningPubkey),
|
||||
let (issuer_signing_pubkey, paths) = match (issuer_id, paths) {
|
||||
(None, None) => return Err(Bolt12SemanticError::MissingIssuerSigningPubkey),
|
||||
(_, Some(paths)) if paths.is_empty() => return Err(Bolt12SemanticError::MissingPaths),
|
||||
(node_id, paths) => (node_id, paths),
|
||||
(issuer_id, paths) => (issuer_id, paths),
|
||||
};
|
||||
|
||||
Ok(OfferContents {
|
||||
chains, metadata, amount, description, features, absolute_expiry, issuer, paths,
|
||||
supported_quantity, signing_pubkey,
|
||||
supported_quantity, issuer_signing_pubkey,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -1210,7 +1210,7 @@ mod tests {
|
|||
assert_eq!(offer.issuer(), None);
|
||||
assert_eq!(offer.supported_quantity(), Quantity::One);
|
||||
assert!(!offer.expects_quantity());
|
||||
assert_eq!(offer.signing_pubkey(), Some(pubkey(42)));
|
||||
assert_eq!(offer.issuer_signing_pubkey(), Some(pubkey(42)));
|
||||
|
||||
assert_eq!(
|
||||
offer.as_tlv_stream(),
|
||||
|
@ -1225,7 +1225,7 @@ mod tests {
|
|||
paths: None,
|
||||
issuer: None,
|
||||
quantity_max: None,
|
||||
node_id: Some(&pubkey(42)),
|
||||
issuer_id: Some(&pubkey(42)),
|
||||
},
|
||||
);
|
||||
|
||||
|
@ -1307,7 +1307,7 @@ mod tests {
|
|||
.amount_msats(1000)
|
||||
.build().unwrap();
|
||||
assert!(offer.metadata().is_some());
|
||||
assert_eq!(offer.signing_pubkey(), Some(node_id));
|
||||
assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
|
||||
|
||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
||||
.build().unwrap()
|
||||
|
@ -1376,7 +1376,7 @@ mod tests {
|
|||
.path(blinded_path)
|
||||
.build().unwrap();
|
||||
assert!(offer.metadata().is_none());
|
||||
assert_ne!(offer.signing_pubkey(), Some(node_id));
|
||||
assert_ne!(offer.issuer_signing_pubkey(), Some(node_id));
|
||||
|
||||
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
|
||||
.build().unwrap()
|
||||
|
@ -1409,8 +1409,8 @@ mod tests {
|
|||
|
||||
// Fails verification with altered signing pubkey
|
||||
let mut tlv_stream = offer.as_tlv_stream();
|
||||
let signing_pubkey = pubkey(1);
|
||||
tlv_stream.node_id = Some(&signing_pubkey);
|
||||
let issuer_id = pubkey(1);
|
||||
tlv_stream.issuer_id = Some(&issuer_id);
|
||||
|
||||
let mut encoded_offer = Vec::new();
|
||||
tlv_stream.write(&mut encoded_offer).unwrap();
|
||||
|
@ -1567,10 +1567,10 @@ mod tests {
|
|||
.unwrap();
|
||||
let tlv_stream = offer.as_tlv_stream();
|
||||
assert_eq!(offer.paths(), paths.as_slice());
|
||||
assert_eq!(offer.signing_pubkey(), Some(pubkey(42)));
|
||||
assert_eq!(offer.issuer_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)));
|
||||
assert_eq!(tlv_stream.issuer_id, Some(&pubkey(42)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -1773,7 +1773,7 @@ mod tests {
|
|||
BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
|
||||
]
|
||||
))
|
||||
.clear_signing_pubkey()
|
||||
.clear_issuer_signing_pubkey()
|
||||
.build()
|
||||
.unwrap();
|
||||
if let Err(e) = offer.to_string().parse::<Offer>() {
|
||||
|
@ -1828,14 +1828,14 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn parses_offer_with_node_id() {
|
||||
fn parses_offer_with_issuer_id() {
|
||||
let offer = OfferBuilder::new(pubkey(42)).build().unwrap();
|
||||
if let Err(e) = offer.to_string().parse::<Offer>() {
|
||||
panic!("error parsing offer: {:?}", e);
|
||||
}
|
||||
|
||||
let mut tlv_stream = offer.as_tlv_stream();
|
||||
tlv_stream.node_id = None;
|
||||
tlv_stream.issuer_id = None;
|
||||
|
||||
let mut encoded_offer = Vec::new();
|
||||
tlv_stream.write(&mut encoded_offer).unwrap();
|
||||
|
@ -1843,7 +1843,7 @@ mod tests {
|
|||
match Offer::try_from(encoded_offer) {
|
||||
Ok(_) => panic!("expected error"),
|
||||
Err(e) => {
|
||||
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey));
|
||||
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingIssuerSigningPubkey));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
@ -1948,7 +1948,7 @@ mod bolt12_tests {
|
|||
// Malformed: empty
|
||||
assert_eq!(
|
||||
"lno1".parse::<Offer>(),
|
||||
Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey)),
|
||||
Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingIssuerSigningPubkey)),
|
||||
);
|
||||
|
||||
// Malformed: truncated at type
|
||||
|
@ -2053,7 +2053,7 @@ mod bolt12_tests {
|
|||
Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
|
||||
);
|
||||
|
||||
// Malformed: invalid offer_node_id
|
||||
// Malformed: invalid offer_issuer_id
|
||||
assert_eq!(
|
||||
"lno1pgz5znzfgdz3vggzqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvpsxqcrqvps".parse::<Offer>(),
|
||||
Err(Bolt12ParseError::Decode(DecodeError::InvalidValue)),
|
||||
|
@ -2078,10 +2078,10 @@ mod bolt12_tests {
|
|||
Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingDescription)),
|
||||
);
|
||||
|
||||
// Missing offer_node_id"
|
||||
// Missing offer_issuer_id
|
||||
assert_eq!(
|
||||
"lno1pgx9getnwss8vetrw3hhyuc".parse::<Offer>(),
|
||||
Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingSigningPubkey)),
|
||||
Err(Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingIssuerSigningPubkey)),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -157,12 +157,10 @@ pub enum Bolt12SemanticError {
|
|||
UnexpectedFeatures,
|
||||
/// A required description was not provided.
|
||||
MissingDescription,
|
||||
/// A signing pubkey was not provided.
|
||||
MissingSigningPubkey,
|
||||
/// A signing pubkey was provided but a different one was expected.
|
||||
InvalidSigningPubkey,
|
||||
/// A signing pubkey was provided but was not expected.
|
||||
UnexpectedSigningPubkey,
|
||||
/// An issuer's signing pubkey was not provided.
|
||||
MissingIssuerSigningPubkey,
|
||||
/// An issuer's signing pubkey was provided but was not expected.
|
||||
UnexpectedIssuerSigningPubkey,
|
||||
/// A quantity was expected but was missing.
|
||||
MissingQuantity,
|
||||
/// An unsupported quantity was provided.
|
||||
|
@ -191,6 +189,10 @@ pub enum Bolt12SemanticError {
|
|||
MissingPaymentHash,
|
||||
/// An invoice payment hash was provided but was not expected.
|
||||
UnexpectedPaymentHash,
|
||||
/// A signing pubkey was not provided.
|
||||
MissingSigningPubkey,
|
||||
/// A signing pubkey was provided but a different one was expected.
|
||||
InvalidSigningPubkey,
|
||||
/// A signature was expected but was missing.
|
||||
MissingSignature,
|
||||
}
|
||||
|
|
|
@ -752,7 +752,7 @@ impl RefundContents {
|
|||
paths: None,
|
||||
issuer: self.issuer.as_ref(),
|
||||
quantity_max: None,
|
||||
node_id: None,
|
||||
issuer_id: None,
|
||||
};
|
||||
|
||||
let features = {
|
||||
|
@ -844,7 +844,7 @@ impl TryFrom<RefundTlvStream> for RefundContents {
|
|||
OfferTlvStream {
|
||||
chains, metadata, currency, amount: offer_amount, description,
|
||||
features: offer_features, absolute_expiry, paths: offer_paths, issuer, quantity_max,
|
||||
node_id,
|
||||
issuer_id,
|
||||
},
|
||||
InvoiceRequestTlvStream {
|
||||
chain, amount, features, quantity, payer_id, payer_note, paths
|
||||
|
@ -887,8 +887,8 @@ impl TryFrom<RefundTlvStream> for RefundContents {
|
|||
return Err(Bolt12SemanticError::UnexpectedQuantity);
|
||||
}
|
||||
|
||||
if node_id.is_some() {
|
||||
return Err(Bolt12SemanticError::UnexpectedSigningPubkey);
|
||||
if issuer_id.is_some() {
|
||||
return Err(Bolt12SemanticError::UnexpectedIssuerSigningPubkey);
|
||||
}
|
||||
|
||||
let amount_msats = match amount {
|
||||
|
@ -1003,7 +1003,7 @@ mod tests {
|
|||
paths: None,
|
||||
issuer: None,
|
||||
quantity_max: None,
|
||||
node_id: None,
|
||||
issuer_id: None,
|
||||
},
|
||||
InvoiceRequestTlvStreamRef {
|
||||
chain: None,
|
||||
|
@ -1509,14 +1509,14 @@ mod tests {
|
|||
},
|
||||
}
|
||||
|
||||
let node_id = payer_pubkey();
|
||||
let issuer_id = payer_pubkey();
|
||||
let mut tlv_stream = refund.as_tlv_stream();
|
||||
tlv_stream.1.node_id = Some(&node_id);
|
||||
tlv_stream.1.issuer_id = Some(&issuer_id);
|
||||
|
||||
match Refund::try_from(tlv_stream.to_bytes()) {
|
||||
Ok(_) => panic!("expected error"),
|
||||
Err(e) => {
|
||||
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedSigningPubkey));
|
||||
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::UnexpectedIssuerSigningPubkey));
|
||||
},
|
||||
}
|
||||
}
|
||||
|
|
|
@ -110,8 +110,8 @@ impl<'a> StaticInvoiceBuilder<'a> {
|
|||
return Err(Bolt12SemanticError::MissingPaths);
|
||||
}
|
||||
|
||||
let offer_signing_pubkey =
|
||||
offer.signing_pubkey().ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
|
||||
let issuer_signing_pubkey =
|
||||
offer.issuer_signing_pubkey().ok_or(Bolt12SemanticError::MissingIssuerSigningPubkey)?;
|
||||
|
||||
let keys = offer
|
||||
.verify(nonce, &expanded_key, &secp_ctx)
|
||||
|
@ -120,7 +120,7 @@ impl<'a> StaticInvoiceBuilder<'a> {
|
|||
.ok_or(Bolt12SemanticError::MissingSigningPubkey)?;
|
||||
|
||||
let signing_pubkey = keys.public_key();
|
||||
if signing_pubkey != offer_signing_pubkey {
|
||||
if signing_pubkey != issuer_signing_pubkey {
|
||||
return Err(Bolt12SemanticError::InvalidSigningPubkey);
|
||||
}
|
||||
|
||||
|
@ -707,11 +707,9 @@ mod tests {
|
|||
assert!(invoice.fallbacks().is_empty());
|
||||
assert_eq!(invoice.invoice_features(), &Bolt12InvoiceFeatures::empty());
|
||||
|
||||
let offer_signing_pubkey = offer.signing_pubkey().unwrap();
|
||||
let signing_pubkey = offer.issuer_signing_pubkey().unwrap();
|
||||
let message = TaggedHash::from_valid_tlv_stream_bytes(SIGNATURE_TAG, &invoice.bytes);
|
||||
assert!(
|
||||
merkle::verify_signature(&invoice.signature, &message, offer_signing_pubkey).is_ok()
|
||||
);
|
||||
assert!(merkle::verify_signature(&invoice.signature, &message, signing_pubkey).is_ok());
|
||||
|
||||
let paths = vec![blinded_path()];
|
||||
assert_eq!(
|
||||
|
@ -728,7 +726,7 @@ mod tests {
|
|||
paths: Some(&paths),
|
||||
issuer: None,
|
||||
quantity_max: None,
|
||||
node_id: Some(&offer_signing_pubkey),
|
||||
issuer_id: Some(&signing_pubkey),
|
||||
},
|
||||
InvoiceTlvStreamRef {
|
||||
paths: Some(Iterable(
|
||||
|
@ -741,7 +739,7 @@ mod tests {
|
|||
amount: None,
|
||||
fallbacks: None,
|
||||
features: None,
|
||||
node_id: Some(&offer_signing_pubkey),
|
||||
node_id: Some(&signing_pubkey),
|
||||
message_paths: Some(&paths),
|
||||
},
|
||||
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
|
||||
|
@ -880,7 +878,7 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn fails_build_offer_signing_pubkey() {
|
||||
fn fails_building_with_missing_issuer_signing_pubkey() {
|
||||
let node_id = recipient_pubkey();
|
||||
let now = now();
|
||||
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
|
||||
|
@ -894,16 +892,15 @@ mod tests {
|
|||
.build()
|
||||
.unwrap();
|
||||
|
||||
// Error if offer signing pubkey is missing.
|
||||
let mut offer_missing_signing_pubkey = valid_offer.clone();
|
||||
let mut offer_tlv_stream = offer_missing_signing_pubkey.as_tlv_stream();
|
||||
offer_tlv_stream.node_id.take();
|
||||
let mut offer_missing_issuer_id = valid_offer.clone();
|
||||
let mut offer_tlv_stream = offer_missing_issuer_id.as_tlv_stream();
|
||||
offer_tlv_stream.issuer_id.take();
|
||||
let mut buffer = Vec::new();
|
||||
offer_tlv_stream.write(&mut buffer).unwrap();
|
||||
offer_missing_signing_pubkey = Offer::try_from(buffer).unwrap();
|
||||
offer_missing_issuer_id = Offer::try_from(buffer).unwrap();
|
||||
|
||||
if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
|
||||
&offer_missing_signing_pubkey,
|
||||
&offer_missing_issuer_id,
|
||||
payment_paths(),
|
||||
vec![blinded_path()],
|
||||
now,
|
||||
|
@ -911,12 +908,20 @@ mod tests {
|
|||
nonce,
|
||||
&secp_ctx,
|
||||
) {
|
||||
assert_eq!(e, Bolt12SemanticError::MissingSigningPubkey);
|
||||
assert_eq!(e, Bolt12SemanticError::MissingIssuerSigningPubkey);
|
||||
} else {
|
||||
panic!("expected error")
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn fails_building_with_invalid_metadata() {
|
||||
let now = now();
|
||||
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
|
||||
let entropy = FixedEntropy {};
|
||||
let nonce = Nonce::from_entropy_source(&entropy);
|
||||
let secp_ctx = Secp256k1::new();
|
||||
|
||||
// Error if the offer's metadata cannot be verified.
|
||||
let offer = OfferBuilder::new(recipient_pubkey())
|
||||
.path(blinded_path())
|
||||
.metadata(vec![42; 32])
|
||||
|
|
Loading…
Add table
Reference in a new issue