From d057a6ad9e4e42edd6a22a68cb9d6cbb9caf592c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jon=20H=C3=A4ggblad?= Date: Sun, 25 Sep 2022 10:04:26 +0200 Subject: [PATCH] WIP: first broadcast then poll send tx --- .../src/nymd/cosmwasm_client/client.rs | 44 ++++++++++++++++++- .../nymd/cosmwasm_client/signing_client.rs | 40 +++++++++++++++++ .../validator-client/src/nymd/mod.rs | 29 ++++++++++++ .../src-tauri/src/operations/mixnet/send.rs | 13 +++++- 4 files changed, 123 insertions(+), 3 deletions(-) diff --git a/common/client-libs/validator-client/src/nymd/cosmwasm_client/client.rs b/common/client-libs/validator-client/src/nymd/cosmwasm_client/client.rs index 8da9d3192c..032204c87c 100644 --- a/common/client-libs/validator-client/src/nymd/cosmwasm_client/client.rs +++ b/common/client-libs/validator-client/src/nymd/cosmwasm_client/client.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 use crate::nymd::coin::Coin; -use crate::nymd::cosmwasm_client::helpers::{create_pagination, next_page_key}; +use crate::nymd::cosmwasm_client::helpers::{create_pagination, next_page_key, CheckResponse}; use crate::nymd::cosmwasm_client::types::{ Account, Code, CodeDetails, Contract, ContractCodeHistoryEntry, ContractCodeId, SequenceResponse, SimulateResponse, @@ -203,6 +203,29 @@ pub trait CosmWasmClient: rpc::Client { Ok(self.tx(id, false).await?) } + async fn poll_tx(&self, id: tx::Hash) -> Result { + self.poll_tx2(id).await?.check_response() + } + + async fn poll_tx2(&self, id: tx::Hash) -> Result { + let start = tokio::time::Instant::now(); + loop { + log::debug!("Polling for result of including {id} in a block..."); + if tokio::time::Instant::now().duration_since(start) >= self.broadcast_timeout() { + return Err(NymdError::BroadcastTimeout { + hash: id, + timeout: self.broadcast_timeout(), + }); + } + + if let Ok(poll_res) = self.get_tx(id).await { + return Ok(poll_res); + } + + tokio::time::sleep(self.broadcast_polling_rate()).await; + } + } + async fn search_tx(&self, query: Query) -> Result, NymdError> { // according to https://docs.tendermint.com/master/rpc/#/Info/tx_search // the maximum entries per page is 100 and the default is 30 @@ -294,6 +317,25 @@ pub trait CosmWasmClient: rpc::Client { } } + async fn broadcast_tx_skip_poll( + &self, + tx: Transaction, + ) -> Result { + let broadcasted = CosmWasmClient::broadcast_tx_sync(self, tx).await?; + + if broadcasted.code.is_err() { + let code_val = broadcasted.code.value(); + return Err(NymdError::BroadcastTxErrorDeliverTx { + hash: broadcasted.hash, + height: None, + code: code_val, + raw_log: broadcasted.log.to_string(), + }); + } + + Ok(broadcasted) + } + async fn get_codes(&self) -> Result, NymdError> { let path = Some("/cosmwasm.wasm.v1.Query/Codes".parse().unwrap()); diff --git a/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs b/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs index b1646f663e..65d268af3a 100644 --- a/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs +++ b/common/client-libs/validator-client/src/nymd/cosmwasm_client/signing_client.rs @@ -395,6 +395,26 @@ pub trait SigningCosmWasmClient: CosmWasmClient { .check_response() } + async fn send_tokens_skip_poll( + &self, + sender_address: &AccountId, + recipient_address: &AccountId, + amount: Vec, + fee: Fee, + memo: impl Into + Send + 'static, + ) -> Result { + let send_msg = MsgSend { + from_address: sender_address.clone(), + to_address: recipient_address.clone(), + amount: amount.into_iter().map(Into::into).collect(), + } + .to_any() + .map_err(|_| NymdError::SerializationError("MsgSend".to_owned()))?; + + self.sign_and_broadcast_skip_poll(sender_address, vec![send_msg], fee, memo) + .await + } + async fn send_tokens_multiple( &self, sender_address: &AccountId, @@ -667,6 +687,26 @@ pub trait SigningCosmWasmClient: CosmWasmClient { self.broadcast_tx(tx_bytes.into()).await } + async fn sign_and_broadcast_skip_poll( + &self, + signer_address: &AccountId, + messages: Vec, + fee: Fee, + memo: impl Into + Send + 'static, + ) -> Result { + let memo = memo.into(); + let fee = self + .determine_transaction_fee(signer_address, &messages, fee, &memo) + .await?; + + let tx_raw = self.sign(signer_address, messages, fee, memo).await?; + let tx_bytes = tx_raw + .to_bytes() + .map_err(|_| NymdError::SerializationError("Tx".to_owned()))?; + + self.broadcast_tx_skip_poll(tx_bytes.into()).await + } + fn sign_direct( &self, signer_address: &AccountId, diff --git a/common/client-libs/validator-client/src/nymd/mod.rs b/common/client-libs/validator-client/src/nymd/mod.rs index c062399357..024c1da806 100644 --- a/common/client-libs/validator-client/src/nymd/mod.rs +++ b/common/client-libs/validator-client/src/nymd/mod.rs @@ -1,16 +1,19 @@ // Copyright 2021 - Nym Technologies SA // SPDX-License-Identifier: Apache-2.0 +//use crate::nymd::cosmwasm_client::helpers::CheckResponse; use crate::nymd::cosmwasm_client::signing_client; use crate::nymd::cosmwasm_client::types::{ Account, ChangeAdminResult, ContractCodeId, ExecuteResult, InstantiateOptions, InstantiateResult, MigrateResult, SequenceResponse, SimulateResponse, UploadResult, }; + use crate::nymd::error::NymdError; use crate::nymd::fee::DEFAULT_SIMULATED_GAS_MULTIPLIER; use crate::nymd::wallet::DirectSecp256k1HdWallet; use cosmrs::cosmwasm; use cosmrs::rpc::endpoint::block::Response as BlockResponse; +use cosmrs::rpc::endpoint::broadcast; use cosmrs::rpc::query::Query; use cosmrs::rpc::Error as TendermintRpcError; use cosmrs::rpc::HttpClientUrl; @@ -468,6 +471,13 @@ impl NymdClient { self.client.get_tx(id).await } + pub async fn poll_tx(&self, id: tx::Hash) -> Result + where + C: CosmWasmClient + Sync, + { + self.client.poll_tx(id).await + } + pub async fn search_tx(&self, query: Query) -> Result, NymdError> where C: CosmWasmClient + Sync, @@ -530,6 +540,25 @@ impl NymdClient { .await } + /// Send funds from one address to another. + /// Same as `send` but immediately returns after broadcasting the transaction, skipping to + /// polling step. + pub async fn send_skip_poll( + &self, + recipient: &AccountId, + amount: Vec, + memo: impl Into + Send + 'static, + fee: Option, + ) -> Result + where + C: SigningCosmWasmClient + Sync, + { + let fee = fee.unwrap_or(Fee::Auto(Some(self.simulated_gas_multiplier))); + self.client + .send_tokens_skip_poll(self.address(), recipient, amount, fee, memo) + .await + } + /// Send funds from one address to multiple others pub async fn send_multiple( &self, diff --git a/nym-wallet/src-tauri/src/operations/mixnet/send.rs b/nym-wallet/src-tauri/src/operations/mixnet/send.rs index 0e4cbdd6a3..5ca1eeb695 100644 --- a/nym-wallet/src-tauri/src/operations/mixnet/send.rs +++ b/nym-wallet/src-tauri/src/operations/mixnet/send.rs @@ -27,11 +27,20 @@ pub async fn send( to_address, fee, ); - let raw_res = guard + // broadcast + let broadcasted = guard .current_client()? .nymd - .send(&to_address, vec![amount_base], memo, fee) + .send_skip_poll(&to_address, vec![amount_base], memo, fee) .await?; + + // print tx hash + let tx_hash = broadcasted.hash; + log::info!("{tx_hash}"); + + // wait for completion + let raw_res = guard.current_client()?.nymd.poll_tx(tx_hash).await?; + log::info!("<<< tx hash = {}", raw_res.hash.to_string()); let res = SendTxResult::new( raw_res,