Allow parsing Offer without signing_pubkey

If an offer has at least one path, it may omit the signing pubkey and
use the blinded node id of the last hop of a path to sign an invoice.
Allow parsing such offers but not yet creating them.
This commit is contained in:
Jeffrey Czyz 2024-04-24 09:03:56 -05:00
parent 520fecf8fc
commit 94d5af663d
No known key found for this signature in database
GPG key ID: 912EF12EA67705F5

View file

@ -436,6 +436,12 @@ macro_rules! offer_builder_test_methods { (
$return_value
}
#[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;
$return_value
}
#[cfg_attr(c_bindings, allow(dead_code))]
pub(super) fn build_unchecked($self: $self_type) -> Offer {
$self.build_without_checks()
@ -1093,9 +1099,10 @@ impl TryFrom<OfferTlvStream> for OfferContents {
Some(n) => Quantity::Bounded(NonZeroU64::new(n).unwrap()),
};
let signing_pubkey = match node_id {
None => return Err(Bolt12SemanticError::MissingSigningPubkey),
Some(node_id) => Some(node_id),
let (signing_pubkey, paths) = match (node_id, paths) {
(None, None) => return Err(Bolt12SemanticError::MissingSigningPubkey),
(_, Some(paths)) if paths.is_empty() => return Err(Bolt12SemanticError::MissingPaths),
(node_id, paths) => (node_id, paths),
};
Ok(OfferContents {
@ -1662,12 +1669,31 @@ mod tests {
panic!("error parsing offer: {:?}", e);
}
let offer = OfferBuilder::new("foo".into(), pubkey(42))
.path(BlindedPath {
introduction_node: IntroductionNode::NodeId(pubkey(40)),
blinding_point: pubkey(41),
blinded_hops: vec![
BlindedHop { blinded_node_id: pubkey(43), encrypted_payload: vec![0; 43] },
BlindedHop { blinded_node_id: pubkey(44), encrypted_payload: vec![0; 44] },
],
})
.clear_signing_pubkey()
.build()
.unwrap();
if let Err(e) = offer.to_string().parse::<Offer>() {
panic!("error parsing offer: {:?}", e);
}
let mut builder = OfferBuilder::new("foo".into(), pubkey(42));
builder.offer.paths = Some(vec![]);
let offer = builder.build().unwrap();
if let Err(e) = offer.to_string().parse::<Offer>() {
panic!("error parsing offer: {:?}", e);
match offer.to_string().parse::<Offer>() {
Ok(_) => panic!("expected error"),
Err(e) => {
assert_eq!(e, Bolt12ParseError::InvalidSemantics(Bolt12SemanticError::MissingPaths));
},
}
}