Skip to content

Commit

Permalink
Move VSS integration tests to integration test folder
Browse files Browse the repository at this point in the history
  • Loading branch information
tnull committed Dec 18, 2023
1 parent 0627f84 commit 193591e
Show file tree
Hide file tree
Showing 6 changed files with 300 additions and 31 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/vss-integration.yml
Original file line number Diff line number Diff line change
Expand Up @@ -74,8 +74,8 @@ jobs:
run: |
cd ldk-node
export TEST_VSS_BASE_URL="http://localhost:8080/vss"
RUSTFLAGS="--cfg=vss_test --cfg=vss" cargo build --verbose --color always
RUSTFLAGS="--cfg=vss_test --cfg=vss" cargo test -- --nocapture
RUSTFLAGS="--cfg vss_test --cfg vss" cargo build --verbose --color always
RUSTFLAGS="--cfg vss_test --cfg vss" cargo test --test integration_tests_vss
- name: Cleanup
run: |
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,12 @@ lightning = { version = "0.0.118", features = ["std", "_test_utils"] }
#lightning = { git = "https://github.com/lightningdevkit/rust-lightning", branch="main", features = ["std", "_test_utils"] }
electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] }
electrum-client = "0.12.0"
bitcoincore-rpc = { version = "0.16.0", default-features = false }
proptest = "1.0.0"
regex = "1.5.6"

[target.'cfg(cln_test)'.dev-dependencies]
clightningrpc = { version = "0.3.0-beta.8", default-features = false }
bitcoincore-rpc = { version = "0.16.0", default-features = false }

[build-dependencies]
uniffi = { version = "0.25.1", features = ["build"], optional = true }
Expand Down
23 changes: 0 additions & 23 deletions src/test/functional_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,29 +18,6 @@ fn channel_full_cycle() {
do_channel_full_cycle(node_a, node_b, &bitcoind, &electrsd, false);
}

#[test]
#[cfg(vss_test)]
fn channel_full_cycle_with_vss_store() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
println!("== Node A ==");
let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap());
let config_a = random_config();
let mut builder_a = NodeBuilder::from_config(config_a);
builder_a.set_esplora_server(esplora_url.clone());
let vss_base_url = std::env::var("TEST_VSS_BASE_URL").unwrap();
let node_a = builder_a.build_with_vss_store(&vss_base_url, "node_1_store".to_string()).unwrap();
node_a.start().unwrap();

println!("\n== Node B ==");
let config_b = random_config();
let mut builder_b = NodeBuilder::from_config(config_b);
builder_b.set_esplora_server(esplora_url);
let node_b = builder_b.build_with_vss_store(&vss_base_url, "node_2_store".to_string()).unwrap();
node_b.start().unwrap();

do_channel_full_cycle(node_a, node_b, &bitcoind, &electrsd, false);
}

#[test]
fn channel_full_cycle_0conf() {
let (bitcoind, electrsd) = setup_bitcoind_and_electrsd();
Expand Down
270 changes: 267 additions & 3 deletions tests/common.rs
Original file line number Diff line number Diff line change
@@ -1,24 +1,29 @@
#![cfg(cln_test)]
#![cfg(any(cln_test, vss_test))]

use ldk_node::{Config, LogLevel};
use ldk_node::{Config, Event, LogLevel, Node, NodeError, PaymentDirection, PaymentStatus};

use lightning::ln::msgs::SocketAddress;
use lightning::util::persist::KVStore;

use bitcoin::{Address, Amount, Network, OutPoint, Txid};

use bitcoincore_rpc::bitcoincore_rpc_json::AddressType;
use bitcoincore_rpc::Client as BitcoindClient;
use bitcoincore_rpc::RpcApi;

use electrum_client::Client as ElectrumClient;
use electrsd::{bitcoind, bitcoind::BitcoinD, ElectrsD};
use electrum_client::raw_client::{ElectrumPlaintextStream, RawClient};
use electrum_client::ElectrumApi;

use rand::distributions::Alphanumeric;
use rand::{thread_rng, Rng};

use std::env;
use std::path::PathBuf;
use std::time::Duration;

pub(crate) type ElectrumClient = RawClient<ElectrumPlaintextStream>;

macro_rules! expect_event {
($node: expr, $event_type: ident) => {{
match $node.wait_next_event() {
Expand Down Expand Up @@ -71,6 +76,26 @@ macro_rules! expect_channel_ready_event {

pub(crate) use expect_channel_ready_event;

pub(crate) fn setup_bitcoind_and_electrsd() -> (BitcoinD, ElectrsD) {
let bitcoind_exe =
env::var("BITCOIND_EXE").ok().or_else(|| bitcoind::downloaded_exe_path().ok()).expect(
"you need to provide an env var BITCOIND_EXE or specify a bitcoind version feature",
);
let mut bitcoind_conf = bitcoind::Conf::default();
bitcoind_conf.network = "regtest";
let bitcoind = BitcoinD::with_conf(bitcoind_exe, &bitcoind_conf).unwrap();

let electrs_exe = env::var("ELECTRS_EXE")
.ok()
.or_else(electrsd::downloaded_exe_path)
.expect("you need to provide env var ELECTRS_EXE or specify an electrsd version feature");
let mut electrsd_conf = electrsd::Conf::default();
electrsd_conf.http_enabled = true;
electrsd_conf.network = "regtest";
let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &electrsd_conf).unwrap();
(bitcoind, electrsd)
}

pub(crate) fn random_storage_path() -> PathBuf {
let mut temp_path = std::env::temp_dir();
let mut rng = thread_rng();
Expand Down Expand Up @@ -220,3 +245,242 @@ pub(crate) fn premine_and_distribute_funds(

generate_blocks_and_wait(bitcoind, electrs, 1);
}

pub(crate) fn do_channel_full_cycle<K: KVStore + Sync + Send>(
node_a: Node<K>, node_b: Node<K>, bitcoind: &BitcoindClient, electrsd: &ElectrumClient,
allow_0conf: bool,
) {
let addr_a = node_a.new_onchain_address().unwrap();
let addr_b = node_b.new_onchain_address().unwrap();

let premine_amount_sat = 100_000;

premine_and_distribute_funds(
&bitcoind,
&electrsd,
vec![addr_a, addr_b],
Amount::from_sat(premine_amount_sat),
);
node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();
assert_eq!(node_a.spendable_onchain_balance_sats().unwrap(), premine_amount_sat);
assert_eq!(node_b.spendable_onchain_balance_sats().unwrap(), premine_amount_sat);

// Check we haven't got any events yet
assert_eq!(node_a.next_event(), None);
assert_eq!(node_b.next_event(), None);

println!("\nA -- connect_open_channel -> B");
let funding_amount_sat = 80_000;
let push_msat = (funding_amount_sat / 2) * 1000; // balance the channel
node_a
.connect_open_channel(
node_b.node_id(),
node_b.listening_addresses().unwrap().first().unwrap().clone(),
funding_amount_sat,
Some(push_msat),
None,
true,
)
.unwrap();

assert_eq!(node_a.list_peers().first().unwrap().node_id, node_b.node_id());
let funding_txo_a = expect_channel_pending_event!(node_a, node_b.node_id());
let funding_txo_b = expect_channel_pending_event!(node_b, node_a.node_id());
assert_eq!(funding_txo_a, funding_txo_b);

wait_for_tx(&electrsd, funding_txo_a.txid);

if !allow_0conf {
generate_blocks_and_wait(&bitcoind, &electrsd, 6);
}

node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();

let onchain_fee_buffer_sat = 1500;
let node_a_upper_bound_sat = premine_amount_sat - funding_amount_sat;
let node_a_lower_bound_sat = premine_amount_sat - funding_amount_sat - onchain_fee_buffer_sat;
assert!(node_a.spendable_onchain_balance_sats().unwrap() < node_a_upper_bound_sat);
assert!(node_a.spendable_onchain_balance_sats().unwrap() > node_a_lower_bound_sat);
assert_eq!(node_b.spendable_onchain_balance_sats().unwrap(), premine_amount_sat);

expect_channel_ready_event!(node_a, node_b.node_id());

let ev = node_b.wait_next_event();
let channel_id = expect_channel_ready_event!(node_b, node_a.node_id());

println!("\nB receive_payment");
let invoice_amount_1_msat = 2500_000;
let invoice = node_b.receive_payment(invoice_amount_1_msat, &"asdf", 9217).unwrap();

println!("\nA send_payment");
let payment_hash = node_a.send_payment(&invoice).unwrap();
assert_eq!(node_a.send_payment(&invoice), Err(NodeError::DuplicatePayment));

assert_eq!(node_a.list_payments().first().unwrap().hash, payment_hash);

let outbound_payments_a =
node_a.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
assert_eq!(outbound_payments_a.len(), 1);

let inbound_payments_a =
node_a.list_payments_with_filter(|p| p.direction == PaymentDirection::Inbound);
assert_eq!(inbound_payments_a.len(), 0);

let outbound_payments_b =
node_b.list_payments_with_filter(|p| p.direction == PaymentDirection::Outbound);
assert_eq!(outbound_payments_b.len(), 0);

let inbound_payments_b =
node_b.list_payments_with_filter(|p| p.direction == PaymentDirection::Inbound);
assert_eq!(inbound_payments_b.len(), 1);

expect_event!(node_a, PaymentSuccessful);
expect_event!(node_b, PaymentReceived);
assert_eq!(node_a.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_a.payment(&payment_hash).unwrap().direction, PaymentDirection::Outbound);
assert_eq!(node_a.payment(&payment_hash).unwrap().amount_msat, Some(invoice_amount_1_msat));
assert_eq!(node_b.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_b.payment(&payment_hash).unwrap().direction, PaymentDirection::Inbound);
assert_eq!(node_b.payment(&payment_hash).unwrap().amount_msat, Some(invoice_amount_1_msat));

// Assert we fail duplicate outbound payments and check the status hasn't changed.
assert_eq!(Err(NodeError::DuplicatePayment), node_a.send_payment(&invoice));
assert_eq!(node_a.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_a.payment(&payment_hash).unwrap().direction, PaymentDirection::Outbound);
assert_eq!(node_a.payment(&payment_hash).unwrap().amount_msat, Some(invoice_amount_1_msat));
assert_eq!(node_b.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_b.payment(&payment_hash).unwrap().direction, PaymentDirection::Inbound);
assert_eq!(node_b.payment(&payment_hash).unwrap().amount_msat, Some(invoice_amount_1_msat));

// Test under-/overpayment
let invoice_amount_2_msat = 2500_000;
let invoice = node_b.receive_payment(invoice_amount_2_msat, &"asdf", 9217).unwrap();

let underpaid_amount = invoice_amount_2_msat - 1;
assert_eq!(
Err(NodeError::InvalidAmount),
node_a.send_payment_using_amount(&invoice, underpaid_amount)
);

println!("\nB overpaid receive_payment");
let invoice = node_b.receive_payment(invoice_amount_2_msat, &"asdf", 9217).unwrap();
let overpaid_amount_msat = invoice_amount_2_msat + 100;

println!("\nA overpaid send_payment");
let payment_hash = node_a.send_payment_using_amount(&invoice, overpaid_amount_msat).unwrap();
expect_event!(node_a, PaymentSuccessful);
let received_amount = match node_b.wait_next_event() {
ref e @ Event::PaymentReceived { amount_msat, .. } => {
println!("{} got event {:?}", std::stringify!(node_b), e);
node_b.event_handled();
amount_msat
}
ref e => {
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
}
};
assert_eq!(received_amount, overpaid_amount_msat);
assert_eq!(node_a.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_a.payment(&payment_hash).unwrap().direction, PaymentDirection::Outbound);
assert_eq!(node_a.payment(&payment_hash).unwrap().amount_msat, Some(overpaid_amount_msat));
assert_eq!(node_b.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_b.payment(&payment_hash).unwrap().direction, PaymentDirection::Inbound);
assert_eq!(node_b.payment(&payment_hash).unwrap().amount_msat, Some(overpaid_amount_msat));

// Test "zero-amount" invoice payment
println!("\nB receive_variable_amount_payment");
let variable_amount_invoice = node_b.receive_variable_amount_payment(&"asdf", 9217).unwrap();
let determined_amount_msat = 2345_678;
assert_eq!(Err(NodeError::InvalidInvoice), node_a.send_payment(&variable_amount_invoice));
println!("\nA send_payment_using_amount");
let payment_hash =
node_a.send_payment_using_amount(&variable_amount_invoice, determined_amount_msat).unwrap();

expect_event!(node_a, PaymentSuccessful);
let received_amount = match node_b.wait_next_event() {
ref e @ Event::PaymentReceived { amount_msat, .. } => {
println!("{} got event {:?}", std::stringify!(node_b), e);
node_b.event_handled();
amount_msat
}
ref e => {
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
}
};
assert_eq!(received_amount, determined_amount_msat);
assert_eq!(node_a.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_a.payment(&payment_hash).unwrap().direction, PaymentDirection::Outbound);
assert_eq!(node_a.payment(&payment_hash).unwrap().amount_msat, Some(determined_amount_msat));
assert_eq!(node_b.payment(&payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_b.payment(&payment_hash).unwrap().direction, PaymentDirection::Inbound);
assert_eq!(node_b.payment(&payment_hash).unwrap().amount_msat, Some(determined_amount_msat));

// Test spontaneous/keysend payments
println!("\nA send_spontaneous_payment");
let keysend_amount_msat = 2500_000;
let keysend_payment_hash =
node_a.send_spontaneous_payment(keysend_amount_msat, node_b.node_id()).unwrap();
expect_event!(node_a, PaymentSuccessful);
let received_keysend_amount = match node_b.wait_next_event() {
ref e @ Event::PaymentReceived { amount_msat, .. } => {
println!("{} got event {:?}", std::stringify!(node_b), e);
node_b.event_handled();
amount_msat
}
ref e => {
panic!("{} got unexpected event!: {:?}", std::stringify!(node_b), e);
}
};
assert_eq!(received_keysend_amount, keysend_amount_msat);
assert_eq!(node_a.payment(&keysend_payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(
node_a.payment(&keysend_payment_hash).unwrap().direction,
PaymentDirection::Outbound
);
assert_eq!(
node_a.payment(&keysend_payment_hash).unwrap().amount_msat,
Some(keysend_amount_msat)
);
assert_eq!(node_b.payment(&keysend_payment_hash).unwrap().status, PaymentStatus::Succeeded);
assert_eq!(node_b.payment(&keysend_payment_hash).unwrap().direction, PaymentDirection::Inbound);
assert_eq!(
node_b.payment(&keysend_payment_hash).unwrap().amount_msat,
Some(keysend_amount_msat)
);

println!("\nB close_channel");
node_b.close_channel(&channel_id, node_a.node_id()).unwrap();
expect_event!(node_a, ChannelClosed);
expect_event!(node_b, ChannelClosed);

wait_for_outpoint_spend(&electrsd, funding_txo_b);

generate_blocks_and_wait(&bitcoind, &electrsd, 1);
node_a.sync_wallets().unwrap();
node_b.sync_wallets().unwrap();

let sum_of_all_payments_sat = (push_msat
+ invoice_amount_1_msat
+ overpaid_amount_msat
+ determined_amount_msat
+ keysend_amount_msat)
/ 1000;
let node_a_upper_bound_sat =
(premine_amount_sat - funding_amount_sat) + (funding_amount_sat - sum_of_all_payments_sat);
let node_a_lower_bound_sat = node_a_upper_bound_sat - onchain_fee_buffer_sat;
assert!(node_a.spendable_onchain_balance_sats().unwrap() > node_a_lower_bound_sat);
assert!(node_a.spendable_onchain_balance_sats().unwrap() < node_a_upper_bound_sat);
let expected_final_amount_node_b_sat = premine_amount_sat + sum_of_all_payments_sat;
assert_eq!(node_b.spendable_onchain_balance_sats().unwrap(), expected_final_amount_node_b_sat);

// Check we handled all events
assert_eq!(node_a.next_event(), None);
assert_eq!(node_b.next_event(), None);

node_a.stop().unwrap();
println!("\nA stopped");
node_b.stop().unwrap();
println!("\nB stopped");
}
5 changes: 3 additions & 2 deletions tests/integration_tests_cln.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@

mod common;

use common::ElectrumClient;

use ldk_node::bitcoin::secp256k1::PublicKey;
use ldk_node::bitcoin::Amount;
use ldk_node::lightning::ln::msgs::SocketAddress;
Expand All @@ -13,7 +15,6 @@ use clightningrpc::responses::NetworkAddress;
use bitcoincore_rpc::Auth;
use bitcoincore_rpc::Client as BitcoindClient;

use electrum_client::Client as ElectrumClient;
use lightning_invoice::Bolt11Invoice;

use rand::distributions::Alphanumeric;
Expand All @@ -30,7 +31,7 @@ fn test_cln() {
Auth::UserPass("user".to_string(), "pass".to_string()),
)
.unwrap();
let electrs_client = ElectrumClient::new("tcp://127.0.0.1:50001").unwrap();
let electrs_client = ElectrumClient::new("tcp://127.0.0.1:50001", None).unwrap();

// Give electrs a kick.
common::generate_blocks_and_wait(&bitcoind_client, &electrs_client, 1);
Expand Down
Loading

0 comments on commit 193591e

Please sign in to comment.