diff --git a/client_cli/pytests/test/domains/test_register_domains.py b/client_cli/pytests/test/domains/test_register_domains.py index 173c054119b..d369aba3b89 100644 --- a/client_cli/pytests/test/domains/test_register_domains.py +++ b/client_cli/pytests/test/domains/test_register_domains.py @@ -68,24 +68,24 @@ def test_register_one_letter_domain(GIVEN_random_character): iroha.should(have.domain(GIVEN_random_character)) -@allure.label("sdk_test_id", "register_max_lenght_domain") -def test_register_max_lenght_domain(GIVEN_128_lenght_name): +@allure.label("sdk_test_id", "register_max_length_domain") +def test_register_max_length_domain(GIVEN_128_length_name): with allure.step( - f'WHEN client_cli registers the longest domain "{GIVEN_128_lenght_name}"' + f'WHEN client_cli registers the longest domain "{GIVEN_128_length_name}"' ): - client_cli.register().domain(GIVEN_128_lenght_name) + client_cli.register().domain(GIVEN_128_length_name) with allure.step( - f'THEN Iroha should have the longest domain "{GIVEN_128_lenght_name}"' + f'THEN Iroha should have the longest domain "{GIVEN_128_length_name}"' ): - iroha.should(have.domain(GIVEN_128_lenght_name)) + iroha.should(have.domain(GIVEN_128_length_name)) @allure.label("sdk_test_id", "register_domain_with_too_long_name") -def test_register_domain_with_too_long_name(GIVEN_129_lenght_name): +def test_register_domain_with_too_long_name(GIVEN_129_length_name): with allure.step( - f'WHEN client_cli registers the domain "{GIVEN_129_lenght_name}" with too long name' + f'WHEN client_cli registers the domain "{GIVEN_129_length_name}" with too long name' ): - client_cli.register().domain(GIVEN_129_lenght_name) + client_cli.register().domain(GIVEN_129_length_name) with allure.step( f'THEN client_cli should have the too long domain error: "{Stderr.TOO_LONG}"' ): diff --git a/config/tests/fixtures.rs b/config/tests/fixtures.rs index 7cfd467fa29..560d91e6ea8 100644 --- a/config/tests/fixtures.rs +++ b/config/tests/fixtures.rs @@ -138,20 +138,20 @@ fn minimal_config_snapshot() -> Result<()> { max_wasm_size_bytes: 4194304, }, asset_metadata_limits: Limits { - max_len: 1048576, - max_entry_byte_size: 4096, + capacity: 1048576, + max_entry_len: 4096, }, asset_definition_metadata_limits: Limits { - max_len: 1048576, - max_entry_byte_size: 4096, + capacity: 1048576, + max_entry_len: 4096, }, account_metadata_limits: Limits { - max_len: 1048576, - max_entry_byte_size: 4096, + capacity: 1048576, + max_entry_len: 4096, }, domain_metadata_limits: Limits { - max_len: 1048576, - max_entry_byte_size: 4096, + capacity: 1048576, + max_entry_len: 4096, }, ident_length_limits: LengthLimits { min: 1, diff --git a/config/tests/fixtures/full.toml b/config/tests/fixtures/full.toml index 878223301aa..06df91c1996 100644 --- a/config/tests/fixtures/full.toml +++ b/config/tests/fixtures/full.toml @@ -65,10 +65,10 @@ max_transactions_in_block = 512 block_time = 2_000 commit_time = 4_000 transaction_limits = {max_instruction_number = 4096, max_wasm_size_bytes = 4194304 } -asset_metadata_limits = { max_len = 1048576, max_entry_byte_size = 4096 } -asset_definition_metadata_limits = { max_len = 1048576, max_entry_byte_size = 4096 } -account_metadata_limits = { max_len = 1048576, max_entry_byte_size = 4096 } -domain_metadata_limits = { max_len = 1048576, max_entry_byte_size = 4096 } +asset_metadata_limits = { capacity = 1048576, max_entry_len = 4096 } +asset_definition_metadata_limits = { capacity = 1048576, max_entry_len = 4096 } +account_metadata_limits = { capacity = 1048576, max_entry_len = 4096 } +domain_metadata_limits = { capacity = 1048576, max_entry_len = 4096 } ident_length_limits = { min = 1, max = 128 } wasm_fuel_limit = 55000000 wasm_max_memory = 524288000 diff --git a/configs/swarm/executor.wasm b/configs/swarm/executor.wasm index 5c3c5605eb3..d04d0c65dc9 100644 Binary files a/configs/swarm/executor.wasm and b/configs/swarm/executor.wasm differ diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 5d5db7b02af..c78bb327168 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -13,17 +13,15 @@ use iroha_data_model::{ isi::InstructionBox, permission::PermissionTokenSchema, prelude::*, - query::{QueryBox, QueryId, QueryRequest, QueryWithParameters}, - smart_contract::{ - payloads::{self, Validate}, - SmartContractQueryRequest, - }, + query::{QueryBox, QueryRequest, QueryWithParameters}, + smart_contract::payloads::{self, Validate}, BatchedResponse, Level as LogLevel, ValidationFail, }; use iroha_logger::debug; // NOTE: Using error_span so that span info is logged on every event use iroha_logger::{error_span as wasm_log_span, prelude::tracing::Span}; use iroha_wasm_codec::{self as codec, WasmUsize}; +use parity_scale_codec::Decode; use wasmtime::{ Caller, Config as WasmtimeConfig, Engine, Linker, Module, Store, StoreLimits, StoreLimitsBuilder, TypedFunc, @@ -74,7 +72,7 @@ mod import { use super::super::*; - pub trait ExecuteOperations { + pub(crate) trait ExecuteOperations { /// Execute `query` on host #[codec::wrap_trait_fn] fn execute_query( @@ -243,6 +241,11 @@ pub mod error { /// [`Result`] type for this module pub type Result = core::result::Result; +#[cfg_attr(test, derive(parity_scale_codec::Encode))] +#[derive(Debug, derive_more::Display, Decode)] +#[repr(transparent)] +pub(crate) struct SmartContractQueryRequest(pub QueryRequest); + /// Create [`Module`] from bytes. /// /// # Errors @@ -1751,12 +1754,14 @@ mod tests { let kura = Kura::blank_kura_for_testing(); let query_handle = LiveQueryStore::test().start(); let mut wsv = WorldStateView::new(world_with_test_account(&authority), kura, query_handle); - let query_hex = encode_hex(SmartContractQueryRequest::query( - QueryBox::from(FindAccountById::new(authority.clone())), - Sorting::default(), - Pagination::default(), - FetchSize::default(), - )); + let query_hex = encode_hex(SmartContractQueryRequest(QueryRequest::Query( + QueryWithParameters::new( + FindAccountById::new(authority.clone()).into(), + Sorting::default(), + Pagination::default(), + FetchSize::default(), + ), + ))); let wat = format!( r#" diff --git a/data_model/derive/src/enum_ref.rs b/data_model/derive/src/enum_ref.rs index 4248949a9d5..ca399cf9938 100644 --- a/data_model/derive/src/enum_ref.rs +++ b/data_model/derive/src/enum_ref.rs @@ -151,7 +151,7 @@ impl ToTokens for EnumRef { quote! { #attrs - pub(super) enum #ident<'a> #impl_generics #where_clause { + pub(crate) enum #ident<'a> #impl_generics #where_clause { #(#variants),* } } diff --git a/data_model/derive/src/lib.rs b/data_model/derive/src/lib.rs index d1ccf69b03d..c661752a262 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -14,32 +14,34 @@ use proc_macro2::TokenStream; /// /// # Example /// -/// ```rust +/// ``` /// use iroha_data_model_derive::EnumRef; /// use parity_scale_codec::Encode; /// /// #[derive(EnumRef)] -/// enum InnerEnum { +/// #[enum_ref(derive(Encode))] +/// pub enum InnerEnum { /// A(u32), /// B(i32) /// } /// /// #[derive(EnumRef)] /// #[enum_ref(derive(Encode))] -/// enum OuterEnum { +/// pub enum OuterEnum { /// A(String), /// #[enum_ref(transparent)] /// B(InnerEnum), /// } /// /// /* will produce: -/// -/// enum InnerEnumRef<'a> { +/// #[derive(Encode)] +/// pub(crate) enum InnerEnumRef<'a> { /// A(&'a u32), /// B(&'a i32), /// } /// -/// enum OuterEnumRef<'a> { +/// #[derive(Encode)] +/// pub(crate) enum OuterEnumRef<'a> { /// A(&'a String), /// B(InnerEnumRef<'a>), /// } @@ -67,7 +69,7 @@ pub fn enum_ref(input: TokenStream) -> Result { /// /// # Example /// -/// ```rust +/// ``` /// use iroha_data_model_derive::model; /// /// #[model] @@ -170,7 +172,7 @@ pub fn model_single(input: TokenStream) -> TokenStream { /// /// The common use-case: /// -/// ```rust +/// ``` /// use iroha_data_model_derive::IdEqOrdHash; /// use iroha_data_model::{Identifiable, IdBox}; /// @@ -230,7 +232,7 @@ pub fn model_single(input: TokenStream) -> TokenStream { /// /// Manual selection of the identifier field: /// -/// ```rust +/// ``` /// use iroha_data_model_derive::IdEqOrdHash; /// use iroha_data_model::{Identifiable, IdBox}; /// diff --git a/data_model/src/isi.rs b/data_model/src/isi.rs index 5e9388f64cf..55dc7775daa 100644 --- a/data_model/src/isi.rs +++ b/data_model/src/isi.rs @@ -1359,7 +1359,7 @@ pub mod error { asset::AssetValueType, metadata, query::error::{FindError, QueryExecutionFail}, - IdBox, Value, + IdBox, }; #[model] @@ -1367,7 +1367,7 @@ pub mod error { use serde::{Deserialize, Serialize}; use super::*; - use crate::asset::AssetDefinitionId; + use crate::{asset::AssetDefinitionId, Value}; /// Instruction execution error type #[derive( @@ -1633,6 +1633,7 @@ pub mod error { Self::Evaluate(InstructionEvaluationError::Type(err)) } } + impl From for MathError { fn from(err: FixedPointOperationError) -> Self { match err { diff --git a/data_model/src/lib.rs b/data_model/src/lib.rs index b0a4e9dd50b..dfbf51ff56c 100644 --- a/data_model/src/lib.rs +++ b/data_model/src/lib.rs @@ -413,11 +413,11 @@ pub mod parameter { })?; let lower = lower.parse::().map_err(|_| ParseError { reason: - "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Invalid `u32` in `max_len` field.", + "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Invalid `u32` in `capacity` field.", })?; let upper = upper.parse::().map_err(|_| ParseError { reason: - "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Invalid `u32` in `max_entry_byte_size` field.", + "Failed to parse the `val` part of the `Parameter` as `MetadataLimits`. Invalid `u32` in `max_entry_len` field.", })?; Value::MetadataLimits(metadata::Limits::new(lower, upper)) } diff --git a/data_model/src/metadata.rs b/data_model/src/metadata.rs index f4ab99dc2b9..5ddc6c595cd 100644 --- a/data_model/src/metadata.rs +++ b/data_model/src/metadata.rs @@ -38,13 +38,13 @@ pub mod model { Serialize, IntoSchema, )] - #[display(fmt = "{max_len},{max_entry_byte_size}_ML")] + #[display(fmt = "{capacity},{max_entry_len}_ML")] #[ffi_type] pub struct Limits { /// Maximum number of entries - pub max_len: u32, + pub capacity: u32, /// Maximum length of entry - pub max_entry_byte_size: u32, + pub max_entry_len: u32, } /// Collection of parameters by their names with checked insertion. @@ -88,12 +88,12 @@ pub mod model { )] #[cfg_attr(feature = "std", derive(thiserror::Error))] pub enum MetadataError { + /// Path specification empty + EmptyPath, /// Metadata entry is too big EntryTooBig(#[cfg_attr(feature = "std", source)] SizeError), /// Metadata exceeds overall length limit - OverallSize(#[cfg_attr(feature = "std", source)] SizeError), - /// Path specification empty - EmptyPath, + MaxCapacity(#[cfg_attr(feature = "std", source)] SizeError), /// `{0}`: path segment not found, i.e. nothing was found at that key MissingSegment(Name), /// `{0}`: path segment not an instance of metadata @@ -127,10 +127,10 @@ pub struct SizeError { impl Limits { /// Constructor. - pub const fn new(max_len: u32, max_entry_byte_size: u32) -> Limits { + pub const fn new(capacity: u32, max_entry_len: u32) -> Limits { Limits { - max_len, - max_entry_byte_size, + capacity, + max_entry_len, } } } @@ -207,8 +207,8 @@ impl Metadata { value: Value, limits: Limits, ) -> Result, MetadataError> { - if self.0.len() >= limits.max_len as usize { - return Err(MetadataError::OverallSize(SizeError { + if self.0.len() >= limits.capacity as usize { + return Err(MetadataError::MaxCapacity(SizeError { limits, actual: self.len_u64(), })); @@ -232,15 +232,15 @@ impl Metadata { /// if the value was already present, `None` otherwise. /// /// # Errors - /// Fails if `max_entry_byte_size` or `max_len` from `limits` are exceeded. + /// Fails if `max_entry_len` or `capacity` from `limits` are exceeded. pub fn insert_with_limits( &mut self, key: Name, value: Value, limits: Limits, ) -> Result, MetadataError> { - if self.0.len() >= limits.max_len as usize && !self.0.contains_key(&key) { - return Err(MetadataError::OverallSize(SizeError { + if self.0.len() >= limits.capacity as usize && !self.0.contains_key(&key) { + return Err(MetadataError::MaxCapacity(SizeError { limits, actual: self.len_u64(), })); @@ -283,7 +283,7 @@ impl Metadata { fn check_size_limits(key: &Name, value: Value, limits: Limits) -> Result<(), MetadataError> { let entry_bytes: Vec = (key, value).encode(); let byte_size = entry_bytes.len(); - if byte_size > limits.max_entry_byte_size as usize { + if byte_size > limits.max_entry_len as usize { return Err(MetadataError::EntryTooBig(SizeError { limits, actual: byte_size diff --git a/data_model/src/query/mod.rs b/data_model/src/query/mod.rs index 0501691ab85..9fce496e897 100644 --- a/data_model/src/query/mod.rs +++ b/data_model/src/query/mod.rs @@ -15,7 +15,7 @@ use core::{cmp::Ordering, num::NonZeroU32, time::Duration}; pub use cursor::ForwardCursor; use derive_more::{Constructor, Display}; use iroha_crypto::{PublicKey, SignatureOf}; -use iroha_data_model_derive::model; +use iroha_data_model_derive::{model, EnumRef}; use iroha_macro::FromVariant; use iroha_schema::IntoSchema; use iroha_version::prelude::*; @@ -32,6 +32,7 @@ use self::{ use crate::{ account::{Account, AccountId}, block::SignedBlock, + events::TriggeringFilterBox, seal, transaction::{SignedTransaction, TransactionPayload, TransactionValue}, Identifiable, Value, @@ -103,12 +104,18 @@ pub type QueryId = String; pub trait Query: Into + seal::Sealed { /// Output type of query type Output: Into + TryFrom; + + /// [`Encode`] [`Self`] as [`QueryBox`]. + /// + /// Used to avoid an unnecessary clone + fn encode_as_query_box(&self) -> Vec; } #[model] pub mod model { use getset::Getters; use iroha_crypto::HashOf; + use strum::EnumDiscriminants; use super::*; use crate::{block::SignedBlock, permission::PermissionTokenId}; @@ -123,6 +130,8 @@ pub mod model { Eq, PartialOrd, Ord, + EnumRef, + EnumDiscriminants, FromVariant, Decode, Encode, @@ -130,6 +139,13 @@ pub mod model { Serialize, IntoSchema, )] + #[enum_ref(derive(Encode, FromVariant))] + #[strum_discriminants( + vis(pub(crate)), + name(QueryType), + derive(Encode), + allow(clippy::enum_variant_names) + )] #[ffi_type] #[allow(missing_docs)] pub enum QueryBox { @@ -244,6 +260,69 @@ pub mod model { } } +macro_rules! impl_query { + ($($ty:ty => $output:ty),+ $(,)?) => { $( + impl Query for $ty { + type Output = $output; + + fn encode_as_query_box(&self) -> Vec { + QueryBoxRef::from(self).encode() + } + } )+ + } +} + +impl_query! { + FindAllRoles => Vec, + FindAllRoleIds => Vec, + FindRolesByAccountId => Vec, + FindRoleByRoleId => crate::role::Role, + FindPermissionTokenSchema => crate::permission::PermissionTokenSchema, + FindPermissionTokensByAccountId => Vec, + FindAllAccounts => Vec, + FindAccountById => crate::account::Account, + FindAccountKeyValueByIdAndKey => MetadataValue, + FindAccountsByName => Vec, + FindAccountsByDomainId => Vec, + FindAccountsWithAsset => Vec, + FindAllAssets => Vec, + FindAllAssetsDefinitions => Vec, + FindAssetById => crate::asset::Asset, + FindAssetDefinitionById => crate::asset::AssetDefinition, + FindAssetsByName => Vec, + FindAssetsByAccountId => Vec, + FindAssetsByAssetDefinitionId => Vec, + FindAssetsByDomainId => Vec, + FindAssetsByDomainIdAndAssetDefinitionId => Vec, + FindAssetQuantityById => crate::NumericValue, + FindTotalAssetQuantityByAssetDefinitionId => crate::NumericValue, + FindAssetKeyValueByIdAndKey => MetadataValue, + FindAssetDefinitionKeyValueByIdAndKey => MetadataValue, + FindAllDomains => Vec, + FindDomainById => crate::domain::Domain, + FindDomainKeyValueByIdAndKey => MetadataValue, + FindAllPeers => Vec, + FindAllParameters => Vec, + FindAllActiveTriggerIds => Vec, + FindTriggerById => crate::trigger::Trigger, + FindTriggerKeyValueByIdAndKey => MetadataValue, + FindTriggersByDomainId => Vec>, + FindAllTransactions => Vec, + FindTransactionsByAccountId => Vec, + FindTransactionByHash => TransactionQueryOutput, + FindAllBlocks => Vec, + FindAllBlockHeaders => Vec, + FindBlockHeaderByHash => crate::block::BlockHeader, +} + +impl Query for QueryBox { + type Output = Value; + + fn encode_as_query_box(&self) -> Vec { + self.encode() + } +} + impl From for Value { #[inline] fn from(source: MetadataValue) -> Self { @@ -258,10 +337,6 @@ impl From for MetadataValue { } } -impl Query for QueryBox { - type Output = Value; -} - impl AsRef for TransactionQueryOutput { fn as_ref(&self) -> &SignedTransaction { &self.transaction.value @@ -294,8 +369,9 @@ pub mod role { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; + use parity_scale_codec::Encode; - use super::Query; + use super::{Query, QueryType}; use crate::prelude::*; queries! { @@ -336,22 +412,6 @@ pub mod role { } } - impl Query for FindAllRoles { - type Output = Vec; - } - - impl Query for FindAllRoleIds { - type Output = Vec; - } - - impl Query for FindRolesByAccountId { - type Output = Vec; - } - - impl Query for FindRoleByRoleId { - type Output = Role; - } - /// The prelude re-exports most commonly used traits, structs and macros from this module. pub mod prelude { pub use super::{FindAllRoleIds, FindAllRoles, FindRoleByRoleId, FindRolesByAccountId}; @@ -365,8 +425,9 @@ pub mod permission { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; + use parity_scale_codec::Encode; - use super::Query; + use super::{Query, QueryType}; use crate::{ permission::{self, PermissionTokenSchema}, prelude::*, @@ -391,14 +452,6 @@ pub mod permission { } } - impl Query for FindPermissionTokenSchema { - type Output = PermissionTokenSchema; - } - - impl Query for FindPermissionTokensByAccountId { - type Output = Vec; - } - /// The prelude re-exports most commonly used traits, structs and macros from this module. pub mod prelude { pub use super::{FindPermissionTokenSchema, FindPermissionTokensByAccountId}; @@ -412,8 +465,9 @@ pub mod account { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; + use parity_scale_codec::Encode; - use super::{MetadataValue, Query}; + use super::{MetadataValue, Query, QueryType}; use crate::prelude::*; queries! { @@ -485,30 +539,6 @@ pub mod account { } } - impl Query for FindAllAccounts { - type Output = Vec; - } - - impl Query for FindAccountById { - type Output = Account; - } - - impl Query for FindAccountKeyValueByIdAndKey { - type Output = MetadataValue; - } - - impl Query for FindAccountsByName { - type Output = Vec; - } - - impl Query for FindAccountsByDomainId { - type Output = Vec; - } - - impl Query for FindAccountsWithAsset { - type Output = Vec; - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{ @@ -527,10 +557,9 @@ pub mod asset { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; - use iroha_data_model_derive::model; + use parity_scale_codec::Encode; - pub use self::model::*; - use super::{MetadataValue, Query}; + use super::{MetadataValue, Query, QueryType}; use crate::prelude::*; queries! { @@ -680,58 +709,6 @@ pub mod asset { } } - impl Query for FindAllAssets { - type Output = Vec; - } - - impl Query for FindAllAssetsDefinitions { - type Output = Vec; - } - - impl Query for FindAssetById { - type Output = Asset; - } - - impl Query for FindAssetDefinitionById { - type Output = AssetDefinition; - } - - impl Query for FindAssetsByName { - type Output = Vec; - } - - impl Query for FindAssetsByAccountId { - type Output = Vec; - } - - impl Query for FindAssetsByAssetDefinitionId { - type Output = Vec; - } - - impl Query for FindAssetsByDomainId { - type Output = Vec; - } - - impl Query for FindAssetsByDomainIdAndAssetDefinitionId { - type Output = Vec; - } - - impl Query for FindAssetQuantityById { - type Output = NumericValue; - } - - impl Query for FindTotalAssetQuantityByAssetDefinitionId { - type Output = NumericValue; - } - - impl Query for FindAssetKeyValueByIdAndKey { - type Output = MetadataValue; - } - - impl Query for FindAssetDefinitionKeyValueByIdAndKey { - type Output = MetadataValue; - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{ @@ -753,8 +730,9 @@ pub mod domain { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; + use parity_scale_codec::Encode; - use super::{MetadataValue, Query}; + use super::{MetadataValue, Query, QueryType}; use crate::prelude::*; queries! { @@ -788,18 +766,6 @@ pub mod domain { } } - impl Query for FindAllDomains { - type Output = Vec; - } - - impl Query for FindDomainById { - type Output = Domain; - } - - impl Query for FindDomainKeyValueByIdAndKey { - type Output = MetadataValue; - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{FindAllDomains, FindDomainById, FindDomainKeyValueByIdAndKey}; @@ -813,9 +779,9 @@ pub mod peer { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; + use parity_scale_codec::Encode; - use super::Query; - use crate::{parameter::Parameter, peer::Peer}; + use super::{Query, QueryType}; queries! { /// [`FindAllPeers`] Iroha Query finds all trusted [`Peer`]s presented in current Iroha [`Peer`]. @@ -832,14 +798,6 @@ pub mod peer { pub struct FindAllParameters; } - impl Query for FindAllPeers { - type Output = Vec; - } - - impl Query for FindAllParameters { - type Output = Vec; - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{FindAllParameters, FindAllPeers}; @@ -852,11 +810,11 @@ pub mod trigger { use alloc::{format, string::String, vec::Vec}; use derive_more::Display; + use parity_scale_codec::Encode; - use super::{MetadataValue, Query}; + use super::{MetadataValue, Query, QueryType}; use crate::{ domain::prelude::*, - events::TriggeringFilterBox, prelude::InstructionBox, trigger::{Trigger, TriggerId}, Executable, Identifiable, Name, Value, @@ -906,22 +864,6 @@ pub mod trigger { } } - impl Query for FindAllActiveTriggerIds { - type Output = Vec; - } - - impl Query for FindTriggerById { - type Output = Trigger; - } - - impl Query for FindTriggerKeyValueByIdAndKey { - type Output = MetadataValue; - } - - impl Query for FindTriggersByDomainId { - type Output = Vec>; - } - pub mod prelude { //! Prelude Re-exports most commonly used traits, structs and macros from this crate. pub use super::{ @@ -941,8 +883,9 @@ pub mod transaction { use derive_more::Display; use iroha_crypto::HashOf; + use parity_scale_codec::Encode; - use super::{Query, TransactionQueryOutput}; + use super::{Query, QueryType, TransactionQueryOutput}; use crate::{account::AccountId, prelude::Account, transaction::SignedTransaction}; queries! { @@ -977,18 +920,6 @@ pub mod transaction { } } - impl Query for FindAllTransactions { - type Output = Vec; - } - - impl Query for FindTransactionsByAccountId { - type Output = Vec; - } - - impl Query for FindTransactionByHash { - type Output = TransactionQueryOutput; - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{FindAllTransactions, FindTransactionByHash, FindTransactionsByAccountId}; @@ -1005,9 +936,10 @@ pub mod block { use derive_more::Display; use iroha_crypto::HashOf; + use parity_scale_codec::{Decode, Encode}; - use super::Query; - use crate::block::{BlockHeader, SignedBlock}; + use super::{Query, QueryType}; + use crate::block::SignedBlock; queries! { /// [`FindAllBlocks`] Iroha Query lists all blocks sorted by @@ -1036,18 +968,6 @@ pub mod block { } } - impl Query for FindAllBlocks { - type Output = Vec; - } - - impl Query for FindAllBlockHeaders { - type Output = Vec; - } - - impl Query for FindBlockHeaderByHash { - type Output = BlockHeader; - } - /// The prelude re-exports most commonly used traits, structs and macros from this crate. pub mod prelude { pub use super::{FindAllBlockHeaders, FindAllBlocks, FindBlockHeaderByHash}; @@ -1201,7 +1121,7 @@ pub mod http { impl QueryBuilder { /// Construct a new request with the `query`. - pub fn new(query: impl Into, authority: AccountId) -> Self { + pub fn new(query: impl Query, authority: AccountId) -> Self { Self { payload: QueryPayload { query: query.into(), diff --git a/data_model/src/smart_contract.rs b/data_model/src/smart_contract.rs index 6e363f07218..379da0585d9 100644 --- a/data_model/src/smart_contract.rs +++ b/data_model/src/smart_contract.rs @@ -1,16 +1,5 @@ //! This module contains data and structures related only to smart contract execution -use parity_scale_codec::{Decode, Encode}; - -pub use self::model::*; -use crate::{ - prelude::FetchSize, - query::{ - cursor::ForwardCursor, sorting::Sorting, Pagination, QueryBox, QueryRequest, - QueryWithParameters, - }, -}; - pub mod payloads { //! Payloads with function arguments for different entrypoints @@ -52,55 +41,3 @@ pub mod payloads { pub target: T, } } - -#[crate::model] -pub mod model { - use super::*; - - /// Request type for `execute_query()` function. - #[derive(Debug, derive_more::Display, Clone, Decode, Encode)] - pub struct SmartContractQueryRequest(pub QueryRequest); -} - -impl SmartContractQueryRequest { - /// Construct a new request containing query. - pub fn query( - query: QueryBox, - sorting: Sorting, - pagination: Pagination, - fetch_size: FetchSize, - ) -> Self { - Self(QueryRequest::Query(QueryWithParameters::new( - query, sorting, pagination, fetch_size, - ))) - } - - /// Construct a new request containing cursor. - pub fn cursor(cursor: ForwardCursor) -> Self { - Self(QueryRequest::Cursor(cursor)) - } - - /// Unwrap [`Self`] if it was previously constructed with [`query()`](Self::query). - /// - /// # Panics - /// - /// Panics if [`Self`] was constructed with [`cursor()`](Self::cursor). - pub fn unwrap_query(self) -> (QueryBox, Sorting, Pagination) { - match self.0 { - QueryRequest::Query(query) => (query.query, query.sorting, query.pagination), - QueryRequest::Cursor(_) => panic!("Expected query, got cursor"), - } - } - - /// Unwrap [`Self`] if it was previously constructed with [`cursor()`](Self::cursor). - /// - /// # Panics - /// - /// Panics if [`Self`] was constructed with [`query()`](Self::query). - pub fn unwrap_cursor(self) -> ForwardCursor { - match self.0 { - QueryRequest::Query(_) => panic!("Expected cursor, got query"), - QueryRequest::Cursor(cursor) => cursor, - } - } -} diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 7de02949e9e..039890fb3b4 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -2367,11 +2367,11 @@ "Limits": { "Struct": [ { - "name": "max_len", + "name": "capacity", "type": "u32" }, { - "name": "max_entry_byte_size", + "name": "max_entry_len", "type": "u32" } ] @@ -2492,18 +2492,18 @@ "MetadataError": { "Enum": [ { - "tag": "EntryTooBig", - "discriminant": 0, - "type": "SizeError" + "tag": "EmptyPath", + "discriminant": 0 }, { - "tag": "OverallSize", + "tag": "EntryTooBig", "discriminant": 1, "type": "SizeError" }, { - "tag": "EmptyPath", - "discriminant": 2 + "tag": "MaxCapacity", + "discriminant": 2, + "type": "SizeError" }, { "tag": "MissingSegment", diff --git a/smart_contract/executor/derive/src/token.rs b/smart_contract/executor/derive/src/token.rs index a68c22ebcb4..e9c2b03f271 100644 --- a/smart_contract/executor/derive/src/token.rs +++ b/smart_contract/executor/derive/src/token.rs @@ -25,7 +25,7 @@ fn impl_token(ident: &syn2::Ident, generics: &syn2::Generics) -> proc_macro2::To fn is_owned_by(&self, account_id: &::iroha_executor::data_model::account::AccountId) -> bool { let account_tokens_cursor = ::iroha_executor::smart_contract::debug::DebugExpectExt::dbg_expect( ::iroha_executor::smart_contract::ExecuteQueryOnHost::execute( - ::iroha_executor::data_model::query::permission::FindPermissionTokensByAccountId::new( + &::iroha_executor::data_model::query::permission::FindPermissionTokensByAccountId::new( account_id.clone(), ) ), diff --git a/smart_contract/src/lib.rs b/smart_contract/src/lib.rs index 502d094e2a1..e4ce211f019 100644 --- a/smart_contract/src/lib.rs +++ b/smart_contract/src/lib.rs @@ -12,7 +12,6 @@ use data_model::{ isi::Instruction, prelude::*, query::{cursor::ForwardCursor, sorting::Sorting, Pagination, Query}, - smart_contract::SmartContractQueryRequest, BatchedResponse, }; use derive_more::Display; @@ -130,44 +129,44 @@ impl ExecuteOnHost for I { } } +#[derive(Debug, Encode)] +enum QueryRequest<'a, Q> { + Query(QueryWithParameters<'a, Q>), + Cursor(&'a ForwardCursor), +} + /// Generic query request containing additional parameters. #[derive(Debug)] -pub struct QueryRequest { - query: Q, +pub struct QueryWithParameters<'a, Q> { + query: &'a Q, sorting: Sorting, pagination: Pagination, fetch_size: FetchSize, } -impl From> for SmartContractQueryRequest { - fn from(query_request: QueryRequest) -> Self { - SmartContractQueryRequest::query( - query_request.query.into(), - query_request.sorting, - query_request.pagination, - query_request.fetch_size, - ) +impl Encode for QueryWithParameters<'_, Q> { + fn encode(&self) -> Vec { + let mut output = self.query.encode_as_query_box(); + self.sorting.encode_to(&mut output); + self.pagination.encode_to(&mut output); + self.fetch_size.encode_to(&mut output); + output } } /// Implementing queries can be executed on the host -/// -/// TODO: `&self` should be enough pub trait ExecuteQueryOnHost: Sized { /// Query output type. type Output; - /// Type of [`QueryRequest`]. - type QueryRequest; - /// Apply sorting to a query - fn sort(self, sorting: Sorting) -> Self::QueryRequest; + fn sort(&self, sorting: Sorting) -> QueryWithParameters; /// Apply pagination to a query - fn paginate(self, pagination: Pagination) -> Self::QueryRequest; + fn paginate(&self, pagination: Pagination) -> QueryWithParameters; /// Set fetch size for a query. Default is [`DEFAULT_FETCH_SIZE`] - fn fetch_size(self, fetch_size: FetchSize) -> Self::QueryRequest; + fn fetch_size(&self, fetch_size: FetchSize) -> QueryWithParameters; /// Execute query on the host /// @@ -175,7 +174,7 @@ pub trait ExecuteQueryOnHost: Sized { /// /// - If query validation failed /// - If query execution failed - fn execute(self) -> Result, ValidationFail>; + fn execute(&self) -> Result, ValidationFail>; } impl ExecuteQueryOnHost for Q @@ -185,10 +184,9 @@ where >::Error: core::fmt::Debug, { type Output = Q::Output; - type QueryRequest = QueryRequest; - fn sort(self, sorting: Sorting) -> Self::QueryRequest { - QueryRequest { + fn sort(&self, sorting: Sorting) -> QueryWithParameters { + QueryWithParameters { query: self, sorting, pagination: Pagination::default(), @@ -196,8 +194,8 @@ where } } - fn paginate(self, pagination: Pagination) -> Self::QueryRequest { - QueryRequest { + fn paginate(&self, pagination: Pagination) -> QueryWithParameters { + QueryWithParameters { query: self, sorting: Sorting::default(), pagination, @@ -205,8 +203,8 @@ where } } - fn fetch_size(self, fetch_size: FetchSize) -> Self::QueryRequest { - QueryRequest { + fn fetch_size(&self, fetch_size: FetchSize) -> QueryWithParameters { + QueryWithParameters { query: self, sorting: Sorting::default(), pagination: Pagination::default(), @@ -214,8 +212,8 @@ where } } - fn execute(self) -> Result, ValidationFail> { - QueryRequest { + fn execute(&self) -> Result, ValidationFail> { + QueryWithParameters { query: self, sorting: Sorting::default(), pagination: Pagination::default(), @@ -225,50 +223,56 @@ where } } -impl ExecuteQueryOnHost for QueryRequest +impl QueryWithParameters<'_, Q> where Q: Query + Encode, Q::Output: DecodeAll, >::Error: core::fmt::Debug, { - type Output = Q::Output; - type QueryRequest = Self; - - fn sort(mut self, sorting: Sorting) -> Self { + /// Apply sorting to a query + #[must_use] + pub fn sort(mut self, sorting: Sorting) -> Self { self.sorting = sorting; self } - fn paginate(mut self, pagination: Pagination) -> Self { + /// Apply pagination to a query + #[must_use] + pub fn paginate(mut self, pagination: Pagination) -> Self { self.pagination = pagination; self } - fn fetch_size(mut self, fetch_size: FetchSize) -> Self::QueryRequest { + /// Set fetch size for a query. Default is [`DEFAULT_FETCH_SIZE`] + #[must_use] + pub fn fetch_size(mut self, fetch_size: FetchSize) -> Self { self.fetch_size = fetch_size; self } - #[allow(irrefutable_let_patterns)] - fn execute(self) -> Result, ValidationFail> { + /// Execute query on the host + /// + /// # Errors + /// + /// - If query validation failed + /// - If query execution failed + pub fn execute(self) -> Result, ValidationFail> { #[cfg(not(test))] use host::execute_query as host_execute_query; #[cfg(test)] use tests::_iroha_smart_contract_execute_query_mock as host_execute_query; - let wasm_query_request = SmartContractQueryRequest::from(self); - // Safety: - `host_execute_query` doesn't take ownership of it's pointer parameter // - ownership of the returned result is transferred into `_decode_from_raw` let res: Result, ValidationFail> = unsafe { decode_with_length_prefix_from_raw(encode_and_execute( - &wasm_query_request, + &QueryRequest::Query(self), host_execute_query, )) }; let (value, cursor) = res?.into(); - let typed_value = Self::Output::try_from(value).expect("Query output has incorrect type"); + let typed_value = Q::Output::try_from(value).expect("Query output has incorrect type"); Ok(QueryOutputCursor { batch: typed_value, cursor, @@ -337,30 +341,23 @@ impl> IntoIterator for QueryOutputCursor> { /// /// - Failed to get next batch of results from the host /// - Failed to convert batch of results into the requested type -/// -/// # Panics -/// -/// Panics if response from host is not [`BatchedResponse::V1`]. pub struct QueryOutputCursorIterator { iter: as IntoIterator>::IntoIter, cursor: ForwardCursor, } impl> QueryOutputCursorIterator { - #[allow(irrefutable_let_patterns)] fn next_batch(&self) -> Result>> { #[cfg(not(test))] use host::execute_query as host_execute_query; #[cfg(test)] use tests::_iroha_smart_contract_execute_query_mock as host_execute_query; - let wasm_query_request = SmartContractQueryRequest::cursor(self.cursor.clone()); - // Safety: - `host_execute_query` doesn't take ownership of it's pointer parameter // - ownership of the returned result is transferred into `_decode_from_raw` let res: Result, ValidationFail> = unsafe { decode_with_length_prefix_from_raw(encode_and_execute( - &wasm_query_request, + &QueryRequest::::Cursor(&self.cursor), host_execute_query, )) }; @@ -403,10 +400,6 @@ pub enum QueryOutputCursorError { Conversion(ErrorTryFromEnum), } -/// World state view of the host -#[derive(Debug, Clone, Copy)] -pub struct Host; - /// Get payload for smart contract `main()` entrypoint. #[cfg(not(test))] pub fn get_smart_contract_payload() -> payloads::SmartContract { @@ -458,10 +451,39 @@ mod tests { use data_model::{query::asset::FindAssetQuantityById, BatchedResponseV1}; use iroha_smart_contract_utils::encode_with_length_prefix; + use parity_scale_codec::Decode; use webassembly_test::webassembly_test; use super::*; + #[derive(Decode)] + struct QueryWithParameters { + query: Q, + sorting: Sorting, + pagination: Pagination, + #[allow(dead_code)] + fetch_size: FetchSize, + } + + #[derive(Decode)] + enum QueryRequest { + Query(QueryWithParameters), + Cursor(#[allow(unused_tuple_struct_fields)] ForwardCursor), + } + + #[derive(Decode)] + #[repr(transparent)] + struct SmartContractQueryRequest(pub QueryRequest); + + impl SmartContractQueryRequest { + fn unwrap_query(self) -> (QueryBox, Sorting, Pagination) { + match self.0 { + QueryRequest::Query(query) => (query.query, query.sorting, query.pagination), + QueryRequest::Cursor(_) => panic!("Expected query, got cursor"), + } + } + } + const QUERY_RESULT: Result, ValidationFail> = Ok(QueryOutputCursor { batch: Value::Numeric(NumericValue::U32(1234_u32)), cursor: ForwardCursor::new(None, None),