diff --git a/CHANGELOG.md b/CHANGELOG.md index cca682d2d..74a491d65 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,15 @@ All notable changes to this project will be documented in this file. +## [1.24.0] – 2021-10-18 + +### New +- `boc.get_boc_depth` function to get depth of the provided boc. +- `boc.decode_tvc` function returns additional fields `code_hash`, `code_depth`, `data_hash`, `data_depth` and `compiler_version` + +- **Debot module**: + - added `parse` function to Json interface. + ## [1.23.0] – 2021-10-05 ### New diff --git a/api/derive/Cargo.toml b/api/derive/Cargo.toml index c9fd5ae50..881ec3278 100644 --- a/api/derive/Cargo.toml +++ b/api/derive/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "api_derive" -version = "1.23.0" +version = "1.24.0" authors = ["TON DEV SOLUTIONS LTD "] edition = "2018" diff --git a/api/info/Cargo.toml b/api/info/Cargo.toml index 3937b42cd..e3759263d 100644 --- a/api/info/Cargo.toml +++ b/api/info/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "api_info" -version = "1.23.0" +version = "1.24.0" authors = ["TON DEV SOLUTIONS LTD "] edition = "2018" diff --git a/api/test/Cargo.toml b/api/test/Cargo.toml index 179b70271..6a33d9136 100644 --- a/api/test/Cargo.toml +++ b/api/test/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "api_test" -version = "1.23.0" +version = "1.24.0" authors = ["TON DEV SOLUTIONS LTD "] edition = "2018" diff --git a/docs/mod_boc.md b/docs/mod_boc.md index efccf7102..2837fb744 100644 --- a/docs/mod_boc.md +++ b/docs/mod_boc.md @@ -18,6 +18,8 @@ BOC manipulation module. [get_boc_hash](#get_boc_hash) – Calculates BOC root hash +[get_boc_depth](#get_boc_depth) – Calculates BOC depth + [get_code_from_tvc](#get_code_from_tvc) – Extracts code from TVC contract image [cache_get](#cache_get) – Get BOC from cache @@ -57,6 +59,10 @@ BOC manipulation module. [ResultOfGetBocHash](#ResultOfGetBocHash) +[ParamsOfGetBocDepth](#ParamsOfGetBocDepth) + +[ResultOfGetBocDepth](#ResultOfGetBocDepth) + [ParamsOfGetCodeFromTvc](#ParamsOfGetCodeFromTvc) [ResultOfGetCodeFromTvc](#ResultOfGetCodeFromTvc) @@ -287,7 +293,7 @@ function get_boc_hash( ): Promise; ``` ### Parameters -- `boc`: _string_ – BOC encoded as base64 +- `boc`: _string_ – BOC encoded as base64 or BOC handle ### Result @@ -295,6 +301,32 @@ function get_boc_hash( - `hash`: _string_ – BOC root hash encoded with hex +## get_boc_depth + +Calculates BOC depth + +```ts +type ParamsOfGetBocDepth = { + boc: string +} + +type ResultOfGetBocDepth = { + depth: number +} + +function get_boc_depth( + params: ParamsOfGetBocDepth, +): Promise; +``` +### Parameters +- `boc`: _string_ – BOC encoded as base64 or BOC handle + + +### Result + +- `depth`: _number_ – BOC root cell depth + + ## get_code_from_tvc Extracts code from TVC contract image @@ -500,11 +532,16 @@ type ParamsOfDecodeTvc = { type ResultOfDecodeTvc = { code?: string, + code_hash?: string, + code_depth?: number, data?: string, + data_hash?: string, + data_depth?: number, library?: string, tick?: boolean, tock?: boolean, - split_depth?: number + split_depth?: number, + compiler_version?: string } function decode_tvc( @@ -519,13 +556,18 @@ function decode_tvc( ### Result - `code`?: _string_ – Contract code BOC encoded as base64 or BOC handle +- `code_hash`?: _string_ – Contract code hash +- `code_depth`?: _number_ – Contract code depth - `data`?: _string_ – Contract data BOC encoded as base64 or BOC handle +- `data_hash`?: _string_ – Contract data hash +- `data_depth`?: _number_ – Contract data depth - `library`?: _string_ – Contract library BOC encoded as base64 or BOC handle - `tick`?: _boolean_ – `special.tick` field.
Specifies the contract ability to handle tick transactions - `tock`?: _boolean_ – `special.tock` field.
Specifies the contract ability to handle tock transactions - `split_depth`?: _number_ – Is present and non-zero only in instances of large smart contracts +- `compiler_version`?: _string_ – Compiler version, for example 'sol 0.49.0' ## encode_tvc @@ -706,7 +748,7 @@ type ParamsOfGetBocHash = { boc: string } ``` -- `boc`: _string_ – BOC encoded as base64 +- `boc`: _string_ – BOC encoded as base64 or BOC handle ## ResultOfGetBocHash @@ -718,6 +760,24 @@ type ResultOfGetBocHash = { - `hash`: _string_ – BOC root hash encoded with hex +## ParamsOfGetBocDepth +```ts +type ParamsOfGetBocDepth = { + boc: string +} +``` +- `boc`: _string_ – BOC encoded as base64 or BOC handle + + +## ResultOfGetBocDepth +```ts +type ResultOfGetBocDepth = { + depth: number +} +``` +- `depth`: _number_ – BOC root cell depth + + ## ParamsOfGetCodeFromTvc ```ts type ParamsOfGetCodeFromTvc = { @@ -928,21 +988,31 @@ type ParamsOfDecodeTvc = { ```ts type ResultOfDecodeTvc = { code?: string, + code_hash?: string, + code_depth?: number, data?: string, + data_hash?: string, + data_depth?: number, library?: string, tick?: boolean, tock?: boolean, - split_depth?: number + split_depth?: number, + compiler_version?: string } ``` - `code`?: _string_ – Contract code BOC encoded as base64 or BOC handle +- `code_hash`?: _string_ – Contract code hash +- `code_depth`?: _number_ – Contract code depth - `data`?: _string_ – Contract data BOC encoded as base64 or BOC handle +- `data_hash`?: _string_ – Contract data hash +- `data_depth`?: _number_ – Contract data depth - `library`?: _string_ – Contract library BOC encoded as base64 or BOC handle - `tick`?: _boolean_ – `special.tick` field.
Specifies the contract ability to handle tick transactions - `tock`?: _boolean_ – `special.tock` field.
Specifies the contract ability to handle tock transactions - `split_depth`?: _number_ – Is present and non-zero only in instances of large smart contracts +- `compiler_version`?: _string_ – Compiler version, for example 'sol 0.49.0' ## ParamsOfEncodeTvc diff --git a/docs/modules.md b/docs/modules.md index 3061f0ef3..641c8e874 100644 --- a/docs/modules.md +++ b/docs/modules.md @@ -151,6 +151,8 @@ Where: [get_boc_hash](mod_boc.md#get_boc_hash) – Calculates BOC root hash +[get_boc_depth](mod_boc.md#get_boc_depth) – Calculates BOC depth + [get_code_from_tvc](mod_boc.md#get_code_from_tvc) – Extracts code from TVC contract image [cache_get](mod_boc.md#cache_get) – Get BOC from cache diff --git a/ton_client/Cargo.toml b/ton_client/Cargo.toml index b0b83f35e..a6ed95ea7 100644 --- a/ton_client/Cargo.toml +++ b/ton_client/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "ton_client" -version = "1.23.0" +version = "1.24.0" authors = ["TON DEV SOLUTIONS LTD "] edition = "2018" license = "Apache-2.0" @@ -20,12 +20,12 @@ api_derive = { path = "../api/derive" } api_info = { path = "../api/info" } ton_sdk = { path = "../ton_sdk", default-features = false } -ton_abi = { git = "https://github.com/tonlabs/ton-labs-abi.git" } -ton_block = { git = "https://github.com/tonlabs/ton-labs-block.git" } -ton_block_json = { git = "https://github.com/tonlabs/ton-labs-block-json.git" } -ton_executor = { git = "https://github.com/tonlabs/ton-labs-executor.git", default-features = false } -ton_types = { git = "https://github.com/tonlabs/ton-labs-types.git" } -ton_vm = { git = "https://github.com/tonlabs/ton-labs-vm.git", default-features = false } +ton_abi = { git = "https://github.com/tonlabs/ton-labs-abi.git", tag = "2.1.1" } +ton_block = { git = "https://github.com/tonlabs/ton-labs-block.git", tag = "1.7.27" } +ton_block_json = { git = "https://github.com/tonlabs/ton-labs-block-json.git", tag = "0.6.24" } +ton_executor = { git = "https://github.com/tonlabs/ton-labs-executor.git", tag = "1.15.31", default-features = false } +ton_types = { git = "https://github.com/tonlabs/ton-labs-types.git", tag = "1.10.10" } +ton_vm = { git = "https://github.com/tonlabs/ton-labs-vm.git", tag = "1.8.19", default-features = false } lockfree = { git = "https://github.com/tonlabs/lockfree.git", package = "lockfree" } sodalite = { git = "https://github.com/tonlabs/sodalite.git", features = ["rand"] } @@ -63,6 +63,8 @@ serde_repr = "0.1.7" sha2 = "0.9.5" tokio = { version = "0.2.13", features = ["sync", "stream"], default-features = false } zstd = { version = "0.7.0", default-features = false } +# TODO: remove fixed versioning when indexmap compilation issue is resolved +indexmap = "=1.6.2" # TODO: remove fixed versioning when tiny-bip39 compilation issue is resolved tiny-bip39 = "=0.7.3" diff --git a/ton_client/src/boc/cache.rs b/ton_client/src/boc/cache.rs index e1f4dbac4..4787f74e5 100644 --- a/ton_client/src/boc/cache.rs +++ b/ton_client/src/boc/cache.rs @@ -19,6 +19,8 @@ use super::Error; use lru::LruCache; use std::collections::{HashMap, HashSet}; use std::sync::Arc; +#[allow(unused_imports)] +use std::str::FromStr; use tokio::sync::{Mutex, RwLock}; use ton_types::{Cell, UInt256}; diff --git a/ton_client/src/boc/hash.rs b/ton_client/src/boc/common.rs similarity index 64% rename from ton_client/src/boc/hash.rs rename to ton_client/src/boc/common.rs index 235b197f5..b19efb272 100644 --- a/ton_client/src/boc/hash.rs +++ b/ton_client/src/boc/common.rs @@ -17,7 +17,7 @@ use crate::error::ClientResult; #[derive(Serialize, Deserialize, Clone, ApiType, Default)] pub struct ParamsOfGetBocHash { - /// BOC encoded as base64 + /// BOC encoded as base64 or BOC handle pub boc: String, } @@ -37,3 +37,27 @@ pub async fn get_boc_hash( let hash = cell.repr_hash().as_hex_string(); Ok(ResultOfGetBocHash { hash }) } + +#[derive(Serialize, Deserialize, Clone, ApiType, Default)] +pub struct ParamsOfGetBocDepth { + /// BOC encoded as base64 or BOC handle + pub boc: String, +} + +#[derive(Serialize, Deserialize, Clone, ApiType, Default)] +pub struct ResultOfGetBocDepth { + /// BOC root cell depth + pub depth: u32, +} + +/// Calculates BOC depth +#[api_function] +pub async fn get_boc_depth( + context: std::sync::Arc, + params: ParamsOfGetBocDepth, +) -> ClientResult { + let (_, cell) = deserialize_cell_from_boc(&context, ¶ms.boc, "").await?; + Ok(ResultOfGetBocDepth { + depth: cell.repr_depth() as u32 + }) +} diff --git a/ton_client/src/boc/internal.rs b/ton_client/src/boc/internal.rs index 510d71c82..95b9c5612 100644 --- a/ton_client/src/boc/internal.rs +++ b/ton_client/src/boc/internal.rs @@ -11,9 +11,11 @@ * limitations under the License. */ -use crate::{ClientContext}; +use crate::ClientContext; use crate::boc::{BocCacheType, Error}; use crate::error::ClientResult; +#[allow(unused_imports)] +use std::str::FromStr; use ton_block::{Deserializable, Serializable}; use ton_types::{UInt256, deserialize_tree_of_cells}; diff --git a/ton_client/src/boc/mod.rs b/ton_client/src/boc/mod.rs index dda12a5f9..89c5324cc 100644 --- a/ton_client/src/boc/mod.rs +++ b/ton_client/src/boc/mod.rs @@ -17,7 +17,7 @@ pub(crate) mod blockchain_config; pub(crate) mod cache; pub(crate) mod encode; mod errors; -pub(crate) mod hash; +pub(crate) mod common; pub(crate) mod internal; pub(crate) mod parse; pub(crate) mod tvc; @@ -34,7 +34,10 @@ pub use cache::{ }; pub use encode::{encode_boc, BuilderOp, ParamsOfEncodeBoc, ResultOfEncodeBoc}; pub use errors::{Error, ErrorCode}; -pub use hash::{get_boc_hash, ParamsOfGetBocHash, ResultOfGetBocHash}; +pub use common::{ + get_boc_depth, get_boc_hash, + ParamsOfGetBocDepth, ResultOfGetBocDepth, ParamsOfGetBocHash, ResultOfGetBocHash, +}; pub use parse::{ parse_account, parse_block, parse_message, parse_shardstate, parse_transaction, required_boc, source_boc, ParamsOfParse, ParamsOfParseShardstate, ResultOfParse, diff --git a/ton_client/src/boc/tests.rs b/ton_client/src/boc/tests.rs index 4c330e1ee..9736d77b3 100644 --- a/ton_client/src/boc/tests.rs +++ b/ton_client/src/boc/tests.rs @@ -368,6 +368,20 @@ fn get_boc_hash() { ); } +#[test] +fn get_boc_depth() { + let client = TestClient::new(); + + let result: super::ResultOfGetBocDepth = client.request( + "boc.get_boc_depth", + super::ParamsOfGetBocDepth { + boc: base64::encode(include_bytes!("test_data/account.boc")) + } + ).unwrap(); + + assert_eq!(result.depth, 8); +} + #[test] fn get_code_from_tvc() { let client = TestClient::new(); @@ -667,14 +681,19 @@ fn check_encode_tvc(client: &TestClient, tvc: String, decoded: ResultOfDecodeTvc fn test_tvc_encode() { let client = TestClient::new(); - let tvc = TestClient::tvc(crate::tests::GIVER_V2, Some(2)); + let tvc = TestClient::tvc("t24_initdata", Some(2)); let decoded = ResultOfDecodeTvc { - code: Some(String::from("te6ccgECFAEAA6EAAib/APSkICLAAZL0oOGK7VNYMPShAwEBCvSkIPShAgAAAgEgBgQB/P9/Ie1E0CDXScIBn9P/0wD0Bfhqf/hh+Gb4Yo4b9AVt+GpwAYBA9A7yvdcL//hicPhjcPhmf/hh4tMAAY4SgQIA1xgg+QFY+EIg+GX5EPKo3iP4QvhFIG6SMHDeuvLgZSHTP9MfNDH4IyEBvvK5IfkAIPhKgQEA9A4gkTHeswUATvLgZvgAIfhKIgFVAcjLP1mBAQD0Q/hqIwRfBNMfAfAB+EdukvI83gIBIAwHAgFYCwgBCbjomPxQCQH++EFujhLtRNDT/9MA9AX4an/4Yfhm+GLe0XBtbwL4SoEBAPSGlQHXCz9/k3BwcOKRII43IyMjbwJvIsgizwv/Ic8LPzExAW8iIaQDWYAg9ENvAjQi+EqBAQD0fJUB1ws/f5NwcHDiAjUzMehfA8iCEHdEx+KCEIAAAACxzwsfIQoAom8iAssf9ADIglhgAAAAAAAAAAAAAAAAzwtmgQOYIs8xAbmWcc9AIc8XlXHPQSHN4iDJcfsAWzDA/44S+ELIy//4Rs8LAPhKAfQAye1U3n/4ZwDFuRar5/8ILdHG3aiaBBrpOEAz+n/6YB6Avw1P/ww/DN8MUcN+gK2/DU4AMAgegd5XuuF//wxOHwxuHwzP/ww8W98I0l5Gcm4/DNxfABo/CFkZf/8I2eFgHwlAPoAZPaqP/wzwAgEgDw0B17sV75NfhBbo4S7UTQ0//TAPQF+Gp/+GH4Zvhi3vpA1w1/ldTR0NN/39cMAJXU0dDSAN/RIiIic8hxzwsBIs8KAHPPQCTPFiP6AoBpz0Byz0AgySL7AF8F+EqBAQD0hpUB1ws/f5NwcHDikSCA4Ako4t+CMiAbuf+EojASEBgQEA9FswMfhq3iL4SoEBAPR8lQHXCz9/k3BwcOICNTMx6F8DXwP4QsjL//hGzwsA+EoB9ADJ7VR/+GcCASAREADHuORhh18ILdHCXaiaGn/6YB6Avw1P/ww/DN8MW9qaPwhfCKQN0kYOG9deXAy/AB8IWRl//wjZ4WAfCUA+gBk9qp8B5B9ghBodo92qfgBGHwhZGX//CNnhYB8JQD6AGT2qj/8M8AIC2hMSAC2vhCyMv/+EbPCwD4SgH0AMntVPgP8gCAB1pwIccAnSLQc9ch1wsAwAGQkOLgIdcNH5LyPOFTEcAAkODBAyKCEP////28sZLyPOAB8AH4R26S8jzeg=")), - data: Some(String::from("te6ccgEBBQEANQABAcABAgPPIAQCAQHeAwAD0CAAQdgAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAABA==")), + code: Some(String::from("te6ccgECEAEAAYkABCSK7VMg4wMgwP/jAiDA/uMC8gsNAgEPAoTtRNDXScMB+GYh2zzTAAGfgQIA1xgg+QFY+EL5EPKo3tM/AfhDIbnytCD4I4ED6KiCCBt3QKC58rT4Y9MfAds88jwFAwNK7UTQ10nDAfhmItDXCwOpOADcIccA4wIh1w0f8rwh4wMB2zzyPAwMAwIoIIIQBoFGw7rjAiCCEGi1Xz+64wIIBAIiMPhCbuMA+Ebyc9H4ANs88gAFCQIW7UTQ10nCAYqOgOILBgFccO1E0PQFcSGAQPQOk9cLB5Fw4vhqciGAQPQPjoDf+GuAQPQO8r3XC//4YnD4YwcBAogPA3Aw+Eby4Ez4Qm7jANHbPCKOICTQ0wH6QDAxyM+HIM6AYs9AXgHPkhoFGw7LB8zJcPsAkVvi4wDyAAsKCQAq+Ev4SvhD+ELIy//LP8+DywfMye1UAAj4SvhLACztRNDT/9M/0wAx0wfU0fhr+Gr4Y/hiAAr4RvLgTAIK9KQg9KEPDgAUc29sIDAuNTEuMAAA")), + code_depth: Some(7), + code_hash: Some(String::from("0ad23f96d7b1c1ce78dae573ac8cdf71523dc30f36316b5aaa5eb3cc540df0e0")), + data: Some(String::from("te6ccgEBAgEAKAABAcABAEPQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAg")), + data_depth: Some(1), + data_hash: Some(String::from("55a703465a160dce20481375de2e5b830c841c2787303835eb5821d62d65ca9d")), library: None, split_depth: None, tick: None, tock: None, + compiler_version: Some("sol 0.51.0".to_owned()), }; check_encode_tvc(&client, tvc, decoded); @@ -682,11 +701,16 @@ fn test_tvc_encode() { let tvc = base64::encode(include_bytes!("test_data/state_init_lib.boc")); let decoded = ResultOfDecodeTvc { code: Some(String::from("te6ccgEBBAEAhwABFP8A9KQT9LzyyAsBAgEgAwIA36X//3aiaGmP6f/o5CxSZ4WPkOeF/+T2qmRnxET/s2X/wQgC+vCAfQFANeegZLh9gEB354V/wQgD39JAfQFANeegZLhkZ82JA6Mrm6RBCAOt5or9AUA156BF6kMrY2N5YQO7e5NjIQxni2S4fYB9gEAAAtI=")), + code_depth: Some(2), + code_hash: Some(String::from("45910e27fe37d8dcf1fac777ebb3bda38ae1ea8389f81bfb1bc0079f3f67ef5b")), data: Some(String::from("te6ccgEBAQEAJgAASBHvVgMAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA==")), + data_depth: Some(0), + data_hash: Some(String::from("97bfef744b0d45f78b901e2997fb55f6dbc1d396a8d2f8f4c3a5468c010db67a")), library: Some(String::from("te6ccgEBBgEAYAACAWIEAQFCv0EkKSBepm1vIATt+lcPb1az6F5ZuqG++8c7faXVW9xhAgEEEjQDAARWeAFCv1ou71BWd19blXL/OtY90qcdH7KByhd6Xhx0cw7MsuUTBQAPq6yrrausq6g=")), split_depth: None, tick: Some(true), tock: Some(true), + compiler_version: None, }; check_encode_tvc(&client, tvc, decoded); diff --git a/ton_client/src/boc/tvc.rs b/ton_client/src/boc/tvc.rs index 6aafa0bb6..c9e80ddc9 100644 --- a/ton_client/src/boc/tvc.rs +++ b/ton_client/src/boc/tvc.rs @@ -215,23 +215,28 @@ pub struct ResultOfGetCompilerVersion { pub version: Option, } -/// Returns the compiler version used to compile the code. -#[api_function] -pub async fn get_compiler_version( - context: std::sync::Arc, - params: ParamsOfGetCompilerVersion, -) -> ClientResult { - let (_, code) = deserialize_cell_from_boc(&context, ¶ms.code, "contract code").await?; - +pub fn get_compiler_version_from_cell( + code: Cell, +) -> ClientResult> { let (_, version) = get_salt_and_ver(code)?; - let version = version.map(|cell| { + version.map(|cell| { let bytes = cell.data(); String::from_utf8(bytes[..bytes.len() - 1].to_vec()) .map_err(|err| Error::invalid_boc( format!("can not convert version cell to string: {}", err))) }) - .transpose()?; + .transpose() +} + +/// Returns the compiler version used to compile the code. +#[api_function] +pub async fn get_compiler_version( + context: std::sync::Arc, + params: ParamsOfGetCompilerVersion, +) -> ClientResult { + let (_, code) = deserialize_cell_from_boc(&context, ¶ms.code, "contract code").await?; + let version = get_compiler_version_from_cell(code)?; Ok(ResultOfGetCompilerVersion { version }) } @@ -312,8 +317,16 @@ pub struct ParamsOfDecodeTvc { pub struct ResultOfDecodeTvc { /// Contract code BOC encoded as base64 or BOC handle pub code: Option, + /// Contract code hash + pub code_hash: Option, + /// Contract code depth + pub code_depth: Option, /// Contract data BOC encoded as base64 or BOC handle pub data: Option, + /// Contract data hash + pub data_hash: Option, + /// Contract data depth + pub data_depth: Option, /// Contract library BOC encoded as base64 or BOC handle pub library: Option, /// `special.tick` field. Specifies the contract ability to handle tick transactions @@ -322,6 +335,8 @@ pub struct ResultOfDecodeTvc { pub tock: Option, /// Is present and non-zero only in instances of large smart contracts pub split_depth: Option, + /// Compiler version, for example 'sol 0.49.0' + pub compiler_version: Option, } /// Decodes tvc into code, data, libraries and special options. @@ -341,16 +356,31 @@ pub async fn decode_tvc( Ok(None) } }}; + let code_depth = tvc.object.code.as_ref().map(|cell| cell.repr_depth() as u32); + let code_hash = tvc.object.code.as_ref().map(|cell| cell.repr_hash().as_hex_string()); + let compiler_version = tvc.object.code.clone() + .map(|cell| get_compiler_version_from_cell(cell).ok()) + .flatten() + .flatten(); let code = serialize("code", tvc.object.code, params.boc_cache.clone()).await?; + + let data_depth = tvc.object.data.as_ref().map(|cell| cell.repr_depth() as u32); + let data_hash = tvc.object.data.as_ref().map(|cell| cell.repr_hash().as_hex_string()); let data = serialize("data", tvc.object.data, params.boc_cache.clone()).await?; + let library = serialize("library", tvc.object.library.root().cloned(), params.boc_cache.clone()).await?; Ok(ResultOfDecodeTvc { code, + code_depth, + code_hash, data, + data_depth, + data_hash, library, tick: tvc.object.special.as_ref().map(|val| val.tick), tock: tvc.object.special.as_ref().map(|val| val.tick), split_depth: tvc.object.split_depth.map(|val| val.0), + compiler_version, }) } diff --git a/ton_client/src/crypto/mod.rs b/ton_client/src/crypto/mod.rs index 9e391ab94..d7513e5ed 100644 --- a/ton_client/src/crypto/mod.rs +++ b/ton_client/src/crypto/mod.rs @@ -36,7 +36,8 @@ pub use crate::crypto::boxes::signing_box::{ pub use crate::crypto::boxes::encryption_box::{ register_encryption_box, remove_encryption_box, create_encryption_box, encryption_box_get_info, encryption_box_encrypt, encryption_box_decrypt, - CipherMode, RegisteredEncryptionBox, EncryptionBoxHandle, EncryptionBoxInfo, EncryptionAlgorithm, + EncryptionBox, CipherMode, RegisteredEncryptionBox, EncryptionBoxHandle, + EncryptionBoxInfo, EncryptionAlgorithm, ParamsOfEncryptionBoxGetInfo, ResultOfEncryptionBoxGetInfo, ParamsOfEncryptionBoxEncrypt, ResultOfEncryptionBoxEncrypt, ParamsOfEncryptionBoxDecrypt, ResultOfEncryptionBoxDecrypt, diff --git a/ton_client/src/debot/json_interface.rs b/ton_client/src/debot/json_interface.rs index faa0392fd..521f21e3d 100644 --- a/ton_client/src/debot/json_interface.rs +++ b/ton_client/src/debot/json_interface.rs @@ -1,9 +1,8 @@ -use super::dinterface::{ - decode_answer_id, get_string_arg, DebotInterface, InterfaceResult, -}; +use super::dinterface::{decode_answer_id, get_string_arg, DebotInterface, InterfaceResult}; use crate::abi::Abi; -use serde_json::Value; -use ton_abi::{Contract, param_type::ParamType, Param}; +use crate::debot::json_lib_utils::pack; +use serde_json::Value as JsonValue; +use ton_abi::{Contract, Param, ParamType}; const ABI: &str = r#" { @@ -19,6 +18,17 @@ const ABI: &str = r#" "outputs": [ {"name":"result","type":"bool"} ] + }, + { + "name": "parse", + "inputs": [ + {"name":"answerId","type":"uint32"}, + {"name":"json","type":"bytes"} + ], + "outputs": [ + {"name":"result","type":"bool"}, + {"components":[{"name":"kind","type":"uint8"},{"name":"value","type":"cell"},{"name":"object","type":"map(uint256,cell)"},{"components":[{"name":"cell","type":"cell"}],"name":"array","type":"tuple[]"}],"name":"obj","type":"tuple"} + ] } ], "data": [ @@ -36,13 +46,15 @@ pub struct JsonInterface { impl JsonInterface { pub fn new(abi: &str) -> Self { - Self { debot_abi: abi.to_owned() } + Self { + debot_abi: abi.to_owned(), + } } - fn deserialize(&self, args: &Value) -> InterfaceResult { + fn deserialize(&self, args: &JsonValue) -> InterfaceResult { let answer_id = decode_answer_id(args)?; let json_str = get_string_arg(args, "json")?; - let mut json_obj: Value = serde_json::from_str(&json_str) + let mut json_obj: JsonValue = serde_json::from_str(&json_str) .map_err(|e| format!("argument \"json\" is not a valid json: {}", e))?; let _ = self.deserialize_json(&mut json_obj, answer_id)?; Ok(( @@ -54,12 +66,31 @@ impl JsonInterface { )) } - fn deserialize_json(&self, json_obj: &mut Value, answer_id: u32) -> Result<(), String> { - let contract = Contract::load(self.debot_abi.as_bytes()) - .map_err(|e| format!("{}", e))?; - let func = contract.function_by_id(answer_id, true) + fn parse(&self, args: &JsonValue) -> InterfaceResult { + let answer_id = decode_answer_id(args)?; + let json_str = get_string_arg(args, "json")?; + let json_obj: JsonValue = serde_json::from_str(&json_str) + .map_err(|e| format!("argument \"json\" is not a valid json: {}", e))?; + let result = pack(json_obj); + Ok(( + answer_id, + json!({ + "result": true, + "obj": result, + }), + )) + } + + fn deserialize_json(&self, json_obj: &mut JsonValue, answer_id: u32) -> Result<(), String> { + let contract = Contract::load(self.debot_abi.as_bytes()).map_err(|e| format!("{}", e))?; + let func = contract + .function_by_id(answer_id, true) .map_err(|_| format!("function with id {} not found", answer_id))?; - let obj = func.inputs.iter().find(|e| e.name == "obj").ok_or(format!("\"obj\" argument not found"))?; + let obj = func + .inputs + .iter() + .find(|e| e.name == "obj") + .ok_or(format!("\"obj\" argument not found"))?; if let ParamType::Tuple(params) = &obj.kind { for p in params { let pointer = ""; @@ -69,49 +100,56 @@ impl JsonInterface { Ok(()) } - fn bypass_json(&self, top_pointer: &str, obj: &mut Value, p: Param) -> Result<(), String> { + fn bypass_json(&self, top_pointer: &str, obj: &mut JsonValue, p: Param) -> Result<(), String> { let pointer = format!("{}/{}", top_pointer, p.name); if let None = obj.pointer(&pointer) { self.try_replace_hyphens(obj, top_pointer, &p.name)?; } match p.kind { ParamType::Bytes => { - Self::string_to_hex(obj, &pointer) - .map_err(|e| format!("{}: \"{}\"", e, p.name))?; - }, + Self::string_to_hex(obj, &pointer).map_err(|e| format!("{}: \"{}\"", e, p.name))?; + } ParamType::Tuple(params) => { for p in params { self.bypass_json(&pointer, obj, p)?; } - }, + } ParamType::Array(ref elem_type) => { - let elem_count = obj.pointer(&pointer) + let elem_count = obj + .pointer(&pointer) .ok_or_else(|| format!("\"{}\" not found", pointer))? .as_array() - .unwrap().len(); + .ok_or_else(|| String::from("Failed to retrieve an array"))? + .len(); for i in 0..elem_count { - self.bypass_json(&pointer, obj, Param::new(&i.to_string(), (**elem_type).clone()))?; + self.bypass_json( + &pointer, + obj, + Param::new(&i.to_string(), (**elem_type).clone()), + )?; } - }, + } ParamType::Map(_, ref value) => { - let keys: Vec = obj.pointer(&pointer) + let keys: Vec = obj + .pointer(&pointer) .ok_or_else(|| format!("\"{}\" not found", pointer))? .as_object() - .unwrap() + .ok_or_else(|| String::from("Failed to retrieve an object"))? .keys() .map(|k| k.clone()) .collect(); for key in keys { self.bypass_json(&pointer, obj, Param::new(key.as_str(), (**value).clone()))?; } - }, + } _ => (), } Ok(()) } - fn string_to_hex(obj: &mut Value, pointer: &str) -> Result<(), String> { - let val_str = obj.pointer(pointer) + fn string_to_hex(obj: &mut JsonValue, pointer: &str) -> Result<(), String> { + let val_str = obj + .pointer(pointer) .ok_or_else(|| format!("argument not found"))? .as_str() .ok_or_else(|| format!("argument not a string"))?; @@ -119,7 +157,12 @@ impl JsonInterface { Ok(()) } - fn try_replace_hyphens(&self, obj: &mut Value, pointer: &str, name: &str) -> Result<(), String> { + fn try_replace_hyphens( + &self, + obj: &mut JsonValue, + pointer: &str, + name: &str, + ) -> Result<(), String> { if name.contains('_') { match obj.pointer_mut(pointer) { Some(subobj) => { @@ -127,7 +170,7 @@ impl JsonInterface { if let Some(value) = map.remove(&name.replace('_', "-")) { map.insert(name.to_owned(), value); } - }, + } None => Err(format!("key not found: \"{}\"", name))?, } } @@ -145,9 +188,10 @@ impl DebotInterface for JsonInterface { Abi::Json(ABI.to_owned()) } - async fn call(&self, func: &str, args: &Value) -> InterfaceResult { + async fn call(&self, func: &str, args: &JsonValue) -> InterfaceResult { match func { "deserialize" => self.deserialize(args), + "parse" => self.parse(args), _ => Err(format!("function \"{}\" is not implemented", func)), } } diff --git a/ton_client/src/debot/json_lib_utils.rs b/ton_client/src/debot/json_lib_utils.rs new file mode 100644 index 000000000..bfe6b3080 --- /dev/null +++ b/ton_client/src/debot/json_lib_utils.rs @@ -0,0 +1,140 @@ +use crate::boc::internal::{deserialize_cell_from_base64, serialize_cell_to_base64}; +use serde_json::Value as JsonValue; +use sha2::Digest; +use std::collections::HashMap; +use ton_abi::{contract::ABI_VERSION_2_0, token::Tokenizer, Param, ParamType, TokenValue}; + +use serde_repr::{Deserialize_repr, Serialize_repr}; +#[derive(Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum ValKind { + String = 0, + Number = 1, + Bool = 2, + Array = 3, + Object = 4, + Null = 5, + Cell = 6, +} + +impl Default for ValKind { + fn default() -> Self { + ValKind::Null + } +} + +#[derive(Serialize, Deserialize, Default)] +struct Cell { + cell: String, +} + +#[derive(Serialize, Deserialize, Default)] +pub struct Value { + kind: ValKind, + value: String, + object: HashMap, + array: Vec, +} + +impl Value { + fn new_null() -> Self { + Self::default() + } + + fn new_bool(v: bool) -> Option { + let mut val = Self::default(); + val.kind = ValKind::Bool; + val.value = Self::serialize(ParamType::Bool, json!(v))?; + Some(val) + } + + fn new_number(v: i64) -> Option { + let mut val = Self::default(); + val.kind = ValKind::Number; + val.value = Self::serialize(ParamType::Int(256), json!(v))?; + Some(val) + } + + fn new_string(v: String) -> Option { + let mut val = Self::default(); + val.kind = ValKind::String; + if deserialize_cell_from_base64(&v, "QueryValue").is_ok() { + val.value = v; + val.kind = ValKind::Cell; + } else { + val.value = Self::serialize(ParamType::Bytes, json!(hex::encode(v)))?; + } + Some(val) + } + + fn new_object(map: serde_json::map::Map) -> Option { + let mut val = Self::default(); + val.kind = ValKind::Object; + for (k, v) in map { + let json: JsonValue = serde_json::to_value(pack(v)?).ok()?; + let packed = Self::pack_value_to_cell(json, Some(&k))?; + let mut hasher = sha2::Sha256::new(); + hasher.update(k); + let hash = hasher.finalize(); + val.object + .insert(format!("0x{}", hex::encode(&hash[..])), packed); + } + Some(val) + } + + fn new_array(array: Vec) -> Option { + let mut val = Self::default(); + val.kind = ValKind::Array; + for element in array { + let json: JsonValue = serde_json::to_value(pack(element)?).ok()?; + let packed = Self::pack_value_to_cell(json, None)?; + val.array.push(Cell { cell: packed }); + } + Some(val) + } + + fn pack_value_to_cell(mut json: JsonValue, key: Option<&String>) -> Option { + let mut params = vec![ + Param::new("kind", ParamType::Uint(8)), + Param::new("value", ParamType::Cell), + Param::new( + "object", + ParamType::Map(Box::new(ParamType::Uint(256)), Box::new(ParamType::Cell)), + ), + Param::new("array", ParamType::Array(Box::new(ParamType::Tuple(vec![Param::new("cell", ParamType::Cell)])))), + ]; + if let Some(k) = key { + params.push(Param::new("key", ParamType::Bytes)); + json["key"] = json!(hex::encode(k)); + } + + let tokens = Tokenizer::tokenize_all_params(¶ms, &json).unwrap(); + let builder = + TokenValue::pack_values_into_chain(&tokens[..], vec![], &ABI_VERSION_2_0).unwrap(); + let serialized = + serialize_cell_to_base64(&ton_types::Cell::from(&builder), "QueryValue").ok()?; + Some(serialized) + } + + fn serialize(param_type: ParamType, json: JsonValue) -> Option { + let tokens = Tokenizer::tokenize_all_params( + &[Param::new("arg0", param_type)], + &json!({ "arg0": json }), + ) + .ok()?; + let builder = + TokenValue::pack_values_into_chain(&tokens[..], vec![], &ABI_VERSION_2_0).ok()?; + serialize_cell_to_base64(&ton_types::Cell::from(&builder), "QueryValue").ok() + } +} + +pub fn pack(json_obj: JsonValue) -> Option { + match json_obj { + JsonValue::Null => Some(Value::new_null()), + JsonValue::Bool(v) => Value::new_bool(v), + JsonValue::String(v) => Value::new_string(v), + JsonValue::Number(v) => Value::new_number(v.as_i64()?), + JsonValue::Object(map) => Value::new_object(map), + JsonValue::Array(array) => Value::new_array(array), + } +} diff --git a/ton_client/src/debot/mod.rs b/ton_client/src/debot/mod.rs index 2edab40bb..2e6119026 100644 --- a/ton_client/src/debot/mod.rs +++ b/ton_client/src/debot/mod.rs @@ -1,323 +1,324 @@ -/* -* Copyright 2018-2020 TON DEV SOLUTIONS LTD. -* -* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use -* this file except in compliance with the License. -* -* Unless required by applicable law or agreed to in writing, software -* distributed under the License is distributed on an "AS IS" BASIS, -* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -* See the License for the specific TON DEV software governing permissions and -* limitations under the License. -*/ - -mod action; -mod activity; -mod base64_interface; -mod hex_interface; -mod json_interface; -mod browser; -pub mod calltype; -mod context; -mod debot_abi; -mod dengine; -mod dinterface; -mod errors; -mod helpers; -mod info; -mod msg_interface; -mod network_interface; -mod query_interface; -mod routines; -mod run_output; -mod sdk_interface; -#[cfg(test)] -mod tests; -#[cfg(test)] -mod tests_interfaces; - -#[cfg(not(feature = "wasm"))] -pub use calltype::prepare_ext_in_message; - -pub use action::DAction; -pub use activity::{DebotActivity, Spending}; -pub use browser::BrowserCallbacks; -pub use context::{DContext, STATE_EXIT, STATE_ZERO}; -pub use dengine::DEngine; -pub use dinterface::{DebotInterface, DebotInterfaceExecutor, InterfaceResult}; -pub use errors::{Error, ErrorCode}; -use info::DInfo; -use crate::error::ClientResult; -use crate::ClientContext; -use std::sync::Arc; -use tokio::sync::Mutex; - -pub const DEBOT_WC: i8 = -31; // 0xDB - -type TonClient = Arc; -type JsonValue = serde_json::Value; - -/// [UNSTABLE](UNSTABLE.md) Handle of registered in SDK debot -#[derive(Serialize, Deserialize, Default, ApiType, Clone)] -pub struct DebotHandle(u32); - -/// [UNSTABLE](UNSTABLE.md) Describes a debot action in a Debot Context. -#[derive(Serialize, Deserialize, Clone, Debug, ApiType, Default, PartialEq)] -pub struct DebotAction { - /// A short action description. Should be used by Debot Browser as name of - /// menu item. - pub description: String, - /// Depends on action type. Can be a debot function name or a print string - /// (for Print Action). - pub name: String, - /// Action type. - pub action_type: u8, - /// ID of debot context to switch after action execution. - pub to: u8, - /// Action attributes. In the form of "param=value,flag". - /// attribute example: instant, args, fargs, sign. - pub attributes: String, - /// Some internal action data. Used by debot only. - pub misc: String, -} - -impl From for DebotAction { - fn from(daction: DAction) -> Self { - Self { - description: daction.desc, - name: daction.name, - action_type: daction.action_type as u8, - to: daction.to, - attributes: daction.attrs, - misc: daction.misc, - } - } -} - -impl Into for DebotAction { - fn into(self) -> DAction { - DAction { - desc: self.description, - name: self.name, - action_type: self.action_type.into(), - to: self.to, - attrs: self.attributes, - misc: self.misc, - } - } -} - -/// [UNSTABLE](UNSTABLE.md) Describes DeBot metadata. -#[derive(Serialize, Deserialize, Clone, Debug, ApiType, Default, PartialEq)] -pub struct DebotInfo { - /// DeBot short name. - pub name: Option, - /// DeBot semantic version. - pub version: Option, - /// The name of DeBot deployer. - pub publisher: Option, - /// Short info about DeBot. - pub caption: Option, - /// The name of DeBot developer. - pub author: Option, - /// TON address of author for questions and donations. - pub support: Option, - /// String with the first messsage from DeBot. - pub hello: Option, - /// String with DeBot interface language (ISO-639). - pub language: Option, - /// String with DeBot ABI. - pub dabi: Option, - /// DeBot icon. - pub icon: Option, - /// Vector with IDs of DInterfaces used by DeBot. - pub interfaces: Vec, -} - -impl From for DebotInfo { - fn from(info: DInfo) -> Self { - Self { - name: info.name, - version: info.version, - publisher: info.publisher, - caption: info.caption, - author: info.author, - support: info.support, - hello: info.hello, - language: info.language, - dabi: info.dabi, - icon : info.icon, - interfaces: info.interfaces, - } - } -} - -/// [UNSTABLE](UNSTABLE.md) Parameters to start DeBot. -/// DeBot must be already initialized with init() function. -#[derive(Serialize, Deserialize, Default, ApiType)] -pub struct ParamsOfStart { - /// Debot handle which references an instance of debot engine. - debot_handle: DebotHandle, -} - -/// [UNSTABLE](UNSTABLE.md) Starts the DeBot. -/// -/// Downloads debot smart contract from blockchain and switches it to -/// context zero. -/// -/// This function must be used by Debot Browser to start a dialog with debot. -/// While the function is executing, several Browser Callbacks can be called, -/// since the debot tries to display all actions from the context 0 to the user. -/// -/// When the debot starts SDK registers `BrowserCallbacks` AppObject. -/// Therefore when `debote.remove` is called the debot is being deleted and the callback is called -/// with `finish`=`true` which indicates that it will never be used again. -#[api_function] -pub async fn start( - context: Arc, - params: ParamsOfStart, -) -> ClientResult<()> { - let mutex = context - .debots - .get(¶ms.debot_handle.0) - .ok_or(Error::invalid_handle(params.debot_handle.0))?; - let mut dengine = mutex.1.lock().await; - dengine.start().await.map_err(Error::start_failed) -} - -/// [UNSTABLE](UNSTABLE.md) Parameters to fetch DeBot metadata. -#[derive(Serialize, Deserialize, Default, ApiType)] -pub struct ParamsOfFetch { - /// Debot smart contract address. - pub address: String, -} - -/// [UNSTABLE](UNSTABLE.md) -#[derive(Serialize, Deserialize, Default, ApiType)] -pub struct ResultOfFetch { - /// Debot metadata. - pub info: DebotInfo, -} - -/// [UNSTABLE](UNSTABLE.md) Fetches DeBot metadata from blockchain. -/// -/// Downloads DeBot from blockchain and creates and fetches its metadata. -#[api_function] -pub async fn fetch( - context: Arc, - params: ParamsOfFetch, -) -> ClientResult { - Ok(ResultOfFetch { - info : DEngine::fetch(context, params.address).await.map_err(Error::fetch_failed)?.into() - }) -} - -/// [UNSTABLE](UNSTABLE.md) Parameters to init DeBot. -#[derive(Serialize, Deserialize, Default, ApiType)] -pub struct ParamsOfInit { - /// Debot smart contract address - pub address: String, -} - -/// [UNSTABLE](UNSTABLE.md) Structure for storing debot handle returned from `init` function. -#[derive(Serialize, Deserialize, ApiType, Default)] -pub struct RegisteredDebot { - /// Debot handle which references an instance of debot engine. - pub debot_handle: DebotHandle, - /// Debot abi as json string. - pub debot_abi: String, - /// Debot metadata. - pub info: DebotInfo, -} - -/// [UNSTABLE](UNSTABLE.md) Creates an instance of DeBot. -/// -/// Downloads DeBot smart contract (code and data) from blockchain and creates -/// an instance of Debot Engine for it. -/// Returns a debot handle which can be used later in `start`, `execute` or `send` functions. -/// # Remarks -/// It does not switch debot to context 0. Browser Callbacks are not called. -/// Can be used to invoke DeBot without starting. -pub async fn init( - context: Arc, - params: ParamsOfInit, - callbacks: impl BrowserCallbacks + Send + Sync + 'static, -) -> ClientResult { - let mut dengine = - DEngine::new_with_client(params.address, None, context.clone(), Arc::new(callbacks)); - let info: DebotInfo = dengine.init().await.map_err(Error::fetch_failed)?.into(); - - let handle = context.get_next_id(); - context.debots.insert(handle, Mutex::new(dengine)); - let debot_abi = info.dabi.clone().unwrap_or(String::new()); - Ok(RegisteredDebot { debot_handle: DebotHandle(handle), info, debot_abi }) -} - -/// [UNSTABLE](UNSTABLE.md) Parameters for executing debot action. -#[derive(Serialize, Deserialize, ApiType, Default)] -pub struct ParamsOfExecute { - /// Debot handle which references an instance of debot engine. - pub debot_handle: DebotHandle, - /// Debot Action that must be executed. - pub action: DebotAction, -} - -/// [UNSTABLE](UNSTABLE.md) Executes debot action. -/// -/// Calls debot engine referenced by debot handle to execute input action. -/// Calls Debot Browser Callbacks if needed. -/// -/// # Remarks -/// Chain of actions can be executed if input action generates a list of subactions. -#[api_function] -pub async fn execute(context: Arc, params: ParamsOfExecute) -> ClientResult<()> { - let mutex = context - .debots - .get(¶ms.debot_handle.0) - .ok_or(Error::invalid_handle(params.debot_handle.0))?; - let mut dengine = mutex.1.lock().await; - dengine - .execute_action(¶ms.action.into()) - .await - .map_err(Error::execute_failed) -} - -/// [UNSTABLE](UNSTABLE.md) -#[derive(Serialize, Deserialize, ApiType, Default)] -pub struct ParamsOfRemove { - /// Debot handle which references an instance of debot engine. - pub debot_handle: DebotHandle, -} - -/// [UNSTABLE](UNSTABLE.md) Destroys debot handle. -/// -/// Removes handle from Client Context and drops debot engine referenced by that handle. -#[api_function] -pub fn remove(context: Arc, params: ParamsOfRemove) -> ClientResult<()> { - context.debots.remove(¶ms.debot_handle.0); - Ok(()) -} - -/// [UNSTABLE](UNSTABLE.md) Parameters of `send` function. -#[derive(Serialize, Deserialize, ApiType, Default)] -pub struct ParamsOfSend { - /// Debot handle which references an instance of debot engine. - pub debot_handle: DebotHandle, - /// BOC of internal message to debot encoded in base64 format. - pub message: String, -} - -/// [UNSTABLE](UNSTABLE.md) Sends message to Debot. -/// -/// Used by Debot Browser to send response on Dinterface call or from other Debots. -#[api_function] -pub async fn send(context: Arc, params: ParamsOfSend) -> ClientResult<()> { - let mutex = context - .debots - .get(¶ms.debot_handle.0) - .ok_or(Error::invalid_handle(params.debot_handle.0))?; - let mut dengine = mutex.1.lock().await; - dengine - .send(params.message) - .await -} +/* +* Copyright 2018-2020 TON DEV SOLUTIONS LTD. +* +* Licensed under the SOFTWARE EVALUATION License (the "License"); you may not use +* this file except in compliance with the License. +* +* Unless required by applicable law or agreed to in writing, software +* distributed under the License is distributed on an "AS IS" BASIS, +* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +* See the License for the specific TON DEV software governing permissions and +* limitations under the License. +*/ + +mod action; +mod activity; +mod base64_interface; +mod hex_interface; +mod json_interface; +mod json_lib_utils; +mod browser; +pub mod calltype; +mod context; +mod debot_abi; +mod dengine; +mod dinterface; +mod errors; +mod helpers; +mod info; +mod msg_interface; +mod network_interface; +mod query_interface; +mod routines; +mod run_output; +mod sdk_interface; +#[cfg(test)] +mod tests; +#[cfg(test)] +mod tests_interfaces; + +#[cfg(not(feature = "wasm"))] +pub use calltype::prepare_ext_in_message; + +pub use action::DAction; +pub use activity::{DebotActivity, Spending}; +pub use browser::BrowserCallbacks; +pub use context::{DContext, STATE_EXIT, STATE_ZERO}; +pub use dengine::DEngine; +pub use dinterface::{DebotInterface, DebotInterfaceExecutor, InterfaceResult}; +pub use errors::{Error, ErrorCode}; +use info::DInfo; +use crate::error::ClientResult; +use crate::ClientContext; +use std::sync::Arc; +use tokio::sync::Mutex; + +pub const DEBOT_WC: i8 = -31; // 0xDB + +type TonClient = Arc; +type JsonValue = serde_json::Value; + +/// [UNSTABLE](UNSTABLE.md) Handle of registered in SDK debot +#[derive(Serialize, Deserialize, Default, ApiType, Clone)] +pub struct DebotHandle(u32); + +/// [UNSTABLE](UNSTABLE.md) Describes a debot action in a Debot Context. +#[derive(Serialize, Deserialize, Clone, Debug, ApiType, Default, PartialEq)] +pub struct DebotAction { + /// A short action description. Should be used by Debot Browser as name of + /// menu item. + pub description: String, + /// Depends on action type. Can be a debot function name or a print string + /// (for Print Action). + pub name: String, + /// Action type. + pub action_type: u8, + /// ID of debot context to switch after action execution. + pub to: u8, + /// Action attributes. In the form of "param=value,flag". + /// attribute example: instant, args, fargs, sign. + pub attributes: String, + /// Some internal action data. Used by debot only. + pub misc: String, +} + +impl From for DebotAction { + fn from(daction: DAction) -> Self { + Self { + description: daction.desc, + name: daction.name, + action_type: daction.action_type as u8, + to: daction.to, + attributes: daction.attrs, + misc: daction.misc, + } + } +} + +impl Into for DebotAction { + fn into(self) -> DAction { + DAction { + desc: self.description, + name: self.name, + action_type: self.action_type.into(), + to: self.to, + attrs: self.attributes, + misc: self.misc, + } + } +} + +/// [UNSTABLE](UNSTABLE.md) Describes DeBot metadata. +#[derive(Serialize, Deserialize, Clone, Debug, ApiType, Default, PartialEq)] +pub struct DebotInfo { + /// DeBot short name. + pub name: Option, + /// DeBot semantic version. + pub version: Option, + /// The name of DeBot deployer. + pub publisher: Option, + /// Short info about DeBot. + pub caption: Option, + /// The name of DeBot developer. + pub author: Option, + /// TON address of author for questions and donations. + pub support: Option, + /// String with the first messsage from DeBot. + pub hello: Option, + /// String with DeBot interface language (ISO-639). + pub language: Option, + /// String with DeBot ABI. + pub dabi: Option, + /// DeBot icon. + pub icon: Option, + /// Vector with IDs of DInterfaces used by DeBot. + pub interfaces: Vec, +} + +impl From for DebotInfo { + fn from(info: DInfo) -> Self { + Self { + name: info.name, + version: info.version, + publisher: info.publisher, + caption: info.caption, + author: info.author, + support: info.support, + hello: info.hello, + language: info.language, + dabi: info.dabi, + icon : info.icon, + interfaces: info.interfaces, + } + } +} + +/// [UNSTABLE](UNSTABLE.md) Parameters to start DeBot. +/// DeBot must be already initialized with init() function. +#[derive(Serialize, Deserialize, Default, ApiType)] +pub struct ParamsOfStart { + /// Debot handle which references an instance of debot engine. + debot_handle: DebotHandle, +} + +/// [UNSTABLE](UNSTABLE.md) Starts the DeBot. +/// +/// Downloads debot smart contract from blockchain and switches it to +/// context zero. +/// +/// This function must be used by Debot Browser to start a dialog with debot. +/// While the function is executing, several Browser Callbacks can be called, +/// since the debot tries to display all actions from the context 0 to the user. +/// +/// When the debot starts SDK registers `BrowserCallbacks` AppObject. +/// Therefore when `debote.remove` is called the debot is being deleted and the callback is called +/// with `finish`=`true` which indicates that it will never be used again. +#[api_function] +pub async fn start( + context: Arc, + params: ParamsOfStart, +) -> ClientResult<()> { + let mutex = context + .debots + .get(¶ms.debot_handle.0) + .ok_or(Error::invalid_handle(params.debot_handle.0))?; + let mut dengine = mutex.1.lock().await; + dengine.start().await.map_err(Error::start_failed) +} + +/// [UNSTABLE](UNSTABLE.md) Parameters to fetch DeBot metadata. +#[derive(Serialize, Deserialize, Default, ApiType)] +pub struct ParamsOfFetch { + /// Debot smart contract address. + pub address: String, +} + +/// [UNSTABLE](UNSTABLE.md) +#[derive(Serialize, Deserialize, Default, ApiType)] +pub struct ResultOfFetch { + /// Debot metadata. + pub info: DebotInfo, +} + +/// [UNSTABLE](UNSTABLE.md) Fetches DeBot metadata from blockchain. +/// +/// Downloads DeBot from blockchain and creates and fetches its metadata. +#[api_function] +pub async fn fetch( + context: Arc, + params: ParamsOfFetch, +) -> ClientResult { + Ok(ResultOfFetch { + info : DEngine::fetch(context, params.address).await.map_err(Error::fetch_failed)?.into() + }) +} + +/// [UNSTABLE](UNSTABLE.md) Parameters to init DeBot. +#[derive(Serialize, Deserialize, Default, ApiType)] +pub struct ParamsOfInit { + /// Debot smart contract address + pub address: String, +} + +/// [UNSTABLE](UNSTABLE.md) Structure for storing debot handle returned from `init` function. +#[derive(Serialize, Deserialize, ApiType, Default)] +pub struct RegisteredDebot { + /// Debot handle which references an instance of debot engine. + pub debot_handle: DebotHandle, + /// Debot abi as json string. + pub debot_abi: String, + /// Debot metadata. + pub info: DebotInfo, +} + +/// [UNSTABLE](UNSTABLE.md) Creates an instance of DeBot. +/// +/// Downloads DeBot smart contract (code and data) from blockchain and creates +/// an instance of Debot Engine for it. +/// Returns a debot handle which can be used later in `start`, `execute` or `send` functions. +/// # Remarks +/// It does not switch debot to context 0. Browser Callbacks are not called. +/// Can be used to invoke DeBot without starting. +pub async fn init( + context: Arc, + params: ParamsOfInit, + callbacks: impl BrowserCallbacks + Send + Sync + 'static, +) -> ClientResult { + let mut dengine = + DEngine::new_with_client(params.address, None, context.clone(), Arc::new(callbacks)); + let info: DebotInfo = dengine.init().await.map_err(Error::fetch_failed)?.into(); + + let handle = context.get_next_id(); + context.debots.insert(handle, Mutex::new(dengine)); + let debot_abi = info.dabi.clone().unwrap_or(String::new()); + Ok(RegisteredDebot { debot_handle: DebotHandle(handle), info, debot_abi }) +} + +/// [UNSTABLE](UNSTABLE.md) Parameters for executing debot action. +#[derive(Serialize, Deserialize, ApiType, Default)] +pub struct ParamsOfExecute { + /// Debot handle which references an instance of debot engine. + pub debot_handle: DebotHandle, + /// Debot Action that must be executed. + pub action: DebotAction, +} + +/// [UNSTABLE](UNSTABLE.md) Executes debot action. +/// +/// Calls debot engine referenced by debot handle to execute input action. +/// Calls Debot Browser Callbacks if needed. +/// +/// # Remarks +/// Chain of actions can be executed if input action generates a list of subactions. +#[api_function] +pub async fn execute(context: Arc, params: ParamsOfExecute) -> ClientResult<()> { + let mutex = context + .debots + .get(¶ms.debot_handle.0) + .ok_or(Error::invalid_handle(params.debot_handle.0))?; + let mut dengine = mutex.1.lock().await; + dengine + .execute_action(¶ms.action.into()) + .await + .map_err(Error::execute_failed) +} + +/// [UNSTABLE](UNSTABLE.md) +#[derive(Serialize, Deserialize, ApiType, Default)] +pub struct ParamsOfRemove { + /// Debot handle which references an instance of debot engine. + pub debot_handle: DebotHandle, +} + +/// [UNSTABLE](UNSTABLE.md) Destroys debot handle. +/// +/// Removes handle from Client Context and drops debot engine referenced by that handle. +#[api_function] +pub fn remove(context: Arc, params: ParamsOfRemove) -> ClientResult<()> { + context.debots.remove(¶ms.debot_handle.0); + Ok(()) +} + +/// [UNSTABLE](UNSTABLE.md) Parameters of `send` function. +#[derive(Serialize, Deserialize, ApiType, Default)] +pub struct ParamsOfSend { + /// Debot handle which references an instance of debot engine. + pub debot_handle: DebotHandle, + /// BOC of internal message to debot encoded in base64 format. + pub message: String, +} + +/// [UNSTABLE](UNSTABLE.md) Sends message to Debot. +/// +/// Used by Debot Browser to send response on Dinterface call or from other Debots. +#[api_function] +pub async fn send(context: Arc, params: ParamsOfSend) -> ClientResult<()> { + let mutex = context + .debots + .get(¶ms.debot_handle.0) + .ok_or(Error::invalid_handle(params.debot_handle.0))?; + let mut dengine = mutex.1.lock().await; + dengine + .send(params.message) + .await +} \ No newline at end of file diff --git a/ton_client/src/debot/query_interface.rs b/ton_client/src/debot/query_interface.rs index 7439da5d7..3c0275e8b 100644 --- a/ton_client/src/debot/query_interface.rs +++ b/ton_client/src/debot/query_interface.rs @@ -3,12 +3,9 @@ use super::dinterface::{ }; use super::TonClient; use crate::abi::Abi; -use crate::boc::internal::{deserialize_cell_from_base64, serialize_cell_to_base64}; +use crate::debot::json_lib_utils::{pack, Value}; use crate::net::{query_collection, OrderBy, ParamsOfQueryCollection, SortDirection}; use serde_json::Value as JsonValue; -use sha2::Digest; -use std::collections::HashMap; -use ton_abi::{contract::ABI_VERSION_2_0, token::Tokenizer, Param, ParamType, TokenValue}; const ABI: &str = r#" { @@ -40,118 +37,6 @@ const ABI: &str = r#" const ID: &str = "5c6fd81616cdfb963632109c42144a3a885c8d0f2e8deb5d8e15872fb92f2811"; -use serde_repr::{Deserialize_repr, Serialize_repr}; -#[derive(Serialize_repr, Deserialize_repr)] -#[repr(u8)] -enum ValKind { - String = 0, - Number = 1, - Bool = 2, - Array = 3, - Object = 4, - Null = 5, - Cell = 6, -} - -impl Default for ValKind { - fn default() -> Self { - ValKind::Null - } -} - -#[derive(Serialize, Deserialize, Default)] -struct Cell { - cell: String, -} - -#[derive(Serialize, Deserialize, Default)] -struct Value { - kind: ValKind, - value: String, - object: HashMap, - array: Vec, -} - -impl Value { - fn new_null() -> Self { - Self::default() - } - - fn new_bool(v: bool) -> Option { - let mut val = Self::default(); - val.kind = ValKind::Bool; - val.value = Self::serialize(ParamType::Bool, json!(v))?; - Some(val) - } - - fn new_number(v: i64) -> Option { - let mut val = Self::default(); - val.kind = ValKind::Number; - val.value = Self::serialize(ParamType::Int(256), json!(v))?; - Some(val) - } - - fn new_string(v: String) -> Option { - let mut val = Self::default(); - val.kind = ValKind::String; - if deserialize_cell_from_base64(&v, "QueryValue").is_ok() { - val.value = v; - val.kind = ValKind::Cell; - } else { - val.value = Self::serialize(ParamType::Bytes, json!(hex::encode(v)))?; - } - Some(val) - } - - fn new_object(map: serde_json::map::Map) -> Option { - let mut val = Self::default(); - val.kind = ValKind::Object; - for (k, v) in map { - let mut hasher = sha2::Sha256::new(); - hasher.update(k); - let hash = hasher.finalize(); - let json: JsonValue = serde_json::to_value(pack(v)?).ok()?; - let params = [ - Param::new("kind", ParamType::Uint(8)), - Param::new("value", ParamType::Cell), - Param::new( - "object", - ParamType::Map(Box::new(ParamType::Uint(256)), Box::new(ParamType::Cell)), - ), - Param::new("array", ParamType::Array(Box::new(ParamType::Cell))), - ]; - let tokens = Tokenizer::tokenize_all_params(¶ms, &json).unwrap(); - let builder = TokenValue::pack_values_into_chain(&tokens[..], vec![], &ABI_VERSION_2_0).unwrap(); - let serialized = - serialize_cell_to_base64(&ton_types::Cell::from(&builder), "QueryValue").ok()?; - val.object - .insert(format!("0x{}", hex::encode(&hash[..])), serialized); - } - Some(val) - } - - fn serialize(param_type: ParamType, json: JsonValue) -> Option { - let tokens = Tokenizer::tokenize_all_params( - &[Param::new("arg0", param_type)], - &json!({ "arg0": json }), - ) - .ok()?; - let builder = TokenValue::pack_values_into_chain(&tokens[..], vec![], &ABI_VERSION_2_0).ok()?; - serialize_cell_to_base64(&ton_types::Cell::from(&builder), "QueryValue").ok() - } -} - -fn pack(json_obj: JsonValue) -> Option { - match json_obj { - JsonValue::Null => Some(Value::new_null()), - JsonValue::Bool(v) => Value::new_bool(v), - JsonValue::String(v) => Value::new_string(v), - JsonValue::Number(v) => Value::new_number(v.as_i64()?), - JsonValue::Object(map) => Value::new_object(map), - JsonValue::Array(_) => Some(Value::new_null()), - } -} - #[derive(Clone)] #[repr(u8)] enum QueryStatus { diff --git a/ton_client/src/debot/tests.rs b/ton_client/src/debot/tests.rs index e7eb82e45..665bc06de 100644 --- a/ton_client/src/debot/tests.rs +++ b/ton_client/src/debot/tests.rs @@ -1408,6 +1408,33 @@ async fn test_debot_query() { ).await; } +#[tokio::test(core_threads = 2)] +async fn test_debot_json_parse() { + let client = std::sync::Arc::new(TestClient::new()); + let DebotData { + debot_addr, + target_addr: _, + keys, + abi, + } = init_simple_debot(client.clone(), "testDebot15").await; + TestBrowser::execute_with_details( + client.clone(), + debot_addr.clone(), + keys, + vec![], + vec![], + build_info( + abi, + 15, + vec![ + format!("0x8796536366ee21852db56dccb60bc564598b618c865fc50c8b1ab740bba128e3"), + format!("0x442288826041d564ccedc579674f17c1b0a3452df799656a9167a41ab270ec19"), + ], + ), + vec![], + ) + .await; +} fn build_info(abi: String, n: u32, interfaces: Vec) -> DebotInfo { let name = format!("TestDeBot{}", n); diff --git a/ton_client/src/json_interface/modules.rs b/ton_client/src/json_interface/modules.rs index 8f406c101..14424be01 100644 --- a/ton_client/src/json_interface/modules.rs +++ b/ton_client/src/json_interface/modules.rs @@ -356,7 +356,8 @@ fn register_boc(handlers: &mut RuntimeHandlers) { crate::boc::get_blockchain_config, crate::boc::blockchain_config::get_blockchain_config_api, ); - module.register_async_fn(crate::boc::get_boc_hash, crate::boc::hash::get_boc_hash_api); + module.register_async_fn(crate::boc::get_boc_hash, crate::boc::common::get_boc_hash_api); + module.register_async_fn(crate::boc::get_boc_depth, crate::boc::common::get_boc_depth_api); module.register_async_fn( crate::boc::get_code_from_tvc, crate::boc::tvc::get_code_from_tvc_api, diff --git a/ton_client/src/tests/contracts/abi_v2/testDebot15.abi.json b/ton_client/src/tests/contracts/abi_v2/testDebot15.abi.json new file mode 100644 index 000000000..aacadc8ee --- /dev/null +++ b/ton_client/src/tests/contracts/abi_v2/testDebot15.abi.json @@ -0,0 +1,78 @@ +{ + "ABI version": 2, + "header": ["pubkey", "time", "expire"], + "functions": [ + { + "name": "start", + "inputs": [ + ], + "outputs": [ + ] + }, + { + "name": "setValue", + "inputs": [ + {"name":"result","type":"bool"}, + {"components":[{"name":"kind","type":"uint8"},{"name":"value","type":"cell"},{"name":"object","type":"map(uint256,cell)"},{"components":[{"name":"cell","type":"cell"}],"name":"array","type":"tuple[]"}],"name":"obj","type":"tuple"} + ], + "outputs": [ + ] + }, + { + "name": "getDebotInfo", + "id": "0xDEB", + "inputs": [ + ], + "outputs": [ + {"name":"name","type":"bytes"}, + {"name":"version","type":"bytes"}, + {"name":"publisher","type":"bytes"}, + {"name":"caption","type":"bytes"}, + {"name":"author","type":"bytes"}, + {"name":"support","type":"address"}, + {"name":"hello","type":"bytes"}, + {"name":"language","type":"bytes"}, + {"name":"dabi","type":"bytes"}, + {"name":"icon","type":"bytes"} + ] + }, + { + "name": "getRequiredInterfaces", + "inputs": [ + ], + "outputs": [ + {"name":"interfaces","type":"uint256[]"} + ] + }, + { + "name": "getDebotOptions", + "inputs": [ + ], + "outputs": [ + {"name":"options","type":"uint8"}, + {"name":"debotAbi","type":"bytes"}, + {"name":"targetAbi","type":"bytes"}, + {"name":"targetAddr","type":"address"} + ] + }, + { + "name": "setABI", + "inputs": [ + {"name":"dabi","type":"bytes"} + ], + "outputs": [ + ] + }, + { + "name": "constructor", + "inputs": [ + ], + "outputs": [ + ] + } + ], + "data": [ + ], + "events": [ + ] +} diff --git a/ton_client/src/tests/contracts/abi_v2/testDebot15.sol b/ton_client/src/tests/contracts/abi_v2/testDebot15.sol new file mode 100644 index 000000000..745870a8d --- /dev/null +++ b/ton_client/src/tests/contracts/abi_v2/testDebot15.sol @@ -0,0 +1,91 @@ +pragma ton-solidity >=0.47.0; +pragma AbiHeader expire; +pragma AbiHeader time; +pragma AbiHeader pubkey; +import "https://raw.githubusercontent.com/tonlabs/debots/main/Debot.sol"; +import "https://raw.githubusercontent.com/tonlabs/DeBot-IS-consortium/main/Terminal/Terminal.sol"; +import "https://raw.githubusercontent.com/tonlabs/DeBot-IS-consortium/main/Json/Json.sol"; + +contract TestDebot15 is Debot { + + using JsonLib for JsonLib.Value; + using JsonLib for mapping(uint256 => TvmCell); + + struct Info{ + string name; + string[] tags; + uint8 age; + uint8[] numbers; + mapping (address => string) addrs; + } + + /// @notice Entry point function for DeBot. + function start() public override { + string json = "{\"name\":\"Joe\",\"tags\":[\"good\",\"bad\",\"ugly\"],\"age\":73,\"numbers\":[1,2,3],\"addrs\":{\"0:1111111111111111111111111111111111111111111111111111111111111111\":\"My main account\"}}"; + Json.parse(tvm.functionId(setValue), json); + } + + function setValue(bool result, JsonLib.Value obj) public { + require(result == true, 199); + + optional(JsonLib.Value) val; + mapping(uint256 => TvmCell) jsonObj = obj.as_object().get(); + + val = jsonObj.get("name"); + string name = val.get().as_string().get(); + require(name =="Joe",200); + + string[] expectedTags = ["good", "bad", "ugly"]; + uint i = 0; + val = jsonObj.get("tags"); + JsonLib.Cell[] elems = val.get().as_array().get(); + for (JsonLib.Cell e: elems) { + val = JsonLib.decodeArrayValue(e.cell); + string tag = val.get().as_string().get(); + require(expectedTags[i] == tag, 300); + i++; + } + + val = jsonObj.get("age"); + int age = val.get().as_number().get(); + require(age == 73, 202); + + val = jsonObj.get("addrs"); + mapping(uint256 => TvmCell) addrs = val.get().as_object().get(); + + val = addrs.get("0:1111111111111111111111111111111111111111111111111111111111111111"); + string desc1 = val.get().as_string().get(); + require(desc1 == "My main account", 205); + + mapping(string => string) expectedAddrs; + expectedAddrs["0:1111111111111111111111111111111111111111111111111111111111111111"] = "My main account"; + for ((uint256 hash, TvmCell cell): addrs) { + optional(string) nameOpt; + (val, nameOpt) = JsonLib.decodeObjectValue(cell); + string desc = val.get().as_string().get(); + require(expectedAddrs.exists(nameOpt.get()), 206); + require(expectedAddrs[nameOpt.get()] == desc, 207); + } + } + + function getDebotInfo() public functionID(0xDEB) override view returns( + string name, string version, string publisher, string caption, string author, + address support, string hello, string language, string dabi, bytes icon + ) { + name = "TestDeBot15"; + version = "0.1.0"; + publisher = "TON Labs"; + caption = "TestDeBot15"; + author = "TON Labs"; + support = address(0); + hello = "TestDeBot15"; + language = "en"; + dabi = m_debotAbi.get(); + icon = ""; + } + + function getRequiredInterfaces() public view override returns (uint256[] interfaces) { + return [ Terminal.ID, Json.ID ]; + } + +} diff --git a/ton_client/src/tests/contracts/abi_v2/testDebot15.tvc b/ton_client/src/tests/contracts/abi_v2/testDebot15.tvc new file mode 100644 index 000000000..4e446044b Binary files /dev/null and b/ton_client/src/tests/contracts/abi_v2/testDebot15.tvc differ diff --git a/ton_sdk/Cargo.toml b/ton_sdk/Cargo.toml index e594a0697..d5c6e5dc1 100644 --- a/ton_sdk/Cargo.toml +++ b/ton_sdk/Cargo.toml @@ -1,15 +1,15 @@ [package] name = "ton_sdk" -version = "1.23.0" +version = "1.21.2" edition = "2018" license = "Apache-2.0" authors = ["TON DEV SOLUTIONS LTD "] [dependencies] -ton_abi = { git = "https://github.com/tonlabs/ton-labs-abi.git" } -ton_block = { git = "https://github.com/tonlabs/ton-labs-block.git" } -ton_vm = { git = "https://github.com/tonlabs/ton-labs-vm.git", default-features = false } -ton_types = { git = "https://github.com/tonlabs/ton-labs-types.git" } +ton_abi = { git = "https://github.com/tonlabs/ton-labs-abi.git", tag = "2.1.1" } +ton_block = { git = "https://github.com/tonlabs/ton-labs-block.git", tag = "1.7.27" } +ton_vm = { git = "https://github.com/tonlabs/ton-labs-vm.git", tag = "1.8.19", default-features = false } +ton_types = { git = "https://github.com/tonlabs/ton-labs-types.git", tag = "1.10.10" } api_info = { path = "../api/info" } api_derive = { path = "../api/derive" } diff --git a/toncli/Cargo.toml b/toncli/Cargo.toml index c8fb54c75..f3cb8e390 100644 --- a/toncli/Cargo.toml +++ b/toncli/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "toncli" -version = "1.23.0" +version = "1.24.0" description = "TON CLient Command Line Tool" authors = ["TON DEV SOLUTIONS LTD "] repository = "https://github.com/tonlabs/TON-SDK" diff --git a/tools/api.json b/tools/api.json index 6f7d89e18..9711f3d8f 100644 --- a/tools/api.json +++ b/tools/api.json @@ -1,5 +1,5 @@ { - "version": "1.23.0", + "version": "1.24.0", "modules": [ { "name": "client", @@ -6466,7 +6466,7 @@ { "name": "boc", "type": "String", - "summary": "BOC encoded as base64", + "summary": "BOC encoded as base64 or BOC handle", "description": null } ], @@ -6487,6 +6487,36 @@ "summary": null, "description": null }, + { + "name": "ParamsOfGetBocDepth", + "type": "Struct", + "struct_fields": [ + { + "name": "boc", + "type": "String", + "summary": "BOC encoded as base64 or BOC handle", + "description": null + } + ], + "summary": null, + "description": null + }, + { + "name": "ResultOfGetBocDepth", + "type": "Struct", + "struct_fields": [ + { + "name": "depth", + "type": "Number", + "number_type": "UInt", + "number_size": 32, + "summary": "BOC root cell depth", + "description": null + } + ], + "summary": null, + "description": null + }, { "name": "ParamsOfGetCodeFromTvc", "type": "Struct", @@ -6845,6 +6875,26 @@ "summary": "Contract code BOC encoded as base64 or BOC handle", "description": null }, + { + "name": "code_hash", + "type": "Optional", + "optional_inner": { + "type": "String" + }, + "summary": "Contract code hash", + "description": null + }, + { + "name": "code_depth", + "type": "Optional", + "optional_inner": { + "type": "Number", + "number_type": "UInt", + "number_size": 32 + }, + "summary": "Contract code depth", + "description": null + }, { "name": "data", "type": "Optional", @@ -6854,6 +6904,26 @@ "summary": "Contract data BOC encoded as base64 or BOC handle", "description": null }, + { + "name": "data_hash", + "type": "Optional", + "optional_inner": { + "type": "String" + }, + "summary": "Contract data hash", + "description": null + }, + { + "name": "data_depth", + "type": "Optional", + "optional_inner": { + "type": "Number", + "number_type": "UInt", + "number_size": 32 + }, + "summary": "Contract data depth", + "description": null + }, { "name": "library", "type": "Optional", @@ -6891,6 +6961,15 @@ }, "summary": "Is present and non-zero only in instances of large smart contracts", "description": null + }, + { + "name": "compiler_version", + "type": "Optional", + "optional_inner": { + "type": "String" + }, + "summary": "Compiler version, for example 'sol 0.49.0'", + "description": null } ], "summary": null, @@ -7283,6 +7362,44 @@ }, "errors": null }, + { + "name": "get_boc_depth", + "summary": "Calculates BOC depth", + "description": null, + "params": [ + { + "name": "context", + "type": "Generic", + "generic_name": "Arc", + "generic_args": [ + { + "type": "Ref", + "ref_name": "ClientContext" + } + ], + "summary": null, + "description": null + }, + { + "name": "params", + "type": "Ref", + "ref_name": "boc.ParamsOfGetBocDepth", + "summary": null, + "description": null + } + ], + "result": { + "type": "Generic", + "generic_name": "ClientResult", + "generic_args": [ + { + "type": "Ref", + "ref_name": "boc.ResultOfGetBocDepth" + } + ] + }, + "errors": null + }, { "name": "get_code_from_tvc", "summary": "Extracts code from TVC contract image",