From d35e3ba5728c7316d7317a982364c08d44ceae3c Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 3 Mar 2023 17:58:51 +0300 Subject: [PATCH 1/6] implement lock free sequence avoid logic Signed-off-by: ozkanonur --- mm2src/coins/tendermint/tendermint_coin.rs | 399 ++++++++++--------- mm2src/coins/tendermint/tendermint_token.rs | 9 +- mm2src/mm2_main/tests/mm2_tests/iris_swap.rs | 2 - 3 files changed, 222 insertions(+), 188 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index f99e55967b..a8ac4fd6ce 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -214,7 +214,6 @@ pub struct TendermintCoinImpl { pub(super) denom: Denom, chain_id: ChainId, gas_price: Option, - pub(super) sequence_lock: AsyncMutex<()>, pub(crate) tokens_info: PaMutex>, /// This spawner is used to spawn coin's related futures that should be aborted on coin deactivation /// or on [`MmArc::stop`]. @@ -265,6 +264,7 @@ pub enum TendermintCoinRpcError { InvalidResponse(String), PerformError(String), RpcClientError(String), + InternalError(String), } impl From for TendermintCoinRpcError { @@ -282,6 +282,7 @@ impl From for BalanceError { TendermintCoinRpcError::Prost(e) => BalanceError::InvalidResponse(e.to_string()), TendermintCoinRpcError::PerformError(e) => BalanceError::Transport(e), TendermintCoinRpcError::RpcClientError(e) => BalanceError::Transport(e), + TendermintCoinRpcError::InternalError(e) => BalanceError::Internal(e), } } } @@ -293,6 +294,7 @@ impl From for ValidatePaymentError { TendermintCoinRpcError::Prost(e) => ValidatePaymentError::InvalidRpcResponse(e.to_string()), TendermintCoinRpcError::PerformError(e) => ValidatePaymentError::Transport(e), TendermintCoinRpcError::RpcClientError(e) => ValidatePaymentError::Transport(e), + TendermintCoinRpcError::InternalError(e) => ValidatePaymentError::InternalError(e), } } } @@ -498,7 +500,6 @@ impl TendermintCoin { chain_id, gas_price: protocol_info.gas_price, avg_blocktime: conf.avg_blocktime, - sequence_lock: AsyncMutex::new(()), tokens_info: PaMutex::new(HashMap::new()), abortable_system, history_sync_state: Mutex::new(history_sync_state), @@ -596,23 +597,88 @@ impl TendermintCoin { sha256(&htlc_id).to_string().to_uppercase() } + pub(super) async fn seq_safe_send_raw_tx_bytes( + &self, + tx_payload: Any, + fee: Fee, + timeout_height: u64, + memo: String, + ) -> Result<(String, Raw), TransactionErr> { + let (tx_id, tx_raw) = loop { + let tx_raw = try_tx_s!(self.any_to_signed_raw_tx( + try_tx_s!(self.my_account_info().await), + tx_payload.clone(), + fee.clone(), + timeout_height, + memo.clone(), + )); + + match self.send_raw_tx_bytes(&try_tx_s!(tx_raw.to_bytes())).compat().await { + Ok(tx_id) => break (tx_id, tx_raw), + Err(e) => { + if e.contains("Wrong account sequence catched") { + debug!("Got wrong account sequence, trying again."); + continue; + } + + return Err(crate::TransactionErr::Plain(ERRL!("{}", e))); + }, + }; + }; + + Ok((tx_id, tx_raw)) + } + #[allow(deprecated)] pub(super) async fn calculate_fee( &self, - base_denom: Denom, - tx_bytes: Vec, + msg: Any, + timeout_height: u64, + memo: String, ) -> MmResult { let path = AbciPath::from_str(ABCI_SIMULATE_TX_PATH).expect("valid path"); - let request = SimulateRequest { tx_bytes, tx: None }; - let request = AbciRequest::new( - Some(path), - request.encode_to_vec(), - ABCI_REQUEST_HEIGHT, - ABCI_REQUEST_PROVE, - ); - let raw_response = self.rpc_client().await?.perform(request).await?; - let response = SimulateResponse::decode(raw_response.response.value.as_slice())?; + let (response, raw_response) = loop { + let account_info = self.my_account_info().await?; + let tx_bytes = self + .gen_simulated_tx(account_info, msg.clone(), timeout_height, memo.clone()) + .map_to_mm(|e| TendermintCoinRpcError::InternalError(format!("{}", e)))?; + + let request = SimulateRequest { tx_bytes, tx: None }; + let request = AbciRequest::new( + Some(path.clone()), + request.encode_to_vec().clone(), + ABCI_REQUEST_HEIGHT, + ABCI_REQUEST_PROVE, + ); + + let raw_response = self.rpc_client().await?.perform(request).await?; + + if raw_response + .response + .log + .to_string() + .contains("incorrect account sequence") + { + debug!("Got wrong account sequence, trying again."); + continue; + } + + match raw_response.response.code { + cosmrs::tendermint::abci::Code::Ok => {}, + cosmrs::tendermint::abci::Code::Err(_) => { + return MmError::err(TendermintCoinRpcError::InvalidResponse(format!( + "Could not read gas_info. Invalid Response: {}", + raw_response.response.log + ))); + }, + }; + + break ( + SimulateResponse::decode(raw_response.response.value.as_slice())?, + raw_response, + ); + }; let gas = response.gas_info.as_ref().ok_or_else(|| { TendermintCoinRpcError::InvalidResponse(format!( @@ -624,7 +690,7 @@ impl TendermintCoin { let amount = ((gas.gas_used as f64 * 1.5) * self.gas_price()).ceil(); let fee_amount = Coin { - denom: base_denom, + denom: self.platform_denom().parse().expect("Platform denom parse can't fail"), amount: (amount as u64).into(), }; @@ -632,18 +698,54 @@ impl TendermintCoin { } #[allow(deprecated)] - pub(super) async fn calculate_fee_amount_as_u64(&self, tx_bytes: Vec) -> MmResult { + pub(super) async fn calculate_fee_amount_as_u64( + &self, + msg: Any, + timeout_height: u64, + memo: String, + ) -> MmResult { let path = AbciPath::from_str(ABCI_SIMULATE_TX_PATH).expect("valid path"); - let request = SimulateRequest { tx_bytes, tx: None }; - let request = AbciRequest::new( - Some(path), - request.encode_to_vec(), - ABCI_REQUEST_HEIGHT, - ABCI_REQUEST_PROVE, - ); - let raw_response = self.rpc_client().await?.perform(request).await?; - let response = SimulateResponse::decode(raw_response.response.value.as_slice())?; + let (response, raw_response) = loop { + let account_info = self.my_account_info().await?; + let tx_bytes = self + .gen_simulated_tx(account_info, msg.clone(), timeout_height, memo.clone()) + .map_to_mm(|e| TendermintCoinRpcError::InternalError(format!("{}", e)))?; + let request = SimulateRequest { tx_bytes, tx: None }; + let request = AbciRequest::new( + Some(path.clone()), + request.encode_to_vec(), + ABCI_REQUEST_HEIGHT, + ABCI_REQUEST_PROVE, + ); + + let raw_response = self.rpc_client().await?.perform(request).await?; + + if raw_response + .response + .log + .to_string() + .contains("incorrect account sequence") + { + debug!("Got wrong account sequence, trying again."); + continue; + } + + match raw_response.response.code { + cosmrs::tendermint::abci::Code::Ok => {}, + cosmrs::tendermint::abci::Code::Err(_) => { + return MmError::err(TendermintCoinRpcError::InvalidResponse(format!( + "Could not read gas_info. Invalid Response: {}", + raw_response.response.log + ))); + }, + }; + + break ( + SimulateResponse::decode(raw_response.response.value.as_slice())?, + raw_response, + ); + }; let gas = response.gas_info.as_ref().ok_or_else(|| { TendermintCoinRpcError::InvalidResponse(format!( @@ -868,29 +970,27 @@ impl TendermintCoin { let create_htlc_tx = try_tx_s!(coin.gen_create_htlc_tx(denom, &to, amount, &secret_hash, time_lock as u64)); - let _sequence_lock = coin.sequence_lock.lock().await; let current_block = try_tx_s!(coin.current_block().compat().await); let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info = try_tx_s!(coin.my_account_info().await); - let simulated_tx = try_tx_s!(coin.gen_simulated_tx( - account_info.clone(), - create_htlc_tx.msg_payload.clone(), - timeout_height, - TX_DEFAULT_MEMO.into(), - )); - - let fee = try_tx_s!(coin.calculate_fee(coin.denom.clone(), simulated_tx).await); - - let tx_raw = try_tx_s!(coin.any_to_signed_raw_tx( - account_info.clone(), - create_htlc_tx.msg_payload.clone(), - fee, - timeout_height, - TX_DEFAULT_MEMO.into(), - )); + let fee = try_tx_s!( + coin.calculate_fee( + create_htlc_tx.msg_payload.clone(), + timeout_height, + TX_DEFAULT_MEMO.to_owned() + ) + .await + ); - let _tx_id = try_tx_s!(coin.send_raw_tx_bytes(&try_tx_s!(tx_raw.to_bytes())).compat().await); + let (_tx_id, tx_raw) = try_tx_s!( + coin.seq_safe_send_raw_tx_bytes( + create_htlc_tx.msg_payload.clone(), + fee.clone(), + timeout_height, + TX_DEFAULT_MEMO.into(), + ) + .await + ); Ok(TransactionEnum::CosmosTransaction(CosmosTransaction { data: tx_raw.into(), @@ -927,30 +1027,18 @@ impl TendermintCoin { let coin = self.clone(); let fut = async move { - let _sequence_lock = coin.sequence_lock.lock().await; - let account_info = try_tx_s!(coin.my_account_info().await); - let current_block = try_tx_s!(coin.current_block().compat().await.map_to_mm(WithdrawError::Transport)); let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let simulated_tx = try_tx_s!(coin.gen_simulated_tx( - account_info.clone(), - tx_payload.clone(), - timeout_height, - TX_DEFAULT_MEMO.into(), - )); - - let fee = try_tx_s!(coin.calculate_fee(coin.denom.clone(), simulated_tx).await); - - let tx_raw = try_tx_s!(coin - .any_to_signed_raw_tx(account_info, tx_payload, fee, timeout_height, memo) - .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))); - - let tx_bytes = try_tx_s!(tx_raw - .to_bytes() - .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))); + let fee = try_tx_s!( + coin.calculate_fee(tx_payload.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned()) + .await + ); - let _tx_id = try_tx_s!(coin.send_raw_tx_bytes(&tx_bytes).compat().await); + let (_tx_id, tx_raw) = try_tx_s!( + coin.seq_safe_send_raw_tx_bytes(tx_payload.clone(), fee.clone(), timeout_height, memo.clone()) + .await + ); Ok(TransactionEnum::CosmosTransaction(CosmosTransaction { data: tx_raw.into(), @@ -1156,23 +1244,15 @@ impl TendermintCoin { })?; let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info = self.my_account_info().await?; - let simulated_tx = self - .gen_simulated_tx( - account_info.clone(), + let fee_uamount = self + .calculate_fee_amount_as_u64( create_htlc_tx.msg_payload.clone(), timeout_height, - TX_DEFAULT_MEMO.into(), + TX_DEFAULT_MEMO.to_owned(), ) - .map_err(|e| { - MmError::new(TradePreimageError::InternalError(format!( - "Tx simulation failed. {:?}", - e - ))) - })?; + .await?; - let fee_uamount = self.calculate_fee_amount_as_u64(simulated_tx).await?; let fee_amount = big_decimal_from_sat_unsigned(fee_uamount, self.decimals); Ok(TradeFee { @@ -1201,7 +1281,6 @@ impl TendermintCoin { })?; let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info = self.my_account_info().await?; let msg_send = MsgSend { from_address: self.account_id.clone(), @@ -1214,16 +1293,9 @@ impl TendermintCoin { .to_any() .map_err(|e| MmError::new(TradePreimageError::InternalError(e.to_string())))?; - let simulated_tx = self - .gen_simulated_tx(account_info.clone(), msg_send, timeout_height, TX_DEFAULT_MEMO.into()) - .map_err(|e| { - MmError::new(TradePreimageError::InternalError(format!( - "Tx simulation failed. {:?}", - e - ))) - })?; - - let fee_uamount = self.calculate_fee_amount_as_u64(simulated_tx).await?; + let fee_uamount = self + .calculate_fee_amount_as_u64(msg_send.clone(), timeout_height, TX_DEFAULT_MEMO.to_owned()) + .await?; let fee_amount = big_decimal_from_sat_unsigned(fee_uamount, decimals); Ok(TradeFee { @@ -1470,17 +1542,14 @@ impl MmCoin for TendermintCoin { .await .map_to_mm(WithdrawError::Transport)?; - let _sequence_lock = coin.sequence_lock.lock().await; let account_info = coin.my_account_info().await?; let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - - let simulated_tx = coin - .gen_simulated_tx(account_info.clone(), msg_send.clone(), timeout_height, memo.clone()) - .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; // >> END TX SIMULATION FOR FEE CALCULATION - let fee_amount_u64 = coin.calculate_fee_amount_as_u64(simulated_tx).await?; + let fee_amount_u64 = coin + .calculate_fee_amount_as_u64(msg_send.clone(), timeout_height, memo.clone()) + .await?; let fee_amount_dec = big_decimal_from_sat_unsigned(fee_amount_u64, coin.decimals()); let fee_amount = Coin { @@ -1736,6 +1805,8 @@ impl MarketCoinOps for TendermintCoin { self.send_raw_tx_bytes(&tx_bytes) } + /// Consider using `seq_safe_raw_tx_bytes` instead. + /// This is considered as unsafe due to sequence mismatches. fn send_raw_tx_bytes(&self, tx: &[u8]) -> Box + Send> { // as sanity check try_fus!(Raw::from_bytes(tx)); @@ -1935,30 +2006,27 @@ impl SwapOps for TendermintCoin { let coin = self.clone(); let fut = async move { - let _sequence_lock = coin.sequence_lock.lock().await; let current_block = try_tx_s!(coin.current_block().compat().await); let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info = try_tx_s!(coin.my_account_info().await); - - let simulated_tx = try_tx_s!(coin.gen_simulated_tx( - account_info.clone(), - claim_htlc_tx.msg_payload.clone(), - timeout_height, - TX_DEFAULT_MEMO.into(), - )); - - let fee = try_tx_s!(coin.calculate_fee(coin.denom.clone(), simulated_tx).await); - - let tx_raw = try_tx_s!(coin.any_to_signed_raw_tx( - account_info, - claim_htlc_tx.msg_payload, - fee, - timeout_height, - TX_DEFAULT_MEMO.into(), - )); + let fee = try_tx_s!( + coin.calculate_fee( + claim_htlc_tx.msg_payload.clone(), + timeout_height, + TX_DEFAULT_MEMO.to_owned() + ) + .await + ); - let tx_id = try_tx_s!(coin.send_raw_tx_bytes(&try_tx_s!(tx_raw.to_bytes())).compat().await); + let (_tx_id, tx_raw) = try_tx_s!( + coin.seq_safe_send_raw_tx_bytes( + claim_htlc_tx.msg_payload.clone(), + fee.clone(), + timeout_height, + TX_DEFAULT_MEMO.into(), + ) + .await + ); Ok(TransactionEnum::CosmosTransaction(CosmosTransaction { data: tx_raw.into(), @@ -1993,30 +2061,27 @@ impl SwapOps for TendermintCoin { let coin = self.clone(); let fut = async move { - let _sequence_lock = coin.sequence_lock.lock().await; let current_block = try_tx_s!(coin.current_block().compat().await); let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info = try_tx_s!(coin.my_account_info().await); - - let simulated_tx = try_tx_s!(coin.gen_simulated_tx( - account_info.clone(), - claim_htlc_tx.msg_payload.clone(), - timeout_height, - TX_DEFAULT_MEMO.into(), - )); - - let fee = try_tx_s!(coin.calculate_fee(coin.denom.clone(), simulated_tx).await); - - let tx_raw = try_tx_s!(coin.any_to_signed_raw_tx( - account_info, - claim_htlc_tx.msg_payload, - fee, - timeout_height, - TX_DEFAULT_MEMO.into(), - )); + let fee = try_tx_s!( + coin.calculate_fee( + claim_htlc_tx.msg_payload.clone(), + timeout_height, + TX_DEFAULT_MEMO.into(), + ) + .await + ); - let tx_id = try_tx_s!(coin.send_raw_tx_bytes(&try_tx_s!(tx_raw.to_bytes())).compat().await); + let (tx_id, tx_raw) = try_tx_s!( + coin.seq_safe_send_raw_tx_bytes( + claim_htlc_tx.msg_payload.clone(), + fee.clone(), + timeout_height, + TX_DEFAULT_MEMO.into(), + ) + .await + ); Ok(TransactionEnum::CosmosTransaction(CosmosTransaction { data: tx_raw.into(), @@ -2351,7 +2416,7 @@ pub mod tendermint_coin_tests { fn test_htlc_create_and_claim() { let rpc_urls = vec![IRIS_TESTNET_RPC_URL.to_string()]; - let protocol_conf = get_iris_usdc_ibc_protocol(); + let protocol_conf = get_iris_protocol(); let ctx = mm2_core::mm_ctx::MmCtxBuilder::default().into_mm_arc(); @@ -2365,7 +2430,7 @@ pub mod tendermint_coin_tests { let coin = block_on(TendermintCoin::init( &ctx, - "USDC-IBC".to_string(), + "IRIS".to_string(), conf, protocol_conf, rpc_urls, @@ -2375,7 +2440,6 @@ pub mod tendermint_coin_tests { .unwrap(); // << BEGIN HTLC CREATION - let base_denom: Denom = "unyan".parse().unwrap(); let to: AccountId = IRIS_TESTNET_HTLC_PAIR2_ADDRESS.parse().unwrap(); const UAMOUNT: u64 = 1; let amount: cosmrs::Decimal = UAMOUNT.into(); @@ -2391,33 +2455,22 @@ pub mod tendermint_coin_tests { let current_block = block_on(async { current_block_fut.await.unwrap() }); let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info_fut = coin.my_account_info(); - let account_info = block_on(async { account_info_fut.await.unwrap() }); - - let simulated_tx = coin - .gen_simulated_tx( - account_info.clone(), + let fee = block_on(async { + coin.calculate_fee( create_htlc_tx.msg_payload.clone(), timeout_height, - TX_DEFAULT_MEMO.into(), - ) - .unwrap(); - - let fee = block_on(async { coin.calculate_fee(base_denom.clone(), simulated_tx).await.unwrap() }); - - let raw_tx = block_on(async { - coin.any_to_signed_raw_tx( - account_info.clone(), - create_htlc_tx.msg_payload.clone(), - fee, - timeout_height, - TX_DEFAULT_MEMO.into(), + TX_DEFAULT_MEMO.to_owned(), ) + .await .unwrap() }); - let tx_bytes = raw_tx.to_bytes().unwrap(); - let send_tx_fut = coin.send_raw_tx_bytes(&tx_bytes).compat(); + let send_tx_fut = coin.seq_safe_send_raw_tx_bytes( + create_htlc_tx.msg_payload.clone(), + fee, + timeout_height, + TX_DEFAULT_MEMO.into(), + ); block_on(async { send_tx_fut.await.unwrap(); }); @@ -2446,36 +2499,22 @@ pub mod tendermint_coin_tests { let current_block = common::block_on(async { current_block_fut.await.unwrap() }); let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let account_info_fut = coin.my_account_info(); - let account_info = block_on(async { account_info_fut.await.unwrap() }); - - let simulated_tx = coin - .gen_simulated_tx( - account_info.clone(), + let fee = block_on(async { + coin.calculate_fee( claim_htlc_tx.msg_payload.clone(), timeout_height, - TX_DEFAULT_MEMO.into(), + TX_DEFAULT_MEMO.to_owned(), ) - .unwrap(); + .await + .unwrap() + }); - let fee = block_on(async { coin.calculate_fee(base_denom.clone(), simulated_tx).await.unwrap() }); + let send_tx_fut = + coin.seq_safe_send_raw_tx_bytes(claim_htlc_tx.msg_payload, fee, timeout_height, TX_DEFAULT_MEMO.into()); - let raw_tx = coin - .any_to_signed_raw_tx( - account_info, - claim_htlc_tx.msg_payload, - fee, - timeout_height, - TX_DEFAULT_MEMO.into(), - ) - .unwrap(); + let (tx_id, _tx_raw) = block_on(async { send_tx_fut.await.unwrap() }); - let tx_bytes = raw_tx.to_bytes().unwrap(); - let send_tx_fut = coin.send_raw_tx_bytes(&tx_bytes).compat(); - block_on(async { - send_tx_fut.await.unwrap(); - }); - println!("Claim HTLC tx hash {}", hex::encode_upper(sha256(&tx_bytes).as_slice())); + println!("Claim HTLC tx hash {}", tx_id); // >> END HTLC CLAIMING } diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 3a0b6af9f1..1da2915074 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -515,16 +515,13 @@ impl MmCoin for TendermintToken { .await .map_to_mm(WithdrawError::Transport)?; - let _sequence_lock = platform.sequence_lock.lock().await; let account_info = platform.my_account_info().await?; - let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; - let simulated_tx = platform - .gen_simulated_tx(account_info.clone(), msg_send.clone(), timeout_height, memo.clone()) - .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; + let fee_amount_u64 = platform + .calculate_fee_amount_as_u64(msg_send.clone(), timeout_height, memo.clone()) + .await?; - let fee_amount_u64 = platform.calculate_fee_amount_as_u64(simulated_tx).await?; let fee_amount_dec = big_decimal_from_sat_unsigned(fee_amount_u64, platform.decimals()); if base_denom_balance < fee_amount_u64 { diff --git a/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs b/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs index c6dd0265b6..6375b31e8c 100644 --- a/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs +++ b/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs @@ -17,8 +17,6 @@ const TBNB_URLS: &[&str] = &["https://data-seed-prebsc-1-s3.binance.org:8545/"]; const TBNB_SWAP_CONTRACT: &str = "0xB1Ad803ea4F57401639c123000C75F5B66E4D123"; #[test] -#[ignore] -// TODO https://github.com/KomodoPlatform/atomicDEX-API/issues/1569 fn start_swap_operation() { let pairs = [ ("USDC-IBC-IRIS", "IRIS-NIMDA"), From 3eaacda6d65ed0576156d4489e062076c08c9da9 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Fri, 3 Mar 2023 18:18:40 +0300 Subject: [PATCH 2/6] add sequence error check in `send_raw_tx_bytes` Signed-off-by: ozkanonur --- mm2src/coins/tendermint/tendermint_coin.rs | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index a8ac4fd6ce..f9f9811af8 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -1819,6 +1819,25 @@ impl MarketCoinOps for TendermintCoin { .broadcast_tx_commit(tx_bytes.into()) .await ); + + if broadcast_res + .check_tx + .log + .to_string() + .contains("incorrect account sequence") + || broadcast_res + .deliver_tx + .log + .to_string() + .contains("incorrect account sequence") + { + return ERR!( + "Wrong account sequence catched. check_tx log: {}, deliver_tx log: {}", + broadcast_res.check_tx.log, + broadcast_res.deliver_tx.log + ); + } + if !broadcast_res.check_tx.code.is_ok() { return ERR!("Tx check failed {:?}", broadcast_res.check_tx); } From 433474618a42b67a3a371d550b309dc88243b7ef Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Mon, 6 Mar 2023 21:42:58 +0300 Subject: [PATCH 3/6] update error handling and `fn platform_denom` Signed-off-by: ozkanonur --- mm2src/coins/tendermint/tendermint_coin.rs | 51 +++++++------------ .../tendermint/tendermint_tx_history_v2.rs | 2 +- 2 files changed, 19 insertions(+), 34 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 0cfa0487e9..75129070d9 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -92,9 +92,11 @@ pub(crate) const TX_DEFAULT_MEMO: &str = ""; const MAX_TIME_LOCK: i64 = 34560; const MIN_TIME_LOCK: i64 = 50; +const ACCOUNT_SEQUENCE_ERR: &str = "incorrect account sequence"; + #[async_trait] pub trait TendermintCommons { - fn platform_denom(&self) -> String; + fn platform_denom(&self) -> &Denom; fn set_history_sync_state(&self, new_state: HistorySyncState); @@ -392,7 +394,7 @@ impl From for SearchForSwapTxSpendErr { #[async_trait] impl TendermintCommons for TendermintCoin { - fn platform_denom(&self) -> String { self.denom.to_string() } + fn platform_denom(&self) -> &Denom { &self.denom } fn set_history_sync_state(&self, new_state: HistorySyncState) { *self.history_sync_state.lock().unwrap() = new_state; @@ -616,7 +618,7 @@ impl TendermintCoin { match self.send_raw_tx_bytes(&try_tx_s!(tx_raw.to_bytes())).compat().await { Ok(tx_id) => break (tx_id, tx_raw), Err(e) => { - if e.contains("Wrong account sequence catched") { + if e.contains(ACCOUNT_SEQUENCE_ERR) { debug!("Got wrong account sequence, trying again."); continue; } @@ -654,22 +656,17 @@ impl TendermintCoin { let raw_response = self.rpc_client().await?.perform(request).await?; - if raw_response - .response - .log - .to_string() - .contains("incorrect account sequence") - { + if raw_response.response.log.to_string().contains(ACCOUNT_SEQUENCE_ERR) { debug!("Got wrong account sequence, trying again."); continue; } match raw_response.response.code { cosmrs::tendermint::abci::Code::Ok => {}, - cosmrs::tendermint::abci::Code::Err(_) => { + cosmrs::tendermint::abci::Code::Err(ecode) => { return MmError::err(TendermintCoinRpcError::InvalidResponse(format!( - "Could not read gas_info. Invalid Response: {}", - raw_response.response.log + "Could not read gas_info. Error code: {} Message: {}", + ecode, raw_response.response.log ))); }, }; @@ -690,7 +687,7 @@ impl TendermintCoin { let amount = ((gas.gas_used as f64 * 1.5) * self.gas_price()).ceil(); let fee_amount = Coin { - denom: self.platform_denom().parse().expect("Platform denom parse can't fail"), + denom: self.platform_denom().clone(), amount: (amount as u64).into(), }; @@ -721,22 +718,17 @@ impl TendermintCoin { let raw_response = self.rpc_client().await?.perform(request).await?; - if raw_response - .response - .log - .to_string() - .contains("incorrect account sequence") - { + if raw_response.response.log.to_string().contains(ACCOUNT_SEQUENCE_ERR) { debug!("Got wrong account sequence, trying again."); continue; } match raw_response.response.code { cosmrs::tendermint::abci::Code::Ok => {}, - cosmrs::tendermint::abci::Code::Err(_) => { + cosmrs::tendermint::abci::Code::Err(ecode) => { return MmError::err(TendermintCoinRpcError::InvalidResponse(format!( - "Could not read gas_info. Invalid Response: {}", - raw_response.response.log + "Could not read gas_info. Error code: {} Message: {}", + ecode, raw_response.response.log ))); }, }; @@ -1820,19 +1812,12 @@ impl MarketCoinOps for TendermintCoin { .await ); - if broadcast_res - .check_tx - .log - .to_string() - .contains("incorrect account sequence") - || broadcast_res - .deliver_tx - .log - .to_string() - .contains("incorrect account sequence") + if broadcast_res.check_tx.log.to_string().contains(ACCOUNT_SEQUENCE_ERR) + || broadcast_res.deliver_tx.log.to_string().contains(ACCOUNT_SEQUENCE_ERR) { return ERR!( - "Wrong account sequence catched. check_tx log: {}, deliver_tx log: {}", + "{}. check_tx log: {}, deliver_tx log: {}", + ACCOUNT_SEQUENCE_ERR, broadcast_res.check_tx.log, broadcast_res.deliver_tx.log ); diff --git a/mm2src/coins/tendermint/tendermint_tx_history_v2.rs b/mm2src/coins/tendermint/tendermint_tx_history_v2.rs index f833594401..fa637e858a 100644 --- a/mm2src/coins/tendermint/tendermint_tx_history_v2.rs +++ b/mm2src/coins/tendermint/tendermint_tx_history_v2.rs @@ -652,7 +652,7 @@ where } let tx_sent_by_me = address == transfer_details.from; - let is_platform_coin_tx = transfer_details.denom == coin.platform_denom(); + let is_platform_coin_tx = transfer_details.denom == coin.platform_denom().to_string(); let is_self_tx = transfer_details.to == transfer_details.from && tx_sent_by_me; let is_sign_claim_htlc = tx_sent_by_me && matches!(transfer_details.transfer_event_type, TransferEventType::ClaimHtlc); From da582578441b4fe94269200f8af20997964f7055 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 9 Mar 2023 21:02:40 +0300 Subject: [PATCH 4/6] fix module doc positioning Signed-off-by: ozkanonur --- mm2src/coins/tendermint/tendermint_token.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 33ae7b852d..906960f7ba 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -1,6 +1,7 @@ +//! Module containing implementation for Tendermint Tokens. They include native assets + IBC + use super::ibc::transfer_v1::MsgTransfer; use super::ibc::IBC_GAS_LIMIT_DEFAULT; -/// Module containing implementation for Tendermint Tokens. They include native assets + IBC use super::{TendermintCoin, TendermintFeeDetails, GAS_LIMIT_DEFAULT, MIN_TX_SATOSHIS, TIMEOUT_HEIGHT_DELTA, TX_DEFAULT_MEMO}; use crate::rpc_command::tendermint::IBCWithdrawRequest; From 365c7dfb0819e711c0ba76293aa542ba8cb907f2 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 9 Mar 2023 21:04:11 +0300 Subject: [PATCH 5/6] decrease swap amount for `iris_swap` Signed-off-by: ozkanonur --- mm2src/mm2_main/tests/mm2_tests/iris_swap.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs b/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs index 2096b98d07..1a47e5ce63 100644 --- a/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs +++ b/mm2src/mm2_main/tests/mm2_tests/iris_swap.rs @@ -23,7 +23,7 @@ fn start_swap_operation() { ("IRIS-NIMDA", "RICK"), ("USDC-IBC-IRIS", "tBNB"), ]; - block_on(trade_base_rel_iris(&pairs, 1, 2, 0.01)); + block_on(trade_base_rel_iris(&pairs, 1, 2, 0.008)); } pub async fn trade_base_rel_iris( From e253d071d9f226cb1bf93ac27f632a4a5b8bfd88 Mon Sep 17 00:00:00 2001 From: ozkanonur Date: Thu, 9 Mar 2023 21:33:40 +0300 Subject: [PATCH 6/6] improve withdraw functions Signed-off-by: ozkanonur --- mm2src/coins/tendermint/tendermint_coin.rs | 12 +++++------- mm2src/coins/tendermint/tendermint_token.rs | 4 ++-- 2 files changed, 7 insertions(+), 9 deletions(-) diff --git a/mm2src/coins/tendermint/tendermint_coin.rs b/mm2src/coins/tendermint/tendermint_coin.rs index 00cf709145..614a6b1352 100644 --- a/mm2src/coins/tendermint/tendermint_coin.rs +++ b/mm2src/coins/tendermint/tendermint_coin.rs @@ -570,7 +570,6 @@ impl TendermintCoin { .await .map_to_mm(WithdrawError::Transport)?; - let account_info = coin.my_account_info().await?; let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; // >> END TX SIMULATION FOR FEE CALCULATION @@ -621,6 +620,7 @@ impl TendermintCoin { .to_any() .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; + let account_info = coin.my_account_info().await?; let tx_raw = coin .any_to_signed_raw_tx(account_info, msg_transfer, fee, timeout_height, memo.clone()) .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; @@ -876,10 +876,9 @@ impl TendermintCoin { .gen_simulated_tx(account_info, msg.clone(), timeout_height, memo.clone()) .map_to_mm(|e| TendermintCoinRpcError::InternalError(format!("{}", e)))?; - let request = SimulateRequest { tx_bytes, tx: None }; let request = AbciRequest::new( Some(path.clone()), - request.encode_to_vec().clone(), + SimulateRequest { tx_bytes, tx: None }.encode_to_vec(), ABCI_REQUEST_HEIGHT, ABCI_REQUEST_PROVE, ); @@ -938,10 +937,10 @@ impl TendermintCoin { let tx_bytes = self .gen_simulated_tx(account_info, msg.clone(), timeout_height, memo.clone()) .map_to_mm(|e| TendermintCoinRpcError::InternalError(format!("{}", e)))?; - let request = SimulateRequest { tx_bytes, tx: None }; + let request = AbciRequest::new( Some(path.clone()), - request.encode_to_vec(), + SimulateRequest { tx_bytes, tx: None }.encode_to_vec(), ABCI_REQUEST_HEIGHT, ABCI_REQUEST_PROVE, ); @@ -1828,8 +1827,6 @@ impl MmCoin for TendermintCoin { .await .map_to_mm(WithdrawError::Transport)?; - let account_info = coin.my_account_info().await?; - let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; // >> END TX SIMULATION FOR FEE CALCULATION @@ -1879,6 +1876,7 @@ impl MmCoin for TendermintCoin { .to_any() .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; + let account_info = coin.my_account_info().await?; let tx_raw = coin .any_to_signed_raw_tx(account_info, msg_send, fee, timeout_height, memo.clone()) .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; diff --git a/mm2src/coins/tendermint/tendermint_token.rs b/mm2src/coins/tendermint/tendermint_token.rs index 906960f7ba..a34b6d347e 100644 --- a/mm2src/coins/tendermint/tendermint_token.rs +++ b/mm2src/coins/tendermint/tendermint_token.rs @@ -171,7 +171,6 @@ impl TendermintToken { .await .map_to_mm(WithdrawError::Transport)?; - let account_info = platform.my_account_info().await?; let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; let fee_amount_u64 = platform @@ -195,6 +194,7 @@ impl TendermintToken { let fee = Fee::from_amount_and_gas(fee_amount, IBC_GAS_LIMIT_DEFAULT); + let account_info = platform.my_account_info().await?; let tx_raw = platform .any_to_signed_raw_tx(account_info, msg_transfer, fee, timeout_height, memo.clone()) .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?; @@ -648,7 +648,6 @@ impl MmCoin for TendermintToken { .await .map_to_mm(WithdrawError::Transport)?; - let account_info = platform.my_account_info().await?; let timeout_height = current_block + TIMEOUT_HEIGHT_DELTA; let fee_amount_u64 = platform @@ -672,6 +671,7 @@ impl MmCoin for TendermintToken { let fee = Fee::from_amount_and_gas(fee_amount, GAS_LIMIT_DEFAULT); + let account_info = platform.my_account_info().await?; let tx_raw = platform .any_to_signed_raw_tx(account_info, msg_send, fee, timeout_height, memo.clone()) .map_to_mm(|e| WithdrawError::InternalError(e.to_string()))?;