Skip to content

Commit

Permalink
Merge pull request #948 from everx-labs/IgorKoval/encode-decode
Browse files Browse the repository at this point in the history
Igor koval/encode decode
  • Loading branch information
IgorKoval authored Nov 14, 2024
2 parents 2eaf128 + ccb1aa5 commit 90f7ed2
Show file tree
Hide file tree
Showing 9 changed files with 176 additions and 47 deletions.
30 changes: 15 additions & 15 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ license = 'Apache-2.0'
name = 'ever-cli'
readme = 'README.md'
repository = 'https://github.com/everx-labs/ever-cli'
version = '0.42.0'
version = '0.43.0'

[dependencies]
anyhow = '1.0'
Expand Down
11 changes: 5 additions & 6 deletions src/debot/term_signing_box.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ use crate::helpers::{read_keys, TonClient};
use ever_client::crypto::{
get_signing_box, remove_signing_box, KeyPair, RegisteredSigningBox, SigningBoxHandle,
};
use std::io::{self, BufRead, BufReader, Read, Write};
use ever_client::encoding::decode_abi_bigint;
use std::io::{self, BufRead, BufReader, Read, Write};

pub(super) struct TerminalSigningBox {
handle: SigningBoxHandle,
Expand Down Expand Up @@ -96,11 +96,10 @@ where
});
if let Ok(ref keys) = pair {
if !possible_keys.is_empty() {
let pub_key_in_radix10 = decode_abi_bigint(&*("0x".to_string() + &*keys.public)).unwrap().to_string();
if !possible_keys
.iter()
.any(|x| *x == pub_key_in_radix10)
{
let pub_key_in_radix10 = decode_abi_bigint(&*("0x".to_string() + &*keys.public))
.unwrap()
.to_string();
if !possible_keys.iter().any(|x| *x == pub_key_in_radix10) {
println!("Unexpected keys.");
println!(
"Hint: enter keypair which contains one of the following public keys: {}",
Expand Down
57 changes: 56 additions & 1 deletion src/decode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,18 @@ use crate::helpers::{
};
use crate::{load_abi, print_args};
use clap::{App, AppSettings, Arg, ArgMatches, SubCommand};
use ever_abi::contract::MAX_SUPPORTED_VERSION;
use ever_abi::ParamType;
use ever_block::base64_decode;
use ever_block::{read_single_root_boc, write_boc, Cell, SliceData};
use ever_block::{Account, AccountStatus, Deserializable, Serializable, StateInit};
use ever_client::abi::{decode_account_data, ParamsOfDecodeAccountData};
use ever_client::abi::{decode_account_data, ParamsOfDecodeAccountData, StackItemToJson};
use ever_vm::int;
use ever_vm::stack::integer::IntegerData;
use ever_vm::stack::StackItem;
use serde::Serialize;
use serde_json::json;
use std::sync::Arc;

pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> {
let tvc_cmd = SubCommand::with_name("stateinit")
Expand Down Expand Up @@ -51,6 +58,15 @@ pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> {
.setting(AppSettings::AllowLeadingHyphen)
.setting(AppSettings::TrailingVarArg)
.setting(AppSettings::DontCollapseArgsInUsage)
.subcommand(SubCommand::with_name("abi-param")
.about("Decodes cell in base64 to json object.")
.arg(Arg::with_name("CELL")
.required(true)
.help("Cell in base64."))
.arg(Arg::with_name("ABI")
.long("--abi")
.takes_value(true)
.help("Path or link to the contract ABI file or pure json ABI data. Can be specified in the config file.")))
.subcommand(SubCommand::with_name("body")
.about("Decodes body base64 string.")
.arg(Arg::with_name("BODY")
Expand Down Expand Up @@ -107,6 +123,9 @@ pub fn create_decode_command<'a, 'b>() -> App<'a, 'b> {
}

pub async fn decode_command(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> {
if let Some(m) = m.subcommand_matches("abi-param") {
return decode_abi_param(m, config).await;
}
if let Some(m) = m.subcommand_matches("body") {
return decode_body_command(m, config).await;
}
Expand Down Expand Up @@ -137,6 +156,42 @@ async fn decode_data_command(m: &ArgMatches<'_>, config: &Config) -> Result<(),
Err("unknown command".to_owned())
}

async fn decode_abi_param(m: &ArgMatches<'_>, config: &Config) -> Result<(), String> {
let str_abi = abi_from_matches_or_config(m, config)?;
let params =
serde_json::from_str::<ever_abi::Param>(str_abi.as_str()).map_err(|e| e.to_string())?;

let cell_in_base64 = m.value_of("CELL").unwrap();
let data = base64_decode(cell_in_base64).map_err(|e| e.to_string())?;
let cell = read_single_root_boc(data).map_err(|e| e.to_string())?;
let stack_items = {
match params.kind {
ParamType::Array(_) => {
let mut slice = SliceData::load_cell(cell.clone()).map_err(|e| e.to_string())?;
let size = slice.get_next_u32().map_err(|e| e.to_string())?;
let dict = slice.reference(0).map_err(|e| e.to_string())?;

let res: Vec<StackItem> = vec![int!(size), StackItem::Cell(dict)];
[StackItem::Tuple(Arc::new(res))]
}
ParamType::Cell | ParamType::Map(_, _) | ParamType::Bytes | ParamType::String => {
[StackItem::Cell(cell)]
}
_ => return Err("Only cell, map, bytes, string and array".to_string()),
}
};

let abi_version = MAX_SUPPORTED_VERSION;

let js_result =
StackItemToJson::convert_vm_items_to_json(&stack_items, &[params], &abi_version)
.map_err(|e| e.to_string())?;

println!("{:#}", js_result);

Ok(())
}

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)?);
Expand Down
9 changes: 5 additions & 4 deletions src/genaddr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,9 +160,9 @@ fn update_contract_state(
use ever_sdk::ContractImage;
use std::io::{Seek, Write};

let data_map_supported: bool = (Contract::load(abi.as_bytes())
.map_err(|e| format!("unable to load abi: {}", e))?)
.data_map_supported();
let contract =
Contract::load(abi.as_bytes()).map_err(|e| format!("unable to load abi: {}", e))?;
let data_map_supported: bool = contract.data_map_supported();

let mut state_init = OpenOptions::new()
.read(true)
Expand Down Expand Up @@ -193,7 +193,8 @@ fn update_contract_state(
} else {
Some(hex::encode(pubkey))
};
let js_init_data = crate::helpers::insert_pubkey_to_init_data(pk, data.as_deref())?;
let js_init_data =
crate::helpers::insert_pubkey_to_init_data(pk, data.as_deref(), &contract)?;
contract_image
.update_data(false, js_init_data.as_str(), abi)
.map_err(|e| format!("unable to update contract image data: {}", e))?;
Expand Down
23 changes: 19 additions & 4 deletions src/helpers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ use crate::replay::{construct_blockchain_config, CONFIG_ADDR};
use crate::SignatureIDType;
use crate::{resolve_net_name, FullConfig};
use clap::ArgMatches;
use ever_abi::{Contract, ParamType};
use ever_block::{
Account, CurrencyCollection, Deserializable, MsgAddressInt, Serializable, StateInit,
};
Expand Down Expand Up @@ -397,7 +398,8 @@ pub async fn calc_acc_address(
init_data: Option<&str>,
abi: Abi,
) -> Result<String, String> {
let data_map_supported = abi.abi().unwrap().data_map_supported();
let contract = abi.abi().unwrap();
let data_map_supported = contract.data_map_supported();

let ton = create_client_local()?;
let dset = if data_map_supported {
Expand All @@ -414,7 +416,7 @@ pub async fn calc_acc_address(
..Default::default()
}
} else {
let init_data_json = insert_pubkey_to_init_data(pubkey.clone(), init_data)?;
let init_data_json = insert_pubkey_to_init_data(pubkey.clone(), init_data, &contract)?;
let js = serde_json::from_str(init_data_json.as_str())
.map_err(|e| format!("initial data is not in json: {}", e))?;
DeploySet {
Expand Down Expand Up @@ -1116,6 +1118,7 @@ pub fn decode_data(data: &str, param_name: &str) -> Result<Vec<u8>, String> {
pub fn insert_pubkey_to_init_data(
pubkey: Option<String>,
opt_init_data: Option<&str>,
contract: &Contract,
) -> Result<String, String> {
let init_data = opt_init_data.unwrap_or("{}");

Expand All @@ -1128,8 +1131,20 @@ pub fn insert_pubkey_to_init_data(
Please, use one way to set public key.".to_owned());
}
if let Some(pk) = pubkey {
let pubkey_str = format!("0x{}", pk);
obj.insert("_pubkey".to_string(), Value::String(pubkey_str));
let pubkey_abi = contract.fields().get(0).unwrap();
assert_eq!(pubkey_abi.name, "_pubkey");
match pubkey_abi.kind {
ParamType::Uint(256) => {
let pubkey_str = format!("0x{}", pk);
obj.insert("_pubkey".to_string(), Value::String(pubkey_str));
}
ParamType::FixedBytes(32) => {
let mut pubkey_str = format!("{}", pk);
assert_eq!(pubkey_str.len(), 64);
obj.insert("_pubkey".to_string(), Value::String(pubkey_str));
}
_ => panic!("Unsupported type of pubkey"),
}
}
}
_ => panic!("js_init_data is not Value::Object"),
Expand Down
52 changes: 51 additions & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,10 @@ 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 ever_client::abi::{CallSet, ParamsOfEncodeMessageBody};
use ever_abi::contract::MAX_SUPPORTED_VERSION;
use ever_abi::token::Tokenizer;
use ever_client::abi::{CallSet, ParamsOfEncodeMessageBody, TokenValueToStackItem};
use ever_vm::stack::StackItem;
use genaddr::generate_address;
use getconfig::{dump_blockchain_config, query_global_config};
use helpers::{
Expand Down Expand Up @@ -424,6 +427,14 @@ async fn main_internal() -> Result<(), String> {
.arg(params_arg.clone())
.arg(abi_arg.clone());

let encode_cmd = SubCommand::with_name("encode")
.setting(AppSettings::AllowLeadingHyphen)
.about("Encode parameters to cell in base64.")
.version(version_string)
.author(author)
.arg(params_arg.clone())
.arg(abi_arg.clone());

let sign_cmd = create_test_sign_command()
.author(author)
.version(version_string)
Expand Down Expand Up @@ -993,6 +1004,7 @@ async fn main_internal() -> Result<(), String> {
.subcommand(send_cmd)
.subcommand(message_cmd)
.subcommand(body_cmd)
.subcommand(encode_cmd)
.subcommand(sign_cmd)
.subcommand(run_cmd)
.subcommand(runget_cmd)
Expand Down Expand Up @@ -1098,6 +1110,9 @@ async fn command_parser(matches: &ArgMatches<'_>, is_json: bool) -> Result<(), S
if let Some(m) = matches.subcommand_matches("body") {
return body_command(m, config).await;
}
if let Some(m) = matches.subcommand_matches("encode") {
return encode_command(m, config).await;
}
if let Some(m) = matches.subcommand_matches("sign") {
return test_sign_command(m, config);
}
Expand Down Expand Up @@ -1256,6 +1271,41 @@ async fn send_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), S
call_contract_with_msg(config, message.unwrap().to_owned(), &abi.unwrap()).await
}

async fn encode_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> {
// let params = load_params(matches.value_of("PARAMS").unwrap())?;
let params = matches.value_of("PARAMS").unwrap().to_string();
let value = serde_json::from_str(params.as_str()).map_err(|e| e.to_string())?;

let str_abi = abi_from_matches_or_config(matches, config)?;
let x = serde_json::from_str::<ever_abi::Param>(str_abi.as_str()).map_err(|e| e.to_string())?;

let token_value = Tokenizer::tokenize_parameter(&x.kind, &value, x.name.as_str())
.map_err(|e| format!("{}", e))?;
let abi_version = MAX_SUPPORTED_VERSION;
let stack_item = TokenValueToStackItem::convert_token_to_vm_type(token_value, &abi_version)
.map_err(|e| e.to_string())?;

let mut opt_cell: Option<ever_block::Cell> = None;
if let StackItem::Cell(ref cell) = stack_item {
opt_cell = Some(cell.clone());
} else if let StackItem::Tuple(ref tuple) = stack_item {
// it's array
if let StackItem::Cell(ref cell) = &tuple[1] {
opt_cell = Some(cell.clone());
}
} else {
return Err("Expected map, cell, array types".to_string());
}

let msg_bytes = ever_block::write_boc(&opt_cell.unwrap())
.map_err(|e| format!("failed to encode out message: {e}"))?;
let mut ser_msg = json!({});
ser_msg["cell_in_base64"] = base64::encode(msg_bytes).into();
println!("{:#}", ser_msg);

Ok(())
}

async fn body_command(matches: &ArgMatches<'_>, config: &Config) -> Result<(), String> {
let method = matches.value_of("METHOD");
let params = matches.value_of("PARAMS");
Expand Down
3 changes: 1 addition & 2 deletions src/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -335,8 +335,7 @@ pub async fn run_get_method(
create_client_local()?
};

let (_, acc_boc) =
load_account(&source_type, addr, Some(ton.clone()), config, None).await?;
let (_, acc_boc) = load_account(&source_type, addr, Some(ton.clone()), config, None).await?;

let params = params
.map(|p| serde_json::from_str(&p))
Expand Down
Loading

0 comments on commit 90f7ed2

Please sign in to comment.