From 0b94e6f2b540f9fbf897fbd2406e2aaebd5feae5 Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Wed, 22 Jul 2020 13:09:35 +0300 Subject: [PATCH 01/15] Local run context --- ton_client/client/src/contracts/run.rs | 26 +++++++++++++---------- ton_sdk/src/contract.rs | 29 +++++++++++++++++++++----- ton_sdk/src/json_helper.rs | 4 ++++ ton_sdk/src/lib.rs | 1 + ton_sdk/src/local_tvm.rs | 20 +++++++++++------- ton_sdk/src/tests/test_local_tvm.rs | 4 ++-- 6 files changed, 59 insertions(+), 25 deletions(-) diff --git a/ton_client/client/src/contracts/run.rs b/ton_client/client/src/contracts/run.rs index 4eb5cbde1..297a40ad5 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::{AbiContract, Contract, FunctionCallSet, LocalRunContext, MessageType, Message, + Transaction, TransactionFees}; 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)] @@ -293,7 +295,7 @@ pub(crate) fn local_run(context: &mut ClientContext, params: ParamsOfLocalRun) - .transpose()?; do_local_run( - Some(context), params.call_set, key_pair.as_ref(), address, account, params.full_run, params.time) + Some(context), params.call_set, key_pair.as_ref(), address, account, params.full_run, params.context) } pub(crate) fn local_run_msg(context: &mut ClientContext, params: ParamsOfLocalRunWithMsg) -> ApiResult { @@ -316,7 +318,7 @@ pub(crate) fn local_run_msg(context: &mut ClientContext, params: ParamsOfLocalRu .map_err(|err| ApiError::invalid_params(¶ms.message_base64, err))?; do_local_run_msg( - Some(context), address, account, params.abi, params.function_name, msg, params.full_run, params.time) + Some(context), address, account, params.abi, params.function_name, msg, params.full_run, params.context) } pub(crate) fn encode_message(context: &mut ClientContext, params: ParamsOfRun) -> ApiResult { @@ -579,7 +581,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( @@ -594,7 +596,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( @@ -605,7 +607,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 { @@ -635,7 +637,7 @@ pub(crate) fn do_local_run_msg( }; if full_run { - let result = contract.local_call(msg, time) + let result = contract.local_call(msg, run_context) .map_err(|err| match err.downcast_ref::() { Some(ton_sdk::SdkError::ContractError(exit_code)) => @@ -677,7 +679,9 @@ 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, 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(); diff --git a/ton_sdk/src/contract.rs b/ton_sdk/src/contract.rs index 47ba2c654..4ef98397a 100644 --- a/ton_sdk/src/contract.rs +++ b/ton_sdk/src/contract.rs @@ -596,6 +596,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 { @@ -749,13 +759,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())?; @@ -775,7 +794,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)?; @@ -784,7 +803,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 345a19806..2624a00b6 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, RecievedTransaction, SdkMessage}; diff --git a/ton_sdk/src/local_tvm.rs b/ton_sdk/src/local_tvm.rs index 95a8d8c2b..5c997a0e8 100644 --- a/ton_sdk/src/local_tvm.rs +++ b/ton_sdk/src/local_tvm.rs @@ -135,21 +135,27 @@ 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 last_lt = Arc::new(AtomicU64::new(transaction_lt.unwrap_or(block_lt + 2) - 1)); let executor = OrdinaryTransactionExecutor::new(config); let transaction = executor.execute( Some(&msg), &mut acc_root, timestamp, block_lt, - lt.clone(), + last_lt.clone(), false) .map_err(|err| { match err.downcast_ref::() { diff --git a/ton_sdk/src/tests/test_local_tvm.rs b/ton_sdk/src/tests/test_local_tvm.rs index 12d400575..ee93644cc 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); From aa70428a016bb9bbcbed40ba4cc223227e56eb28 Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Wed, 22 Jul 2020 15:56:58 +0300 Subject: [PATCH 02/15] Fix lt --- ton_sdk/src/local_tvm.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ton_sdk/src/local_tvm.rs b/ton_sdk/src/local_tvm.rs index 5c997a0e8..b3740ff04 100644 --- a/ton_sdk/src/local_tvm.rs +++ b/ton_sdk/src/local_tvm.rs @@ -148,14 +148,14 @@ pub mod executor { let mut acc_root = account.write_to_new_cell()?.into(); let block_lt = block_lt.unwrap_or(transaction_lt.unwrap_or(1_000_001) - 1); - let last_lt = Arc::new(AtomicU64::new(transaction_lt.unwrap_or(block_lt + 2) - 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), &mut acc_root, timestamp, block_lt, - last_lt.clone(), + lt.clone(), false) .map_err(|err| { match err.downcast_ref::() { From 85ec27eda99ce6aff2c4e8b6da8c42daedcce395 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Fri, 7 Aug 2020 13:21:51 +0500 Subject: [PATCH 03/15] 0.26.0 start --- CHANGELOG.md | 7 +++++++ ton_client/client/Cargo.toml | 2 +- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e170522c5..0394b5203 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,13 @@ # 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` + +### Fixed +- incorrect block walking in `wait_for_transaction` in case of shard merging. + ## 0.25.3 Jul 30, 2020 ### New - All methods that require contract's code/data can use field `boc` diff --git a/ton_client/client/Cargo.toml b/ton_client/client/Cargo.toml index fbd80110a..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.3" +version = "0.26.0" authors = ["Michael Vlasov"] edition = "2018" license = "Apache-2.0" From 272ed0068d6596230a76f830cd4c1db9a26e2379 Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Fri, 7 Aug 2020 19:24:52 +0500 Subject: [PATCH 04/15] NEW: default mnemonic params have changed to dictionary:1 (english), wordCount:12, derivation path:"m/44'/396'/0'/0/0" --- ton_client/client/src/crypto/mnemonic.rs | 25 ++++++++++--------- ton_client/client/src/crypto/mod.rs | 6 ++--- ton_client/client/src/tests/mod.rs | 31 +++++++++++++++++++++--- 3 files changed, 44 insertions(+), 18 deletions(-) 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/crypto/mod.rs b/ton_client/client/src/crypto/mod.rs index c4b416ad3..7ea6b84c0 100644 --- a/ton_client/client/src/crypto/mod.rs +++ b/ton_client/client/src/crypto/mod.rs @@ -206,11 +206,11 @@ pub(crate) struct HDKeyGetKeyParams { } fn default_dictionary() -> u8 { - 0 + 1 } fn default_word_count() -> u8 { - 24 + 12 } fn default_hardened() -> bool { @@ -222,7 +222,7 @@ fn default_compliant() -> bool { } fn default_path() -> String { - String::new() + "m/44'/396'/0'/0/0".into() } fn default_result_encoding_hex() -> OutputEncoding { diff --git a/ton_client/client/src/tests/mod.rs b/ton_client/client/src/tests/mod.rs index 76610473a..4107b8b80 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": "owner stock veteran sort resource round smart plug tent picture ozone fury", + }), + )); + assert_eq!(get_map_string(&keys, "public"), "36cf573461971289477d65ebc67664805207d07d1cfb337bc28ff86a3f4fa8c7"); + + 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( @@ -210,18 +220,28 @@ fn test_tg_mnemonic() { let phrase = parse_string(client.request("crypto.mnemonic.from.random", json!({ }))); + assert_eq!(phrase.split(" ").count(), 12); + + 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"); From 8aba0be2d3506cab51696008c152f7c2195a8578 Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Tue, 11 Aug 2020 18:23:03 +0300 Subject: [PATCH 05/15] Rename fields --- ton_sdk/src/contract.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/ton_sdk/src/contract.rs b/ton_sdk/src/contract.rs index 45888b5d4..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, @@ -680,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), @@ -733,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. From 6e37ab40ffebdd9627ce307f606763e0c38395f9 Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Wed, 12 Aug 2020 12:10:42 +0300 Subject: [PATCH 06/15] Update CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 07a408050..611083ac7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,8 @@ 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 From 5e9b41ae6458e49e3fcc6ef6640f83520a86fd5d Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Tue, 18 Aug 2020 18:18:55 +0300 Subject: [PATCH 07/15] More errors with address and function fields --- ton_client/client/src/contracts/deploy.rs | 25 ++++++++++-- ton_client/client/src/contracts/mod.rs | 9 +++-- ton_client/client/src/contracts/run.rs | 48 +++++++++++++---------- 3 files changed, 55 insertions(+), 27 deletions(-) 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 b105786ed..8899b4ab4 100644 --- a/ton_client/client/src/contracts/run.rs +++ b/ton_client/client/src/contracts/run.rs @@ -11,8 +11,8 @@ * limitations under the License. */ -use ton_sdk::{AbiContract, Contract, FunctionCallSet, LocalRunContext, MessageType, Message, - Transaction, TransactionFees}; +use ton_sdk::{Contract, MessageType, AbiContract, FunctionCallSet, Transaction, Message, + TransactionFees}; use ton_sdk::json_abi::encode_function_call; use ton_types::cells_serialization::BagOfCells; use ton_block::{AccStatusChange, Message as TvmMessage, MsgAddressInt}; @@ -618,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) } } @@ -750,7 +751,7 @@ pub(crate) fn resolve_msg_error( err } else { main_error.data["disclaimer"] = "Local contract call succeded. Can not resolve extended error".into(); - main_error + main_error.add_address(&address) } } @@ -759,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)) } From 00503316207bb2d348adb34792764dcb784bb10c Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Tue, 18 Aug 2020 18:24:55 +0300 Subject: [PATCH 08/15] Fix build --- ton_client/client/src/contracts/run.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/ton_client/client/src/contracts/run.rs b/ton_client/client/src/contracts/run.rs index 8899b4ab4..4294b4cd2 100644 --- a/ton_client/client/src/contracts/run.rs +++ b/ton_client/client/src/contracts/run.rs @@ -12,7 +12,7 @@ */ use ton_sdk::{Contract, MessageType, AbiContract, FunctionCallSet, Transaction, Message, - TransactionFees}; + TransactionFees, LocalRunContext}; use ton_sdk::json_abi::encode_function_call; use ton_types::cells_serialization::BagOfCells; use ton_block::{AccStatusChange, Message as TvmMessage, MsgAddressInt}; @@ -744,7 +744,7 @@ pub(crate) fn resolve_msg_error( let mut context = LocalRunContext::default(); context.time = Some(time); - let result = do_local_run_msg(None, address, Some(account), None, None, msg, true, context); + 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(); From 6bfe8439216bb72266623199e94fa394be3c80a5 Mon Sep 17 00:00:00 2001 From: Alexey Vavilin Date: Thu, 20 Aug 2020 15:25:54 +0300 Subject: [PATCH 09/15] Send message is always success --- ton_sdk/src/node_client.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) 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(()) } } From 49284b5cf5646033e3344a1f257b21b12b8c7cea Mon Sep 17 00:00:00 2001 From: Michael Vlasov Date: Tue, 25 Aug 2020 16:57:07 +0500 Subject: [PATCH 10/15] FIX: revert default mnemonic parameters --- ton_client/client/src/crypto/mod.rs | 6 +++--- ton_client/client/src/tests/mod.rs | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ton_client/client/src/crypto/mod.rs b/ton_client/client/src/crypto/mod.rs index 7ea6b84c0..c4b416ad3 100644 --- a/ton_client/client/src/crypto/mod.rs +++ b/ton_client/client/src/crypto/mod.rs @@ -206,11 +206,11 @@ pub(crate) struct HDKeyGetKeyParams { } fn default_dictionary() -> u8 { - 1 + 0 } fn default_word_count() -> u8 { - 12 + 24 } fn default_hardened() -> bool { @@ -222,7 +222,7 @@ fn default_compliant() -> bool { } fn default_path() -> String { - "m/44'/396'/0'/0/0".into() + String::new() } fn default_result_encoding_hex() -> OutputEncoding { diff --git a/ton_client/client/src/tests/mod.rs b/ton_client/client/src/tests/mod.rs index 4107b8b80..3a4fdbe80 100644 --- a/ton_client/client/src/tests/mod.rs +++ b/ton_client/client/src/tests/mod.rs @@ -195,10 +195,10 @@ fn test_tg_mnemonic() { let keys = parse_object(client.request( "crypto.mnemonic.derive.sign.keys", json!({ - "phrase": "owner stock veteran sort resource round smart plug tent picture ozone fury", + "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"), "36cf573461971289477d65ebc67664805207d07d1cfb337bc28ff86a3f4fa8c7"); + assert_eq!(get_map_string(&keys, "public"), "c374990ccacb36a87cb016e54fd6fcf0c344e9b0bc6744d9db89f4c272ef9712"); let keys = parse_object(client.request( "crypto.mnemonic.derive.sign.keys", @@ -220,7 +220,7 @@ fn test_tg_mnemonic() { let phrase = parse_string(client.request("crypto.mnemonic.from.random", json!({ }))); - assert_eq!(phrase.split(" ").count(), 12); + assert_eq!(phrase.split(" ").count(), 24); let phrase = parse_string(client.request("crypto.mnemonic.from.random", json!({ "dictionary": 1, From 29a7d4a6b14a93607522199d9c722719d582efcc Mon Sep 17 00:00:00 2001 From: Victor Korsakov <26911098+diserere@users.noreply.github.com> Date: Tue, 25 Aug 2020 21:05:29 +0300 Subject: [PATCH 11/15] Add conditional run for tests --- Jenkinsfile | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/Jenkinsfile b/Jenkinsfile index d978d5261..42f6cf05e 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1093,6 +1093,11 @@ ton_client/platforms/ton-client-web""" if [ -e 'toDeploy' ] ; then echo 'Remove...' ; rm -rf toDeploy ; fi mkdir toDeploy """ + + /* Compile string for bucket tag */ + BRANCH_NAME_STRIPPED = "${BRANCH_NAME}".replaceAll("[^a-zA-Z0-9_-]+","__") + BUCKET_TAG = "${BRANCH_NAME_STRIPPED}_b${BUILD_ID}" + dir('toDeploy') { unstash 'cl-linux-bin' unstash 'cl-darwin-bin' @@ -1105,6 +1110,9 @@ 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(".", "_") + deployPath = '' sh """ for it in \$(ls) @@ -1112,7 +1120,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 \ From c996263e57b53e8af5e341d4f818b9b89e1dccd0 Mon Sep 17 00:00:00 2001 From: Sergei Voronezhskii Date: Wed, 26 Aug 2020 12:40:50 +0300 Subject: [PATCH 12/15] FIX: replace only dots in git branch name --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 42f6cf05e..f61c81d6b 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1111,7 +1111,7 @@ ton_client/platforms/ton-client-web""" def deployPath = 'tmp_sdk' if(GIT_BRANCH == "${getVar(G_binversion)}-rc") { - TON_SDK_BIN_VERSION = GIT_BRANCH.replaceAll(".", "_") + TON_SDK_BIN_VERSION = GIT_BRANCH.replaceAll("\.", "_") deployPath = '' sh """ From 98c44eb8bcc06c24342648e3b61a4611956df81f Mon Sep 17 00:00:00 2001 From: Sergei Voronezhskii Date: Wed, 26 Aug 2020 12:58:46 +0300 Subject: [PATCH 13/15] FIX: clean unused code --- Jenkinsfile | 4 ---- 1 file changed, 4 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index f61c81d6b..680fcbe0a 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1094,10 +1094,6 @@ ton_client/platforms/ton-client-web""" mkdir toDeploy """ - /* Compile string for bucket tag */ - BRANCH_NAME_STRIPPED = "${BRANCH_NAME}".replaceAll("[^a-zA-Z0-9_-]+","__") - BUCKET_TAG = "${BRANCH_NAME_STRIPPED}_b${BUILD_ID}" - dir('toDeploy') { unstash 'cl-linux-bin' unstash 'cl-darwin-bin' From cab6a43c30cd9da3c4f26e48ad1c2181e6bbcd79 Mon Sep 17 00:00:00 2001 From: Victor Korsakov <26911098+diserere@users.noreply.github.com> Date: Wed, 26 Aug 2020 13:48:02 +0300 Subject: [PATCH 14/15] Fix regexp & clean up unused code --- Jenkinsfile | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/Jenkinsfile b/Jenkinsfile index 42f6cf05e..037f82847 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1094,10 +1094,6 @@ ton_client/platforms/ton-client-web""" mkdir toDeploy """ - /* Compile string for bucket tag */ - BRANCH_NAME_STRIPPED = "${BRANCH_NAME}".replaceAll("[^a-zA-Z0-9_-]+","__") - BUCKET_TAG = "${BRANCH_NAME_STRIPPED}_b${BUILD_ID}" - dir('toDeploy') { unstash 'cl-linux-bin' unstash 'cl-darwin-bin' @@ -1111,7 +1107,8 @@ ton_client/platforms/ton-client-web""" def deployPath = 'tmp_sdk' if(GIT_BRANCH == "${getVar(G_binversion)}-rc") { - TON_SDK_BIN_VERSION = GIT_BRANCH.replaceAll(".", "_") + TON_SDK_BIN_VERSION = GIT_BRANCH.replaceAll("\\.", "_") + echo "TON_SDK_BIN_VERSION: ${TON_SDK_BIN_VERSION}" deployPath = '' sh """ From a390689b9fefc2f81f247480a7d43907cdff1d32 Mon Sep 17 00:00:00 2001 From: Sergei Voronezhskii Date: Wed, 26 Aug 2020 13:50:16 +0300 Subject: [PATCH 15/15] FIX: use replace instead --- Jenkinsfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Jenkinsfile b/Jenkinsfile index 680fcbe0a..5b7736317 100644 --- a/Jenkinsfile +++ b/Jenkinsfile @@ -1107,7 +1107,7 @@ ton_client/platforms/ton-client-web""" def deployPath = 'tmp_sdk' if(GIT_BRANCH == "${getVar(G_binversion)}-rc") { - TON_SDK_BIN_VERSION = GIT_BRANCH.replaceAll("\.", "_") + TON_SDK_BIN_VERSION = GIT_BRANCH.replace(".", "_") deployPath = '' sh """