Skip to content

Commit 8143d98

Browse files
committed
Add BOLT 12 merkle root test for invoice_request
A BOLT 12 test vector uses an `invoice_request` message that has a currency, which aren't supported, so using OfferBuilder::build_unchecked is required to avoid a panic.
1 parent 2086194 commit 8143d98

File tree

2 files changed

+53
-2
lines changed

2 files changed

+53
-2
lines changed

lightning/src/offers/invoice_request.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ impl<'a> InvoiceRequestBuilder<'a> {
186186
}
187187

188188
#[cfg(test)]
189-
fn build_unchecked(self) -> UnsignedInvoiceRequest<'a> {
189+
pub(super) fn build_unchecked(self) -> UnsignedInvoiceRequest<'a> {
190190
let InvoiceRequestBuilder { offer, invoice_request } = self;
191191
UnsignedInvoiceRequest { offer, invoice_request }
192192
}
@@ -238,7 +238,7 @@ impl<'a> UnsignedInvoiceRequest<'a> {
238238
/// [`Offer`]: crate::offers::offer::Offer
239239
#[derive(Clone, Debug)]
240240
pub struct InvoiceRequest {
241-
bytes: Vec<u8>,
241+
pub(super) bytes: Vec<u8>,
242242
contents: InvoiceRequestContents,
243243
signature: Option<Signature>,
244244
}

lightning/src/offers/merkle.rs

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,10 @@ impl<'a> Iterator for TlvStream<'a> {
189189
#[cfg(test)]
190190
mod tests {
191191
use bitcoin::hashes::{Hash, sha256};
192+
use bitcoin::secp256k1::{KeyPair, Secp256k1, SecretKey};
193+
use crate::offers::offer::{Amount, OfferBuilder};
194+
use crate::offers::invoice_request::InvoiceRequest;
195+
use crate::offers::parse::Bech32Encode;
192196

193197
#[test]
194198
fn calculates_merkle_root_hash() {
@@ -209,4 +213,51 @@ mod tests {
209213
sha256::Hash::from_slice(&hex::decode("ab2e79b1283b0b31e0b035258de23782df6b89a38cfa7237bde69aed1a658c5d").unwrap()).unwrap(),
210214
);
211215
}
216+
217+
#[test]
218+
fn calculates_merkle_root_hash_from_invoice_request() {
219+
let secp_ctx = Secp256k1::new();
220+
let recipient_pubkey = {
221+
let secret_key = SecretKey::from_slice(&hex::decode("4141414141414141414141414141414141414141414141414141414141414141").unwrap()).unwrap();
222+
KeyPair::from_secret_key(&secp_ctx, &secret_key).public_key()
223+
};
224+
let payer_keys = {
225+
let secret_key = SecretKey::from_slice(&hex::decode("4242424242424242424242424242424242424242424242424242424242424242").unwrap()).unwrap();
226+
KeyPair::from_secret_key(&secp_ctx, &secret_key)
227+
};
228+
229+
// BOLT 12 test vectors
230+
let invoice_request = OfferBuilder::new("A Mathematical Treatise".into(), recipient_pubkey)
231+
.amount(Amount::Currency { iso4217_code: *b"USD", amount: 100 })
232+
.build_unchecked()
233+
.request_invoice(payer_keys.public_key())
234+
.metadata(vec![0; 8])
235+
.build_unchecked()
236+
.sign(|digest| secp_ctx.sign_schnorr_no_aux_rand(digest, &payer_keys))
237+
.unwrap();
238+
assert_eq!(
239+
invoice_request.to_string(),
240+
"lnr1qqyqqqqqqqqqqqqqqcp4256ypqqkgzshgysy6ct5dpjk6ct5d93kzmpq23ex2ct5d9ek293pqthvwfzadd7jejes8q9lhc4rvjxd022zv5l44g6qah82ru5rdpnpjkppqvjx204vgdzgsqpvcp4mldl3plscny0rt707gvpdh6ndydfacz43euzqhrurageg3n7kafgsek6gz3e9w52parv8gs2hlxzk95tzeswywffxlkeyhml0hh46kndmwf4m6xma3tkq2lu04qz3slje2rfthc89vss",
241+
);
242+
assert_eq!(
243+
super::root_hash(&invoice_request.bytes[..]),
244+
sha256::Hash::from_slice(&hex::decode("608407c18ad9a94d9ea2bcdbe170b6c20c462a7833a197621c916f78cf18e624").unwrap()).unwrap(),
245+
);
246+
}
247+
248+
impl AsRef<[u8]> for InvoiceRequest {
249+
fn as_ref(&self) -> &[u8] {
250+
&self.bytes
251+
}
252+
}
253+
254+
impl Bech32Encode for InvoiceRequest {
255+
const BECH32_HRP: &'static str = "lnr";
256+
}
257+
258+
impl core::fmt::Display for InvoiceRequest {
259+
fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
260+
self.fmt_bech32_str(f)
261+
}
262+
}
212263
}

0 commit comments

Comments
 (0)