diff --git a/Cargo.lock b/Cargo.lock index 433ae37..be535b3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -291,7 +291,6 @@ dependencies = [ name = "cli" version = "0.1.0" dependencies = [ - "adnl 0.1.0", "base64 0.13.1", "chrono", "clap", @@ -301,6 +300,7 @@ dependencies = [ "pretty-hex", "rand", "regex", + "tokio", "ton_liteapi", "ton_networkconfig", "ureq", diff --git a/cli/Cargo.toml b/cli/Cargo.toml index ddc0d0a..77e2e4b 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -16,4 +16,4 @@ regex = "1" ton_liteapi = { path = "../liteapi" } ton_networkconfig = { path = "../network-config", features = ["adnl"] } rand = "0.8.5" -adnl = "0.1.0" \ No newline at end of file +tokio = { version = "1.36", features = ["full"] } \ No newline at end of file diff --git a/cli/src/arg_parsers.rs b/cli/src/arg_parsers.rs index 0788daf..be58238 100644 --- a/cli/src/arg_parsers.rs +++ b/cli/src/arg_parsers.rs @@ -1,7 +1,7 @@ use std::error::Error; use regex::Regex; -use ton_liteapi::tl_types::{Int256, BlockIdExt, AccountId}; +use ton_liteapi::tl::common::{Int256, BlockIdExt, AccountId}; pub fn parse_block_id_ext(s: &str) -> std::result::Result { let re = Regex::new(r"\(([-]?\d+),([a-fA-F0-9]+),(\d+)\):([^:]+):(.+)").unwrap(); diff --git a/cli/src/main.rs b/cli/src/main.rs index 7bd6172..f0789a2 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -2,16 +2,14 @@ mod arg_parsers; use chrono::{DateTime, Utc}; use clap::{Parser, Subcommand}; -use adnl::AdnlPublicKey; -use rand::seq::SliceRandom; -use ton_liteapi::tl_types::{BlockIdExt, Int256, AccountId}; -use ton_liteapi::LiteClient; +use rand::seq::SliceRandom as _; +use ton_liteapi::tl::common::{AccountId, BlockId, BlockIdExt, Int256, TransactionId3}; +use ton_liteapi::client::LiteClient; use pretty_hex::PrettyHex; -use ton_networkconfig::{ConfigGlobal, ConfigLiteServer, ConfigPublicKey}; +use ton_networkconfig::ConfigGlobal; use std::error::Error; use std::fs::{read_to_string, File}; use std::io::{stdin, Read}; -use std::net::TcpStream; use std::path::PathBuf; use std::str::FromStr; use std::time::{Duration, UNIX_EPOCH}; @@ -24,13 +22,7 @@ type Result = std::result::Result>; #[clap(author, version, about, long_about = None)] struct Args { /// Local network config from file - #[clap( - short, - long, - parse(from_os_str), - value_name = "FILE", - group = "config-group" - )] + #[clap(short, long, parse(from_os_str), value_name = "FILE", group = "config-group")] config: Option, /// Use testnet config, if not provided use mainnet config #[clap(short, long, parse(from_flag), group = "config-group")] @@ -45,7 +37,7 @@ enum Commands { GetMasterchainInfo, /// Get masterchain info with additional data GetMasterchainInfoExt { - mode: i32, + mode: u32, }, /// Get server time GetTime, @@ -64,7 +56,16 @@ enum Commands { GetBlockHeader { #[clap(value_parser = parse_block_id_ext)] block_id_ext: BlockIdExt, - mode: i32, + #[clap(long)] + with_state_update: bool, + #[clap(long)] + with_value_flow: bool, + #[clap(long)] + with_extra: bool, + #[clap(long)] + with_shard_hashes: bool, + #[clap(long)] + with_prev_blk_signatures: bool, }, /// Send external message #[clap(arg_required_else_help = true, parse(from_os_str))] @@ -83,28 +84,32 @@ enum Commands { block_id_ext: BlockIdExt, #[clap(value_parser = parse_account_id)] account_id: AccountId, - method_id: i64, + method_id: u64, params: Vec, }, GetShardInfo { - seqno: u32, + #[clap(value_parser = parse_block_id_ext)] + block_id_ext: BlockIdExt, workchain: i32, + shard: u64, + exact: bool, }, GetAllShardsInfo { - seqno: u32, + #[clap(value_parser = parse_block_id_ext)] + block_id_ext: BlockIdExt, }, GetOneTransaction { #[clap(value_parser = parse_block_id_ext)] block_id_ext: BlockIdExt, #[clap(value_parser = parse_account_id)] account_id: AccountId, - lt: i64, + lt: u64, }, GetTransactions { - count: i32, + count: u32, #[clap(value_parser = parse_account_id)] account_id: AccountId, - lt: i64, + lt: u64, hash: Int256, }, LookupBlock { @@ -113,79 +118,164 @@ enum Commands { #[clap(short, long, group = "lookup-variant")] seqno: Option, #[clap(short, long, group = "lookup-variant")] - ltime: Option, + lt: Option, #[clap(short, long, group = "lookup-variant")] - utime: Option, + utime: Option, + #[clap(long)] + with_state_update: bool, + #[clap(long)] + with_value_flow: bool, + #[clap(long)] + with_extra: bool, + #[clap(long)] + with_shard_hashes: bool, + #[clap(long)] + with_prev_blk_signatures: bool, }, ListBlockTransactions { #[clap(value_parser = parse_block_id_ext)] block_id_ext: BlockIdExt, - count: i32, - #[clap(short, long, parse(from_flag))] + count: u32, + #[clap(short, long)] reverse_order: bool, - #[clap(short, long, parse(from_flag))] + #[clap(short, long)] want_proof: bool, #[clap(requires = "after-lt", value_parser = parse_account_id, long)] after_account: Option, #[clap(requires = "after-account", long)] - after_lt: Option, + after_lt: Option, }, GetBlockProof { #[clap(value_parser = parse_block_id_ext)] known_block: BlockIdExt, #[clap(value_parser = parse_block_id_ext)] target_block: Option, + #[clap(long)] + allow_weak_target: bool, + #[clap(long)] + base_block_from_request: bool, }, GetConfigAll { - mode: i32, #[clap(value_parser = parse_block_id_ext)] block_id_ext: BlockIdExt, + #[clap(long)] + with_state_root: bool, + #[clap(long)] + with_libraries: bool, + #[clap(long)] + with_state_extra_root: bool, + #[clap(long)] + with_shard_hashes: bool, + #[clap(long)] + with_validator_set: bool, + #[clap(long)] + with_special_smc: bool, + #[clap(long)] + with_accounts_root: bool, + #[clap(long)] + with_prev_blocks: bool, + #[clap(long)] + with_workchain_info: bool, + #[clap(long)] + with_capabilities: bool, + #[clap(long)] + extract_from_key_block: bool, }, GetConfigParams { - mode: i32, #[clap(value_parser = parse_block_id_ext)] block_id_ext: BlockIdExt, param_list: Vec, + #[clap(long)] + with_state_root: bool, + #[clap(long)] + with_libraries: bool, + #[clap(long)] + with_state_extra_root: bool, + #[clap(long)] + with_shard_hashes: bool, + #[clap(long)] + with_validator_set: bool, + #[clap(long)] + with_special_smc: bool, + #[clap(long)] + with_accounts_root: bool, + #[clap(long)] + with_prev_blocks: bool, + #[clap(long)] + with_workchain_info: bool, + #[clap(long)] + with_capabilities: bool, + #[clap(long)] + extract_from_key_block: bool, }, GetValidatorStats { #[clap(value_parser = parse_block_id_ext)] block_id_ext: BlockIdExt, - limit: i32, + limit: u32, start_after: Option, - modified_after: Option, + modified_after: Option, }, } -fn execute_command(client: &mut LiteClient, command: &Commands) -> Result<()> { +#[tokio::main] +async fn main() -> Result<()> { + env_logger::init(); + let args = Args::parse(); + let config_json = if let Some(config) = args.config { + read_to_string(config)? + } else { + download_config(args.testnet).await? + }; + let config: ConfigGlobal = ConfigGlobal::from_str(&config_json)?; + let ls = config.liteservers.choose(&mut rand::thread_rng()).unwrap(); + let public_key: [u8; 32] = ls.id.clone().into(); + let mut client = LiteClient::connect(ls.socket_addr(), public_key).await?; + + if let Err(e) = execute_command(&mut client, &args.command).await { + println!("[ERROR] {:?}", e); + } + Ok(()) +} + +async fn execute_command(client: &mut LiteClient, command: &Commands) -> Result<()> { match command { Commands::GetMasterchainInfo => { - let result = (*client).get_masterchain_info()?; + let result = client.get_masterchain_info().await?; println!("{:#?}\n", result); println!("Last masterchain BlockIdExt: {}", result.last); } Commands::GetMasterchainInfoExt { mode } => { - let result = (*client).get_masterchain_info_ext(0)?; + let result = client.get_masterchain_info_ext(*mode).await?; println!("{:#?}\n", result); println!("Last masterchain BlockIdExt: {}", result.last); } Commands::GetTime => { - let result = (*client).get_time()?.now as u64; - let time = DateTime::::from(UNIX_EPOCH + Duration::from_secs(result)); + let result = client.get_time().await?; + let time = DateTime::::from(UNIX_EPOCH + Duration::from_secs(result as u64)); println!("Current time: {} => {:?}", result, time); } Commands::GetVersion => { - let result = (*client).get_version()?; + let result = client.get_version().await?; println!("Current version: {:?}", result); } Commands::GetBlock { block_id_ext } => { - let result = (*client).get_block(block_id_ext.clone())?; - println!("BlockData: {:?}", result.data.hex_dump()); + let result = client.get_block(block_id_ext.clone()).await?; + println!("BlockData: {:?}", result.hex_dump()); } Commands::GetState { block_id_ext } => { - let result = (*client).get_state(block_id_ext.clone())?; + let result = client.get_state(block_id_ext.clone()).await?; + println!("{:#?}", result); } - Commands::GetBlockHeader { block_id_ext, mode } => { - + Commands::GetBlockHeader { block_id_ext, with_state_update, with_value_flow, with_extra, with_shard_hashes, with_prev_blk_signatures } => { + let result = client.get_block_header( + block_id_ext.clone(), + *with_state_update, + *with_value_flow, + *with_extra, + *with_shard_hashes, + *with_prev_blk_signatures, + ).await?; + println!("Block Header: {:?}", result.hex_dump()); } Commands::SendMessage { file } => { let mut data = Vec::::new(); @@ -194,86 +284,120 @@ fn execute_command(client: &mut LiteClient, command: &Commands) -> Re } else { File::open(file)?.read_to_end(&mut data)?; } - let result = client.send_message(data)?; + let result = client.send_message(data).await?; println!("result = {:?}", result); } Commands::GetAccountState { block_id_ext, account_id } => { - let result = (*client).get_account_state(block_id_ext.clone(), account_id.clone())?; + let result = client.get_account_state(block_id_ext.clone(), account_id.clone()).await?; println!("{:#?}", result); } Commands::RunSmcMethod { block_id_ext, account_id, method_id, params } => { - + let result = client.run_smc_method(0, block_id_ext.clone(), account_id.clone(), *method_id, params.clone()).await?; + println!("{:#?}", result); } - Commands::GetShardInfo { seqno, workchain } => { - let block = (*client).lookup_block( - ton_liteapi::tl_types::BlockId { - workchain: -1, - shard: 9223372036854775808, - seqno: *seqno, - }, - None, - None, - )?; - let result = - (*client).get_shard_info(block.id, *workchain, 9223372036854775808, true)?; - println!("{:?}", &result); + Commands::GetShardInfo { block_id_ext, workchain, shard, exact } => { + let result = client.get_shard_info(block_id_ext.clone(), *workchain, *shard, *exact).await?; + println!("{:#?}", result); } - Commands::GetAllShardsInfo { seqno } => { - let block = (*client).lookup_block( - ton_liteapi::tl_types::BlockId { - workchain: -1, - shard: 9223372036854775808, - seqno: *seqno, - }, - None, - None, - )?; - let result = (*client).get_all_shards_info(block.id)?; - println!("{:?}", &result); + Commands::GetAllShardsInfo { block_id_ext } => { + let result = client.get_all_shards_info(block_id_ext.clone()).await?; + println!("{:#?}", result); } Commands::GetOneTransaction { block_id_ext, account_id, lt } => { - + let result = client.get_one_transaction(block_id_ext.clone(), account_id.clone(), *lt).await?; + println!("{:#?}", result); } Commands::GetTransactions { count, account_id, lt, hash } => { - + let result = client.get_transactions(*count, account_id.clone(), *lt, hash.clone()).await?; + println!("{:#?}", result); } - Commands::LookupBlock { - seqno, - ltime, - utime, - workchain, - shard, - } => { - let block = ton_liteapi::tl_types::BlockId { - seqno: if let Some(seqno) = seqno { *seqno } else { 0 }, - shard: *shard, - workchain: *workchain, - }; - let res = (*client).lookup_block(block, *ltime, *utime).unwrap(); - println!("{:#?}\n", res); - println!("BlockIdExt: {}", res.id); + Commands::LookupBlock { workchain, shard, seqno, lt, utime, with_state_update, with_value_flow, with_extra, with_shard_hashes, with_prev_blk_signatures } => { + let result = client.lookup_block( + (), + BlockId { workchain: *workchain, shard: *shard, seqno: seqno.unwrap_or(0) }, + seqno.map(|_| ()), + *lt, + *utime, + *with_state_update, + *with_value_flow, + *with_extra, + *with_shard_hashes, + *with_prev_blk_signatures, + ).await?; + println!("{:#?}", result); } Commands::ListBlockTransactions { block_id_ext, count, reverse_order, want_proof, after_account, after_lt } => { - + let after = after_account.as_ref().and_then(|account| after_lt.map(|lt| TransactionId3 { + account: account.id.clone(), + lt, + })); + let result = client.list_block_transactions( + block_id_ext.clone(), + *count, + after, + *reverse_order, + *want_proof, + ).await?; + println!("{:#?}", result); } - Commands::GetBlockProof { known_block, target_block } => { - let result = (*client).get_block_proof(known_block.clone(), None)?; - println!("{:?}", &result); + Commands::GetBlockProof { known_block, target_block, allow_weak_target, base_block_from_request } => { + let result = client.get_block_proof( + known_block.clone(), + target_block.clone(), + *allow_weak_target, + *base_block_from_request, + ).await?; + println!("{:#?}", result); } - Commands::GetConfigAll { mode, block_id_ext } => { - + Commands::GetConfigAll { block_id_ext, with_state_root, with_libraries, with_state_extra_root, with_shard_hashes, with_validator_set, with_special_smc, with_accounts_root, with_prev_blocks, with_workchain_info, with_capabilities, extract_from_key_block } => { + let result = client.get_config_all( + block_id_ext.clone(), + *with_state_root, + *with_libraries, + *with_state_extra_root, + *with_shard_hashes, + *with_validator_set, + *with_special_smc, + *with_accounts_root, + *with_prev_blocks, + *with_workchain_info, + *with_capabilities, + *extract_from_key_block, + ).await?; + println!("{:#?}", result); } - Commands::GetConfigParams { mode, block_id_ext, param_list } => { - + Commands::GetConfigParams { block_id_ext, param_list, with_state_root, with_libraries, with_state_extra_root, with_shard_hashes, with_validator_set, with_special_smc, with_accounts_root, with_prev_blocks, with_workchain_info, with_capabilities, extract_from_key_block } => { + let result = client.get_config_params( + block_id_ext.clone(), + param_list.clone(), + *with_state_root, + *with_libraries, + *with_state_extra_root, + *with_shard_hashes, + *with_validator_set, + *with_special_smc, + *with_accounts_root, + *with_prev_blocks, + *with_workchain_info, + *with_capabilities, + *extract_from_key_block, + ).await?; + println!("{:#?}", result); } Commands::GetValidatorStats { block_id_ext, limit, start_after, modified_after } => { - + let result = client.get_validator_stats( + block_id_ext.clone(), + *limit, + start_after.clone(), + *modified_after, + ).await?; + println!("{:#?}", result); } }; Ok(()) } -fn download_config(testnet: bool) -> Result { +async fn download_config(testnet: bool) -> Result { let url = if testnet { "https://ton.org/testnet-global.config.json" } else { @@ -291,38 +415,3 @@ fn download_config(testnet: bool) -> Result { } Ok(response.into_string()?) } - -fn connect_ls(ls: &ConfigLiteServer) -> Result> { - let transport = TcpStream::connect_timeout(&ls.socket_addr().into(), Duration::from_secs(2))?; - Ok(LiteClient::connect::(transport, ls.id.clone())?) -} - -fn connect_any(config: &ConfigGlobal) -> Result> { - for ls in &config.liteservers { - log::info!("Connecting to {} (id {})", ls.socket_addr(), base64::encode(ls.id.to_bytes())); - match connect_ls(ls) { - Ok(x) => return Ok(x), - Err(e) => { - log::warn!("Connection error: {}", e); - }, - } - } - return Err("No liteservers available".into()) -} - -fn main() -> Result<()> { - env_logger::init(); - let args = Args::parse(); - let config_json = if let Some(config) = args.config { - read_to_string(config)? - } else { - download_config(args.testnet)? - }; - let mut config: ConfigGlobal = ConfigGlobal::from_str(&config_json)?; - config.liteservers.shuffle(&mut rand::thread_rng()); - let mut client = connect_any(&config)?; - if let Err(e) = execute_command(&mut client, &args.command) { - println!("[ERROR] {}", e); - } - Ok(()) -} diff --git a/liteapi/src/tl/response.rs b/liteapi/src/tl/response.rs index 6ea60b0..3111bd9 100644 --- a/liteapi/src/tl/response.rs +++ b/liteapi/src/tl/response.rs @@ -45,6 +45,7 @@ pub struct Version { #[derivative(Debug, Clone, PartialEq)] pub struct BlockData { pub id: BlockIdExt, + #[derivative(Debug(format_with="fmt_bytes"))] pub data: Vec, } @@ -54,6 +55,7 @@ pub struct BlockState { pub id: BlockIdExt, pub root_hash: Int256, pub file_hash: Int256, + #[derivative(Debug(format_with="fmt_bytes"))] pub data: Vec, } @@ -73,6 +75,7 @@ pub struct BlockHeader { pub with_shard_hashes: Option<()>, #[tl(flags_bit = "mode.6")] pub with_prev_blk_signatures: Option<()>, + #[derivative(Debug(format_with="fmt_bytes"))] pub header_proof: Vec, } @@ -103,17 +106,23 @@ pub struct RunMethodResult { pub id: BlockIdExt, pub shardblk: BlockIdExt, #[tl(flags_bit = "mode.0")] + #[derivative(Debug(format_with="fmt_opt_bytes"))] pub shard_proof: Option>, #[tl(flags_bit = "mode.0")] + #[derivative(Debug(format_with="fmt_opt_bytes"))] pub proof: Option>, #[tl(flags_bit = "mode.1")] + #[derivative(Debug(format_with="fmt_opt_bytes"))] pub state_proof: Option>, #[tl(flags_bit = "mode.3")] + #[derivative(Debug(format_with="fmt_opt_bytes"))] pub init_c7: Option>, #[tl(flags_bit = "mode.4")] + #[derivative(Debug(format_with="fmt_opt_bytes"))] pub lib_extras: Option>, pub exit_code: i32, #[tl(flags_bit = "mode.2")] + #[derivative(Debug(format_with="fmt_opt_bytes"))] pub result: Option>, } @@ -122,7 +131,9 @@ pub struct RunMethodResult { pub struct ShardInfo { pub id: BlockIdExt, pub shardblk: BlockIdExt, + #[derivative(Debug(format_with = "fmt_bytes"))] pub shard_proof: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub shard_descr: Vec, } @@ -130,7 +141,9 @@ pub struct ShardInfo { #[derivative(Debug, Clone, PartialEq)] pub struct AllShardsInfo { pub id: BlockIdExt, + #[derivative(Debug(format_with = "fmt_bytes"))] pub proof: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub data: Vec, } @@ -138,7 +151,9 @@ pub struct AllShardsInfo { #[derivative(Debug, Clone, PartialEq)] pub struct TransactionInfo { pub id: BlockIdExt, + #[derivative(Debug(format_with = "fmt_bytes"))] pub proof: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub transaction: Vec, } @@ -146,9 +161,20 @@ pub struct TransactionInfo { #[derivative(Debug, Clone, PartialEq)] pub struct TransactionList { pub ids: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub transactions: Vec, } +#[derive(TlRead, TlWrite, Derivative)] +#[derivative(Debug, Clone, PartialEq)] +pub struct TransactionMetadata { + #[tl(flags)] + mode: (), + depth: u32, + initiator: AccountId, + initiator_lt: u64, +} + #[derive(TlRead, TlWrite, Derivative)] #[derivative(Debug, Clone, PartialEq)] pub struct TransactionId { @@ -160,6 +186,8 @@ pub struct TransactionId { pub lt: Option, #[tl(flags_bit = "mode.2")] pub hash: Option, + #[tl(flags_bit = "mode.8")] + pub metadata: Option, } #[derive(TlRead, TlWrite, Derivative)] @@ -169,6 +197,7 @@ pub struct BlockTransactions { pub req_count: u32, pub incomplete: bool, pub ids: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub proof: Vec, } @@ -187,7 +216,9 @@ pub struct ConfigInfo { #[tl(flags)] pub mode: (), pub id: BlockIdExt, + #[derivative(Debug(format_with = "fmt_bytes"))] pub state_proof: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub config_proof: Vec, #[tl(flags_bit = "mode.0")] pub with_state_root: Option<()>, @@ -221,7 +252,9 @@ pub struct ValidatorStats { pub id: BlockIdExt, pub count: u32, pub complete: bool, + #[derivative(Debug(format_with = "fmt_bytes"))] pub state_proof: Vec, + #[derivative(Debug(format_with = "fmt_bytes"))] pub data_proof: Vec, } @@ -299,7 +332,7 @@ pub enum Response { #[tl(id = 0x6f26c60b)] TransactionList(TransactionList), - /// liteServer.transactionId mode:# account:mode.0?int256 lt:mode.1?long hash:mode.2?int256 = liteServer.TransactionId; + /// liteServer.transactionId mode:# account:mode.0?int256 lt:mode.1?long hash:mode.2?int256 metadata:mode.8?liteServer.transactionMetadata = liteServer.TransactionId; #[tl(id = 0xb12f65af)] TransactionId(TransactionId), diff --git a/liteapi/src/tl/utils.rs b/liteapi/src/tl/utils.rs index 3bbccd6..21c3265 100644 --- a/liteapi/src/tl/utils.rs +++ b/liteapi/src/tl/utils.rs @@ -27,6 +27,14 @@ pub fn fmt_bytes(bytes: &[u8], f: &mut std::fmt::Formatter) -> Result<(), std::f write!(f, "0x{}", hex::encode(bytes)) } +pub fn fmt_opt_bytes>(bytes: &Option, f: &mut std::fmt::Formatter) -> Result<(), std::fmt::Error> { + if let Some(bytes) = bytes { + write!(f, "Some(0x{})", hex::encode(bytes)) + } else { + write!(f, "None") + } +} + pub mod struct_as_bytes { use tl_proto::{TlPacket, TlRead, TlResult, TlWrite}; diff --git a/network-config/src/lib.rs b/network-config/src/lib.rs index b9545b2..711aeac 100644 --- a/network-config/src/lib.rs +++ b/network-config/src/lib.rs @@ -43,11 +43,10 @@ impl FromStr for ConfigGlobal { } } -#[cfg(feature = "adnl")] -impl AdnlPublicKey for ConfigPublicKey { - fn to_bytes(&self) -> [u8; 32] { +impl Into<[u8; 32]> for ConfigPublicKey { + fn into(self) -> [u8; 32] { match self { - ConfigPublicKey::Ed25519 { key } => *key, + ConfigPublicKey::Ed25519 { key } => key, } } }