diff --git a/CHANGELOG.md b/CHANGELOG.md index 845b5b813..611083ac7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,12 @@ # Release Notes All notable changes to this project will be documented in this file. +## 0.26.0 Aug 7, 2020 +### New +- `crypto` function `crypto.derive_sign_keys_from_mnemonic` +- full local run functions use `LocalRunContext` to exactly reproduce all transaction parameters and +produce the same result as node + ## 0.25.4 Aug 5, 2020 ### Fixed - `waitForTransaction` didn't use prev_alt_ref for block walking diff --git a/Jenkinsfile b/Jenkinsfile index d978d5261..037f82847 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1093,6 +1093,7 @@ ton_client/platforms/ton-client-web""" if [ -e 'toDeploy' ] ; then echo 'Remove...' ; rm -rf toDeploy ; fi mkdir toDeploy """ + dir('toDeploy') { unstash 'cl-linux-bin' unstash 'cl-darwin-bin' @@ -1105,6 +1106,10 @@ ton_client/platforms/ton-client-web""" unstash 'web-bin' def deployPath = 'tmp_sdk' if(GIT_BRANCH == "${getVar(G_binversion)}-rc") { + + TON_SDK_BIN_VERSION = GIT_BRANCH.replaceAll("\\.", "_") + echo "TON_SDK_BIN_VERSION: ${TON_SDK_BIN_VERSION}" + deployPath = '' sh """ for it in \$(ls) @@ -1112,7 +1117,24 @@ ton_client/platforms/ton-client-web""" mv \$it \$(echo \$it | sed -E \"s/([0-9]+_[0-9]+_[0-9]+)/\\1-rc/\"); done """ + + def params = [ + [ + $class: 'StringParameterValue', + name: 'TON_SDK_BIN_VERSION', + value: "${TON_SDK_BIN_VERSION}" + ], + [ + $class: 'BooleanParameterValue', + name: 'RUN_TESTS_TON_SURF', + value: true + ], + ] + + build job: "Integration/integration-tests/master", parameters: params + } + withAWS(credentials: 'CI_bucket_writer', region: 'eu-central-1') { identity = awsIdentity() s3Upload \ diff --git a/ton_client/client/Cargo.toml b/ton_client/client/Cargo.toml index 53472938d..e7a842f8c 100644 --- a/ton_client/client/Cargo.toml +++ b/ton_client/client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ton_client" -version = "0.25.4" +version = "0.26.0" authors = ["Michael Vlasov"] edition = "2018" license = "Apache-2.0" diff --git a/ton_client/client/src/contracts/deploy.rs b/ton_client/client/src/contracts/deploy.rs index a72cae168..7628ed8c7 100644 --- a/ton_client/client/src/contracts/deploy.rs +++ b/ton_client/client/src/contracts/deploy.rs @@ -32,10 +32,16 @@ pub struct DeployFunctionCallSet { pub constructor_params: serde_json::Value, } +impl DeployFunctionCallSet { + pub fn function_name() -> &'static str { + "constructor" + } +} + impl Into for DeployFunctionCallSet { fn into(self) -> FunctionCallSet { FunctionCallSet { - func: "constructor".to_owned(), + func: Self::function_name().to_owned(), header: self.constructor_header.map(|value| value.to_string().to_owned()), input: self.constructor_params.to_string(), abi: self.abi.to_string(), @@ -133,11 +139,20 @@ pub(crate) async fn deploy(context: &mut ClientContext, params: ParamsOfDeploy) let client = context.get_client()?; trace!("-> -> deploy"); - let tr = deploy_contract(client, params, contract_image, &key_pair).await?; + let tr = deploy_contract(client, params, contract_image, &key_pair) + .await + .map_err(|err| err + .add_function(Some(&DeployFunctionCallSet::function_name())) + .add_network_url(client) + )?; trace!("-> -> deploy transaction: {}", tr.parsed.id()); trace!("<-"); - super::run::check_transaction_status(&tr.parsed, true, &account_id, None)?; + super::run::check_transaction_status(&tr.parsed, true, &account_id, None) + .map_err(|err| err + .add_function(Some(&DeployFunctionCallSet::function_name())) + .add_network_url(client) + )?; Ok(ResultOfDeploy { address: account_encode(&account_id), already_deployed: false, @@ -308,7 +323,9 @@ async fn deploy_contract(client: &NodeClient, params: ParamsOfDeploy, image: Con match result { Err(err) => Err(resolve_msg_sdk_error( - client, err, &msg, ApiError::contracts_deploy_failed).await?), + client, err, &msg, None, + ApiError::contracts_deploy_failed).await? + ), Ok(tr) => Ok(tr) } } diff --git a/ton_client/client/src/contracts/mod.rs b/ton_client/client/src/contracts/mod.rs index ecafa3875..95a4175b4 100644 --- a/ton_client/client/src/contracts/mod.rs +++ b/ton_client/client/src/contracts/mod.rs @@ -296,8 +296,9 @@ pub(crate) async fn process_message(context: &mut ClientContext, params: ParamsO let transaction = match result { Err(err) => return Err(run::resolve_msg_sdk_error( - client, err, &msg, ApiError::contracts_process_message_failed - ).await?), + client, err, &msg, params.function_name.as_ref().map(|string| string.as_str()), ApiError::contracts_process_message_failed + ).await? + ), Ok(tr) => tr }; @@ -368,7 +369,9 @@ pub(crate) async fn wait_transaction(context: &mut ClientContext, params: Params let transaction = match result { Err(err) => return Err(run::resolve_msg_sdk_error( - client, err, &msg, ApiError::contracts_process_message_failed + client, err, &msg, + params.function_name.as_ref().map(|string| string.as_str()), + ApiError::contracts_process_message_failed ).await?), Ok(tr) => tr }; diff --git a/ton_client/client/src/contracts/run.rs b/ton_client/client/src/contracts/run.rs index 934990747..4294b4cd2 100644 --- a/ton_client/client/src/contracts/run.rs +++ b/ton_client/client/src/contracts/run.rs @@ -11,11 +11,11 @@ * limitations under the License. */ -use ton_sdk::{Contract, MessageType, AbiContract, FunctionCallSet}; +use ton_sdk::{Contract, MessageType, AbiContract, FunctionCallSet, Transaction, Message, + TransactionFees, LocalRunContext}; use ton_sdk::json_abi::encode_function_call; use ton_types::cells_serialization::BagOfCells; use ton_block::{AccStatusChange, Message as TvmMessage, MsgAddressInt}; -use ton_sdk::{Transaction, Message, TransactionFees}; use crate::contracts::{EncodedMessage, EncodedUnsignedMessage}; use crate::client::ClientContext; @@ -76,7 +76,8 @@ pub(crate) struct ParamsOfLocalRun { pub key_pair: Option, #[serde(default)] pub full_run: bool, - pub time: Option, + #[serde(flatten)] + pub context: LocalRunContext, } #[derive(Serialize, Deserialize)] @@ -89,7 +90,8 @@ pub(crate) struct ParamsOfLocalRunWithMsg { pub message_base64: String, #[serde(default)] pub full_run: bool, - pub time: Option, + #[serde(flatten)] + pub context: LocalRunContext, } #[derive(Serialize, Deserialize)] @@ -320,7 +322,7 @@ pub(crate) fn local_run(context: &mut ClientContext, params: ParamsOfLocalRun) - address, account, params.full_run, - params.time, + params.context, ).map_err(|err| match context.get_client() { Ok(client) => err.add_network_url(client), Err(_) => err @@ -356,7 +358,7 @@ pub(crate) fn local_run_msg(context: &mut ClientContext, params: ParamsOfLocalRu params.function_name, msg, params.full_run, - params.time, + params.context, ).map_err(|err| match context.get_client() { Ok(client) => err.add_network_url(client), Err(_) => err @@ -616,7 +618,8 @@ async fn call_contract( match result { Err(err) => Err(resolve_msg_sdk_error( - client, err, &msg, ApiError::contracts_run_failed).await?), + client, err, &msg, Some(¶ms.call_set.function_name), ApiError::contracts_run_failed + ).await?), Ok(tr) => Ok(tr) } } @@ -630,7 +633,7 @@ pub(crate) fn do_local_run( address: MsgAddressInt, account: Option, full_run: bool, - time: Option, + run_context: LocalRunContext, ) -> ApiResult { let msg = Contract::construct_call_message_json( address.clone(), call_set.clone().into(), false, keys, None, None) @@ -644,7 +647,7 @@ pub(crate) fn do_local_run( Some(call_set.function_name), msg.message, full_run, - time) + run_context) } pub(crate) fn do_local_run_msg( @@ -655,7 +658,7 @@ pub(crate) fn do_local_run_msg( function_name: Option, msg: TvmMessage, full_run: bool, - time: Option, + run_context: LocalRunContext, ) -> ApiResult { let contract = match account { // load contract data from node manually @@ -684,8 +687,8 @@ pub(crate) fn do_local_run_msg( }; if full_run { - let result = contract.local_call(msg, time) - .map_err(|err| + let result = contract.local_call(msg, run_context) + .map_err(|err| match err.downcast_ref::() { Some(ton_sdk::SdkError::ContractError(exit_code)) => ApiError::tvm_execution_failed(None, *exit_code, &address), @@ -739,14 +742,16 @@ pub(crate) fn resolve_msg_error( Err(err) => return err }; - let result = do_local_run_msg(None, address, Some(account), None, None, msg, true, Some(time)); + let mut context = LocalRunContext::default(); + context.time = Some(time); + let result = do_local_run_msg(None, address.clone(), Some(account), None, None, msg, true, context); if let Err(mut err) = result { err.data["original_error"] = serde_json::to_value(main_error).unwrap_or_default(); err } else { main_error.data["disclaimer"] = "Local contract call succeded. Can not resolve extended error".into(); - main_error + main_error.add_address(&address) } } @@ -755,23 +760,30 @@ pub(crate) async fn resolve_msg_sdk_error ApiError>( client: &NodeClient, error: failure::Error, msg: &ton_sdk::SdkMessage, + function: Option<&str>, default_error: F, ) -> ApiResult { - match error.downcast_ref::() { - Some(SdkError::MessageExpired { msg_id: _, expire: _, sending_time, block_time: _, block_id: _ }) | - Some(SdkError::TransactionWaitTimeout { msg_id: _, sending_time, timeout: _, state: _ }) => { - let account = Contract::load(client, &msg.address) - .await - .map_err(|err| apierror_from_sdkerror( - &err, ApiError::contracts_run_contract_load_failed, Some(client), - ).add_address(&msg.address))? - .ok_or(ApiError::account_missing(&msg.address))?; - let main_error = apierror_from_sdkerror(&error, default_error, None); - let resolved = resolve_msg_error( - msg.address.clone(), account, &msg.serialized_message, *sending_time, main_error, - ).add_network_url(client); - Ok(resolved) + let err = { + match error.downcast_ref::() { + Some(SdkError::MessageExpired { msg_id: _, expire: _, sending_time, block_time: _, block_id: _ }) | + Some(SdkError::TransactionWaitTimeout { msg_id: _, sending_time, timeout: _, state: _ }) => { + let account = Contract::load(client, &msg.address) + .await + .map_err(|err| apierror_from_sdkerror( + &err, ApiError::contracts_run_contract_load_failed, Some(client), + ).add_address(&msg.address))? + .ok_or(ApiError::account_missing(&msg.address))?; + let main_error = apierror_from_sdkerror(&error, default_error, None); + let resolved = resolve_msg_error( + msg.address.clone(), account, &msg.serialized_message, *sending_time, main_error, + ); + Ok(resolved) + } + _ => Err(apierror_from_sdkerror(&error, default_error, Some(client))) } - _ => Err(apierror_from_sdkerror(&error, default_error, Some(client))) - } + }?; + Ok(err + .add_network_url(client) + .add_function(function) + .add_address(&msg.address)) } diff --git a/ton_client/client/src/crypto/mnemonic.rs b/ton_client/client/src/crypto/mnemonic.rs index d52f2745c..cd1376cb5 100644 --- a/ton_client/client/src/crypto/mnemonic.rs +++ b/ton_client/client/src/crypto/mnemonic.rs @@ -36,6 +36,14 @@ pub trait CryptoMnemonic { fn entropy_from_phrase(&self, phrase: &String) -> ApiResult; } +fn check_phrase(mnemonic: &dyn CryptoMnemonic, phrase: &String) -> ApiResult<()> { + if mnemonic.is_phrase_valid(phrase)? { + Ok(()) + } else { + Err(ApiError::crypto_bip39_invalid_phrase(phrase)) + } +} + pub struct Bip39Mnemonic { mnemonic_type: MnemonicType, language: Language, @@ -84,6 +92,7 @@ impl CryptoMnemonic for Bip39Mnemonic { path: &String, compliant: bool, ) -> ApiResult { + check_phrase(self, phrase)?; let derived = HDPrivateKey::from_mnemonic(phrase)?.derive_path(path, compliant)?; ed25519_keys_from_secret_bytes(&derived.secret()) } @@ -99,6 +108,7 @@ impl CryptoMnemonic for Bip39Mnemonic { } fn seed_from_phrase_and_salt(&self, phrase: &String, salt: &String) -> ApiResult { + check_phrase(self, phrase)?; let mnemonic = Mnemonic::from_phrase(phrase, self.language) .map_err(|err| ApiError::crypto_bip39_invalid_phrase(err))?; @@ -115,6 +125,7 @@ impl CryptoMnemonic for Bip39Mnemonic { #[allow(dead_code)] fn entropy_from_phrase(&self, phrase: &String) -> ApiResult { + check_phrase(self, phrase)?; let mnemonic = Mnemonic::from_phrase(phrase, self.language) .map_err(|err| ApiError::crypto_bip39_invalid_phrase(err))?; Ok(hex::encode(mnemonic.entropy())) @@ -169,14 +180,6 @@ impl TonMnemonic { }; count == self.word_count && Self::is_basic_seed(phrase) } - - fn check_phrase(&self, phrase: &String) -> ApiResult<()> { - if self.internal_is_phrase_valid(phrase) { - Ok(()) - } else { - Err(ApiError::crypto_bip39_invalid_phrase(phrase)) - } - } } @@ -205,7 +208,7 @@ impl CryptoMnemonic for TonMnemonic { _path: &String, _compliant: bool, ) -> ApiResult { - self.check_phrase(phrase)?; + check_phrase(self, phrase)?; let seed = Self::seed_from_string(&phrase, "TON default seed", 100_000); ed25519_keys_from_secret_bytes(&seed[..32]) } @@ -227,12 +230,12 @@ impl CryptoMnemonic for TonMnemonic { } fn seed_from_phrase_and_salt(&self, phrase: &String, salt: &String) -> ApiResult { - self.check_phrase(phrase)?; + check_phrase(self, phrase)?; Ok(hex::encode(Self::seed_from_string(phrase, salt, 100_000).as_ref())) } fn entropy_from_phrase(&self, phrase: &String) -> ApiResult { - self.check_phrase(phrase)?; + check_phrase(self, phrase)?; Ok(hex::encode(Self::entropy_from_string(&phrase).as_ref())) } } diff --git a/ton_client/client/src/tests/mod.rs b/ton_client/client/src/tests/mod.rs index 76610473a..3a4fdbe80 100644 --- a/ton_client/client/src/tests/mod.rs +++ b/ton_client/client/src/tests/mod.rs @@ -195,7 +195,17 @@ fn test_tg_mnemonic() { let keys = parse_object(client.request( "crypto.mnemonic.derive.sign.keys", json!({ - "phrase": "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry teach mechanic rain float vicious solution assume hedgehog rail sort chuckle" + "phrase": "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry teach mechanic rain float vicious solution assume hedgehog rail sort chuckle", + }), + )); + assert_eq!(get_map_string(&keys, "public"), "c374990ccacb36a87cb016e54fd6fcf0c344e9b0bc6744d9db89f4c272ef9712"); + + let keys = parse_object(client.request( + "crypto.mnemonic.derive.sign.keys", + json!({ + "phrase": "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry teach mechanic rain float vicious solution assume hedgehog rail sort chuckle", + "dictionary": 0, + "wordCount": 24, }), )); let ton_public = parse_string(client.request( @@ -212,16 +222,26 @@ fn test_tg_mnemonic() { }))); assert_eq!(phrase.split(" ").count(), 24); + let phrase = parse_string(client.request("crypto.mnemonic.from.random", json!({ + "dictionary": 1, + "wordCount": 24, + }))); + assert_eq!(phrase.split(" ").count(), 24); + let entropy = "2199ebe996f14d9e4e2595113ad1e6276bd05e2e147e16c8ab8ad5d47d13b44fcf"; let mnemonic = parse_string(client.request("crypto.mnemonic.from.entropy", json!({ + "dictionary": 0, + "wordCount": 24, "entropy": json!({ - "hex": entropy + "hex": entropy, }), }))); let public = get_map_string(&parse_object(client.request( "crypto.mnemonic.derive.sign.keys", json!({ - "phrase": mnemonic + "phrase": mnemonic, + "dictionary": 0, + "wordCount": 24 }), )), "public"); let ton_public = parse_string(client.request( @@ -229,11 +249,14 @@ fn test_tg_mnemonic() { Value::String(public), )); assert_eq!(ton_public, "PuYGEX9Zreg-CX4Psz5dKehzW9qCs794oBVUKqqFO7aWAOTD"); + // let ton_phrase = "shove often foil innocent soft slim pioneer day uncle drop nephew soccer worry renew public hand word nut again dry first delay first maple"; let is_valid = client.request( "crypto.mnemonic.verify", json!({ - "phrase": "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry teach mechanic rain float vicious solution assume hedgehog rail sort chuckle" + "phrase": "unit follow zone decline glare flower crisp vocal adapt magic much mesh cherry teach mechanic rain float vicious solution assume hedgehog rail sort chuckle", + "dictionary": 0, + "wordCount": 24, }), ).unwrap(); assert_eq!(is_valid, "true"); diff --git a/ton_sdk/src/contract.rs b/ton_sdk/src/contract.rs index aa63a6e5c..b33c7f03d 100644 --- a/ton_sdk/src/contract.rs +++ b/ton_sdk/src/contract.rs @@ -181,16 +181,16 @@ pub struct Contract { pub balance_other: Option>, // Obsolete. You must use the `boc` instead. - #[serde(with = "json_helper::opt_cell", rename = "code")] - pub _code: Option, + #[serde(with = "json_helper::opt_cell")] + pub code: Option, pub code_hash: Option, pub data_hash: Option, // Obsolete. You must use the `boc` instead. - #[serde(with = "json_helper::opt_cell", rename = "data")] - pub _data: Option, + #[serde(with = "json_helper::opt_cell")] + pub data: Option, #[serde(with = "json_helper::opt_cell")] pub boc: Option, @@ -589,6 +589,16 @@ pub struct ShardDescr { pub shard: u64, } +#[derive(Deserialize, Serialize, Debug, Default, Clone)] +#[serde(default, rename_all = "camelCase")] +pub struct LocalRunContext { + #[serde(with = "json_helper::opt_cell")] + pub config_boc: Option, + pub time: Option, + pub transaction_lt: Option, + pub block_lt: Option +} + impl Contract { /// Returns contract's address pub fn address(&self) -> MsgAddressInt { @@ -670,8 +680,8 @@ impl Contract { acc_type: acc.status(), balance, balance_other: if balance_other.len() > 0 { Some(balance_other) } else { None }, - _code: code, - _data: data, + code: code, + data: data, code_hash, data_hash, boc: Some(boc), @@ -723,11 +733,11 @@ impl Contract { } pub fn get_code(&self) -> Option { - self.get_acc_cell(&self._code, |acc| acc.get_code()) + self.get_acc_cell(&self.code, |acc| acc.get_code()) } pub fn get_data(&self) -> Option { - self.get_acc_cell(&self._data, |acc| acc.get_data()) + self.get_acc_cell(&self.data, |acc| acc.get_data()) } /// Invokes local TVM instance with provided inbound message. @@ -809,13 +819,22 @@ impl Contract { /// Invokes local transaction executor instance with provided inbound message. /// Returns outbound messages generated by contract function and transaction fees - pub fn local_call(&self, message: TvmMessage, time: Option) -> Result { + pub fn local_call(&self, message: TvmMessage, context: LocalRunContext) -> Result { // TODO: get real config + let config = match context.config_boc { + Some(cell) => { + BlockchainConfig::with_config( + ton_block::ConfigParams::construct_from(&mut cell.into())?)? + } + None => BlockchainConfig::default() + }; let (transaction, account_root) = local_tvm::executor::call_executor( self.to_account()?, message, - BlockchainConfig::default(), - time.unwrap_or(Self::now()))?; + config, + context.time.unwrap_or(Self::now()), + context.block_lt, + context.transaction_lt)?; let transaction = Transaction::try_from(transaction)?; let updated_account = Self::from_cells(account_root.clone().into())?; @@ -835,7 +854,7 @@ impl Contract { input: String, abi: String, key_pair: Option<&Keypair>, - time: Option, + context: LocalRunContext ) -> Result { // pack params into bag of cells via ABI let msg_body = ton_abi::encode_function_call(abi, func, header, input, false, key_pair)?; @@ -844,7 +863,7 @@ impl Contract { let msg = Self::create_message(address, msg_body.into())?; - self.local_call(msg, time) + self.local_call(msg, context) } /// Decodes output parameters returned by contract function call diff --git a/ton_sdk/src/json_helper.rs b/ton_sdk/src/json_helper.rs index 8a015b3ae..ba63dae28 100644 --- a/ton_sdk/src/json_helper.rs +++ b/ton_sdk/src/json_helper.rs @@ -44,6 +44,10 @@ impl<'de> serde::de::Visitor<'de> for StringVisitor { { d.deserialize_string(StringVisitor) } + + fn visit_unit(self) -> Result { + Ok("null".to_owned()) + } } struct U8Visitor; diff --git a/ton_sdk/src/lib.rs b/ton_sdk/src/lib.rs index ad398ddab..209d30324 100644 --- a/ton_sdk/src/lib.rs +++ b/ton_sdk/src/lib.rs @@ -35,6 +35,7 @@ pub use contract::{ Contract, ContractImage, FunctionCallSet, + LocalRunContext, MessageProcessingState, ReceivedTransaction, SdkMessage}; diff --git a/ton_sdk/src/local_tvm.rs b/ton_sdk/src/local_tvm.rs index 95a8d8c2b..b3740ff04 100644 --- a/ton_sdk/src/local_tvm.rs +++ b/ton_sdk/src/local_tvm.rs @@ -135,14 +135,20 @@ pub mod executor { Serializable, }; use ton_executor::ExecutorError; - - pub(crate) fn call_executor(account: Account, msg: Message, config: BlockchainConfig, timestamp: u32) - -> Result<(Transaction, Cell)> - { + use std::sync::atomic::AtomicU64; + + pub(crate) fn call_executor( + account: Account, + msg: Message, + config: BlockchainConfig, + timestamp: u32, + block_lt: Option, + transaction_lt: Option, + ) -> Result<(Transaction, Cell)> { let mut acc_root = account.write_to_new_cell()?.into(); - let block_lt = 1_000_000; - let lt = Arc::new(std::sync::atomic::AtomicU64::new(block_lt + 1)); + let block_lt = block_lt.unwrap_or(transaction_lt.unwrap_or(1_000_001) - 1); + let lt = Arc::new(AtomicU64::new(transaction_lt.unwrap_or(block_lt + 1))); let executor = OrdinaryTransactionExecutor::new(config); let transaction = executor.execute( Some(&msg), diff --git a/ton_sdk/src/node_client.rs b/ton_sdk/src/node_client.rs index 475cecf7d..c15507125 100644 --- a/ton_sdk/src/node_client.rs +++ b/ton_sdk/src/node_client.rs @@ -15,7 +15,7 @@ use crate::{NodeClientConfig, TimeoutsConfig}; use crate::error::SdkError; use graphite::client::GqlClient; use graphite::types::{VariableRequest}; -use futures::{TryFutureExt, Stream, StreamExt}; +use futures::{Stream, StreamExt}; use serde_json::Value; use reqwest::{ClientBuilder}; use reqwest::StatusCode; @@ -365,11 +365,14 @@ impl NodeClient { }; let client = self.client.as_ref().ok_or(SdkError::SdkNotInitialized)?; - client.query_vars(Self::generate_post_mutation(&[request])?) - .map_err(|_| SdkError::NetworkError { - msg: "Post message error: server did not responded".to_owned() - }.into()) - .map_ok(|_| ()) - .await + let result = client.query_vars(Self::generate_post_mutation(&[request])?).await; + + // send message is always successful in order to process case when server received message + // but client didn't receive responce + if let Err(err) = result { + log::warn!("Post message error: {}", err); + } + + Ok(()) } } diff --git a/ton_sdk/src/tests/test_local_tvm.rs b/ton_sdk/src/tests/test_local_tvm.rs index 7880a97f2..566b702e7 100644 --- a/ton_sdk/src/tests/test_local_tvm.rs +++ b/ton_sdk/src/tests/test_local_tvm.rs @@ -58,7 +58,7 @@ fn test_local_call_accept_error() { "{}".to_owned(), PIGGY_BANK_CONTRACT_ABI.to_owned(), None, - None); + Default::default()); assert!(result.is_err()); } @@ -73,7 +73,7 @@ fn test_executor_call() { "{\"to\": \"0:e6392da8a96f648098f818501f0211f27c89675e5f196445d211947b48e7c85b\"}".to_owned(), PIGGY_BANK_CONTRACT_ABI.to_owned(), Some(&keypair), - None).expect("Error calling contract"); + Default::default()).expect("Error calling contract"); assert!(result.transaction.out_messages.len() == 1); assert!(!result.transaction.aborted);