From 4150f47655c2f120d724245d792aca5b10c4b9e9 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Sun, 20 Aug 2023 00:38:56 +0200 Subject: [PATCH 01/10] Add note regarding Request, Method structs --- swap/src/api/request.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index 06838531..f2c3e47c 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -23,6 +23,7 @@ use std::time::Duration; use tracing::{debug_span, Instrument, Span}; use uuid::Uuid; +//TODO: Request and Method can be combined into a single enum #[derive(PartialEq, Debug)] pub struct Request { pub cmd: Method, From b98108df065ad6cafe798ab5b3f73af456c09cbd Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Sun, 20 Aug 2023 00:40:21 +0200 Subject: [PATCH 02/10] Update request.rs --- swap/src/api/request.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index f2c3e47c..a91ae788 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -160,7 +160,6 @@ impl Request { let state_name = format!("{:?}", swap_state); - // variable timelock: Option> let timelock = match swap_state { BobState::Started { .. } | BobState::SafelyAborted @@ -182,7 +181,7 @@ impl Request { | BobState::XmrRedeemed { .. } => None, }; - // Add txids + // TODO: Add relevant txids Ok(json!({ "seller": { "peerId": peerId.to_string(), From 4bcdb1995a053f49a2eb8375a21721b4f723cc11 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Wed, 23 Aug 2023 00:37:25 +0200 Subject: [PATCH 03/10] Add tracing span attribute log_reference_id to logs caused by rpc call --- swap/src/api/request.rs | 70 +++++++++------ swap/src/cli/tracing.rs | 1 - swap/src/rpc/methods.rs | 189 +++++++++++++++++----------------------- 3 files changed, 121 insertions(+), 139 deletions(-) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index a91ae788..85462d4c 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -15,18 +15,18 @@ use qrcode::QrCode; use serde_json::json; use std::cmp::min; use std::convert::TryInto; -use std::fmt::Formatter; use std::future::Future; use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; -use tracing::{debug_span, Instrument, Span}; +use tracing::{debug_span, Instrument, Span, field}; use uuid::Uuid; //TODO: Request and Method can be combined into a single enum #[derive(PartialEq, Debug)] pub struct Request { pub cmd: Method, + pub log_reference: Option, } #[derive(Debug, PartialEq)] @@ -69,52 +69,60 @@ pub enum Method { } impl Method { - fn get_tracing_span(&self) -> Span { - match self { - Method::Balance => debug_span!("method", name = "Balance"), + fn get_tracing_span(&self, log_reference_id: Option) -> Span { + let span = match self { + Method::Balance => debug_span!("method", name = "Balance", log_reference_id=field::Empty), Method::BuyXmr { swap_id, .. } => { - debug_span!("method", name="BuyXmr", swap_id=%swap_id) + debug_span!("method", name="BuyXmr", swap_id=%swap_id, log_reference_id=field::Empty) } Method::CancelAndRefund { swap_id } => { - debug_span!("method", name="CancelAndRefund", swap_id=%swap_id) + debug_span!("method", name="CancelAndRefund", swap_id=%swap_id, log_reference_id=field::Empty) } Method::Resume { swap_id } => { - debug_span!("method", name="Resume", swap_id=%swap_id) + debug_span!("method", name="Resume", swap_id=%swap_id, log_reference_id=field::Empty) } - Method::Config => debug_span!("method", name = "Config"), + Method::Config => debug_span!("method", name = "Config", log_reference_id=field::Empty), Method::ExportBitcoinWallet => { - debug_span!("method", name = "ExportBitcoinWallet") + debug_span!("method", name = "ExportBitcoinWallet", log_reference_id=field::Empty) } Method::GetCurrentSwap => { - debug_span!("method", name = "GetCurrentSwap") + debug_span!("method", name = "GetCurrentSwap", log_reference_id=field::Empty) } Method::GetSwapInfo { .. } => { - debug_span!("method", name = "GetSwapInfo") + debug_span!("method", name = "GetSwapInfo", log_reference_id=field::Empty) } - Method::History => debug_span!("method", name = "History"), + Method::History => debug_span!("method", name = "History", log_reference_id=field::Empty), Method::ListSellers { .. } => { - debug_span!("method", name = "ListSellers") + debug_span!("method", name = "ListSellers", log_reference_id=field::Empty) } Method::MoneroRecovery { .. } => { - debug_span!("method", name = "MoneroRecovery") + debug_span!("method", name = "MoneroRecovery", log_reference_id=field::Empty) } - Method::RawHistory => debug_span!("method", name = "RawHistory"), + Method::RawHistory => debug_span!("method", name = "RawHistory", log_reference_id=field::Empty), Method::StartDaemon { .. } => { - debug_span!("method", name = "StartDaemon") + debug_span!("method", name = "StartDaemon", log_reference_id=field::Empty) } Method::SuspendCurrentSwap => { - debug_span!("method", name = "SuspendCurrentSwap") + debug_span!("method", name = "SuspendCurrentSwap", log_reference_id=field::Empty) } Method::WithdrawBtc { .. } => { - debug_span!("method", name = "WithdrawBtc") + debug_span!("method", name = "WithdrawBtc", log_reference_id=field::Empty) } + }; + if let Some(log_reference_id) = log_reference_id { + span.record("log_reference_id", &log_reference_id.as_str()); } + span } } impl Request { pub fn new(cmd: Method) -> Request { - Request { cmd } + Request { cmd, log_reference: None } + } + + pub fn with_id(cmd: Method, id: Option) -> Request { + Request { cmd, log_reference: id } } // We pass the outer tracing span down to this function such that it can be passed down to other spawned tokio tasks @@ -126,13 +134,18 @@ impl Request { ) -> Result { match self.cmd { Method::SuspendCurrentSwap => { - context.swap_lock.send_suspend_signal().await?; let swap_id = context.swap_lock.get_current_swap_id().await; - Ok(json!({ - "swapId": swap_id, - "success": true - })) + if swap_id.is_some() { + context.swap_lock.send_suspend_signal().await?; + + Ok(json!({ + "success": true, + "swapId": swap_id.unwrap() + })) + } else { + bail!("No swap is currently running") + } } Method::GetSwapInfo { swap_id } => { let bitcoin_wallet = context @@ -158,7 +171,7 @@ impl Request { let start_date = context.db.get_swap_start_date(swap_id).await?; - let state_name = format!("{:?}", swap_state); + let state_name = format!("{}", swap_state); let timelock = match swap_state { BobState::Started { .. } @@ -183,6 +196,7 @@ impl Request { // TODO: Add relevant txids Ok(json!({ + "swapId": swap_id, "seller": { "peerId": peerId.to_string(), "addresses": addresses @@ -191,6 +205,7 @@ impl Request { "startDate": start_date, // If none return null, if some unwrap and return as json "timelock": timelock.map(|tl| tl.map(|tl| json!(tl)).unwrap_or(json!(null))).unwrap_or(json!(null)), + // Use display to get the string representation of the state "stateName": state_name, })) } @@ -662,7 +677,7 @@ impl Request { } pub async fn call(self, context: Arc) -> Result { - let method_span = self.cmd.get_tracing_span(); + let method_span = self.cmd.get_tracing_span(self.log_reference.clone()); self.handle_cmd(context, method_span.clone()) .instrument(method_span) @@ -679,6 +694,7 @@ fn qr_code(value: &impl ToString) -> Result { .build(); Ok(qr_code) } + pub async fn determine_btc_to_swap( json: bool, bid_quote: impl Future>, diff --git a/swap/src/cli/tracing.rs b/swap/src/cli/tracing.rs index 5a360d1e..1ede1e8a 100644 --- a/swap/src/cli/tracing.rs +++ b/swap/src/cli/tracing.rs @@ -22,7 +22,6 @@ pub fn init(debug: bool, json: bool, dir: impl AsRef) -> Result<()> { fmt::layer() .with_ansi(false) .with_target(false) - .with_span_events(fmt::format::FmtSpan::FULL) .json() .with_writer(appender), ); diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index 0572636c..32559a1b 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -9,73 +9,93 @@ use libp2p::core::Multiaddr; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; +use jsonrpsee::types::Params; use uuid::Uuid; pub fn register_modules(context: Arc) -> RpcModule> { let mut module = RpcModule::new(context); module - .register_async_method("suspend_current_swap", |_, context| async move { - execute_request(Method::SuspendCurrentSwap, &context).await + .register_async_method("suspend_current_swap", |params, context| async move { + execute_request(params, Method::SuspendCurrentSwap, &context).await }) .unwrap(); module - .register_async_method("get_swap_info", |params, context| async move { - let params: HashMap = params.parse()?; + .register_async_method("get_swap_info", |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; let swap_id = params.get("swap_id").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()) })?; - get_swap_info(*swap_id, &context).await + execute_request( + params_raw, + Method::GetSwapInfo { + swap_id: *swap_id, + }, + &context, + ).await }) .unwrap(); module - .register_async_method("get_bitcoin_balance", |_, context| async move { - get_bitcoin_balance(&context).await + .register_async_method("get_bitcoin_balance", |params, context| async move { + execute_request(params, Method::Balance, &context).await }) .unwrap(); module - .register_async_method("get_history", |_, context| async move { - get_history(&context).await + .register_async_method("get_history", |params, context| async move { + execute_request(params, Method::History, &context).await }) .unwrap(); module - .register_async_method("get_raw_history", |_, context| async move { - get_raw_history(&context).await + .register_async_method("get_raw_history", |params, context| async move { + execute_request(params, Method::RawHistory, &context).await }) .unwrap(); module - .register_async_method("resume_swap", |params, context| async move { - let params: HashMap = params.parse()?; + .register_async_method("resume_swap", |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; let swap_id = params.get("swap_id").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()) })?; - resume_swap(*swap_id, &context).await + execute_request( + params_raw, + Method::Resume { + swap_id: *swap_id, + }, + &context, + ).await }) .unwrap(); module - .register_async_method("cancel_refund_swap", |params, context| async move { - let params: HashMap = params.parse()?; + .register_async_method("cancel_refund_swap", |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; let swap_id = params.get("swap_id").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()) })?; - cancel_and_refund_swap(*swap_id, &context).await + execute_request( + params_raw, + Method::CancelAndRefund { + swap_id: *swap_id, + }, + &context, + ).await }) .unwrap(); + module - .register_async_method("withdraw_btc", |params, context| async move { - let params: HashMap = params.parse()?; + .register_async_method("withdraw_btc", |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; let amount = if let Some(amount_str) = params.get("amount") { Some( @@ -96,12 +116,19 @@ pub fn register_modules(context: Arc) -> RpcModule> { let withdraw_address = bitcoin_address::validate(withdraw_address, context.config.is_testnet)?; - withdraw_btc(withdraw_address, amount, &context).await + execute_request( + params_raw, + Method::WithdrawBtc { + amount, + address: withdraw_address, + }, + &context, + ).await }) .expect("Could not register RPC method withdraw_btc"); module - .register_async_method("buy_xmr", |params, context| async move { - let params: HashMap = params.parse()?; + .register_async_method("buy_xmr", |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; let bitcoin_change_address = bitcoin::Address::from_str( params.get("bitcoin_change_address").ok_or_else(|| { @@ -132,29 +159,38 @@ pub fn register_modules(context: Arc) -> RpcModule> { })?) .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; - buy_xmr( - bitcoin_change_address, - monero_receive_address, - seller, + execute_request( + params_raw, + Method::BuyXmr { + bitcoin_change_address, + monero_receive_address, + seller, + swap_id: Uuid::new_v4(), + }, &context, - ) - .await + ).await }) .unwrap(); module - .register_async_method("list_sellers", |params, context| async move { - let params: HashMap = params.parse()?; + .register_async_method("list_sellers", |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; let rendezvous_point = params.get("rendezvous_point").ok_or_else(|| { jsonrpsee_core::Error::Custom("Does not contain rendezvous_point".to_string()) })?; - list_sellers(rendezvous_point.clone(), &context).await + execute_request( + params_raw, + Method::ListSellers { + rendezvous_point: rendezvous_point.clone(), + }, + &context, + ).await }) .unwrap(); module - .register_async_method("get_current_swap", |_, context| async move { - get_current_swap(&context).await + .register_async_method("get_current_swap", |params, context| async move { + execute_request(params, Method::GetCurrentSwap, &context).await }) .unwrap(); @@ -162,88 +198,19 @@ pub fn register_modules(context: Arc) -> RpcModule> { } async fn execute_request( + params: Params<'static>, cmd: Method, context: &Arc, ) -> Result { - let request = Request::new(cmd); + let params_parsed = params.parse::>() + .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; + + let reference_id = params_parsed + .get("log_reference_id"); + + let request = Request::with_id(cmd, reference_id.map(|s| s.clone())); request .call(Arc::clone(context)) .await .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string())) -} - -async fn get_current_swap( - context: &Arc, -) -> Result { - execute_request(Method::GetCurrentSwap, context).await -} - -async fn get_bitcoin_balance( - context: &Arc, -) -> Result { - execute_request(Method::Balance, context).await -} - -async fn get_history(context: &Arc) -> Result { - execute_request(Method::History, context).await -} - -async fn get_raw_history( - context: &Arc, -) -> Result { - execute_request(Method::RawHistory, context).await -} - -async fn get_swap_info( - swap_id: Uuid, - context: &Arc, -) -> Result { - execute_request(Method::GetSwapInfo { swap_id }, context).await -} - -async fn resume_swap( - swap_id: Uuid, - context: &Arc, -) -> Result { - execute_request(Method::Resume { swap_id }, context).await -} - -async fn cancel_and_refund_swap( - swap_id: Uuid, - context: &Arc, -) -> Result { - execute_request(Method::CancelAndRefund { swap_id }, context).await -} - -async fn withdraw_btc( - address: bitcoin::Address, - amount: Option, - context: &Arc, -) -> Result { - execute_request(Method::WithdrawBtc { amount, address }, context).await -} - -async fn buy_xmr( - bitcoin_change_address: bitcoin::Address, - monero_receive_address: monero::Address, - seller: Multiaddr, - context: &Arc, -) -> Result { - execute_request( - Method::BuyXmr { - seller, - swap_id: Uuid::new_v4(), - bitcoin_change_address, - monero_receive_address, - }, - context, - ) - .await -} - -async fn list_sellers( - rendezvous_point: Multiaddr, - context: &Arc, -) -> Result { - execute_request(Method::ListSellers { rendezvous_point }, context).await -} +} \ No newline at end of file From dac9d96c392e076c15c78d33cbd49c68044822ab Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Thu, 24 Aug 2023 14:26:28 +0200 Subject: [PATCH 04/10] Sync bitcoin wallet before initial max_giveable call --- swap/src/api/request.rs | 93 +++++++++++++++++++++++++++++++---------- swap/src/rpc/methods.rs | 41 ++++++++---------- 2 files changed, 89 insertions(+), 45 deletions(-) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index 85462d4c..d5a2dc87 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -19,7 +19,7 @@ use std::future::Future; use std::net::SocketAddr; use std::sync::Arc; use std::time::Duration; -use tracing::{debug_span, Instrument, Span, field}; +use tracing::{debug_span, field, Instrument, Span}; use uuid::Uuid; //TODO: Request and Method can be combined into a single enum @@ -71,7 +71,9 @@ pub enum Method { impl Method { fn get_tracing_span(&self, log_reference_id: Option) -> Span { let span = match self { - Method::Balance => debug_span!("method", name = "Balance", log_reference_id=field::Empty), + Method::Balance => { + debug_span!("method", name = "Balance", log_reference_id = field::Empty) + } Method::BuyXmr { swap_id, .. } => { debug_span!("method", name="BuyXmr", swap_id=%swap_id, log_reference_id=field::Empty) } @@ -81,32 +83,72 @@ impl Method { Method::Resume { swap_id } => { debug_span!("method", name="Resume", swap_id=%swap_id, log_reference_id=field::Empty) } - Method::Config => debug_span!("method", name = "Config", log_reference_id=field::Empty), + Method::Config => { + debug_span!("method", name = "Config", log_reference_id = field::Empty) + } Method::ExportBitcoinWallet => { - debug_span!("method", name = "ExportBitcoinWallet", log_reference_id=field::Empty) + debug_span!( + "method", + name = "ExportBitcoinWallet", + log_reference_id = field::Empty + ) } Method::GetCurrentSwap => { - debug_span!("method", name = "GetCurrentSwap", log_reference_id=field::Empty) + debug_span!( + "method", + name = "GetCurrentSwap", + log_reference_id = field::Empty + ) } Method::GetSwapInfo { .. } => { - debug_span!("method", name = "GetSwapInfo", log_reference_id=field::Empty) + debug_span!( + "method", + name = "GetSwapInfo", + log_reference_id = field::Empty + ) + } + Method::History => { + debug_span!("method", name = "History", log_reference_id = field::Empty) } - Method::History => debug_span!("method", name = "History", log_reference_id=field::Empty), Method::ListSellers { .. } => { - debug_span!("method", name = "ListSellers", log_reference_id=field::Empty) + debug_span!( + "method", + name = "ListSellers", + log_reference_id = field::Empty + ) } Method::MoneroRecovery { .. } => { - debug_span!("method", name = "MoneroRecovery", log_reference_id=field::Empty) + debug_span!( + "method", + name = "MoneroRecovery", + log_reference_id = field::Empty + ) } - Method::RawHistory => debug_span!("method", name = "RawHistory", log_reference_id=field::Empty), + Method::RawHistory => debug_span!( + "method", + name = "RawHistory", + log_reference_id = field::Empty + ), Method::StartDaemon { .. } => { - debug_span!("method", name = "StartDaemon", log_reference_id=field::Empty) + debug_span!( + "method", + name = "StartDaemon", + log_reference_id = field::Empty + ) } Method::SuspendCurrentSwap => { - debug_span!("method", name = "SuspendCurrentSwap", log_reference_id=field::Empty) + debug_span!( + "method", + name = "SuspendCurrentSwap", + log_reference_id = field::Empty + ) } Method::WithdrawBtc { .. } => { - debug_span!("method", name = "WithdrawBtc", log_reference_id=field::Empty) + debug_span!( + "method", + name = "WithdrawBtc", + log_reference_id = field::Empty + ) } }; if let Some(log_reference_id) = log_reference_id { @@ -118,11 +160,17 @@ impl Method { impl Request { pub fn new(cmd: Method) -> Request { - Request { cmd, log_reference: None } + Request { + cmd, + log_reference: None, + } } pub fn with_id(cmd: Method, id: Option) -> Request { - Request { cmd, log_reference: id } + Request { + cmd, + log_reference: id, + } } // We pass the outer tracing span down to this function such that it can be passed down to other spawned tokio tasks @@ -703,21 +751,21 @@ pub async fn determine_btc_to_swap( max_giveable_fn: FMG, sync: FS, estimate_fee: FFE, -) -> Result<(bitcoin::Amount, bitcoin::Amount)> +) -> Result<(Amount, Amount)> where - TB: Future>, + TB: Future>, FB: Fn() -> TB, - TMG: Future>, + TMG: Future>, FMG: Fn() -> TMG, TS: Future>, FS: Fn() -> TS, - FFE: Fn(bitcoin::Amount) -> TFE, - TFE: Future>, + FFE: Fn(Amount) -> TFE, + TFE: Future>, { tracing::debug!("Requesting quote"); let bid_quote = bid_quote.await?; - if bid_quote.max_quantity == bitcoin::Amount::ZERO { + if bid_quote.max_quantity == Amount::ZERO { bail!(ZeroQuoteReceived) } @@ -728,9 +776,10 @@ where "Received quote", ); + sync().await?; let mut max_giveable = max_giveable_fn().await?; - if max_giveable == bitcoin::Amount::ZERO || max_giveable < bid_quote.min_quantity { + if max_giveable == Amount::ZERO || max_giveable < bid_quote.min_quantity { let deposit_address = get_new_address.await?; let minimum_amount = bid_quote.min_quantity; let maximum_amount = bid_quote.max_quantity; diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index 32559a1b..9144cfbb 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -5,11 +5,11 @@ use crate::monero::monero_address; use crate::{bitcoin, monero}; use anyhow::Result; use jsonrpsee::server::RpcModule; +use jsonrpsee::types::Params; use libp2p::core::Multiaddr; use std::collections::HashMap; use std::str::FromStr; use std::sync::Arc; -use jsonrpsee::types::Params; use uuid::Uuid; pub fn register_modules(context: Arc) -> RpcModule> { @@ -31,11 +31,10 @@ pub fn register_modules(context: Arc) -> RpcModule> { execute_request( params_raw, - Method::GetSwapInfo { - swap_id: *swap_id, - }, + Method::GetSwapInfo { swap_id: *swap_id }, &context, - ).await + ) + .await }) .unwrap(); @@ -65,13 +64,7 @@ pub fn register_modules(context: Arc) -> RpcModule> { jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()) })?; - execute_request( - params_raw, - Method::Resume { - swap_id: *swap_id, - }, - &context, - ).await + execute_request(params_raw, Method::Resume { swap_id: *swap_id }, &context).await }) .unwrap(); @@ -85,11 +78,10 @@ pub fn register_modules(context: Arc) -> RpcModule> { execute_request( params_raw, - Method::CancelAndRefund { - swap_id: *swap_id, - }, + Method::CancelAndRefund { swap_id: *swap_id }, &context, - ).await + ) + .await }) .unwrap(); @@ -123,7 +115,8 @@ pub fn register_modules(context: Arc) -> RpcModule> { address: withdraw_address, }, &context, - ).await + ) + .await }) .expect("Could not register RPC method withdraw_btc"); module @@ -168,7 +161,8 @@ pub fn register_modules(context: Arc) -> RpcModule> { swap_id: Uuid::new_v4(), }, &context, - ).await + ) + .await }) .unwrap(); module @@ -184,7 +178,8 @@ pub fn register_modules(context: Arc) -> RpcModule> { rendezvous_point: rendezvous_point.clone(), }, &context, - ).await + ) + .await }) .unwrap(); @@ -202,15 +197,15 @@ async fn execute_request( cmd: Method, context: &Arc, ) -> Result { - let params_parsed = params.parse::>() + let params_parsed = params + .parse::>() .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string()))?; - let reference_id = params_parsed - .get("log_reference_id"); + let reference_id = params_parsed.get("log_reference_id"); let request = Request::with_id(cmd, reference_id.map(|s| s.clone())); request .call(Arc::clone(context)) .await .map_err(|err| jsonrpsee_core::Error::Custom(err.to_string())) -} \ No newline at end of file +} From 8719896fdbeff633f390869705201e0a5888fa56 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Thu, 24 Aug 2023 18:17:41 +0200 Subject: [PATCH 05/10] use Span::current() to pass down to tracing span to spawned tasks --- swap/src/api/request.rs | 16 ++++++---------- swap/src/bitcoin/wallet.rs | 3 ++- 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index d5a2dc87..110e7b2a 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -178,7 +178,6 @@ impl Request { async fn handle_cmd( self, context: Arc, - tracing_span: Span, ) -> Result { match self.cmd { Method::SuspendCurrentSwap => { @@ -265,8 +264,6 @@ impl Request { } => { context.swap_lock.acquire_swap_lock(swap_id).await?; - let tracing_span_clone = tracing_span.clone(); - tokio::spawn(async move { tokio::select! { biased; @@ -311,7 +308,7 @@ impl Request { let (event_loop, mut event_loop_handle) = EventLoop::new(swap_id, swarm, seller_peer_id)?; - let event_loop = tokio::spawn(event_loop.run().instrument(tracing_span_clone.clone())); + let event_loop = tokio::spawn(event_loop.run().instrument(Span::current())); let max_givable = || bitcoin_wallet.max_giveable(TxLock::script_size()); let estimate_fee = |amount| bitcoin_wallet.estimate_fee(TxLock::weight(), amount); @@ -394,7 +391,7 @@ impl Request { .release_swap_lock() .await .expect("Could not release swap lock"); - }.instrument(tracing_span)); + }.instrument(Span::current())); Ok(json!({ "swapId": swap_id.to_string(), @@ -402,7 +399,6 @@ impl Request { } Method::Resume { swap_id } => { context.swap_lock.acquire_swap_lock(swap_id).await?; - let tracing_span_clone = tracing_span.clone(); tokio::spawn(async move { tokio::select! { @@ -449,7 +445,7 @@ impl Request { let (event_loop, event_loop_handle) = EventLoop::new(swap_id, swarm, seller_peer_id)?; - let handle = tokio::spawn(event_loop.run().instrument(tracing_span_clone)); + let handle = tokio::spawn(event_loop.run().instrument(Span::current())); let monero_receive_address = context.db.get_monero_address(swap_id).await?; let swap = Swap::from_db( @@ -495,7 +491,7 @@ impl Request { .release_swap_lock() .await .expect("Could not release swap lock"); - }.instrument(tracing_span)); + }.instrument(Span::current())); Ok(json!({ "result": "ok", })) @@ -725,9 +721,9 @@ impl Request { } pub async fn call(self, context: Arc) -> Result { - let method_span = self.cmd.get_tracing_span(self.log_reference.clone()); + let method_span = self.cmd.get_tracing_span(self.log_reference.clone()).clone(); - self.handle_cmd(context, method_span.clone()) + self.handle_cmd(context) .instrument(method_span) .await } diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index 6aed30da..c1f8565c 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -24,6 +24,7 @@ use std::path::Path; use std::sync::Arc; use std::time::{Duration, Instant}; use tokio::sync::{watch, Mutex}; +use tracing::{Instrument, Span}; const SLED_TREE_NAME: &str = "default_tree"; @@ -192,7 +193,7 @@ impl Wallet { tokio::time::sleep(Duration::from_secs(5)).await; } - }); + }.instrument(Span::current())); Subscription { receiver, From 63afad08749b9952c7c52c2bce8df8b690dbd38c Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Mon, 28 Aug 2023 00:24:16 +0200 Subject: [PATCH 06/10] Remove unused shutdown channel --- swap/src/bin/swap.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/swap/src/bin/swap.rs b/swap/src/bin/swap.rs index 4d920fae..8cea4033 100644 --- a/swap/src/bin/swap.rs +++ b/swap/src/bin/swap.rs @@ -17,11 +17,9 @@ use std::env; use std::sync::Arc; use swap::cli::command::{parse_args_and_apply_defaults, ParseResult}; use swap::common::check_latest_version; -use tokio::sync::broadcast; #[tokio::main] async fn main() -> Result<()> { - let (tx, _) = broadcast::channel(1); let (context, request) = match parse_args_and_apply_defaults(env::args_os()).await? { ParseResult::Context(context, request) => (context, request), ParseResult::PrintAndExitZero { message } => { @@ -34,7 +32,6 @@ async fn main() -> Result<()> { eprintln!("{}", e); } let _result = request.call(Arc::clone(&context)).await?; - tx.send(())?; Ok(()) } From 4623a08ebf134da0afa494616bcf0eaf6b438328 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Mon, 28 Aug 2023 00:47:32 +0200 Subject: [PATCH 07/10] Add `get_monero_recovery_info` RPC endpoint - Add `get_monero_recovery_info` RPC endpoint - format PrivateViewKey using Display --- swap/src/api/request.rs | 64 ++++++++++++++++------------------------- swap/src/monero.rs | 7 +++++ swap/src/rpc/methods.rs | 24 +++++++++++++++- 3 files changed, 54 insertions(+), 41 deletions(-) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index 110e7b2a..c0e87474 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -173,12 +173,7 @@ impl Request { } } - // We pass the outer tracing span down to this function such that it can be passed down to other spawned tokio tasks - // This ensures that tasks like the event_loop are all part of the same tracing span - async fn handle_cmd( - self, - context: Arc, - ) -> Result { + async fn handle_cmd(self, context: Arc) -> Result { match self.cmd { Method::SuspendCurrentSwap => { let swap_id = context.swap_lock.get_current_swap_id().await; @@ -679,40 +674,28 @@ impl Request { Method::MoneroRecovery { swap_id } => { let swap_state: BobState = context.db.get_state(swap_id).await?.try_into()?; - match swap_state { - BobState::Started { .. } - | BobState::SwapSetupCompleted(_) - | BobState::BtcLocked { .. } - | BobState::XmrLockProofReceived { .. } - | BobState::XmrLocked(_) - | BobState::EncSigSent(_) - | BobState::CancelTimelockExpired(_) - | BobState::BtcCancelled(_) - | BobState::BtcRefunded(_) - | BobState::BtcPunished { .. } - | BobState::SafelyAborted - | BobState::XmrRedeemed { .. } => { - bail!("Cannot print monero recovery information in state {}, only possible for BtcRedeemed", swap_state) - } - BobState::BtcRedeemed(state5) => { - let (spend_key, view_key) = state5.xmr_keys(); + if let BobState::BtcRedeemed(state5) = swap_state { + let (spend_key, view_key) = state5.xmr_keys(); - let address = monero::Address::standard( - context.config.env_config.monero_network, - monero::PublicKey::from_private_key(&spend_key), - monero::PublicKey::from(view_key.public()), - ); - tracing::info!("Wallet address: {}", address.to_string()); + let address = monero::Address::standard( + context.config.env_config.monero_network, + monero::PublicKey::from_private_key(&spend_key), + monero::PublicKey::from(view_key.public()), + ); - let view_key = serde_json::to_string(&view_key)?; - println!("View key: {}", view_key); + tracing::info!(address=%address, spend_key=%spend_key, view_key=%view_key, "Monero recovery information"); - println!("Spend key: {}", spend_key); - } + return Ok(json!({ + "address": address, + "spend_key": spend_key.to_string(), + "view_key": view_key.to_string(), + })); + } else { + bail!( + "Cannot print monero recovery information in state {}, only possible for BtcRedeemed", + swap_state + ) } - Ok(json!({ - "result": [] - })) } Method::GetCurrentSwap => Ok(json!({ "swap_id": context.swap_lock.get_current_swap_id().await @@ -721,11 +704,12 @@ impl Request { } pub async fn call(self, context: Arc) -> Result { - let method_span = self.cmd.get_tracing_span(self.log_reference.clone()).clone(); + let method_span = self + .cmd + .get_tracing_span(self.log_reference.clone()) + .clone(); - self.handle_cmd(context) - .instrument(method_span) - .await + self.handle_cmd(context).instrument(method_span).await } } diff --git a/swap/src/monero.rs b/swap/src/monero.rs index f13b7ee0..1e1e5583 100644 --- a/swap/src/monero.rs +++ b/swap/src/monero.rs @@ -42,6 +42,13 @@ pub fn private_key_from_secp256k1_scalar(scalar: bitcoin::Scalar) -> PrivateKey #[derive(Clone, Copy, Debug, Serialize, Deserialize, PartialEq, Eq)] pub struct PrivateViewKey(#[serde(with = "monero_private_key")] PrivateKey); +impl fmt::Display for PrivateViewKey { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // Delegate to the Display implementation of PrivateKey + write!(f, "{}", self.0) + } +} + impl PrivateViewKey { pub fn new_random(rng: &mut R) -> Self { let scalar = Scalar::random(rng); diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index 9144cfbb..7f51ac6e 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -85,6 +85,26 @@ pub fn register_modules(context: Arc) -> RpcModule> { }) .unwrap(); + module + .register_async_method( + "get_monero_recovery_info", + |params_raw, context| async move { + let params: HashMap = params_raw.parse()?; + + let swap_id = params.get("swap_id").ok_or_else(|| { + jsonrpsee_core::Error::Custom("Does not contain swap_id".to_string()) + })?; + + execute_request( + params_raw, + Method::MoneroRecovery { swap_id: *swap_id }, + &context, + ) + .await + }, + ) + .unwrap(); + module .register_async_method("withdraw_btc", |params_raw, context| async move { let params: HashMap = params_raw.parse()?; @@ -118,7 +138,8 @@ pub fn register_modules(context: Arc) -> RpcModule> { ) .await }) - .expect("Could not register RPC method withdraw_btc"); + .unwrap(); + module .register_async_method("buy_xmr", |params_raw, context| async move { let params: HashMap = params_raw.parse()?; @@ -165,6 +186,7 @@ pub fn register_modules(context: Arc) -> RpcModule> { .await }) .unwrap(); + module .register_async_method("list_sellers", |params_raw, context| async move { let params: HashMap = params_raw.parse()?; From 9c9644fe1b426cd4e8c59befaf8e6ffbee7aecdf Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Mon, 28 Aug 2023 00:50:41 +0200 Subject: [PATCH 08/10] Rename `Method::RawHistory` to `Method::GetRawStates` --- swap/src/api/request.rs | 28 ++++++++++++++-------------- swap/src/rpc/methods.rs | 2 +- 2 files changed, 15 insertions(+), 15 deletions(-) diff --git a/swap/src/api/request.rs b/swap/src/api/request.rs index c0e87474..1f0e229f 100644 --- a/swap/src/api/request.rs +++ b/swap/src/api/request.rs @@ -37,27 +37,27 @@ pub enum Method { monero_receive_address: monero::Address, swap_id: Uuid, }, - History, - RawHistory, - Config, - WithdrawBtc { - amount: Option, - address: bitcoin::Address, - }, - Balance, Resume { swap_id: Uuid, }, CancelAndRefund { swap_id: Uuid, }, + MoneroRecovery { + swap_id: Uuid, + }, + History, + Config, + WithdrawBtc { + amount: Option, + address: bitcoin::Address, + }, + Balance, ListSellers { rendezvous_point: Multiaddr, }, ExportBitcoinWallet, - MoneroRecovery { - swap_id: Uuid, - }, + SuspendCurrentSwap, StartDaemon { server_address: Option, }, @@ -65,7 +65,7 @@ pub enum Method { GetSwapInfo { swap_id: Uuid, }, - SuspendCurrentSwap, + GetRawStates, } impl Method { @@ -124,7 +124,7 @@ impl Method { log_reference_id = field::Empty ) } - Method::RawHistory => debug_span!( + Method::GetRawStates => debug_span!( "method", name = "RawHistory", log_reference_id = field::Empty @@ -528,7 +528,7 @@ impl Request { Ok(json!({ "swaps": vec })) } - Method::RawHistory => { + Method::GetRawStates => { let raw_history = context.db.raw_all().await?; Ok(json!({ "raw_history": raw_history })) diff --git a/swap/src/rpc/methods.rs b/swap/src/rpc/methods.rs index 7f51ac6e..b7dc39cc 100644 --- a/swap/src/rpc/methods.rs +++ b/swap/src/rpc/methods.rs @@ -52,7 +52,7 @@ pub fn register_modules(context: Arc) -> RpcModule> { module .register_async_method("get_raw_history", |params, context| async move { - execute_request(params, Method::RawHistory, &context).await + execute_request(params, Method::GetRawStates, &context).await }) .unwrap(); From a104c5aa7b01ca02656272b62d66379d74544704 Mon Sep 17 00:00:00 2001 From: binarybaron <86064887+binarybaron@users.noreply.github.com> Date: Mon, 28 Aug 2023 10:28:13 +0200 Subject: [PATCH 09/10] Wait for swap to be suspended after sending signal --- swap/src/api.rs | 32 ++++++++++++++++++++++++++++---- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/swap/src/api.rs b/swap/src/api.rs index 6dbf14f2..25baee2c 100644 --- a/swap/src/api.rs +++ b/swap/src/api.rs @@ -34,16 +34,14 @@ use uuid::Uuid; pub struct SwapLock { current_swap: RwLock>, - _suspension_rec: Receiver<()>, suspension_trigger: Sender<()>, } impl SwapLock { pub fn new() -> Self { - let (suspension_trigger, _suspension_rec) = broadcast::channel(10); + let (suspension_trigger, _) = broadcast::channel(10); SwapLock { current_swap: RwLock::new(None), - _suspension_rec, suspension_trigger, } } @@ -76,9 +74,35 @@ impl SwapLock { current_swap } + /// Sends a signal to suspend all ongoing swap processes. + /// + /// This function performs the following steps: + /// 1. Triggers the suspension by sending a unit `()` signal to all listeners via `self.suspension_trigger`. + /// 2. Polls the `current_swap` state every 50 milliseconds to check if it has been set to `None`, indicating that the swap processes have been suspended and the lock released. + /// 3. If the lock is not released within 10 seconds, the function returns an error. + /// + /// If we send a suspend signal while no swap is in progress, the function will not fail, but will return immediately. + /// + /// # Returns + /// - `Ok(())` if the swap lock is successfully released. + /// - `Err(Error)` if the function times out waiting for the swap lock to be released. + /// + /// # Notes + /// The 50ms polling interval is considered negligible overhead compared to the typical time required to suspend ongoing swap processes. pub async fn send_suspend_signal(&self) -> Result<(), Error> { + const TIMEOUT: i32 = 10_000; + const INTERVAL: i32 = 50; + let _ = self.suspension_trigger.send(())?; - Ok(()) + + for _ in 0..(TIMEOUT / INTERVAL) { + if self.get_current_swap_id().await.is_none() { + return Ok(()); + } + tokio::time::sleep(tokio::time::Duration::from_millis(INTERVAL)).await; + } + + bail!("Timed out waiting for swap lock to be released"); } pub async fn release_swap_lock(&self) -> Result { From ccf9b0c31fd804fff86813f2353d6328b3a68e60 Mon Sep 17 00:00:00 2001 From: Lorenzo Tucci Date: Fri, 1 Sep 2023 12:31:39 +0300 Subject: [PATCH 10/10] fix compile issues for tests and use serial_test crate --- swap/src/api.rs | 4 ++-- swap/src/bitcoin.rs | 5 +++-- swap/src/bitcoin/wallet.rs | 11 ++++++----- swap/src/cli/command.rs | 1 + swap/tests/rpc.rs | 37 ++++++++++++------------------------- 5 files changed, 24 insertions(+), 34 deletions(-) diff --git a/swap/src/api.rs b/swap/src/api.rs index 01fc79fd..0f5805cd 100644 --- a/swap/src/api.rs +++ b/swap/src/api.rs @@ -90,8 +90,8 @@ impl SwapLock { /// # Notes /// The 50ms polling interval is considered negligible overhead compared to the typical time required to suspend ongoing swap processes. pub async fn send_suspend_signal(&self) -> Result<(), Error> { - const TIMEOUT: i32 = 10_000; - const INTERVAL: i32 = 50; + const TIMEOUT: u64 = 10_000; + const INTERVAL: u64 = 50; let _ = self.suspension_trigger.send(())?; diff --git a/swap/src/bitcoin.rs b/swap/src/bitcoin.rs index 683f1dd5..2ac0aa78 100644 --- a/swap/src/bitcoin.rs +++ b/swap/src/bitcoin.rs @@ -371,6 +371,7 @@ mod tests { use crate::protocol::{alice, bob}; use rand::rngs::OsRng; use uuid::Uuid; + use std::matches; #[test] fn lock_confirmations_le_to_cancel_timelock_no_timelock_expired() { @@ -384,7 +385,7 @@ mod tests { tx_cancel_status, ); - assert_eq!(expired_timelock, ExpiredTimelocks::None) + assert!(matches!(expired_timelock, ExpiredTimelocks::None { .. })); } #[test] @@ -399,7 +400,7 @@ mod tests { tx_cancel_status, ); - assert_eq!(expired_timelock, ExpiredTimelocks::Cancel) + assert!(matches!(expired_timelock, ExpiredTimelocks::Cancel {..})); } #[test] diff --git a/swap/src/bitcoin/wallet.rs b/swap/src/bitcoin/wallet.rs index c1f8565c..7cd334fa 100644 --- a/swap/src/bitcoin/wallet.rs +++ b/swap/src/bitcoin/wallet.rs @@ -1004,9 +1004,10 @@ mod tests { #[test] fn given_depth_0_should_meet_confirmation_target_one() { + let script = ScriptStatus::Confirmed(Confirmed { depth: 0 }); - let confirmed = script.is_confirmed_with(1); + let confirmed = script.is_confirmed_with(1 as u32); assert!(confirmed) } @@ -1015,7 +1016,7 @@ mod tests { fn given_confirmations_1_should_meet_confirmation_target_one() { let script = ScriptStatus::from_confirmations(1); - let confirmed = script.is_confirmed_with(1); + let confirmed = script.is_confirmed_with(1 as u32); assert!(confirmed) } @@ -1034,7 +1035,7 @@ mod tests { fn given_depth_0_should_return_0_blocks_left_until_1() { let script = ScriptStatus::Confirmed(Confirmed { depth: 0 }); - let blocks_left = script.blocks_left_until(1); + let blocks_left = script.blocks_left_until(1 as u32); assert_eq!(blocks_left, 0) } @@ -1043,7 +1044,7 @@ mod tests { fn given_depth_1_should_return_0_blocks_left_until_1() { let script = ScriptStatus::Confirmed(Confirmed { depth: 1 }); - let blocks_left = script.blocks_left_until(1); + let blocks_left = script.blocks_left_until(1 as u32); assert_eq!(blocks_left, 0) } @@ -1052,7 +1053,7 @@ mod tests { fn given_depth_0_should_return_1_blocks_left_until_2() { let script = ScriptStatus::Confirmed(Confirmed { depth: 0 }); - let blocks_left = script.blocks_left_until(2); + let blocks_left = script.blocks_left_until(2 as u32); assert_eq!(blocks_left, 1) } diff --git a/swap/src/cli/command.rs b/swap/src/cli/command.rs index d770d507..86e48f16 100644 --- a/swap/src/cli/command.rs +++ b/swap/src/cli/command.rs @@ -1054,6 +1054,7 @@ mod tests { Config::default(is_testnet, None, debug, json), Request::buy_xmr(is_testnet), ); + let args = parse_args_and_apply_defaults(raw_ars).await.unwrap(); let (actual_config, actual_request) = match args { ParseResult::Context(context, request) => (context.config.clone(), request), diff --git a/swap/tests/rpc.rs b/swap/tests/rpc.rs index 6f516624..f034e7b1 100644 --- a/swap/tests/rpc.rs +++ b/swap/tests/rpc.rs @@ -5,17 +5,15 @@ use jsonrpsee::ws_client::WsClientBuilder; use jsonrpsee_core::client::ClientT; use jsonrpsee_core::params::ObjectParams; -use sequential_test::sequential; +use serial_test::serial; use std::collections::HashMap; use std::sync::Arc; use std::time::Duration; -use swap::api::request::{Method, Params, Request, Shutdown}; +use swap::api::request::{Method, Request }; use swap::api::Context; use swap::cli::command::{Bitcoin, Monero}; -use tokio::sync::broadcast; - use uuid::Uuid; #[cfg(test)] @@ -34,7 +32,6 @@ pub async fn initialize_context() -> (Arc, Request) { let (is_testnet, debug, json) = (true, false, false); // let data_dir = data::data_dir_from(None, is_testnet).unwrap(); let server_address = None; - let (tx, _) = broadcast::channel(1); let bitcoin = Bitcoin { bitcoin_electrum_rpc_url: None, @@ -45,7 +42,7 @@ pub async fn initialize_context() -> (Arc, Request) { monero_daemon_address: None, }; - let request = Request::new(tx.subscribe(), Method::StartDaemon, Params::default()); + let request = Request::new(Method::StartDaemon { server_address: None }); let context = Context::build( Some(bitcoin), @@ -56,7 +53,6 @@ pub async fn initialize_context() -> (Arc, Request) { debug, json, server_address, - tx, ) .await .unwrap(); @@ -65,7 +61,7 @@ pub async fn initialize_context() -> (Arc, Request) { } #[tokio::test] -#[sequential] +#[serial] pub async fn can_start_server() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -73,12 +69,11 @@ pub async fn can_start_server() { request.call(Arc::clone(&move_ctx)).await; }); tokio::time::sleep(Duration::from_secs(3)).await; - ctx.shutdown.send(()); assert!(true); } #[tokio::test] -#[sequential] +#[serial] pub async fn get_bitcoin_balance() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -96,11 +91,10 @@ pub async fn get_bitcoin_balance() { .unwrap(); assert_eq!(response, HashMap::from([("balance".to_string(), 0)])); - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn get_history() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -119,11 +113,10 @@ pub async fn get_history() { let swaps: Vec<(Uuid, String)> = Vec::new(); assert_eq!(response, HashMap::from([("swaps".to_string(), swaps)])); - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn get_raw_history() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -145,11 +138,10 @@ pub async fn get_raw_history() { response, HashMap::from([("raw_history".to_string(), raw_history)]) ); - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn get_seller() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -197,11 +189,10 @@ pub async fn get_seller() { e ), } - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn get_swap_start_date() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -244,11 +235,10 @@ pub async fn get_swap_start_date() { Ok(hash) => (), Err(e) => panic!("Expected a HashMap, got an error: {}", e), } - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn resume_swap() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -291,11 +281,10 @@ pub async fn resume_swap() { Ok(hash) => (), Err(e) => panic!("Expected a HashMap, got an error: {}", e), } - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn withdraw_btc() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -348,11 +337,10 @@ pub async fn withdraw_btc() { Err(e) => panic!("Expected a HashMap, got an error: {}", e), } - ctx.shutdown.send(()); } #[tokio::test] -#[sequential] +#[serial] pub async fn buy_xmr() { let (ctx, mut request) = initialize_context().await; let move_ctx = Arc::clone(&ctx); @@ -454,5 +442,4 @@ pub async fn buy_xmr() { Err(e) => panic!("Expected a HashMap, got an error: {}", e), } - ctx.shutdown.send(()); }