From 5f5ac20860d2768a80b0e75957ca86c4aea40a59 Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Thu, 2 Feb 2023 20:40:56 +0300 Subject: [PATCH 1/9] fix for solidity config --- Cargo.toml | 5 +-- src/getconfig.rs | 88 ++++++++++++++++++++++++++++++++++++++---------- src/main.rs | 6 ++-- 3 files changed, 78 insertions(+), 21 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 987e6867..b82bb126 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,8 @@ license = 'Apache-2.0' name = 'tonos-cli' readme = 'README.md' repository = 'https://github.com/tonlabs/tonos-cli' -version = '0.31.0' +version = '0.32.0' +default-run = 'tonos-cli' [features] sold = ["dep:sold"] @@ -51,7 +52,7 @@ ton_abi = { git = 'https://github.com/tonlabs/ton-labs-abi.git', tag = '2.3.54' ton_block = { git = 'https://github.com/tonlabs/ton-labs-block.git', tag = '1.9.18' } ton_block_json = { git = 'https://github.com/tonlabs/ton-labs-block-json.git', tag = '0.7.83' } ton_client = { git = 'https://github.com/tonlabs/TON-SDK.git', tag = '1.40.0' } -ton_executor = { default-features = false, git = 'https://github.com/tonlabs/ton-labs-executor.git', tag = '1.15.154' } +ton_executor = { git = 'https://github.com/tonlabs/ton-labs-executor.git', tag = '1.15.154' } ton_labs_assembler = { git = 'https://github.com/tonlabs/ton-labs-assembler.git', tag = '1.2.77' } ton_sdk = { git = 'https://github.com/tonlabs/TON-SDK.git', tag = '1.40.0' } ton_types = { git = 'https://github.com/tonlabs/ton-labs-types.git', tag = '1.12.6' } diff --git a/src/getconfig.rs b/src/getconfig.rs index 0160859c..0de1550b 100644 --- a/src/getconfig.rs +++ b/src/getconfig.rs @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 TON DEV SOLUTIONS LTD. + * Copyright 2018-2023 TON DEV SOLUTIONS LTD. * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. @@ -10,10 +10,14 @@ * See the License for the specific TON DEV software governing permissions and * limitations under the License. */ + +use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signer}; +use num_bigint::BigUint; use std::time::{SystemTime, UNIX_EPOCH}; -use crate::helpers::{create_client_verbose, query_with_limit}; use crate::config::Config; -use serde_json::{json}; +use crate::helpers::{create_client_verbose, query_with_limit}; +use serde_json::json; +use ton_abi::{Contract, Token, TokenValue, Uint}; use ton_block::{ExternalInboundMessageHeader, Grams, Message, MsgAddressInt, Serializable}; use ton_block::MsgAddressExt::AddrNone; use ton_client::net::{OrderBy, SortDirection}; @@ -317,26 +321,29 @@ pub async fn query_global_config(config: &Config, index: Option<&str>) -> Result } pub async fn gen_update_config_message( - seqno: &str, + abi: Option<&str>, + seqno: Option<&str>, config_master_file: &str, new_param_file: &str, is_json: bool ) -> Result<(), String> { - let seqno = u32::from_str_radix(seqno, 10) - .map_err(|e| format!(r#"failed to parse "seqno": {}"#, e))?; - let config_master_address = std::fs::read(&*(config_master_file.to_string() + ".addr")) .map_err(|e| format!(r#"failed to read "config_master": {}"#, e))?; let config_account = ton_types::AccountId::from_raw(config_master_address, 32*8); - let private_key = std::fs::read(&*(config_master_file.to_string() + ".pk")) + let private_key_of_config_account = std::fs::read(&*(config_master_file.to_string() + ".pk")) .map_err(|e| format!(r#"failed to read "config_master": {}"#, e))?; let config_str = std::fs::read_to_string(new_param_file) .map_err(|e| format!(r#"failed to read "new_param_file": {}"#, e))?; let (config_cell, key_number) = serialize_config_param(config_str)?; - let message = prepare_message_new_config_param(config_cell, seqno, key_number, config_account, private_key)?; + let message = if let Some(abi) = abi { + prepare_message_new_config_param_solidity(abi, config_cell, key_number, config_account, &private_key_of_config_account)? + } else { + let seqno = seqno.unwrap().parse().map_err(|e| format!(r#"failed to parse "seqno": {}"#, e))?; + prepare_message_new_config_param(config_cell, seqno, key_number, config_account, &private_key_of_config_account)? + }; let msg_bytes = message.write_to_bytes() .map_err(|e| format!(r#"failed to serialize message": {}"#, e))?; @@ -394,7 +401,7 @@ fn prepare_message_new_config_param( seqno: u32, key_number: u32, config_account: SliceData, - private_key_of_config_account: Vec + private_key_of_config_account: &[u8] ) -> Result { let prefix = hex::decode(PREFIX_UPDATE_CONFIG_MESSAGE_DATA).unwrap(); let since_the_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32 + 100; // timestamp + 100 secs @@ -406,15 +413,15 @@ fn prepare_message_new_config_param( cell.append_i32(key_number as i32).unwrap(); cell.checked_append_reference(config_param.clone()).unwrap(); - let exp_key = ed25519_dalek::ExpandedSecretKey::from( - &ed25519_dalek::SecretKey::from_bytes(private_key_of_config_account.as_slice() - ) - .map_err(|e| format!(r#"failed to read private key from config-master file": {}"#, e))?); - let pub_key = ed25519_dalek::PublicKey::from(&exp_key); - let msg_signature = exp_key.sign(cell.finalize(0).unwrap().repr_hash().into_vec().as_slice(), &pub_key).to_bytes().to_vec(); + let secret = SecretKey::from_bytes(private_key_of_config_account) + .map_err(|e| format!(r#"failed to read private key from config-master file": {}"#, e))?; + let public = PublicKey::from(&secret); + let keypair = Keypair { secret, public }; + + let msg_signature = keypair.sign(cell.finalize(0).unwrap().repr_hash().as_slice()).to_bytes(); let mut cell = BuilderData::default(); - cell.append_raw(msg_signature.as_slice(), 64*8).unwrap(); + cell.append_raw(&msg_signature, 64*8).unwrap(); cell.append_raw(prefix.as_slice(), 32).unwrap(); cell.append_u32(seqno).unwrap(); cell.append_u32(since_the_epoch).unwrap(); @@ -430,6 +437,53 @@ fn prepare_message_new_config_param( Ok(message) } +fn prepare_message_new_config_param_solidity( + abi: &str, + config_param: Cell, + key_number: u32, + config_account: SliceData, + private_key_of_config_account: &[u8] +) -> Result { + let secret = SecretKey::from_bytes(private_key_of_config_account) + .map_err(|e| format!(r#"failed to read private key from config-master file": {}"#, e))?; + let public = PublicKey::from(&secret); + let keypair = Keypair { secret, public }; + + let config_contract_address = MsgAddressInt::with_standart(None, -1, config_account).unwrap(); + let since_the_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_micros() as u64; + + let header = [("time".to_owned(), TokenValue::Time(since_the_epoch))] + .into_iter() + .collect(); + + let parameters = [ + Token::new("index", convert_to_uint(&key_number.to_be_bytes(), 32)), + Token::new("data", TokenValue::Cell(config_param)), + ]; + + let abi = std::fs::read(abi) + .map_err(|err| format!("cannot read abi file {}: {}", abi, err))?; + let contract = Contract::load(&*abi) + .map_err(|err| err.to_string())?; + let function = contract.function("set_config_param") + .map_err(|err| err.to_string())?; + let body = function + .encode_input(&header, ¶meters, false, Some(&keypair), Some(config_contract_address.clone())) + .and_then(|builder| SliceData::load_builder(builder)) + .map_err(|err| format!("cannot prepare message body {}", err))?; + + let hdr = ExternalInboundMessageHeader::new(AddrNone, config_contract_address); + Ok(Message::with_ext_in_header_and_body(hdr, body)) +} + +fn convert_to_uint(value: &[u8], bits_count: usize) -> TokenValue { + assert!(value.len() * 8 >= bits_count); + TokenValue::Uint(Uint { + number: BigUint::from_bytes_be(value), + size: bits_count, + }) +} + pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), String> { let ton = create_client_verbose(&config)?; diff --git a/src/main.rs b/src/main.rs index 61f8bb50..c02d2a8a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -783,6 +783,7 @@ async fn main_internal() -> Result <(), String> { let update_config_param_cmd = SubCommand::with_name("update_config") .about("Generates message with update of config params.") + .arg(abi_arg.clone()) .arg(Arg::with_name("SEQNO") .takes_value(true) .help("Current seqno from config contract")) @@ -983,7 +984,7 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), return config_command(m, full_config, is_json); } - full_config.config.is_json = is_json || full_config.config.is_json; + full_config.config.is_json |= is_json; let config = &mut full_config.config; if let Some(url) = matches.value_of("NETWORK") { @@ -1628,13 +1629,14 @@ async fn getconfig_command(matches: &ArgMatches<'_>, config: &Config) -> Result< } async fn update_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + let abi = matches.value_of("ABI"); let seqno = matches.value_of("SEQNO"); let config_master = matches.value_of("CONFIG_MASTER_KEY_FILE"); let new_param = matches.value_of("NEW_PARAM_FILE"); if !config.is_json { print_args!(seqno, config_master, new_param); } - gen_update_config_message(seqno.unwrap(), config_master.unwrap(), new_param.unwrap(), config.is_json).await + gen_update_config_message(abi, seqno, config_master.unwrap(), new_param.unwrap(), config.is_json).await } async fn dump_bc_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { From e876bae6532d926767695b829796f2a4297ab064 Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Tue, 28 Feb 2023 22:38:41 +0300 Subject: [PATCH 2/9] fix for clippy --- CHANGELOG.md | 5 ++ Cargo.toml | 20 ++++---- README.md | 45 ++++++++++++++++- build.rs | 8 +-- src/account.rs | 20 +++----- src/call.rs | 24 ++++----- src/completion.rs | 18 +++---- src/config.rs | 23 ++++----- src/convert.rs | 4 +- src/crypto.rs | 11 ++-- src/debot/pipechain.rs | 6 +-- src/debot/processor.rs | 6 +-- src/debot/term_encryption_box.rs | 2 +- src/debug.rs | 52 +++++++++---------- src/decode.rs | 45 ++++++++--------- src/deploy.rs | 4 +- src/depool.rs | 48 +++++++++--------- src/genaddr.rs | 2 +- src/getconfig.rs | 40 ++++++++------- src/helpers.rs | 69 +++++++++++++------------ src/main.rs | 87 ++++++++++++++++---------------- src/message.rs | 17 +++---- src/multisig.rs | 9 ++-- src/replay.rs | 16 +++--- src/run.rs | 57 ++++++++++----------- src/sendfile.rs | 2 +- tests/browser.rs | 2 +- tests/common/mod.rs | 7 ++- tests/test_cli.rs | 14 ++--- 29 files changed, 342 insertions(+), 321 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e1064a28..ef81aaba 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,11 @@ All notable changes to this project will be documented in this file. +## Version: 0.30.2 + +### New +- Added ABI parameter to `update_config` command for solidity config contract; + ## Version: 0.30.1 ### New diff --git a/Cargo.toml b/Cargo.toml index b82bb126..d4f496c0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,16 +48,16 @@ log = { features = [ 'std' ], version = '0.4' } serde = { features = [ 'derive' ], version = '1.0' } tokio = { default-features = false, features = [ 'full' ], version = '1.21' } url = '2.3.1' -ton_abi = { git = 'https://github.com/tonlabs/ton-labs-abi.git', tag = '2.3.54' } -ton_block = { git = 'https://github.com/tonlabs/ton-labs-block.git', tag = '1.9.18' } -ton_block_json = { git = 'https://github.com/tonlabs/ton-labs-block-json.git', tag = '0.7.83' } -ton_client = { git = 'https://github.com/tonlabs/TON-SDK.git', tag = '1.40.0' } -ton_executor = { git = 'https://github.com/tonlabs/ton-labs-executor.git', tag = '1.15.154' } -ton_labs_assembler = { git = 'https://github.com/tonlabs/ton-labs-assembler.git', tag = '1.2.77' } -ton_sdk = { git = 'https://github.com/tonlabs/TON-SDK.git', tag = '1.40.0' } -ton_types = { git = 'https://github.com/tonlabs/ton-labs-types.git', tag = '1.12.6' } -ton_vm = { git = 'https://github.com/tonlabs/ton-labs-vm.git', tag = '1.8.96' } -sold = { git = 'https://github.com/tonlabs/TON-Solidity-Compiler.git', tag = '0.66.0', optional = true } +ton_abi = { git = 'https://github.com/tonlabs/ever-abi.git' } +ton_block = { git = 'https://github.com/tonlabs/ever-block.git' } +ton_block_json = { git = 'https://github.com/tonlabs/ever-block-json.git' } +ton_client = { git = 'https://github.com/tonlabs/ever-sdk.git' } +ton_executor = { git = 'https://github.com/tonlabs/ever-executor.git' } +ton_labs_assembler = { git = 'https://github.com/tonlabs/ever-assembler.git' } +ton_sdk = { git = 'https://github.com/tonlabs/ever-sdk.git' } +ton_types = { git = 'https://github.com/tonlabs/ever-types.git' } +ton_vm = { git = 'https://github.com/tonlabs/ever-vm.git' } +sold = { git = 'https://github.com/tonlabs/TON-Solidity-Compiler.git', optional = true } [dev-dependencies] assert_cmd = '2.0' diff --git a/README.md b/README.md index 2e7b9280..dcc64c11 100644 --- a/README.md +++ b/README.md @@ -1379,7 +1379,7 @@ Result: { ``` -## 4.5. Generate encrypted message offline +## 4.5.1. Generate encrypted message offline An internet connection is not required to create an encrypted message. Use the following command to do it: @@ -1433,6 +1433,45 @@ Expire at: Sat, 08 May 2021 16:42:03 +0300 Message saved to file message.boc ``` +## 4.5.2. Generate payload for internal message + +An internet connection is not required to create an payload for message. Use the following command to do it: + +```bash +tonos-cli body [--output ] [--abi ] +``` + +`--output ` - specify path to file where the raw message should be written to, instead of printing it to terminal. + +`` - contract interface file. + +`` - the method being called. + +`` - parameters of the called method. + +The TONOS-CLI utility displays encrypted message text and a QR code that also contains the message. Copy the message text or scan the QR code and broadcast the message online. + +Example (raw boc of create new multisig transaction message with a lifetime of 1 hour saved to file): + +```bash +$ tonos-cli message --raw --output message.boc --sign k1.keys.json --abi SafeMultisigWallet.abi.json 0:a4629d617df931d8ad86ed24f4cac3d321788ba082574144f5820f2894493fbc submitTransaction '{"dest":"-1:0c5d5215317ec8eef1b84c43cbf08523c33f69677365de88fe3d96a0b31b59c6","value":234000000,"bounce":false,"allBalance":false,"payload":""}' --lifetime 3600 +Config: /home/user/tonos-cli.conf.json +Input arguments: + address: 0:a4629d617df931d8ad86ed24f4cac3d321788ba082574144f5820f2894493fbc + method: submitTransaction + params: {"dest":"-1:0c5d5215317ec8eef1b84c43cbf08523c33f69677365de88fe3d96a0b31b59c6","value":234000000,"bounce":false,"allBalance":false,"payload":""} + abi: SafeMultisigWallet.abi.json + keys: k1.keys.json +lifetime: 3600 + output: message.boc +Generating external inbound message... + +MessageId: 59d698efe871cf9ffa8f6eb4c784b294538cd2223b4c876bb4e999a8edf8d410 +Expire at: Sat, 08 May 2021 16:42:03 +0300 +Message saved to file message.boc +``` + + ## 4.6. Broadcast previously generated message Use the following command to send a previously generated message, that is not in raw format, and not in a file: @@ -2618,9 +2657,11 @@ Succeeded. Use the following command to update one parameter of the blockchain global config, that is stored in a .json file: ```bash -tonos-cli update_config +tonos-cli update_config [--abi ] ``` +`` – ABI json file for solidity config contract, in this case `seqno` is not used and must be `0` + `` – current seqno of config contract. It can get from command `seqno` on config account. `` – prefix of config master files. There should be two files: `.addr` with address of config master and `.pk` with private key of config master. diff --git a/build.rs b/build.rs index ca1715b3..c0262be5 100644 --- a/build.rs +++ b/build.rs @@ -19,26 +19,26 @@ fn main() { let mut build_time = String::from("Unknown"); let branch = Command::new("git") - .args(&["rev-parse", "--abbrev-ref", "HEAD"]) + .args(["rev-parse", "--abbrev-ref", "HEAD"]) .output(); if let Ok(branch) = branch { git_branch = String::from_utf8(branch.stdout).unwrap_or_else(|_| "Unknown".to_string()); } - let last = Command::new("git").args(&["rev-parse", "HEAD"]).output(); + let last = Command::new("git").args(["rev-parse", "HEAD"]).output(); if let Ok(last) = last { git_commit = String::from_utf8(last.stdout).unwrap_or_else(|_| "Unknown".to_string()); } let time = Command::new("git") - .args(&["log", "-1", "--date=iso", "--pretty=format:%cd"]) + .args(["log", "-1", "--date=iso", "--pretty=format:%cd"]) .output(); if let Ok(time) = time { commit_date = String::from_utf8(time.stdout).unwrap_or_else(|_| "Unknown".to_string()); } - let b_time = Command::new("date").args(&["+%Y-%m-%d %T %z"]).output(); + let b_time = Command::new("date").args(["+%Y-%m-%d %T %z"]).output(); if let Ok(b_time) = b_time { build_time = String::from_utf8(b_time.stdout).unwrap_or_else(|_| "Unknown".to_string()); } diff --git a/src/account.rs b/src/account.rs index 018a1c82..4a14843a 100644 --- a/src/account.rs +++ b/src/account.rs @@ -34,7 +34,7 @@ const ACCOUNT_FIELDS: &str = r#" const DEFAULT_PATH: &str = "."; async fn query_accounts(config: &Config, addresses: Vec, fields: &str) -> Result, String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; if !config.is_json { println!("Processing..."); @@ -86,7 +86,7 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } return Ok(()); } - let accounts = query_accounts(&config, addresses.clone(), ACCOUNT_FIELDS).await?; + let accounts = query_accounts(config, addresses.clone(), ACCOUNT_FIELDS).await?; if !config.is_json { println!("Succeeded."); } @@ -156,7 +156,7 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio ); } else { print_account( - &config, + config, Some(acc_type), Some(address.clone()), Some(balance), @@ -170,7 +170,7 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } else if config.is_json { json_res[address.clone()] = json_account(Some(acc_type), Some(address.clone()), None, None, None, None, None, None); } else { - print_account(&config, Some(acc_type), Some(address.clone()), None, None, None, None, None, None); + print_account(config, Some(acc_type), Some(address.clone()), None, None, None, None, None, None); } if !config.is_json { println!(); @@ -195,11 +195,7 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } else if config.is_json { println!("{{\n}}"); } else { - if config.is_json { - println!("{{\n}}"); - } else { - println!("Account not found."); - } + println!("Account not found."); } if dumptvc.is_some() || dumpboc.is_some() && addresses.len() == 1 && accounts.len() == 1 { @@ -232,7 +228,7 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<(), String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; if !config.is_json { println!("Processing..."); @@ -242,7 +238,7 @@ pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<() ton.clone(), addr, "boc", - ).await.map_err(|e| e)?; + ).await?; let res = calc_storage_fee( ton.clone(), @@ -265,7 +261,7 @@ pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<() } pub async fn dump_accounts(config: &Config, addresses: Vec, path: Option<&str>) -> Result<(), String> { - let accounts = query_accounts(&config, addresses.clone(), "id boc").await?; + let accounts = query_accounts(config, addresses.clone(), "id boc").await?; let mut addresses = addresses.clone(); check_dir(path.unwrap_or(""))?; for account in accounts.iter() { diff --git a/src/call.rs b/src/call.rs index 20e5dfda..d2aa3157 100644 --- a/src/call.rs +++ b/src/call.rs @@ -121,7 +121,7 @@ pub async fn emulate_locally( let addr = ton_block::MsgAddressInt::from_str(addr) .map_err(|e| format!("couldn't decode address: {}", e))?; state = base64::encode( - &ton_types::cells_serialization::serialize_toc( + ton_types::cells_serialization::serialize_toc( &Account::with_address(addr) .serialize() .map_err(|e| format!("couldn't create dummy account for deploy emulation: {}", e))? @@ -219,7 +219,7 @@ pub async fn process_message( config: &Config, ) -> Result { let callback = |event| { async move { - if let ProcessingEvent::DidSend { shard_block_id: _, message_id, message: _ } = event { + if let ProcessingEvent::DidSend { shard_block_id: _, message_id, message_dst: _, message: _ } = event { println!("MessageId: {}", message_id) } }}; @@ -257,7 +257,7 @@ pub async fn call_contract_with_result( keys: Option, is_fee: bool, ) -> Result { - let ton = if config.debug_fail != "None".to_string() { + let ton = if &config.debug_fail != "None" { let log_path = format!("call_{}_{}.log", addr, method); log::set_max_level(log::LevelFilter::Trace); log::set_boxed_logger( @@ -294,7 +294,7 @@ pub async fn call_contract_with_client( let needs_encoded_msg = is_fee || config.async_call || config.local_run || - config.debug_fail != "None".to_string(); + &config.debug_fail != "None"; let message = if needs_encoded_msg { let msg = encode_message(ton.clone(), msg_params.clone()).await @@ -307,17 +307,15 @@ pub async fn call_contract_with_client( } } if config.async_call { - return send_message_and_wait(ton, - Some(abi), - msg.message.clone(), - config).await; + let msg = msg.message.clone(); + return send_message_and_wait(ton, Some(abi), msg, config).await; } Some(msg.message) } else { None }; - let dump = if config.debug_fail != "None".to_string() { + let dump = if &config.debug_fail != "None" { let acc_boc = query_account_field( ton.clone(), addr, @@ -336,17 +334,17 @@ pub async fn call_contract_with_client( let res = process_message(ton.clone(), msg_params, config).await; - if config.debug_fail != "None".to_string() && res.is_err() + if &config.debug_fail != "None" && res.is_err() && res.clone().err().unwrap().code == SDK_EXECUTION_ERROR_CODE { if config.is_json { - let e = format!("{:#}", res.clone().err().unwrap()); + let e = format!("{:#}", res.err().unwrap()); let err: Value = serde_json::from_str(&e) .unwrap_or(Value::String(e)); let res = json!({"Error": err}); println!("{}", serde_json::to_string_pretty(&res) .unwrap_or("{{ \"JSON serialization error\" }}".to_string())); } else { - println!("Error: {:#}", res.clone().err().unwrap()); + println!("Error: {:#}", res.err().unwrap()); println!("Execution failed. Starting debug..."); } let (mut account, message, now, bc_config) = dump.unwrap(); @@ -396,7 +394,7 @@ pub async fn call_contract( pub async fn call_contract_with_msg(config: &Config, str_msg: String, abi_path: &str) -> Result<(), String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; let abi = load_abi(abi_path, config).await?; let (msg, _) = unpack_message(&str_msg)?; diff --git a/src/completion.rs b/src/completion.rs index 5d572fa5..212f7337 100644 --- a/src/completion.rs +++ b/src/completion.rs @@ -72,13 +72,11 @@ fn print_paths(prefix: &str) { return; } let mut saved_path: Vec = vec![]; - for path in paths.unwrap() { - if let Ok(path) = path { - let path = path.path(); - let path_str = path.to_str().unwrap(); - if path_str.starts_with(prefix) { - saved_path.push(path); - } + for path in paths.unwrap().flatten() { + let path = path.path(); + let path_str = path.to_str().unwrap(); + if path_str.starts_with(prefix) { + saved_path.push(path); } } if saved_path.len() == 1 && saved_path[0].is_dir() { @@ -112,8 +110,8 @@ fn main() { } } let config_path = options_map.get(&"-c") - .or(options_map.get(&"--config") - .or(Some(&CONFIG_BASE_NAME))).unwrap(); + .or_else(|| options_map.get(&"--config")) + .unwrap_or(&CONFIG_BASE_NAME); let conf_str = std::fs::read_to_string(config_path).ok().unwrap_or_default(); let config: serde_json::Result = serde_json::from_str(&conf_str); if config.is_err() { @@ -150,7 +148,7 @@ fn main() { if abi_path.is_none() { return; } - if let Ok(abi) = std::fs::read_to_string(&abi_path.unwrap()) { + if let Ok(abi) = std::fs::read_to_string(abi_path.unwrap()) { if let Ok(abi_contract) = serde_json::from_str::(&abi) { for function in abi_contract.functions { if function.name.starts_with(word_being_completed) { diff --git a/src/config.rs b/src/config.rs index 54a8cabc..b34f88b5 100644 --- a/src/config.rs +++ b/src/config.rs @@ -285,20 +285,20 @@ impl FullConfig { pub fn from_file(path: &str) -> FullConfig { let conf_str = std::fs::read_to_string(path).ok().unwrap_or_default(); - let config: serde_json::error::Result = serde_json::from_str(&conf_str); - if config.is_ok() && config.as_ref().unwrap() != &Config::default() { - return FullConfig::new(config.unwrap(), path.to_string()); + if let Ok(config) = serde_json::from_str::(&conf_str) { + if config != Config::default() { + return FullConfig::new(config, path.to_string()); + } } - let full_config: serde_json::error::Result = serde_json::from_str(&conf_str); - let mut full_config = if full_config.is_err() { - let conf_str = std::fs::read_to_string(&global_config_path()).ok() + let mut full_config = if let Ok(full_config) = serde_json::from_str::(&conf_str) { + full_config + } else { + let conf_str = std::fs::read_to_string(global_config_path()).ok() .unwrap_or_default(); let mut global_config = serde_json::from_str::(&conf_str) - .unwrap_or(FullConfig::default()); + .unwrap_or_default(); global_config.path = path.to_string(); global_config - } else { - full_config.unwrap() }; full_config.path = path.to_string(); full_config @@ -343,13 +343,12 @@ impl FullConfig { pub fn add_endpoint(path: &str, url: &str, endpoints: &str) -> Result<(), String> { let mut fconf = FullConfig::from_file(path); let mut new_endpoints : Vec = endpoints - .replace('[', "") - .replace(']', "") + .replace(['[', ']'], "") .split(',') .map(|s| s.to_string()) .collect(); - let old_endpoints = fconf.endpoints_map.entry(url.to_string()).or_insert(vec![]); + let old_endpoints = fconf.endpoints_map.entry(url.to_string()).or_default(); old_endpoints.append(&mut new_endpoints); old_endpoints.sort(); old_endpoints.dedup(); diff --git a/src/convert.rs b/src/convert.rs index d6272716..885d719f 100644 --- a/src/convert.rs +++ b/src/convert.rs @@ -52,9 +52,9 @@ pub fn nodeid_from_pubkey(key: &[u8]) -> Result { } let mut hasher = Sha256::new(); // node id magic - hasher.update(&[0xc6, 0xb4, 0x13, 0x48]); + hasher.update([0xc6, 0xb4, 0x13, 0x48]); //key hasher.update(key); - Ok(hex::encode(&hasher.finalize())) + Ok(hex::encode(hasher.finalize())) } diff --git a/src/crypto.rs b/src/crypto.rs index 54ed221c..e1ed4c7d 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -22,14 +22,13 @@ use ton_client::crypto::{ ParamsOfHDKeyDeriveFromXPrvPath, ParamsOfHDKeyXPrvFromMnemonic, ParamsOfNaclSignKeyPairFromSecret, - ParamsOfMnemonicFromRandom + ParamsOfMnemonicFromRandom, MnemonicDictionary }; use crate::Config; pub fn load_keypair(keys: &str) -> Result { if keys.find(' ').is_none() { - let keys = read_keys(keys)?; - Ok(keys) + read_keys(keys) } else { generate_keypair_from_mnemonic(keys) } @@ -40,7 +39,7 @@ pub fn gen_seed_phrase() -> Result { mnemonic_from_random( client, ParamsOfMnemonicFromRandom { - dictionary: Some(1), + dictionary: Some(MnemonicDictionary::English), word_count: Some(WORD_COUNT), ..Default::default() }, @@ -54,7 +53,7 @@ pub fn generate_keypair_from_mnemonic(mnemonic: &str) -> Result let hdk_master = hdkey_xprv_from_mnemonic( client.clone(), ParamsOfHDKeyXPrvFromMnemonic { - dictionary: Some(1), + dictionary: Some(MnemonicDictionary::English), word_count: Some(WORD_COUNT), phrase: mnemonic.to_string(), ..Default::default() @@ -164,7 +163,7 @@ pub fn generate_keypair(keys_path: Option<&str>, mnemonic: Option<&str>, config: } }; - let keys = if mnemonic.contains(" ") { + let keys = if mnemonic.contains(' ') { generate_keypair_from_mnemonic(&mnemonic)? } else { generate_keypair_from_secret(mnemonic)? diff --git a/src/debot/pipechain.rs b/src/debot/pipechain.rs index 75ab9b68..68422588 100644 --- a/src/debot/pipechain.rs +++ b/src/debot/pipechain.rs @@ -7,9 +7,9 @@ fn default_mandatory() -> bool { false } #[derive(Deserialize, Clone, PartialEq)] pub enum ApproveKind { - ApproveOnChainCall, - ApproveNetwork, - ApproveMessageLimit, + OnChainCall, + Network, + MessageLimit, } #[derive(Deserialize, Clone, Default)] diff --git a/src/debot/processor.rs b/src/debot/processor.rs index 1a15de6a..f789ceca 100644 --- a/src/debot/processor.rs +++ b/src/debot/processor.rs @@ -67,7 +67,7 @@ impl ChainProcessor { &mut self, in_interface: &str, in_method: &str, - in_params: &Value + _in_params: &Value ) -> Result, ProcessorError> { let chlink = self.chain_iter.next().ok_or( if self.interactive() { @@ -81,7 +81,7 @@ impl ChainProcessor { ChainLink::Input {interface, method, params, mandatory} => { if interface != in_interface { if !mandatory { - self.next_input(in_interface, in_method, in_params) + self.next_input(in_interface, in_method, _in_params) } else { Err(ProcessorError::UnexpectedInterface) } @@ -115,7 +115,7 @@ impl ChainProcessor { pub fn next_approve(&mut self, activity: &DebotActivity) -> Result { let app_kind = match activity { - DebotActivity::Transaction {..} => ApproveKind::ApproveOnChainCall, + DebotActivity::Transaction {..} => ApproveKind::OnChainCall, }; let auto_approve = self.pipechain.auto_approve.as_ref().map(|vec| vec.iter().any(|x| *x == app_kind)); diff --git a/src/debot/term_encryption_box.rs b/src/debot/term_encryption_box.rs index 1ca485ec..56df5d3b 100644 --- a/src/debot/term_encryption_box.rs +++ b/src/debot/term_encryption_box.rs @@ -50,7 +50,7 @@ impl TerminalEncryptionBox { let mut writer = io::stdout(); let enter_str = "enter seed phrase or path to keypair file"; let value = input(enter_str, &mut reader, &mut writer); - let pair = load_keypair(&value).map_err(|e| e)?; + let pair = load_keypair(&value)?; key = format!("{:064}", pair.secret); } diff --git a/src/debug.rs b/src/debug.rs index e704983b..ad400d58 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -388,20 +388,20 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is if !config.is_json { print_args!(tx_id, trace_path, config_path, contract_path); } - let address = query_address(tx_id.unwrap(), &config).await?; + let address = query_address(tx_id.unwrap(), config).await?; (tx_id.unwrap().to_string(), address) } else { let address = Some(matches.value_of("ADDRESS") .map(|s| s.to_string()) - .or(config.addr.clone()) + .or_else(|| config.addr.clone()) .ok_or("ADDRESS is not defined. Supply it in the config file or command line." .to_string())?); if !config.is_json { print_args!(address, trace_path, config_path, contract_path); } let address = address.unwrap(); - let transactions = query_transactions(&address, &config).await?; + let transactions = query_transactions(&address, config).await?; let tr_id = choose_transaction(transactions)?; (tr_id, address) }; @@ -493,7 +493,7 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - print_args!(input, tx_id, output, config_path); } - let ton_client = create_client(&config)?; + let ton_client = create_client(config)?; let trans = query_collection( ton_client.clone(), ParamsOfQueryCollection { @@ -590,7 +590,7 @@ fn parse_now(matches: &ArgMatches<'_>) -> Result { fn load_decode_abi(matches: &ArgMatches<'_>, config: &Config) -> Option { let abi = matches.value_of("DECODE_ABI") .map(|s| s.to_owned()) - .or(abi_from_matches_or_config(matches, &config).ok()); + .or_else(|| abi_from_matches_or_config(matches, config).ok()); match abi { Some(path) => match std::fs::read_to_string(path) { Ok(res) => Some(res), @@ -712,12 +712,10 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, Err(e) => { if !is_getter { format!("Execution failed: {}", e) + } else if e.contains("Contract did not accept message") { + "Execution finished.".to_string() } else { - if e.to_string().contains("Contract did not accept message") { - "Execution finished.".to_string() - } else { - format!("Execution failed: {}", e) - } + format!("Execution failed: {}", e) } } }; @@ -762,13 +760,13 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res print_args!(input, message, output, debug_info); } - let ton_client = create_client(&config)?; + let ton_client = create_client(config)?; let input = input.unwrap(); let account = if is_boc { Account::construct_from_file(input) .map_err(|e| format!(" failed to load account from the file {}: {}", input, e))? } else { - let address = load_ton_address(input, &config)?; + let address = load_ton_address(input, config)?; let account = query_account_field(ton_client.clone(), &address, "boc").await?; Account::construct_from_base64(&account) .map_err(|e| format!("Failed to construct account: {}", e))? @@ -834,12 +832,12 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let tvc = matches.value_of("TVC"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); - let opt_abi = Some(abi_from_matches_or_config(matches, &config)?); + let opt_abi = Some(abi_from_matches_or_config(matches, config)?); let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) - .or(load_debug_info(opt_abi.as_ref().unwrap())); + .or_else(|| load_debug_info(opt_abi.as_ref().unwrap())); let sign = matches.value_of("KEYS") .map(|s| s.to_string()) - .or(config.keys_path.clone()); + .or_else(|| config.keys_path.clone()); let params = unpack_alternative_params( matches, opt_abi.as_ref().unwrap(), @@ -941,7 +939,7 @@ async fn decode_messages(msgs: OutMessages, abi: Option, config: &Config let mut ser_msg = serialize_msg(&msg.0, abi.clone(), config).await .map_err(|e| format!("Failed to serialize message: {}", e))?; let msg_str = base64::encode( - &ton_types::cells_serialization::serialize_toc( + ton_types::cells_serialization::serialize_toc( &msg.0 .serialize() .map_err(|e| format!("Failed to serialize out message: {}", e))? @@ -1080,7 +1078,7 @@ pub async fn execute_debug( let executor = Box::new( OrdinaryTransactionExecutor::new( - bc_config.clone(), + bc_config, ) ); let params = ExecuteParams { @@ -1137,7 +1135,7 @@ fn trace_callback(info: &EngineTraceInfo, debug_info: &Option) { fn trace_callback_minimal(info: &EngineTraceInfo, debug_info: &Option) { - let position = match get_position(info, &debug_info) { + let position = match get_position(info, debug_info) { Some(position) => position, _ => "".to_string() }; @@ -1165,7 +1163,7 @@ fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Optio Some(matches) => { let opt_abi = abi_from_matches_or_config(matches, config); let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) - .or( + .or_else(|| if opt_abi.is_ok() { load_debug_info(opt_abi.as_ref().unwrap()) } else { @@ -1197,7 +1195,7 @@ fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Optio }) }, _ => { - Some(if config.debug_fail == "Full".to_string() { + Some(if config.debug_fail == *"Full" { Arc::new(move |_, info| trace_callback(info, &None)) } else { Arc::new(move |_, info| trace_callback_minimal(info, &None)) @@ -1217,11 +1215,9 @@ pub async fn sequence_diagram_command(matches: &ArgMatches<'_>, config: &Config) let mut addresses = vec!(); let lines = std::io::BufReader::new(file).lines(); - for line in lines { - if let Ok(line) = line { - if !line.is_empty() && !line.starts_with('#'){ - addresses.push(load_ton_address(&line, config)?); - } + for line in lines.flatten() { + if !line.is_empty() && !line.starts_with('#'){ + addresses.push(load_ton_address(&line, config)?); } } if addresses.iter().collect::>().len() < addresses.len() { @@ -1234,7 +1230,7 @@ pub async fn sequence_diagram_command(matches: &ArgMatches<'_>, config: &Config) }) } -fn infer_address_width(input: &Vec, min_width: usize) -> Result { +fn infer_address_width(input: &[String], min_width: usize) -> Result { let max_width = input.iter().fold(0, |acc, item| { std::cmp::max(acc, item.len()) }); @@ -1312,8 +1308,8 @@ async fn fetch_transactions(config: &Config, addresses: &Vec) -> Result< }); } - let last = transactions.result.last().ok_or("Failed to get last txn".to_string())?; - lt = last["lt"].as_str().ok_or("Failed to parse value".to_string())?.to_owned(); + let last = transactions.result.last().ok_or_else(|| "Failed to get last txn".to_string())?; + lt = last["lt"].as_str().ok_or_else(|| "Failed to parse value".to_string())?.to_owned(); } } txns.sort_by(|tr1, tr2| tr1.tr.logical_time().partial_cmp(&tr2.tr.logical_time()).unwrap()); diff --git a/src/decode.rs b/src/decode.rs index 67bf0ce1..1b53eedc 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -130,7 +130,7 @@ async fn decode_data_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), async fn decode_body_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let body = m.value_of("BODY"); - let abi = Some(abi_from_matches_or_config(m, &config)?); + let abi = Some(abi_from_matches_or_config(m, config)?); if !config.is_json { print_args!(body, abi); } @@ -203,10 +203,10 @@ pub async fn print_account_data(account: &Account, tvc_path: Option<&str>, confi }; let data = tree_of_cells_into_base64(account.get_data().as_ref())?; - let data = hex::encode(base64::decode(&data) + let data = hex::encode(base64::decode(data) .map_err(|e| format!("Failed to decode base64: {}", e))?); print_account( - &config, + config, Some(state), Some(address), Some(balance), @@ -227,7 +227,7 @@ pub async fn print_account_data(account: &Account, tvc_path: Option<&str>, confi async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let msg = m.value_of("MSG"); - let abi = Some(abi_from_matches_or_config(m, &config)?); + let abi = Some(abi_from_matches_or_config(m, config)?); if !config.is_json { print_args!(msg, abi); } @@ -275,7 +275,7 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( async fn decode_tvc_fields(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let tvc = m.value_of("TVC"); - let abi = Some(abi_from_matches_or_config(m, &config)?); + let abi = Some(abi_from_matches_or_config(m, config)?); if !config.is_json { print_args!(tvc, abi); } @@ -304,14 +304,14 @@ async fn decode_tvc_fields(m: &ArgMatches<'_>, config: &Config) -> Result<(), St async fn decode_account_fields(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = m.value_of("ADDRESS"); - let abi = Some(abi_from_matches_or_config(m, &config)?); + let abi = Some(abi_from_matches_or_config(m, config)?); if !config.is_json { print_args!(address, abi); } let abi = load_abi(abi.as_ref().unwrap(), config).await?; - let ton = create_client_verbose(&config)?; - let address = load_ton_address(address.unwrap(), &config)?; + let ton = create_client_verbose(config)?; + let address = load_ton_address(address.unwrap(), config)?; let data = query_account_field(ton.clone(), &address, "data").await?; let res = decode_account_data( @@ -370,7 +370,7 @@ async fn decode_body(body_base64: &str, abi_path: &str, is_json: bool, config: & if let Ok(has_sign) = flag { if has_sign { let signature_bytes = slice.get_next_bytes(64).unwrap(); - signature = Some(hex::encode(&signature_bytes)); + signature = Some(hex::encode(signature_bytes)); } } } @@ -410,8 +410,8 @@ async fn decode_message(msg_boc: Vec, abi_path: Option) -> Result) -> Result { @@ -436,7 +436,7 @@ async fn decode_tvc_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), S let ton = if is_local { create_client_local()? } else { - create_client_verbose(&config)? + create_client_verbose(config)? }; let input = input.unwrap().to_owned(); @@ -596,17 +596,14 @@ pub mod msg_printer { }; let output = res.value.take().ok_or("failed to obtain the result")?; let mut decoded = json!({res.name : output}); - match res.header { - Some(header) => { - if header.expire.is_some() || header.pubkey.is_some() || header.time.is_some() { - decoded["BodyHeader"] = json!({ - "expire": json!(header.expire.map(|exp| format!("{exp}")).unwrap_or("None".to_string())), - "time": json!(header.time.map(|time| format!("{time}")).unwrap_or("None".to_string())), - "pubkey": json!(header.pubkey.unwrap_or("None".to_string())), - }) - } - }, - None => {} + if let Some(header) = res.header { + if header.expire.is_some() || header.pubkey.is_some() || header.time.is_some() { + decoded["BodyHeader"] = json!({ + "expire": json!(header.expire.map(|exp| format!("{exp}")).unwrap_or("None".to_string())), + "time": json!(header.time.map(|time| format!("{time}")).unwrap_or("None".to_string())), + "pubkey": json!(header.pubkey.unwrap_or("None".to_string())), + }) + } } Ok(decoded) } @@ -654,6 +651,6 @@ mod tests { async fn test_decode_body_json() { let body = "te6ccgEBAQEARAAAgwAAALqUCTqWL8OX7JivfJrAAzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMzMQAAAAAAAAAAAAAAAEeGjADA=="; let config = Config::default(); - let _out = decode_body(body, "tests/samples/wallet.abi.json", true, &config).await.unwrap(); + decode_body(body, "tests/samples/wallet.abi.json", true, &config).await.unwrap(); } } diff --git a/src/deploy.rs b/src/deploy.rs index e3946f8f..6e0e0de5 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -55,7 +55,7 @@ pub async fn deploy_contract( } if config.async_call { - let abi = load_abi(&abi, config).await?; + let abi = load_abi(abi, config).await?; send_message_and_wait(ton, Some(abi), enc_msg.message, @@ -137,7 +137,7 @@ pub async fn prepare_deploy_message_params( keys: Option, wc: i32 ) -> Result<(ParamsOfEncodeMessage, String), String> { - let tvc_base64 = base64::encode(&tvc_bytes); + let tvc_base64 = base64::encode(tvc_bytes); let addr = calc_acc_address( tvc_bytes, diff --git a/src/depool.rs b/src/depool.rs index b412678a..545bbe59 100644 --- a/src/depool.rs +++ b/src/depool.rs @@ -214,7 +214,7 @@ struct CommandData<'a> { impl<'a> CommandData<'a> { pub fn from_matches_and_conf(m: &'a ArgMatches, config: &'a Config, depool: String) -> Result { - let (wallet, stake, keys) = parse_stake_data(m, &config)?; + let (wallet, stake, keys) = parse_stake_data(m, config)?; let depool_fee = config.depool_fee.clone().to_string(); Ok(CommandData {config, depool, wallet, stake, keys, depool_fee}) } @@ -260,8 +260,8 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<( if let Some(matches) = matches { let is_vesting = m.subcommand_matches("vesting").is_some(); set_wait_answer(matches); - let (wallet, keys) = parse_wallet_data(&matches, &config)?; - return set_donor_command(matches, &config, depool.as_str(), &wallet, &keys, is_vesting).await; + let (wallet, keys) = parse_wallet_data(matches, config)?; + return set_donor_command(matches, config, depool.as_str(), &wallet, &keys, is_vesting).await; } } @@ -309,16 +309,16 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<( let matches = m.subcommand_matches("on").or(m.subcommand_matches("off")); if let Some(matches) = matches { set_wait_answer(matches); - let (wallet, keys) = parse_wallet_data(&matches, &config)?; + let (wallet, keys) = parse_wallet_data(matches, config)?; let enable_withdraw = m.subcommand_matches("on").is_some(); - return set_withdraw_command(&config, &depool, &wallet, &keys, enable_withdraw).await; + return set_withdraw_command(config, &depool, &wallet, &keys, enable_withdraw).await; } } if let Some(m) = m.subcommand_matches("events") { - return events_command(m, &config, &depool).await + return events_command(m, config, &depool).await } if let Some(m) = m.subcommand_matches("answers") { - return answer_command(m, &config, &depool).await + return answer_command(m, config, &depool).await } if let Some(m) = m.subcommand_matches("replenish") { return replenish_command( @@ -326,8 +326,8 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<( ).await; } if let Some(m) = m.subcommand_matches("ticktock") { - let (wallet, keys) = parse_wallet_data(&m, &config)?; - return ticktock_command(&config, &depool, &wallet, &keys).await; + let (wallet, keys) = parse_wallet_data(m, config)?; + return ticktock_command(config, &depool, &wallet, &keys).await; } Err("unknown depool command".to_owned()) } @@ -429,8 +429,8 @@ async fn print_event(ton: TonClient, event: &serde_json::Value) -> Result<(), St } async fn get_events(config: &Config, depool: &str, since: u32) -> Result<(), String> { - let ton = create_client_verbose(&config)?; - let _addr = load_ton_address(depool, &config)?; + let ton = create_client_verbose(config)?; + let _addr = load_ton_address(depool, config)?; let events = ton_client::net::query_collection( ton.clone(), @@ -451,8 +451,8 @@ async fn get_events(config: &Config, depool: &str, since: u32) -> Result<(), Str } async fn wait_for_event(config: &Config, depool: &str) -> Result<(), String> { - let ton = create_client_verbose(&config)?; - let _addr = load_ton_address(depool, &config)?; + let ton = create_client_verbose(config)?; + let _addr = load_ton_address(depool, config)?; println!("Waiting for a new event..."); let event = ton_client::net::wait_for_collection( ton.clone(), @@ -597,12 +597,12 @@ async fn add_ordinary_stake(cmd: CommandData<'_>) -> Result<(), String> { let fee = u64::from_str_radix(&convert::convert_token(&cmd.depool_fee)?, 10) .map_err(|e| format!(r#"failed to parse depool fee value: {}"#, e))?; let value = (fee + stake) as f64 * 1.0 / 1e9; - call_contract(&cmd.config, &cmd.wallet, &cmd.depool, &format!("{}", value), &cmd.keys, &body, true).await + call_contract(cmd.config, &cmd.wallet, &cmd.depool, &format!("{}", value), &cmd.keys, &body, true).await } async fn replenish_stake(cmd: CommandData<'_>) -> Result<(), String> { let body = encode_replenish_stake().await?; - call_contract(&cmd.config, &cmd.wallet, &cmd.depool, cmd.stake, &cmd.keys, &body, false).await + call_contract(cmd.config, &cmd.wallet, &cmd.depool, cmd.stake, &cmd.keys, &body, false).await } async fn call_ticktock( @@ -622,7 +622,7 @@ async fn add_exotic_stake( tp: u32, is_vesting: bool, ) -> Result<(), String> { - let beneficiary = load_ton_address(beneficiary, &cmd.config)?; + let beneficiary = load_ton_address(beneficiary, cmd.config)?; let stake = u64::from_str_radix(&convert::convert_token(cmd.stake)?, 10) .map_err(|e| format!(r#"failed to parse stake value: {}"#, e))?; let body = if is_vesting { @@ -633,7 +633,7 @@ async fn add_exotic_stake( let fee = u64::from_str_radix(&convert::convert_token(&cmd.depool_fee)?, 10) .map_err(|e| format!(r#"failed to parse depool fee value: {}"#, e))?; let value = (fee + stake) as f64 * 1.0 / 1e9; - call_contract(&cmd.config, &cmd.wallet, &cmd.depool, &format!("{}", value), &cmd.keys, &body, true).await + call_contract(cmd.config, &cmd.wallet, &cmd.depool, &format!("{}", value), &cmd.keys, &body, true).await } fn get_stake(stake: &str) -> Result { @@ -647,7 +647,7 @@ async fn remove_stake( ) -> Result<(), String> { let stake = get_stake(cmd.stake)?; let body = encode_remove_stake(stake).await?; - call_contract(&cmd.config, &cmd.wallet, &cmd.depool, &cmd.depool_fee, &cmd.keys, &body, true).await + call_contract(cmd.config, &cmd.wallet, &cmd.depool, &cmd.depool_fee, &cmd.keys, &body, true).await } async fn withdraw_stake( @@ -655,14 +655,14 @@ async fn withdraw_stake( ) -> Result<(), String> { let stake = get_stake(cmd.stake)?; let body = encode_withdraw_stake(stake).await?; - call_contract(&cmd.config, &cmd.wallet, &cmd.depool, &cmd.depool_fee, &cmd.keys, &body, true).await + call_contract(cmd.config, &cmd.wallet, &cmd.depool, &cmd.depool_fee, &cmd.keys, &body, true).await } async fn transfer_stake(cmd: CommandData<'_>, dest: &str) -> Result<(), String> { - let dest = load_ton_address(dest, &cmd.config)?; + let dest = load_ton_address(dest, cmd.config)?; let stake = get_stake(cmd.stake)?; let body = encode_transfer_stake(dest.as_str(), stake).await?; - call_contract(&cmd.config, &cmd.wallet, &cmd.depool, &cmd.depool_fee, &cmd.keys, &body, true).await + call_contract(cmd.config, &cmd.wallet, &cmd.depool, &cmd.depool_fee, &cmd.keys, &body, true).await } async fn set_withdraw( @@ -674,7 +674,7 @@ async fn set_withdraw( ) -> Result<(), String> { let body = encode_set_withdraw(enable).await?; let value = config.depool_fee.to_string(); - call_contract(config, &wallet, &depool, &value.to_string(), &keys, &body, true).await + call_contract(config, wallet, depool, &value.to_string(), keys, &body, true).await } async fn set_donor( @@ -687,7 +687,7 @@ async fn set_donor( ) -> Result<(), String> { let body = encode_set_donor(is_vesting, donor).await?; let value = config.depool_fee.to_string(); - call_contract(config, &wallet, &depool, &value.to_string(), &keys, &body, true).await + call_contract(config, wallet, depool, &value.to_string(), keys, &body, true).await } async fn encode_body(func: &str, params: serde_json::Value) -> Result { @@ -821,7 +821,7 @@ async fn call_contract_and_get_answer( body: &str, answer_is_expected: bool ) -> Result<(), String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; let abi = load_abi(MSIG_ABI, config).await?; let start = now()?; diff --git a/src/genaddr.rs b/src/genaddr.rs index 73e7215d..2e578ab9 100644 --- a/src/genaddr.rs +++ b/src/genaddr.rs @@ -90,7 +90,7 @@ pub async fn generate_address( if new_keys && keys_file.is_some() { let keys_json = serde_json::to_string_pretty(&keys.clone().unwrap()) .map_err(|e| format!("failed to serialize the keypair: {}", e))?; - std::fs::write(keys_file.unwrap(), &keys_json) + std::fs::write(keys_file.unwrap(), keys_json) .map_err(|e| format!("failed to save the keypair: {}", e))?; } diff --git a/src/getconfig.rs b/src/getconfig.rs index 0de1550b..2383267f 100644 --- a/src/getconfig.rs +++ b/src/getconfig.rs @@ -234,7 +234,7 @@ master { "#; pub async fn query_global_config(config: &Config, index: Option<&str>) -> Result<(), String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; let mut result = QUERY_FIELDS.to_owned(); result.push_str(r#" p40 { @@ -325,6 +325,7 @@ pub async fn gen_update_config_message( seqno: Option<&str>, config_master_file: &str, new_param_file: &str, + output: Option<&str>, is_json: bool ) -> Result<(), String> { let config_master_address = std::fs::read(&*(config_master_file.to_string() + ".addr")) @@ -347,8 +348,12 @@ pub async fn gen_update_config_message( let msg_bytes = message.write_to_bytes() .map_err(|e| format!(r#"failed to serialize message": {}"#, e))?; - let msg_hex = hex::encode(&msg_bytes); + if let Some(output) = output { + std::fs::write(output, &msg_bytes) + .map_err(|err| format!("cannot store message to file {} {}", output, err))?; + } + let msg_hex = hex::encode(msg_bytes); if is_json { println!("{{\"Message\": \"{}\"}}", msg_hex); } else { @@ -359,27 +364,28 @@ pub async fn gen_update_config_message( } pub fn serialize_config_param(config_str: String) -> Result<(Cell, u32), String> { - let config_json: serde_json::Value = serde_json::from_str(&*config_str) + let config_json: serde_json::Value = serde_json::from_str(&config_str) .map_err(|e| format!(r#"failed to parse "new_param_file": {}"#, e))?; let config_json = config_json.as_object() - .ok_or(format!(r#""new_param_file" is not json object"#))?; + .ok_or(r#""new_param_file" is not json object"#.to_string())?; if config_json.len() != 1 { Err(r#""new_param_file" is not a valid json"#.to_string())?; } let mut key_number = None; - for key in config_json.keys() { - if !key.starts_with("p") { - Err(r#""new_param_file" is not a valid json"#.to_string())?; + if let Some(p) = config_json.keys().next() { + if let Some(p) = p.strip_prefix('p') { + key_number = Some(p.parse::()) } - key_number = Some(key.trim_start_matches("p").to_string()); - break; } - - let key_number = key_number - .ok_or(format!(r#""new_param_file" is not a valid json"#))? - .parse::() - .map_err(|e| format!(r#""new_param_file" is not a valid json: {}"#, e))?; + let Some(Ok(key_number)) = key_number else { + let err = if let Some(Err(err)) = key_number { + err.to_string() + } else { + String::new() + }; + return Err(format!(r#""new_param_file" is not a valid json {}"#, err)) + }; let config_params = ton_block_json::parse_config(config_json) .map_err(|e| format!(r#"failed to parse config params from "new_param_file": {}"#, e))?; @@ -469,7 +475,7 @@ fn prepare_message_new_config_param_solidity( .map_err(|err| err.to_string())?; let body = function .encode_input(&header, ¶meters, false, Some(&keypair), Some(config_contract_address.clone())) - .and_then(|builder| SliceData::load_builder(builder)) + .and_then(SliceData::load_builder) .map_err(|err| format!("cannot prepare message body {}", err))?; let hdr = ExternalInboundMessageHeader::new(AddrNone, config_contract_address); @@ -485,7 +491,7 @@ fn convert_to_uint(value: &[u8], bits_count: usize) -> TokenValue { } pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; let last_key_block_query = query_with_limit( ton.clone(), @@ -512,7 +518,7 @@ pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), S ).await .map_err(|e| format!("Failed to get blockchain config: {}", e))?; - let bc_config = base64::decode(&bc_config.config_boc) + let bc_config = base64::decode(bc_config.config_boc) .map_err(|e| format!("Failed to decode BOC: {}", e))?; std::fs::write(path, bc_config) .map_err(|e| format!("Failed to write data to the file {}: {}", path, e))?; diff --git a/src/helpers.rs b/src/helpers.rs index 31b76564..eef09001 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -14,26 +14,26 @@ use std::env; use std::path::PathBuf; use crate::config::{Config, LOCALNET}; -use std::sync::Arc; -use std::time::{Duration, SystemTime}; +use ton_abi::Contract; +use ton_block::{Account, MsgAddressInt, Deserializable, CurrencyCollection, StateInit, Serializable}; use ton_client::abi::{ Abi, AbiConfig, AbiContract, DecodedMessageBody, DeploySet, ParamsOfDecodeMessageBody, - ParamsOfEncodeMessage, Signer, + ParamsOfEncodeMessage, Signer, decode_message_body, }; -use ton_client::crypto::{CryptoConfig, KeyPair}; +use ton_client::crypto::{CryptoConfig, KeyPair, MnemonicDictionary}; use ton_client::error::ClientError; use ton_client::net::{query_collection, OrderBy, ParamsOfQueryCollection, NetworkConfig}; use ton_client::{ClientConfig, ClientContext}; -use ton_block::{Account, MsgAddressInt, Deserializable, CurrencyCollection, StateInit, Serializable}; +use ton_executor::BlockchainConfig; +use std::sync::Arc; use std::str::FromStr; +use std::time::{Duration, SystemTime}; use clap::ArgMatches; use serde_json::{Value, json}; -use ton_client::abi::Abi::Contract; -use ton_executor::BlockchainConfig; use url::Url; use crate::call::parse_params; -use crate::{FullConfig, resolve_net_name}; use crate::replay::{CONFIG_ADDR, construct_blockchain_config}; +use crate::{FullConfig, resolve_net_name}; pub const TEST_MAX_LEVEL: log::LevelFilter = log::LevelFilter::Debug; pub const MAX_LEVEL: log::LevelFilter = log::LevelFilter::Warn; @@ -85,10 +85,9 @@ impl log::Log for SimpleLogger { pub fn read_keys(filename: &str) -> Result { let keys_str = std::fs::read_to_string(filename) - .map_err(|e| format!("failed to read the keypair file: {}", e))?; - let keys: KeyPair = serde_json::from_str(&keys_str) - .map_err(|e| format!("failed to load keypair: {}", e))?; - Ok(keys) + .map_err(|e| format!("failed to read the keypair file {}: {}", filename, e))?; + serde_json::from_str(&keys_str) + .map_err(|e| format!("failed to load keypair: {}", e)) } pub fn load_ton_address(addr: &str, config: &Config) -> Result { @@ -130,7 +129,7 @@ pub fn get_server_endpoints(config: &Config) -> Vec { cur_endpoints.iter_mut().map(|end| { let mut end = end.trim_end_matches('/').to_owned(); if config.project_id.is_some() { - end.push_str("/"); + end.push('/'); end.push_str(&config.project_id.clone().unwrap()); } end.to_owned() @@ -155,7 +154,7 @@ pub fn create_client(config: &Config) -> Result { message_expiration_timeout_grow_factor: 1.3, }, crypto: CryptoConfig { - mnemonic_dictionary: 1, + mnemonic_dictionary: MnemonicDictionary::English, mnemonic_word_count: WORD_COUNT, hdkey_derivation_path: HD_PATH.to_string(), }, @@ -207,11 +206,11 @@ pub async fn query_raw( { let context = create_client_verbose(config)?; - let filter = filter.map(|s| serde_json::from_str(s)).transpose() + let filter = filter.map(serde_json::from_str).transpose() .map_err(|e| format!("Failed to parse filter field: {}", e))?; let limit = limit.map(|s| s.parse::()).transpose() .map_err(|e| format!("Failed to parse limit field: {}", e))?; - let order = order.map(|s| serde_json::from_str(s)).transpose() + let order = order.map(serde_json::from_str).transpose() .map_err(|e| format!("Failed to parse order field: {}", e))?; let query = ton_client::net::query_collection( @@ -304,7 +303,7 @@ pub async fn decode_msg_body( ) -> Result { let abi = load_abi(abi_path, config).await?; - ton_client::abi::decode_message_body( + decode_message_body( ton, ParamsOfDecodeMessageBody { abi, @@ -324,24 +323,24 @@ pub async fn load_abi_str(abi_path: &str, config: &Config) -> Result Result { let abi_str = load_abi_str(abi_path, config).await?; - Ok(Contract(serde_json::from_str::(&abi_str) - .map_err(|e| format!("ABI is not a valid json: {}", e))?, - )) + let contract = serde_json::from_str::(&abi_str) + .map_err(|e| format!("ABI is not a valid json: {}", e))?; + Ok(Abi::Contract(contract)) } -pub async fn load_ton_abi(abi_path: &str, config: &Config) -> Result { +pub async fn load_ton_abi(abi_path: &str, config: &Config) -> Result { let abi_str = load_abi_str(abi_path, config).await?; - Ok(ton_abi::Contract::load(abi_str.as_bytes()) - .map_err(|e| format!("Failed to load ABI: {}", e))?) + Contract::load(abi_str.as_bytes()) + .map_err(|e| format!("Failed to load ABI: {}", e)) } pub async fn load_file_with_url(url: &str, timeout: u64) -> Result, String> { @@ -580,9 +579,9 @@ pub fn check_dir(path: &str) -> Result<(), String> { #[derive(PartialEq)] pub enum AccountSource { - NETWORK, - BOC, - TVC, + Network, + Boc, + Tvc, } pub async fn load_account( @@ -592,11 +591,11 @@ pub async fn load_account( config: &Config ) -> Result<(Account, String), String> { match source_type { - AccountSource::NETWORK => { + AccountSource::Network => { let ton_client = match ton_client { Some(ton_client) => ton_client, None => { - create_client(&config)? + create_client(config)? } }; let boc = query_account_field(ton_client.clone(),source, "boc").await?; @@ -605,7 +604,7 @@ pub async fn load_account( boc)) }, _ => { - let account = if source_type == &AccountSource::BOC { + let account = if source_type == &AccountSource::Boc { Account::construct_from_file(source) .map_err(|e| format!(" failed to load account from the file {}: {}", source, e))? } else { @@ -613,7 +612,7 @@ pub async fn load_account( }; let account_bytes = account.write_to_bytes() .map_err(|e| format!(" failed to load data from the account: {}", e))?; - Ok((account, base64::encode(&account_bytes))) + Ok((account, base64::encode(account_bytes))) }, } } @@ -1006,7 +1005,7 @@ pub fn blockchain_config_from_default_json() -> Result ] } }"#; - let map = serde_json::from_str::>(&json) + let map = serde_json::from_str::>(json) .map_err(|e| format!("Failed to parse config params as json: {e}"))?; let config_params = ton_block_json::parse_config(&map) .map_err(|e| format!("Failed to parse config params: {e}"))?; diff --git a/src/main.rs b/src/main.rs index c02d2a8a..adb4d229 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 TON DEV SOLUTIONS LTD. + * Copyright 2018-2023 TON DEV SOLUTIONS LTD. * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. @@ -388,6 +388,7 @@ async fn main_internal() -> Result <(), String> { .author(author) .arg(method_arg.clone()) .arg(params_arg.clone()) + .arg(output_arg.clone()) .arg(abi_arg.clone()); let sign_cmd = SubCommand::with_name("sign") @@ -784,6 +785,7 @@ async fn main_internal() -> Result <(), String> { let update_config_param_cmd = SubCommand::with_name("update_config") .about("Generates message with update of config params.") .arg(abi_arg.clone()) + .arg(output_arg.clone()) .arg(Arg::with_name("SEQNO") .takes_value(true) .help("Current seqno from config contract")) @@ -949,7 +951,7 @@ async fn main_internal() -> Result <(), String> { clap::ErrorKind::HelpDisplayed => { println!("{}", e); exit(0); }, _ => { eprintln!("{}", e); - format!("{{\n \"Error\": \"{}\"\n}}", e.message.replace("\n", "\\n")) + format!("{{\n \"Error\": \"{}\"\n}}", e.message.replace('\n', "\\n")) } })?; @@ -960,23 +962,19 @@ async fn main_internal() -> Result <(), String> { if e.is_empty() { e } else { - if !is_json { - format!("Error: {}", e) - } else { - let err: serde_json::Value = serde_json::from_str(&e) - .unwrap_or(serde_json::Value::String(e)); - let res = json!({"Error": err}); - serde_json::to_string_pretty(&res) - .unwrap_or("{{ \"JSON serialization error\" }}".to_string()) - } + let err: serde_json::Value = serde_json::from_str(&e) + .unwrap_or(serde_json::Value::String(e)); + let res = json!({"Error": err}); + serde_json::to_string_pretty(&res) + .unwrap_or_else(|_| "{{ \"JSON serialization error\" }}".to_string()) } }) } async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), String> { let config_file = matches.value_of("CONFIG").map(|v| v.to_string()) - .or(env::var("TONOSCLI_CONFIG").ok()) - .unwrap_or(default_config_name()); + .or_else(|| env::var("TONOSCLI_CONFIG").ok()) + .unwrap_or_else(default_config_name); let mut full_config = FullConfig::from_file(&config_file); @@ -988,7 +986,7 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), let config = &mut full_config.config; if let Some(url) = matches.value_of("NETWORK") { - let resolved_url = resolve_net_name(url).unwrap_or(url.to_owned()); + let resolved_url = resolve_net_name(url).unwrap_or_else(|| url.to_string()); let empty : Vec = Vec::new(); config.endpoints = full_config.endpoints_map.get(&resolved_url).unwrap_or(&empty).clone(); config.url = resolved_url; @@ -1165,7 +1163,7 @@ fn getkeypair_command(matches: &ArgMatches, config: &Config) -> Result<(), Strin async fn send_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let message = matches.value_of("MESSAGE"); - let abi = Some(abi_from_matches_or_config(matches, &config)?); + let abi = Some(abi_from_matches_or_config(matches, config)?); if !config.is_json { print_args!(message, abi); @@ -1178,7 +1176,7 @@ async fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), S let method = matches.value_of("METHOD"); let params = matches.value_of("PARAMS"); let output = matches.value_of("OUTPUT"); - let abi = Some(abi_from_matches_or_config(matches, &config)?); + let abi = Some(abi_from_matches_or_config(matches, config)?); let params = Some(load_params(params.unwrap())?); if !config.is_json { print_args!(method, params, abi, output); @@ -1224,10 +1222,10 @@ fn sign_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> return Err("nor data neither cell parameter".to_string()) }; let pair = match matches.value_of("KEYS") { - Some(keys) => crypto::load_keypair(&keys)?, + Some(keys) => crypto::load_keypair(keys)?, None => { match &config.keys_path { - Some(keys) => crypto::load_keypair(&keys)?, + Some(keys) => crypto::load_keypair(keys)?, None => return Err("nor signing keys in the params neither in the config".to_string()) } } @@ -1255,22 +1253,22 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) let raw = matches.is_present("RAW"); let output = matches.value_of("OUTPUT"); - let abi = Some(abi_from_matches_or_config(matches, &config)?); + let abi = Some(abi_from_matches_or_config(matches, config)?); let keys = matches.value_of("KEYS") - .or(matches.value_of("SIGN")) + .or_else(|| matches.value_of("SIGN")) .map(|s| s.to_string()) - .or(config.keys_path.clone()); + .or_else(|| config.keys_path.clone()); let params = Some(load_params(params.unwrap())?); if !config.is_json { print_args!(address, method, params, abi, keys, lifetime, output); } - let address = load_ton_address(address.unwrap(), &config)?; + let address = load_ton_address(address.unwrap(), config)?; match call { CallType::Call | CallType::Fee => { - let is_fee = if let CallType::Fee = call { true } else { false }; + let is_fee = matches!(call, CallType::Fee); call_contract( config, address.as_str(), @@ -1325,13 +1323,13 @@ async fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Re print_args!(address, method, params, abi, keys); } - let address = load_ton_address(address.unwrap().as_str(), &config)?; + let address = load_ton_address(address.unwrap().as_str(), config)?; call_contract( config, address.as_str(), &abi.unwrap(), - &method.unwrap(), + method.unwrap(), ¶ms.unwrap(), keys, false, @@ -1349,16 +1347,16 @@ async fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), print_args!(address, method, params); } let source_type = if matches.is_present("TVC") { - AccountSource::TVC + AccountSource::Tvc } else if matches.is_present("BOC") { - AccountSource::BOC + AccountSource::Boc } else { - AccountSource::NETWORK + AccountSource::Network }; - let address = if source_type != AccountSource::NETWORK { + let address = if source_type != AccountSource::Network { address.unwrap().to_string() } else { - load_ton_address(address.unwrap(), &config)? + load_ton_address(address.unwrap(), config)? }; let bc_config = matches.value_of("BCCONFIG"); run_get_method(config, &address, method.unwrap(), params, source_type, bc_config).await @@ -1394,7 +1392,7 @@ async fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) let config = &full_config.config; let tvc = matches.value_of("TVC"); let wc = wc_from_matches_or_config(matches, config)?; - let abi = Some(abi_from_matches_or_config(matches, &config)?); + let abi = Some(abi_from_matches_or_config(matches, config)?); let params = unpack_alternative_params( matches, abi.as_ref().unwrap(), @@ -1444,7 +1442,7 @@ fn config_command(matches: &ArgMatches, mut full_config: FullConfig, is_json: bo )? } else if let Some(alias_matches) = alias_matches.subcommand_matches("remove") { full_config.remove_alias(alias_matches.value_of("ALIAS").unwrap())? - } else if let Some(_) = alias_matches.subcommand_matches("reset") { + } else if alias_matches.subcommand_matches("reset").is_some() { full_config.aliases = BTreeMap::new(); full_config.to_file(&full_config.path)?; } @@ -1476,7 +1474,7 @@ async fn genaddr_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() let abi = match abi_from_matches_or_config(matches, config) { Ok(abi) => Some(abi), Err(err) => { - match load_abi_from_tvc(tvc.clone().unwrap()) { + match load_abi_from_tvc(tvc.unwrap()) { Some(abi) => Some(abi), None => return Err(err) } @@ -1503,7 +1501,7 @@ async fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() let mut formatted_list = vec![]; for address in addresses_list.iter() { if !is_boc { - let formatted = load_ton_address(address, &config)?; + let formatted = load_ton_address(address, config)?; formatted_list.push(formatted); } else { if !std::path::Path::new(address).exists() { @@ -1518,14 +1516,14 @@ async fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() if !config.is_json { print_args!(addresses); } - get_account(&config, formatted_list, tvcname, bocname, is_boc).await + get_account(config, formatted_list, tvcname, bocname, is_boc).await } async fn dump_accounts_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let addresses_list = matches.values_of("ADDRESS").unwrap().collect::>(); let mut formatted_list = vec![]; for address in addresses_list.iter() { - let formatted = load_ton_address(address, &config)?; + let formatted = load_ton_address(address, config)?; formatted_list.push(formatted); } let path = matches.value_of("PATH"); @@ -1538,7 +1536,7 @@ async fn dump_accounts_command(matches: &ArgMatches<'_>, config: &Config) -> Res async fn account_wait_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS").unwrap(); - let address = load_ton_address(address, &config)?; + let address = load_ton_address(address, config)?; let timeout = matches.value_of("TIMEOUT").unwrap_or("30").parse::() .map_err(|e| format!("failed to parse timeout: {}", e))?; wait_for_change(config, &address, timeout).await @@ -1559,14 +1557,14 @@ async fn storage_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() if !config.is_json { print_args!(address, period); } - let address = load_ton_address(address.unwrap(), &config)?; + let address = load_ton_address(address.unwrap(), config)?; let period = period.map(|val| { u32::from_str_radix(val, 10) .map_err(|e| format!("failed to parse period: {}", e)) }) .transpose()? .unwrap_or(DEF_STORAGE_PERIOD); - calc_storage(&config, address.as_str(), period).await + calc_storage(config, address.as_str(), period).await } async fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -1579,7 +1577,7 @@ async fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> R if !config.is_json { print_args!(address, comment, keys, lifetime); } - let address = load_ton_address(address.unwrap(), &config)?; + let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; create_proposal( @@ -1602,7 +1600,7 @@ async fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Res if !config.is_json { print_args!(address, id, keys, lifetime); } - let address = load_ton_address(address.unwrap(), &config)?; + let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; vote(config, address.as_str(), keys, id.unwrap(), lifetime, offline).await?; @@ -1616,7 +1614,7 @@ async fn proposal_decode_command(matches: &ArgMatches<'_>, config: &Config) -> R if !config.is_json { print_args!(address, id); } - let address = load_ton_address(address.unwrap(), &config)?; + let address = load_ton_address(address.unwrap(), config)?; decode_proposal(config, address.as_str(), id.unwrap()).await } @@ -1633,10 +1631,11 @@ async fn update_config_command(matches: &ArgMatches<'_>, config: &Config) -> Res let seqno = matches.value_of("SEQNO"); let config_master = matches.value_of("CONFIG_MASTER_KEY_FILE"); let new_param = matches.value_of("NEW_PARAM_FILE"); + let ouput = matches.value_of("OUTPUT"); if !config.is_json { print_args!(seqno, config_master, new_param); } - gen_update_config_message(abi, seqno, config_master.unwrap(), new_param.unwrap(), config.is_json).await + gen_update_config_message(abi, seqno, config_master.unwrap(), new_param.unwrap(), ouput, config.is_json).await } async fn dump_bc_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -1659,7 +1658,7 @@ fn nodeid_command(matches: &ArgMatches, config: &Config) -> Result<(), String> { convert::nodeid_from_pubkey(&vec)? } else if let Some(pair) = keypair { let pair = crypto::load_keypair(pair)?; - convert::nodeid_from_pubkey(&hex::decode(&pair.public) + convert::nodeid_from_pubkey(&hex::decode(pair.public) .map_err(|e| format!("failed to decode public key: {}", e))?)? } else { return Err("Either public key or key pair parameter should be provided".to_owned()); diff --git a/src/message.rs b/src/message.rs index e55e2223..e372f2d7 100644 --- a/src/message.rs +++ b/src/message.rs @@ -61,21 +61,21 @@ pub fn prepare_message_params ( keys: Option, ) -> Result { let keys = keys.map(|k| load_keypair(&k)).transpose()?; - let params = serde_json::from_str(¶ms) + let params = serde_json::from_str(params) .map_err(|e| format!("arguments are not in json format: {}", e))?; let call_set = Some(CallSet { function_name: method.into(), input: Some(params), - header: header.clone(), + header, }); Ok(ParamsOfEncodeMessage { abi, address: Some(addr.to_owned()), call_set, - signer: if keys.is_some() { - Signer::Keys { keys: keys.unwrap() } + signer: if let Some(keys) = keys { + Signer::Keys { keys } } else { Signer::None }, @@ -165,12 +165,12 @@ pub async fn generate_message( ) -> Result<(), String> { let ton = create_client_local()?; - let ton_addr = load_ton_address(addr, &config) - .map_err(|e| format!("failed to parse address: {}", e.to_string()))?; + let ton_addr = load_ton_address(addr, config) + .map_err(|e| format!("failed to parse address: {}", e))?; let abi = load_abi(abi, config).await?; - let expire_at = lifetime + timestamp.clone().map(|millis| (millis / 1000) as u32).unwrap_or(now()?); + let expire_at = lifetime + timestamp.map(|millis| (millis / 1000) as u32).unwrap_or(now()?); let header = FunctionHeader { expire: Some(expire_at), time: timestamp, @@ -206,8 +206,7 @@ pub fn display_generated_message( print_encoded_message(msg, is_json); let msg_bytes = pack_message(msg, method, is_raw)?; - if output.is_some() { - let out_file = output.unwrap(); + if let Some(out_file) = output { std::fs::write(out_file, msg_bytes) .map_err(|e| format!("cannot write message to file: {}", e))?; if !is_json { diff --git a/src/multisig.rs b/src/multisig.rs index 6dc93866..2917fbc9 100644 --- a/src/multisig.rs +++ b/src/multisig.rs @@ -257,7 +257,7 @@ async fn multisig_send_command(matches: &ArgMatches<'_>, config: &Config) -> Res .ok_or("--value parameter is not defined".to_string())?; let comment = matches.value_of("PURPOSE"); - let address = load_ton_address(address, &config)?; + let address = load_ton_address(address, config)?; send(config, address.as_str(), dest, value, keys, comment).await } @@ -345,10 +345,7 @@ async fn multisig_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> R let keys = load_keypair(&keys)?; let owners_string = if let Some(owners) = matches.value_of("OWNERS") { - owners.replace('[', "") - .replace(']', "") - .replace('\"', "") - .replace('\'', "") + owners.replace(['[', ']', '\"', '\''], "") .replace("0x", "") .split(',') .map(|o| @@ -370,7 +367,7 @@ async fn multisig_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> R println!("Wallet address: {}", address); } - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; if let Some(value) = matches.value_of("VALUE") { let params = format!(r#"{{"dest":"{}","amount":"{}"}}"#, address, value); diff --git a/src/replay.rs b/src/replay.rs index 4c0180cc..0ecd453d 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -140,7 +140,7 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo println!("account {}: zerostate not found, writing out default initial state", account_address); } let data = format!("{{\"id\":\"{}\",\"boc\":\"{}\"}}\n", - account_address, base64::encode(&Account::default().write_to_bytes() + account_address, base64::encode(Account::default().write_to_bytes() .map_err(|e| format!("failed to serialize account: {}", e))?)); writer.write_all(data.as_bytes()).map_err(|e| format!("Failed to write to file: {}", e))?; } @@ -316,12 +316,10 @@ pub async fn replay( let state = choose(&mut account_state, &mut config_state); let tr = state.tr.as_ref().ok_or("failed to obtain state transaction")?; - if iterate_config { - if cur_block_lt == 0 || cur_block_lt != tr.block_lt { - assert!(tr.block_lt > cur_block_lt); - cur_block_lt = tr.block_lt; - config = construct_blockchain_config(&config_account)?; - } + if iterate_config && (cur_block_lt == 0 || cur_block_lt != tr.block_lt) { + assert!(tr.block_lt > cur_block_lt); + cur_block_lt = tr.block_lt; + config = construct_blockchain_config(&config_account)?; } let mut account_root = state.account.serialize() @@ -378,7 +376,7 @@ pub async fn replay( } if trace_callback.is_some() { init_trace_last_logger()?; - let executor = Box::new(OrdinaryTransactionExecutor::new(config.clone())); + let executor = Box::new(OrdinaryTransactionExecutor::new(config)); let msg = tr.tr.in_msg_cell().map(|c| Message::construct_from_cell(c) .map_err(|e| format!("failed to construct message: {}", e))).transpose()?; let params = ExecuteParams { @@ -545,7 +543,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res println!("Pre-replaying block accounts"); let tasks: Vec<_> = accounts.iter().map(|(account, txns)| { let account_filename = account.split(':').last().unwrap_or("").to_owned(); - let _config = config.clone().to_owned(); + let _config = config.clone(); let txnid = txns[0].0.clone(); tokio::spawn(async move { if !std::path::Path::new(format!("{}-{}.boc", account_filename, txnid).as_str()).exists() { diff --git a/src/run.rs b/src/run.rs index 5ece427a..3a40aead 100644 --- a/src/run.rs +++ b/src/run.rs @@ -32,18 +32,18 @@ pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_ (address.unwrap(), abi.unwrap()) } else { (matches.value_of("ADDRESS").unwrap().to_string(), - abi_from_matches_or_config(matches, &config)?) + abi_from_matches_or_config(matches, config)?) }; let account_source = if matches.is_present("TVC") { - AccountSource::TVC + AccountSource::Tvc } else if matches.is_present("BOC") { - AccountSource::BOC + AccountSource::Boc } else { - AccountSource::NETWORK + AccountSource::Network }; - let ton_client = if account_source == AccountSource::NETWORK { - if config.debug_fail != "None".to_string() { + let ton_client = if account_source == AccountSource::Network { + if &config.debug_fail != "None" { let method = if is_alternative { matches.value_of("METHOD").or(config.method.as_deref()) .ok_or("Method is not defined. Supply it in the config file or command line.")? @@ -53,11 +53,11 @@ pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_ let log_path = format!("run_{}_{}.log", address, method); log::set_max_level(log::LevelFilter::Trace); log::set_boxed_logger( - Box::new(DebugLogger::new(log_path.to_string())) + Box::new(DebugLogger::new(log_path)) ).map_err(|e| format!("Failed to set logger: {}", e))?; - create_client(&config)? + create_client(config)? } else { - create_client_verbose(&config)? + create_client_verbose(config)? } } else { create_client_local()? @@ -67,12 +67,12 @@ pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_ &account_source, &address, Some(ton_client.clone()), - &config + config ).await?; let address = match account_source { - AccountSource::NETWORK => address, - AccountSource::BOC => account.get_addr().unwrap().to_string(), - AccountSource::TVC => std::iter::repeat("0").take(64).collect::() + AccountSource::Network => address, + AccountSource::Boc => account.get_addr().unwrap().to_string(), + AccountSource::Tvc => "0".repeat(64) }; run(matches, config, Some(ton_client), &address, account_boc, abi_path, is_alternative).await } @@ -122,7 +122,7 @@ async fn run( let msg = prepare_message( ton_client.clone(), - &address, + address, abi.clone(), method, ¶ms.unwrap(), @@ -144,7 +144,7 @@ async fn run( }, ).await; - if config.debug_fail != "None".to_string() && result.is_err() + if &config.debug_fail != "None" && result.is_err() && result.clone().err().unwrap().code == SDK_EXECUTION_ERROR_CODE { // TODO: add code to use bc_config from file @@ -154,7 +154,7 @@ async fn run( .unwrap_or(Value::String(e)); let res = json!({"Error": err}); println!("{}", serde_json::to_string_pretty(&res) - .unwrap_or("{{ \"JSON serialization error\" }}".to_string())); + .unwrap_or_else(|_| "{{ \"JSON serialization error\" }}".to_string())); } else { println!("Error: {:#}", result.clone().err().unwrap()); println!("Execution failed. Starting debug..."); @@ -168,7 +168,7 @@ async fn run( let now = now_ms(); let message = Message::construct_from_base64(&msg.message) .map_err(|e| format!("failed to construct message: {}", e))?; - match execute_debug( + if let Err(e) = execute_debug( get_blockchain_config(config, None).await?, &mut account, Some(&message), @@ -178,12 +178,9 @@ async fn run( true, config ).await { - Err(e) => { - if !e.contains("Contract did not accept message") { - return Err(e); - } - }, - Ok(_) => {} + if !e.contains("Contract did not accept message") { + return Err(e); + } } if !config.is_json { @@ -218,7 +215,7 @@ fn prepare_execution_options(bc_config: Option<&str>) -> Result) -> Result, source_type: AccountSource, bc_config: Option<&str>) -> Result<(), String> { - let ton = if source_type == AccountSource::NETWORK { - create_client_verbose(&config)? + let ton = if source_type == AccountSource::Network { + create_client_verbose(config)? } else { create_client_local()? }; @@ -255,7 +252,7 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O ..Default::default() }, ).await - .map_err(|e| format!("run failed: {}", e.to_string()))? + .map_err(|e| format!("run failed: {}", e))? .output; if !config.is_json { @@ -265,10 +262,8 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O let mut res = Map::new(); match result { Value::Array(array) => { - let mut i = 0; - for val in array.iter() { + for (i, val) in array.iter().enumerate() { res.insert(format!("value{}", i), val.to_owned()); - i = 1 + i; } }, _ => { @@ -276,7 +271,7 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O } } let res = Value::Object(res); - println!("{}", serde_json::to_string_pretty(&res).unwrap_or("Undefined".to_string())); + println!("{}", serde_json::to_string_pretty(&res).unwrap_or_else(|_| "Undefined".to_string())); } Ok(()) } diff --git a/src/sendfile.rs b/src/sendfile.rs index cdcf1222..d5ab527a 100644 --- a/src/sendfile.rs +++ b/src/sendfile.rs @@ -15,7 +15,7 @@ use crate::config::Config; use crate::call::send_message_and_wait; pub async fn sendfile(config: &Config, msg_boc: &str) -> Result<(), String> { - let ton = create_client_verbose(&config)?; + let ton = create_client_verbose(config)?; let boc_vec = std::fs::read(msg_boc) .map_err(|e| format!("failed to read boc file: {}", e))?; let tvm_msg = ton_sdk::Contract::deserialize_message(&boc_vec[..]) diff --git a/tests/browser.rs b/tests/browser.rs index b349a178..2d1ed655 100644 --- a/tests/browser.rs +++ b/tests/browser.rs @@ -158,7 +158,7 @@ fn test_pipechain_inputs() -> Result<(), Box> { .assert() .success(); - let _ = std::fs::remove_file(path_to_pipechain_tmp)?; + std::fs::remove_file(path_to_pipechain_tmp)?; let out_value: serde_json::Value = serde_json::from_slice(&assert.get_output().stdout).unwrap(); let eq = predicate::eq(return_value); diff --git a/tests/common/mod.rs b/tests/common/mod.rs index 8a986c39..f83f7d15 100644 --- a/tests/common/mod.rs +++ b/tests/common/mod.rs @@ -13,7 +13,7 @@ pub const GIVER_V2_KEY: &str = "tests/samples/giver_v2.key"; lazy_static! { pub static ref NETWORK: String = env::var("TON_NETWORK_ADDRESS") - .unwrap_or("http://127.0.0.1/".to_string()); + .unwrap_or_else(|_| "http://127.0.0.1/".to_string()); } #[allow(dead_code)] @@ -35,9 +35,8 @@ pub fn get_config() -> Result, Box> { #[allow(dead_code)] pub fn set_config(config: &[&str], argument: &[&str], config_path: Option<&str>) -> Result<(), Box> { let mut cmd = Command::cargo_bin(BIN_NAME)?; - if config_path.is_some() { - cmd.arg("--config") - .arg(config_path.unwrap()); + if let Some(config_path) = config_path { + cmd.arg("--config").arg(config_path); } cmd.arg("config"); for i in 0..config.len() { diff --git a/tests/test_cli.rs b/tests/test_cli.rs index 2537385e..892f0380 100644 --- a/tests/test_cli.rs +++ b/tests/test_cli.rs @@ -655,7 +655,7 @@ fn test_async_deploy() -> Result<(), Box> { fs::remove_file(config_path)?; let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("account") - .arg(addr.clone()); + .arg(addr); wait_for_cmd_res(&mut cmd, "acc_type: Active")?; @@ -2821,7 +2821,7 @@ fn test_options_priority() -> Result<(), Box> { .arg("--abi") .arg(SAFEMSIG_ABI) .arg("--addr") - .arg(address.clone()) + .arg(address) .arg("-m") .arg("getParameters") .arg("{}"); @@ -2840,7 +2840,7 @@ fn test_options_priority() -> Result<(), Box> { Some(config_path) )?; - let params = format!("{{\"dest\":\"{}\",\"value\":1000000000,\"bounce\":false}}", address.clone()); + let params = format!("{{\"dest\":\"{}\",\"value\":1000000000,\"bounce\":false}}", address); let mut cmd = Command::cargo_bin(BIN_NAME)?; cmd.arg("--config") .arg(config_path) @@ -2884,7 +2884,7 @@ fn test_options_priority() -> Result<(), Box> { .arg("run") .arg("--abi") .arg(SAFEMSIG_ABI) - .arg(address.clone()) + .arg(address) .arg("getParameters") .arg("{}"); cmd.assert() @@ -2962,7 +2962,7 @@ fn test_alternative_parameters() -> Result<(), Box> { set_config( &["--abi", "--addr", "--keys", "--method"], - &[abi_path, &address.clone(), key_path, "add"], + &[abi_path, &address, key_path, "add"], Some(config_path) )?; @@ -3082,7 +3082,7 @@ fn test_alternative_paths() -> Result<(), Box> { set_config( &["--abi"], - &[&*SAFEMSIG_ABI_LINK], + &[SAFEMSIG_ABI_LINK], Some(config_path) )?; @@ -3129,7 +3129,7 @@ fn test_alternative_paths() -> Result<(), Box> { .arg(config_path) .arg("runx") .arg("--addr") - .arg(address.clone()) + .arg(address) .arg("-m") .arg("getParameters") .arg("--abi") From 2a3fc9438b07ca645823b560af6161ea6e6de0c8 Mon Sep 17 00:00:00 2001 From: SergeyY <43989533+yaroslavser@users.noreply.github.com> Date: Fri, 3 Mar 2023 09:51:34 +0300 Subject: [PATCH 3/9] Update Cargo.toml --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index f6995d60..ad06a589 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,7 +16,7 @@ license = 'Apache-2.0' name = 'tonos-cli' readme = 'README.md' repository = 'https://github.com/tonlabs/tonos-cli' -version = '0.32.0' +version = '0.32.1' default-run = 'tonos-cli' [features] From bc5156440f515e2634d033f9cb1f185153df585d Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Fri, 3 Mar 2023 10:10:26 +0300 Subject: [PATCH 4/9] fix runtime --- src/debot/mod.rs | 4 +- src/debug.rs | 4 +- src/decode.rs | 14 +- src/depool.rs | 4 +- src/getconfig.rs | 9 +- src/helpers.rs | 2 +- src/main.rs | 326 ++++++++++++++++++++++++++--------------------- src/multisig.rs | 18 +-- src/replay.rs | 23 ++-- src/run.rs | 28 ++-- 10 files changed, 242 insertions(+), 190 deletions(-) diff --git a/src/debot/mod.rs b/src/debot/mod.rs index 3c5f0960..191f0281 100644 --- a/src/debot/mod.rs +++ b/src/debot/mod.rs @@ -83,7 +83,7 @@ pub fn create_debot_command<'a, 'b>() -> App<'a, 'b> { ) } -pub async fn debot_command(m: &ArgMatches<'_>, config: Config) -> Result<(), String> { +pub fn debot_command(m: &ArgMatches<'_>, config: Config) -> Result<(), String> { let debug = m.is_present("DEBUG"); let log_conf = ConfigBuilder::new() .add_filter_ignore_str("executor") @@ -110,6 +110,7 @@ pub async fn debot_command(m: &ArgMatches<'_>, config: Config) -> Result<(), Str } CombinedLogger::init(loggers).unwrap(); + crate::RUNTIME.block_on(async move { if let Some(m) = m.subcommand_matches("fetch") { return fetch_command(m, config).await; } @@ -120,6 +121,7 @@ pub async fn debot_command(m: &ArgMatches<'_>, config: Config) -> Result<(), Str return invoke_command(m, config).await; } Err("unknown debot command".to_owned()) + }) } async fn fetch_command(m: &ArgMatches<'_>, config: Config) -> Result<(), String> { diff --git a/src/debug.rs b/src/debug.rs index ad400d58..96d58322 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -348,7 +348,8 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .subcommand(msg_cmd) } -pub async fn debug_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { +pub fn debug_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { + crate::RUNTIME.block_on(async move { let config = &full_config.config; if let Some(matches) = matches.subcommand_matches("transaction") { return debug_transaction_command(matches, config, false).await; @@ -375,6 +376,7 @@ pub async fn debug_command(matches: &ArgMatches<'_>, full_config: &FullConfig) - return sequence_diagram_command(matches, config).await; } Err("unknown command".to_owned()) + }) } async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is_account: bool) -> Result<(), String> { diff --git a/src/decode.rs b/src/decode.rs index 1b53eedc..77696b99 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -97,9 +97,10 @@ pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> { .help("Path to the TVC file where to save the dump.")))) } -pub async fn decode_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +pub fn decode_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + crate::RUNTIME.block_on(async move { if let Some(m) = m.subcommand_matches("body") { - return decode_body_command(m, config).await; + return decode_body_command(m, config); } if let Some(m) = m.subcommand_matches("msg") { return decode_message_command(m, config).await; @@ -116,6 +117,7 @@ pub async fn decode_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), S } } Err("unknown command".to_owned()) + }) } async fn decode_data_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -128,14 +130,16 @@ async fn decode_data_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), Err("unknown command".to_owned()) } -async fn decode_body_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn decode_body_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let body = m.value_of("BODY"); let abi = Some(abi_from_matches_or_config(m, config)?); if !config.is_json { print_args!(body, abi); } - decode_body(body.unwrap(), &abi.unwrap(), config.is_json, config).await?; - Ok(()) + crate::RUNTIME.block_on(async move { + decode_body(body.unwrap(), &abi.unwrap(), config.is_json, config).await?; + Ok(()) + }) } async fn decode_account_from_boc(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { diff --git a/src/depool.rs b/src/depool.rs index 545bbe59..6f9ba45b 100644 --- a/src/depool.rs +++ b/src/depool.rs @@ -241,7 +241,8 @@ fn parse_stake_data<'a>(m: &'a ArgMatches, config: &Config) -> Result<(String, & Ok((wallet, stake, keys)) } -pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<(), String> { +pub fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<(), String> { + crate::RUNTIME.block_on(async move { let depool = m.value_of("ADDRESS") .map(|s| s.to_string()) .or(config.addr.clone()) @@ -330,6 +331,7 @@ pub async fn depool_command(m: &ArgMatches<'_>, config: &mut Config) -> Result<( return ticktock_command(config, &depool, &wallet, &keys).await; } Err("unknown depool command".to_owned()) + }) } async fn answer_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Result<(), String> { diff --git a/src/getconfig.rs b/src/getconfig.rs index 2383267f..e7769bf3 100644 --- a/src/getconfig.rs +++ b/src/getconfig.rs @@ -13,9 +13,8 @@ use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signer}; use num_bigint::BigUint; -use std::time::{SystemTime, UNIX_EPOCH}; use crate::config::Config; -use crate::helpers::{create_client_verbose, query_with_limit}; +use crate::helpers::{create_client_verbose, query_with_limit, now}; use serde_json::json; use ton_abi::{Contract, Token, TokenValue, Uint}; use ton_block::{ExternalInboundMessageHeader, Grams, Message, MsgAddressInt, Serializable}; @@ -320,7 +319,7 @@ pub async fn query_global_config(config: &Config, index: Option<&str>) -> Result Ok(()) } -pub async fn gen_update_config_message( +pub fn gen_update_config_message( abi: Option<&str>, seqno: Option<&str>, config_master_file: &str, @@ -410,7 +409,7 @@ fn prepare_message_new_config_param( private_key_of_config_account: &[u8] ) -> Result { let prefix = hex::decode(PREFIX_UPDATE_CONFIG_MESSAGE_DATA).unwrap(); - let since_the_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_secs() as u32 + 100; // timestamp + 100 secs + let since_the_epoch = now()? + 100; // timestamp + 100 secs let mut cell = BuilderData::default(); cell.append_raw(prefix.as_slice(), 32).unwrap(); @@ -456,7 +455,7 @@ fn prepare_message_new_config_param_solidity( let keypair = Keypair { secret, public }; let config_contract_address = MsgAddressInt::with_standart(None, -1, config_account).unwrap(); - let since_the_epoch = SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_micros() as u64; + let since_the_epoch = now()? as u64 * 1000; let header = [("time".to_owned(), TokenValue::Time(since_the_epoch))] .into_iter() diff --git a/src/helpers.rs b/src/helpers.rs index eef09001..fa98abe1 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -661,7 +661,7 @@ pub fn parse_lifetime(lifetime: Option<&str>, config: &Config) -> Result { + ($( $arg:expr ),* ) => { println!("Input arguments:"); $( println!( diff --git a/src/main.rs b/src/main.rs index adb4d229..35d970ec 100644 --- a/src/main.rs +++ b/src/main.rs @@ -17,6 +17,8 @@ mod account; mod call; +#[cfg(feature = "sold")] +mod compile; mod config; mod convert; mod crypto; @@ -35,43 +37,46 @@ mod replay; mod debug; mod run; mod message; -#[cfg(feature = "sold")] -mod compile; -use account::{get_account, calc_storage, wait_for_change}; +use account::{calc_storage, dump_accounts, get_account, wait_for_change}; use call::{call_contract, call_contract_with_msg}; use clap::{ArgMatches, SubCommand, Arg, AppSettings, App}; +#[cfg(feature = "sold")] +use compile::{compile_command, create_compile_command}; use config::{Config, set_config, clear_config}; +use config::{FullConfig, resolve_net_name}; use crypto::{generate_mnemonic, extract_pubkey, generate_keypair}; use debot::{create_debot_command, debot_command}; -use decode::{create_decode_command, decode_command}; use debug::{create_debug_command, debug_command}; +use decode::{create_decode_command, decode_command}; use deploy::{deploy_contract, generate_deploy_message}; use depool::{create_depool_command, depool_command}; use ed25519_dalek::Signer; use genaddr::generate_address; -use getconfig::{query_global_config, dump_blockchain_config}; -use helpers::{load_ton_address, load_abi, create_client_local, query_raw, - contract_data_from_matches_or_config_alias, decode_data}; +use getconfig::{gen_update_config_message, query_global_config, dump_blockchain_config}; +use helpers::{ + abi_from_matches_or_config, contract_data_from_matches_or_config_alias, create_client_local, + decode_data, default_config_name, global_config_path, load_abi, load_abi_from_tvc, load_params, + load_ton_address, parse_lifetime, query_raw, unpack_alternative_params, + wc_from_matches_or_config, AccountSource, +}; +use message::generate_message; use multisig::{create_multisig_command, multisig_command}; use replay::{fetch_block_command, fetch_command, replay_command}; +use run::{run_command, run_get_method}; use serde_json::json; -use std::collections::BTreeMap; -use std::env; -use std::process::exit; -use std::sync::Arc; +use std::{env, process::exit, sync::Arc}; use ton_client::abi::{ParamsOfEncodeMessageBody, CallSet}; use ton_types::deserialize_tree_of_cells_inmem; use voting::{create_proposal, decode_proposal, vote}; -use crate::account::dump_accounts; -#[cfg(feature = "sold")] -use crate::compile::{compile_command, create_compile_command}; -use crate::config::{FullConfig, resolve_net_name}; -use crate::getconfig::gen_update_config_message; -use crate::helpers::{abi_from_matches_or_config, AccountSource, default_config_name, global_config_path, load_abi_from_tvc, load_params, parse_lifetime, unpack_alternative_params, wc_from_matches_or_config}; -use crate::message::generate_message; -use crate::run::{run_command, run_get_method}; +lazy_static::lazy_static! { + static ref RUNTIME: tokio::runtime::Runtime = tokio::runtime::Builder::new_current_thread() + .enable_all() + .thread_stack_size(800 * 1024 * 1024) + .build() + .expect("Can't create Engine tokio runtime"); +} const DEF_MSG_LIFETIME: u32 = 30; const DEF_STORAGE_PERIOD: u32 = 60 * 60 * 24 * 365; @@ -88,15 +93,15 @@ enum DeployType { Fee, } -#[tokio::main] -async fn main() -> Result<(), i32> { - main_internal().await.map_err(|err_str| { - if !err_str.is_empty() { println!("{}", err_str); } - 1 - }) +fn main() -> Result<(), i32> { + if let Err(err_str) = main_internal() { + println!("{}", err_str); + return Err(1) + } + Ok(()) } -async fn main_internal() -> Result <(), String> { +fn main_internal() -> Result <(), String> { let version_string = env!("CARGO_PKG_VERSION"); let abi_arg = Arg::with_name("ABI") @@ -886,7 +891,7 @@ async fn main_internal() -> Result <(), String> { env!("BUILD_TIME"), env!("BUILD_GIT_DATE"), env!("BUILD_GIT_BRANCH")); - let matches = App::new("tonos_cli") + let matches = App::new("tonos-cli") .version(&*version) .author(author) .about("TONLabs console tool for TON") @@ -942,7 +947,7 @@ async fn main_internal() -> Result <(), String> { .subcommand(runx_cmd) .subcommand(update_config_param_cmd) .setting(AppSettings::SubcommandRequired); -#[cfg(feature = "sold")] + #[cfg(feature = "sold")] let matches = matches.subcommand(create_compile_command()); let matches = matches.get_matches_safe() @@ -957,7 +962,7 @@ async fn main_internal() -> Result <(), String> { let is_json = matches.is_present("JSON"); - command_parser(&matches, is_json).await + command_parser(&matches, is_json) .map_err(|e| { if e.is_empty() { e @@ -971,7 +976,7 @@ async fn main_internal() -> Result <(), String> { }) } -async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), String> { +fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), String> { let config_file = matches.value_of("CONFIG").map(|v| v.to_string()) .or_else(|| env::var("TONOSCLI_CONFIG").ok()) .unwrap_or_else(default_config_name); @@ -993,59 +998,59 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), } if let Some(m) = matches.subcommand_matches("callx") { - return callx_command(m, &full_config).await; + return callx_command(m, &full_config); } if let Some(m) = matches.subcommand_matches("runx") { - return run_command(m, &full_config, true).await; + return run_command(m, &full_config, true); } if let Some(m) = matches.subcommand_matches("deployx") { - return deployx_command(m, &mut full_config).await; + return deployx_command(m, &mut full_config); } if let Some(m) = matches.subcommand_matches("call") { - return call_command(m, config, CallType::Call).await; + return call_command(m, config, CallType::Call); } if let Some(m) = matches.subcommand_matches("run") { - return run_command(m, &full_config, false).await; + return run_command(m, &full_config, false); } if let Some(m) = matches.subcommand_matches("runget") { - return runget_command(m, config).await; + return runget_command(m, config); } if let Some(m) = matches.subcommand_matches("body") { - return body_command(m, config).await; + return body_command(m, config); } if let Some(m) = matches.subcommand_matches("sign") { return sign_command(m, config); } if let Some(m) = matches.subcommand_matches("message") { - return call_command(m, config, CallType::Msg).await; + return call_command(m, config, CallType::Msg); } if let Some(m) = matches.subcommand_matches("send") { - return send_command(m, config).await; + return send_command(m, config); } if let Some(m) = matches.subcommand_matches("deploy") { - return deploy_command(m, &mut full_config, DeployType::Full).await; + return deploy_command(m, &mut full_config, DeployType::Full); } if let Some(m) = matches.subcommand_matches("deploy_message") { - return deploy_command(m, &mut full_config, DeployType::MsgOnly).await; + return deploy_command(m, &mut full_config, DeployType::MsgOnly); } if let Some(m) = matches.subcommand_matches("genaddr") { - return genaddr_command(m, config).await; + return genaddr_command(m, config); } if let Some(m) = matches.subcommand_matches("getkeypair") { return getkeypair_command(m, config); } if let Some(m) = matches.subcommand_matches("account") { - return account_command(m, config).await; + return account_command(m, config); } if let Some(m) = matches.subcommand_matches("fee") { if let Some(m) = m.subcommand_matches("storage") { - return storage_command(m, config).await; + return storage_command(m, config); } if let Some(m) = m.subcommand_matches("deploy") { - return deploy_command(m, &mut full_config, DeployType::Fee).await; + return deploy_command(m, &mut full_config, DeployType::Fee); } if let Some(m) = m.subcommand_matches("call") { - return call_command(m, config, CallType::Fee).await; + return call_command(m, config, CallType::Fee); } } if let Some(m) = matches.subcommand_matches("genphrase") { @@ -1056,68 +1061,68 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result <(), } if let Some(m) = matches.subcommand_matches("proposal") { if let Some(m) = m.subcommand_matches("create") { - return proposal_create_command(m, config).await; + return proposal_create_command(m, config); } if let Some(m) = m.subcommand_matches("vote") { - return proposal_vote_command(m, config).await; + return proposal_vote_command(m, config); } if let Some(m) = m.subcommand_matches("decode") { - return proposal_decode_command(m, config).await; + return proposal_decode_command(m, config); } } if let Some(m) = matches.subcommand_matches("multisig") { - return multisig_command(m, config).await; + return multisig_command(m, config); } if let Some(m) = matches.subcommand_matches("depool") { - return depool_command(m, config).await; + return depool_command(m, config); } if let Some(m) = matches.subcommand_matches("getconfig") { - return getconfig_command(m, config).await; + return getconfig_command(m, config); } if let Some(m) = matches.subcommand_matches("update_config") { - return update_config_command(m, config).await; + return update_config_command(m, config); } if let Some(matches) = matches.subcommand_matches("dump") { if let Some(m) = matches.subcommand_matches("config") { - return dump_bc_config_command(m, config).await; + return dump_bc_config_command(m, config); } if let Some(m) = matches.subcommand_matches("account") { - return dump_accounts_command(m, config).await; + return dump_accounts_command(m, config); } } if let Some(m) = matches.subcommand_matches("account-wait") { - return account_wait_command(m, config).await; + return account_wait_command(m, config); } if let Some(m) = matches.subcommand_matches("query-raw") { - return query_raw_command(m, config).await; + return query_raw_command(m, config); } if let Some(m) = matches.subcommand_matches("nodeid") { return nodeid_command(m, config); } if let Some(m) = matches.subcommand_matches("sendfile") { - return sendfile_command(m, config).await; + return sendfile_command(m, config); } if let Some(m) = matches.subcommand_matches("decode") { - return decode_command(m, config).await; + return decode_command(m, config); } if let Some(m) = matches.subcommand_matches("debug") { - return debug_command(m, &full_config).await; + return debug_command(m, &full_config); } if let Some(m) = matches.subcommand_matches("debot") { - return debot_command(m, config.to_owned()).await; + return debot_command(m, config.to_owned()); } if let Some(m) = matches.subcommand_matches("fetch-block") { - return fetch_block_command(m, config).await; + return fetch_block_command(m, config); } if let Some(m) = matches.subcommand_matches("fetch") { - return fetch_command(m, config).await; + return fetch_command(m, config); } if let Some(m) = matches.subcommand_matches("replay") { - return replay_command(m, config).await; + return replay_command(m, config); } -#[cfg(feature = "sold")] + #[cfg(feature = "sold")] if let Some(m) = matches.subcommand_matches("compile") { - return compile_command(m, &config).await; + return compile_command(m, &config); } if matches.subcommand_matches("version").is_some() { if config.is_json { @@ -1161,35 +1166,37 @@ fn getkeypair_command(matches: &ArgMatches, config: &Config) -> Result<(), Strin generate_keypair(key_file, phrase, config) } -async fn send_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - let message = matches.value_of("MESSAGE"); - let abi = Some(abi_from_matches_or_config(matches, config)?); +fn send_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + let message = matches.value_of("MESSAGE").unwrap(); + let abi_path = abi_from_matches_or_config(matches, config)?; if !config.is_json { - print_args!(message, abi); + print_args!(Some(&message), Some(&abi_path)); } - call_contract_with_msg(config, message.unwrap().to_owned(), &abi.unwrap()).await + RUNTIME.block_on(async move { + call_contract_with_msg(config, message.to_owned(), &abi_path).await + }) } -async fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let method = matches.value_of("METHOD"); let params = matches.value_of("PARAMS"); let output = matches.value_of("OUTPUT"); - let abi = Some(abi_from_matches_or_config(matches, config)?); + let abi_path = abi_from_matches_or_config(matches, config)?; let params = Some(load_params(params.unwrap())?); if !config.is_json { - print_args!(method, params, abi, output); + print_args!(method, params, Some(&abi_path), output); } let params = serde_json::from_str(¶ms.unwrap()) .map_err(|e| format!("arguments are not in json format: {}", e))?; let client = create_client_local()?; - let body = ton_client::abi::encode_message_body( + let body = RUNTIME.block_on(async move {ton_client::abi::encode_message_body( client.clone(), ParamsOfEncodeMessageBody { - abi: load_abi(abi.as_ref().unwrap(), config).await?, + abi: load_abi(&abi_path, config).await?, call_set: CallSet::some_with_function_and_input(method.unwrap(), params) .ok_or("failed to create CallSet with specified parameters.")?, is_internal: true, @@ -1197,7 +1204,8 @@ async fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), S }, ).await .map_err(|e| format!("failed to encode body: {}", e)) - .map(|r| r.body)?; + .map(|r| r.body) + })?; if !config.is_json { println!("Message body: {}", body); @@ -1245,7 +1253,8 @@ fn sign_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> Ok(()) } -async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Result<(), String> { +fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Result<(), String> { + RUNTIME.block_on(async move { let address = matches.value_of("ADDRESS"); let method = matches.value_of("METHOD"); let params = matches.value_of("PARAMS"); @@ -1253,7 +1262,7 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) let raw = matches.is_present("RAW"); let output = matches.value_of("OUTPUT"); - let abi = Some(abi_from_matches_or_config(matches, config)?); + let abi_path = abi_from_matches_or_config(matches, config)?; let keys = matches.value_of("KEYS") .or_else(|| matches.value_of("SIGN")) @@ -1262,7 +1271,7 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) let params = Some(load_params(params.unwrap())?); if !config.is_json { - print_args!(address, method, params, abi, keys, lifetime, output); + print_args!(address, method, params, Some(&abi_path), keys, lifetime, output); } let address = load_ton_address(address.unwrap(), config)?; @@ -1272,7 +1281,7 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) call_contract( config, address.as_str(), - &abi.unwrap(), + &abi_path, method.unwrap(), ¶ms.unwrap(), keys, @@ -1293,7 +1302,7 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) generate_message( config, address.as_str(), - &abi.unwrap(), + &abi_path, method.unwrap(), ¶ms.unwrap(), keys, @@ -1304,23 +1313,26 @@ async fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) ).await }, } + }) } -async fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { +fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { let config = &full_config.config; - let method = Some(matches.value_of("METHOD").or(config.method.as_deref()) - .ok_or("Method is not defined. Supply it in the config file or command line.")?); - let (address, abi, keys) = contract_data_from_matches_or_config_alias(matches, full_config)?; + let method = matches.value_of("METHOD").or(config.method.as_deref()) + .ok_or("Method is not defined. Supply it in the config file or command line.")?; + let (address, abi_path, keys) = contract_data_from_matches_or_config_alias(matches, full_config)?; + let abi_path = abi_path.unwrap(); + RUNTIME.block_on(async move { let params = unpack_alternative_params( matches, - abi.as_ref().unwrap(), - method.unwrap(), + &abi_path, + method, config ).await?; - let params = Some(load_params(params.unwrap().as_ref())?); + let params = load_params(params.unwrap().as_ref())?; if !config.is_json { - print_args!(address, method, params, abi, keys); + print_args!(address, Some(&method), Some(¶ms), Some(&abi_path), keys); } let address = load_ton_address(address.unwrap().as_str(), config)?; @@ -1328,15 +1340,16 @@ async fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Re call_contract( config, address.as_str(), - &abi.unwrap(), - method.unwrap(), - ¶ms.unwrap(), + &abi_path, + method, + ¶ms, keys, false, ).await + }) } -async fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let method = matches.value_of("METHOD"); let params = matches.values_of("PARAMS"); @@ -1359,18 +1372,20 @@ async fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), load_ton_address(address.unwrap(), config)? }; let bc_config = matches.value_of("BCCONFIG"); - run_get_method(config, &address, method.unwrap(), params, source_type, bc_config).await + RUNTIME.block_on(async move { + run_get_method(config, &address, method.unwrap(), params, source_type, bc_config).await + }) } -async fn deploy_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig, deploy_type: DeployType) -> Result<(), String> { +fn deploy_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig, deploy_type: DeployType) -> Result<(), String> { let config = &full_config.config; let tvc = matches.value_of("TVC"); let params = matches.value_of("PARAMS"); let wc = wc_from_matches_or_config(matches, config)?; let raw = matches.is_present("RAW"); let output = matches.value_of("OUTPUT"); - let abi = Some(abi_from_matches_or_config(matches, config)?); + let abi_path = abi_from_matches_or_config(matches, config)?; let keys = matches.value_of("KEYS") .or(matches.value_of("SIGN")) .map(|s| s.to_string()) @@ -1379,23 +1394,24 @@ async fn deploy_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig, let params = Some(load_params(params.unwrap())?); if !config.is_json { let opt_wc = Some(format!("{}", wc)); - print_args!(tvc, params, abi, keys, opt_wc, alias); - } - match deploy_type { - DeployType::Full => deploy_contract(full_config, tvc.unwrap(), &abi.unwrap(), ¶ms.unwrap(), keys, wc, false, alias).await, - DeployType::MsgOnly => generate_deploy_message(tvc.unwrap(), &abi.unwrap(), ¶ms.unwrap(), keys, wc, raw, output, config).await, - DeployType::Fee => deploy_contract(full_config, tvc.unwrap(), &abi.unwrap(), ¶ms.unwrap(), keys, wc, true, None).await, + print_args!(tvc, params, Some(&abi_path), keys, opt_wc, alias); } + RUNTIME.block_on(async move { match deploy_type { + DeployType::Full => deploy_contract(full_config, tvc.unwrap(), &abi_path, ¶ms.unwrap(), keys, wc, false, alias).await, + DeployType::MsgOnly => generate_deploy_message(tvc.unwrap(), &abi_path, ¶ms.unwrap(), keys, wc, raw, output, &full_config.config).await, + DeployType::Fee => deploy_contract(full_config, tvc.unwrap(), &abi_path, ¶ms.unwrap(), keys, wc, true, None).await, + } }) } -async fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) -> Result<(), String> { +fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) -> Result<(), String> { + RUNTIME.block_on(async move { let config = &full_config.config; - let tvc = matches.value_of("TVC"); + let tvc = matches.value_of("TVC").unwrap(); let wc = wc_from_matches_or_config(matches, config)?; - let abi = Some(abi_from_matches_or_config(matches, config)?); + let abi_path = abi_from_matches_or_config(matches, config)?; let params = unpack_alternative_params( matches, - abi.as_ref().unwrap(), + &abi_path, "constructor", config ).await?; @@ -1406,9 +1422,10 @@ async fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) let alias = matches.value_of("ALIAS"); if !config.is_json { let opt_wc = Some(format!("{}", wc)); - print_args!(tvc, params, abi, keys, opt_wc, alias); + print_args!(Some(tvc), params, Some(&abi_path), keys, opt_wc, alias); } - deploy_contract(full_config, tvc.unwrap(), &abi.unwrap(), ¶ms.unwrap(), keys, wc, false, alias).await + deploy_contract(full_config, tvc, &abi_path, ¶ms.unwrap(), keys, wc, false, alias).await + }) } fn config_command(matches: &ArgMatches, mut full_config: FullConfig, is_json: bool) -> Result<(), String> { @@ -1443,7 +1460,7 @@ fn config_command(matches: &ArgMatches, mut full_config: FullConfig, is_json: bo } else if let Some(alias_matches) = alias_matches.subcommand_matches("remove") { full_config.remove_alias(alias_matches.value_of("ALIAS").unwrap())? } else if alias_matches.subcommand_matches("reset").is_some() { - full_config.aliases = BTreeMap::new(); + full_config.aliases = Default::default(); full_config.to_file(&full_config.path)?; } full_config.print_aliases(); @@ -1464,30 +1481,29 @@ fn config_command(matches: &ArgMatches, mut full_config: FullConfig, is_json: bo result } -async fn genaddr_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - let tvc = matches.value_of("TVC"); +fn genaddr_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + RUNTIME.block_on(async move { + let tvc = matches.value_of("TVC").unwrap(); let wc = matches.value_of("WC"); let keys = matches.value_of("GENKEY").or(matches.value_of("SETKEY")); let new_keys = matches.is_present("GENKEY"); let init_data = matches.value_of("DATA"); let update_tvc = matches.is_present("SAVE"); - let abi = match abi_from_matches_or_config(matches, config) { - Ok(abi) => Some(abi), + let abi_path = match abi_from_matches_or_config(matches, config) { + Ok(abi) => abi, Err(err) => { - match load_abi_from_tvc(tvc.unwrap()) { - Some(abi) => Some(abi), - None => return Err(err) - } + load_abi_from_tvc(tvc).ok_or_else(|| err)? } }; let is_update_tvc = if update_tvc { Some("true") } else { None }; if !config.is_json { - print_args!(tvc, abi, wc, keys, init_data, is_update_tvc); + print_args!(Some(tvc), Some(&abi_path), wc, keys, init_data, is_update_tvc); } - generate_address(config, tvc.unwrap(), &abi.unwrap(), wc, keys, new_keys, init_data, update_tvc).await + generate_address(config, tvc, &abi_path, wc, keys, new_keys, init_data, update_tvc).await + }) } -async fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let addresses_list = matches.values_of("ADDRESS") .map(|val| val.collect::>()) .or(config.addr.as_ref().map(|addr| vec![addr.as_str()])) @@ -1516,10 +1532,12 @@ async fn account_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() if !config.is_json { print_args!(addresses); } - get_account(config, formatted_list, tvcname, bocname, is_boc).await + RUNTIME.block_on(async move { + get_account(config, formatted_list, tvcname, bocname, is_boc).await + }) } -async fn dump_accounts_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn dump_accounts_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let addresses_list = matches.values_of("ADDRESS").unwrap().collect::>(); let mut formatted_list = vec![]; for address in addresses_list.iter() { @@ -1531,27 +1549,33 @@ async fn dump_accounts_command(matches: &ArgMatches<'_>, config: &Config) -> Res if !config.is_json { print_args!(addresses, path); } - dump_accounts(config, formatted_list, path).await + RUNTIME.block_on(async move { + dump_accounts(config, formatted_list, path).await + }) } -async fn account_wait_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn account_wait_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS").unwrap(); let address = load_ton_address(address, config)?; let timeout = matches.value_of("TIMEOUT").unwrap_or("30").parse::() .map_err(|e| format!("failed to parse timeout: {}", e))?; - wait_for_change(config, &address, timeout).await + RUNTIME.block_on(async move { + wait_for_change(config, &address, timeout).await + }) } -async fn query_raw_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn query_raw_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let collection = matches.value_of("COLLECTION").unwrap(); let filter = matches.value_of("FILTER"); let limit = matches.value_of("LIMIT"); let order = matches.value_of("ORDER"); let result = matches.value_of("RESULT").unwrap(); - query_raw(config, collection, filter, limit, order, result).await + RUNTIME.block_on(async move { + query_raw(config, collection, filter, limit, order, result).await + }) } -async fn storage_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn storage_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let period = matches.value_of("PERIOD"); if !config.is_json { @@ -1564,10 +1588,12 @@ async fn storage_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() }) .transpose()? .unwrap_or(DEF_STORAGE_PERIOD); - calc_storage(config, address.as_str(), period).await + RUNTIME.block_on(async move { + calc_storage(config, address.as_str(), period).await + }) } -async fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let dest = matches.value_of("DEST"); let keys = matches.value_of("KEYS"); @@ -1580,7 +1606,7 @@ async fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> R let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; - create_proposal( + RUNTIME.block_on(async move { create_proposal( config, address.as_str(), keys, @@ -1588,10 +1614,10 @@ async fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> R comment.unwrap(), lifetime, offline - ).await + ).await }) } -async fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let keys = matches.value_of("KEYS"); let id = matches.value_of("ID"); @@ -1603,30 +1629,36 @@ async fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Res let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; - vote(config, address.as_str(), keys, id.unwrap(), lifetime, offline).await?; + RUNTIME.block_on(async move { + vote(config, address.as_str(), keys, id.unwrap(), lifetime, offline).await + })?; println!("{{}}"); Ok(()) } -async fn proposal_decode_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn proposal_decode_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let id = matches.value_of("ID"); if !config.is_json { print_args!(address, id); } let address = load_ton_address(address.unwrap(), config)?; - decode_proposal(config, address.as_str(), id.unwrap()).await + RUNTIME.block_on(async move { + decode_proposal(config, address.as_str(), id.unwrap()).await + }) } -async fn getconfig_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn getconfig_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let index = matches.value_of("INDEX"); if !config.is_json { print_args!(index); } - query_global_config(config, index).await + RUNTIME.block_on(async move { + query_global_config(config, index).await + }) } -async fn update_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn update_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let abi = matches.value_of("ABI"); let seqno = matches.value_of("SEQNO"); let config_master = matches.value_of("CONFIG_MASTER_KEY_FILE"); @@ -1635,15 +1667,17 @@ async fn update_config_command(matches: &ArgMatches<'_>, config: &Config) -> Res if !config.is_json { print_args!(seqno, config_master, new_param); } - gen_update_config_message(abi, seqno, config_master.unwrap(), new_param.unwrap(), ouput, config.is_json).await + gen_update_config_message(abi, seqno, config_master.unwrap(), new_param.unwrap(), ouput, config.is_json) } -async fn dump_bc_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn dump_bc_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let path = matches.value_of("PATH"); if !config.is_json { print_args!(path); } - dump_blockchain_config(config, path.unwrap()).await + RUNTIME.block_on(async move { + dump_blockchain_config(config, path.unwrap()).await + }) } fn nodeid_command(matches: &ArgMatches, config: &Config) -> Result<(), String> { @@ -1673,10 +1707,12 @@ fn nodeid_command(matches: &ArgMatches, config: &Config) -> Result<(), String> { Ok(()) } -async fn sendfile_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn sendfile_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let boc = m.value_of("BOC"); if !config.is_json { print_args!(boc); } - sendfile::sendfile(config, boc.unwrap()).await + RUNTIME.block_on(async move { + sendfile::sendfile(config, boc.unwrap()).await + }) } diff --git a/src/multisig.rs b/src/multisig.rs index 2917fbc9..3c55edbc 100644 --- a/src/multisig.rs +++ b/src/multisig.rs @@ -236,14 +236,16 @@ pub fn create_multisig_command<'a, 'b>() -> App<'a, 'b> { .help("Number of confirmations required for executing transaction. Default value is 1."))) } -pub async fn multisig_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - if let Some(m) = m.subcommand_matches("send") { - return multisig_send_command(m, config).await; - } - if let Some(m) = m.subcommand_matches("deploy") { - return multisig_deploy_command(m, config).await; - } - Err("unknown multisig command".to_owned()) +pub fn multisig_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + crate::RUNTIME.block_on(async move { + if let Some(m) = m.subcommand_matches("send") { + return multisig_send_command(m, config).await; + } + if let Some(m) = m.subcommand_matches("deploy") { + return multisig_deploy_command(m, config).await; + } + Err("unknown multisig command".to_owned()) + }) } async fn multisig_send_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { diff --git a/src/replay.rs b/src/replay.rs index 0ecd453d..c0fc37d4 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -33,7 +33,7 @@ use ton_executor::{BlockchainConfig, ExecuteParams, OrdinaryTransactionExecutor, use ton_types::{BuilderData, SliceData, UInt256, serialize_tree_of_cells}; use ton_vm::executor::{Engine, EngineTraceInfo}; -use crate::config::Config; +use crate::{config::Config, RUNTIME}; use crate::helpers::{create_client, get_blockchain_config}; pub static CONFIG_ADDR: &str = "-1:5555555555555555555555555555555555555555555555555555555555555555"; @@ -607,21 +607,22 @@ struct BlockAccountDescr { transactions: Vec, } -pub async fn fetch_block_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +pub fn fetch_block_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + RUNTIME.block_on(async move { fetch_block(config, m.value_of("BLOCKID").ok_or("Missing block id")?, m.value_of("OUTPUT").ok_or("Missing output filename")? - ).await.map_err(|e| e.to_string())?; - Ok(()) + ).await.map_err(|e| e.to_string()) + }) } -pub async fn fetch_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - fetch(config, +pub fn fetch_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { + RUNTIME.block_on(async move { fetch(config, m.value_of("ADDRESS").ok_or("Missing account address")?, m.value_of("OUTPUT").ok_or("Missing output filename")?, None, true - ).await?; + ).await })?; if config.is_json { println!("{{}}"); } else { @@ -630,15 +631,17 @@ pub async fn fetch_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), St Ok(()) } -pub async fn replay_command(m: &ArgMatches<'_>, cli_config: &Config) -> Result<(), String> { +pub fn replay_command(m: &ArgMatches<'_>, cli_config: &Config) -> Result<(), String> { + RUNTIME.block_on(async move { let (config_txns, bc_config) = if m.is_present("DEFAULT_CONFIG") { ("", Some(get_blockchain_config(cli_config, None).await?)) } else { (m.value_of("CONFIG_TXNS").ok_or("Missing config txns filename")?, None) }; - let _ = replay(m.value_of("INPUT_TXNS").ok_or("Missing input txns filename")?, + replay(m.value_of("INPUT_TXNS").ok_or("Missing input txns filename")?, config_txns, m.value_of("TXNID").ok_or("Missing final txn id")?, None, ||{Ok(())}, DUMP_ALL, cli_config, bc_config - ).await?; + ).await + })?; Ok(()) } diff --git a/src/run.rs b/src/run.rs index 3a40aead..524e38a0 100644 --- a/src/run.rs +++ b/src/run.rs @@ -25,7 +25,7 @@ use crate::helpers::{create_client, now, now_ms, SDK_EXECUTION_ERROR_CODE, TonCl load_account, load_params, unpack_alternative_params, get_blockchain_config}; use crate::message::prepare_message; -pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_alternative: bool) -> Result<(), String> { +pub fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_alternative: bool) -> Result<(), String> { let config = &full_config.config; let (address, abi_path) = if is_alternative { let (address,abi, _) = contract_data_from_matches_or_config_alias(matches, full_config)?; @@ -63,18 +63,20 @@ pub async fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_ create_client_local()? }; - let (account, account_boc) = load_account( - &account_source, - &address, - Some(ton_client.clone()), - config - ).await?; - let address = match account_source { - AccountSource::Network => address, - AccountSource::Boc => account.get_addr().unwrap().to_string(), - AccountSource::Tvc => "0".repeat(64) - }; - run(matches, config, Some(ton_client), &address, account_boc, abi_path, is_alternative).await + crate::RUNTIME.block_on(async move { + let (account, account_boc) = load_account( + &account_source, + &address, + Some(ton_client.clone()), + config + ).await?; + let address = match account_source { + AccountSource::Network => address, + AccountSource::Boc => account.get_addr().unwrap().to_string(), + AccountSource::Tvc => "0".repeat(64) + }; + run(matches, config, Some(ton_client), &address, account_boc, abi_path, is_alternative).await + }) } async fn run( From 960807df80c0e46b6ed66f3c68bf46d1e893f301 Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Fri, 3 Mar 2023 10:26:57 +0300 Subject: [PATCH 5/9] update used tags --- Cargo.toml | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ad06a589..64747cae 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -48,15 +48,15 @@ log = { features = [ 'std' ], version = '0.4' } serde = { features = [ 'derive' ], version = '1.0' } tokio = { default-features = false, features = [ 'full' ], version = '1.21' } url = '2.3.1' -ton_abi = { git = 'https://github.com/tonlabs/ton-labs-abi.git', tag = '2.3.54' } -ton_block = { git = 'https://github.com/tonlabs/ton-labs-block.git', tag = '1.9.18' } -ton_block_json = { git = 'https://github.com/tonlabs/ton-labs-block-json.git', tag = '0.7.83' } -ton_client = { git = 'https://github.com/tonlabs/TON-SDK.git', tag = '1.40.0' } -ton_executor = { git = 'https://github.com/tonlabs/ton-labs-executor.git', tag = '1.15.154' } -ton_labs_assembler = { git = 'https://github.com/tonlabs/ton-labs-assembler.git', tag = '1.2.77' } -ton_sdk = { git = 'https://github.com/tonlabs/TON-SDK.git', tag = '1.40.0' } -ton_types = { git = 'https://github.com/tonlabs/ton-labs-types.git', tag = '1.12.6' } -ton_vm = { git = 'https://github.com/tonlabs/ton-labs-vm.git', tag = '1.8.96' } +ton_abi = { git = 'https://github.com/tonlabs/ever-abi.git', tag = '2.3.65' } +ton_block = { git = 'https://github.com/tonlabs/ever-block.git', tag = '1.9.28' } +ton_block_json = { git = 'https://github.com/tonlabs/ever-block-json.git', tag = '0.7.95' } +ton_client = { git = 'https://github.com/tonlabs/ever-sdk.git', tag = '1.41.0' } +ton_executor = { git = 'https://github.com/tonlabs/ever-executor.git', tag = '1.15.173' } +ton_labs_assembler = { git = 'https://github.com/tonlabs/ever-assembler.git', tag = '1.2.84' } +ton_sdk = { git = 'https://github.com/tonlabs/ever-sdk.git', tag = '1.41.0' } +ton_types = { git = 'https://github.com/tonlabs/ever-types.git', tag = '1.12.7' } +ton_vm = { git = 'https://github.com/tonlabs/ever-vm.git', tag = '1.8.114' } sold = { git = 'https://github.com/tonlabs/TON-Solidity-Compiler.git', tag = '0.66.0', optional = true } [dev-dependencies] From d2c5ca9c64990743279c915a8d5edf777f453f85 Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Mon, 6 Mar 2023 10:40:03 +0300 Subject: [PATCH 6/9] fix now --- src/debug.rs | 42 +++++++++++++++--------------------------- src/depool.rs | 4 ++-- src/getconfig.rs | 6 +++--- src/helpers.rs | 13 ++++++------- src/message.rs | 6 +++--- src/run.rs | 2 +- tests/test_cli.rs | 4 ---- 7 files changed, 30 insertions(+), 47 deletions(-) diff --git a/src/debug.rs b/src/debug.rs index 96d58322..0b09ba32 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -940,13 +940,8 @@ async fn decode_messages(msgs: OutMessages, abi: Option, config: &Config for msg in msgs { let mut ser_msg = serialize_msg(&msg.0, abi.clone(), config).await .map_err(|e| format!("Failed to serialize message: {}", e))?; - let msg_str = base64::encode( - ton_types::cells_serialization::serialize_toc( - &msg.0 - .serialize() - .map_err(|e| format!("Failed to serialize out message: {}", e))? - ).map_err(|e| format!("failed to encode out message: {}", e))? - ); + let bytes = msg.0.write_to_bytes().map_err(|e| format!("Failed to serialize out message: {}", e))?; + let msg_str = base64::encode(bytes); ser_msg["Message_base64"] = serde_json::Value::String(msg_str); if ser_msg["BodyCall"].is_object() { res.push(ser_msg["BodyCall"].clone()); @@ -1137,10 +1132,7 @@ fn trace_callback(info: &EngineTraceInfo, debug_info: &Option) { fn trace_callback_minimal(info: &EngineTraceInfo, debug_info: &Option) { - let position = match get_position(info, debug_info) { - Some(position) => position, - _ => "".to_string() - }; + let position = get_position(info, debug_info).unwrap_or_default(); log::info!(target: "tvm", "{} {} {} {} {}", info.step, info.gas_used, info.gas_cmd, info.cmd_str, position); } @@ -1166,8 +1158,8 @@ fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Optio let opt_abi = abi_from_matches_or_config(matches, config); let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) .or_else(|| - if opt_abi.is_ok() { - load_debug_info(opt_abi.as_ref().unwrap()) + if let Ok(opt_abi) = &opt_abi { + load_debug_info(opt_abi) } else { None } @@ -1197,7 +1189,7 @@ fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Optio }) }, _ => { - Some(if config.debug_fail == *"Full" { + Some(if &config.debug_fail == "Full" { Arc::new(move |_, info| trace_callback(info, &None)) } else { Arc::new(move |_, info| trace_callback_minimal(info, &None)) @@ -1299,14 +1291,14 @@ async fn fetch_transactions(config: &Config, addresses: &Vec) -> Result< for txn in &transactions.result { let boc = txn["boc"].as_str().unwrap(); - let id = txn["id"].as_str().unwrap(); + let id = txn["id"].as_str().unwrap().to_owned(); let workchain_id = txn["workchain_id"].as_i64().unwrap(); - let txn = Transaction::construct_from_base64(boc) + let tr = Transaction::construct_from_base64(boc) .map_err(|e| format!("Failed to deserialize txn: {}", e))?; txns.push(TransactionExt { - id: id.to_owned(), - address: format!("{}:{}", workchain_id, txn.account_id().to_hex_string()), - tr: txn, + id, + address: format!("{}:{:x}", workchain_id, tr.account_id()), + tr, }); } @@ -1314,7 +1306,7 @@ async fn fetch_transactions(config: &Config, addresses: &Vec) -> Result< lt = last["lt"].as_str().ok_or_else(|| "Failed to parse value".to_string())?.to_owned(); } } - txns.sort_by(|tr1, tr2| tr1.tr.logical_time().partial_cmp(&tr2.tr.logical_time()).unwrap()); + txns.sort_by(|tr1, tr2| tr1.tr.logical_time().cmp(&tr2.tr.logical_time())); Ok(txns) } @@ -1330,16 +1322,12 @@ fn map_inbound_messages_onto_tr(txns: &Vec) -> HashMap) -> Result, String> { let mut messages = vec!(); tr.iterate_out_msgs(|msg| { - let hash = msg.serialize().unwrap().repr_hash(); - let lt = if let Some(tr) = map.get(&hash) { - tr.logical_time() - } else { - u64::MAX - }; + let hash = msg.serialize()?.repr_hash(); + let lt = map.get(&hash).map_or(u64::MAX, |tr| tr.logical_time()); messages.push((lt, msg)); Ok(true) }).unwrap(); - messages.sort_by(|(lt1, _), (lt2, _)| lt2.partial_cmp(lt1).unwrap()); + messages.sort_by(|(lt1, _), (lt2, _)| lt2.cmp(lt1)); Ok(messages.iter().map(|(_, v)| v.clone()).collect()) } diff --git a/src/depool.rs b/src/depool.rs index 6f9ba45b..c4100a88 100644 --- a/src/depool.rs +++ b/src/depool.rs @@ -460,7 +460,7 @@ async fn wait_for_event(config: &Config, depool: &str) -> Result<(), String> { ton.clone(), ParamsOfWaitForCollection { collection: "messages".to_owned(), - filter: Some(events_filter(depool, now()?)), + filter: Some(events_filter(depool, now())), result: "id body created_at created_at_string".to_owned(), timeout: Some(config.timeout), ..Default::default() @@ -825,7 +825,7 @@ async fn call_contract_and_get_answer( ) -> Result<(), String> { let ton = create_client_verbose(config)?; let abi = load_abi(MSIG_ABI, config).await?; - let start = now()?; + let start = now(); let params = json!({ "dest": dest_addr, diff --git a/src/getconfig.rs b/src/getconfig.rs index e7769bf3..10f15e70 100644 --- a/src/getconfig.rs +++ b/src/getconfig.rs @@ -14,7 +14,7 @@ use ed25519_dalek::{Keypair, PublicKey, SecretKey, Signer}; use num_bigint::BigUint; use crate::config::Config; -use crate::helpers::{create_client_verbose, query_with_limit, now}; +use crate::helpers::{create_client_verbose, query_with_limit, now, now_ms}; use serde_json::json; use ton_abi::{Contract, Token, TokenValue, Uint}; use ton_block::{ExternalInboundMessageHeader, Grams, Message, MsgAddressInt, Serializable}; @@ -409,7 +409,7 @@ fn prepare_message_new_config_param( private_key_of_config_account: &[u8] ) -> Result { let prefix = hex::decode(PREFIX_UPDATE_CONFIG_MESSAGE_DATA).unwrap(); - let since_the_epoch = now()? + 100; // timestamp + 100 secs + let since_the_epoch = now() + 100; // timestamp + 100 secs let mut cell = BuilderData::default(); cell.append_raw(prefix.as_slice(), 32).unwrap(); @@ -455,7 +455,7 @@ fn prepare_message_new_config_param_solidity( let keypair = Keypair { secret, public }; let config_contract_address = MsgAddressInt::with_standart(None, -1, config_account).unwrap(); - let since_the_epoch = now()? as u64 * 1000; + let since_the_epoch = now_ms(); let header = [("time".to_owned(), TokenValue::Time(since_the_epoch))] .into_iter() diff --git a/src/helpers.rs b/src/helpers.rs index fa98abe1..1a4e2670 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -101,16 +101,15 @@ pub fn load_ton_address(addr: &str, config: &Config) -> Result { Ok(addr) } -pub fn now() -> Result { - Ok(SystemTime::now() - .duration_since(SystemTime::UNIX_EPOCH) - .map_err(|e| format!("failed to obtain system time: {}", e))? - .as_secs() as u32 - ) +pub fn now() -> u32 { + (now_ms() / 1000) as u32 } pub fn now_ms() -> u64 { - chrono::prelude::Utc::now().timestamp_millis() as u64 + SystemTime::now() + .duration_since(SystemTime::UNIX_EPOCH) + .unwrap_or_else(|e| panic!("failed to obtain system time: {}", e)) + .as_millis() as u64 } pub type TonClient = Arc; diff --git a/src/message.rs b/src/message.rs index e372f2d7..2270a5df 100644 --- a/src/message.rs +++ b/src/message.rs @@ -84,8 +84,8 @@ pub fn prepare_message_params ( } pub fn print_encoded_message(msg: &EncodedMessage, is_json:bool) { - let expire = if msg.expire.is_some() { - let expire_at = Local.timestamp_opt(msg.expire.unwrap() as i64, 0).single().unwrap(); + let expire = if let Some(expire) = msg.expire { + let expire_at = Local.timestamp(expire as i64, 0); expire_at.to_rfc2822() } else { "unknown".to_string() @@ -170,7 +170,7 @@ pub async fn generate_message( let abi = load_abi(abi, config).await?; - let expire_at = lifetime + timestamp.map(|millis| (millis / 1000) as u32).unwrap_or(now()?); + let expire_at = lifetime + timestamp.map_or_else(|| now(), |millis| (millis / 1000) as u32); let header = FunctionHeader { expire: Some(expire_at), time: timestamp, diff --git a/src/run.rs b/src/run.rs index 524e38a0..c967d6a7 100644 --- a/src/run.rs +++ b/src/run.rs @@ -115,7 +115,7 @@ async fn run( let params = Some(load_params(params.unwrap().as_ref())?); - let now = now()?; + let now = now(); let expire_at = config.lifetime + now; let header = FunctionHeader { expire: Some(expire_at), diff --git a/tests/test_cli.rs b/tests/test_cli.rs index 892f0380..924dd8d2 100644 --- a/tests/test_cli.rs +++ b/tests/test_cli.rs @@ -22,10 +22,6 @@ const SAFEMSIG_ADDR: &str = "0:d5f5cfc4b52d2eb1bd9d3a8e51707872c7ce0c174facddd0e const SAFEMSIG_CONSTR_ARG: &str = r#"{"owners":["0xc8bd66f90d61f7e1e1a6151a0dbe9d8640666920d8c0cf399cbfb72e089d2e41"],"reqConfirms":1}"#; const SAVED_CONFIG: &str = "tests/config_contract.saved"; -fn now_ms() -> u64 { - chrono::prelude::Utc::now().timestamp_millis() as u64 -} - fn generate_public_key(seed: &str) -> Result> { let mut cmd = Command::cargo_bin(BIN_NAME)?; let out = cmd.arg("genpubkey") From 5f6c0337d62ea9342a1bd96716bb60418b9e5d47 Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Sat, 11 Mar 2023 23:30:06 +0300 Subject: [PATCH 7/9] refactoring --- src/account.rs | 31 +++--- src/call.rs | 34 +++--- src/debug.rs | 261 ++++++++++++++++++++++++++--------------------- src/decode.rs | 48 +++++---- src/deploy.rs | 36 +++---- src/depool.rs | 10 +- src/getconfig.rs | 13 +-- src/helpers.rs | 119 +++++++++------------ src/main.rs | 100 ++++++++---------- src/message.rs | 17 +-- src/multisig.rs | 46 +++++---- src/replay.rs | 81 +++++++-------- src/run.rs | 88 ++++++++-------- src/voting.rs | 30 +++--- 14 files changed, 459 insertions(+), 455 deletions(-) diff --git a/src/account.rs b/src/account.rs index 4a14843a..6ff4d60d 100644 --- a/src/account.rs +++ b/src/account.rs @@ -33,7 +33,7 @@ const ACCOUNT_FIELDS: &str = r#" const DEFAULT_PATH: &str = "."; -async fn query_accounts(config: &Config, addresses: Vec, fields: &str) -> Result, String> { +fn query_accounts(config: &Config, addresses: Vec, fields: &str) -> Result, String> { let ton = create_client_verbose(config)?; if !config.is_json { @@ -55,16 +55,17 @@ async fn query_accounts(config: &Config, addresses: Vec, fields: &str) - }); } it += cnt; - let mut query_result = query_collection( - ton.clone(), - ParamsOfQueryCollection { - collection: "accounts".to_owned(), - filter: Some(filter), - result: fields.to_string(), - limit: Some(cnt as u32), - ..Default::default() - }, - ).await.map_err(|e| format!("failed to query account info: {}", e))?; + let context = ton.clone(); + let params = ParamsOfQueryCollection { + collection: "accounts".to_owned(), + filter: Some(filter), + result: fields.to_string(), + limit: Some(cnt as u32), + ..Default::default() + }; + let mut query_result = crate::RUNTIME.block_on(async move { + query_collection(context, params).await + }).map_err(|e| format!("failed to query account info: {}", e))?; res.append(query_result.result.as_mut()); } Ok(res) @@ -86,7 +87,7 @@ pub async fn get_account(config: &Config, addresses: Vec, dumptvc: Optio } return Ok(()); } - let accounts = query_accounts(config, addresses.clone(), ACCOUNT_FIELDS).await?; + let accounts = query_accounts(config, addresses.clone(), ACCOUNT_FIELDS)?; if !config.is_json { println!("Succeeded."); } @@ -238,7 +239,7 @@ pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<() ton.clone(), addr, "boc", - ).await?; + )?; let res = calc_storage_fee( ton.clone(), @@ -261,7 +262,7 @@ pub async fn calc_storage(config: &Config, addr: &str, period: u32) -> Result<() } pub async fn dump_accounts(config: &Config, addresses: Vec, path: Option<&str>) -> Result<(), String> { - let accounts = query_accounts(config, addresses.clone(), "id boc").await?; + let accounts = query_accounts(config, addresses.clone(), "id boc")?; let mut addresses = addresses.clone(); check_dir(path.unwrap_or(""))?; for account in accounts.iter() { @@ -306,7 +307,7 @@ fn extract_last_trans_lt(v: &serde_json::Value) -> Option<&str> { pub async fn wait_for_change(config: &Config, account_address: &str, wait_secs: u64) -> Result<(), String> { let context = create_client_verbose(config)?; - let query = ton_client::net::query_collection( + let query = query_collection( context.clone(), ParamsOfQueryCollection { collection: "accounts".to_owned(), diff --git a/src/call.rs b/src/call.rs index d2aa3157..d51c7591 100644 --- a/src/call.rs +++ b/src/call.rs @@ -31,7 +31,6 @@ use ton_client::tvm::{ AccountForExecutor }; use ton_block::{Account, Serializable, Deserializable, Message}; -use std::str::FromStr; use serde_json::{json, Value}; use ton_abi::ParamType; use ton_client::error::ClientError; @@ -68,8 +67,10 @@ fn parse_integer_param(value: &str) -> Result { } } -async fn build_json_from_params(params_vec: Vec<&str>, abi_path: &str, method: &str, config: &Config) -> Result { - let abi_obj = load_ton_abi(abi_path, config).await?; +fn build_json_from_params(params_vec: Vec<&str>, abi_path: &str, method: &str, config: &Config) -> Result { + let abi_obj = crate::RUNTIME.block_on(async move { + load_ton_abi(abi_path, config).await + })?; let functions = abi_obj.functions(); let func_obj = functions.get(method).ok_or("failed to load function from abi")?; @@ -115,11 +116,10 @@ pub async fn emulate_locally( is_fee: bool, ) -> Result<(), String> { let state: String; - let state_boc = query_account_field(ton.clone(), addr, "boc").await; + let state_boc = query_account_field(ton.clone(), addr, "boc"); if state_boc.is_err() { if is_fee { - let addr = ton_block::MsgAddressInt::from_str(addr) - .map_err(|e| format!("couldn't decode address: {}", e))?; + let addr = addr.parse().map_err(|e| format!("couldn't decode address: {}", e))?; state = base64::encode( ton_types::cells_serialization::serialize_toc( &Account::with_address(addr) @@ -248,7 +248,7 @@ pub async fn process_message( Ok(res.decoded.and_then(|d| d.output).unwrap_or(json!({}))) } -pub async fn call_contract_with_result( +pub fn call_contract_with_result( config: &Config, addr: &str, abi_path: &str, @@ -267,7 +267,9 @@ pub async fn call_contract_with_result( } else { create_client_verbose(config)? }; - call_contract_with_client(ton, config, addr, abi_path, method, params, keys, is_fee).await + crate::RUNTIME.block_on(async move { + call_contract_with_client(ton, config, addr, abi_path, method, params, keys, is_fee).await + }) } pub async fn call_contract_with_client( @@ -320,14 +322,14 @@ pub async fn call_contract_with_client( ton.clone(), addr, "boc", - ).await?; + )?; let account = Account::construct_from_base64(&acc_boc) .map_err(|e| format!("Failed to construct account: {}", e))? .serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; let now = now_ms(); - Some((account, message.unwrap(), now, get_blockchain_config(config, None).await?)) + Some((account, message.unwrap(), now, get_blockchain_config(config, None)?)) } else { None }; @@ -350,14 +352,14 @@ pub async fn call_contract_with_client( let (mut account, message, now, bc_config) = dump.unwrap(); let message = Message::construct_from_base64(&message) .map_err(|e| format!("failed to construct message: {}", e))?; - let _ = execute_debug(bc_config, &mut account, Some(&message), (now / 1000) as u32, now,now, false, config).await?; + let _ = execute_debug(bc_config, &mut account, Some(&message), (now / 1000) as u32, now,now, false, config)?; if !config.is_json { let log_path = format!("call_{}_{}.log", addr, method); println!("Debug finished."); println!("Log saved to {}", log_path); } - return Err("".to_string()); + return Err(String::new()); } res.map_err(|e| format!("{:#}", e)) } @@ -375,7 +377,7 @@ pub fn print_json_result(result: Value, config: &Config) -> Result<(), String> { Ok(()) } -pub async fn call_contract( +pub fn call_contract( config: &Config, addr: &str, abi_path: &str, @@ -384,7 +386,7 @@ pub async fn call_contract( keys: Option, is_fee: bool, ) -> Result<(), String> { - let result = call_contract_with_result(config, addr, abi_path, method, params, keys, is_fee).await?; + let result = call_contract_with_result(config, addr, abi_path, method, params, keys, is_fee)?; if !config.is_json { println!("Succeeded."); } @@ -426,11 +428,11 @@ pub async fn call_contract_with_msg(config: &Config, str_msg: String, abi_path: Ok(()) } -pub async fn parse_params(params_vec: Vec<&str>, abi_path: &str, method: &str, config: &Config) -> Result { +pub fn parse_params(params_vec: Vec<&str>, abi_path: &str, method: &str, config: &Config) -> Result { if params_vec.len() == 1 { // if there is only 1 parameter it must be a json string with arguments Ok(params_vec[0].to_owned()) } else { - build_json_from_params(params_vec, abi_path, method, config).await + build_json_from_params(params_vec, abi_path, method, config) } } diff --git a/src/debug.rs b/src/debug.rs index 0b09ba32..b7fbd52f 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -17,12 +17,13 @@ use crate::config::Config; use crate::helpers::{load_ton_address, create_client, load_abi, now_ms, construct_account_from_tvc, query_account_field, query_with_limit, create_client_verbose, abi_from_matches_or_config, load_debug_info, wc_from_matches_or_config, - TEST_MAX_LEVEL, MAX_LEVEL, get_blockchain_config}; + TEST_MAX_LEVEL, MAX_LEVEL, get_blockchain_config, create_client_local}; use crate::replay::{ fetch, CONFIG_ADDR, replay, DUMP_NONE, DUMP_CONFIG, DUMP_ACCOUNT }; use std::io::{Write, BufRead}; use std::collections::{HashSet, HashMap}; +use std::path::Path; use ton_block::{Message, Account, Serializable, Deserializable, OutMessages, Transaction, MsgAddressInt, CurrencyCollection, GasLimitsPrices, ConfigParamEnum}; use ton_types::{UInt256, HashmapE, Cell, AccountId}; @@ -167,6 +168,23 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .conflicts_with("TVC") .help("Flag that changes behavior of the command to work with the saved account state (account BOC)."); + let tvc_arg = Arg::with_name("TVC") + .long("--tvc") + .conflicts_with("BOC") + .help("Flag that changes behavior of the command to work with the saved contract state (stateInit TVC)."); + + let balance = Arg::with_name("BALANCE") + .long("--balance") + .requires("TVC") + .conflicts_with("BOC") + .help("balance for account constructed from TVC file"); + + let account_address = Arg::with_name("ACCOUNT_ADDRESS") + .long("--tvc_address") + .takes_value(true) + .requires("TVC") + .help("Account address for account constructed from TVC."); + let tx_id_arg = Arg::with_name("TX_ID") .required(true) .takes_value(true) @@ -209,7 +227,7 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { let update_arg = Arg::with_name("UPDATE_BOC") .long("--update") .short("-u") - .requires("BOC") + .required_unless_one(&["BOC", "TVC"]) .help("Update contract BOC after execution"); let now_arg = Arg::with_name("NOW") @@ -219,12 +237,14 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { let msg_cmd = SubCommand::with_name("message") .about("Play message locally with trace") + .alias("m") .arg(output_arg.clone()) .arg(dbg_info_arg.clone()) .arg(address_arg.clone()) .arg(full_trace_arg.clone()) .arg(decode_abi_arg.clone()) .arg(boc_arg.clone()) + .arg(tvc_arg.clone()) .arg(config_path_arg.clone()) .arg(update_arg.clone()) .arg(now_arg.clone()) @@ -245,15 +265,10 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .arg(full_trace_arg.clone()) .arg(decode_abi_arg.clone()) .arg(boc_arg.clone()) - .arg(Arg::with_name("TVC") - .long("--tvc") - .conflicts_with("BOC") - .help("Flag that changes behavior of the command to work with the saved contract state (stateInit TVC).")) - .arg(Arg::with_name("ACCOUNT_ADDRESS") - .takes_value(true) - .long("--tvc_address") - .help("Account address for account constructed from TVC.") - .requires("TVC")) + .arg(tvc_arg.clone()) + .arg(update_arg.clone()) + .arg(balance.clone()) + .arg(account_address.clone()) .arg(now_arg.clone()) .arg(config_path_arg.clone()); @@ -293,6 +308,7 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { SubCommand::with_name("debug") .about("Debug commands.") + .alias("d") .subcommand(SubCommand::with_name("transaction") .about("Replay transaction with specified ID.") .arg(default_config_arg.clone()) @@ -349,38 +365,36 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { } pub fn debug_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { - crate::RUNTIME.block_on(async move { let config = &full_config.config; if let Some(matches) = matches.subcommand_matches("transaction") { - return debug_transaction_command(matches, config, false).await; + return debug_transaction_command(matches, config, false); } if let Some(matches) = matches.subcommand_matches("account") { - return debug_transaction_command(matches, config, true).await; + return debug_transaction_command(matches, config, true); } if let Some(matches) = matches.subcommand_matches("call") { - return debug_call_command(matches, full_config, false).await; + return debug_call_command(matches, full_config, false); } if let Some(matches) = matches.subcommand_matches("run") { - return debug_call_command(matches, full_config, true).await; + return debug_call_command(matches, full_config, true); } if let Some(matches) = matches.subcommand_matches("message") { - return debug_message_command(matches, config).await; + return debug_message_command(matches, config); } if let Some(matches) = matches.subcommand_matches("replay") { - return replay_transaction_command(matches, config).await; + return replay_transaction_command(matches, config); } if let Some(matches) = matches.subcommand_matches("deploy") { - return debug_deploy_command(matches, config).await; + return debug_deploy_command(matches, config); } if let Some(matches) = matches.subcommand_matches("sequence-diagram") { - return sequence_diagram_command(matches, config).await; + return sequence_diagram_command(matches, config); } Err("unknown command".to_owned()) - }) } -async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is_account: bool) -> Result<(), String> { - let trace_path = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); +fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is_account: bool) -> Result<(), String> { + let trace_path = matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH); let config_path = matches.value_of("CONFIG_PATH"); let contract_path = matches.value_of("CONTRACT_PATH"); let is_default_config = matches.is_present("DEFAULT_CONFIG"); @@ -388,9 +402,9 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is let (tx_id, address) = if !is_account { let tx_id = matches.value_of("TX_ID"); if !config.is_json { - print_args!(tx_id, trace_path, config_path, contract_path); + print_args!(tx_id, Some(trace_path), config_path, contract_path); } - let address = query_address(tx_id.unwrap(), config).await?; + let address = query_address(tx_id.unwrap(), config)?; (tx_id.unwrap().to_string(), address) } else { let address = @@ -400,14 +414,15 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is .ok_or("ADDRESS is not defined. Supply it in the config file or command line." .to_string())?); if !config.is_json { - print_args!(address, trace_path, config_path, contract_path); + print_args!(address, Some(trace_path), config_path, contract_path); } let address = address.unwrap(); - let transactions = query_transactions(&address, config).await?; + let transactions = query_transactions(&address, config)?; let tr_id = choose_transaction(transactions)?; (tr_id, address) }; +crate::RUNTIME.block_on(async move { let config_path = if is_default_config || config_boc.is_some() { "" } else { @@ -437,11 +452,10 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is } }; - let trace_path = trace_path.unwrap().to_string(); let init_logger = || { log::set_max_level(log::LevelFilter::Trace); log::set_boxed_logger( - Box::new(DebugLogger::new(trace_path.clone())) + Box::new(DebugLogger::new(trace_path.to_string())) ).map_err(|e| format!("Failed to set logger: {}", e))?; Ok(()) }; @@ -458,7 +472,7 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is } let blockchain_config = if is_default_config || config_boc.is_some() { - let bc_config = get_blockchain_config(config, config_boc).await?; + let bc_config = get_blockchain_config(config, config_boc)?; Some(bc_config) } else { None @@ -475,16 +489,17 @@ async fn debug_transaction_command(matches: &ArgMatches<'_>, config: &Config, is blockchain_config ).await?; - decode_messages(tr.out_msgs, load_decode_abi(matches, config), config).await?; + decode_messages(tr.out_msgs, decode_abi_path(matches, config), config).await?; if !config.is_json { println!("Log saved to {}.", trace_path); } else { println!("{{}}"); } Ok(()) + }) } -async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let tx_id = matches.value_of("TX_ID"); let config_path = matches.value_of("CONFIG_PATH"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); @@ -494,8 +509,10 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - if !config.is_json { print_args!(input, tx_id, output, config_path); } - + let bc_config = get_blockchain_config(config, config_path)?; let ton_client = create_client(config)?; + +crate::RUNTIME.block_on(async move { let trans = query_collection( ton_client.clone(), ParamsOfQueryCollection { @@ -542,7 +559,7 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - ).map_err(|e| format!("Failed to set logger: {}", e))?; let result_trans = execute_debug( - get_blockchain_config(config, config_path).await?, + bc_config, &mut account, msg.as_ref(), trans.now(), @@ -550,12 +567,12 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - trans.logical_time(), false, config - ).await; + ); if do_update && result_trans.is_ok() { Account::construct_from_cell(account.clone()) .map_err(|e| format!("Failed to construct account: {}", e))? - .write_to_file(input.unwrap()) + .write_to_file(Path::new(input.unwrap()).with_extension("boc")) .map_err(|e| format!("Failed to save account state: {}", e))?; if !config.is_json { println!("Contract state was updated."); @@ -564,7 +581,7 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - match result_trans { Ok(result_trans) => { - decode_messages(result_trans.out_msgs,load_decode_abi(matches, config), config).await?; + decode_messages(result_trans.out_msgs, decode_abi_path(matches, config), config).await?; if !config.is_json { println!("Execution finished."); } @@ -579,6 +596,7 @@ async fn replay_transaction_command(matches: &ArgMatches<'_>, config: &Config) - println!("Log saved to {}", output.unwrap()); } Ok(()) +}) } fn parse_now(matches: &ArgMatches<'_>) -> Result { @@ -589,56 +607,48 @@ fn parse_now(matches: &ArgMatches<'_>) -> Result { }) } -fn load_decode_abi(matches: &ArgMatches<'_>, config: &Config) -> Option { - let abi = matches.value_of("DECODE_ABI") +fn decode_abi_path(matches: &ArgMatches<'_>, config: &Config) -> Option { + matches.value_of("DECODE_ABI") .map(|s| s.to_owned()) - .or_else(|| abi_from_matches_or_config(matches, config).ok()); - match abi { - Some(path) => match std::fs::read_to_string(path) { - Ok(res) => Some(res), - Err(e) => { - if !config.is_json { - println!("Failed to read abi: {}", e); - } - None - } - } - _ => None - } + .or_else(|| abi_from_matches_or_config(matches, config).ok()) } -async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_getter: bool) -> Result<(), String> { +fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_getter: bool) -> Result<(), String> { let (input, opt_abi, sign) = contract_data_from_matches_or_config_alias(matches, full_config)?; - let input = input.as_ref(); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); let method = Some(matches.value_of("METHOD").or(full_config.config.method.as_deref()) .ok_or("Method is not defined. Supply it in the config file or command line.")?); let is_boc = matches.is_present("BOC"); let is_tvc = matches.is_present("TVC"); - let loaded_abi = load_abi(opt_abi.as_ref().unwrap(), &full_config.config).await?; let params = unpack_alternative_params( matches, opt_abi.as_ref().unwrap(), method.unwrap(), &full_config.config - ).await?; + )?; if !full_config.config.is_json { print_args!(input, method, params, sign, opt_abi, output); } - let ton_client = create_client(&full_config.config)?; // TODO: create local for boc and tvc + let ton_client = if is_boc || is_tvc { + create_client_local()? + } else { + create_client(&full_config.config)? + }; let input = input.unwrap(); let mut account = if is_tvc { - construct_account_from_tvc(input, - matches.value_of("ACCOUNT_ADDRESS"), - Some(u64::MAX))? + construct_account_from_tvc( + &input, + matches.value_of("ACCOUNT_ADDRESS"), + matches.value_of("BALANCE").map_or(u64::MAX, |f| f.parse().unwrap()) + )? } else if is_boc { - Account::construct_from_file(input) + Account::construct_from_file(&input) .map_err(|e| format!(" failed to load account from the file {}: {}", input, e))? } else { - let address = load_ton_address(input, &full_config.config)?; - let account = query_account_field(ton_client.clone(), &address, "boc").await?; + let address = load_ton_address(&input, &full_config.config)?; + let account = query_account_field(ton_client.clone(), &address, "boc")?; Account::construct_from_base64(&account) .map_err(|e| format!("Failed to construct account: {}", e))? }; @@ -655,20 +665,24 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, time: Some(now), ..Default::default() }; - let call_set = CallSet { + let call_set = Some(CallSet { function_name: method.unwrap().to_string(), input: Some(params), header: Some(header) + }); + let bc_config = get_blockchain_config(&full_config.config, matches.value_of("CONFIG_PATH"))?; +crate::RUNTIME.block_on(async move { + let abi = load_abi(opt_abi.as_ref().unwrap(), &full_config.config).await?; + let signer = if let Some(keys) = keys { + Signer::Keys { keys } + } else { + Signer::None }; let msg_params = ParamsOfEncodeMessage { - abi: loaded_abi, + abi, address: Some(format!("0:{}", "0".repeat(64))), // TODO: add option or get from input - call_set: Some(call_set), - signer: if keys.is_some() { - Signer::Keys { keys: keys.unwrap() } - } else { - Signer::None - }, + call_set, + signer, ..Default::default() }; @@ -695,7 +709,7 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, ).map_err(|e| format!("Failed to set logger: {}", e))?; let trans = execute_debug( - get_blockchain_config(&full_config.config, matches.value_of("CONFIG_PATH")).await?, + bc_config, &mut acc_root, Some(&message), (now / 1000) as u32, @@ -703,12 +717,12 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, now, is_getter, &full_config.config, - ).await; + ); let mut out_res = vec![]; let msg_string = match trans { Ok(trans) => { - out_res = decode_messages(trans.out_msgs,load_decode_abi(matches, &full_config.config), &full_config.config).await?; + out_res = decode_messages(trans.out_msgs, decode_abi_path(matches, &full_config.config), &full_config.config).await?; "Execution finished.".to_string() } Err(e) => { @@ -725,7 +739,7 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, if matches.is_present("UPDATE_BOC") { Account::construct_from_cell(acc_root) .map_err(|e| format!("Failed to construct account: {}", e))? - .write_to_file(input) + .write_to_file(Path::new(&input).with_extension("boc")) .map_err(|e| format!("Failed to dump account: {}", e))?; if !full_config.config.is_json { println!("{} successfully updated", input); @@ -750,13 +764,15 @@ async fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, println!("{{}}"); } Ok(()) +}) } -async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let input = matches.value_of("ADDRESS"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()); let is_boc = matches.is_present("BOC"); + let is_tvc = matches.is_present("TVC"); let message = matches.value_of("MESSAGE"); if !config.is_json { print_args!(input, message, output, debug_info); @@ -764,12 +780,18 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res let ton_client = create_client(config)?; let input = input.unwrap(); - let account = if is_boc { + let account = if is_tvc { + construct_account_from_tvc( + &input, + matches.value_of("ACCOUNT_ADDRESS"), + matches.value_of("BALANCE").map_or(u64::MAX, |f| f.parse().unwrap()) + )? + } else if is_boc { Account::construct_from_file(input) .map_err(|e| format!(" failed to load account from the file {}: {}", input, e))? } else { let address = load_ton_address(input, config)?; - let account = query_account_field(ton_client.clone(), &address, "boc").await?; + let account = query_account_field(ton_client.clone(), &address, "boc")?; Account::construct_from_base64(&account) .map_err(|e| format!("Failed to construct account: {}", e))? }; @@ -790,9 +812,11 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res Box::new(DebugLogger::new(trace_path.clone())) ).map_err(|e| format!("Failed to set logger: {}", e))?; + let bc_config = get_blockchain_config(config, matches.value_of("CONFIG_PATH"))?; +crate::RUNTIME.block_on(async move { let now = parse_now(matches)?; let trans = execute_debug( - get_blockchain_config(config, matches.value_of("CONFIG_PATH")).await?, + bc_config, &mut acc_root, Some(&message), (now / 1000) as u32, @@ -800,11 +824,11 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res now, false, config - ).await; + ); let msg_string = match trans { Ok(trans) => { - decode_messages(trans.out_msgs,load_decode_abi(matches, config), config).await?; + decode_messages(trans.out_msgs, decode_abi_path(matches, config), config).await?; "Execution finished.".to_string() } Err(e) => { @@ -815,7 +839,7 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res if matches.is_present("UPDATE_BOC") { Account::construct_from_cell(acc_root) .map_err(|e| format!("Failed to construct account: {}", e))? - .write_to_file(input) + .write_to_file(Path::new(input).with_extension("boc")) .map_err(|e| format!("Failed to dump account: {}", e))?; if !config.is_json { println!("{} successfully updated", input); @@ -829,31 +853,33 @@ async fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Res println!("{{}}"); } Ok(()) +}) } -async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let tvc = matches.value_of("TVC"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); - let opt_abi = Some(abi_from_matches_or_config(matches, config)?); + let abi_path = abi_from_matches_or_config(matches, config)?; let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) - .or_else(|| load_debug_info(opt_abi.as_ref().unwrap())); + .or_else(|| load_debug_info(&abi_path)); let sign = matches.value_of("KEYS") .map(|s| s.to_string()) .or_else(|| config.keys_path.clone()); let params = unpack_alternative_params( matches, - opt_abi.as_ref().unwrap(), + &abi_path, "constructor", config - ).await?; + )?; let wc = Some(wc_from_matches_or_config(matches, config)?); if !config.is_json { - print_args!(tvc, params, sign, opt_abi, output, debug_info); + print_args!(tvc, params, sign, Some(&abi_path), output, debug_info); } +crate::RUNTIME.block_on(async move { let (msg, address) = prepare_deploy_message( tvc.unwrap(), - opt_abi.as_ref().unwrap(), + &abi_path, params.as_ref().unwrap(), sign, wc.unwrap(), @@ -879,7 +905,7 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu ton_client.clone(), &address, "boc" - ).await?; + )?; Account::construct_from_base64(&account) .map_err(|e| format!("Failed to construct account: {}", e))? }; @@ -899,8 +925,9 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu let now = parse_now(matches)?; + let bc_config = get_blockchain_config(config, matches.value_of("CONFIG_PATH"))?; let trans = execute_debug( - get_blockchain_config(config, matches.value_of("CONFIG_PATH")).await?, + bc_config, &mut acc_root, Some(&message), (now / 1000) as u32, @@ -908,11 +935,11 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu now, false, config, - ).await; + ); let msg_string = match trans { Ok(trans) => { - decode_messages(trans.out_msgs,load_decode_abi(matches, config), config).await?; + decode_messages(trans.out_msgs, decode_abi_path(matches, config), config).await?; "Execution finished.".to_string() } Err(e) => { @@ -925,11 +952,11 @@ async fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Resu } else { println!("{{}}"); } - Ok(()) +}) } -async fn decode_messages(msgs: OutMessages, abi: Option, config: &Config) -> Result, String> { +async fn decode_messages(msgs: OutMessages, abi_path: Option, config: &Config) -> Result, String> { if !msgs.is_empty() { log::debug!(target: "executor", "Output messages:\n----------------"); } @@ -938,7 +965,7 @@ async fn decode_messages(msgs: OutMessages, abi: Option, config: &Config let mut res = vec![]; for msg in msgs { - let mut ser_msg = serialize_msg(&msg.0, abi.clone(), config).await + let mut ser_msg = serialize_msg(&msg.0, abi_path.clone(), config).await .map_err(|e| format!("Failed to serialize message: {}", e))?; let bytes = msg.0.write_to_bytes().map_err(|e| format!("Failed to serialize out message: {}", e))?; let msg_str = base64::encode(bytes); @@ -952,7 +979,7 @@ async fn decode_messages(msgs: OutMessages, abi: Option, config: &Config Ok(res) } -async fn query_address(tr_id: &str, config: &Config) -> Result { +fn query_address(tr_id: &str, config: &Config) -> Result { let ton_client = create_client(config)?; let query_result = query_with_limit( ton_client, @@ -965,8 +992,7 @@ async fn query_address(tr_id: &str, config: &Config) -> Result { "account_addr", None, Some(1) - ).await - .map_err(|e| format!("Failed to query address: {}", e))?; + ).map_err(|e| format!("Failed to query address: {}", e))?; match query_result.len() { 0 => Err("Transaction was not found".to_string()), _ => Ok(query_result[0]["account_addr"] @@ -993,7 +1019,7 @@ impl fmt::Display for TrDetails { } } -async fn query_transactions(address: &str, config: &Config) -> Result, String> { +fn query_transactions(address: &str, config: &Config) -> Result, String> { let ton_client = create_client(config)?; let order = vec![OrderBy{ path: "lt".to_string(), direction: SortDirection::DESC }]; let query_result = query_with_limit( @@ -1007,8 +1033,7 @@ async fn query_transactions(address: &str, config: &Config) -> Result Err("Transaction list is empty.".to_string()), _ => { @@ -1040,7 +1065,7 @@ fn choose_transaction(transactions: Vec) -> Result { Ok(transactions[chosen-1].transaction_id.trim_start_matches(|c| c == '"').trim_end_matches(|c| c == '"').to_string()) } -pub async fn execute_debug( +pub fn execute_debug( bc_config: BlockchainConfig, account: &mut Cell, message: Option<&Message>, @@ -1093,7 +1118,7 @@ pub async fn execute_debug( message, account, params - ).map_err(|e| format!("Debug failed: {}", e)) + ).map_err(|e| format!("Debug failed: {:?}", e)) } fn trace_callback(info: &EngineTraceInfo, debug_info: &Option) { @@ -1155,27 +1180,27 @@ fn get_position(info: &EngineTraceInfo, debug_info: &Option) -> Option< fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Option> { match matches { Some(matches) => { - let opt_abi = abi_from_matches_or_config(matches, config); - let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) + let debug_info = matches.value_of("DBG_INFO") + .map(|s| s.to_string()) .or_else(|| - if let Ok(opt_abi) = &opt_abi { - load_debug_info(opt_abi) + if let Ok(abi_path) = abi_from_matches_or_config(matches, config) { + load_debug_info(&abi_path) } else { None } ); - let debug_info: Option = match debug_info { - Some(dbg_info) => { - match File::open(dbg_info.clone()) { + let debug_info = match debug_info { + Some(debug_info) => { + match File::open(&debug_info) { Ok(file ) => match serde_json::from_reader(file) { Ok(info) => Some(info), Err(e) => { - println!("Failed to serde debug info from file {}: {}", dbg_info,e); + println!("Failed to serde debug info from file {}: {}", debug_info, e); None }, }, Err(e) => { - println!("Failed to open file {}: {}", dbg_info, e); + println!("Failed to open file {}: {}", debug_info, e); None } } @@ -1202,7 +1227,7 @@ fn generate_callback(matches: Option<&ArgMatches<'_>>, config: &Config) -> Optio const RENDER_NONE: u8 = 0x00; const RENDER_GAS: u8 = 0x01; -pub async fn sequence_diagram_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { +pub fn sequence_diagram_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let filename = matches.value_of("ADDRESSES").unwrap(); let file = std::fs::File::open(filename) .map_err(|e| format!("Failed to open file: {}", e))?; @@ -1219,9 +1244,11 @@ pub async fn sequence_diagram_command(matches: &ArgMatches<'_>, config: &Config) } let mut output = std::fs::File::create(format!("{}.plantuml", filename)) .map_err(|e| format!("Failed to create file: {}", e))?; - make_sequence_diagram(config, addresses, RENDER_NONE, &mut output).await.map(|res| { - println!("{}", res); - }) + let res = crate::RUNTIME.block_on(async move { + make_sequence_diagram(config, addresses, RENDER_NONE, &mut output).await + })?; + println!("{}", res); + Ok(()) } fn infer_address_width(input: &[String], min_width: usize) -> Result { diff --git a/src/decode.rs b/src/decode.rs index 77696b99..e7bcdc79 100644 --- a/src/decode.rs +++ b/src/decode.rs @@ -64,6 +64,9 @@ pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> { .long("--base64") .help("Flag that changes behavior of the command to work with data in base64 (FLAG IS DEPRECATED)."))) .subcommand(tvc_cmd) + // .subcommand(SubCommand::with_name("config_param") + // .about("Top level command of config param decode commands.") + // ) .subcommand(SubCommand::with_name("account") .about("Top level command of account decode commands.") .subcommand(SubCommand::with_name("data") @@ -98,7 +101,7 @@ pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> { } pub fn decode_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - crate::RUNTIME.block_on(async move { + crate::RUNTIME.block_on(async move { if let Some(m) = m.subcommand_matches("body") { return decode_body_command(m, config); } @@ -231,9 +234,9 @@ pub async fn print_account_data(account: &Account, tvc_path: Option<&str>, confi async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let msg = m.value_of("MSG"); - let abi = Some(abi_from_matches_or_config(m, config)?); + let abi_path = Some(abi_from_matches_or_config(m, config)?); if !config.is_json { - print_args!(msg, abi); + print_args!(msg, abi_path); } if m.is_present("BASE64") && !config.is_json { println!("Flag --base64 is deprecated. Command can be used for base64 input without this flag.") @@ -242,14 +245,14 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( let decoded_message = if std::path::Path::new(input).exists() { let msg_bytes = std::fs::read(input) .map_err(|e| format!(" failed to read msg from file {input}: {}", e))?; - match decode_message(msg_bytes.clone(), abi.clone()).await { + match decode_message(msg_bytes.clone(), abi_path.clone()).await { Ok(result) => result, Err(e) => { let message_str = String::from_utf8(msg_bytes) .map_err(|_| format!("Failed to decode message from file: {e}"))?; let message_bytes = base64::decode(&message_str) .map_err(|e2| format!("Failed to decode message data: {e2}"))?; - decode_message(message_bytes, abi).await + decode_message(message_bytes, abi_path).await .map_err(|e2| format!("Failed to decode message from file: {e2}"))? } } @@ -257,18 +260,18 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( let base64_decode = base64::decode(input) .map_err(|e| format!("{e}")); let msg_decode = match base64_decode { - Ok(base64_decode) => decode_message(base64_decode, abi.clone()).await, + Ok(base64_decode) => decode_message(base64_decode, abi_path.clone()).await, Err(e) => Err(e) }; match msg_decode { Ok(result) => result, Err(e) => { let ton_client = create_client(config)?; - let query_boc = query_message(ton_client, input).await + let query_boc = query_message(ton_client, input) .map_err(|e2| format!("Failed to decode message, specify path to the file, message id or message in base64.\nBase64 error: {e}\nQuery error: {e2}"))?; let message_bytes = base64::decode(&query_boc) .map_err(|e2| format!("Failed to decode queried message: {e2}"))?; - decode_message(message_bytes, abi).await + decode_message(message_bytes, abi_path).await .map_err(|e2| format!("Failed to decode queried message: {e2}"))? } } @@ -279,11 +282,11 @@ async fn decode_message_command(m: &ArgMatches<'_>, config: &Config) -> Result<( async fn decode_tvc_fields(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let tvc = m.value_of("TVC"); - let abi = Some(abi_from_matches_or_config(m, config)?); + let abi_path = abi_from_matches_or_config(m, config)?; if !config.is_json { - print_args!(tvc, abi); + print_args!(tvc, Some(abi_path.to_string())); } - let abi = load_abi(abi.as_ref().unwrap(), config).await?; + let abi = load_abi(&abi_path, config).await?; let state = StateInit::construct_from_file(tvc.unwrap()) .map_err(|e| format!("failed to load StateInit from the tvc file: {}", e))?; let b64 = tree_of_cells_into_base64(state.data.as_ref())?; @@ -316,7 +319,7 @@ async fn decode_account_fields(m: &ArgMatches<'_>, config: &Config) -> Result<() let ton = create_client_verbose(config)?; let address = load_ton_address(address.unwrap(), config)?; - let data = query_account_field(ton.clone(), &address, "data").await?; + let data = query_account_field(ton.clone(), &address, "data")?; let res = decode_account_data( ton, @@ -452,7 +455,7 @@ async fn decode_tvc_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), S } else { format!("{}:{}", config.wc, input) }; - let boc = query_account_field(ton.clone(), &input, "boc").await?; + let boc = query_account_field(ton.clone(), &input, "boc")?; let account = Account::construct_from_base64(&boc) .map_err(|e| format!("Failed to query account BOC: {}", e))?; account.state_init().ok_or("Failed to load stateInit from the BOC.")?.to_owned() @@ -490,15 +493,11 @@ pub mod msg_printer { } async fn get_code_version(ton: TonClient, code: String) -> String { - let result = get_compiler_version( - ton, - ParamsOfGetCompilerVersion { - code, - ..Default::default() - } - ).await; - - if let Ok(result) = result { + let params = ParamsOfGetCompilerVersion { + code, + ..Default::default() + }; + if let Ok(result) = get_compiler_version(ton, params).await { if let Some(version) = result.version { return version; } @@ -623,10 +622,9 @@ pub mod msg_printer { res["Body"] = json!(&tree_of_cells_into_base64( msg.body().map(|slice| slice.into_cell()).as_ref() )?); - if abi_path.is_some() && msg.body().is_some() { - let abi_path = abi_path.unwrap(); + if let (Some(abi_path), Some(msg_body)) = (abi_path, msg.body()) { let mut body_vec = Vec::new(); - serialize_tree_of_cells(&msg.body().unwrap().into_cell(), &mut body_vec) + serialize_tree_of_cells(&msg_body.into_cell(), &mut body_vec) .map_err(|e| format!("failed to serialize body: {}", e))?; res["BodyCall"] = match serialize_body(body_vec, &abi_path, ton, config).await { Ok(res) => res, diff --git a/src/deploy.rs b/src/deploy.rs index 6e0e0de5..12f31d49 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -111,25 +111,24 @@ pub async fn generate_deploy_message( } pub async fn prepare_deploy_message( - tvc: &str, - abi: &str, + tvc_path: &str, + abi_path: &str, params: &str, keys_file: Option, wc: i32, config: &Config, ) -> Result<(ParamsOfEncodeMessage, String), String> { - let abi = load_abi(abi, config).await?; + let abi = load_abi(abi_path, config).await?; let keys = keys_file.map(|k| load_keypair(&k)).transpose()?; - let tvc_bytes = &std::fs::read(tvc) + let tvc_bytes = std::fs::read(tvc_path) .map_err(|e| format!("failed to read smart contract file: {}", e))?; - return prepare_deploy_message_params(tvc_bytes, abi, params, keys, wc).await; + return prepare_deploy_message_params(&tvc_bytes, abi, params, keys, wc).await; } - pub async fn prepare_deploy_message_params( tvc_bytes: &[u8], abi: Abi, @@ -137,7 +136,7 @@ pub async fn prepare_deploy_message_params( keys: Option, wc: i32 ) -> Result<(ParamsOfEncodeMessage, String), String> { - let tvc_base64 = base64::encode(tvc_bytes); + let tvc = base64::encode(tvc_bytes); let addr = calc_acc_address( tvc_bytes, @@ -147,24 +146,25 @@ pub async fn prepare_deploy_message_params( abi.clone() ).await?; - let dset = DeploySet { - tvc: tvc_base64, + let deploy_set = Some(DeploySet { + tvc, workchain_id: Some(wc), ..Default::default() - }; + }); let params = serde_json::from_str(params) .map_err(|e| format!("function arguments is not a json: {}", e))?; - + let call_set = CallSet::some_with_function_and_input("constructor", params); + let signer = if let Some(keys) = keys { + Signer::Keys{ keys } + } else { + Signer::None + }; Ok((ParamsOfEncodeMessage { abi, address: Some(addr.clone()), - deploy_set: Some(dset), - call_set: CallSet::some_with_function_and_input("constructor", params), - signer: if keys.is_some() { - Signer::Keys{ keys: keys.unwrap() } - } else { - Signer::None - }, + deploy_set, + call_set, + signer, ..Default::default() }, addr)) } diff --git a/src/depool.rs b/src/depool.rs index c4100a88..1c24d102 100644 --- a/src/depool.rs +++ b/src/depool.rs @@ -29,8 +29,8 @@ use clap::{App, ArgMatches, SubCommand, Arg, AppSettings}; use serde_json::json; use ton_client::abi::{ParamsOfEncodeMessageBody, CallSet, ParamsOfDecodeMessageBody}; -use ton_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection}; -use crate::call::{process_message}; +use ton_client::net::{OrderBy, ParamsOfQueryCollection, ParamsOfWaitForCollection, SortDirection, query_collection}; +use crate::call::process_message; use std::collections::HashMap; use crate::message::prepare_message_params; @@ -351,7 +351,7 @@ async fn answer_command(m: &ArgMatches<'_>, config: &Config, depool: &str) -> Re let wallet = load_ton_address(&wallet, config) .map_err(|e| format!("invalid depool address: {}", e))?; - let messages = ton_client::net::query_collection( + let messages = query_collection( ton.clone(), ParamsOfQueryCollection { collection: "messages".to_owned(), @@ -434,7 +434,7 @@ async fn get_events(config: &Config, depool: &str, since: u32) -> Result<(), Str let ton = create_client_verbose(config)?; let _addr = load_ton_address(depool, config)?; - let events = ton_client::net::query_collection( + let events = query_collection( ton.clone(), ParamsOfQueryCollection { collection: "messages".to_owned(), @@ -800,7 +800,7 @@ async fn call_contract( answer_is_expected: bool ) -> Result<(), String> { if config.no_answer { - send_with_body(config, wallet, depool, value, keys, body).await + send_with_body(config, wallet, depool, value, keys, body) } else { call_contract_and_get_answer( config, diff --git a/src/getconfig.rs b/src/getconfig.rs index 10f15e70..6ac11720 100644 --- a/src/getconfig.rs +++ b/src/getconfig.rs @@ -265,7 +265,7 @@ pub async fn query_global_config(config: &Config, index: Option<&str>) -> Result &result, Some(vec!(OrderBy{ path: "seq_no".to_string(), direction: SortDirection::DESC })), Some(1), - ).await { + ) { Ok(result) => Ok(result), Err(e) => { if e.message.contains("Server responded with code 400") { @@ -282,7 +282,7 @@ pub async fn query_global_config(config: &Config, index: Option<&str>) -> Result &result, Some(vec!(OrderBy{ path: "seq_no".to_string(), direction: SortDirection::DESC })), Some(1), - ).await.map_err(|e| format!("failed to query master block config: {}", e)) + ).map_err(|e| format!("failed to query master block config: {}", e)) } else { Err(format!("failed to query master block config: {}", e)) } @@ -489,7 +489,7 @@ fn convert_to_uint(value: &[u8], bits_count: usize) -> TokenValue { }) } -pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), String> { +pub fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), String> { let ton = create_client_verbose(config)?; let last_key_block_query = query_with_limit( @@ -499,7 +499,7 @@ pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), S "boc", Some(vec![OrderBy{ path: "seq_no".to_owned(), direction: SortDirection::DESC }]), Some(1), - ).await.map_err(|e| format!("failed to query last key block: {}", e))?; + ).map_err(|e| format!("failed to query last key block: {}", e))?; if last_key_block_query.is_empty() { return Err("Key block not found".to_string()); @@ -508,14 +508,14 @@ pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), S let block = last_key_block_query[0]["boc"].as_str() .ok_or("Failed to query last block BOC.")?.to_owned(); +crate::RUNTIME.block_on(async move { let bc_config = get_blockchain_config( ton.clone(), ParamsOfGetBlockchainConfig { block_boc: block, ..Default::default() }, - ).await - .map_err(|e| format!("Failed to get blockchain config: {}", e))?; + ).await.map_err(|e| format!("Failed to get blockchain config: {}", e))?; let bc_config = base64::decode(bc_config.config_boc) .map_err(|e| format!("Failed to decode BOC: {}", e))?; @@ -527,4 +527,5 @@ pub async fn dump_blockchain_config(config: &Config, path: &str) -> Result<(), S println!("{{}}"); } Ok(()) +}) } diff --git a/src/helpers.rs b/src/helpers.rs index 1a4e2670..db9f96c4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -201,8 +201,7 @@ pub async fn query_raw( limit: Option<&str>, order: Option<&str>, result: &str -) -> Result<(), String> -{ +) -> Result<(), String> { let context = create_client_verbose(config)?; let filter = filter.map(serde_json::from_str).transpose() @@ -212,23 +211,22 @@ pub async fn query_raw( let order = order.map(serde_json::from_str).transpose() .map_err(|e| format!("Failed to parse order field: {}", e))?; - let query = ton_client::net::query_collection( - context.clone(), - ParamsOfQueryCollection { - collection: collection.to_owned(), - filter, - limit, - order, - result: result.to_owned(), - ..Default::default() - } - ).await.map_err(|e| format!("Failed to execute query: {}", e))?; + let params = ParamsOfQueryCollection { + collection: collection.to_string(), + filter, + limit, + order, + result: result.to_string(), + ..Default::default() + }; + let query = query_collection(context, params).await + .map_err(|e| format!("Failed to execute query: {}", e))?; println!("{:#}", Value::Array(query.result)); Ok(()) } -pub async fn query_with_limit( +pub fn query_with_limit( ton: TonClient, collection: &str, filter: Value, @@ -236,22 +234,19 @@ pub async fn query_with_limit( order: Option>, limit: Option, ) -> Result, ClientError> { - query_collection( - ton, - ParamsOfQueryCollection { - collection: collection.to_owned(), - filter: Some(filter), - result: result.to_owned(), - order, - limit, - ..Default::default() - }, - ) - .await + let params = ParamsOfQueryCollection { + collection: collection.to_owned(), + filter: Some(filter), + result: result.to_owned(), + order, + limit, + ..Default::default() + }; + crate::RUNTIME.block_on(async move { query_collection(ton, params).await }) .map(|r| r.result) } -pub async fn query_message( +pub fn query_message( ton: TonClient, message_id: &str, ) -> Result { @@ -262,17 +257,15 @@ pub async fn query_message( "boc", None, Some(1), - ).await - .map_err(|e| format!("failed to query account data: {}", e))?; + ).map_err(|e| format!("failed to query account data: {}", e))?; if messages.is_empty() { Err("message with specified id was not found.".to_string()) - } - else { + } else { Ok(messages[0]["boc"].as_str().ok_or("Failed to obtain message boc.".to_string())?.to_string()) } } -pub async fn query_account_field(ton: TonClient, address: &str, field: &str) -> Result { +pub fn query_account_field(ton: TonClient, address: &str, field: &str) -> Result { let accounts = query_with_limit( ton.clone(), "accounts", @@ -280,8 +273,7 @@ pub async fn query_account_field(ton: TonClient, address: &str, field: &str) -> field, None, Some(1), - ).await - .map_err(|e| format!("failed to query account data: {}", e))?; + ).map_err(|e| format!("failed to query account data: {}", e))?; if accounts.is_empty() { return Err(format!("account with address {} not found", address)); } @@ -550,17 +542,14 @@ pub fn print_account( } } -pub fn construct_account_from_tvc(tvc_path: &str, address: Option<&str>, balance: Option) -> Result { +pub fn construct_account_from_tvc(tvc_path: &str, address: Option<&str>, balance: u64) -> Result { Account::active_by_init_code_hash( match address { Some(address) => MsgAddressInt::from_str(address) .map_err(|e| format!("Failed to set address: {}", e))?, _ => MsgAddressInt::default() }, - match balance { - Some(balance) => CurrencyCollection::with_grams(balance), - _ => CurrencyCollection::default() - }, + CurrencyCollection::with_grams(balance), 0, StateInit::construct_from_file(tvc_path) .map_err(|e| format!(" failed to load TVC from the file {}: {}", tvc_path, e))?, @@ -583,7 +572,7 @@ pub enum AccountSource { Tvc, } -pub async fn load_account( +pub fn load_account( source_type: &AccountSource, source: &str, ton_client: Option, @@ -597,7 +586,7 @@ pub async fn load_account( create_client(config)? } }; - let boc = query_account_field(ton_client.clone(),source, "boc").await?; + let boc = query_account_field(ton_client.clone(),source, "boc")?; Ok((Account::construct_from_base64(&boc) .map_err(|e| format!("Failed to construct account: {}", e))?, boc)) @@ -607,7 +596,7 @@ pub async fn load_account( Account::construct_from_file(source) .map_err(|e| format!(" failed to load account from the file {}: {}", source, e))? } else { - construct_account_from_tvc(source, None, None)? + construct_account_from_tvc(source, None, 0)? }; let account_bytes = account.write_to_bytes() .map_err(|e| format!(" failed to load data from the account: {}", e))?; @@ -617,8 +606,8 @@ pub async fn load_account( } -pub fn load_debug_info(abi: &str) -> Option { - check_file_exists(abi, &[".json", ".abi"], &[".dbg.json", ".debug.json", ".map.json"]) +pub fn load_debug_info(abi_path: &str) -> Option { + check_file_exists(abi_path, &[".json", ".abi"], &[".dbg.json", ".debug.json", ".map.json"]) } pub fn load_abi_from_tvc(tvc: &str) -> Option { @@ -682,10 +671,10 @@ pub fn load_params(params: &str) -> Result { }) } -pub async fn unpack_alternative_params(matches: &ArgMatches<'_>, abi_path: &str, method: &str, config: &Config) -> Result, String> { +pub fn unpack_alternative_params(matches: &ArgMatches<'_>, abi_path: &str, method: &str, config: &Config) -> Result, String> { if matches.is_present("PARAMS") { let params = matches.values_of("PARAMS").unwrap().collect::>(); - Ok(Some(parse_params(params, abi_path, method, config).await?)) + Ok(Some(parse_params(params, abi_path, method, config)?)) } else { Ok(config.parameters.clone().or(Some("{}".to_string()))) } @@ -725,7 +714,7 @@ pub fn contract_data_from_matches_or_config_alias( Ok((address, Some(abi), keys)) } -pub fn blockchain_config_from_default_json() -> Result { +fn blockchain_config_from_default_json() -> Result { // Default config params from evernode-se https://github.com/tonlabs/evernode-se/blob/master/docker/ton-node/blockchain.conf.json let json = r#"{ "p0": "5555555555555555555555555555555555555555555555555555555555555555", @@ -1014,28 +1003,22 @@ pub fn blockchain_config_from_default_json() -> Result // loads blockchain config from the config contract boc, if it is none tries to load config contract // from the network, if it is unavailable returns default. -pub async fn get_blockchain_config(cli_config: &Config, config_contract_boc_path: Option<&str>) -> +pub fn get_blockchain_config(cli_config: &Config, config_contract_boc_path: Option<&str>) -> Result { - match config_contract_boc_path { - Some(config_path) => { - let acc =Account::construct_from_file(config_path) - .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; - construct_blockchain_config(&acc) - }, - None => { - let ton_client = create_client(cli_config)?; - let config = query_account_field( - ton_client.clone(), - CONFIG_ADDR, - "boc", - ).await; - let config_account = config.and_then(|config| - Account::construct_from_base64(&config) - .map_err(|e| format!("Failed to construct config account: {e}"))); - match config_account { - Ok(config) => construct_blockchain_config(&config), - Err(_) => blockchain_config_from_default_json() - } + if let Some(config_path) = config_contract_boc_path { + let acc = Account::construct_from_file(config_path) + .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; + construct_blockchain_config(&acc) + } else { + let ton_client = create_client(cli_config)?; + let config = query_account_field( + ton_client, + CONFIG_ADDR, + "boc", + )?; + match Account::construct_from_base64(&config) { + Ok(config_account) => construct_blockchain_config(&config_account), + Err(_) => blockchain_config_from_default_json() } } } diff --git a/src/main.rs b/src/main.rs index 35d970ec..627c0c4d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -73,7 +73,7 @@ use voting::{create_proposal, decode_proposal, vote}; lazy_static::lazy_static! { static ref RUNTIME: tokio::runtime::Runtime = tokio::runtime::Builder::new_current_thread() .enable_all() - .thread_stack_size(800 * 1024 * 1024) + .thread_stack_size(8 * 1024 * 1024) .build() .expect("Can't create Engine tokio runtime"); } @@ -110,7 +110,7 @@ fn main_internal() -> Result <(), String> { .help("Path or link to the contract ABI file or pure json ABI data. Can be specified in the config file."); let keys_arg = Arg::with_name("KEYS") - .long("--keys") + .long("--keys_file") .takes_value(true) .help("Seed phrase or path to the file with keypair used to sign the message. Can be specified in the config file."); @@ -1230,11 +1230,11 @@ fn sign_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> return Err("nor data neither cell parameter".to_string()) }; let pair = match matches.value_of("KEYS") { - Some(keys) => crypto::load_keypair(keys)?, + Some(keys_file) => crypto::load_keypair(keys_file)?, None => { match &config.keys_path { - Some(keys) => crypto::load_keypair(keys)?, - None => return Err("nor signing keys in the params neither in the config".to_string()) + Some(keys_file) => crypto::load_keypair(keys_file)?, + None => return Err("nor signing keys_file in the params neither in the config".to_string()) } } }; @@ -1254,7 +1254,6 @@ fn sign_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> } fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Result<(), String> { - RUNTIME.block_on(async move { let address = matches.value_of("ADDRESS"); let method = matches.value_of("METHOD"); let params = matches.value_of("PARAMS"); @@ -1264,14 +1263,14 @@ fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Re let abi_path = abi_from_matches_or_config(matches, config)?; - let keys = matches.value_of("KEYS") + let keys_file = matches.value_of("KEYS") .or_else(|| matches.value_of("SIGN")) .map(|s| s.to_string()) .or_else(|| config.keys_path.clone()); let params = Some(load_params(params.unwrap())?); if !config.is_json { - print_args!(address, method, params, Some(&abi_path), keys, lifetime, output); + print_args!(address, method, params, Some(&abi_path), keys_file, lifetime, output); } let address = load_ton_address(address.unwrap(), config)?; @@ -1284,9 +1283,9 @@ fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Re &abi_path, method.unwrap(), ¶ms.unwrap(), - keys, + keys_file, is_fee, - ).await + ) }, CallType::Msg => { let lifetime = lifetime.map(|val| { @@ -1305,34 +1304,32 @@ fn call_command(matches: &ArgMatches<'_>, config: &Config, call: CallType) -> Re &abi_path, method.unwrap(), ¶ms.unwrap(), - keys, + keys_file, lifetime, raw, output, timestamp, - ).await + ) }, } - }) } fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<(), String> { let config = &full_config.config; let method = matches.value_of("METHOD").or(config.method.as_deref()) .ok_or("Method is not defined. Supply it in the config file or command line.")?; - let (address, abi_path, keys) = contract_data_from_matches_or_config_alias(matches, full_config)?; + let (address, abi_path, keys_file) = contract_data_from_matches_or_config_alias(matches, full_config)?; let abi_path = abi_path.unwrap(); - RUNTIME.block_on(async move { let params = unpack_alternative_params( matches, &abi_path, method, config - ).await?; + )?; let params = load_params(params.unwrap().as_ref())?; if !config.is_json { - print_args!(address, Some(&method), Some(¶ms), Some(&abi_path), keys); + print_args!(address, Some(&method), Some(¶ms), Some(&abi_path), keys_file); } let address = load_ton_address(address.unwrap().as_str(), config)?; @@ -1343,10 +1340,9 @@ fn callx_command(matches: &ArgMatches<'_>, full_config: &FullConfig) -> Result<( &abi_path, method, ¶ms, - keys, + keys_file, false, - ).await - }) + ) } fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -1372,39 +1368,36 @@ fn runget_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), Strin load_ton_address(address.unwrap(), config)? }; let bc_config = matches.value_of("BCCONFIG"); - RUNTIME.block_on(async move { - run_get_method(config, &address, method.unwrap(), params, source_type, bc_config).await - }) + run_get_method(config, &address, method.unwrap(), params, source_type, bc_config) } fn deploy_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig, deploy_type: DeployType) -> Result<(), String> { let config = &full_config.config; - let tvc = matches.value_of("TVC"); - let params = matches.value_of("PARAMS"); + let tvc = matches.value_of("TVC").unwrap(); + let params = matches.value_of("PARAMS").unwrap(); let wc = wc_from_matches_or_config(matches, config)?; let raw = matches.is_present("RAW"); let output = matches.value_of("OUTPUT"); let abi_path = abi_from_matches_or_config(matches, config)?; - let keys = matches.value_of("KEYS") + let keys_file = matches.value_of("KEYS") .or(matches.value_of("SIGN")) .map(|s| s.to_string()) .or(config.keys_path.clone()); let alias = matches.value_of("ALIAS"); - let params = Some(load_params(params.unwrap())?); + let params = load_params(params)?; if !config.is_json { let opt_wc = Some(format!("{}", wc)); - print_args!(tvc, params, Some(&abi_path), keys, opt_wc, alias); + print_args!(Some(tvc), Some(¶ms), Some(&abi_path), keys_file, opt_wc, alias); } RUNTIME.block_on(async move { match deploy_type { - DeployType::Full => deploy_contract(full_config, tvc.unwrap(), &abi_path, ¶ms.unwrap(), keys, wc, false, alias).await, - DeployType::MsgOnly => generate_deploy_message(tvc.unwrap(), &abi_path, ¶ms.unwrap(), keys, wc, raw, output, &full_config.config).await, - DeployType::Fee => deploy_contract(full_config, tvc.unwrap(), &abi_path, ¶ms.unwrap(), keys, wc, true, None).await, + DeployType::Full => deploy_contract(full_config, tvc, &abi_path, ¶ms, keys_file, wc, false, alias).await, + DeployType::MsgOnly => generate_deploy_message(tvc, &abi_path, ¶ms, keys_file, wc, raw, output, &full_config.config).await, + DeployType::Fee => deploy_contract(full_config, tvc, &abi_path, ¶ms, keys_file, wc, true, None).await, } }) } fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) -> Result<(), String> { - RUNTIME.block_on(async move { let config = &full_config.config; let tvc = matches.value_of("TVC").unwrap(); let wc = wc_from_matches_or_config(matches, config)?; @@ -1414,17 +1407,18 @@ fn deployx_command(matches: &ArgMatches<'_>, full_config: &mut FullConfig) -> Re &abi_path, "constructor", config - ).await?; - let keys = matches.value_of("KEYS") + )?.unwrap(); + let keys_file = matches.value_of("KEYS") .map(|s| s.to_string()) .or(config.keys_path.clone()); let alias = matches.value_of("ALIAS"); if !config.is_json { let opt_wc = Some(format!("{}", wc)); - print_args!(Some(tvc), params, Some(&abi_path), keys, opt_wc, alias); + print_args!(Some(tvc), Some(¶ms), Some(&abi_path), keys_file, opt_wc, alias); } - deploy_contract(full_config, tvc, &abi_path, ¶ms.unwrap(), keys, wc, false, alias).await + RUNTIME.block_on(async move { + deploy_contract(full_config, tvc, &abi_path, ¶ms, keys_file, wc, false, alias).await }) } @@ -1485,21 +1479,21 @@ fn genaddr_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), Stri RUNTIME.block_on(async move { let tvc = matches.value_of("TVC").unwrap(); let wc = matches.value_of("WC"); - let keys = matches.value_of("GENKEY").or(matches.value_of("SETKEY")); + let keys_file = matches.value_of("GENKEY").or(matches.value_of("SETKEY")); let new_keys = matches.is_present("GENKEY"); let init_data = matches.value_of("DATA"); let update_tvc = matches.is_present("SAVE"); let abi_path = match abi_from_matches_or_config(matches, config) { - Ok(abi) => abi, + Ok(abi) => abi.to_string(), Err(err) => { load_abi_from_tvc(tvc).ok_or_else(|| err)? } }; let is_update_tvc = if update_tvc { Some("true") } else { None }; if !config.is_json { - print_args!(Some(tvc), Some(&abi_path), wc, keys, init_data, is_update_tvc); + print_args!(Some(tvc), Some(&abi_path), wc, keys_file, init_data, is_update_tvc); } - generate_address(config, tvc, &abi_path, wc, keys, new_keys, init_data, update_tvc).await + generate_address(config, tvc, &abi_path, wc, keys_file, new_keys, init_data, update_tvc).await }) } @@ -1596,42 +1590,40 @@ fn storage_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), Stri fn proposal_create_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); let dest = matches.value_of("DEST"); - let keys = matches.value_of("KEYS"); + let keys_file = matches.value_of("KEYS"); let comment = matches.value_of("COMMENT"); let lifetime = matches.value_of("LIFETIME"); let offline = matches.is_present("OFFLINE"); if !config.is_json { - print_args!(address, comment, keys, lifetime); + print_args!(address, comment, keys_file, lifetime); } let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; - RUNTIME.block_on(async move { create_proposal( + create_proposal( config, address.as_str(), - keys, + keys_file, dest.unwrap(), comment.unwrap(), lifetime, offline - ).await }) + ) } fn proposal_vote_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { let address = matches.value_of("ADDRESS"); - let keys = matches.value_of("KEYS"); + let keys_file = matches.value_of("KEYS"); let id = matches.value_of("ID"); let lifetime = matches.value_of("LIFETIME"); let offline = matches.is_present("OFFLINE"); if !config.is_json { - print_args!(address, id, keys, lifetime); + print_args!(address, id, keys_file, lifetime); } let address = load_ton_address(address.unwrap(), config)?; let lifetime = parse_lifetime(lifetime, config)?; - RUNTIME.block_on(async move { - vote(config, address.as_str(), keys, id.unwrap(), lifetime, offline).await - })?; + vote(config, address.as_str(), keys_file, id.unwrap(), lifetime, offline)?; println!("{{}}"); Ok(()) } @@ -1643,9 +1635,7 @@ fn proposal_decode_command(matches: &ArgMatches<'_>, config: &Config) -> Result< print_args!(address, id); } let address = load_ton_address(address.unwrap(), config)?; - RUNTIME.block_on(async move { - decode_proposal(config, address.as_str(), id.unwrap()).await - }) + decode_proposal(config, address.as_str(), id.unwrap()) } fn getconfig_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -1675,9 +1665,7 @@ fn dump_bc_config_command(matches: &ArgMatches<'_>, config: &Config) -> Result<( if !config.is_json { print_args!(path); } - RUNTIME.block_on(async move { - dump_blockchain_config(config, path.unwrap()).await - }) + dump_blockchain_config(config, path.unwrap()) } fn nodeid_command(matches: &ArgMatches, config: &Config) -> Result<(), String> { diff --git a/src/message.rs b/src/message.rs index 2270a5df..3f4c3709 100644 --- a/src/message.rs +++ b/src/message.rs @@ -25,7 +25,7 @@ pub struct EncodedMessage { pub address: String, } -pub async fn prepare_message( +pub fn prepare_message( ton: TonClient, addr: &str, abi: Abi, @@ -41,8 +41,9 @@ pub async fn prepare_message( let msg_params = prepare_message_params(addr, abi, method, params, header.clone(), keys)?; - let msg = encode_message(ton, msg_params).await - .map_err(|e| format!("failed to create inbound message: {}", e))?; + let msg = crate::RUNTIME.block_on(async move { + encode_message(ton, msg_params).await + }).map_err(|e| format!("failed to create inbound message: {}", e))?; Ok(EncodedMessage { message: msg.message, @@ -151,10 +152,10 @@ pub fn unpack_message(str_msg: &str) -> Result<(EncodedMessage, String), String> Ok((msg, method)) } -pub async fn generate_message( +pub fn generate_message( config: &Config, addr: &str, - abi: &str, + abi_path: &str, method: &str, params: &str, keys: Option, @@ -168,7 +169,9 @@ pub async fn generate_message( let ton_addr = load_ton_address(addr, config) .map_err(|e| format!("failed to parse address: {}", e))?; - let abi = load_abi(abi, config).await?; + let abi = crate::RUNTIME.block_on(async move { + load_abi(abi_path, config).await + })?; let expire_at = lifetime + timestamp.map_or_else(|| now(), |millis| (millis / 1000) as u32); let header = FunctionHeader { @@ -186,7 +189,7 @@ pub async fn generate_message( Some(header), keys, config.is_json, - ).await?; + )?; display_generated_message(&msg, method, is_raw, output, config.is_json)?; diff --git a/src/multisig.rs b/src/multisig.rs index 3c55edbc..04109655 100644 --- a/src/multisig.rs +++ b/src/multisig.rs @@ -260,30 +260,32 @@ async fn multisig_send_command(matches: &ArgMatches<'_>, config: &Config) -> Res let comment = matches.value_of("PURPOSE"); let address = load_ton_address(address, config)?; - send(config, address.as_str(), dest, value, keys, comment).await + send(config, address.as_str(), dest, value, keys, comment) } -pub async fn encode_transfer_body(text: &str, config: &Config) -> Result { +pub fn encode_transfer_body(text: &str, config: &Config) -> Result { let text = hex::encode(text.as_bytes()); let client = create_client_local()?; - let abi = load_abi(TRANSFER_WITH_COMMENT, config).await?; - encode_message_body( - client.clone(), - ParamsOfEncodeMessageBody { - abi, - call_set: CallSet::some_with_function_and_input( - "transfer", - json!({ "comment": text }), - ).ok_or("failed to create CallSet with specified parameters")?, - is_internal: true, - ..Default::default() - }, - ).await - .map_err(|e| format!("failed to encode transfer body: {}", e)) - .map(|r| r.body) + crate::RUNTIME.block_on(async move { + let abi = load_abi(TRANSFER_WITH_COMMENT, config).await?; + encode_message_body( + client.clone(), + ParamsOfEncodeMessageBody { + abi, + call_set: CallSet::some_with_function_and_input( + "transfer", + json!({ "comment": text }), + ).ok_or("failed to create CallSet with specified parameters")?, + is_internal: true, + ..Default::default() + }, + ).await + .map_err(|e| format!("failed to encode transfer body: {}", e)) + .map(|r| r.body) + }) } -async fn send( +fn send( config: &Config, addr: &str, dest: &str, @@ -292,15 +294,15 @@ async fn send( comment: Option<&str> ) -> Result<(), String> { let body = if let Some(text) = comment { - encode_transfer_body(text, config).await? + encode_transfer_body(text, config)? } else { "".to_owned() }; - send_with_body(config, addr, dest, value, keys, &body).await + send_with_body(config, addr, dest, value, keys, &body) } -pub async fn send_with_body( +pub fn send_with_body( config: &Config, addr: &str, dest: &str, @@ -324,7 +326,7 @@ pub async fn send_with_body( ¶ms, Some(keys.to_owned()), false, - ).await + ) } async fn multisig_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { diff --git a/src/replay.rs b/src/replay.rs index c0fc37d4..ad2e9bbc 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -18,7 +18,6 @@ use std::{ sync::{Arc, atomic::AtomicU64} }; use clap::ArgMatches; -use failure::err_msg; use serde::{Deserialize, Serialize}; use serde_json::Value; @@ -30,7 +29,7 @@ use ton_client::{ }; use ton_executor::{BlockchainConfig, ExecuteParams, OrdinaryTransactionExecutor, TickTockTransactionExecutor, TransactionExecutor}; -use ton_types::{BuilderData, SliceData, UInt256, serialize_tree_of_cells}; +use ton_types::{error, fail, BuilderData, SliceData, UInt256, serialize_tree_of_cells}; use ton_vm::executor::{Engine, EngineTraceInfo}; use crate::{config::Config, RUNTIME}; @@ -48,9 +47,9 @@ pub fn construct_blockchain_config(config_account: &Account) -> Result Result { +fn construct_blockchain_config_err(config_account: &Account) -> Result { let config_cell = config_account - .get_data().ok_or(err_msg("Failed to get account's data"))? + .get_data().ok_or(error!("Failed to get account's data"))? .reference(0).ok(); let config_params = ConfigParams::with_address_and_params( UInt256::with_array([0x55; 32]), config_cell); @@ -118,8 +117,7 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo order: None, ..Default::default() }, - ) - .await; + ).await; let mut zerostate_found = false; if let Ok(zerostates) = zerostates { @@ -168,7 +166,7 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo "lt": { "gt": lt }, }) }; - let query = query_collection( + query_collection( context.clone(), ParamsOfQueryCollection { collection: "transactions".to_owned(), @@ -180,8 +178,7 @@ pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bo ]), ..Default::default() }, - ); - query.await + ).await }; let transactions = tokio_retry::Retry::spawn(retry_strategy.clone(), action).await @@ -386,29 +383,27 @@ pub async fn replay( trace_callback, ..ExecuteParams::default() }; - let tr = executor.execute_with_libs_and_params( + return executor.execute_with_libs_and_params( msg.as_ref(), &mut account_root, - params).map_err(|e| format!("Failed to execute txn: {}", e))?; - return Ok(tr); + params + ).map_err(|e| format!("Failed to execute txn: {}", e)); } } - let executor: Box = - match tr.tr.read_description() - .map_err(|e| format!("failed to read transaction: {}", e))? { - TransactionDescr::TickTock(desc) => { - Box::new(TickTockTransactionExecutor::new(config.clone(), desc.tt)) - } - TransactionDescr::Ordinary(_) => { - Box::new(OrdinaryTransactionExecutor::new(config.clone())) - } - _ => { - panic!("Unknown transaction type"); - } - }; + let description = tr.tr.read_description() + .map_err(|e| format!("failed to read transaction: {}", e))?; + let executor: Box = match description { + TransactionDescr::TickTock(desc) => { + Box::new(TickTockTransactionExecutor::new(config.clone(), desc.tt)) + } + TransactionDescr::Ordinary(_) => { + Box::new(OrdinaryTransactionExecutor::new(config.clone())) + } + _ => unreachable!("Unknown transaction type") + }; - let msg = tr.tr.in_msg_cell().map(|c| Message::construct_from_cell(c) - .map_err(|e| format!("failed to construct message: {}", e))).transpose()?; + let in_msg = tr.tr.read_in_msg() + .map_err(|e| format!("failed to read in message: {}", e))?; let params = ExecuteParams { block_unixtime: tr.tr.now(), @@ -417,9 +412,10 @@ pub async fn replay( ..ExecuteParams::default() }; let tr_local = executor.execute_with_libs_and_params( - msg.as_ref(), + in_msg.as_ref(), &mut account_root, - params).map_err(|e| format!("Failed to execute txn: {}", e))?; + params + ).map_err(|e| format!("Failed to execute txn: {}", e))?; state.account = Account::construct_from_cell(account_root.clone()) .map_err(|e| format!("Failed to construct account: {}", e))?; @@ -456,9 +452,9 @@ pub async fn replay( Err("Specified transaction was not found.".to_string()) } -pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Result<(), failure::Error> { +pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Result<(), ton_types::Error> { let context = create_client(config) - .map_err(|e| err_msg(format!("Failed to create ctx: {}", e)))?; + .map_err(|e| error!("Failed to create ctx: {}", e))?; let block = query_collection( context.clone(), @@ -477,7 +473,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res ).await?; if block.result.len() != 1 { - return Err(err_msg("Failed to fetch the block")) + fail!("Failed to fetch the block") } let mut accounts = vec!(); @@ -506,7 +502,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res })?; if accounts.is_empty() { - return Err(err_msg("The block is empty")) + fail!("The block is empty") } for (account, _) in &accounts { @@ -514,7 +510,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res fetch(config, account.as_str(), format!("{}.txns", account).as_str(), - Some(end_lt), false).await.map_err(err_msg)?; + Some(end_lt), false).await.map_err(failure::err_msg)? } let config_txns_path = format!("{}.txns", CONFIG_ADDR); @@ -523,7 +519,9 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res fetch(config, CONFIG_ADDR, config_txns_path.as_str(), - Some(end_lt), false).await.map_err(err_msg)?; + Some(end_lt), + false, + ).await.map_err(failure::err_msg)?; } let acc = accounts[0].0.as_str(); @@ -535,7 +533,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res replay(format!("{}.txns", acc).as_str(),config_txns_path.as_str(), txnid, None, || Ok(()), DUMP_CONFIG, config, None - ).await.map_err(err_msg)?; + ).await.map_err(failure::err_msg)?; } else { println!("Using pre-computed config {}", config_path); } @@ -556,7 +554,7 @@ pub async fn fetch_block(config: &Config, block_id: &str, filename: &str) -> Res DUMP_ACCOUNT, &_config, None, - ).await.map_err(err_msg).unwrap(); + ).await.unwrap(); } }) }).collect(); @@ -632,16 +630,15 @@ pub fn fetch_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> } pub fn replay_command(m: &ArgMatches<'_>, cli_config: &Config) -> Result<(), String> { - RUNTIME.block_on(async move { let (config_txns, bc_config) = if m.is_present("DEFAULT_CONFIG") { - ("", Some(get_blockchain_config(cli_config, None).await?)) + ("", Some(get_blockchain_config(cli_config, None)?)) } else { (m.value_of("CONFIG_TXNS").ok_or("Missing config txns filename")?, None) }; - replay(m.value_of("INPUT_TXNS").ok_or("Missing input txns filename")?, + RUNTIME.block_on(async move { replay( + m.value_of("INPUT_TXNS").ok_or("Missing input txns filename")?, config_txns, m.value_of("TXNID").ok_or("Missing final txn id")?, None, ||{Ok(())}, DUMP_ALL, cli_config, bc_config - ).await - })?; + ).await })?; Ok(()) } diff --git a/src/run.rs b/src/run.rs index c967d6a7..5a49fe7c 100644 --- a/src/run.rs +++ b/src/run.rs @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 TON DEV SOLUTIONS LTD. + * Copyright 2018-2023 EverX * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. @@ -16,8 +16,9 @@ use serde_json::{Map, Value, json}; use ton_block::{Account, Deserializable, Message, Serializable}; use ton_client::abi::{FunctionHeader}; use ton_client::tvm::{ExecutionOptions, ParamsOfRunGet, ParamsOfRunTvm, run_get, run_tvm}; +use crate::RUNTIME; use crate::config::{Config, FullConfig}; -use crate::call::{print_json_result}; +use crate::call::print_json_result; use crate::debug::{execute_debug, DebugLogger}; use crate::helpers::{create_client, now, now_ms, SDK_EXECUTION_ERROR_CODE, TonClient, contract_data_from_matches_or_config_alias, abi_from_matches_or_config, @@ -31,8 +32,10 @@ pub fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_altern let (address,abi, _) = contract_data_from_matches_or_config_alias(matches, full_config)?; (address.unwrap(), abi.unwrap()) } else { - (matches.value_of("ADDRESS").unwrap().to_string(), - abi_from_matches_or_config(matches, config)?) + ( + matches.value_of("ADDRESS").unwrap().to_string(), + abi_from_matches_or_config(matches, config)? + ) }; let account_source = if matches.is_present("TVC") { AccountSource::Tvc @@ -63,29 +66,27 @@ pub fn run_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_altern create_client_local()? }; - crate::RUNTIME.block_on(async move { - let (account, account_boc) = load_account( - &account_source, - &address, - Some(ton_client.clone()), - config - ).await?; - let address = match account_source { - AccountSource::Network => address, - AccountSource::Boc => account.get_addr().unwrap().to_string(), - AccountSource::Tvc => "0".repeat(64) - }; - run(matches, config, Some(ton_client), &address, account_boc, abi_path, is_alternative).await - }) + let (account, account_boc) = load_account( + &account_source, + &address, + Some(ton_client.clone()), + config + )?; + let address = match account_source { + AccountSource::Network => address, + AccountSource::Boc => account.get_addr().unwrap().to_string(), + AccountSource::Tvc => "0".repeat(64) + }; + run(matches, config, Some(ton_client), &address, &account_boc, &abi_path, is_alternative) } -async fn run( +fn run( matches: &ArgMatches<'_>, config: &Config, ton_client: Option, address: &str, - account_boc: String, - abi_path: String, + account_boc: &str, + abi_path: &str, is_alternative: bool, ) -> Result<(), String> { let method = if is_alternative { @@ -94,7 +95,10 @@ async fn run( } else { matches.value_of("METHOD").unwrap() }; +println!("55"); let bc_config = matches.value_of("BCCONFIG"); + let execution_options = prepare_execution_options(bc_config)?; + let bc_config = get_blockchain_config(config, None)?; if !config.is_json { println!("Running get-method..."); @@ -106,13 +110,14 @@ async fn run( } }; - let abi = load_abi(&abi_path, config).await?; + let abi = RUNTIME.block_on(async move { + load_abi(abi_path, config).await + })?; let params = if is_alternative { - unpack_alternative_params(matches, &abi_path, method, config).await? + unpack_alternative_params(matches, abi_path, method, config)? } else { matches.value_of("PARAMS").map(|s| s.to_owned()) }; - let params = Some(load_params(params.unwrap().as_ref())?); let now = now(); @@ -131,20 +136,20 @@ async fn run( Some(header), None, config.is_json, - ).await?; + )?; - let execution_options = prepare_execution_options(bc_config)?; - let result = run_tvm( + let message = msg.message.clone(); + let result = RUNTIME.block_on(async move { run_tvm( ton_client.clone(), ParamsOfRunTvm { - message: msg.message.clone(), - account: account_boc.clone(), + message, + account: account_boc.to_string(), abi: Some(abi.clone()), return_updated_account: Some(true), execution_options, ..Default::default() - }, - ).await; + } + ).await }); if &config.debug_fail != "None" && result.is_err() && result.clone().err().unwrap().code == SDK_EXECUTION_ERROR_CODE { @@ -170,8 +175,8 @@ async fn run( let now = now_ms(); let message = Message::construct_from_base64(&msg.message) .map_err(|e| format!("failed to construct message: {}", e))?; - if let Err(e) = execute_debug( - get_blockchain_config(config, None).await?, + let result = execute_debug( + bc_config, &mut account, Some(&message), (now / 1000) as u32, @@ -179,7 +184,8 @@ async fn run( now, true, config - ).await { + ); + if let Err(e) = result { if !e.contains("Contract did not accept message") { return Err(e); } @@ -209,7 +215,6 @@ async fn run( } } } - Ok(()) } @@ -227,14 +232,14 @@ fn prepare_execution_options(bc_config: Option<&str>) -> Result, source_type: AccountSource, bc_config: Option<&str>) -> Result<(), String> { +pub fn run_get_method(config: &Config, addr: &str, method: &str, params: Option, source_type: AccountSource, bc_config: Option<&str>) -> Result<(), String> { let ton = if source_type == AccountSource::Network { create_client_verbose(config)? } else { create_client_local()? }; - let (_, acc_boc) = load_account(&source_type, addr, Some(ton.clone()), config).await?; + let (_, acc_boc) = load_account(&source_type, addr, Some(ton.clone()), config)?; let params = params.map(|p| serde_json::from_str(&p)) .transpose() @@ -244,18 +249,17 @@ pub async fn run_get_method(config: &Config, addr: &str, method: &str, params: O println!("Running get-method..."); } let execution_options = prepare_execution_options(bc_config)?; - let result = run_get( + let function_name = method.to_owned(); + let result = RUNTIME.block_on(async move { run_get( ton, ParamsOfRunGet { account: acc_boc, - function_name: method.to_owned(), + function_name, input: params, execution_options, ..Default::default() }, - ).await - .map_err(|e| format!("run failed: {}", e))? - .output; + ).await }).map_err(|e| format!("run failed: {}", e))?.output; if !config.is_json { println!("Succeeded."); diff --git a/src/voting.rs b/src/voting.rs index 4e770779..a8009d2a 100644 --- a/src/voting.rs +++ b/src/voting.rs @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 TON DEV SOLUTIONS LTD. + * Copyright 2018-2023 EverX * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. @@ -16,7 +16,7 @@ use crate::helpers::{create_client_local, decode_msg_body}; use crate::multisig::{encode_transfer_body, MSIG_ABI, TRANSFER_WITH_COMMENT}; use serde_json::json; -pub async fn create_proposal( +pub fn create_proposal( config: &Config, addr: &str, keys: Option<&str>, @@ -26,7 +26,7 @@ pub async fn create_proposal( offline: bool, ) -> Result<(), String> { - let payload = encode_transfer_body(text, config).await?; + let payload = encode_transfer_body(text, config)?; let params = json!({ "dest": dest, @@ -50,9 +50,8 @@ pub async fn create_proposal( false, None, None, - ).await + ) } else { - call::call_contract( config, addr, @@ -61,11 +60,11 @@ pub async fn create_proposal( ¶ms, keys, false, - ).await + ) } } -pub async fn vote( +pub fn vote( config: &Config, addr: &str, keys: Option<&str>, @@ -92,7 +91,7 @@ pub async fn vote( false, None, None, - ).await + ) } else { call::call_contract( config, @@ -102,11 +101,11 @@ pub async fn vote( ¶ms, keys, false, - ).await + ) } } -pub async fn decode_proposal( +pub fn decode_proposal( config: &Config, addr: &str, proposal_id: &str, @@ -121,11 +120,12 @@ pub async fn decode_proposal( "{}", None, false, - ).await?; + )?; let txns = result["transactions"].as_array() .ok_or(r#"failed to decode result: "transactions" array not found"#.to_string())?; + let ton = create_client_local()?; for txn in txns { let txn_id = txn["id"].as_str() .ok_or(r#"failed to parse transaction in list: "id" not found"#.to_string())?; @@ -133,16 +133,14 @@ pub async fn decode_proposal( if txn_id == proposal_id { let body = txn["payload"].as_str() .ok_or(r#"failed to parse transaction in list: "payload" not found"#.to_string())?; - let ton = create_client_local()?; - let result = decode_msg_body( + let ton = ton.clone(); + let result = crate::RUNTIME.block_on(async move { decode_msg_body( ton.clone(), TRANSFER_WITH_COMMENT, body, true, config, - ) - .await - .map_err(|e| format!("failed to decode proposal payload: {}", e))?; + ).await }).map_err(|e| format!("failed to decode proposal payload: {}", e))?; let comment = String::from_utf8( hex::decode( From c7380dfdbe19cb93575f31bf739e662a2118103c Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Mon, 13 Mar 2023 16:28:26 +0300 Subject: [PATCH 8/9] fix bc_config --- src/debug.rs | 6 +-- src/helpers.rs | 21 ++++++--- src/replay.rs | 16 ++++--- src/run.rs | 124 +++++++++++++++++++++++++------------------------ 4 files changed, 90 insertions(+), 77 deletions(-) diff --git a/src/debug.rs b/src/debug.rs index b7fbd52f..0c861683 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -182,6 +182,7 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { let account_address = Arg::with_name("ACCOUNT_ADDRESS") .long("--tvc_address") .takes_value(true) + .allow_hyphen_values(true) .requires("TVC") .help("Account address for account constructed from TVC."); @@ -297,8 +298,7 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { let call_cmd = run_cmd.clone().name("call") .about("Play call locally with trace") - .arg(sign_arg.clone()) - .arg(update_arg.clone()); + .arg(sign_arg.clone()); let config_boc_arg = Arg::with_name("CONFIG_BOC") .help("Path to the config contract boc.") @@ -696,7 +696,7 @@ crate::RUNTIME.block_on(async move { .map_err(|e| format!("Failed to construct message: {}", e))?; if is_getter { - account.set_balance(CurrencyCollection::with_grams(u64::MAX)); + account.set_balance(CurrencyCollection::with_grams((1 << 56) - 1)); } let mut acc_root = account.serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; diff --git a/src/helpers.rs b/src/helpers.rs index db9f96c4..79d89f92 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -96,7 +96,7 @@ pub fn load_ton_address(addr: &str, config: &Config) -> Result { } else { addr.to_owned() }; - let _ = MsgAddressInt::from_str(&addr) + MsgAddressInt::from_str(&addr) .map_err(|e| format!("Address is specified in the wrong format. Error description: {}", e))?; Ok(addr) } @@ -545,8 +545,8 @@ pub fn print_account( pub fn construct_account_from_tvc(tvc_path: &str, address: Option<&str>, balance: u64) -> Result { Account::active_by_init_code_hash( match address { - Some(address) => MsgAddressInt::from_str(address) - .map_err(|e| format!("Failed to set address: {}", e))?, + Some(address) => MsgAddressInt::from_str(address.trim()) + .map_err(|e| format!("Failed to set address {}: {}", address, e))?, _ => MsgAddressInt::default() }, CurrencyCollection::with_grams(balance), @@ -1006,9 +1006,18 @@ fn blockchain_config_from_default_json() -> Result { pub fn get_blockchain_config(cli_config: &Config, config_contract_boc_path: Option<&str>) -> Result { if let Some(config_path) = config_contract_boc_path { - let acc = Account::construct_from_file(config_path) - .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; - construct_blockchain_config(&acc) + let bytes = std::fs::read(config_path) + .map_err(|e| format!("Failed to load config from file {config_path}: {e}"))?; + let cell = ton_types::deserialize_tree_of_cells(&mut std::io::Cursor::new(bytes)) + .map_err(|e| format!("Failed to deserialize cell from file {config_path}: {e}"))?; + if let Ok(config_params) = ton_block::ConfigParams::construct_from_cell(cell.clone()) { + BlockchainConfig::with_config(config_params) + .map_err(|e| format!("Failed to construct config: {}", e)) + } else { + let acc = Account::construct_from_cell(cell) + .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; + construct_blockchain_config(&acc) + } } else { let ton_client = create_client(cli_config)?; let config = query_account_field( diff --git a/src/replay.rs b/src/replay.rs index ad2e9bbc..d7171620 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -44,16 +44,18 @@ pub const DUMP_EXECUTOR_CONFIG: u8 = 0x04; pub const DUMP_ALL: u8 = 0xFF; pub fn construct_blockchain_config(config_account: &Account) -> Result { - construct_blockchain_config_err(config_account).map_err(|e| format!("Failed to construct config: {}", e)) + extract_config_params_from_account(config_account) + .and_then(|config_params| BlockchainConfig::with_config(config_params)) + .map_err(|e| format!("Failed to construct config: {}", e)) } -fn construct_blockchain_config_err(config_account: &Account) -> Result { +pub fn extract_config_params_from_account(config_account: &Account) -> Result { let config_cell = config_account - .get_data().ok_or(error!("Failed to get account's data"))? - .reference(0).ok(); - let config_params = ConfigParams::with_address_and_params( - UInt256::with_array([0x55; 32]), config_cell); - BlockchainConfig::with_config(config_params) + .get_data() + .ok_or_else(|| error!("Failed to get account's data"))? + .reference(0)?; + Ok(ConfigParams::with_address_and_params( + UInt256::with_array([0x55; 32]), Some(config_cell))) } pub async fn fetch(config: &Config, account_address: &str, filename: &str, lt_bound: Option, rewrite_file: bool) -> Result<(), String> { diff --git a/src/run.rs b/src/run.rs index 5a49fe7c..c3ebd715 100644 --- a/src/run.rs +++ b/src/run.rs @@ -16,7 +16,8 @@ use serde_json::{Map, Value, json}; use ton_block::{Account, Deserializable, Message, Serializable}; use ton_client::abi::{FunctionHeader}; use ton_client::tvm::{ExecutionOptions, ParamsOfRunGet, ParamsOfRunTvm, run_get, run_tvm}; -use crate::RUNTIME; +use ton_executor::BlockchainConfig; +use crate::{RUNTIME, print_args}; use crate::config::{Config, FullConfig}; use crate::call::print_json_result; use crate::debug::{execute_debug, DebugLogger}; @@ -91,18 +92,20 @@ fn run( ) -> Result<(), String> { let method = if is_alternative { matches.value_of("METHOD").or(config.method.as_deref()) - .ok_or("Method is not defined. Supply it in the config file or command line.")? + .ok_or("Method is not defined. Supply it in the config file or command line.")? } else { matches.value_of("METHOD").unwrap() }; -println!("55"); let bc_config = matches.value_of("BCCONFIG"); - let execution_options = prepare_execution_options(bc_config)?; - let bc_config = get_blockchain_config(config, None)?; if !config.is_json { println!("Running get-method..."); + print_args!(bc_config, Some(method)); } + + let bc_config = get_blockchain_config(config, bc_config)?; + let execution_options = prepare_execution_options(&bc_config)?; + let ton_client = match ton_client { Some(ton_client) => { ton_client }, None => { @@ -151,55 +154,58 @@ println!("55"); } ).await }); - if &config.debug_fail != "None" && result.is_err() - && result.clone().err().unwrap().code == SDK_EXECUTION_ERROR_CODE { - // TODO: add code to use bc_config from file + let result = match result { + Err(err) => { + if &config.debug_fail != "None" && err.code == SDK_EXECUTION_ERROR_CODE { + if config.is_json { + let e = format!("{:#}", err); + let e: Value = serde_json::from_str(&e) + .unwrap_or(Value::String(e)); + let res = json!({"Error": e}); + println!("{}", serde_json::to_string_pretty(&res) + .unwrap_or_else(|_| "{{ \"JSON serialization error\" }}".to_string())); + } else { + println!("Error: {:#}", err); + println!("Execution failed. Starting debug..."); + } - if config.is_json { - let e = format!("{:#}", result.clone().err().unwrap()); - let err: Value = serde_json::from_str(&e) - .unwrap_or(Value::String(e)); - let res = json!({"Error": err}); - println!("{}", serde_json::to_string_pretty(&res) - .unwrap_or_else(|_| "{{ \"JSON serialization error\" }}".to_string())); - } else { - println!("Error: {:#}", result.clone().err().unwrap()); - println!("Execution failed. Starting debug..."); - } + let mut account = Account::construct_from_base64(&account_boc) + .map_err(|e| format!("Failed to construct account: {}", e))? + .serialize() + .map_err(|e| format!("Failed to serialize account: {}", e))?; - let mut account = Account::construct_from_base64(&account_boc) - .map_err(|e| format!("Failed to construct account: {}", e))? - .serialize() - .map_err(|e| format!("Failed to serialize account: {}", e))?; + let now = now_ms(); + let message = Message::construct_from_base64(&msg.message) + .map_err(|e| format!("failed to construct message: {}", e))?; + let result = execute_debug( + bc_config, + &mut account, + Some(&message), + (now / 1000) as u32, + now, + now, + true, + config + ); + if let Err(e) = result { + if !e.contains("Contract did not accept message") { + return Err(e); + } + } - let now = now_ms(); - let message = Message::construct_from_base64(&msg.message) - .map_err(|e| format!("failed to construct message: {}", e))?; - let result = execute_debug( - bc_config, - &mut account, - Some(&message), - (now / 1000) as u32, - now, - now, - true, - config - ); - if let Err(e) = result { - if !e.contains("Contract did not accept message") { - return Err(e); + if !config.is_json { + let log_path = format!("run_{}_{}.log", address, method); + println!("Debug finished."); + println!("Log saved to {}", log_path); + } + return Err(String::new()); + } else { + return Err(format!("{:#}", err)) } } + Ok(result) => result + }; - if !config.is_json { - let log_path = format!("run_{}_{}.log", address, method); - println!("Debug finished."); - println!("Log saved to {}", log_path); - } - return Err("".to_string()); - } - - let result = result.map_err(|e| format!("{:#}", e))?; if !config.is_json { println!("Succeeded."); } @@ -218,18 +224,13 @@ println!("55"); Ok(()) } -fn prepare_execution_options(bc_config: Option<&str>) -> Result, String> { - if let Some(config) = bc_config { - let bytes = std::fs::read(config) - .map_err(|e| format!("Failed to read data from file {}: {}", config, e))?; - let config_boc = base64::encode(bytes); - let ex_opt = ExecutionOptions{ - blockchain_config: Some(config_boc), - ..Default::default() - }; - return Ok(Some(ex_opt)); - } - Ok(None) +fn prepare_execution_options(bc_config: &BlockchainConfig) -> Result, String> { + let bytes = bc_config.raw_config().write_to_bytes() + .map_err(|e| format!("Failed to serialize config params {}", e))?; + Ok(Some(ExecutionOptions { + blockchain_config: Some(base64::encode(bytes)), + ..Default::default() + })) } pub fn run_get_method(config: &Config, addr: &str, method: &str, params: Option, source_type: AccountSource, bc_config: Option<&str>) -> Result<(), String> { @@ -248,7 +249,8 @@ pub fn run_get_method(config: &Config, addr: &str, method: &str, params: Option< if !config.is_json { println!("Running get-method..."); } - let execution_options = prepare_execution_options(bc_config)?; + let bc_config = get_blockchain_config(config, bc_config)?; + let execution_options = prepare_execution_options(&bc_config)?; let function_name = method.to_owned(); let result = RUNTIME.block_on(async move { run_get( ton, From e599c4f7c66acff19ea793697cd2237a7ac12d9c Mon Sep 17 00:00:00 2001 From: sergeyyar Date: Tue, 14 Mar 2023 16:59:19 +0300 Subject: [PATCH 9/9] refactoring --- src/debug.rs | 91 +++++++++++++++++++++++++++----------------------- src/deploy.rs | 2 +- src/helpers.rs | 20 ++++++----- src/replay.rs | 2 +- 4 files changed, 64 insertions(+), 51 deletions(-) diff --git a/src/debug.rs b/src/debug.rs index 0c861683..06246fea 100644 --- a/src/debug.rs +++ b/src/debug.rs @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 TON DEV SOLUTIONS LTD. + * Copyright 2018-2023 EverX. All Rights Reserved. * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. @@ -289,6 +289,7 @@ pub fn create_debug_command<'a, 'b>() -> App<'a, 'b> { .help("Path to the TVC file with contract stateinit.")) .arg(Arg::with_name("WC") .takes_value(true) + .allow_hyphen_values(true) .long("--wc") .help("Workchain ID")) .arg(params_arg.clone()) @@ -550,8 +551,8 @@ crate::RUNTIME.block_on(async move { .serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; - let msg = trans.in_msg_cell().map(|c| Message::construct_from_cell(c) - .map_err(|e| format!("failed to construct message: {}", e))).transpose()?; + let msg = trans.read_in_msg() + .map_err(|e| format!("failed to construct message: {}", e))?; log::set_max_level(log::LevelFilter::Trace); log::set_boxed_logger( @@ -616,8 +617,8 @@ fn decode_abi_path(matches: &ArgMatches<'_>, config: &Config) -> Option fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_getter: bool) -> Result<(), String> { let (input, opt_abi, sign) = contract_data_from_matches_or_config_alias(matches, full_config)?; let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); - let method = Some(matches.value_of("METHOD").or(full_config.config.method.as_deref()) - .ok_or("Method is not defined. Supply it in the config file or command line.")?); + let method = matches.value_of("METHOD").or(full_config.config.method.as_deref()); + let bc_config = matches.value_of("CONFIG_PATH"); let is_boc = matches.is_present("BOC"); let is_tvc = matches.is_present("TVC"); let params = unpack_alternative_params( @@ -628,7 +629,7 @@ fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_get )?; if !full_config.config.is_json { - print_args!(input, method, params, sign, opt_abi, output); + print_args!(input, method, params, sign, opt_abi, output, bc_config); } let ton_client = if is_boc || is_tvc { @@ -636,6 +637,7 @@ fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_get } else { create_client(&full_config.config)? }; + let bc_config = get_blockchain_config(&full_config.config, bc_config)?; let input = input.unwrap(); let mut account = if is_tvc { construct_account_from_tvc( @@ -670,14 +672,14 @@ fn debug_call_command(matches: &ArgMatches<'_>, full_config: &FullConfig, is_get input: Some(params), header: Some(header) }); - let bc_config = get_blockchain_config(&full_config.config, matches.value_of("CONFIG_PATH"))?; -crate::RUNTIME.block_on(async move { - let abi = load_abi(opt_abi.as_ref().unwrap(), &full_config.config).await?; let signer = if let Some(keys) = keys { Signer::Keys { keys } } else { Signer::None }; + let abi = crate::RUNTIME.block_on(async move { + load_abi(opt_abi.as_ref().unwrap(), &full_config.config).await + })?; let msg_params = ParamsOfEncodeMessage { abi, address: Some(format!("0:{}", "0".repeat(64))), // TODO: add option or get from input @@ -686,27 +688,27 @@ crate::RUNTIME.block_on(async move { ..Default::default() }; - let message = encode_message( - ton_client.clone(), - msg_params - ).await - .map_err(|e| format!("Failed to encode message: {}", e))?; + let message = crate::RUNTIME.block_on(async move { + encode_message( + ton_client.clone(), + msg_params + ).await + }).map_err(|e| format!("Failed to encode message: {}", e))?; let message = Message::construct_from_base64(&message.message) .map_err(|e| format!("Failed to construct message: {}", e))?; if is_getter { - account.set_balance(CurrencyCollection::with_grams((1 << 56) - 1)); + account.set_balance(CurrencyCollection::with_grams(u64::MAX)); } let mut acc_root = account.serialize() .map_err(|e| format!("Failed to serialize account: {}", e))?; let trace_path = output.unwrap().to_string(); + let logger = Box::new(DebugLogger::new(trace_path.clone())); log::set_max_level(log::LevelFilter::Trace); - log::set_boxed_logger( - Box::new(DebugLogger::new(trace_path.clone())) - ).map_err(|e| format!("Failed to set logger: {}", e))?; + log::set_boxed_logger(logger).map_err(|e| format!("Failed to set logger: {}", e))?; let trans = execute_debug( bc_config, @@ -722,7 +724,11 @@ crate::RUNTIME.block_on(async move { let mut out_res = vec![]; let msg_string = match trans { Ok(trans) => { - out_res = decode_messages(trans.out_msgs, decode_abi_path(matches, &full_config.config), &full_config.config).await?; + out_res = crate::RUNTIME.block_on(async move { decode_messages( + trans.out_msgs, + decode_abi_path(matches, &full_config.config), + &full_config.config + ).await })?; "Execution finished.".to_string() } Err(e) => { @@ -764,7 +770,6 @@ crate::RUNTIME.block_on(async move { println!("{{}}"); } Ok(()) -}) } fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { @@ -774,8 +779,9 @@ fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() let is_boc = matches.is_present("BOC"); let is_tvc = matches.is_present("TVC"); let message = matches.value_of("MESSAGE"); + let bc_config = matches.value_of("CONFIG_PATH"); if !config.is_json { - print_args!(input, message, output, debug_info); + print_args!(input, message, output, debug_info, bc_config); } let ton_client = create_client(config)?; @@ -812,7 +818,7 @@ fn debug_message_command(matches: &ArgMatches<'_>, config: &Config) -> Result<() Box::new(DebugLogger::new(trace_path.clone())) ).map_err(|e| format!("Failed to set logger: {}", e))?; - let bc_config = get_blockchain_config(config, matches.value_of("CONFIG_PATH"))?; + let bc_config = get_blockchain_config(config, bc_config)?; crate::RUNTIME.block_on(async move { let now = parse_now(matches)?; let trans = execute_debug( @@ -857,7 +863,7 @@ crate::RUNTIME.block_on(async move { } fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> { - let tvc = matches.value_of("TVC"); + let tvc_path = matches.value_of("TVC"); let output = Some(matches.value_of("LOG_PATH").unwrap_or(DEFAULT_TRACE_PATH)); let abi_path = abi_from_matches_or_config(matches, config)?; let debug_info = matches.value_of("DBG_INFO").map(|s| s.to_string()) @@ -872,25 +878,23 @@ fn debug_deploy_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), config )?; let wc = Some(wc_from_matches_or_config(matches, config)?); + let bc_config = matches.value_of("CONFIG_PATH"); if !config.is_json { - print_args!(tvc, params, sign, Some(&abi_path), output, debug_info); + print_args!(tvc_path, params, sign, Some(&abi_path), output, debug_info, bc_config); } -crate::RUNTIME.block_on(async move { - let (msg, address) = prepare_deploy_message( - tvc.unwrap(), + let (msg, address) = crate::RUNTIME.block_on(async move { prepare_deploy_message( + tvc_path.unwrap(), &abi_path, params.as_ref().unwrap(), sign, wc.unwrap(), config - ).await?; + ).await })?; let init_balance = matches.is_present("INIT_BALANCE"); - let ton_client = create_client(config)?; - let enc_msg = encode_message(ton_client.clone(), msg.clone()).await - .map_err(|e| format!("failed to create inbound message: {}", e))?; - + let ton_client; let account = if init_balance { + ton_client = create_client_local()?; Account::with_address_and_ballance( &MsgAddressInt::with_standart( None, @@ -901,6 +905,7 @@ crate::RUNTIME.block_on(async move { &CurrencyCollection::with_grams(u64::MAX) ) } else { + ton_client = create_client(config)?; let account = query_account_field( ton_client.clone(), &address, @@ -909,6 +914,9 @@ crate::RUNTIME.block_on(async move { Account::construct_from_base64(&account) .map_err(|e| format!("Failed to construct account: {}", e))? }; + let enc_msg = crate::RUNTIME.block_on(async move { + encode_message(ton_client, msg).await + }).map_err(|e| format!("failed to create inbound message: {}", e))?; let message = Message::construct_from_base64(&enc_msg.message) .map_err(|e| format!("Failed to construct message: {}", e))?; @@ -925,7 +933,7 @@ crate::RUNTIME.block_on(async move { let now = parse_now(matches)?; - let bc_config = get_blockchain_config(config, matches.value_of("CONFIG_PATH"))?; + let bc_config = get_blockchain_config(config, bc_config)?; let trans = execute_debug( bc_config, &mut acc_root, @@ -939,7 +947,9 @@ crate::RUNTIME.block_on(async move { let msg_string = match trans { Ok(trans) => { - decode_messages(trans.out_msgs, decode_abi_path(matches, config), config).await?; + crate::RUNTIME.block_on(async move { + decode_messages(trans.out_msgs, decode_abi_path(matches, config), config).await + })?; "Execution finished.".to_string() } Err(e) => { @@ -953,7 +963,6 @@ crate::RUNTIME.block_on(async move { println!("{{}}"); } Ok(()) -}) } async fn decode_messages(msgs: OutMessages, abi_path: Option, config: &Config) -> Result, String> { @@ -1081,19 +1090,19 @@ pub fn execute_debug( gas_price: 65536000, flat_gas_limit: 100, flat_gas_price: 1000000, - gas_limit: u64::MAX, + gas_limit: 0x00FF_FFFF_FFFF_FFFF, special_gas_limit: u64::MAX, - gas_credit: u64::MAX, + gas_credit: 0x00FF_FFFF, block_gas_limit: u64::MAX, freeze_due_limit: 100000000, - delete_due_limit:1000000000, - max_gas_threshold:u128::MAX, + delete_due_limit: 1000000000, + max_gas_threshold: u128::MAX, }; let c20 = ConfigParamEnum::ConfigParam20(gas.clone()); let c21 = ConfigParamEnum::ConfigParam21(gas); config.set_config(c20).unwrap(); config.set_config(c21).unwrap(); - BlockchainConfig::with_config(config).map_err(|e| format!("Failed to construct config: {}", e))? + BlockchainConfig::with_config(config).map_err(|e| format!("Failed to construct config from config: {}", e))? } else { bc_config }; @@ -1118,7 +1127,7 @@ pub fn execute_debug( message, account, params - ).map_err(|e| format!("Debug failed: {:?}", e)) + ).map_err(|e| format!("Debug failed: {}", e)) } fn trace_callback(info: &EngineTraceInfo, debug_info: &Option) { diff --git a/src/deploy.rs b/src/deploy.rs index 12f31d49..2e1846e5 100644 --- a/src/deploy.rs +++ b/src/deploy.rs @@ -123,7 +123,7 @@ pub async fn prepare_deploy_message( let keys = keys_file.map(|k| load_keypair(&k)).transpose()?; let tvc_bytes = std::fs::read(tvc_path) - .map_err(|e| format!("failed to read smart contract file: {}", e))?; + .map_err(|e| format!("failed to read smart contract file {}: {}", tvc_path, e))?; return prepare_deploy_message_params(&tvc_bytes, abi, params, keys, wc).await; diff --git a/src/helpers.rs b/src/helpers.rs index 79d89f92..50ea2ad4 100644 --- a/src/helpers.rs +++ b/src/helpers.rs @@ -1,5 +1,5 @@ /* - * Copyright 2018-2021 TON DEV SOLUTIONS LTD. + * Copyright 2018-2023 EverX. All Rights Reserved. * * Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use * this file except in compliance with the License. @@ -25,6 +25,7 @@ use ton_client::error::ClientError; use ton_client::net::{query_collection, OrderBy, ParamsOfQueryCollection, NetworkConfig}; use ton_client::{ClientConfig, ClientContext}; use ton_executor::BlockchainConfig; +use ton_types::SliceData; use std::sync::Arc; use std::str::FromStr; use std::time::{Duration, SystemTime}; @@ -1010,14 +1011,17 @@ pub fn get_blockchain_config(cli_config: &Config, config_contract_boc_path: Opti .map_err(|e| format!("Failed to load config from file {config_path}: {e}"))?; let cell = ton_types::deserialize_tree_of_cells(&mut std::io::Cursor::new(bytes)) .map_err(|e| format!("Failed to deserialize cell from file {config_path}: {e}"))?; - if let Ok(config_params) = ton_block::ConfigParams::construct_from_cell(cell.clone()) { - BlockchainConfig::with_config(config_params) - .map_err(|e| format!("Failed to construct config: {}", e)) - } else { - let acc = Account::construct_from_cell(cell) - .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; - construct_blockchain_config(&acc) + let mut slice = SliceData::load_cell(cell.clone()) + .map_err(|e| format!("Failed to load cell: {e}"))?; + if let Ok(config_params) = ton_block::ConfigParams::construct_from(&mut slice) { + if slice.remaining_bits() == 0 && slice.remaining_references() == 0 { + return BlockchainConfig::with_config(config_params) + .map_err(|e| format!("Failed to construct config from file: {}", e)); + } } + let acc = Account::construct_from_cell(cell) + .map_err(|e| format!("Failed to load config contract account from file {config_path}: {e}"))?; + construct_blockchain_config(&acc) } else { let ton_client = create_client(cli_config)?; let config = query_account_field( diff --git a/src/replay.rs b/src/replay.rs index d7171620..ae4acbd1 100644 --- a/src/replay.rs +++ b/src/replay.rs @@ -46,7 +46,7 @@ pub const DUMP_ALL: u8 = 0xFF; pub fn construct_blockchain_config(config_account: &Account) -> Result { extract_config_params_from_account(config_account) .and_then(|config_params| BlockchainConfig::with_config(config_params)) - .map_err(|e| format!("Failed to construct config: {}", e)) + .map_err(|e| format!("Failed to construct config from account: {}", e)) } pub fn extract_config_params_from_account(config_account: &Account) -> Result {