Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sendpayment Part 2: Channel open, Get invoice #58

Merged
merged 15 commits into from
Oct 8, 2022
Merged
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
101 changes: 98 additions & 3 deletions common/src/ln/invoice.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,101 @@ impl Display for LxInvoice {
}
}

// TODO(max): We should proptest the serde and fromstr/display impls but it's
// non-trivial to impl Arbitrary for Invoice. lightning_invoice::InvoiceBuilder
// is probably the way.
// `any::<String>()` requires proptest feature std which doesn't work in SGX
#[cfg(all(test, not(target_env = "sgx")))]
mod test {
use std::time::{Duration, SystemTime, UNIX_EPOCH};

use bitcoin::hashes::{sha256, Hash};
use bitcoin::secp256k1::{self, Secp256k1};
use lightning::ln::PaymentSecret;
use lightning_invoice::{Currency, InvoiceBuilder};
use proptest::arbitrary::{any, Arbitrary};
use proptest::strategy::{BoxedStrategy, Strategy};

use super::*;
use crate::cli::Network;
use crate::rng::SmallRng;
use crate::root_seed::RootSeed;
use crate::test_utils::roundtrip;

impl Arbitrary for LxInvoice {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
let currency = any::<Network>().prop_map(Currency::from);
let description = any::<String>();

let payment_hash = any::<[u8; 32]>()
.prop_map(|buf| sha256::Hash::from_slice(&buf).unwrap());

let payment_secret = any::<[u8; 32]>().prop_map(PaymentSecret);

let timestamp = any::<SystemTime>().prop_map(|system_time| {
// TODO: We convert to and from unix seconds because LDK's
// fromstr/display impl fails the roundtrip test if the
// SystemTime passed to InvoiceBuilder::timestamp isn't rounded
// to the nearest second. We can drop the prop_map once
// <https://github.com/lightningdevkit/rust-lightning/pull/1760>
// is merged and released.
let unix_secs = system_time
.duration_since(UNIX_EPOCH)
.unwrap_or(Duration::from_secs(0))
.as_secs();
UNIX_EPOCH + Duration::from_secs(unix_secs)
});

let min_final_cltv_expiry = any::<u64>();

let secret_key = any::<SmallRng>()
.prop_map(|mut rng| {
RootSeed::from_rng(&mut rng).derive_node_key_pair(&mut rng)
})
.prop_map(secp256k1::SecretKey::from);
(
currency,
description,
payment_hash,
payment_secret,
timestamp,
min_final_cltv_expiry,
secret_key,
)
.prop_map(
|(
currency,
description,
payment_hash,
payment_secret,
timestamp,
min_final_cltv_expiry,
secret_key,
)| {
let invoice = InvoiceBuilder::new(currency)
.description(description)
.payment_hash(payment_hash)
.payment_secret(payment_secret)
.timestamp(timestamp)
.min_final_cltv_expiry(min_final_cltv_expiry)
.build_signed(|hash| {
Secp256k1::new()
.sign_ecdsa_recoverable(hash, &secret_key)
})
.expect("Could not build invoice");
Self(invoice)
},
)
.boxed()
}
}

#[test]
fn invoice_serde_roundtrip() {
roundtrip::serde_roundtrip_proptest::<LxInvoice>();
}

#[test]
fn invoice_fromstr_display_roundtrip() {
roundtrip::fromstr_display_roundtrip_proptest::<LxInvoice>();
}
}