Skip to content

Commit 0dbf5f2

Browse files
committed
Test verification with experimental offer TLVs
Offer metadata is generated from the offer TLVs and should included those in the experimental range. When verifying invoice request and invoice messages, these TLVs must be included. Similarly, OfferId construction should included these TLVs as well. Modify the BOLT12 verification tests to cover these TLVs.
1 parent cd48683 commit 0dbf5f2

File tree

5 files changed

+121
-10
lines changed

5 files changed

+121
-10
lines changed

lightning/src/offers/invoice.rs

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1708,7 +1708,9 @@ mod tests {
17081708
message_paths: None,
17091709
},
17101710
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
1711-
ExperimentalOfferTlvStreamRef {},
1711+
ExperimentalOfferTlvStreamRef {
1712+
experimental_foo: None,
1713+
},
17121714
),
17131715
);
17141716

@@ -1802,7 +1804,9 @@ mod tests {
18021804
message_paths: None,
18031805
},
18041806
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
1805-
ExperimentalOfferTlvStreamRef {},
1807+
ExperimentalOfferTlvStreamRef {
1808+
experimental_foo: None,
1809+
},
18061810
),
18071811
);
18081812

@@ -1897,6 +1901,7 @@ mod tests {
18971901
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
18981902
.amount_msats(1000)
18991903
.path(blinded_path)
1904+
.experimental_foo(42)
19001905
.build().unwrap();
19011906
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
19021907
.build().unwrap()
@@ -1918,6 +1923,7 @@ mod tests {
19181923
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
19191924
.amount_msats(1000)
19201925
// Omit the path so that node_id is used for the issuer id instead of deriving it
1926+
.experimental_foo(42)
19211927
.build().unwrap();
19221928
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
19231929
.build().unwrap()
@@ -1939,6 +1945,7 @@ mod tests {
19391945
let secp_ctx = Secp256k1::new();
19401946

19411947
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
1948+
.experimental_foo(42)
19421949
.build().unwrap();
19431950

19441951
if let Err(e) = refund

lightning/src/offers/invoice_request.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1393,7 +1393,9 @@ mod tests {
13931393
paths: None,
13941394
},
13951395
SignatureTlvStreamRef { signature: Some(&invoice_request.signature()) },
1396-
ExperimentalOfferTlvStreamRef {},
1396+
ExperimentalOfferTlvStreamRef {
1397+
experimental_foo: None,
1398+
},
13971399
),
13981400
);
13991401

@@ -1441,6 +1443,7 @@ mod tests {
14411443

14421444
let offer = OfferBuilder::new(recipient_pubkey())
14431445
.amount_msats(1000)
1446+
.experimental_foo(42)
14441447
.build().unwrap();
14451448
let invoice_request = offer
14461449
.request_invoice_deriving_metadata(signing_pubkey, &expanded_key, nonce, payment_id)
@@ -1524,6 +1527,7 @@ mod tests {
15241527

15251528
let offer = OfferBuilder::new(recipient_pubkey())
15261529
.amount_msats(1000)
1530+
.experimental_foo(42)
15271531
.build().unwrap();
15281532
let invoice_request = offer
15291533
.request_invoice_deriving_signing_pubkey(&expanded_key, nonce, &secp_ctx, payment_id)

lightning/src/offers/offer.rs

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,8 @@ macro_rules! offer_explicit_metadata_builder_methods { (
226226
chains: None, metadata: None, amount: None, description: None,
227227
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
228228
supported_quantity: Quantity::One, issuer_signing_pubkey: Some(signing_pubkey),
229+
#[cfg(test)]
230+
experimental_foo: None,
229231
},
230232
metadata_strategy: core::marker::PhantomData,
231233
secp_ctx: None,
@@ -267,6 +269,8 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => {
267269
chains: None, metadata: Some(metadata), amount: None, description: None,
268270
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
269271
supported_quantity: Quantity::One, issuer_signing_pubkey: Some(node_id),
272+
#[cfg(test)]
273+
experimental_foo: None,
270274
},
271275
metadata_strategy: core::marker::PhantomData,
272276
secp_ctx: Some(secp_ctx),
@@ -465,6 +469,12 @@ macro_rules! offer_builder_test_methods { (
465469
$return_value
466470
}
467471

472+
#[cfg_attr(c_bindings, allow(dead_code))]
473+
pub(super) fn experimental_foo($($self_mut)* $self: $self_type, experimental_foo: u64) -> $return_type {
474+
$self.offer.experimental_foo = Some(experimental_foo);
475+
$return_value
476+
}
477+
468478
#[cfg_attr(c_bindings, allow(dead_code))]
469479
pub(super) fn build_unchecked($self: $self_type) -> Offer {
470480
$self.build_without_checks()
@@ -572,6 +582,8 @@ pub(super) struct OfferContents {
572582
paths: Option<Vec<BlindedPath>>,
573583
supported_quantity: Quantity,
574584
issuer_signing_pubkey: Option<PublicKey>,
585+
#[cfg(test)]
586+
experimental_foo: Option<u64>,
575587
}
576588

577589
macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
@@ -1004,7 +1016,10 @@ impl OfferContents {
10041016
issuer_id: self.issuer_signing_pubkey.as_ref(),
10051017
};
10061018

1007-
let experimental_offer = ExperimentalOfferTlvStreamRef {};
1019+
let experimental_offer = ExperimentalOfferTlvStreamRef {
1020+
#[cfg(test)]
1021+
experimental_foo: self.experimental_foo,
1022+
};
10081023

10091024
(offer, experimental_offer)
10101025
}
@@ -1101,9 +1116,15 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef<'a>, OFFER_TYPES, {
11011116
/// Valid type range for experimental offer TLV records.
11021117
pub(super) const EXPERIMENTAL_OFFER_TYPES: core::ops::Range<u64> = 1_000_000_000..2_000_000_000;
11031118

1119+
#[cfg(not(test))]
11041120
tlv_stream!(ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, EXPERIMENTAL_OFFER_TYPES, {
11051121
});
11061122

1123+
#[cfg(test)]
1124+
tlv_stream!(ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, EXPERIMENTAL_OFFER_TYPES, {
1125+
(1_999_999_999, experimental_foo: (u64, HighZeroBytesDroppedBigSize)),
1126+
});
1127+
11071128
type FullOfferTlvStream = (OfferTlvStream, ExperimentalOfferTlvStream);
11081129

11091130
type FullOfferTlvStreamRef<'a> = (OfferTlvStreamRef<'a>, ExperimentalOfferTlvStreamRef);
@@ -1151,7 +1172,10 @@ impl TryFrom<FullOfferTlvStream> for OfferContents {
11511172
chains, metadata, currency, amount, description, features, absolute_expiry, paths,
11521173
issuer, quantity_max, issuer_id,
11531174
},
1154-
ExperimentalOfferTlvStream {},
1175+
ExperimentalOfferTlvStream {
1176+
#[cfg(test)]
1177+
experimental_foo,
1178+
},
11551179
) = tlv_stream;
11561180

11571181
let metadata = metadata.map(|metadata| Metadata::Bytes(metadata));
@@ -1190,6 +1214,8 @@ impl TryFrom<FullOfferTlvStream> for OfferContents {
11901214
Ok(OfferContents {
11911215
chains, metadata, amount, description, features, absolute_expiry, issuer, paths,
11921216
supported_quantity, issuer_signing_pubkey,
1217+
#[cfg(test)]
1218+
experimental_foo,
11931219
})
11941220
}
11951221
}
@@ -1267,7 +1293,9 @@ mod tests {
12671293
quantity_max: None,
12681294
issuer_id: Some(&pubkey(42)),
12691295
},
1270-
ExperimentalOfferTlvStreamRef {},
1296+
ExperimentalOfferTlvStreamRef {
1297+
experimental_foo: None,
1298+
},
12711299
),
12721300
);
12731301

@@ -1347,6 +1375,7 @@ mod tests {
13471375
use super::OfferWithDerivedMetadataBuilder as OfferBuilder;
13481376
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
13491377
.amount_msats(1000)
1378+
.experimental_foo(42)
13501379
.build().unwrap();
13511380
assert!(offer.metadata().is_some());
13521381
assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
@@ -1417,6 +1446,7 @@ mod tests {
14171446
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
14181447
.amount_msats(1000)
14191448
.path(blinded_path)
1449+
.experimental_foo(42)
14201450
.build().unwrap();
14211451
assert!(offer.metadata().is_none());
14221452
assert_ne!(offer.issuer_signing_pubkey(), Some(node_id));

lightning/src/offers/refund.rs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,8 @@ macro_rules! refund_explicit_metadata_builder_methods { () => {
176176
payer: PayerContents(metadata), description: String::new(), absolute_expiry: None,
177177
issuer: None, chain: None, amount_msats, features: InvoiceRequestFeatures::empty(),
178178
quantity: None, payer_signing_pubkey: signing_pubkey, payer_note: None, paths: None,
179+
#[cfg(test)]
180+
experimental_foo: None,
179181
},
180182
secp_ctx: None,
181183
})
@@ -218,6 +220,8 @@ macro_rules! refund_builder_methods { (
218220
payer: PayerContents(metadata), description: String::new(), absolute_expiry: None,
219221
issuer: None, chain: None, amount_msats, features: InvoiceRequestFeatures::empty(),
220222
quantity: None, payer_signing_pubkey: node_id, payer_note: None, paths: None,
223+
#[cfg(test)]
224+
experimental_foo: None,
221225
},
222226
secp_ctx: Some(secp_ctx),
223227
})
@@ -358,6 +362,12 @@ macro_rules! refund_builder_test_methods { (
358362
$self.refund.features = features;
359363
$return_value
360364
}
365+
366+
#[cfg_attr(c_bindings, allow(dead_code))]
367+
pub(super) fn experimental_foo($($self_mut)* $self: $self_type, experimental_foo: u64) -> $return_type {
368+
$self.refund.experimental_foo = Some(experimental_foo);
369+
$return_value
370+
}
361371
} }
362372

363373
impl<'a> RefundBuilder<'a, secp256k1::SignOnly> {
@@ -437,6 +447,8 @@ pub(super) struct RefundContents {
437447
payer_signing_pubkey: PublicKey,
438448
payer_note: Option<String>,
439449
paths: Option<Vec<BlindedPath>>,
450+
#[cfg(test)]
451+
experimental_foo: Option<u64>,
440452
}
441453

442454
impl Refund {
@@ -770,7 +782,10 @@ impl RefundContents {
770782
paths: self.paths.as_ref(),
771783
};
772784

773-
let experimental_offer = ExperimentalOfferTlvStreamRef {};
785+
let experimental_offer = ExperimentalOfferTlvStreamRef {
786+
#[cfg(test)]
787+
experimental_foo: self.experimental_foo,
788+
};
774789

775790
(payer, offer, invoice_request, experimental_offer)
776791
}
@@ -855,7 +870,10 @@ impl TryFrom<RefundTlvStream> for RefundContents {
855870
InvoiceRequestTlvStream {
856871
chain, amount, features, quantity, payer_id, payer_note, paths
857872
},
858-
_experimental_offer_tlv_stream,
873+
ExperimentalOfferTlvStream {
874+
#[cfg(test)]
875+
experimental_foo,
876+
},
859877
) = tlv_stream;
860878

861879
let payer = match payer_metadata {
@@ -916,6 +934,8 @@ impl TryFrom<RefundTlvStream> for RefundContents {
916934
Ok(RefundContents {
917935
payer, description, absolute_expiry, issuer, chain, amount_msats, features, quantity,
918936
payer_signing_pubkey, payer_note, paths,
937+
#[cfg(test)]
938+
experimental_foo,
919939
})
920940
}
921941
}
@@ -1020,7 +1040,9 @@ mod tests {
10201040
payer_note: None,
10211041
paths: None,
10221042
},
1023-
ExperimentalOfferTlvStreamRef {},
1043+
ExperimentalOfferTlvStreamRef {
1044+
experimental_foo: None,
1045+
},
10241046
),
10251047
);
10261048

@@ -1049,6 +1071,7 @@ mod tests {
10491071
let refund = RefundBuilder
10501072
::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx, 1000, payment_id)
10511073
.unwrap()
1074+
.experimental_foo(42)
10521075
.build().unwrap();
10531076
assert_eq!(refund.payer_signing_pubkey(), node_id);
10541077

@@ -1117,6 +1140,7 @@ mod tests {
11171140
::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx, 1000, payment_id)
11181141
.unwrap()
11191142
.path(blinded_path)
1143+
.experimental_foo(42)
11201144
.build().unwrap();
11211145
assert_ne!(refund.payer_signing_pubkey(), node_id);
11221146

lightning/src/offers/static_invoice.rs

Lines changed: 47 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -812,7 +812,7 @@ mod tests {
812812
message_paths: Some(&paths),
813813
},
814814
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
815-
ExperimentalOfferTlvStreamRef {},
815+
ExperimentalOfferTlvStreamRef { experimental_foo: None },
816816
)
817817
);
818818

@@ -880,6 +880,52 @@ mod tests {
880880
}
881881
}
882882

883+
#[test]
884+
fn builds_invoice_from_offer_using_derived_key() {
885+
let node_id = recipient_pubkey();
886+
let now = now();
887+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
888+
let entropy = FixedEntropy {};
889+
let nonce = Nonce::from_entropy_source(&entropy);
890+
let secp_ctx = Secp256k1::new();
891+
892+
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
893+
.path(blinded_path())
894+
.experimental_foo(42)
895+
.build()
896+
.unwrap();
897+
898+
if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
899+
&offer,
900+
payment_paths(),
901+
vec![blinded_path()],
902+
now,
903+
&expanded_key,
904+
nonce,
905+
&secp_ctx,
906+
)
907+
.unwrap()
908+
.build_and_sign(&secp_ctx)
909+
{
910+
panic!("error building invoice: {:?}", e);
911+
}
912+
913+
let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32]));
914+
if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
915+
&offer,
916+
payment_paths(),
917+
vec![blinded_path()],
918+
now,
919+
&expanded_key,
920+
nonce,
921+
&secp_ctx,
922+
) {
923+
assert_eq!(e, Bolt12SemanticError::InvalidMetadata);
924+
} else {
925+
panic!("expected error")
926+
}
927+
}
928+
883929
#[test]
884930
fn fails_build_with_missing_paths() {
885931
let node_id = recipient_pubkey();

0 commit comments

Comments
 (0)