diff --git a/configs/swarm/executor.wasm b/configs/swarm/executor.wasm index afde5635a2d..2e5a1d20aa0 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 ec431e8e458..ad7b2f4f75b 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 @@ -1748,12 +1751,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..117bfa7fef6 100644 --- a/data_model/derive/src/lib.rs +++ b/data_model/derive/src/lib.rs @@ -14,32 +14,32 @@ 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> { +/// pub(crate) enum InnerEnumRef<'a> { /// A(&'a u32), /// B(&'a i32), /// } /// -/// enum OuterEnumRef<'a> { +/// pub(crate) enum OuterEnumRef<'a> { /// A(&'a String), /// B(InnerEnumRef<'a>), /// } @@ -67,7 +67,7 @@ pub fn enum_ref(input: TokenStream) -> Result { /// /// # Example /// -/// ```rust +/// ``` /// use iroha_data_model_derive::model; /// /// #[model] @@ -170,7 +170,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 +230,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/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/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 1654b9e8bc5..fc36ba36cb3 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),