diff --git a/Cargo.lock b/Cargo.lock index 9dd97ceba2..388b753b00 100755 --- a/Cargo.lock +++ b/Cargo.lock @@ -1918,6 +1918,14 @@ dependencies = [ "syn 1.0.109", ] +[[package]] +name = "multiversx-sc-codec-human-readable" +version = "0.1.0" +dependencies = [ + "multiversx-sc-meta", + "multiversx-sc-scenario", +] + [[package]] name = "multiversx-sc-derive" version = "0.44.0" diff --git a/Cargo.toml b/Cargo.toml index ef92a8a7b9..51f5300809 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ resolver = "2" members = [ "data/codec", "data/codec-derive", + "data/human-readable", "framework/base", "framework/derive", diff --git a/data/codec/src/single/top_en.rs b/data/codec/src/single/top_en.rs index 2826c7d3d2..68d86667a1 100644 --- a/data/codec/src/single/top_en.rs +++ b/data/codec/src/single/top_en.rs @@ -4,7 +4,7 @@ use crate::{ }; use alloc::vec::Vec; -pub trait TopEncode: Sized { +pub trait TopEncode { /// Attempt to serialize the value to ouput. fn top_encode(&self, output: O) -> Result<(), EncodeError> where diff --git a/data/human-readable/Cargo.toml b/data/human-readable/Cargo.toml new file mode 100644 index 0000000000..500d566244 --- /dev/null +++ b/data/human-readable/Cargo.toml @@ -0,0 +1,25 @@ +[package] +name = "multiversx-sc-codec-human-readable" +version = "0.1.0" +edition = "2018" +publish = false + +authors = ["MultiversX "] +license = "GPL-3.0-only" +readme = "README.md" +repository = "https://github.com/multiversx/mx-sdk-rs" +homepage = "https://multiversx.com/" +documentation = "https://docs.multiversx.com/" +description = "Conversions from a human readable format to the multiversx-sc-codec" +keywords = ["multiversx", "wasm", "webassembly", "blockchain", "contract"] +categories = ["cryptography::cryptocurrencies", "development-tools"] + +[dependencies] + +[dependencies.multiversx-sc-scenario] +version = "=0.44.0" +path = "../../framework/scenario" + +[dependencies.multiversx-sc-meta] +version = "=0.44.0" +path = "../../framework/meta" diff --git a/data/human-readable/src/interpret.rs b/data/human-readable/src/interpret.rs new file mode 100644 index 0000000000..6b8b4caaf2 --- /dev/null +++ b/data/human-readable/src/interpret.rs @@ -0,0 +1,57 @@ +use std::{error::Error, fmt::Display}; + +use crate::multiversx_sc::abi::{TypeContents, TypeDescription}; +use multiversx_sc_meta::abi_json::ContractAbiJson; +use multiversx_sc_scenario::num_bigint::BigUint; + +use crate::{AnyValue, SingleValue::UnsignedNumber}; + +pub fn interpret_value_according_to_abi( + input: &str, + type_name: &str, + contract_abi: &ContractAbiJson, // TODO: will need to convert to high-level ContractAbi first, this is just a prototype +) -> Result> { + let type_description = if let Some(type_description_json) = contract_abi.types.get(type_name) { + type_description_json.to_type_description(type_name) + } else { + TypeDescription { + docs: Vec::new(), + name: type_name.to_string(), + contents: TypeContents::NotSpecified, + } + }; + interpret_any_value(input, &type_description) +} + +pub fn interpret_any_value( + input: &str, + type_description: &TypeDescription, +) -> Result> { + match &type_description.contents { + TypeContents::NotSpecified => interpret_single_value(input, type_description.name.as_str()), + TypeContents::Enum(_) => todo!(), + TypeContents::Struct(_) => todo!(), + TypeContents::ExplicitEnum(_) => panic!("not supported"), + } +} + +fn interpret_single_value(input: &str, type_name: &str) -> Result> { + match type_name { + "BigUint" | "u64" | "u32" | "u16" | "usize" | "u8" => { + let value = input.parse::()?; + Ok(AnyValue::SingleValue(UnsignedNumber(value))) + }, + _ => Err(Box::new(InterpretError("unknown type"))), + } +} + +#[derive(Debug)] +pub struct InterpretError(&'static str); + +impl Display for InterpretError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + self.0.fmt(f) + } +} + +impl Error for InterpretError {} diff --git a/data/human-readable/src/lib.rs b/data/human-readable/src/lib.rs new file mode 100644 index 0000000000..613e656b7e --- /dev/null +++ b/data/human-readable/src/lib.rs @@ -0,0 +1,6 @@ +mod interpret; +mod value; + +use multiversx_sc_scenario::multiversx_sc; +pub use interpret::*; +pub use value::*; diff --git a/data/human-readable/src/value/any_value.rs b/data/human-readable/src/value/any_value.rs new file mode 100644 index 0000000000..97bf8ec17e --- /dev/null +++ b/data/human-readable/src/value/any_value.rs @@ -0,0 +1,39 @@ +use multiversx_sc_scenario::multiversx_sc::codec::{ + EncodeErrorHandler, NestedEncode, NestedEncodeOutput, TopEncode, TopEncodeOutput, +}; + +use crate::{EnumVariant, SingleValue, StructValue}; + +pub enum AnyValue { + SingleValue(SingleValue), + Struct(StructValue), + Enum(Box), +} + +impl NestedEncode for AnyValue { + fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> + where + O: NestedEncodeOutput, + H: EncodeErrorHandler, + { + match self { + AnyValue::SingleValue(sv) => sv.dep_encode_or_handle_err(dest, h), + AnyValue::Struct(s) => s.dep_encode_or_handle_err(dest, h), + AnyValue::Enum(_) => todo!(), + } + } +} + +impl TopEncode for AnyValue { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + match self { + AnyValue::SingleValue(sv) => sv.top_encode_or_handle_err(output, h), + AnyValue::Struct(s) => s.top_encode_or_handle_err(output, h), + AnyValue::Enum(_) => todo!(), + } + } +} diff --git a/data/human-readable/src/value/enum_value.rs b/data/human-readable/src/value/enum_value.rs new file mode 100644 index 0000000000..864b889e8b --- /dev/null +++ b/data/human-readable/src/value/enum_value.rs @@ -0,0 +1,6 @@ +use crate::AnyValue; + +pub struct EnumVariant { + pub discriminant: usize, + pub value: AnyValue, +} diff --git a/data/human-readable/src/value/mod.rs b/data/human-readable/src/value/mod.rs new file mode 100644 index 0000000000..5c87ded058 --- /dev/null +++ b/data/human-readable/src/value/mod.rs @@ -0,0 +1,9 @@ +mod any_value; +mod enum_value; +mod single_value; +mod struct_value; + +pub use any_value::*; +pub use enum_value::*; +pub use single_value::*; +pub use struct_value::*; diff --git a/data/human-readable/src/value/single_value.rs b/data/human-readable/src/value/single_value.rs new file mode 100644 index 0000000000..fbb972daa8 --- /dev/null +++ b/data/human-readable/src/value/single_value.rs @@ -0,0 +1,41 @@ +use multiversx_sc_scenario::multiversx_sc::codec::{ + num_bigint::{BigInt, BigUint}, + EncodeErrorHandler, NestedEncode, NestedEncodeOutput, TopEncode, TopEncodeOutput, +}; + +pub enum SingleValue { + UnsignedNumber(BigUint), + SignedNumber(BigInt), + Bytes(Box<[u8]>), + Bool(bool), +} + +impl NestedEncode for SingleValue { + fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> + where + O: NestedEncodeOutput, + H: EncodeErrorHandler, + { + match self { + SingleValue::UnsignedNumber(bu) => bu.dep_encode_or_handle_err(dest, h), + SingleValue::SignedNumber(bi) => bi.dep_encode_or_handle_err(dest, h), + SingleValue::Bytes(bytes) => bytes.dep_encode_or_handle_err(dest, h), + SingleValue::Bool(b) => b.dep_encode_or_handle_err(dest, h), + } + } +} + +impl TopEncode for SingleValue { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + match self { + SingleValue::UnsignedNumber(bu) => bu.top_encode_or_handle_err(output, h), + SingleValue::SignedNumber(bi) => bi.top_encode_or_handle_err(output, h), + SingleValue::Bytes(bytes) => bytes.top_encode_or_handle_err(output, h), + SingleValue::Bool(b) => b.top_encode_or_handle_err(output, h), + } + } +} diff --git a/data/human-readable/src/value/struct_value.rs b/data/human-readable/src/value/struct_value.rs new file mode 100644 index 0000000000..d90d5a1b85 --- /dev/null +++ b/data/human-readable/src/value/struct_value.rs @@ -0,0 +1,38 @@ +use multiversx_sc_scenario::multiversx_sc::codec::{ + EncodeErrorHandler, NestedEncode, NestedEncodeOutput, TopEncode, TopEncodeOutput, +}; + +use crate::AnyValue; + +pub struct StructValue(Vec); + +pub struct StructField { + pub name: String, + pub value: AnyValue, +} + +impl NestedEncode for StructValue { + fn dep_encode_or_handle_err(&self, dest: &mut O, h: H) -> Result<(), H::HandledErr> + where + O: NestedEncodeOutput, + H: EncodeErrorHandler, + { + for field in &self.0 { + field.value.dep_encode_or_handle_err(dest, h)?; + } + Ok(()) + } +} + +impl TopEncode for StructValue { + fn top_encode_or_handle_err(&self, output: O, h: H) -> Result<(), H::HandledErr> + where + O: TopEncodeOutput, + H: EncodeErrorHandler, + { + let mut buffer = output.start_nested_encode(); + self.dep_encode_or_handle_err(&mut buffer, h)?; + output.finalize_nested_encode(buffer); + Ok(()) + } +} diff --git a/data/human-readable/tests/single_value_basic_test.rs b/data/human-readable/tests/single_value_basic_test.rs new file mode 100644 index 0000000000..0728a30902 --- /dev/null +++ b/data/human-readable/tests/single_value_basic_test.rs @@ -0,0 +1,21 @@ +use multiversx_sc_codec_human_readable::interpret_value_according_to_abi; +use multiversx_sc_meta::abi_json::{deserialize_abi_from_json, ContractAbiJson}; +use multiversx_sc_scenario::multiversx_sc::codec::top_encode_to_vec_u8; + +const TEST_ABI_JSON: &str = r#"{ + "name": "Test", + "endpoints": [], + "events": [], + "esdtAttributes": [], + "hasCallback": false, + "types": {} +}"#; + +#[test] +fn test_display_unsigned() { + let abi_json: ContractAbiJson = deserialize_abi_from_json(TEST_ABI_JSON).unwrap(); + + let result = interpret_value_according_to_abi("123", "BigUint", &abi_json).unwrap(); + let serialized = top_encode_to_vec_u8(&result).unwrap(); + assert_eq!(serialized, vec![123]); +} diff --git a/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs b/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs index ec80ca9cc1..79aa391b0d 100644 --- a/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs +++ b/framework/base/src/contract_base/wrappers/blockchain_wrapper.rs @@ -39,7 +39,7 @@ where } } - #[deprecated(since = "0.41.0", note = "Please use method `get_caller` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `get_caller` instead.")] #[cfg(feature = "alloc")] #[inline] pub fn get_caller_legacy(&self) -> crate::types::Address { @@ -53,7 +53,7 @@ where ManagedAddress::from_handle(handle) } - #[deprecated(since = "0.41.0", note = "Please use method `get_sc_address` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `get_sc_address` instead.")] #[cfg(feature = "alloc")] #[inline] pub fn get_sc_address_legacy(&self) -> crate::types::Address { @@ -89,7 +89,7 @@ where } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `get_shard_of_address` instead." )] #[cfg(feature = "alloc")] @@ -104,7 +104,7 @@ where } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `is_smart_contract` instead." )] #[cfg(feature = "alloc")] @@ -118,7 +118,7 @@ where A::blockchain_api_impl().is_smart_contract(address.get_handle()) } - #[deprecated(since = "0.41.0", note = "Please use method `get_balance` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `get_balance` instead.")] #[cfg(feature = "alloc")] #[inline] pub fn get_balance_legacy(&self, address: &crate::types::Address) -> BigUint { @@ -145,7 +145,7 @@ where } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `get_state_root_hash` instead." )] #[cfg(feature = "alloc")] @@ -161,7 +161,7 @@ where ManagedByteArray::from_handle(handle) } - #[deprecated(since = "0.41.0", note = "Please use method `get_tx_hash` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `get_tx_hash` instead.")] #[cfg(feature = "alloc")] #[inline] pub fn get_tx_hash_legacy(&self) -> crate::types::H256 { @@ -201,7 +201,7 @@ where } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `get_block_random_seed` instead." )] #[cfg(feature = "alloc")] @@ -238,7 +238,7 @@ where } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `get_prev_block_random_seed` instead." )] #[cfg(feature = "alloc")] diff --git a/framework/base/src/types/managed/basic/elliptic_curve.rs b/framework/base/src/types/managed/basic/elliptic_curve.rs index d70f7f738d..7c40ff1256 100644 --- a/framework/base/src/types/managed/basic/elliptic_curve.rs +++ b/framework/base/src/types/managed/basic/elliptic_curve.rs @@ -151,7 +151,7 @@ impl EllipticCurve { api.ec_is_on_curve(self.handle.clone(), x_point.handle, y_point.handle) } - #[deprecated(since = "0.41.0", note = "Please use method `scalar_mult` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `scalar_mult` instead.")] pub fn scalar_mult_legacy( &self, x_point: BigUint, @@ -199,7 +199,7 @@ impl EllipticCurve { } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `scalar_base_mult` instead." )] pub fn scalar_base_mult_legacy(&self, data: &[u8]) -> (BigUint, BigUint) { @@ -234,7 +234,7 @@ impl EllipticCurve { ) } - #[deprecated(since = "0.41.0", note = "Please use method `marshal` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `marshal` instead.")] #[cfg(feature = "alloc")] pub fn marshal_legacy( &self, @@ -258,7 +258,7 @@ impl EllipticCurve { } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `marshal_compressed` instead." )] #[cfg(feature = "alloc")] @@ -283,7 +283,7 @@ impl EllipticCurve { ManagedBuffer::from_handle(result_handle) } - #[deprecated(since = "0.41.0", note = "Please use method `unmarshal` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `unmarshal` instead.")] pub fn unmarshal_legacy(&self, data: &[u8]) -> (BigUint, BigUint) { let api = M::managed_type_impl(); let x_pair_handle = api.bi_new_zero(); @@ -317,7 +317,7 @@ impl EllipticCurve { } #[deprecated( - since = "0.41.0", + since = "0.44.0", note = "Please use method `unmarshal_compressed` instead." )] pub fn unmarshal_compressed_legacy(&self, data: &[u8]) -> (BigUint, BigUint) { @@ -352,7 +352,7 @@ impl EllipticCurve { ) } - #[deprecated(since = "0.41.0", note = "Please use method `generate_key` instead.")] + #[deprecated(since = "0.44.0", note = "Please use method `generate_key` instead.")] #[cfg(feature = "alloc")] pub fn generate_key_legacy(&self) -> (BigUint, BigUint, crate::types::heap::BoxedBytes) { let api = M::managed_type_impl(); diff --git a/framework/meta/src/cmd/standalone/upgrade/upgrade_selector.rs b/framework/meta/src/cmd/standalone/upgrade/upgrade_selector.rs index db8f0ef404..83c442d5ce 100644 --- a/framework/meta/src/cmd/standalone/upgrade/upgrade_selector.rs +++ b/framework/meta/src/cmd/standalone/upgrade/upgrade_selector.rs @@ -86,7 +86,7 @@ fn upgrade_post_processing(dir: &RelevantDirectory) { match dir.upgrade_in_progress { Some((_, "0.28.0")) | Some((_, "0.29.0")) | Some((_, "0.30.0")) | Some((_, "0.31.0")) | Some((_, "0.32.0")) | Some((_, "0.33.0")) | Some((_, "0.34.0")) | Some((_, "0.35.0")) - | Some((_, "0.36.0")) | Some((_, "0.37.0")) | Some((_, "0.40.0")) | Some((_, "0.41.0")) + | Some((_, "0.36.0")) | Some((_, "0.37.0")) | Some((_, "0.40.0")) | Some((_, "0.44.0")) | Some((_, "0.42.0")) | Some((_, "0.43.0")) => { print_post_processing(dir); cargo_check(dir); diff --git a/framework/meta/src/version_history.rs b/framework/meta/src/version_history.rs index 206d8017ea..037ad02f98 100644 --- a/framework/meta/src/version_history.rs +++ b/framework/meta/src/version_history.rs @@ -39,7 +39,7 @@ pub const VERSIONS: &[&str] = &[ "0.39.8", "0.40.0", "0.40.1", - "0.41.0", + "0.44.0", "0.41.1", "0.41.2", "0.41.3",