From 3280cf18a8c441209f5978b3f16ab32d090e1894 Mon Sep 17 00:00:00 2001 From: Lucas Soriano del Pino Date: Thu, 18 Jan 2024 13:34:55 +1100 Subject: [PATCH 1/4] fix(tests-e2e): Delete another irrelevant test --- crates/tests-e2e/tests/maker.rs | 84 --------------------------------- 1 file changed, 84 deletions(-) delete mode 100644 crates/tests-e2e/tests/maker.rs diff --git a/crates/tests-e2e/tests/maker.rs b/crates/tests-e2e/tests/maker.rs deleted file mode 100644 index f3fe6f8ae..000000000 --- a/crates/tests-e2e/tests/maker.rs +++ /dev/null @@ -1,84 +0,0 @@ -use anyhow::Result; -use bitcoin::Amount; -use std::time::Duration; -use tests_e2e::bitcoind::Bitcoind; -use tests_e2e::coordinator::Coordinator; -use tests_e2e::http::init_reqwest; -use tests_e2e::logger::init_tracing; -use tests_e2e::maker::Maker; -use tests_e2e::wait_until; - -#[tokio::test] -#[ignore = "need to be run with 'just e2e' command"] -async fn maker_can_open_channel_to_coordinator_and_send_payment() -> Result<()> { - init_tracing(); - - let client = init_reqwest(); - - let coordinator = Coordinator::new_local(client.clone()); - assert!(coordinator.is_running().await); - - // Start maker after coordinator as its health check needs coordinator - let maker = Maker::new_local(client.clone()); - wait_until!(maker.is_running().await); - - let node_info_coordinator = coordinator.get_node_info().await?; - - // Ensure the maker has a free UTXO available. - let address = maker.get_new_address().await.unwrap(); - let bitcoind = Bitcoind::new_local(client.clone()); - bitcoind - .send_to_address(&address, Amount::ONE_BTC) - .await - .unwrap(); - bitcoind.mine(1).await.unwrap(); - maker.sync().await.unwrap(); - - let balance_maker_before_channel = maker.get_balance().await?.offchain; - - let outbound_liquidity_maker = 500_000; - maker - .open_channel(node_info_coordinator, outbound_liquidity_maker, None) - .await?; - - // Wait for the channel between maker and coordinator to be open. - tokio::time::sleep(Duration::from_secs(5)).await; - - // Mine one block to render the public channel is usable. - bitcoind.mine(1).await.unwrap(); - coordinator.sync_wallet().await.unwrap(); - maker.sync().await.unwrap(); - - let balance_maker_after_channel = maker.get_balance().await?.offchain; - - assert_eq!( - balance_maker_before_channel + outbound_liquidity_maker, - balance_maker_after_channel - ); - - let balance_coordinator_after_channel = coordinator.get_balance().await?.lightning; - - let payment_amount = 100_000; - let invoice = coordinator.create_invoice(Some(payment_amount)).await?; - - maker.pay_invoice(invoice).await?; - - wait_until!( - coordinator.get_balance().await.unwrap().lightning > balance_coordinator_after_channel - ); - - let balance_maker_after_payment = maker.get_balance().await?.offchain; - let balance_coordinator_after_payment = coordinator.get_balance().await?.lightning; - - assert_eq!( - balance_maker_after_channel - payment_amount, - balance_maker_after_payment - ); - - assert_eq!( - balance_coordinator_after_channel + payment_amount, - balance_coordinator_after_payment - ); - - Ok(()) -} From 0efb791602613f332d17c4fb7fa6b903249baadd Mon Sep 17 00:00:00 2001 From: Lucas Soriano del Pino Date: Thu, 18 Jan 2024 13:35:23 +1100 Subject: [PATCH 2/4] chore(tests-e2e): Delete dead code --- crates/tests-e2e/src/coordinator.rs | 183 ---------------------------- 1 file changed, 183 deletions(-) diff --git a/crates/tests-e2e/src/coordinator.rs b/crates/tests-e2e/src/coordinator.rs index 174618c72..18e1e75ce 100644 --- a/crates/tests-e2e/src/coordinator.rs +++ b/crates/tests-e2e/src/coordinator.rs @@ -1,18 +1,7 @@ use anyhow::Context; use anyhow::Result; use bitcoin::Address; -use bitcoin::Txid; -use commons::CollaborativeRevertCoordinatorExpertRequest; -use commons::CollaborativeRevertCoordinatorRequest; -use coordinator::admin::Balance; -use coordinator::routes::InvoiceParams; -use ln_dlc_node::lightning_invoice; -use ln_dlc_node::node::NodeInfo; use reqwest::Client; -use rust_decimal::Decimal; -use rust_decimal_macros::dec; -use serde::Deserialize; -use serde::Serialize; /// A wrapper over the coordinator HTTP API. /// @@ -22,41 +11,6 @@ pub struct Coordinator { host: String, } -#[derive(Deserialize)] -pub struct SubChannels { - #[serde(flatten)] - pub channel_details: Vec, -} - -#[derive(Deserialize, Debug)] -pub struct SubChannel { - pub channel_id: String, - pub dlc_channel_id: Option, - pub counter_party: String, - pub subchannel_state: SubChannelState, -} - -#[derive(Deserialize, Debug)] -pub struct Channel { - pub channel_id: String, - pub counterparty: String, - pub funding_txo: Option, - pub original_funding_txo: Option, - pub outbound_capacity_msat: u64, -} - -#[derive(Deserialize, Debug, PartialEq, Eq)] -pub enum SubChannelState { - Signed, - Closing, - OnChainClosed, - CounterOnChainClosed, - CloseConfirmed, - // We don't care about other states for now - #[serde(other)] - Other, -} - impl Coordinator { pub fn new(client: Client, host: &str) -> Self { Self { @@ -74,127 +28,15 @@ impl Coordinator { self.get("/health").await.is_ok() } - pub async fn is_node_connected(&self, node_id: &str) -> Result { - let result = self - .get(&format!("/api/admin/is_connected/{node_id}")) - .await? - .status() - .is_success(); - Ok(result) - } - pub async fn sync_wallet(&self) -> Result<()> { self.post("/api/admin/sync").await?; Ok(()) } - pub async fn pay_invoice(&self, invoice: &str) -> Result<()> { - self.post(&format!("/api/admin/send_payment/{invoice}")) - .await?; - Ok(()) - } - - pub async fn create_invoice( - &self, - amount: Option, - ) -> Result { - let invoice_params = InvoiceParams { - amount, - description: Some("Fee for tests".to_string()), - expiry: None, - }; - - let encoded_params = serde_urlencoded::to_string(&invoice_params)?; - - let invoice = self - .get(&format!("/api/invoice?{encoded_params}")) - .await? - .text() - .await? - .parse()?; - - Ok(invoice) - } - pub async fn get_new_address(&self) -> Result
{ Ok(self.get("/api/newaddress").await?.text().await?.parse()?) } - pub async fn get_balance(&self) -> Result { - Ok(self.get("/api/admin/wallet/balance").await?.json().await?) - } - - pub async fn get_node_info(&self) -> Result { - self.get("/api/node") - .await? - .json() - .await - .context("could not parse json") - } - - pub async fn broadcast_node_announcement(&self) -> Result { - let status = self - .post("/api/admin/broadcast_announcement") - .await? - .error_for_status()?; - Ok(status) - } - - pub async fn get_sub_channels(&self) -> Result> { - Ok(self.get("/api/admin/sub_channels").await?.json().await?) - } - - pub async fn force_close_channel(&self, channel_id: &str) -> Result { - self.delete(format!("/api/admin/channels/{channel_id}?force=true").as_str()) - .await - } - - pub async fn collaborative_revert_channel( - &self, - channel_id: &str, - txid: Txid, - vout: u32, - ) -> Result { - self.post_with_body( - "/api/admin/channels/revert", - &CollaborativeRevertCoordinatorRequest { - channel_id: channel_id.to_string(), - price: dec!(30_000.0), - fee_rate_sats_vb: 4, - txid, - vout, - }, - ) - .await - } - - pub async fn expert_collaborative_revert_channel( - &self, - channel_id: &str, - coordinator_amount: u64, - price: Decimal, - txid: Txid, - vout: u32, - ) -> Result { - self.post_with_body( - "/api/admin/channels/revert-expert", - &CollaborativeRevertCoordinatorExpertRequest { - channel_id: channel_id.to_string(), - coordinator_amount, - txid, - vout, - fee_rate_sats_vb: 4, - price, - }, - ) - .await - } - - pub async fn rollover(&self, dlc_channel_id: &str) -> Result { - self.post(format!("/api/rollover/{dlc_channel_id}").as_str()) - .await - } - async fn get(&self, path: &str) -> Result { self.client .get(format!("{0}{path}", self.host)) @@ -214,29 +56,4 @@ impl Coordinator { .error_for_status() .context("Coordinator did not return 200 OK") } - - async fn post_with_body( - &self, - path: &str, - body: &T, - ) -> Result { - self.client - .post(format!("{0}{path}", self.host)) - .json(body) - .send() - .await - .context("Could not send POST request to coordinator")? - .error_for_status() - .context("Coordinator did not return 200 OK") - } - - async fn delete(&self, path: &str) -> Result { - self.client - .delete(format!("{0}{path}", self.host)) - .send() - .await - .context("Could not send DELETE request to coordinator")? - .error_for_status() - .context("Coordinator did not return 200 OK") - } } From d9299161e83b41408eb7157a400d6006175e053e Mon Sep 17 00:00:00 2001 From: Lucas Soriano del Pino Date: Thu, 18 Jan 2024 13:35:34 +1100 Subject: [PATCH 3/4] fix(tests-e2e): Refresh wallet periodically after initial funding --- crates/tests-e2e/src/setup.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/crates/tests-e2e/src/setup.rs b/crates/tests-e2e/src/setup.rs index d83514754..2c297b9d5 100644 --- a/crates/tests-e2e/src/setup.rs +++ b/crates/tests-e2e/src/setup.rs @@ -73,9 +73,11 @@ impl TestSetup { .unwrap(); bitcoind.mine(1).await.unwrap(); - refresh_wallet_info(); - wait_until!(app.rx.wallet_info().unwrap().balances.on_chain == fund_amount.to_sat()); + wait_until!({ + refresh_wallet_info(); + app.rx.wallet_info().unwrap().balances.on_chain == fund_amount.to_sat() + }); let on_chain_balance = app.rx.wallet_info().unwrap().balances.on_chain; From 2dccdd856f95f9eab74ef9a9af5c82fbde4e209f Mon Sep 17 00:00:00 2001 From: Lucas Soriano del Pino Date: Thu, 18 Jan 2024 13:36:37 +1100 Subject: [PATCH 4/4] fix(coordinator): Allow requests with up to 50MB bodies By default this is set to 2MB, according to the docs[1]. We need larger bodies than before (even in the e2e test!), because we added lots of CET adaptor signatures to the database recently[2]. I also played around with nginx's `client_max_body_size`, but that's actually irrelevant since we don't use nginx as a reverse proxy for the coordinator in the e2e tests. Related to https://github.com/get10101/10101/issues/1719. [1]: https://docs.rs/axum/latest/axum/extract/struct.DefaultBodyLimit.html#method.disable. [2]: https://github.com/get10101/10101/pull/1817. --- coordinator/src/routes.rs | 3 + crates/tests-e2e/tests/restore_from_backup.rs | 91 ++++++++++--------- 2 files changed, 51 insertions(+), 43 deletions(-) diff --git a/coordinator/src/routes.rs b/coordinator/src/routes.rs index bb015c6fb..769c8297f 100644 --- a/coordinator/src/routes.rs +++ b/coordinator/src/routes.rs @@ -30,6 +30,7 @@ use crate::parse_dlc_channel_id; use crate::settings::Settings; use crate::settings::SettingsFile; use crate::AppError; +use axum::extract::DefaultBodyLimit; use axum::extract::Path; use axum::extract::Query; use axum::extract::State; @@ -170,6 +171,8 @@ pub fn router( ) .route("/metrics", get(get_metrics)) .route("/health", get(get_health)) + .layer(DefaultBodyLimit::disable()) + .layer(DefaultBodyLimit::max(50 * 1024)) .with_state(app_state) } diff --git a/crates/tests-e2e/tests/restore_from_backup.rs b/crates/tests-e2e/tests/restore_from_backup.rs index 94a677faa..eaf65e8a0 100644 --- a/crates/tests-e2e/tests/restore_from_backup.rs +++ b/crates/tests-e2e/tests/restore_from_backup.rs @@ -1,47 +1,52 @@ +use native::api; +use native::trade::position::PositionState; +use tests_e2e::app::run_app; +use tests_e2e::logger::init_tracing; +use tests_e2e::setup; +use tests_e2e::setup::dummy_order; +use tests_e2e::wait_until; +use tokio::task::spawn_blocking; + #[tokio::test(flavor = "multi_thread")] #[ignore = "need to be run with 'just e2e' command"] async fn app_can_be_restored_from_a_backup() { - // TODO: this should be re-implemented - // init_tracing(); - // - // let test = setup::TestSetup::new_with_open_position().await; - // - // let seed_phrase = api::get_seed_phrase(); - // - // let off_chain = test.app.rx.wallet_info().unwrap().balances.off_chain; - // - // // kill the app - // test.app.stop(); - // tracing::info!("Shutting down app!"); - // - // let app = run_app(Some(seed_phrase.0)).await; - // - // assert_eq!(app.rx.wallet_info().unwrap().balances.off_chain, off_chain); - // - // let positions = spawn_blocking(|| api::get_positions().unwrap()) - // .await - // .unwrap(); - // assert_eq!(1, positions.len()); - // - // // Test if full backup is running without errors - // spawn_blocking(|| api::full_backup().unwrap()) - // .await - // .unwrap(); - // - // wait_until!(test.app.rx.channel_status().unwrap() == ChannelStatus::WithPosition); - //ip - - // let closing_order = { - // let mut order = dummy_order(); - // order.direction = api::Direction::Short; - // order - // }; - // - // tracing::info!("Closing a position"); - // spawn_blocking(move || api::submit_order(closing_order).unwrap()) - // .await - // .unwrap(); - // - // wait_until!(test.app.rx.position().unwrap().position_state == PositionState::Closing); - // wait_until!(test.app.rx.position_close().is_some()); + init_tracing(); + + let test = setup::TestSetup::new_with_open_position().await; + + let seed_phrase = api::get_seed_phrase(); + + let off_chain = test.app.rx.wallet_info().unwrap().balances.off_chain; + + // kill the app + test.app.stop(); + tracing::info!("Shutting down app!"); + + let app = run_app(Some(seed_phrase.0)).await; + + assert_eq!(app.rx.wallet_info().unwrap().balances.off_chain, off_chain); + + let positions = spawn_blocking(|| api::get_positions().unwrap()) + .await + .unwrap(); + assert_eq!(1, positions.len()); + + // Test if full backup is running without errors + spawn_blocking(|| api::full_backup().unwrap()) + .await + .unwrap(); + + let closing_order = { + let mut order = dummy_order(); + order.direction = api::Direction::Short; + order + }; + + tracing::info!("Closing a position"); + spawn_blocking(move || api::submit_order(closing_order).unwrap()) + .await + .unwrap(); + + wait_until!(test.app.rx.position().unwrap().position_state == PositionState::Closing); + wait_until!(test.app.rx.position_close().is_some()); }