Skip to content

Commit d703c13

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 0e00c71 commit d703c13

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
@@ -1677,7 +1677,9 @@ mod tests {
16771677
message_paths: None,
16781678
},
16791679
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
1680-
ExperimentalOfferTlvStreamRef {},
1680+
ExperimentalOfferTlvStreamRef {
1681+
experimental_foo: None,
1682+
},
16811683
),
16821684
);
16831685

@@ -1771,7 +1773,9 @@ mod tests {
17711773
message_paths: None,
17721774
},
17731775
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
1774-
ExperimentalOfferTlvStreamRef {},
1776+
ExperimentalOfferTlvStreamRef {
1777+
experimental_foo: None,
1778+
},
17751779
),
17761780
);
17771781

@@ -1865,6 +1869,7 @@ mod tests {
18651869
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
18661870
.amount_msats(1000)
18671871
.path(blinded_path)
1872+
.experimental_foo(42)
18681873
.build().unwrap();
18691874
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
18701875
.build().unwrap()
@@ -1886,6 +1891,7 @@ mod tests {
18861891
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
18871892
.amount_msats(1000)
18881893
// Omit the path so that node_id is used for the signing pubkey instead of deriving it
1894+
.experimental_foo(42)
18891895
.build().unwrap();
18901896
let invoice_request = offer.request_invoice(vec![1; 32], payer_pubkey()).unwrap()
18911897
.build().unwrap()
@@ -1907,6 +1913,7 @@ mod tests {
19071913
let secp_ctx = Secp256k1::new();
19081914

19091915
let refund = RefundBuilder::new(vec![1; 32], payer_pubkey(), 1000).unwrap()
1916+
.experimental_foo(42)
19101917
.build().unwrap();
19111918

19121919
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
@@ -1408,7 +1408,9 @@ mod tests {
14081408
paths: None,
14091409
},
14101410
SignatureTlvStreamRef { signature: Some(&invoice_request.signature()) },
1411-
ExperimentalOfferTlvStreamRef {},
1411+
ExperimentalOfferTlvStreamRef {
1412+
experimental_foo: None,
1413+
},
14121414
),
14131415
);
14141416

@@ -1456,6 +1458,7 @@ mod tests {
14561458

14571459
let offer = OfferBuilder::new(recipient_pubkey())
14581460
.amount_msats(1000)
1461+
.experimental_foo(42)
14591462
.build().unwrap();
14601463
let invoice_request = offer
14611464
.request_invoice_deriving_metadata(signing_pubkey, &expanded_key, nonce, payment_id)
@@ -1539,6 +1542,7 @@ mod tests {
15391542

15401543
let offer = OfferBuilder::new(recipient_pubkey())
15411544
.amount_msats(1000)
1545+
.experimental_foo(42)
15421546
.build().unwrap();
15431547
let invoice_request = offer
15441548
.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
@@ -225,6 +225,8 @@ macro_rules! offer_explicit_metadata_builder_methods { (
225225
chains: None, metadata: None, amount: None, description: None,
226226
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
227227
supported_quantity: Quantity::One, issuer_signing_pubkey: Some(signing_pubkey),
228+
#[cfg(test)]
229+
experimental_foo: None,
228230
},
229231
metadata_strategy: core::marker::PhantomData,
230232
secp_ctx: None,
@@ -266,6 +268,8 @@ macro_rules! offer_derived_metadata_builder_methods { ($secp_context: ty) => {
266268
chains: None, metadata: Some(metadata), amount: None, description: None,
267269
features: OfferFeatures::empty(), absolute_expiry: None, issuer: None, paths: None,
268270
supported_quantity: Quantity::One, issuer_signing_pubkey: Some(node_id),
271+
#[cfg(test)]
272+
experimental_foo: None,
269273
},
270274
metadata_strategy: core::marker::PhantomData,
271275
secp_ctx: Some(secp_ctx),
@@ -464,6 +468,12 @@ macro_rules! offer_builder_test_methods { (
464468
$return_value
465469
}
466470

471+
#[cfg_attr(c_bindings, allow(dead_code))]
472+
pub(super) fn experimental_foo($($self_mut)* $self: $self_type, experimental_foo: u64) -> $return_type {
473+
$self.offer.experimental_foo = Some(experimental_foo);
474+
$return_value
475+
}
476+
467477
#[cfg_attr(c_bindings, allow(dead_code))]
468478
pub(super) fn build_unchecked($self: $self_type) -> Offer {
469479
$self.build_without_checks()
@@ -571,6 +581,8 @@ pub(super) struct OfferContents {
571581
paths: Option<Vec<BlindedMessagePath>>,
572582
supported_quantity: Quantity,
573583
issuer_signing_pubkey: Option<PublicKey>,
584+
#[cfg(test)]
585+
experimental_foo: Option<u64>,
574586
}
575587

576588
macro_rules! offer_accessors { ($self: ident, $contents: expr) => {
@@ -1010,7 +1022,10 @@ impl OfferContents {
10101022
issuer_id: self.issuer_signing_pubkey.as_ref(),
10111023
};
10121024

1013-
let experimental_offer = ExperimentalOfferTlvStreamRef {};
1025+
let experimental_offer = ExperimentalOfferTlvStreamRef {
1026+
#[cfg(test)]
1027+
experimental_foo: self.experimental_foo,
1028+
};
10141029

10151030
(offer, experimental_offer)
10161031
}
@@ -1107,9 +1122,15 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef<'a>, OFFER_TYPES, {
11071122
/// Valid type range for experimental offer TLV records.
11081123
pub(super) const EXPERIMENTAL_OFFER_TYPES: core::ops::Range<u64> = 1_000_000_000..2_000_000_000;
11091124

1125+
#[cfg(not(test))]
11101126
tlv_stream!(ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, EXPERIMENTAL_OFFER_TYPES, {
11111127
});
11121128

1129+
#[cfg(test)]
1130+
tlv_stream!(ExperimentalOfferTlvStream, ExperimentalOfferTlvStreamRef, EXPERIMENTAL_OFFER_TYPES, {
1131+
(1_999_999_999, experimental_foo: (u64, HighZeroBytesDroppedBigSize)),
1132+
});
1133+
11131134
type FullOfferTlvStream = (OfferTlvStream, ExperimentalOfferTlvStream);
11141135

11151136
type FullOfferTlvStreamRef<'a> = (OfferTlvStreamRef<'a>, ExperimentalOfferTlvStreamRef);
@@ -1157,7 +1178,10 @@ impl TryFrom<FullOfferTlvStream> for OfferContents {
11571178
chains, metadata, currency, amount, description, features, absolute_expiry, paths,
11581179
issuer, quantity_max, issuer_id,
11591180
},
1160-
ExperimentalOfferTlvStream {},
1181+
ExperimentalOfferTlvStream {
1182+
#[cfg(test)]
1183+
experimental_foo,
1184+
},
11611185
) = tlv_stream;
11621186

11631187
let metadata = metadata.map(|metadata| Metadata::Bytes(metadata));
@@ -1196,6 +1220,8 @@ impl TryFrom<FullOfferTlvStream> for OfferContents {
11961220
Ok(OfferContents {
11971221
chains, metadata, amount, description, features, absolute_expiry, issuer, paths,
11981222
supported_quantity, issuer_signing_pubkey,
1223+
#[cfg(test)]
1224+
experimental_foo,
11991225
})
12001226
}
12011227
}
@@ -1274,7 +1300,9 @@ mod tests {
12741300
quantity_max: None,
12751301
issuer_id: Some(&pubkey(42)),
12761302
},
1277-
ExperimentalOfferTlvStreamRef {},
1303+
ExperimentalOfferTlvStreamRef {
1304+
experimental_foo: None,
1305+
},
12781306
),
12791307
);
12801308

@@ -1354,6 +1382,7 @@ mod tests {
13541382
use super::OfferWithDerivedMetadataBuilder as OfferBuilder;
13551383
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
13561384
.amount_msats(1000)
1385+
.experimental_foo(42)
13571386
.build().unwrap();
13581387
assert!(offer.metadata().is_some());
13591388
assert_eq!(offer.issuer_signing_pubkey(), Some(node_id));
@@ -1423,6 +1452,7 @@ mod tests {
14231452
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
14241453
.amount_msats(1000)
14251454
.path(blinded_path)
1455+
.experimental_foo(42)
14261456
.build().unwrap();
14271457
assert!(offer.metadata().is_none());
14281458
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<BlindedMessagePath>>,
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
}
@@ -1021,7 +1041,9 @@ mod tests {
10211041
payer_note: None,
10221042
paths: None,
10231043
},
1024-
ExperimentalOfferTlvStreamRef {},
1044+
ExperimentalOfferTlvStreamRef {
1045+
experimental_foo: None,
1046+
},
10251047
),
10261048
);
10271049

@@ -1050,6 +1072,7 @@ mod tests {
10501072
let refund = RefundBuilder
10511073
::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx, 1000, payment_id)
10521074
.unwrap()
1075+
.experimental_foo(42)
10531076
.build().unwrap();
10541077
assert_eq!(refund.payer_signing_pubkey(), node_id);
10551078

@@ -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
@@ -827,7 +827,7 @@ mod tests {
827827
message_paths: Some(&paths),
828828
},
829829
SignatureTlvStreamRef { signature: Some(&invoice.signature()) },
830-
ExperimentalOfferTlvStreamRef {},
830+
ExperimentalOfferTlvStreamRef { experimental_foo: None },
831831
)
832832
);
833833

@@ -895,6 +895,52 @@ mod tests {
895895
}
896896
}
897897

898+
#[test]
899+
fn builds_invoice_from_offer_using_derived_key() {
900+
let node_id = recipient_pubkey();
901+
let now = now();
902+
let expanded_key = ExpandedKey::new(&KeyMaterial([42; 32]));
903+
let entropy = FixedEntropy {};
904+
let nonce = Nonce::from_entropy_source(&entropy);
905+
let secp_ctx = Secp256k1::new();
906+
907+
let offer = OfferBuilder::deriving_signing_pubkey(node_id, &expanded_key, nonce, &secp_ctx)
908+
.path(blinded_path())
909+
.experimental_foo(42)
910+
.build()
911+
.unwrap();
912+
913+
if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
914+
&offer,
915+
payment_paths(),
916+
vec![blinded_path()],
917+
now,
918+
&expanded_key,
919+
nonce,
920+
&secp_ctx,
921+
)
922+
.unwrap()
923+
.build_and_sign(&secp_ctx)
924+
{
925+
panic!("error building invoice: {:?}", e);
926+
}
927+
928+
let expanded_key = ExpandedKey::new(&KeyMaterial([41; 32]));
929+
if let Err(e) = StaticInvoiceBuilder::for_offer_using_derived_keys(
930+
&offer,
931+
payment_paths(),
932+
vec![blinded_path()],
933+
now,
934+
&expanded_key,
935+
nonce,
936+
&secp_ctx,
937+
) {
938+
assert_eq!(e, Bolt12SemanticError::InvalidMetadata);
939+
} else {
940+
panic!("expected error")
941+
}
942+
}
943+
898944
#[test]
899945
fn fails_build_with_missing_paths() {
900946
let node_id = recipient_pubkey();

0 commit comments

Comments
 (0)