From 38d5bde7cb4ff19b29ce32925b0d7f8d6999a4f3 Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 27 Nov 2024 21:44:46 +0200 Subject: [PATCH 01/10] fix(taker_swap): check for existing payment before timeout Move payment existence check before timeout validation and skip timeout if payment is already sent, as we should proceed to waiting for maker to spend the taker payment. --- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 148 ++++++++++++---------- 1 file changed, 83 insertions(+), 65 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index c7b1cf59a9..fb5926c7f4 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1514,34 +1514,53 @@ impl TakerSwap { ])); } - let timeout = self.r().data.maker_payment_wait; - let now = now_sec(); - if now > timeout { - return Ok((Some(TakerSwapCommand::Finish), vec![ - TakerSwapEvent::TakerPaymentTransactionFailed(ERRL!("Timeout {} > {}", now, timeout).into()), - ])); - } - + // Extract values from the lock before async operations let taker_payment_lock = self.r().data.taker_payment_lock; let other_taker_coin_htlc_pub = self.r().other_taker_coin_htlc_pub; let secret_hash = self.r().secret_hash.clone(); + let taker_coin_start_block = self.r().data.taker_coin_start_block; let taker_coin_swap_contract_address = self.r().data.taker_coin_swap_contract_address.clone(); let unique_data = self.unique_swap_data(); let taker_amount_decimal = self.taker_amount.to_decimal(); let payment_instructions = self.r().payment_instructions.clone(); - let f = self.taker_coin.check_if_my_payment_sent(CheckIfMyPaymentSentArgs { - time_lock: taker_payment_lock, - other_pub: other_taker_coin_htlc_pub.as_slice(), - secret_hash: &secret_hash.0, - search_from_block: self.r().data.taker_coin_start_block, - swap_contract_address: &taker_coin_swap_contract_address, - swap_unique_data: &unique_data, - amount: &taker_amount_decimal, - payment_instructions: &payment_instructions, - }); + // Look for previously sent taker payment in case of restart + let maybe_existing_payment = match self + .taker_coin + .check_if_my_payment_sent(CheckIfMyPaymentSentArgs { + time_lock: taker_payment_lock, + other_pub: other_taker_coin_htlc_pub.as_slice(), + secret_hash: &secret_hash.0, + search_from_block: taker_coin_start_block, + swap_contract_address: &taker_coin_swap_contract_address, + swap_unique_data: &unique_data, + amount: &taker_amount_decimal, + payment_instructions: &payment_instructions, + }) + .await + { + Ok(Some(tx)) => Some(tx), + Ok(None) => None, + Err(e) => { + return Ok((Some(TakerSwapCommand::Finish), vec![ + TakerSwapEvent::TakerPaymentTransactionFailed(ERRL!("{}", e).into()), + ])) + }, + }; + + // Skip timeout check if payment was already sent + if maybe_existing_payment.is_none() { + let timeout = self.r().data.maker_payment_wait; + let now = now_sec(); + if now > timeout { + return Ok((Some(TakerSwapCommand::Finish), vec![ + TakerSwapEvent::TakerPaymentTransactionFailed(ERRL!("Timeout {} > {}", now, timeout).into()), + ])); + } + } + + // Set up watcher reward if enabled let reward_amount = self.r().reward_amount.clone(); - let wait_until = taker_payment_lock; let watcher_reward = if self.r().watcher_reward { match self .taker_coin @@ -1550,7 +1569,7 @@ impl TakerSwap { Some(self.taker_amount.clone().into()), Some(self.maker_amount.clone().into()), reward_amount, - wait_until, + taker_payment_lock, ) .await { @@ -1567,50 +1586,45 @@ impl TakerSwap { None }; - let transaction = match f.await { - Ok(res) => match res { - Some(tx) => tx, - None => { - let time_lock = match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => self.r().data.started_at, - Err(_) => taker_payment_lock, - }; - let lock_duration = self.r().data.lock_duration; - let payment = self - .taker_coin - .send_taker_payment(SendPaymentArgs { - time_lock_duration: lock_duration, - time_lock, - other_pubkey: &*other_taker_coin_htlc_pub, - secret_hash: &secret_hash.0, - amount: taker_amount_decimal, - swap_contract_address: &taker_coin_swap_contract_address, - swap_unique_data: &unique_data, - payment_instructions: &payment_instructions, - watcher_reward, - wait_for_confirmation_until: taker_payment_lock, - }) - .await; + // Use existing payment or create new one + let transaction = match maybe_existing_payment { + Some(tx) => tx, + None => { + let time_lock = match std::env::var("USE_TEST_LOCKTIME") { + Ok(_) => self.r().data.started_at, + Err(_) => taker_payment_lock, + }; - match payment { - Ok(t) => t, - Err(err) => { - return Ok((Some(TakerSwapCommand::Finish), vec![ - TakerSwapEvent::TakerPaymentTransactionFailed( - ERRL!("{}", err.get_plain_text_format()).into(), - ), - ])); - }, - } - }, - }, - Err(e) => { - return Ok((Some(TakerSwapCommand::Finish), vec![ - TakerSwapEvent::TakerPaymentTransactionFailed(ERRL!("{}", e).into()), - ])) + let lock_duration = self.r().data.lock_duration; + match self + .taker_coin + .send_taker_payment(SendPaymentArgs { + time_lock_duration: lock_duration, + time_lock, + other_pubkey: &*other_taker_coin_htlc_pub, + secret_hash: &secret_hash.0, + amount: taker_amount_decimal, + swap_contract_address: &taker_coin_swap_contract_address, + swap_unique_data: &unique_data, + payment_instructions: &payment_instructions, + watcher_reward, + wait_for_confirmation_until: taker_payment_lock, + }) + .await + { + Ok(t) => t, + Err(err) => { + return Ok((Some(TakerSwapCommand::Finish), vec![ + TakerSwapEvent::TakerPaymentTransactionFailed( + ERRL!("{}", err.get_plain_text_format()).into(), + ), + ])) + }, + } }, }; + // Create transaction identifier and prepare `TakerPaymentSent` success event let tx_hash = transaction.tx_hash_as_bytes(); let tx_hex = BytesJson::from(transaction.tx_hex()); info!("Taker payment tx hash {:02x}", tx_hash); @@ -1618,8 +1632,9 @@ impl TakerSwap { tx_hex: tx_hex.clone(), tx_hash, }; - let mut swap_events = vec![TakerSwapEvent::TakerPaymentSent(tx_ident)]; + + // Process watcher logic if enabled and supported by both coins if self.ctx.use_watchers() && self.taker_coin.is_supported_by_watchers() && self.maker_coin.is_supported_by_watchers() @@ -1636,6 +1651,7 @@ impl TakerSwap { Ok(_) => self.r().data.started_at, Err(_) => self.r().data.taker_payment_lock, }; + let taker_payment_refund_preimage_fut = self.taker_coin.create_taker_payment_refund_preimage( &transaction.tx_hex(), time_lock, @@ -1644,13 +1660,15 @@ impl TakerSwap { &self.r().data.taker_coin_swap_contract_address, &self.unique_swap_data(), ); - let payment_fut_pair = try_join( + + match try_join( maker_payment_spend_preimage_fut.compat(), taker_payment_refund_preimage_fut.compat(), - ); - - match payment_fut_pair.await { + ) + .await + { Ok((maker_payment_spend, taker_payment_refund)) => { + // Prepare and broadcast watcher message let watcher_data = self.create_watcher_data( transaction.tx_hash_as_bytes().into_vec(), maker_payment_spend.tx_hex(), From cedebad560a95a1d59618a91ecaf5b916061c41c Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 27 Nov 2024 22:50:17 +0200 Subject: [PATCH 02/10] fix(maker_swap): implement the same fix --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 122 ++++++++++++---------- 1 file changed, 68 insertions(+), 54 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 0eb72b8a71..41eb9cb34e 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -794,32 +794,52 @@ impl MakerSwap { } async fn maker_payment(&self) -> Result<(Option, Vec), String> { + // Extract values from lock before async operations let lock_duration = self.r().data.lock_duration; - let timeout = self.r().data.started_at + lock_duration / 3; - let now = now_sec(); - if now > timeout { - return Ok((Some(MakerSwapCommand::Finish), vec![ - MakerSwapEvent::MakerPaymentTransactionFailed(ERRL!("Timeout {} > {}", now, timeout).into()), - ])); - } - let maker_payment_lock = self.r().data.maker_payment_lock; let other_maker_coin_htlc_pub = self.r().other_maker_coin_htlc_pub; let secret_hash = self.secret_hash(); let maker_coin_swap_contract_address = self.r().data.maker_coin_swap_contract_address.clone(); let unique_data = self.unique_swap_data(); let payment_instructions = self.r().payment_instructions.clone(); - let transaction_f = self.maker_coin.check_if_my_payment_sent(CheckIfMyPaymentSentArgs { - time_lock: maker_payment_lock, - other_pub: &*other_maker_coin_htlc_pub, - secret_hash: secret_hash.as_slice(), - search_from_block: self.r().data.maker_coin_start_block, - swap_contract_address: &maker_coin_swap_contract_address, - swap_unique_data: &unique_data, - amount: &self.maker_amount, - payment_instructions: &payment_instructions, - }); + let maker_coin_start_block = self.r().data.maker_coin_start_block; + + // Look for previously sent maker payment in case of restart + let maybe_existing_payment = match self + .maker_coin + .check_if_my_payment_sent(CheckIfMyPaymentSentArgs { + time_lock: maker_payment_lock, + other_pub: &*other_maker_coin_htlc_pub, + secret_hash: secret_hash.as_slice(), + search_from_block: maker_coin_start_block, + swap_contract_address: &maker_coin_swap_contract_address, + swap_unique_data: &unique_data, + amount: &self.maker_amount, + payment_instructions: &payment_instructions, + }) + .await + { + Ok(Some(tx)) => Some(tx), + Ok(None) => None, + Err(e) => { + return Ok((Some(MakerSwapCommand::Finish), vec![ + MakerSwapEvent::MakerPaymentTransactionFailed(ERRL!("{}", e).into()), + ])) + }, + }; + // Skip timeout check if payment was already sent + if maybe_existing_payment.is_none() { + let timeout = self.r().data.started_at + lock_duration / 3; + let now = now_sec(); + if now > timeout { + return Ok((Some(MakerSwapCommand::Finish), vec![ + MakerSwapEvent::MakerPaymentTransactionFailed(ERRL!("Timeout {} > {}", now, timeout).into()), + ])); + } + } + + // Set up watcher reward if enabled let wait_maker_payment_until = wait_for_maker_payment_conf_until(self.r().data.started_at, lock_duration); let watcher_reward = if self.r().watcher_reward { match self @@ -838,45 +858,39 @@ impl MakerSwap { None }; - let transaction = match transaction_f.await { - Ok(res) => match res { - Some(tx) => tx, - None => { - let payment = self - .maker_coin - .send_maker_payment(SendPaymentArgs { - time_lock_duration: lock_duration, - time_lock: maker_payment_lock, - other_pubkey: &*other_maker_coin_htlc_pub, - secret_hash: secret_hash.as_slice(), - amount: self.maker_amount.clone(), - swap_contract_address: &maker_coin_swap_contract_address, - swap_unique_data: &unique_data, - payment_instructions: &payment_instructions, - watcher_reward, - wait_for_confirmation_until: wait_maker_payment_until, - }) - .await; - - match payment { - Ok(t) => t, - Err(err) => { - return Ok((Some(MakerSwapCommand::Finish), vec![ - MakerSwapEvent::MakerPaymentTransactionFailed( - ERRL!("{}", err.get_plain_text_format()).into(), - ), - ])); - }, - } - }, - }, - Err(e) => { - return Ok((Some(MakerSwapCommand::Finish), vec![ - MakerSwapEvent::MakerPaymentTransactionFailed(ERRL!("{}", e).into()), - ])) + // Use existing payment or create new one + let transaction = match maybe_existing_payment { + Some(tx) => tx, + None => { + match self + .maker_coin + .send_maker_payment(SendPaymentArgs { + time_lock_duration: lock_duration, + time_lock: maker_payment_lock, + other_pubkey: &*other_maker_coin_htlc_pub, + secret_hash: secret_hash.as_slice(), + amount: self.maker_amount.clone(), + swap_contract_address: &maker_coin_swap_contract_address, + swap_unique_data: &unique_data, + payment_instructions: &payment_instructions, + watcher_reward, + wait_for_confirmation_until: wait_maker_payment_until, + }) + .await + { + Ok(t) => t, + Err(err) => { + return Ok((Some(MakerSwapCommand::Finish), vec![ + MakerSwapEvent::MakerPaymentTransactionFailed( + ERRL!("{}", err.get_plain_text_format()).into(), + ), + ])); + }, + } }, }; + // Build transaction identifier and prepare events let tx_hash = transaction.tx_hash_as_bytes(); info!("{}: Maker payment tx {:02x}", MAKER_PAYMENT_SENT_LOG, tx_hash); From c039ebdd86b3dd96183ac787cfa930ca2e25745a Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 4 Dec 2024 00:54:27 +0200 Subject: [PATCH 03/10] review fixes: make some code comments better --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 4 ++-- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 41eb9cb34e..6301076e0a 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -803,6 +803,7 @@ impl MakerSwap { let unique_data = self.unique_swap_data(); let payment_instructions = self.r().payment_instructions.clone(); let maker_coin_start_block = self.r().data.maker_coin_start_block; + let wait_maker_payment_until = wait_for_maker_payment_conf_until(self.r().data.started_at, lock_duration); // Look for previously sent maker payment in case of restart let maybe_existing_payment = match self @@ -828,7 +829,7 @@ impl MakerSwap { }, }; - // Skip timeout check if payment was already sent + // If the payment is not yet sent, make sure we didn't miss the deadline for sending it. if maybe_existing_payment.is_none() { let timeout = self.r().data.started_at + lock_duration / 3; let now = now_sec(); @@ -840,7 +841,6 @@ impl MakerSwap { } // Set up watcher reward if enabled - let wait_maker_payment_until = wait_for_maker_payment_conf_until(self.r().data.started_at, lock_duration); let watcher_reward = if self.r().watcher_reward { match self .maker_coin diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index fb5926c7f4..3a2763d8d0 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1548,7 +1548,7 @@ impl TakerSwap { }, }; - // Skip timeout check if payment was already sent + // If the payment is not yet sent, make sure we didn't miss the deadline for sending it. if maybe_existing_payment.is_none() { let timeout = self.r().data.maker_payment_wait; let now = now_sec(); From 61f8357cf93083ea9108db9d5801ccd7e9ec63aa Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 4 Dec 2024 01:21:37 +0200 Subject: [PATCH 04/10] refactor: extract taker payment watcher reward setup to a function --- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 54 ++++++++++++----------- 1 file changed, 28 insertions(+), 26 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 3a2763d8d0..415b4cf252 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -20,7 +20,7 @@ use coins::lp_price::fetch_swap_coins_price; use coins::{lp_coinfind, CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, MmCoin, MmCoinEnum, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapTxTypeWithSecretHash, - TradeFee, TradePreimageValue, ValidatePaymentInput, WaitForHTLCTxSpendArgs}; + TradeFee, TradePreimageValue, ValidatePaymentInput, WaitForHTLCTxSpendArgs, WatcherReward}; use common::executor::Timer; use common::log::{debug, error, info, warn}; use common::{bits256, now_ms, now_sec, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; @@ -1506,6 +1506,25 @@ impl TakerSwap { } } + async fn setup_watcher_reward(&self, taker_payment_lock: u64) -> Result, String> { + if !self.r().watcher_reward { + return Ok(None); + } + + let reward_amount = self.r().reward_amount.clone(); + self.taker_coin + .get_taker_watcher_reward( + &self.maker_coin, + Some(self.taker_amount.clone().into()), + Some(self.maker_amount.clone().into()), + reward_amount, + taker_payment_lock, + ) + .await + .map(Some) + .map_err(|err| ERRL!("Watcher reward error: {}", err.to_string())) + } + async fn send_taker_payment(&self) -> Result<(Option, Vec), String> { #[cfg(test)] if self.fail_at == Some(FailAt::TakerPayment) { @@ -1559,31 +1578,14 @@ impl TakerSwap { } } - // Set up watcher reward if enabled - let reward_amount = self.r().reward_amount.clone(); - let watcher_reward = if self.r().watcher_reward { - match self - .taker_coin - .get_taker_watcher_reward( - &self.maker_coin, - Some(self.taker_amount.clone().into()), - Some(self.maker_amount.clone().into()), - reward_amount, - taker_payment_lock, - ) - .await - { - Ok(reward) => Some(reward), - Err(err) => { - return Ok((Some(TakerSwapCommand::Finish), vec![ - TakerSwapEvent::TakerPaymentTransactionFailed( - ERRL!("Watcher reward error: {}", err.to_string()).into(), - ), - ])) - }, - } - } else { - None + // Set up watcher reward + let watcher_reward = match self.setup_watcher_reward(taker_payment_lock).await { + Ok(reward) => reward, + Err(err) => { + return Ok((Some(TakerSwapCommand::Finish), vec![ + TakerSwapEvent::TakerPaymentTransactionFailed(err.into()), + ])); + }, }; // Use existing payment or create new one From 81f4e8331598f2ed17fad4734aa5bd63d1219552 Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 4 Dec 2024 01:28:41 +0200 Subject: [PATCH 05/10] refactor: extract maker payment watcher reward setup to a function --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 35 ++++++++++++----------- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 2 +- 2 files changed, 20 insertions(+), 17 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 6301076e0a..8dffb49d18 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -20,7 +20,7 @@ use coins::lp_price::fetch_swap_coins_price; use coins::{CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, MmCoin, MmCoinEnum, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapTxTypeWithSecretHash, TradeFee, - TradePreimageValue, TransactionEnum, ValidateFeeArgs, ValidatePaymentInput}; + TradePreimageValue, TransactionEnum, ValidateFeeArgs, ValidatePaymentInput, WatcherReward}; use common::log::{debug, error, info, warn}; use common::{bits256, executor::Timer, now_ms, DEX_FEE_ADDR_RAW_PUBKEY}; use common::{now_sec, wait_until_sec}; @@ -793,6 +793,17 @@ impl MakerSwap { Ok((Some(MakerSwapCommand::SendPayment), swap_events)) } + async fn setup_maker_watcher_reward(&self, wait_maker_payment_until: u64) -> Result, String> { + if !self.r().watcher_reward { + return Ok(None); + } + + self.maker_coin + .get_maker_watcher_reward(&self.taker_coin, self.watcher_reward_amount(), wait_maker_payment_until) + .await + .map_err(|err| err.into_inner().to_string()) + } + async fn maker_payment(&self) -> Result<(Option, Vec), String> { // Extract values from lock before async operations let lock_duration = self.r().data.lock_duration; @@ -841,21 +852,13 @@ impl MakerSwap { } // Set up watcher reward if enabled - let watcher_reward = if self.r().watcher_reward { - match self - .maker_coin - .get_maker_watcher_reward(&self.taker_coin, self.watcher_reward_amount(), wait_maker_payment_until) - .await - { - Ok(reward) => reward, - Err(err) => { - return Ok((Some(MakerSwapCommand::Finish), vec![ - MakerSwapEvent::MakerPaymentTransactionFailed(err.into_inner().to_string().into()), - ])) - }, - } - } else { - None + let watcher_reward = match self.setup_maker_watcher_reward(wait_maker_payment_until).await { + Ok(reward) => reward, + Err(err) => { + return Ok((Some(MakerSwapCommand::Finish), vec![ + MakerSwapEvent::MakerPaymentTransactionFailed(err.into()), + ])) + }, }; // Use existing payment or create new one diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 415b4cf252..bb883424d1 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1578,7 +1578,7 @@ impl TakerSwap { } } - // Set up watcher reward + // Set up watcher reward if enable let watcher_reward = match self.setup_watcher_reward(taker_payment_lock).await { Ok(reward) => reward, Err(err) => { From 199b135db3021dab4927e8e6d6c1833e5b94169d Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 4 Dec 2024 01:36:34 +0200 Subject: [PATCH 06/10] refactor: extract taker payment watcher logic to a function --- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 132 ++++++++++++---------- 1 file changed, 71 insertions(+), 61 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index bb883424d1..b26294304c 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -20,7 +20,7 @@ use coins::lp_price::fetch_swap_coins_price; use coins::{lp_coinfind, CanRefundHtlc, CheckIfMyPaymentSentArgs, ConfirmPaymentInput, FeeApproxStage, FoundSwapTxSpend, MmCoin, MmCoinEnum, PaymentInstructionArgs, PaymentInstructions, PaymentInstructionsErr, RefundPaymentArgs, SearchForSwapTxSpendInput, SendPaymentArgs, SpendPaymentArgs, SwapTxTypeWithSecretHash, - TradeFee, TradePreimageValue, ValidatePaymentInput, WaitForHTLCTxSpendArgs, WatcherReward}; + TradeFee, TradePreimageValue, TransactionEnum, ValidatePaymentInput, WaitForHTLCTxSpendArgs, WatcherReward}; use common::executor::Timer; use common::log::{debug, error, info, warn}; use common::{bits256, now_ms, now_sec, wait_until_sec, DEX_FEE_ADDR_RAW_PUBKEY}; @@ -1525,6 +1525,74 @@ impl TakerSwap { .map_err(|err| ERRL!("Watcher reward error: {}", err.to_string())) } + async fn process_watcher_logic(&self, transaction: &TransactionEnum) -> Option { + if !(self.ctx.use_watchers() + && self.taker_coin.is_supported_by_watchers() + && self.maker_coin.is_supported_by_watchers()) + { + return None; + } + + let maker_payment_spend_preimage_fut = self.maker_coin.create_maker_payment_spend_preimage( + &self.r().maker_payment.as_ref().unwrap().tx_hex, + self.maker_payment_lock.load(Ordering::Relaxed), + self.r().other_maker_coin_htlc_pub.as_slice(), + &self.r().secret_hash.0, + &self.unique_swap_data()[..], + ); + + let time_lock = match std::env::var("USE_TEST_LOCKTIME") { + Ok(_) => self.r().data.started_at, + Err(_) => self.r().data.taker_payment_lock, + }; + + let taker_payment_refund_preimage_fut = self.taker_coin.create_taker_payment_refund_preimage( + &transaction.tx_hex(), + time_lock, + &*self.r().other_taker_coin_htlc_pub, + &self.r().secret_hash.0, + &self.r().data.taker_coin_swap_contract_address, + &self.unique_swap_data(), + ); + + match try_join( + maker_payment_spend_preimage_fut.compat(), + taker_payment_refund_preimage_fut.compat(), + ) + .await + { + Ok((maker_payment_spend, taker_payment_refund)) => { + let watcher_data = self.create_watcher_data( + transaction.tx_hash_as_bytes().into_vec(), + maker_payment_spend.tx_hex(), + taker_payment_refund.tx_hex(), + ); + let swpmsg_watcher = SwapWatcherMsg::TakerSwapWatcherMsg(watcher_data); + + let htlc_keypair = self.taker_coin.derive_htlc_key_pair(&self.unique_swap_data()); + broadcast_swap_message( + &self.ctx, + watcher_topic(&self.r().data.taker_coin), + swpmsg_watcher, + &Some(htlc_keypair), + ); + + info!("{}", WATCHER_MESSAGE_SENT_LOG); + Some(TakerSwapEvent::WatcherMessageSent( + Some(maker_payment_spend.tx_hex()), + Some(taker_payment_refund.tx_hex()), + )) + }, + Err(e) => { + error!( + "The watcher message could not be sent, error creating at least one of the preimages: {}", + e.get_plain_text_format() + ); + None + }, + } + } + async fn send_taker_payment(&self) -> Result<(Option, Vec), String> { #[cfg(test)] if self.fail_at == Some(FailAt::TakerPayment) { @@ -1637,66 +1705,8 @@ impl TakerSwap { let mut swap_events = vec![TakerSwapEvent::TakerPaymentSent(tx_ident)]; // Process watcher logic if enabled and supported by both coins - if self.ctx.use_watchers() - && self.taker_coin.is_supported_by_watchers() - && self.maker_coin.is_supported_by_watchers() - { - let maker_payment_spend_preimage_fut = self.maker_coin.create_maker_payment_spend_preimage( - &self.r().maker_payment.as_ref().unwrap().tx_hex, - self.maker_payment_lock.load(Ordering::Relaxed), - self.r().other_maker_coin_htlc_pub.as_slice(), - &self.r().secret_hash.0, - &self.unique_swap_data()[..], - ); - - let time_lock = match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => self.r().data.started_at, - Err(_) => self.r().data.taker_payment_lock, - }; - - let taker_payment_refund_preimage_fut = self.taker_coin.create_taker_payment_refund_preimage( - &transaction.tx_hex(), - time_lock, - &*self.r().other_taker_coin_htlc_pub, - &self.r().secret_hash.0, - &self.r().data.taker_coin_swap_contract_address, - &self.unique_swap_data(), - ); - - match try_join( - maker_payment_spend_preimage_fut.compat(), - taker_payment_refund_preimage_fut.compat(), - ) - .await - { - Ok((maker_payment_spend, taker_payment_refund)) => { - // Prepare and broadcast watcher message - let watcher_data = self.create_watcher_data( - transaction.tx_hash_as_bytes().into_vec(), - maker_payment_spend.tx_hex(), - taker_payment_refund.tx_hex(), - ); - let swpmsg_watcher = SwapWatcherMsg::TakerSwapWatcherMsg(watcher_data); - - let htlc_keypair = self.taker_coin.derive_htlc_key_pair(&self.unique_swap_data()); - broadcast_swap_message( - &self.ctx, - watcher_topic(&self.r().data.taker_coin), - swpmsg_watcher, - &Some(htlc_keypair), - ); - - swap_events.push(TakerSwapEvent::WatcherMessageSent( - Some(maker_payment_spend.tx_hex()), - Some(taker_payment_refund.tx_hex()), - )); - info!("{}", WATCHER_MESSAGE_SENT_LOG); - }, - Err(e) => error!( - "The watcher message could not be sent, error creating at least one of the preimages: {}", - e.get_plain_text_format() - ), - } + if let Some(watcher_event) = self.process_watcher_logic(&transaction).await { + swap_events.push(watcher_event); } Ok((Some(TakerSwapCommand::WaitForTakerPaymentSpend), swap_events)) From f6471b5f344c3ab14d178f6c1e3a979b6f0fc062 Mon Sep 17 00:00:00 2001 From: shamardy Date: Wed, 4 Dec 2024 01:38:56 +0200 Subject: [PATCH 07/10] one last small refactor --- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index b26294304c..57ed42101c 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1526,10 +1526,11 @@ impl TakerSwap { } async fn process_watcher_logic(&self, transaction: &TransactionEnum) -> Option { - if !(self.ctx.use_watchers() + let watchers_enabled_and_supported = self.ctx.use_watchers() && self.taker_coin.is_supported_by_watchers() - && self.maker_coin.is_supported_by_watchers()) - { + && self.maker_coin.is_supported_by_watchers(); + + if !watchers_enabled_and_supported { return None; } From 5eca01d30f4dfd7c0ce7dde6da2fdf3497523b84 Mon Sep 17 00:00:00 2001 From: shamardy Date: Tue, 10 Dec 2024 19:22:41 +0200 Subject: [PATCH 08/10] add some doc comments --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 8 ++++++++ mm2src/mm2_main/src/lp_swap/taker_swap.rs | 15 +++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 8dffb49d18..5b54b43f94 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -793,6 +793,14 @@ impl MakerSwap { Ok((Some(MakerSwapCommand::SendPayment), swap_events)) } + /// Sets up the watcher reward for the maker's payment in the swap. + /// + /// The reward mainly serves as compensation to watchers for the mining fees + /// paid to execute the transactions. + /// + /// The reward configuration depends on the specific requirements of the coins + /// involved in the swap. + /// Some coins may not support watcher rewards at all. async fn setup_maker_watcher_reward(&self, wait_maker_payment_until: u64) -> Result, String> { if !self.r().watcher_reward { return Ok(None); diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index 57ed42101c..ef8e021b77 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1506,6 +1506,14 @@ impl TakerSwap { } } + /// Sets up the watcher reward for the taker's payment in the swap. + /// + /// The reward mainly serves as compensation to watchers for the mining fees + /// paid to execute the transactions. + /// + /// The reward configuration depends on the specific requirements of the coins + /// involved in the swap. + /// Some coins may not support watcher rewards at all. async fn setup_watcher_reward(&self, taker_payment_lock: u64) -> Result, String> { if !self.r().watcher_reward { return Ok(None); @@ -1525,6 +1533,13 @@ impl TakerSwap { .map_err(|err| ERRL!("Watcher reward error: {}", err.to_string())) } + /// Processes watcher-related logic for the swap by preparing and broadcasting necessary data. + /// + /// This function creates spend/refund preimages and broadcasts them to watchers if both coins + /// support watcher functionality and watchers are enabled. + /// + /// The preimages allow watchers to either complete the swap by spending the maker payment + /// or refund the taker payment if needed. async fn process_watcher_logic(&self, transaction: &TransactionEnum) -> Option { let watchers_enabled_and_supported = self.ctx.use_watchers() && self.taker_coin.is_supported_by_watchers() From 557ebe240de484df63822346c8563d6aa0412b48 Mon Sep 17 00:00:00 2001 From: shamardy Date: Thu, 12 Dec 2024 16:57:48 +0200 Subject: [PATCH 09/10] remove reliance on `USE_TEST_LOCKTIME` env var --- mm2src/mm2_main/src/lp_swap.rs | 10 +- mm2src/mm2_main/src/lp_swap/swap_watcher.rs | 31 ++-- mm2src/mm2_main/src/lp_swap/taker_restart.rs | 11 +- mm2src/mm2_main/src/lp_swap/taker_swap.rs | 20 +-- mm2src/mm2_main/src/mm2.rs | 13 +- .../tests/docker_tests/swap_watcher_tests.rs | 150 ++++++++++-------- 6 files changed, 115 insertions(+), 120 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap.rs b/mm2src/mm2_main/src/lp_swap.rs index 0acb7fc443..016ca519e1 100644 --- a/mm2src/mm2_main/src/lp_swap.rs +++ b/mm2src/mm2_main/src/lp_swap.rs @@ -91,7 +91,7 @@ use std::sync::{Arc, Mutex, Weak}; use std::time::Duration; use uuid::Uuid; -#[cfg(feature = "custom-swap-locktime")] +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] use std::sync::atomic::{AtomicU64, Ordering}; mod check_balance; @@ -420,13 +420,13 @@ async fn recv_swap_msg( /// in order to give different and/or heavy communication channels a chance. const BASIC_COMM_TIMEOUT: u64 = 90; -#[cfg(not(feature = "custom-swap-locktime"))] +#[cfg(not(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests")))] /// Default atomic swap payment locktime, in seconds. /// Maker sends payment with LOCKTIME * 2 /// Taker sends payment with LOCKTIME const PAYMENT_LOCKTIME: u64 = 3600 * 2 + 300 * 2; -#[cfg(feature = "custom-swap-locktime")] +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] /// Default atomic swap payment locktime, in seconds. /// Maker sends payment with LOCKTIME * 2 /// Taker sends payment with LOCKTIME @@ -435,9 +435,9 @@ pub(crate) static PAYMENT_LOCKTIME: AtomicU64 = AtomicU64::new(super::CUSTOM_PAY #[inline] /// Returns `PAYMENT_LOCKTIME` pub fn get_payment_locktime() -> u64 { - #[cfg(not(feature = "custom-swap-locktime"))] + #[cfg(not(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests")))] return PAYMENT_LOCKTIME; - #[cfg(feature = "custom-swap-locktime")] + #[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] PAYMENT_LOCKTIME.load(Ordering::Relaxed) } diff --git a/mm2src/mm2_main/src/lp_swap/swap_watcher.rs b/mm2src/mm2_main/src/lp_swap/swap_watcher.rs index 312f62e5c5..bba8479b7c 100644 --- a/mm2src/mm2_main/src/lp_swap/swap_watcher.rs +++ b/mm2src/mm2_main/src/lp_swap/swap_watcher.rs @@ -258,10 +258,7 @@ impl State for ValidateTakerPayment { let validate_input = WatcherValidatePaymentInput { payment_tx: taker_payment_hex.clone(), taker_payment_refund_preimage: watcher_ctx.data.taker_payment_refund_preimage.clone(), - time_lock: match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => watcher_ctx.data.swap_started_at, - Err(_) => watcher_ctx.taker_locktime(), - }, + time_lock: watcher_ctx.taker_locktime(), taker_pub: watcher_ctx.verified_pub.clone(), maker_pub: watcher_ctx.data.maker_pub.clone(), secret_hash: watcher_ctx.data.secret_hash.clone(), @@ -451,20 +448,18 @@ impl State for RefundTakerPayment { async fn on_changed(self: Box, watcher_ctx: &mut WatcherStateMachine) -> StateResult { debug!("Watcher refund taker payment"); - if std::env::var("USE_TEST_LOCKTIME").is_err() { - loop { - match watcher_ctx - .taker_coin - .can_refund_htlc(watcher_ctx.taker_locktime()) - .await - { - Ok(CanRefundHtlc::CanRefundNow) => break, - Ok(CanRefundHtlc::HaveToWait(to_sleep)) => Timer::sleep(to_sleep as f64).await, - Err(e) => { - error!("Error {} on can_refund_htlc, retrying in 30 seconds", e); - Timer::sleep(30.).await; - }, - } + loop { + match watcher_ctx + .taker_coin + .can_refund_htlc(watcher_ctx.taker_locktime()) + .await + { + Ok(CanRefundHtlc::CanRefundNow) => break, + Ok(CanRefundHtlc::HaveToWait(to_sleep)) => Timer::sleep(to_sleep as f64).await, + Err(e) => { + error!("Error {} on can_refund_htlc, retrying in 30 seconds", e); + Timer::sleep(30.).await; + }, } } diff --git a/mm2src/mm2_main/src/lp_swap/taker_restart.rs b/mm2src/mm2_main/src/lp_swap/taker_restart.rs index d934b6b11e..014f671bd1 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_restart.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_restart.rs @@ -154,11 +154,7 @@ pub async fn check_taker_payment_spend(swap: &TakerSwap) -> Result swap.r().data.started_at, - Err(_) => swap.r().data.taker_payment_lock, - }; + let taker_payment_lock = swap.r().data.taker_payment_lock; let secret_hash = swap.r().secret_hash.0.clone(); let unique_data = swap.unique_swap_data(); let watcher_reward = swap.r().watcher_reward; @@ -223,10 +219,7 @@ pub async fn add_taker_payment_refunded_by_watcher_event( ) -> Result { let other_maker_coin_htlc_pub = swap.r().other_maker_coin_htlc_pub; let taker_coin_swap_contract_address = swap.r().data.taker_coin_swap_contract_address.clone(); - let taker_payment_lock = match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => swap.r().data.started_at, - Err(_) => swap.r().data.taker_payment_lock, - }; + let taker_payment_lock = swap.r().data.taker_payment_lock; let secret_hash = swap.r().secret_hash.0.clone(); let validate_input = ValidateWatcherSpendInput { diff --git a/mm2src/mm2_main/src/lp_swap/taker_swap.rs b/mm2src/mm2_main/src/lp_swap/taker_swap.rs index ef8e021b77..90c2f3655d 100644 --- a/mm2src/mm2_main/src/lp_swap/taker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/taker_swap.rs @@ -1557,14 +1557,9 @@ impl TakerSwap { &self.unique_swap_data()[..], ); - let time_lock = match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => self.r().data.started_at, - Err(_) => self.r().data.taker_payment_lock, - }; - let taker_payment_refund_preimage_fut = self.taker_coin.create_taker_payment_refund_preimage( &transaction.tx_hex(), - time_lock, + self.r().data.taker_payment_lock, &*self.r().other_taker_coin_htlc_pub, &self.r().secret_hash.0, &self.r().data.taker_coin_swap_contract_address, @@ -1676,17 +1671,12 @@ impl TakerSwap { let transaction = match maybe_existing_payment { Some(tx) => tx, None => { - let time_lock = match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => self.r().data.started_at, - Err(_) => taker_payment_lock, - }; - let lock_duration = self.r().data.lock_duration; match self .taker_coin .send_taker_payment(SendPaymentArgs { time_lock_duration: lock_duration, - time_lock, + time_lock: taker_payment_lock, other_pubkey: &*other_taker_coin_htlc_pub, secret_hash: &secret_hash.0, amount: taker_amount_decimal, @@ -1779,11 +1769,7 @@ impl TakerSwap { info!("Waiting for maker to spend taker payment!"); - let wait_until = match std::env::var("USE_TEST_LOCKTIME") { - Ok(_) => self.r().data.started_at, - Err(_) => self.r().data.taker_payment_lock, - }; - + let wait_until = self.r().data.taker_payment_lock; let secret_hash = self.r().secret_hash.clone(); let taker_coin_start_block = self.r().data.taker_coin_start_block; let taker_coin_swap_contract_address = self.r().data.taker_coin_swap_contract_address.clone(); diff --git a/mm2src/mm2_main/src/mm2.rs b/mm2src/mm2_main/src/mm2.rs index dd7c7bed27..7ca5a995d1 100644 --- a/mm2src/mm2_main/src/mm2.rs +++ b/mm2src/mm2_main/src/mm2.rs @@ -47,10 +47,11 @@ use common::log::LogLevel; use common::password_policy::password_policy; use mm2_core::mm_ctx::MmCtxBuilder; -#[cfg(feature = "custom-swap-locktime")] use common::log::warn; -#[cfg(feature = "custom-swap-locktime")] +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] +use common::log::warn; +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] use lp_swap::PAYMENT_LOCKTIME; -#[cfg(feature = "custom-swap-locktime")] +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] use std::sync::atomic::Ordering; use gstuff::slurp; @@ -85,7 +86,7 @@ pub mod rpc; pub const PASSWORD_MAXIMUM_CONSECUTIVE_CHARACTERS: usize = 3; -#[cfg(feature = "custom-swap-locktime")] +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] const CUSTOM_PAYMENT_LOCKTIME_DEFAULT: u64 = 900; pub struct LpMainParams { @@ -102,7 +103,7 @@ impl LpMainParams { } } -#[cfg(feature = "custom-swap-locktime")] +#[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] /// Reads `payment_locktime` from conf arg and assigns it into `PAYMENT_LOCKTIME` in lp_swap. /// Assigns 900 if `payment_locktime` is invalid or not provided. fn initialize_payment_locktime(conf: &Json) { @@ -150,7 +151,7 @@ pub async fn lp_main( } } - #[cfg(feature = "custom-swap-locktime")] + #[cfg(any(feature = "custom-swap-locktime", test, feature = "run-docker-tests"))] initialize_payment_locktime(&conf); let ctx = MmCtxBuilder::new() diff --git a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs index 49abc5c77f..404762a13f 100644 --- a/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs +++ b/mm2src/mm2_main/tests/docker_tests/swap_watcher_tests.rs @@ -92,6 +92,7 @@ fn start_swaps_and_get_balances( alice_privkey: &str, bob_privkey: &str, watcher_privkey: &str, + custom_locktime: Option, ) -> BalanceResult { let coins = json!([ eth_dev_conf(), @@ -100,7 +101,10 @@ fn start_swaps_and_get_balances( mycoin1_conf(1000) ]); - let alice_conf = Mm2TestConf::seednode(&format!("0x{}", alice_privkey), &coins); + let mut alice_conf = Mm2TestConf::seednode(&format!("0x{}", alice_privkey), &coins); + if let Some(locktime) = custom_locktime { + alice_conf.conf["payment_locktime"] = locktime.into(); + } let mut mm_alice = block_on(MarketMakerIt::start_with_envs( alice_conf.conf.clone(), alice_conf.rpc_password.clone(), @@ -111,7 +115,10 @@ fn start_swaps_and_get_balances( let (_alice_dump_log, _alice_dump_dashboard) = mm_alice.mm_dump(); log!("Alice log path: {}", mm_alice.log_path.display()); - let bob_conf = Mm2TestConf::light_node(&format!("0x{}", bob_privkey), &coins, &[&mm_alice.ip.to_string()]); + let mut bob_conf = Mm2TestConf::light_node(&format!("0x{}", bob_privkey), &coins, &[&mm_alice.ip.to_string()]); + if let Some(locktime) = custom_locktime { + bob_conf.conf["payment_locktime"] = locktime.into(); + } let mut mm_bob = block_on(MarketMakerIt::start_with_envs( bob_conf.conf.clone(), bob_conf.rpc_password, @@ -157,13 +164,16 @@ fn start_swaps_and_get_balances( ), }; - let watcher_conf = Mm2TestConf::watcher_light_node( + let mut watcher_conf = Mm2TestConf::watcher_light_node( &format!("0x{}", watcher_privkey), &coins, &[&mm_alice.ip.to_string()], watcher_conf, ) .conf; + if let Some(locktime) = custom_locktime { + watcher_conf["payment_locktime"] = locktime.into(); + } let mut mm_watcher = block_on(MarketMakerIt::start_with_envs( watcher_conf, @@ -270,9 +280,17 @@ fn check_actual_events(mm_alice: &MarketMakerIt, uuid: &str, expected_events: &[ status_response } -fn run_taker_node(coins: &Value, envs: &[(&str, &str)], seednodes: &[&str]) -> (MarketMakerIt, Mm2TestConf) { +fn run_taker_node( + coins: &Value, + envs: &[(&str, &str)], + seednodes: &[&str], + custom_locktime: Option, +) -> (MarketMakerIt, Mm2TestConf) { let privkey = hex::encode(random_secp256k1_secret()); - let conf = Mm2TestConf::light_node(&format!("0x{}", privkey), coins, seednodes); + let mut conf = Mm2TestConf::light_node(&format!("0x{}", privkey), coins, seednodes); + if let Some(locktime) = custom_locktime { + conf.conf["payment_locktime"] = locktime.into(); + } let mm = block_on(MarketMakerIt::start_with_envs( conf.conf.clone(), conf.rpc_password.clone(), @@ -309,13 +327,21 @@ fn restart_taker_and_wait_until(conf: &Mm2TestConf, envs: &[(&str, &str)], wait_ mm_alice } -fn run_maker_node(coins: &Value, envs: &[(&str, &str)], seednodes: &[&str]) -> MarketMakerIt { +fn run_maker_node( + coins: &Value, + envs: &[(&str, &str)], + seednodes: &[&str], + custom_locktime: Option, +) -> MarketMakerIt { let privkey = hex::encode(random_secp256k1_secret()); - let conf = if seednodes.is_empty() { + let mut conf = if seednodes.is_empty() { Mm2TestConf::seednode(&format!("0x{}", privkey), coins) } else { Mm2TestConf::light_node(&format!("0x{}", privkey), coins, seednodes) }; + if let Some(locktime) = custom_locktime { + conf.conf["payment_locktime"] = locktime.into(); + } let mm = block_on(MarketMakerIt::start_with_envs( conf.conf.clone(), conf.rpc_password, @@ -339,9 +365,13 @@ fn run_watcher_node( envs: &[(&str, &str)], seednodes: &[&str], watcher_conf: WatcherConf, + custom_locktime: Option, ) -> MarketMakerIt { let privkey = hex::encode(random_secp256k1_secret()); - let conf = Mm2TestConf::watcher_light_node(&format!("0x{}", privkey), coins, seednodes, watcher_conf).conf; + let mut conf = Mm2TestConf::watcher_light_node(&format!("0x{}", privkey), coins, seednodes, watcher_conf).conf; + if let Some(locktime) = custom_locktime { + conf["payment_locktime"] = locktime.into(); + } let mm = block_on(MarketMakerIt::start_with_envs( conf, DEFAULT_RPC_PASSWORD.to_string(), @@ -363,11 +393,13 @@ fn run_watcher_node( #[test] fn test_taker_saves_the_swap_as_successful_after_restart_panic_at_wait_for_taker_payment_spend() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); - let mut mm_bob = run_maker_node(&coins, &[], &[]); - let (mut mm_alice, mut alice_conf) = - run_taker_node(&coins, &[("TAKER_FAIL_AT", "wait_for_taker_payment_spend_panic")], &[ - &mm_bob.ip.to_string(), - ]); + let mut mm_bob = run_maker_node(&coins, &[], &[], None); + let (mut mm_alice, mut alice_conf) = run_taker_node( + &coins, + &[("TAKER_FAIL_AT", "wait_for_taker_payment_spend_panic")], + &[&mm_bob.ip.to_string()], + None, + ); let watcher_conf = WatcherConf { wait_taker_payment: 0., @@ -375,7 +407,7 @@ fn test_taker_saves_the_swap_as_successful_after_restart_panic_at_wait_for_taker refund_start_factor: 1.5, search_interval: 1.0, }; - let mut mm_watcher = run_watcher_node(&coins, &[], &[&mm_bob.ip.to_string()], watcher_conf); + let mut mm_watcher = run_watcher_node(&coins, &[], &[&mm_bob.ip.to_string()], watcher_conf, None); let uuids = block_on(start_swaps( &mut mm_bob, @@ -422,11 +454,13 @@ fn test_taker_saves_the_swap_as_successful_after_restart_panic_at_wait_for_taker #[test] fn test_taker_saves_the_swap_as_successful_after_restart_panic_at_maker_payment_spend() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); - let mut mm_bob = run_maker_node(&coins, &[], &[]); - let (mut mm_alice, mut alice_conf) = - run_taker_node(&coins, &[("TAKER_FAIL_AT", "maker_payment_spend_panic")], &[&mm_bob - .ip - .to_string()]); + let mut mm_bob = run_maker_node(&coins, &[], &[], None); + let (mut mm_alice, mut alice_conf) = run_taker_node( + &coins, + &[("TAKER_FAIL_AT", "maker_payment_spend_panic")], + &[&mm_bob.ip.to_string()], + None, + ); let watcher_conf = WatcherConf { wait_taker_payment: 0., @@ -434,7 +468,7 @@ fn test_taker_saves_the_swap_as_successful_after_restart_panic_at_maker_payment_ refund_start_factor: 1.5, search_interval: 1.0, }; - let mut mm_watcher = run_watcher_node(&coins, &[], &[&mm_bob.ip.to_string()], watcher_conf); + let mut mm_watcher = run_watcher_node(&coins, &[], &[&mm_bob.ip.to_string()], watcher_conf, None); let uuids = block_on(start_swaps( &mut mm_bob, @@ -477,15 +511,13 @@ fn test_taker_saves_the_swap_as_successful_after_restart_panic_at_maker_payment_ #[test] fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_panic_at_wait_for_taker_payment_spend() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); - let mm_seednode = run_maker_node(&coins, &[("USE_TEST_LOCKTIME", "")], &[]); - let mut mm_bob = run_maker_node(&coins, &[("USE_TEST_LOCKTIME", "")], &[&mm_seednode.ip.to_string()]); + let mm_seednode = run_maker_node(&coins, &[], &[], Some(60)); + let mut mm_bob = run_maker_node(&coins, &[], &[&mm_seednode.ip.to_string()], Some(60)); let (mut mm_alice, mut alice_conf) = run_taker_node( &coins, - &[ - ("USE_TEST_LOCKTIME", ""), - ("TAKER_FAIL_AT", "wait_for_taker_payment_spend_panic"), - ], + &[("TAKER_FAIL_AT", "wait_for_taker_payment_spend_panic")], &[&mm_seednode.ip.to_string()], + Some(60), ); let watcher_conf = WatcherConf { @@ -494,12 +526,7 @@ fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_pa refund_start_factor: 0., search_interval: 1., }; - let mut mm_watcher = run_watcher_node( - &coins, - &[("USE_TEST_LOCKTIME", "")], - &[&mm_seednode.ip.to_string()], - watcher_conf, - ); + let mut mm_watcher = run_watcher_node(&coins, &[], &[&mm_seednode.ip.to_string()], watcher_conf, Some(60)); let uuids = block_on(start_swaps( &mut mm_bob, @@ -521,11 +548,7 @@ fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_pa block_on(mm_alice.stop()).unwrap(); - let mm_alice = restart_taker_and_wait_until( - &alice_conf, - &[("USE_TEST_LOCKTIME", "")], - &format!("[swap uuid={}] Finished", &uuids[0]), - ); + let mm_alice = restart_taker_and_wait_until(&alice_conf, &[], &format!("[swap uuid={}] Finished", &uuids[0])); let expected_events = [ "Started", @@ -550,15 +573,13 @@ fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_pa #[test] fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_panic_at_taker_payment_refund() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); - let mm_seednode = run_maker_node(&coins, &[("USE_TEST_LOCKTIME", "")], &[]); - let mut mm_bob = run_maker_node(&coins, &[("USE_TEST_LOCKTIME", "")], &[&mm_seednode.ip.to_string()]); + let mm_seednode = run_maker_node(&coins, &[], &[], Some(60)); + let mut mm_bob = run_maker_node(&coins, &[], &[&mm_seednode.ip.to_string()], Some(60)); let (mut mm_alice, mut alice_conf) = run_taker_node( &coins, - &[ - ("USE_TEST_LOCKTIME", ""), - ("TAKER_FAIL_AT", "taker_payment_refund_panic"), - ], + &[("TAKER_FAIL_AT", "taker_payment_refund_panic")], &[&mm_seednode.ip.to_string()], + Some(60), ); let watcher_conf = WatcherConf { @@ -567,12 +588,7 @@ fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_pa refund_start_factor: 0., search_interval: 1., }; - let mut mm_watcher = run_watcher_node( - &coins, - &[("USE_TEST_LOCKTIME", "")], - &[&mm_seednode.ip.to_string()], - watcher_conf, - ); + let mut mm_watcher = run_watcher_node(&coins, &[], &[&mm_seednode.ip.to_string()], watcher_conf, Some(60)); let uuids = block_on(start_swaps( &mut mm_bob, @@ -594,11 +610,7 @@ fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_pa block_on(mm_alice.stop()).unwrap(); - let mm_alice = restart_taker_and_wait_until( - &alice_conf, - &[("USE_TEST_LOCKTIME", "")], - &format!("[swap uuid={}] Finished", &uuids[0]), - ); + let mm_alice = restart_taker_and_wait_until(&alice_conf, &[], &format!("[swap uuid={}] Finished", &uuids[0])); let expected_events = [ "Started", @@ -626,8 +638,8 @@ fn test_taker_saves_the_swap_as_finished_after_restart_taker_payment_refunded_pa #[test] fn test_taker_completes_swap_after_restart() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); - let mut mm_bob = run_maker_node(&coins, &[], &[]); - let (mut mm_alice, mut alice_conf) = run_taker_node(&coins, &[], &[&mm_bob.ip.to_string()]); + let mut mm_bob = run_maker_node(&coins, &[], &[], None); + let (mut mm_alice, mut alice_conf) = run_taker_node(&coins, &[], &[&mm_bob.ip.to_string()], None); let uuids = block_on(start_swaps( &mut mm_bob, @@ -671,8 +683,8 @@ fn test_taker_completes_swap_after_restart() { #[test] fn test_taker_completes_swap_after_taker_payment_spent_while_offline() { let coins = json!([mycoin_conf(1000), mycoin1_conf(1000)]); - let mut mm_bob = run_maker_node(&coins, &[], &[]); - let (mut mm_alice, mut alice_conf) = run_taker_node(&coins, &[], &[&mm_bob.ip.to_string()]); + let mut mm_bob = run_maker_node(&coins, &[], &[], None); + let (mut mm_alice, mut alice_conf) = run_taker_node(&coins, &[], &[&mm_bob.ip.to_string()], None); let uuids = block_on(start_swaps( &mut mm_bob, @@ -736,6 +748,7 @@ fn test_watcher_spends_maker_payment_utxo_utxo() { &alice_privkey, &bob_privkey, &watcher_privkey, + None, ); let acoin_volume = BigDecimal::from_str("50").unwrap(); @@ -776,6 +789,7 @@ fn test_watcher_spends_maker_payment_utxo_eth() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); let mycoin_volume = BigDecimal::from_str("1").unwrap(); @@ -805,6 +819,7 @@ fn test_watcher_spends_maker_payment_eth_utxo() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); let eth_volume = BigDecimal::from_str("0.01").unwrap(); @@ -847,6 +862,7 @@ fn test_watcher_spends_maker_payment_eth_erc20() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); let eth_volume = BigDecimal::from_str("0.01").unwrap(); @@ -880,6 +896,7 @@ fn test_watcher_spends_maker_payment_erc20_eth() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); let jst_volume = BigDecimal::from_str("1").unwrap(); @@ -910,6 +927,7 @@ fn test_watcher_spends_maker_payment_utxo_erc20() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); let mycoin_volume = BigDecimal::from_str("1").unwrap(); @@ -943,6 +961,7 @@ fn test_watcher_spends_maker_payment_erc20_utxo() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); let mycoin_volume = BigDecimal::from_str("1").unwrap(); @@ -991,11 +1010,12 @@ fn test_watcher_refunds_taker_payment_utxo() { 25., 25., 2., - &[("USE_TEST_LOCKTIME", "")], + &[], SwapFlow::WatcherRefundsTakerPayment, alice_privkey, bob_privkey, watcher_privkey, + Some(60), ); assert_eq!( @@ -1017,11 +1037,12 @@ fn test_watcher_refunds_taker_payment_eth() { 0.01, 0.01, 1., - &[("USE_TEST_LOCKTIME", ""), ("USE_WATCHER_REWARD", "")], + &[("USE_WATCHER_REWARD", "")], SwapFlow::WatcherRefundsTakerPayment, &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + Some(60), ); assert_eq!(balances.alice_bcoin_balance_after, balances.alice_bcoin_balance_before); @@ -1040,15 +1061,12 @@ fn test_watcher_refunds_taker_payment_erc20() { 100., 100., 0.01, - &[ - ("USE_TEST_LOCKTIME", ""), - ("TEST_COIN_PRICE", "0.01"), - ("USE_WATCHER_REWARD", ""), - ], + &[("TEST_COIN_PRICE", "0.01"), ("USE_WATCHER_REWARD", "")], SwapFlow::WatcherRefundsTakerPayment, &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + Some(60), ); let erc20_volume = BigDecimal::from_str("1").unwrap(); @@ -1080,6 +1098,7 @@ fn test_watcher_waits_for_taker_utxo() { alice_privkey, bob_privkey, watcher_privkey, + None, ); } @@ -1100,6 +1119,7 @@ fn test_watcher_waits_for_taker_eth() { &alice_coin.display_priv_key().unwrap()[2..], &bob_coin.display_priv_key().unwrap()[2..], &watcher_coin.display_priv_key().unwrap()[2..], + None, ); } From 6568a6b8b3ededa8cebe05876a2e267eb712bfd2 Mon Sep 17 00:00:00 2001 From: shamardy Date: Thu, 9 Jan 2025 15:11:40 +0200 Subject: [PATCH 10/10] rename `setup_maker_watcher_reward` to `setup_watcher_reward` --- mm2src/mm2_main/src/lp_swap/maker_swap.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/mm2src/mm2_main/src/lp_swap/maker_swap.rs b/mm2src/mm2_main/src/lp_swap/maker_swap.rs index 5b54b43f94..e5e8c23c7a 100644 --- a/mm2src/mm2_main/src/lp_swap/maker_swap.rs +++ b/mm2src/mm2_main/src/lp_swap/maker_swap.rs @@ -801,7 +801,7 @@ impl MakerSwap { /// The reward configuration depends on the specific requirements of the coins /// involved in the swap. /// Some coins may not support watcher rewards at all. - async fn setup_maker_watcher_reward(&self, wait_maker_payment_until: u64) -> Result, String> { + async fn setup_watcher_reward(&self, wait_maker_payment_until: u64) -> Result, String> { if !self.r().watcher_reward { return Ok(None); } @@ -860,7 +860,7 @@ impl MakerSwap { } // Set up watcher reward if enabled - let watcher_reward = match self.setup_maker_watcher_reward(wait_maker_payment_until).await { + let watcher_reward = match self.setup_watcher_reward(wait_maker_payment_until).await { Ok(reward) => reward, Err(err) => { return Ok((Some(MakerSwapCommand::Finish), vec![