-
Notifications
You must be signed in to change notification settings - Fork 418
Closed
Description
As noted on Discord, if you pass in a SystemTime
in to InvoiceBuilder::timestamp
that isn't rounded to the nearest second, serializing with .to_string()
then deserializing back to Invoice
using .from_str()
will cause assert_eq!(invoice1, invoice2)
to fail.
Here's a quick and dirty testcase adapted from the InvoiceBuilder
example:
Cargo.toml
[dependencies]
bitcoin_hashes = "0.11.0"
lightning-block-sync = "0.0.111"
lightning = "0.0.111"
lightning-invoice = "0.19"
secp256k1 = "0.24.0"
lib.rs
use std::str::FromStr;
use bitcoin_hashes::{Hash, sha256};
use lightning::ln::PaymentSecret;
use lightning_invoice::{Currency, Invoice, InvoiceBuilder};
use secp256k1::{Secp256k1, SecretKey};
#[test]
fn invoice_roundtrip() {
let private_key = SecretKey::from_slice(
&[
0xe1, 0x26, 0xf6, 0x8f, 0x7e, 0xaf, 0xcc, 0x8b, 0x74, 0xf5, 0x4d, 0x26, 0x9f,
0xe2, 0x06, 0xbe, 0x71, 0x50, 0x00, 0xf9, 0x4d, 0xac, 0x06, 0x7d, 0x1c, 0x04,
0xa8, 0xca, 0x3b, 0x2d, 0xb7, 0x34
][..]
).unwrap();
let payment_hash = sha256::Hash::from_slice(&[0; 32][..]).unwrap();
let payment_secret = PaymentSecret([42u8; 32]);
let invoice1 = InvoiceBuilder::new(Currency::Bitcoin)
.description("Coins pls!".into())
.payment_hash(payment_hash)
.payment_secret(payment_secret)
.current_timestamp()
.min_final_cltv_expiry(144)
.build_signed(|hash| {
Secp256k1::new().sign_ecdsa_recoverable(hash, &private_key)
})
.unwrap();
let invoice2 = Invoice::from_str(&invoice1.to_string()).unwrap();
assert_eq!(invoice1, invoice2);
}
Output:
Compiling invoice-roundtrip v0.1.0 (/Users/fang/temp/invoice-roundtrip)
Finished dev [unoptimized + debuginfo] target(s) in 0.26s
Running `target/debug/invoice-roundtrip`
thread 'main' panicked at 'assertion failed: `(left == right)`
left: `Invoice { signed_invoice: SignedRawInvoice { raw_invoice: RawInvoice { hrp: RawHrp { currency: Bitcoin, raw_amount: None, si_prefix: None }, data: RawDataPart { timestamp: PositiveTimestamp(1665106253.008274s), tagged_fields: [KnownSemantics(Description(Description("Coins pls!"))), KnownSemantics(PaymentHash(Sha256(0000000000000000000000000000000000000000000000000000000000000000))), KnownSemantics(PaymentSecret(PaymentSecret([42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42]))), KnownSemantics(Features([0, 65])), KnownSemantics(MinFinalCltvExpiry(MinFinalCltvExpiry(144)))] } }, hash: [76, 189, 147, 119, 65, 8, 203, 66, 80, 235, 100, 185, 22, 133, 69, 181, 99, 161, 108, 45, 204, 248, 253, 155, 49, 209, 115, 87, 177, 181, 140, 216], signature: InvoiceSignature(RecoverableSignature(58f688605065861c440bd2877112fbba0e1cd79a78476eb183252e020d122e9a665850ba5ee0ed63bbbe5f203e978dafeab02d7132d741316c9a40944763266401)) } }`,
right: `Invoice { signed_invoice: SignedRawInvoice { raw_invoice: RawInvoice { hrp: RawHrp { currency: Bitcoin, raw_amount: None, si_prefix: None }, data: RawDataPart { timestamp: PositiveTimestamp(1665106253s), tagged_fields: [KnownSemantics(Description(Description("Coins pls!"))), KnownSemantics(PaymentHash(Sha256(0000000000000000000000000000000000000000000000000000000000000000))), KnownSemantics(PaymentSecret(PaymentSecret([42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42, 42]))), KnownSemantics(Features([0, 65])), KnownSemantics(MinFinalCltvExpiry(MinFinalCltvExpiry(144)))] } }, hash: [76, 189, 147, 119, 65, 8, 203, 66, 80, 235, 100, 185, 22, 133, 69, 181, 99, 161, 108, 45, 204, 248, 253, 155, 49, 209, 115, 87, 177, 181, 140, 216], signature: InvoiceSignature(RecoverableSignature(58f688605065861c440bd2877112fbba0e1cd79a78476eb183252e020d122e9a665850ba5ee0ed63bbbe5f203e978dafeab02d7132d741316c9a40944763266401)) } }`', src/main.rs:31:5
stack backtrace:
0: rust_begin_unwind
at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/std/src/panicking.rs:584:5
1: core::panicking::panic_fmt
at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/panicking.rs:142:14
2: core::panicking::assert_failed_inner
3: core::panicking::assert_failed
at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/panicking.rs:181:5
4: invoice_roundtrip::main
at ./src/main.rs:31:5
5: core::ops::function::FnOnce::call_once
at /rustc/4b91a6ea7258a947e59c6522cd5898e7c0a6a88f/library/core/src/ops/function.rs:248:5
note: Some details are omitted, run with `RUST_BACKTRACE=full` for a verbose backtrace.
The best solution is probably to drop any sub-second parts from the SystemTime
/ Duration
s passed into the InvoiceBuilder
.
Metadata
Metadata
Assignees
Labels
No labels