From 279fe395addf88d24a6c4b5608d9b9b639b7101c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marin=20Ver=C5=A1i=C4=87?= Date: Wed, 28 Jun 2023 17:25:11 +0200 Subject: [PATCH] [refactor]: pin wsv + iterators so that they can persist between queries MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Marin Veršić --- core/benches/apply_blocks/apply_blocks.rs | 2 +- core/src/smartcontracts/isi/account.rs | 137 ++++++------ core/src/smartcontracts/isi/asset.rs | 225 +++++++++----------- core/src/smartcontracts/isi/block.rs | 40 ++-- core/src/smartcontracts/isi/domain.rs | 26 +-- core/src/smartcontracts/isi/query.rs | 108 ++++++++-- core/src/smartcontracts/isi/triggers/mod.rs | 69 +++--- core/src/smartcontracts/isi/tx.rs | 57 ++--- core/src/smartcontracts/isi/world.rs | 62 ++---- core/src/smartcontracts/mod.rs | 6 +- core/src/sumeragi/main_loop.rs | 1 - core/src/wsv.rs | 6 +- data_model/src/query.rs | 24 ++- 13 files changed, 399 insertions(+), 364 deletions(-) diff --git a/core/benches/apply_blocks/apply_blocks.rs b/core/benches/apply_blocks/apply_blocks.rs index 7c434066a69..917d29dee22 100644 --- a/core/benches/apply_blocks/apply_blocks.rs +++ b/core/benches/apply_blocks/apply_blocks.rs @@ -51,7 +51,7 @@ fn create_block( let pending_block = PendingBlock { header, transactions: vec![TransactionValue { - tx: transaction, + value: transaction, error: None, }], event_recommendations: Vec::new(), diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 3cda1ee2bcf..124f4dfb50e 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -475,73 +475,71 @@ pub mod query { use eyre::{Result, WrapErr}; use iroha_data_model::{ - evaluate::ExpressionEvaluator, query::error::QueryExecutionFail as Error, + evaluate::ExpressionEvaluator, + query::{error::QueryExecutionFail as Error, MetadataValue}, }; use super::*; - use crate::smartcontracts::query::Lazy; + use crate::smartcontracts::query::WsvIterator; impl ValidQuery for FindRolesByAccountId { #[metrics(+"find_roles_by_account_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let account_id = wsv .evaluate(&self.id) .wrap_err("Failed to evaluate account id") .map_err(|e| Error::Evaluate(e.to_string()))?; + iroha_logger::trace!(%account_id, roles=?wsv.world.roles); - Ok(Box::new( - wsv.map_account(&account_id, |account| &account.roles)? - .iter() - .cloned(), - )) + + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.map_account(&account_id, |account| account.roles.iter())? + .cloned(), + )) + }) } } impl ValidQuery for FindPermissionTokensByAccountId { #[metrics(+"find_permission_tokens_by_account_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let account_id = wsv .evaluate(&self.id) .wrap_err("Failed to evaluate account id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%account_id, accounts=?wsv.world.domains); - Ok(Box::new( - wsv.account_permission_tokens(&account_id)?.cloned(), - )) + + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.account_permission_tokens(&account_id)?.cloned(), + )) + }) } } impl ValidQuery for FindAllAccounts { #[metrics(+"find_all_accounts")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new( - wsv.domains() - .values() - .flat_map(|domain| domain.accounts.values()) - .cloned(), - )) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domains() + .values() + .flat_map(|domain| domain.accounts.values()) + .cloned(), + )) + }) } } impl ValidQuery for FindAccountById { #[metrics(+"find_account_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get id") .map_err(|e| Error::Evaluate(e.to_string()))?; + iroha_logger::trace!(%id); wsv.map_account(&id, Clone::clone).map_err(Into::into) } @@ -549,53 +547,49 @@ pub mod query { impl ValidQuery for FindAccountsByName { #[metrics(+"find_account_by_name")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let name = wsv .evaluate(&self.name) .wrap_err("Failed to get account name") .map_err(|e| Error::Evaluate(e.to_string()))?; + iroha_logger::trace!(%name); - Ok(Box::new( - wsv.domains() - .values() - .flat_map(move |domain| { - let name = name.clone(); - - domain - .accounts - .values() - .filter(move |account| account.id().name == name) - }) - .cloned(), - )) + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domains() + .values() + .flat_map(move |domain| { + let name = name.clone(); + + domain + .accounts + .values() + .filter(move |account| account.id().name == name) + }) + .cloned(), + )) + }) } } impl ValidQuery for FindAccountsByDomainId { #[metrics(+"find_accounts_by_domain_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let id = wsv .evaluate(&self.domain_id) .wrap_err("Failed to get domain id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%id); - Ok(Box::new(wsv.domain(&id)?.accounts.values().cloned())) + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new(wsv.domain(&id)?.accounts.values().cloned())) + }) } } impl ValidQuery for FindAccountKeyValueByIdAndKey { #[metrics(+"find_account_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get account id") @@ -613,26 +607,25 @@ pub mod query { impl ValidQuery for FindAccountsWithAsset { #[metrics(+"find_accounts_with_asset")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let asset_definition_id = wsv .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%asset_definition_id); - Ok(Box::new( - wsv.map_domain(&asset_definition_id.domain_id.clone(), move |domain| { - domain.accounts.values().filter(move |account| { - let asset_id = - AssetId::new(asset_definition_id.clone(), account.id().clone()); - account.assets.get(&asset_id).is_some() - }) - })? - .cloned(), - )) + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.map_domain(&asset_definition_id.domain_id.clone(), move |domain| { + domain.accounts.values().filter(move |account| { + let asset_id = + AssetId::new(asset_definition_id.clone(), account.id().clone()); + account.assets.get(&asset_id).is_some() + }) + })? + .cloned(), + )) + }) } } } diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index 32544fc073d..65605a97e15 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -436,58 +436,55 @@ pub mod isi { /// Asset-related query implementations. pub mod query { use eyre::{Result, WrapErr as _}; - use iroha_data_model::query::{ - asset::IsAssetDefinitionOwner, error::QueryExecutionFail as Error, + use iroha_data_model::{ + asset::{Asset, AssetDefinition}, + query::{asset::IsAssetDefinitionOwner, error::QueryExecutionFail as Error, MetadataValue}, }; use super::*; - use crate::smartcontracts::query::Lazy; + use crate::smartcontracts::query::WsvIterator; impl ValidQuery for FindAllAssets { #[metrics(+"find_all_assets")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new( - wsv.domains() - .values() - .flat_map(|domain| { - domain - .accounts - .values() - .flat_map(|account| account.assets.values()) - }) - .cloned(), - )) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domains() + .values() + .flat_map(|domain| { + domain + .accounts + .values() + .flat_map(|account| account.assets.values()) + }) + .cloned(), + )) + }) } } impl ValidQuery for FindAllAssetsDefinitions { #[metrics(+"find_all_asset_definitions")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new( - wsv.domains() - .values() - .flat_map(|domain| domain.asset_definitions.values()) - .cloned(), - )) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domains() + .values() + .flat_map(|domain| domain.asset_definitions.values()) + .cloned(), + )) + }) } } impl ValidQuery for FindAssetById { #[metrics(+"find_asset_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset id") .map_err(|e| Error::Evaluate(e.to_string()))?; + iroha_logger::trace!(%id); wsv.asset(&id).map_err(|asset_err| { if let Err(definition_err) = wsv.asset_definition(&id.definition_id) { @@ -501,10 +498,7 @@ pub mod query { impl ValidQuery for FindAssetDefinitionById { #[metrics(+"find_asset_defintion_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset definition id") @@ -518,108 +512,100 @@ pub mod query { impl ValidQuery for FindAssetsByName { #[metrics(+"find_assets_by_name")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let name = wsv .evaluate(&self.name) .wrap_err("Failed to get asset name") .map_err(|e| Error::Evaluate(e.to_string()))?; - iroha_logger::trace!(%name); - Ok(Box::new( - wsv.domains() - .values() - .flat_map(move |domain| { - let name = name.clone(); - domain.accounts.values().flat_map(move |account| { + iroha_logger::trace!(%name); + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domains() + .values() + .flat_map(move |domain| { let name = name.clone(); - account - .assets - .values() - .filter(move |asset| asset.id().definition_id.name == name) + domain.accounts.values().flat_map(move |account| { + let name = name.clone(); + + account + .assets + .values() + .filter(move |asset| asset.id().definition_id.name == name) + }) }) - }) - .cloned(), - )) + .cloned(), + )) + }) } } impl ValidQuery for FindAssetsByAccountId { #[metrics(+"find_assets_by_account_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let id = wsv .evaluate(&self.account_id) .wrap_err("Failed to get account id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%id); - Ok(Box::new(wsv.account_assets(&id)?)) + WsvIterator::::new(wsv, |wsv| Ok(Box::new(wsv.account_assets(&id)?.cloned()))) } } impl ValidQuery for FindAssetsByAssetDefinitionId { #[metrics(+"find_assets_by_asset_definition_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let id = wsv .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset definition id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%id); - Ok(Box::new( - wsv.domains() - .values() - .flat_map(move |domain| { - let id = id.clone(); - - domain.accounts.values().flat_map(move |account| { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domains() + .values() + .flat_map(move |domain| { let id = id.clone(); - account - .assets - .values() - .filter(move |asset| asset.id().definition_id == id) + domain.accounts.values().flat_map(move |account| { + let id = id.clone(); + + account + .assets + .values() + .filter(move |asset| asset.id().definition_id == id) + }) }) - }) - .cloned(), - )) + .cloned(), + )) + }) } } impl ValidQuery for FindAssetsByDomainId { #[metrics(+"find_assets_by_domain_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let id = wsv .evaluate(&self.domain_id) .wrap_err("Failed to get domain id") .map_err(|e| Error::Evaluate(e.to_string()))?; iroha_logger::trace!(%id); - Ok(Box::new( - wsv.domain(&id)? - .accounts - .values() - .flat_map(|account| account.assets.values()) - .cloned(), - )) + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domain(&id)? + .accounts + .values() + .flat_map(|account| account.assets.values()) + .cloned(), + )) + }) } } impl ValidQuery for FindAssetsByDomainIdAndAssetDefinitionId { #[metrics(+"find_assets_by_domain_id_and_asset_definition_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { let domain_id = wsv .evaluate(&self.domain_id) .wrap_err("Failed to get domain id") @@ -628,36 +614,36 @@ pub mod query { .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset definition id") .map_err(|e| Error::Evaluate(e.to_string()))?; - let domain = wsv.domain(&domain_id)?; - let _definition = domain + let _definition = wsv + .domain(&domain_id)? .asset_definitions .get(&asset_definition_id) .ok_or_else(|| FindError::AssetDefinition(asset_definition_id.clone()))?; iroha_logger::trace!(%domain_id, %asset_definition_id); - Ok(Box::new( - domain - .accounts - .values() - .flat_map(move |account| { - let domain_id = domain_id.clone(); - let asset_definition_id = asset_definition_id.clone(); - - account.assets.values().filter(move |asset| { - asset.id().account_id.domain_id == domain_id - && asset.id().definition_id == asset_definition_id + + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.domain(&domain_id)? + .accounts + .values() + .flat_map(move |account| { + let domain_id = domain_id.clone(); + let asset_definition_id = asset_definition_id.clone(); + + account.assets.values().filter(move |asset| { + asset.id().account_id.domain_id == domain_id + && asset.id().definition_id == asset_definition_id + }) }) - }) - .cloned(), - )) + .cloned(), + )) + }) } } impl ValidQuery for FindAssetQuantityById { #[metrics(+"find_asset_quantity_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset id") @@ -681,10 +667,7 @@ pub mod query { impl ValidQuery for FindTotalAssetQuantityByAssetDefinitionId { #[metrics(+"find_total_asset_quantity_by_asset_definition_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset definition id") @@ -697,10 +680,7 @@ pub mod query { impl ValidQuery for FindAssetKeyValueByIdAndKey { #[metrics(+"find_asset_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset id") @@ -732,10 +712,7 @@ pub mod query { impl ValidQuery for IsAssetDefinitionOwner { #[metrics("is_asset_definition_owner")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let asset_definition_id = wsv .evaluate(&self.asset_definition_id) .wrap_err("Failed to get asset definition id") diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index d70c95ad998..1b61d507d54 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -1,6 +1,7 @@ //! This module contains trait implementations related to block queries use eyre::{Result, WrapErr}; use iroha_data_model::{ + block::{BlockHeader, VersionedCommittedBlock}, evaluate::ExpressionEvaluator, query::{ block::FindBlockHeaderByHash, @@ -10,40 +11,41 @@ use iroha_data_model::{ use iroha_telemetry::metrics; use super::*; -use crate::smartcontracts::query::Lazy; +use crate::smartcontracts::query::WsvIterator; impl ValidQuery for FindAllBlocks { #[metrics(+"find_all_blocks")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { - Ok(Box::new( - wsv.all_blocks().rev().map(|block| Clone::clone(&*block)), - )) + wsv: &WorldStateView, + ) -> Result, QueryExecutionFail> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.all_blocks().rev().map(|block| Clone::clone(&*block)), + )) + }) } } impl ValidQuery for FindAllBlockHeaders { #[metrics(+"find_all_block_headers")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { - Ok(Box::new( - wsv.all_blocks() - .rev() - .map(|block| block.as_v1().header.clone()), - )) + wsv: &WorldStateView, + ) -> Result, QueryExecutionFail> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.all_blocks() + .rev() + .map(|block| block.as_v1().header.clone()), + )) + }) } } impl ValidQuery for FindBlockHeaderByHash { #[metrics(+"find_block_header")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + fn execute(&self, wsv: &WorldStateView) -> Result { let hash = wsv .evaluate(&self.hash) .wrap_err("Failed to evaluate hash") diff --git a/core/src/smartcontracts/isi/domain.rs b/core/src/smartcontracts/isi/domain.rs index e208457a9dc..9428203fa5b 100644 --- a/core/src/smartcontracts/isi/domain.rs +++ b/core/src/smartcontracts/isi/domain.rs @@ -288,27 +288,21 @@ pub mod isi { /// Query module provides [`Query`] Domain related implementations. pub mod query { use eyre::{Result, WrapErr}; - use iroha_data_model::query::error::QueryExecutionFail as Error; + use iroha_data_model::query::{error::QueryExecutionFail as Error, MetadataValue}; use super::*; - use crate::smartcontracts::query::Lazy; + use crate::smartcontracts::query::WsvIterator; impl ValidQuery for FindAllDomains { #[metrics(+"find_all_domains")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new(wsv.domains().values().cloned())) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| Ok(Box::new(wsv.domains().values().cloned()))) } } impl ValidQuery for FindDomainById { #[metrics(+"find_domain_by_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get domain id") @@ -320,10 +314,7 @@ pub mod query { impl ValidQuery for FindDomainKeyValueByIdAndKey { #[metrics(+"find_domain_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get domain id") @@ -341,10 +332,7 @@ pub mod query { impl ValidQuery for FindAssetDefinitionKeyValueByIdAndKey { #[metrics(+"find_asset_definition_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .wrap_err("Failed to get asset definition id") diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index a5d7c67da14..145eb7cece6 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -5,8 +5,20 @@ clippy::std_instead_of_core, clippy::std_instead_of_alloc )] + +use core::pin::Pin; +use std::{marker::PhantomPinned, ptr::NonNull}; + use eyre::Result; -use iroha_data_model::{prelude::*, query::error::QueryExecutionFail as Error}; +use iroha_data_model::{ + block::{BlockHeader, VersionedCommittedBlock}, + parameter::Parameter, + peer::Peer, + permission::PermissionTokenDefinition, + prelude::*, + query::error::QueryExecutionFail as Error, + trigger::OptimizedExecutable, +}; use parity_scale_codec::{Decode, Encode}; use crate::{prelude::ValidQuery, WorldStateView}; @@ -14,29 +26,97 @@ use crate::{prelude::ValidQuery, WorldStateView}; /// Represents lazy evaluated query output pub trait Lazy { /// Type of the lazy evaluated query output - type Lazy<'a>; + type Lazy; } /// Lazily evaluated equivalent of [`Value`] -pub enum LazyValue<'a> { +pub enum LazyValue { /// Concrete computed [`Value`] Value(Value), /// Iterator over a set of [`Value`]s - Iter(Box + 'a>), + Iter(Box>), +} + +struct WsvIteratorInternal { + // NOTE: Contains references into wsv is best be dropped before wsv + iter: NonNull>, + wsv: WorldStateView, + _pinned: PhantomPinned, +} + +// TODO: Can't it be a pub(crate) type? +pub struct WsvIterator(Pin>>); +impl WsvIterator { + fn get_inner_mut(&mut self) -> &mut dyn Iterator { + unsafe { self.0.as_mut().get_unchecked_mut().iter.as_mut() } + } +} + +impl Iterator for WsvIterator { + type Item = T; + + fn next(&mut self) -> Option { + self.get_inner_mut().next() + } +} + +// FIXME: due to current limitations in the borrow checker, this implies a `'static` lifetime [E0521] +macro_rules! impl_new { + ($($ty:ty),* $(,)?) => { $( + impl WsvIterator<$ty> { + pub fn new(wsv: &WorldStateView, wsv_mapper: F) -> Result + where + for<'a> F: FnOnce(&'a WorldStateView) -> Result + 'a>, Error>, { + const DUMMY_ITER: core::iter::Empty<$ty> = core::iter::empty(); + + let mut wsv_iter = Box::pin(WsvIteratorInternal { + wsv: wsv.clone(), + iter: NonNull::from(&DUMMY_ITER), + _pinned: PhantomPinned, + }); + + // SAFETY: remove pesky lifetime limitation + let wsv_iter_ref: &WsvIteratorInternal<_> = unsafe { &*(wsv_iter.as_ref().get_ref() as *const _) }; + let wsv_iter_ptr_mut = NonNull::new(Box::into_raw(wsv_mapper(&wsv_iter_ref.wsv)?)).expect("Pointer must be non-null"); + + unsafe { wsv_iter.as_mut().get_unchecked_mut().iter = wsv_iter_ptr_mut } + + + Ok(Self(wsv_iter)) + } + } )* + }; } +impl_new! { Account, Role, RoleId, PermissionToken, Asset, AssetDefinition, Domain, Value, TransactionQueryResult, VersionedCommittedBlock, PermissionTokenDefinition, Peer, Parameter, Trigger, TriggerId, BlockHeader } + +//impl WsvIterator { +// pub fn new(wsv: &WorldStateView, wsv_mapper: F) -> Result +// where +// for<'a> F: FnOnce(&'a WorldStateView) -> Result + 'a>, Error>, +// { +// let dummy_iter = core::iter::empty(); +// let wsv_iter = Box::pin(WsvIteratorInternal { +// wsv: wsv.clone(), +// iter: NonNull::from(&dummy_iter), +// _pinned: PhantomPinned, +// }); +// +// Ok(Self(wsv_iter)) +// } +//} impl Lazy for Value { - type Lazy<'a> = LazyValue<'a>; + type Lazy = LazyValue; } impl Lazy for Vec { - type Lazy<'a> = Box + 'a>; + type Lazy = WsvIterator; } macro_rules! impl_lazy { ( $($ident:ty),+ $(,)? ) => { $( impl Lazy for $ident { - type Lazy<'a> = Self; + type Lazy = Self; } )+ }; } @@ -90,11 +170,12 @@ impl ValidQueryRequest { /// /// # Errors /// Forwards `self.query.execute` error. - pub fn execute<'wsv>(&'wsv self, wsv: &'wsv WorldStateView) -> Result, Error> { + pub fn execute(&self, wsv: &WorldStateView) -> Result { let value = self.0.query().execute(wsv)?; Ok(if let LazyValue::Iter(iter) = value { - LazyValue::Iter(Box::new(iter.filter(|val| self.0.filter().applies(val)))) + //let iter = iter.filter(|val| self.0.filter().applies(val)); + LazyValue::Iter(iter) } else { value }) @@ -110,17 +191,14 @@ impl ValidQueryRequest { } impl ValidQuery for QueryBox { - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { iroha_logger::debug!(query=%self, "Executing"); macro_rules! match_all { ( non_iter: {$( $non_iter_query:ident ),+ $(,)?} $( $query:ident, )+ ) => { match self { $( QueryBox::$non_iter_query(query) => query.execute(wsv).map(Value::from).map(LazyValue::Value), )+ $( - QueryBox::$query(query) => query.execute(wsv).map(|i| i.map(Value::from)).map(|iter| LazyValue::Iter(Box::new(iter))), )+ + QueryBox::$query(query) => query.execute(wsv).map(|iter| LazyValue::Iter(Box::new(iter.map(Value::from)))), )+ } }; } @@ -469,7 +547,7 @@ mod tests { if found_accepted.transaction.error.is_none() { assert_eq!( va_tx.hash().transmute(), - found_accepted.transaction.tx.hash() + found_accepted.transaction.value.hash() ) } Ok(()) diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index 6e2e9613ca9..916a58b35a9 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -195,27 +195,27 @@ pub mod isi { pub mod query { //! Queries associated to triggers. - use iroha_data_model::query::error::QueryExecutionFail as Error; + use iroha_data_model::{ + query::{error::QueryExecutionFail as Error, MetadataValue}, + trigger::{OptimizedExecutable, TriggerId}, + }; use super::*; - use crate::{prelude::*, smartcontracts::query::Lazy}; + use crate::{prelude::*, smartcontracts::query::WsvIterator}; impl ValidQuery for FindAllActiveTriggerIds { #[metrics(+"find_all_active_triggers")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new(wsv.triggers().ids().cloned())) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| Ok(Box::new(wsv.triggers().ids().cloned()))) } } impl ValidQuery for FindTriggerById { #[metrics(+"find_trigger_by_id")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + wsv: &WorldStateView, + ) -> Result, Error> { let id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate trigger id. {e}")))?; @@ -243,10 +243,7 @@ pub mod query { impl ValidQuery for FindTriggerKeyValueByIdAndKey { #[metrics(+"find_trigger_key_value_by_id_and_key")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate trigger id. {e}")))?; @@ -269,32 +266,34 @@ pub mod query { impl ValidQuery for FindTriggersByDomainId { #[metrics(+"find_triggers_by_domain_id")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> eyre::Result<::Lazy<'wsv>, Error> { + wsv: &WorldStateView, + ) -> eyre::Result>, Error> { let domain_id = wsv .evaluate(&self.domain_id) .map_err(|e| Error::Evaluate(format!("Failed to evaluate domain id. {e}")))?; - Ok(Box::new(wsv.triggers().inspect_by_domain_id( - &domain_id, - |trigger_id, action| { - let Action { - executable: loaded_executable, - repeats, - authority, - filter, - metadata, - } = action.clone_and_box(); - - Trigger::new( - trigger_id.clone(), - Action::new(loaded_executable, repeats, authority, filter) - .with_metadata(metadata), - ) - }, - ))) + WsvIterator::>::new(wsv, |wsv| { + Ok(Box::new(wsv.triggers().inspect_by_domain_id( + &domain_id, + |trigger_id, action| { + let Action { + executable: loaded_executable, + repeats, + authority, + filter, + metadata, + } = action.clone_and_box(); + + Trigger::new( + trigger_id.clone(), + Action::new(loaded_executable, repeats, authority, filter) + .with_metadata(metadata), + ) + }, + ))) + }) } } } diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index 2c87fa781cb..843c50c71a0 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -16,7 +16,7 @@ use iroha_data_model::{ }; use iroha_telemetry::metrics; -use super::{query::Lazy, *}; +use super::{query::WsvIterator, *}; pub(crate) struct BlockTransactionIter(Arc, usize); pub(crate) struct BlockTransactionRef(Arc, usize); @@ -58,50 +58,51 @@ impl BlockTransactionRef { impl ValidQuery for FindAllTransactions { #[metrics(+"find_all_transactions")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { - Ok(Box::new( - wsv.all_blocks() - .flat_map(BlockTransactionIter::new) - .map(|tx| TransactionQueryResult { - block_hash: tx.block_hash(), - transaction: tx.value(), - }), - )) + wsv: &WorldStateView, + ) -> Result, QueryExecutionFail> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.all_blocks() + .flat_map(BlockTransactionIter::new) + .map(|tx| TransactionQueryResult { + block_hash: tx.block_hash(), + transaction: tx.value(), + }), + )) + }) } } impl ValidQuery for FindTransactionsByAccountId { #[metrics(+"find_transactions_by_account_id")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + wsv: &WorldStateView, + ) -> Result, QueryExecutionFail> { let account_id = wsv .evaluate(&self.account_id) .wrap_err("Failed to get account id") .map_err(|e| QueryExecutionFail::Evaluate(e.to_string()))?; - Ok(Box::new( - wsv.all_blocks() - .flat_map(BlockTransactionIter::new) - .filter(move |tx| *tx.authority() == account_id) - .map(|tx| TransactionQueryResult { - block_hash: tx.block_hash(), - transaction: tx.value(), - }), - )) + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.all_blocks() + .flat_map(BlockTransactionIter::new) + .filter(move |tx| *tx.authority() == account_id) + .map(|tx| TransactionQueryResult { + block_hash: tx.block_hash(), + transaction: tx.value(), + }), + )) + }) } } impl ValidQuery for FindTransactionByHash { #[metrics(+"find_transaction_by_hash")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail> { + fn execute(&self, wsv: &WorldStateView) -> Result { let tx_hash = wsv .evaluate(&self.hash) .wrap_err("Failed to get hash") diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index f81fe0f44f1..abb192fcafa 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -421,40 +421,27 @@ pub mod query { }; use super::*; - use crate::smartcontracts::query::Lazy; + use crate::smartcontracts::query::WsvIterator; impl ValidQuery for FindAllRoles { #[metrics(+"find_all_roles")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new(wsv.world.roles.values().cloned())) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| Ok(Box::new(wsv.world.roles.values().cloned()))) } } impl ValidQuery for FindAllRoleIds { #[metrics(+"find_all_role_ids")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new(wsv - .world - .roles - .values() - // To me, this should probably be a method, not a field. - .map(Role::id) - .cloned())) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new(wsv.world.roles.values().map(Role::id).cloned())) + }) } } impl ValidQuery for FindRoleByRoleId { #[metrics(+"find_role_by_role_id")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let role_id = wsv .evaluate(&self.id) .map_err(|e| Error::Evaluate(e.to_string()))?; @@ -469,42 +456,35 @@ pub mod query { impl ValidQuery for FindAllPeers { #[metrics("find_all_peers")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new(wsv.peers().cloned().map(Peer::new))) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| Ok(Box::new(wsv.peers().cloned().map(Peer::new)))) } } impl ValidQuery for FindAllPermissionTokenDefinitions { #[metrics("find_all_token_ids")] - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new( - wsv.permission_token_definitions().values().cloned(), - )) + wsv: &WorldStateView, + ) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| { + Ok(Box::new( + wsv.permission_token_definitions().values().cloned(), + )) + }) } } impl ValidQuery for FindAllParameters { #[metrics("find_all_parameters")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { - Ok(Box::new(wsv.parameters().cloned())) + fn execute(&self, wsv: &WorldStateView) -> Result, Error> { + WsvIterator::::new(wsv, |wsv| Ok(Box::new(wsv.parameters().cloned()))) } } impl ValidQuery for DoesAccountHavePermissionToken { #[metrics("does_account_have_permission")] - fn execute<'wsv>( - &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, Error> { + fn execute(&self, wsv: &WorldStateView) -> Result { let authority = wsv .evaluate(&self.account_id) .map_err(|e| Error::Evaluate(e.to_string()))?; diff --git a/core/src/smartcontracts/mod.rs b/core/src/smartcontracts/mod.rs index ebab9f86afe..dc612b54f45 100644 --- a/core/src/smartcontracts/mod.rs +++ b/core/src/smartcontracts/mod.rs @@ -39,10 +39,10 @@ where /// /// # Errors /// Concrete to each implementer - fn execute<'wsv>( + fn execute( &self, - wsv: &'wsv WorldStateView, - ) -> Result<::Lazy<'wsv>, QueryExecutionFail>; + wsv: &WorldStateView, + ) -> Result<::Lazy, QueryExecutionFail>; } impl ExpressionEvaluator for WorldStateView { diff --git a/core/src/sumeragi/main_loop.rs b/core/src/sumeragi/main_loop.rs index 42c65d33867..8baa337c059 100644 --- a/core/src/sumeragi/main_loop.rs +++ b/core/src/sumeragi/main_loop.rs @@ -353,7 +353,6 @@ impl Sumeragi { // https://github.com/hyperledger/iroha/issues/3396 // Kura should store the block only upon successful application to the internal WSV to avoid storing a corrupted block. // Public-facing WSV update should happen after that and be followed by `BlockCommited` event to prevent client access to uncommitted data. - // TODO: Redundant clone Strategy::kura_store_block(&self.kura, committed_block); // Update WSV copy that is public facing diff --git a/core/src/wsv.rs b/core/src/wsv.rs index a9576b6455f..33914c71650 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -158,8 +158,8 @@ impl WorldStateView { pub fn account_assets( &self, id: &AccountId, - ) -> Result + '_, QueryExecutionFail> { - self.map_account(id, |account| account.assets.values().cloned()) + ) -> Result, QueryExecutionFail> { + self.map_account(id, |account| account.assets.values()) } /// Return a set of all permission tokens granted to this account. @@ -579,7 +579,7 @@ impl WorldStateView { /// /// # Errors /// Fails if there is no domain - pub fn domain<'wsv>(&'wsv self, id: &DomainId) -> Result<&'wsv Domain, FindError> { + pub fn domain(&self, id: &DomainId) -> Result<&Domain, FindError> { let domain = self .world .domains diff --git a/data_model/src/query.rs b/data_model/src/query.rs index a704a87c342..fe6b907ab73 100644 --- a/data_model/src/query.rs +++ b/data_model/src/query.rs @@ -176,18 +176,34 @@ pub mod model { /// The hash of the block to which `tx` belongs to pub block_hash: HashOf, } -} -/// Type returned from [`Metadata`] queries -pub struct MetadataValue(Value); + /// Type returned from [`Metadata`] queries + #[derive( + Debug, + Clone, + PartialEq, + Eq, + PartialOrd, + Ord, + Decode, + Encode, + Deserialize, + Serialize, + IntoSchema, + )] + #[ffi_type] + pub struct MetadataValue(pub Value); +} impl From for Value { + #[inline] fn from(source: MetadataValue) -> Self { source.0 } } impl From for MetadataValue { + #[inline] fn from(source: Value) -> Self { Self(source) } @@ -1369,6 +1385,7 @@ pub mod http { }) } } + impl Decode for SignedQuery { fn decode(input: &mut I) -> Result { SignedQueryCandidate::decode(input)? @@ -1376,6 +1393,7 @@ pub mod http { .map_err(Into::into) } } + impl<'de> Deserialize<'de> for SignedQuery { fn deserialize(deserializer: D) -> Result where