From 55de672264fdecea68d6251b0def0f914ea8ea46 Mon Sep 17 00:00:00 2001 From: Shanin Roman Date: Tue, 19 Mar 2024 18:28:01 +0300 Subject: [PATCH] [refactor]: remove WorldSnapshot and StateSnapshot Signed-off-by: Shanin Roman --- Cargo.lock | 2 +- Cargo.toml | 2 +- cli/src/lib.rs | 2 +- core/src/block_sync.rs | 7 +- core/src/executor.rs | 14 +- core/src/lib.rs | 2 +- core/src/smartcontracts/isi/account.rs | 54 +-- core/src/smartcontracts/isi/asset.rs | 83 ++-- core/src/smartcontracts/isi/block.rs | 18 +- core/src/smartcontracts/isi/domain.rs | 24 +- core/src/smartcontracts/isi/mod.rs | 6 +- core/src/smartcontracts/isi/query.rs | 53 ++- core/src/smartcontracts/isi/triggers/mod.rs | 38 +- core/src/smartcontracts/isi/tx.rs | 15 +- core/src/smartcontracts/isi/world.rs | 39 +- core/src/smartcontracts/mod.rs | 4 +- core/src/smartcontracts/wasm.rs | 132 +++--- core/src/snapshot.rs | 2 +- core/src/state.rs | 411 +++++++----------- core/src/sumeragi/mod.rs | 5 +- core/src/tx.rs | 2 +- core/test_network/src/lib.rs | 1 + telemetry/derive/src/lib.rs | 17 +- .../derive/tests/ui_fail/args_no_wsv.stderr | 2 +- telemetry/derive/tests/ui_fail/no_args.stderr | 2 +- torii/src/routing.rs | 5 +- 26 files changed, 430 insertions(+), 512 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 180d4eddc09..25fdf79ec11 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -5304,7 +5304,7 @@ dependencies = [ [[package]] name = "storage" version = "0.1.0" -source = "git+https://github.com/Erigara/storage.git?rev=232843aab94770089ecbffe8c8e8cb24c9cedb62#232843aab94770089ecbffe8c8e8cb24c9cedb62" +source = "git+https://github.com/Erigara/storage.git?rev=79689ae68573bfe4c4d80d902c726d84fec22257#79689ae68573bfe4c4d80d902c726d84fec22257" dependencies = [ "concread", "serde", diff --git a/Cargo.toml b/Cargo.toml index 940423c7db1..f7ac885a380 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -134,7 +134,7 @@ parity-scale-codec = { version = "3.6.5", default-features = false } json5 = "0.4.1" toml = "0.8.8" -storage = { git = "https://github.com/Erigara/storage.git", rev = "232843aab94770089ecbffe8c8e8cb24c9cedb62" } +storage = { git = "https://github.com/Erigara/storage.git", rev = "79689ae68573bfe4c4d80d902c726d84fec22257" } [workspace.lints] rustdoc.private_doc_tests = "deny" diff --git a/cli/src/lib.rs b/cli/src/lib.rs index 80edb2adada..eb631467a21 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -22,7 +22,7 @@ use iroha_core::{ snapshot::{ try_read_snapshot, SnapshotMaker, SnapshotMakerHandle, TryReadError as TryReadSnapshotError, }, - state::{State, World}, + state::{State, StateReadOnly, World}, sumeragi::{SumeragiHandle, SumeragiStartArgs}, IrohaNetwork, }; diff --git a/core/src/block_sync.rs b/core/src/block_sync.rs index a88903fa812..d2e5c6b7219 100644 --- a/core/src/block_sync.rs +++ b/core/src/block_sync.rs @@ -10,7 +10,12 @@ use iroha_p2p::Post; use parity_scale_codec::{Decode, Encode}; use tokio::sync::mpsc; -use crate::{kura::Kura, state::State, sumeragi::SumeragiHandle, IrohaNetwork, NetworkMessage}; +use crate::{ + kura::Kura, + state::{State, StateReadOnly}, + sumeragi::SumeragiHandle, + IrohaNetwork, NetworkMessage, +}; /// [`BlockSynchronizer`] actor handle. #[derive(Clone)] diff --git a/core/src/executor.rs b/core/src/executor.rs index 38da0d0b0e1..2f760b1aea7 100644 --- a/core/src/executor.rs +++ b/core/src/executor.rs @@ -17,7 +17,7 @@ use serde::{ use crate::{ smartcontracts::{wasm, Execute as _}, - state::{deserialize::WasmSeed, StateSnapshot, StateTransaction}, + state::{deserialize::WasmSeed, StateReadOnly, StateTransaction}, }; impl From for ValidationFail { @@ -213,9 +213,9 @@ impl Executor { /// - Failed to prepare runtime for WASM execution; /// - Failed to execute the entrypoint of the WASM blob; /// - Executor denied the operation. - pub fn validate_query( + pub fn validate_query( &self, - state_snapshot: &StateSnapshot<'_>, + state_ro: &S, authority: &AccountId, query: QueryBox, ) -> Result<(), ValidationFail> { @@ -224,13 +224,13 @@ impl Executor { match self { Self::Initial => Ok(()), Self::UserProvided(UserProvidedExecutor(loaded_executor)) => { - let runtime = wasm::RuntimeBuilder::::new() - .with_engine(state_snapshot.engine.clone()) // Cloning engine is cheap, see [`wasmtime::Engine`] docs - .with_config(state_snapshot.config.executor_runtime) + let runtime = wasm::RuntimeBuilder::>::new() + .with_engine(state_ro.engine().clone()) // Cloning engine is cheap, see [`wasmtime::Engine`] docs + .with_config(state_ro.config().executor_runtime) .build()?; runtime.execute_executor_validate_query( - state_snapshot, + state_ro, authority, &loaded_executor.module, query, diff --git a/core/src/lib.rs b/core/src/lib.rs index 75051059e74..ab0b9be0d6b 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -161,7 +161,7 @@ pub mod prelude { #[doc(inline)] pub use crate::{ smartcontracts::ValidQuery, - state::{StateView, World}, + state::{StateReadOnly, StateView, World, WorldReadOnly}, tx::AcceptedTransaction, }; } diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 1e9124f9255..aa814e37f7a 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -598,18 +598,18 @@ pub mod query { }; use super::*; - use crate::state::StateSnapshot; + use crate::state::StateReadOnly; impl ValidQuery for FindRolesByAccountId { #[metrics(+"find_roles_by_account_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let account_id = &self.id; - state_snapshot.world.account(account_id)?; + state_ro.world().account(account_id)?; Ok(Box::new( - state_snapshot.world.account_roles(account_id).cloned(), + state_ro.world().account_roles_iter(account_id).cloned(), )) } } @@ -618,13 +618,13 @@ pub mod query { #[metrics(+"find_permission_tokens_by_account_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let account_id = &self.id; Ok(Box::new( - state_snapshot - .world - .account_permission_tokens(account_id)? + state_ro + .world() + .account_permission_tokens_iter(account_id)? .cloned(), )) } @@ -634,12 +634,12 @@ pub mod query { #[metrics(+"find_all_accounts")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { Ok(Box::new( - state_snapshot - .world - .domains() + state_ro + .world() + .domains_iter() .flat_map(|domain| domain.accounts.values()) .cloned(), )) @@ -648,11 +648,11 @@ pub mod query { impl ValidQuery for FindAccountById { #[metrics(+"find_account_by_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; iroha_logger::trace!(%id); - state_snapshot - .world + state_ro + .world() .map_account(id, Clone::clone) .map_err(Into::into) } @@ -662,14 +662,14 @@ pub mod query { #[metrics(+"find_account_by_name")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let name = self.name.clone(); iroha_logger::trace!(%name); Ok(Box::new( - state_snapshot - .world - .domains() + state_ro + .world() + .domains_iter() .flat_map(move |domain| { let name = name.clone(); @@ -687,25 +687,25 @@ pub mod query { #[metrics(+"find_accounts_by_domain_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let id = &self.domain_id; iroha_logger::trace!(%id); Ok(Box::new( - state_snapshot.world.domain(id)?.accounts.values().cloned(), + state_ro.world().domain(id)?.accounts.values().cloned(), )) } } impl ValidQuery for FindAccountKeyValueByIdAndKey { #[metrics(+"find_account_key_value_by_id_and_key")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; let key = &self.key; iroha_logger::trace!(%id, %key); - state_snapshot - .world + state_ro + .world() .map_account(id, |account| account.metadata.get(key).cloned())? .ok_or_else(|| FindError::MetadataKey(key.clone()).into()) .map(Into::into) @@ -716,14 +716,14 @@ pub mod query { #[metrics(+"find_accounts_with_asset")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let asset_definition_id = self.asset_definition_id.clone(); iroha_logger::trace!(%asset_definition_id); Ok(Box::new( - state_snapshot - .world + state_ro + .world() .map_domain(&asset_definition_id.domain_id.clone(), move |domain| { domain.accounts.values().filter(move |account| { let asset_id = diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index bc81839bd60..78d7ff998b5 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -432,18 +432,18 @@ pub mod query { }; use super::*; - use crate::state::StateSnapshot; + use crate::state::StateReadOnly; impl ValidQuery for FindAllAssets { #[metrics(+"find_all_assets")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { Ok(Box::new( - state_snapshot - .world - .domains() + state_ro + .world() + .domains_iter() .flat_map(|domain| { domain .accounts @@ -459,12 +459,12 @@ pub mod query { #[metrics(+"find_all_asset_definitions")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { Ok(Box::new( - state_snapshot - .world - .domains() + state_ro + .world() + .domains_iter() .flat_map(|domain| domain.asset_definitions.values()) .cloned(), )) @@ -473,13 +473,11 @@ pub mod query { impl ValidQuery for FindAssetById { #[metrics(+"find_asset_by_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; iroha_logger::trace!(%id); - state_snapshot.world.asset(id).map_err(|asset_err| { - if let Err(definition_err) = - state_snapshot.world.asset_definition(&id.definition_id) - { + state_ro.world().asset(id).map_err(|asset_err| { + if let Err(definition_err) = state_ro.world().asset_definition(&id.definition_id) { definition_err.into() } else { asset_err @@ -490,13 +488,10 @@ pub mod query { impl ValidQuery for FindAssetDefinitionById { #[metrics(+"find_asset_defintion_by_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; - let entry = state_snapshot - .world - .asset_definition(id) - .map_err(Error::from)?; + let entry = state_ro.world().asset_definition(id).map_err(Error::from)?; Ok(entry) } @@ -506,14 +501,14 @@ pub mod query { #[metrics(+"find_assets_by_name")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let name = self.name.clone(); iroha_logger::trace!(%name); Ok(Box::new( - state_snapshot - .world - .domains() + state_ro + .world() + .domains_iter() .flat_map(move |domain| { let name = name.clone(); @@ -535,11 +530,11 @@ pub mod query { #[metrics(+"find_assets_by_account_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let id = &self.account_id; iroha_logger::trace!(%id); - Ok(Box::new(state_snapshot.world.account_assets(id)?.cloned())) + Ok(Box::new(state_ro.world().account_assets(id)?.cloned())) } } @@ -547,14 +542,14 @@ pub mod query { #[metrics(+"find_assets_by_asset_definition_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let id = self.asset_definition_id.clone(); iroha_logger::trace!(%id); Ok(Box::new( - state_snapshot - .world - .domains() + state_ro + .world() + .domains_iter() .flat_map(move |domain| { let id = id.clone(); @@ -576,13 +571,13 @@ pub mod query { #[metrics(+"find_assets_by_domain_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let id = &self.domain_id; iroha_logger::trace!(%id); Ok(Box::new( - state_snapshot - .world + state_ro + .world() .domain(id)? .accounts .values() @@ -596,11 +591,11 @@ pub mod query { #[metrics(+"find_assets_by_domain_id_and_asset_definition_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { let domain_id = self.domain_id.clone(); let asset_definition_id = self.asset_definition_id.clone(); - let domain = state_snapshot.world.domain(&domain_id)?; + let domain = state_ro.world().domain(&domain_id)?; let _definition = domain .asset_definitions .get(&asset_definition_id) @@ -626,15 +621,15 @@ pub mod query { impl ValidQuery for FindAssetQuantityById { #[metrics(+"find_asset_quantity_by_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; iroha_logger::trace!(%id); - let value = state_snapshot - .world + let value = state_ro + .world() .asset(id) .map_err(|asset_err| { if let Err(definition_err) = - state_snapshot.world.asset_definition(&id.definition_id) + state_ro.world().asset_definition(&id.definition_id) { Error::Find(definition_err) } else { @@ -654,23 +649,21 @@ pub mod query { impl ValidQuery for FindTotalAssetQuantityByAssetDefinitionId { #[metrics(+"find_total_asset_quantity_by_asset_definition_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; iroha_logger::trace!(%id); - let asset_value = state_snapshot.world.asset_total_amount(id)?; + let asset_value = state_ro.world().asset_total_amount(id)?; Ok(asset_value) } } impl ValidQuery for FindAssetKeyValueByIdAndKey { #[metrics(+"find_asset_key_value_by_id_and_key")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; let key = &self.key; - let asset = state_snapshot.world.asset(id).map_err(|asset_err| { - if let Err(definition_err) = - state_snapshot.world.asset_definition(&id.definition_id) - { + let asset = state_ro.world().asset(id).map_err(|asset_err| { + if let Err(definition_err) = state_ro.world().asset_definition(&id.definition_id) { Error::Find(definition_err) } else { asset_err diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index ac44efe2a49..a9aae24e084 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -10,19 +10,16 @@ use iroha_data_model::{ use iroha_telemetry::metrics; use super::*; -use crate::state::StateSnapshot; +use crate::state::StateReadOnly; impl ValidQuery for FindAllBlocks { #[metrics(+"find_all_blocks")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, QueryExecutionFail> { Ok(Box::new( - state_snapshot - .all_blocks() - .rev() - .map(|block| (*block).clone()), + state_ro.all_blocks().rev().map(|block| (*block).clone()), )) } } @@ -31,7 +28,7 @@ impl ValidQuery for FindAllBlockHeaders { #[metrics(+"find_all_block_headers")] fn execute<'state>( &self, - staete_snapshot: &'state StateSnapshot<'state>, + staete_snapshot: &'state impl StateReadOnly, ) -> Result + 'state>, QueryExecutionFail> { Ok(Box::new( staete_snapshot @@ -44,13 +41,10 @@ impl ValidQuery for FindAllBlockHeaders { impl ValidQuery for FindBlockHeaderByHash { #[metrics(+"find_block_header")] - fn execute( - &self, - state_snapshot: &StateSnapshot<'_>, - ) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let hash = self.hash; - let block = state_snapshot + let block = state_ro .all_blocks() .find(|block| block.hash() == hash) .ok_or_else(|| QueryExecutionFail::Find(FindError::Block(hash)))?; diff --git a/core/src/smartcontracts/isi/domain.rs b/core/src/smartcontracts/isi/domain.rs index daeec356a3b..33715ef239c 100644 --- a/core/src/smartcontracts/isi/domain.rs +++ b/core/src/smartcontracts/isi/domain.rs @@ -147,7 +147,7 @@ pub mod isi { let asset_definition_id = self.object_id; let mut assets_to_remove = Vec::new(); - for domain in state_transaction.world.domains() { + for domain in state_transaction.world.domains_iter() { for account in domain.accounts.values() { assets_to_remove.extend( account @@ -367,35 +367,35 @@ pub mod query { }; use super::*; - use crate::state::StateSnapshot; + use crate::state::StateReadOnly; impl ValidQuery for FindAllDomains { #[metrics(+"find_all_domains")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { - Ok(Box::new(state_snapshot.world.domains().cloned())) + Ok(Box::new(state_ro.world().domains_iter().cloned())) } } impl ValidQuery for FindDomainById { #[metrics(+"find_domain_by_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; iroha_logger::trace!(%id); - Ok(state_snapshot.world.domain(id)?.clone()) + Ok(state_ro.world().domain(id)?.clone()) } } impl ValidQuery for FindDomainKeyValueByIdAndKey { #[metrics(+"find_domain_key_value_by_id_and_key")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; let key = &self.key; iroha_logger::trace!(%id, %key); - state_snapshot - .world + state_ro + .world() .map_domain(id, |domain| domain.metadata.get(key).cloned())? .ok_or_else(|| FindError::MetadataKey(key.clone()).into()) .map(Into::into) @@ -404,12 +404,12 @@ pub mod query { impl ValidQuery for FindAssetDefinitionKeyValueByIdAndKey { #[metrics(+"find_asset_definition_key_value_by_id_and_key")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; let key = &self.key; iroha_logger::trace!(%id, %key); - Ok(state_snapshot - .world + Ok(state_ro + .world() .asset_definition(id)? .metadata .get(key) diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index b98fe7f5942..f54d41f234b 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -16,9 +16,13 @@ use iroha_data_model::{ prelude::*, }; use iroha_logger::prelude::*; +use storage::storage::StorageReadOnly; use super::Execute; -use crate::{prelude::*, state::StateTransaction}; +use crate::{ + prelude::*, + state::{StateReadOnly, StateTransaction, WorldReadOnly}, +}; /// Trait for proxy objects used for registration. pub trait Registrable { diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index deea64f3181..8a5c7f2c6fe 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -7,7 +7,10 @@ use iroha_data_model::{ }; use parity_scale_codec::{Decode, Encode}; -use crate::{prelude::ValidQuery, state::StateSnapshot}; +use crate::{ + prelude::ValidQuery, + state::{StateReadOnly, WorldReadOnly}, +}; /// Represents lazy evaluated query output pub trait Lazy { @@ -67,10 +70,10 @@ impl ValidQueryRequest { /// - Account has incorrect permissions pub fn validate( query: SignedQuery, - state_snapshot: &StateSnapshot<'_>, + state_ro: &impl StateReadOnly, ) -> Result { - let account_has_public_key = state_snapshot - .world + let account_has_public_key = state_ro + .world() .map_account(query.authority(), |account| { account.contains_signatory(query.signature().public_key()) }) @@ -81,8 +84,8 @@ impl ValidQueryRequest { )) .into()); } - state_snapshot.world.executor.validate_query( - state_snapshot, + state_ro.world().executor().validate_query( + state_ro, query.authority(), query.query().clone(), )?; @@ -95,9 +98,9 @@ impl ValidQueryRequest { /// Forwards `self.query.execute` error. pub fn execute<'state>( &'state self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result, Error> { - let output = self.0.query().execute(state_snapshot)?; + let output = self.0.query().execute(state_ro)?; Ok(if let LazyQueryOutput::Iter(iter) = output { LazyQueryOutput::Iter(Box::new(iter.filter(|val| self.0.filter().applies(val)))) @@ -118,15 +121,15 @@ impl ValidQueryRequest { impl ValidQuery for QueryBox { fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result, Error> { 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(state_snapshot).map(QueryOutputBox::from).map(LazyQueryOutput::QueryOutput), )+ $( - QueryBox::$query(query) => query.execute(state_snapshot).map(|i| i.map(QueryOutputBox::from)).map(|iter| LazyQueryOutput::Iter(Box::new(iter))), )+ + QueryBox::$non_iter_query(query) => query.execute(state_ro).map(QueryOutputBox::from).map(LazyQueryOutput::QueryOutput), )+ $( + QueryBox::$query(query) => query.execute(state_ro).map(|i| i.map(QueryOutputBox::from)).map(|iter| LazyQueryOutput::Iter(Box::new(iter))), )+ } }; } @@ -344,7 +347,7 @@ mod tests { let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; let asset_id = AssetId::new(asset_definition_id, ALICE_ID.clone()); let bytes = FindAssetKeyValueByIdAndKey::new(asset_id, Name::from_str("Bytes")?) - .execute(&state.view().to_snapshot())?; + .execute(&state.view())?; assert_eq!( MetadataValueBox::Vec(vec![1_u32.into(), 2_u32.into(), 3_u32.into()]), bytes, @@ -359,7 +362,7 @@ mod tests { let state = State::new(world_with_test_account_with_metadata()?, kura, query_handle); let bytes = FindAccountKeyValueByIdAndKey::new(ALICE_ID.clone(), Name::from_str("Bytes")?) - .execute(&state.view().to_snapshot())?; + .execute(&state.view())?; assert_eq!( MetadataValueBox::Vec(vec![1_u32.into(), 2_u32.into(), 3_u32.into()]), bytes, @@ -372,9 +375,7 @@ mod tests { let num_blocks = 100; let state = state_with_test_blocks_and_transactions(num_blocks, 1, 1)?; - let blocks = FindAllBlocks - .execute(&state.view().to_snapshot())? - .collect::>(); + let blocks = FindAllBlocks.execute(&state.view())?.collect::>(); assert_eq!(blocks.len() as u64, num_blocks); assert!(blocks.windows(2).all(|wnd| wnd[0] >= wnd[1])); @@ -388,7 +389,7 @@ mod tests { let state = state_with_test_blocks_and_transactions(num_blocks, 1, 1)?; let block_headers = FindAllBlockHeaders - .execute(&state.view().to_snapshot())? + .execute(&state.view())? .collect::>(); assert_eq!(block_headers.len() as u64, num_blocks); @@ -401,17 +402,16 @@ mod tests { async fn find_block_header_by_hash() -> Result<()> { let state = state_with_test_blocks_and_transactions(1, 1, 1)?; let state_view = state.view(); - let state_snapshot = state_view.to_snapshot(); - let block = state_snapshot.all_blocks().last().expect("state is empty"); + let block = state_view.all_blocks().last().expect("state is empty"); assert_eq!( - FindBlockHeaderByHash::new(block.hash()).execute(&state_snapshot)?, + FindBlockHeaderByHash::new(block.hash()).execute(&state_view)?, *block.header() ); assert!( FindBlockHeaderByHash::new(HashOf::from_untyped_unchecked(Hash::new([42]))) - .execute(&state_snapshot) + .execute(&state_view) .is_err() ); @@ -424,9 +424,8 @@ mod tests { let state = state_with_test_blocks_and_transactions(num_blocks, 1, 1)?; let state_view = state.view(); - let state_snapshot = state_view.to_snapshot(); let txs = FindAllTransactions - .execute(&state_snapshot)? + .execute(&state_view)? .collect::>(); assert_eq!(txs.len() as u64, num_blocks * 2); @@ -475,20 +474,19 @@ mod tests { state_block.commit(); let state_view = state.view(); - let state_snapshot = state_view.to_snapshot(); let unapplied_tx = TransactionBuilder::new(chain_id, ALICE_ID.clone()) .with_instructions([Unregister::account("account@domain".parse().unwrap())]) .sign(&ALICE_KEYS); let wrong_hash = unapplied_tx.hash(); - let not_found = FindTransactionByHash::new(wrong_hash).execute(&state_snapshot); + let not_found = FindTransactionByHash::new(wrong_hash).execute(&state_view); assert!(matches!( not_found, Err(Error::Find(FindError::Transaction(_))) )); let found_accepted = - FindTransactionByHash::new(va_tx.as_ref().hash()).execute(&state_snapshot)?; + FindTransactionByHash::new(va_tx.as_ref().hash()).execute(&state_view)?; if found_accepted.transaction.error.is_none() { assert_eq!( va_tx.as_ref().hash(), @@ -526,8 +524,7 @@ mod tests { let domain_id = DomainId::from_str("wonderland")?; let key = Name::from_str("Bytes")?; - let bytes = FindDomainKeyValueByIdAndKey::new(domain_id, key) - .execute(&state.view().to_snapshot())?; + let bytes = FindDomainKeyValueByIdAndKey::new(domain_id, key).execute(&state.view())?; assert_eq!( MetadataValueBox::Vec(vec![1_u32.into(), 2_u32.into(), 3_u32.into()]), bytes, diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index 9b3b92ce4c0..67e150f8f83 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -233,34 +233,34 @@ pub mod query { }; use super::*; - use crate::{prelude::*, state::StateSnapshot}; + use crate::{prelude::*, state::StateReadOnly}; impl ValidQuery for FindAllActiveTriggerIds { #[metrics(+"find_all_active_triggers")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { - Ok(Box::new(state_snapshot.world.triggers.ids().cloned())) + Ok(Box::new(state_ro.world().triggers().ids().cloned())) } } impl ValidQuery for FindTriggerById { #[metrics(+"find_trigger_by_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; iroha_logger::trace!(%id); // Can't use just `LoadedActionTrait::clone_and_box` cause this will trigger lifetime mismatch #[allow(clippy::redundant_closure_for_method_calls)] - let loaded_action = state_snapshot - .world - .triggers + let loaded_action = state_ro + .world() + .triggers() .inspect_by_id(id, |action| action.clone_and_box()) .ok_or_else(|| Error::Find(FindError::Trigger(id.clone())))?; - let action = state_snapshot - .world - .triggers + let action = state_ro + .world() + .triggers() .get_original_action(loaded_action).into(); // TODO: Should we redact the metadata if the account is not the authority/owner? @@ -270,13 +270,13 @@ pub mod query { impl ValidQuery for FindTriggerKeyValueByIdAndKey { #[metrics(+"find_trigger_key_value_by_id_and_key")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let id = &self.id; let key = &self.key; iroha_logger::trace!(%id, %key); - state_snapshot - .world - .triggers + state_ro + .world() + .triggers() .inspect_by_id(id, |action| { action .metadata() @@ -293,19 +293,19 @@ pub mod query { #[metrics(+"find_triggers_by_domain_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> eyre::Result + 'state>, Error> { let domain_id = &self.domain_id; Ok(Box::new( - state_snapshot - .world - .triggers + state_ro + .world() + .triggers() .inspect_by_domain_id(domain_id, |trigger_id, action| { (trigger_id.clone(), action.clone_and_box()) }) .map(|(trigger_id, action)| { - let action = state_snapshot.world.triggers.get_original_action(action).into(); + let action = state_ro.world().triggers().get_original_action(action).into(); Trigger::new(trigger_id, action) }), )) diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index c6287918db3..7fcf1ad2782 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -16,7 +16,6 @@ use iroha_data_model::{ use iroha_telemetry::metrics; use super::*; -use crate::state::StateSnapshot; pub(crate) struct BlockTransactionIter(Arc, usize); pub(crate) struct BlockTransactionRef(Arc, usize); @@ -68,10 +67,10 @@ impl ValidQuery for FindAllTransactions { #[metrics(+"find_all_transactions")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, QueryExecutionFail> { Ok(Box::new( - state_snapshot + state_ro .all_blocks() .flat_map(BlockTransactionIter::new) .map(|tx| TransactionQueryOutput { @@ -86,12 +85,12 @@ impl ValidQuery for FindTransactionsByAccountId { #[metrics(+"find_transactions_by_account_id")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, QueryExecutionFail> { let account_id = self.account_id.clone(); Ok(Box::new( - state_snapshot + state_ro .all_blocks() .flat_map(BlockTransactionIter::new) .filter(move |tx| *tx.authority() == account_id) @@ -107,15 +106,15 @@ impl ValidQuery for FindTransactionByHash { #[metrics(+"find_transaction_by_hash")] fn execute( &self, - state_snapshot: &StateSnapshot<'_>, + state_ro: &impl StateReadOnly, ) -> Result { let tx_hash = self.hash; iroha_logger::trace!(%tx_hash); - if !state_snapshot.has_transaction(tx_hash) { + if !state_ro.has_transaction(tx_hash) { return Err(FindError::Transaction(tx_hash).into()); }; - let block = state_snapshot + let block = state_ro .block_with_tx(&tx_hash) .ok_or_else(|| FindError::Transaction(tx_hash))?; diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index b309e40a4bc..d2146ae2c22 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -386,18 +386,18 @@ pub mod query { }; use super::*; - use crate::state::StateSnapshot; + use crate::state::StateReadOnly; impl ValidQuery for FindAllRoles { #[metrics(+"find_all_roles")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { Ok(Box::new( - state_snapshot - .world - .roles + state_ro + .world() + .roles() .iter() .map(|(_, role)| role) .cloned(), @@ -409,12 +409,12 @@ pub mod query { #[metrics(+"find_all_role_ids")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { Ok(Box::new( - state_snapshot - .world - .roles + state_ro + .world() + .roles() .iter() .map(|(_, role)| role) // To me, this should probably be a method, not a field. @@ -426,11 +426,11 @@ pub mod query { impl ValidQuery for FindRoleByRoleId { #[metrics(+"find_role_by_role_id")] - fn execute(&self, state_snapshot: &StateSnapshot<'_>) -> Result { + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { let role_id = &self.id; iroha_logger::trace!(%role_id); - state_snapshot.world.roles.get(role_id).map_or_else( + state_ro.world().roles().get(role_id).map_or_else( || Err(Error::Find(FindError::Role(role_id.clone()))), |role_ref| Ok(role_ref.clone()), ) @@ -441,21 +441,16 @@ pub mod query { #[metrics("find_all_peers")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { - Ok(Box::new( - state_snapshot.world.peers().cloned().map(Peer::new), - )) + Ok(Box::new(state_ro.world().peers().cloned().map(Peer::new))) } } impl ValidQuery for FindPermissionTokenSchema { #[metrics("find_permission_token_schema")] - fn execute( - &self, - state_snapshot: &StateSnapshot<'_>, - ) -> Result { - Ok(state_snapshot.world.permission_token_schema.clone()) + fn execute(&self, state_ro: &impl StateReadOnly) -> Result { + Ok(state_ro.world().permission_token_schema().clone()) } } @@ -463,9 +458,9 @@ pub mod query { #[metrics("find_all_parameters")] fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result + 'state>, Error> { - Ok(Box::new(state_snapshot.world.parameters().cloned())) + Ok(Box::new(state_ro.world().parameters_iter().cloned())) } } } diff --git a/core/src/smartcontracts/mod.rs b/core/src/smartcontracts/mod.rs index c724b9adb4c..fceb17c3557 100644 --- a/core/src/smartcontracts/mod.rs +++ b/core/src/smartcontracts/mod.rs @@ -13,7 +13,7 @@ use iroha_data_model::{ pub use isi::*; use self::query::Lazy; -use crate::state::{StateSnapshot, StateTransaction}; +use crate::state::{StateReadOnly, StateTransaction}; /// Trait implementations should provide actions to apply changes on [`StateTransaction`]. pub trait Execute { @@ -41,6 +41,6 @@ where /// Concrete to each implementer fn execute<'state>( &self, - state_snapshot: &'state StateSnapshot<'state>, + state_ro: &'state impl StateReadOnly, ) -> Result<::Lazy<'state>, QueryExecutionFail>; } diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 7f5f2efe739..bcf63cea816 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -32,7 +32,7 @@ use wasmtime::{ use crate::{ query::store::LiveQueryStoreHandle, smartcontracts::{wasm::state::ValidateQueryOperation, Execute}, - state::{StateSnapshot, StateTransaction}, + state::{StateReadOnly, StateTransaction, WorldReadOnly}, ValidQuery as _, }; @@ -412,12 +412,10 @@ pub mod state { pub mod chain_state { //! Strongly typed kinds of chain state - use std::borrow::Borrow; - use super::*; /// Read-only access to chain state. - pub struct WithConst<'wrld, 'state>(pub(in super::super) &'wrld StateSnapshot<'state>); + pub struct WithConst<'wrld, S: StateReadOnly>(pub(in super::super) &'wrld S); /// Mutable access to chain state. pub struct WithMut<'wrld, 'block, 'state>( @@ -428,28 +426,19 @@ pub mod state { /// /// Exists to write generic code for [`WithMut`] and [`WithConst`]. pub trait ConstState { - /// Type which can be borrowed into `[WorldStateSnapshot]` - type State<'wrld, 'state: 'wrld>: Borrow> - where - Self: 'state + 'wrld; - /// Get immutable chain state. - fn state(&self) -> Self::State<'_, '_>; + fn state(&self) -> &impl StateReadOnly; } - impl ConstState for WithConst<'_, '_> { - type State<'wrld, 'state: 'wrld> = &'wrld StateSnapshot<'state> where Self: 'state; - - fn state(&self) -> &StateSnapshot<'_> { + impl ConstState for WithConst<'_, S> { + fn state(&self) -> &impl StateReadOnly { self.0 } } impl ConstState for WithMut<'_, '_, '_> { - type State<'wrld, 'state: 'wrld> = StateSnapshot<'state> where Self: 'state; - - fn state(&self) -> StateSnapshot<'_> { - self.0.to_snapshot() + fn state(&self) -> &impl StateReadOnly { + self.0 } } } @@ -519,11 +508,11 @@ pub mod state { authority: &AccountId, query: QueryBox, ) -> Result<(), ValidationFail> { - let state_snapshot = self.state.state(); - state_snapshot - .world - .executor - .validate_query(&state_snapshot, authority, query) + let state_ro = self.state.state(); + state_ro + .world() + .executor() + .validate_query(state_ro, authority, query) } } @@ -533,11 +522,11 @@ pub mod state { authority: &AccountId, query: QueryBox, ) -> Result<(), ValidationFail> { - let state_snapshot = self.state.state(); - state_snapshot - .world - .executor - .validate_query(&state_snapshot, authority, query) + let state_ro = self.state.state(); + state_ro + .world() + .executor() + .validate_query(state_ro, authority, query) } } @@ -553,8 +542,8 @@ pub mod state { >; /// State for executing `validate_query()` entrypoint - pub type ValidateQuery<'wrld, 'state> = - CommonState, specific::executor::ValidateQuery>; + pub type ValidateQuery<'wrld, S> = + CommonState, specific::executor::ValidateQuery>; /// State for executing `validate_instruction()` entrypoint pub type ValidateInstruction<'wrld, 'block, 'state> = CommonState< @@ -583,9 +572,18 @@ pub mod state { impl_blank_validate_operations!( ValidateTransaction<'_, '_, '_>, ValidateInstruction<'_, '_, '_>, - ValidateQuery<'_, '_>, Migrate<'_, '_, '_>, ); + + impl ValidateQueryOperation for ValidateQuery<'_, S> { + fn validate_query( + &self, + _authority: &AccountId, + _query: QueryBox, + ) -> Result<(), ValidationFail> { + Ok(()) + } + } } } @@ -777,7 +775,10 @@ impl Runtime> { let mut state = store.into_data(); let executed_queries = state.take_executed_queries(); - forget_all_executed_queries(state.state.state().borrow().query_handle, executed_queries)?; + forget_all_executed_queries( + state.state.state().borrow().query_handle(), + executed_queries, + )?; Ok(validation_res) } } @@ -801,13 +802,13 @@ where fetch_size, }) => { let batched = { - let state_snapshot = state.state.state(); - let state_snapshot = state_snapshot.borrow(); + let state_ro = state.state.state(); + let state_ro = state_ro.borrow(); state.validate_query(&state.authority, query.clone())?; - let output = query.execute(state_snapshot)?; + let output = query.execute(state_ro)?; - state_snapshot - .query_handle + state_ro + .query_handle() .handle_query_output(output, &sorting, pagination, fetch_size) }?; match &batched { @@ -829,7 +830,7 @@ where .state .state() .borrow() - .query_handle + .query_handle() .handle_query_cursor(cursor) } } @@ -1253,7 +1254,7 @@ impl<'wrld> FakeSetPermissionTokenSchema Runtime> { +impl<'wrld, S: StateReadOnly> Runtime> { /// Execute `validate_query()` entrypoint of the given module of runtime executor /// /// # Errors @@ -1264,7 +1265,7 @@ impl<'wrld, 'state> Runtime> { /// - if unable to decode [`executor::Result`] pub fn execute_executor_validate_query( &self, - state_transaction: &'wrld StateSnapshot<'state>, + state_ro: &'wrld S, authority: &AccountId, module: &wasmtime::Module, query: QueryBox, @@ -1277,7 +1278,7 @@ impl<'wrld, 'state> Runtime> { authority.clone(), self.config, span, - state::chain_state::WithConst(state_transaction), + state::chain_state::WithConst(state_ro), state::specific::executor::ValidateQuery::new(query), ), import::EXECUTOR_VALIDATE_QUERY, @@ -1285,13 +1286,14 @@ impl<'wrld, 'state> Runtime> { } } -impl<'wrld, 'state> import::traits::ExecuteOperations> - for Runtime> +impl<'wrld, S: StateReadOnly> + import::traits::ExecuteOperations> + for Runtime> { #[codec::wrap] fn execute_query( query_request: SmartContractQueryRequest, - state: &mut state::executor::ValidateQuery<'wrld, 'state>, + state: &mut state::executor::ValidateQuery<'wrld, S>, ) -> Result, ValidationFail> { debug!(%query_request, "Executing as executor"); @@ -1301,40 +1303,38 @@ impl<'wrld, 'state> import::traits::ExecuteOperations, + _state: &mut state::executor::ValidateQuery<'wrld, S>, ) -> Result<(), ValidationFail> { panic!("Executor `validate_query()` entrypoint should not execute instructions") } } -impl<'wrld, 'state> - import::traits::GetExecutorPayloads> - for Runtime> +impl<'wrld, S: StateReadOnly> + import::traits::GetExecutorPayloads> + for Runtime> { #[codec::wrap] - fn get_migrate_payload( - _state: &state::executor::ValidateQuery<'wrld, 'state>, - ) -> payloads::Migrate { + fn get_migrate_payload(_state: &state::executor::ValidateQuery<'wrld, S>) -> payloads::Migrate { panic!("Executor `validate_query()` entrypoint should not query payload for `migrate()` entrypoint") } #[codec::wrap] fn get_validate_transaction_payload( - _state: &state::executor::ValidateQuery<'wrld, 'state>, + _state: &state::executor::ValidateQuery<'wrld, S>, ) -> Validate { panic!("Executor `validate_query()` entrypoint should not query payload for `validate_transaction()` entrypoint") } #[codec::wrap] fn get_validate_instruction_payload( - _state: &state::executor::ValidateQuery<'wrld, 'state>, + _state: &state::executor::ValidateQuery<'wrld, S>, ) -> Validate { panic!("Executor `validate_query()` entrypoint should not query payload for `validate_instruction()` entrypoint") } #[codec::wrap] fn get_validate_query_payload( - state: &state::executor::ValidateQuery<'wrld, 'state>, + state: &state::executor::ValidateQuery<'wrld, S>, ) -> Validate { Validate { authority: state.authority.clone(), @@ -1344,8 +1344,8 @@ impl<'wrld, 'state> } } -impl<'wrld, 'state> FakeSetPermissionTokenSchema> - for Runtime> +impl<'wrld, S: StateReadOnly> FakeSetPermissionTokenSchema> + for Runtime> { const ENTRYPOINT_FN_NAME: &'static str = "validate_query"; } @@ -1633,25 +1633,25 @@ impl<'wrld, 'block, 'state> } } -impl<'wrld, 'state> RuntimeBuilder> { +impl<'wrld, S: StateReadOnly> RuntimeBuilder> { /// Builds the [`Runtime`] for *Executor* `validate_query()` execution /// /// # Errors /// /// Fails if failed to create default linker. - pub fn build(self) -> Result>> { + pub fn build(self) -> Result>> { self.finalize(|engine| { let mut linker = Linker::new(engine); // NOTE: doesn't need closure here because `ValidateQuery` is covariant over 'wrld so 'static can be used and substituted with appropriate lifetime - create_imports!(linker, state::executor::ValidateQuery<'_, '_>, - export::EXECUTE_ISI => Runtime::execute_instruction, - export::EXECUTE_QUERY => Runtime::execute_query, - export::GET_MIGRATE_PAYLOAD => Runtime::get_migrate_payload, - export::GET_VALIDATE_TRANSACTION_PAYLOAD => Runtime::get_validate_transaction_payload, - export::GET_VALIDATE_INSTRUCTION_PAYLOAD => Runtime::get_validate_instruction_payload, - export::GET_VALIDATE_QUERY_PAYLOAD => Runtime::get_validate_query_payload, - export::SET_PERMISSION_TOKEN_SCHEMA => Runtime::set_permission_token_schema, + create_imports!(linker, state::executor::ValidateQuery<'_, S>, + export::EXECUTE_ISI => |caller: ::wasmtime::Caller>, offset, len| Runtime::execute_instruction(caller, offset, len), + export::EXECUTE_QUERY => |caller: ::wasmtime::Caller>, offset, len| Runtime::execute_query(caller, offset, len), + export::GET_MIGRATE_PAYLOAD => |caller: ::wasmtime::Caller>| Runtime::get_migrate_payload(caller), + export::GET_VALIDATE_TRANSACTION_PAYLOAD => |caller: ::wasmtime::Caller>| Runtime::get_validate_transaction_payload(caller), + export::GET_VALIDATE_INSTRUCTION_PAYLOAD => |caller: ::wasmtime::Caller>| Runtime::get_validate_instruction_payload(caller), + export::GET_VALIDATE_QUERY_PAYLOAD => |caller: ::wasmtime::Caller>| Runtime::get_validate_query_payload(caller), + export::SET_PERMISSION_TOKEN_SCHEMA => |caller: ::wasmtime::Caller>, offset, len| Runtime::set_permission_token_schema(caller, offset, len), )?; Ok(linker) }) diff --git a/core/src/snapshot.rs b/core/src/snapshot.rs index e6c5b892eb3..f88a69d6dcf 100644 --- a/core/src/snapshot.rs +++ b/core/src/snapshot.rs @@ -16,7 +16,7 @@ use tokio::sync::mpsc; use crate::{ kura::{BlockCount, Kura}, query::store::LiveQueryStoreHandle, - state::{deserialize::KuraSeed, State}, + state::{deserialize::KuraSeed, State, StateReadOnly}, }; /// Name of the [`State`] snapshot file. diff --git a/core/src/state.rs b/core/src/state.rs index 43f2d545073..da949dda172 100644 --- a/core/src/state.rs +++ b/core/src/state.rs @@ -26,7 +26,7 @@ use serde::{ use storage::{ cell::{Block as CellBlock, Cell, Transaction as CellTransaction, View as CellView}, storage::{ - Block as StorageBlock, RangeIter, Snapshot as StorageSnapshot, Storage, + Block as StorageBlock, RangeIter, Storage, StorageReadOnly, Transaction as StorageTransaction, View as StorageView, }, }; @@ -153,29 +153,6 @@ pub struct WorldView<'world> { pub(crate) executor: CellView<'world, Executor>, } -/// Consistent point in time view of the [`World`] -/// Used in places where [`WorldBlock`], [`WorldTransaction`], [`WorldView`] need to be converted to the same type for immutable operations -pub struct WorldSnapshot<'world> { - /// Iroha config parameters. - pub(crate) parameters: &'world Parameters, - /// Identifications of discovered trusted peers. - pub(crate) trusted_peers_ids: &'world PeersIds, - /// Registered domains. - pub(crate) domains: StorageSnapshot<'world, DomainId, Domain>, - /// Roles. [`Role`] pairs. - pub(crate) roles: StorageSnapshot<'world, RoleId, Role>, - /// Permission tokens of an account. - pub(crate) account_permission_tokens: StorageSnapshot<'world, AccountId, Permissions>, - /// Roles of an account. - pub(crate) account_roles: StorageSnapshot<'world, RoleIdWithOwner, ()>, - /// Registered permission token ids. - pub(crate) permission_token_schema: &'world PermissionTokenSchema, - /// Triggers - pub(crate) triggers: &'world TriggerSet, - /// Runtime Executor - pub(crate) executor: &'world Executor, -} - /// Current state of the blockchain #[derive(Serialize)] pub struct State { @@ -270,29 +247,6 @@ pub struct StateView<'state> { pub new_tx_amounts: &'state Mutex>, } -/// Consistent point in time view of the [`State`] -/// Used in places where [`StateBlock`], [`StateTransaction`], [`StateView`] need to be converted to the same type for immutable operations -pub struct StateSnapshot<'state> { - /// The world. Contains `domains`, `triggers`, `roles` and other data representing the current state of the blockchain. - pub world: WorldSnapshot<'state>, - /// Configuration of World State View. - pub config: &'state Config, - /// Blockchain. - pub block_hashes: &'state Vec>, - /// Hashes of transactions mapped onto block height where they stored - pub transactions: StorageSnapshot<'state, HashOf, u64>, - /// Engine for WASM [`Runtime`](wasm::Runtime) to execute triggers. - pub engine: &'state wasmtime::Engine, - - /// Reference to Kura subsystem. - kura: &'state Kura, - /// Handle to the [`LiveQueryStore`]. - pub query_handle: &'state LiveQueryStoreHandle, - /// Temporary metrics buffer of amounts of any asset that has been transacted. - /// TODO: this should be done through events - pub new_tx_amounts: &'state Mutex>, -} - impl World { /// Creates an empty `World`. pub fn new() -> Self { @@ -347,26 +301,28 @@ impl World { } } -macro_rules! world_read_only_methods { - ($($tt:tt)*) => { - macro_rules! insert_world_read_only_methods { - () => { - $($tt)* - } - } - } -} +/// Trait to perform read-only operations on [`WorldBlock`], [`WorldTransaction`] and [`WorldView`] +#[allow(missing_docs)] +pub trait WorldReadOnly { + fn parameters(&self) -> &Parameters; + fn trusted_peers_ids(&self) -> &PeersIds; + fn domains(&self) -> &impl StorageReadOnly; + fn roles(&self) -> &impl StorageReadOnly; + fn account_permission_tokens(&self) -> &impl StorageReadOnly; + fn account_roles(&self) -> &impl StorageReadOnly; + fn permission_token_schema(&self) -> &PermissionTokenSchema; + fn triggers(&self) -> &TriggerSet; + fn executor(&self) -> &Executor; -world_read_only_methods! { // Domain-related methods /// Get `Domain` without an ability to modify it. /// /// # Errors /// Fails if there is no domain - pub fn domain(&self, id: &DomainId) -> Result<&Domain, FindError> { + fn domain(&self, id: &DomainId) -> Result<&Domain, FindError> { let domain = self - .domains + .domains() .get(id) .ok_or_else(|| FindError::Domain(id.clone()))?; Ok(domain) @@ -376,7 +332,7 @@ world_read_only_methods! { /// /// # Errors /// Fails if there is no domain - pub fn map_domain<'slf, T>( + fn map_domain<'slf, T>( &'slf self, id: &DomainId, f: impl FnOnce(&'slf Domain) -> T, @@ -388,8 +344,8 @@ world_read_only_methods! { /// Returns reference for domains map #[inline] - pub fn domains(&self) -> impl Iterator { - self.domains.iter().map(|(_, domain)| domain) + fn domains_iter(&self) -> impl Iterator { + self.domains().iter().map(|(_, domain)| domain) } // Account-related methods @@ -398,7 +354,7 @@ world_read_only_methods! { /// /// # Errors /// Fails if there is no domain or account - pub fn account(&self, id: &AccountId) -> Result<&Account, FindError> { + fn account(&self, id: &AccountId) -> Result<&Account, FindError> { self.domain(&id.domain_id).and_then(|domain| { domain .accounts @@ -411,7 +367,7 @@ world_read_only_methods! { /// /// # Errors /// Fails if there is no domain or account - pub fn map_account<'slf, T>( + fn map_account<'slf, T>( &'slf self, id: &AccountId, f: impl FnOnce(&'slf Account) -> T, @@ -428,19 +384,26 @@ world_read_only_methods! { /// /// # Errors /// Fails if there is no domain or account - pub fn account_assets( + fn account_assets( &self, id: &AccountId, - ) -> Result, QueryExecutionFail> { + ) -> Result, QueryExecutionFail> { self.map_account(id, |account| account.assets.values()) } /// Get [`Account`]'s [`RoleId`]s // NOTE: have to use concreate type because don't want to capture lifetme of `id` - pub fn account_roles<'slf>(&'slf self, id: &AccountId) -> core::iter::Map, fn((&'slf RoleIdWithOwner, &'slf ())) -> &'slf RoleId> { - self.account_roles + #[allow(clippy::type_complexity)] + fn account_roles_iter<'slf>( + &'slf self, + id: &AccountId, + ) -> core::iter::Map< + RangeIter<'slf, RoleIdWithOwner, ()>, + fn((&'slf RoleIdWithOwner, &'slf ())) -> &'slf RoleId, + > { + self.account_roles() .range(RoleIdByAccountBounds::new(id)) - .map(|(role, _)| &role.role_id) + .map(|(role, ())| &role.role_id) } /// Return a set of all permission tokens granted to this account. @@ -448,7 +411,7 @@ world_read_only_methods! { /// # Errors /// /// - if `account_id` is not found in `self` - pub fn account_permission_tokens<'slf>( + fn account_permission_tokens_iter<'slf>( &'slf self, account_id: &AccountId, ) -> Result, FindError> { @@ -458,8 +421,8 @@ world_read_only_methods! { .account_inherent_permission_tokens(account_id) .collect::>(); - for role_id in self.account_roles(account_id) { - if let Some(role) = self.roles.get(role_id) { + for role_id in self.account_roles_iter(account_id) { + if let Some(role) = self.roles().get(role_id) { tokens.extend(role.permissions.iter()); } } @@ -472,23 +435,23 @@ world_read_only_methods! { /// # Errors /// /// - `account_id` is not found in `self.world`. - pub fn account_inherent_permission_tokens<'slf>( + fn account_inherent_permission_tokens<'slf>( &'slf self, account_id: &AccountId, ) -> std::collections::btree_set::Iter<'slf, PermissionToken> { - self.account_permission_tokens + self.account_permission_tokens() .get(account_id) .map_or_else(Default::default, std::collections::BTreeSet::iter) } /// Return `true` if [`Account`] contains a permission token not associated with any role. #[inline] - pub fn account_contains_inherent_permission( + fn account_contains_inherent_permission( &self, account: &AccountId, token: &PermissionToken, ) -> bool { - self.account_permission_tokens + self.account_permission_tokens() .get(account) .map_or(false, |permissions| permissions.contains(token)) } @@ -501,7 +464,7 @@ world_read_only_methods! { /// - No such [`Asset`] /// - The [`Account`] with which the [`Asset`] is associated doesn't exist. /// - The [`Domain`] with which the [`Account`] is associated doesn't exist. - pub fn asset(&self, id: &AssetId) -> Result { + fn asset(&self, id: &AssetId) -> Result { self.map_account( &id.account_id, |account| -> Result { @@ -509,7 +472,7 @@ world_read_only_methods! { .assets .get(id) .ok_or_else(|| QueryExecutionFail::from(FindError::Asset(id.clone()))) - .map(Clone::clone) + .cloned() }, )? } @@ -520,25 +483,19 @@ world_read_only_methods! { /// /// # Errors /// - Asset definition entry not found - pub fn asset_definition( - &self, - asset_id: &AssetDefinitionId, - ) -> Result { + fn asset_definition(&self, asset_id: &AssetDefinitionId) -> Result { self.domain(&asset_id.domain_id)? .asset_definitions .get(asset_id) .ok_or_else(|| FindError::AssetDefinition(asset_id.clone())) - .map(Clone::clone) + .cloned() } /// Get total amount of [`Asset`]. /// /// # Errors /// - Asset definition not found - pub fn asset_total_amount( - &self, - definition_id: &AssetDefinitionId, - ) -> Result { + fn asset_total_amount(&self, definition_id: &AssetDefinitionId) -> Result { self.domain(&definition_id.domain_id)? .asset_total_quantities .get(definition_id) @@ -547,24 +504,24 @@ world_read_only_methods! { } /// Get an immutable iterator over the [`PeerId`]s. - pub fn peers(&self) -> impl ExactSizeIterator { - self.trusted_peers_ids.iter() + fn peers(&self) -> impl ExactSizeIterator { + self.trusted_peers_ids().iter() } /// Get all `Parameter`s registered in the world. - pub fn parameters(&self) -> impl Iterator { - self.parameters.iter() + fn parameters_iter(&self) -> impl Iterator { + self.parameters().iter() } /// Query parameter and convert it to a proper type - pub fn query_param, P: core::hash::Hash + Eq + ?Sized>( + fn query_param, P: core::hash::Hash + Eq + ?Sized>( &self, param: &P, ) -> Option where Parameter: Borrow

, { - Parameters::get(&self.parameters, param) + Parameters::get(self.parameters(), param) .as_ref() .map(|param| ¶m.val) .cloned() @@ -573,11 +530,49 @@ world_read_only_methods! { /// Returns reference for trusted peer ids #[inline] - pub fn peers_ids(&self) -> &PeersIds { - &self.trusted_peers_ids + fn peers_ids(&self) -> &PeersIds { + self.trusted_peers_ids() } } +macro_rules! impl_world_ro { + ($($ident:ty),*) => {$( + impl WorldReadOnly for $ident { + fn parameters(&self) -> &Parameters { + &self.parameters + } + fn trusted_peers_ids(&self) -> &PeersIds { + &self.trusted_peers_ids + } + fn domains(&self) -> &impl StorageReadOnly { + &self.domains + } + fn roles(&self) -> &impl StorageReadOnly { + &self.roles + } + fn account_permission_tokens(&self) -> &impl StorageReadOnly { + &self.account_permission_tokens + } + fn account_roles(&self) -> &impl StorageReadOnly { + &self.account_roles + } + fn permission_token_schema(&self) -> &PermissionTokenSchema { + &self.permission_token_schema + } + fn triggers(&self) -> &TriggerSet { + &self.triggers + } + fn executor(&self) -> &Executor { + &self.executor + } + } + )*}; +} + +impl_world_ro! { + WorldBlock<'_>, WorldTransaction<'_, '_>, WorldView<'_> +} + impl<'world> WorldBlock<'world> { /// Create struct to apply transaction's changes pub fn trasaction(&mut self) -> WorldTransaction<'_, 'world> { @@ -611,23 +606,6 @@ impl<'world> WorldBlock<'world> { self.trusted_peers_ids.commit(); self.parameters.commit(); } - - /// Convert [`Self`] to [`WorldSnapshot`] - pub fn to_snapshot(&self) -> WorldSnapshot<'_> { - WorldSnapshot { - parameters: &self.parameters, - trusted_peers_ids: &self.trusted_peers_ids, - domains: self.domains.to_snapshot(), - roles: self.roles.to_snapshot(), - account_permission_tokens: self.account_permission_tokens.to_snapshot(), - account_roles: self.account_roles.to_snapshot(), - permission_token_schema: &self.permission_token_schema, - triggers: &self.triggers, - executor: &self.executor, - } - } - - insert_world_read_only_methods! {} } impl WorldTransaction<'_, '_> { @@ -645,21 +623,6 @@ impl WorldTransaction<'_, '_> { self.events_buffer.events_created_in_transaction = 0; } - /// Convert [`Self`] to [`WorldSnapshot`] - pub fn to_snapshot(&self) -> WorldSnapshot<'_> { - WorldSnapshot { - parameters: &self.parameters, - trusted_peers_ids: &self.trusted_peers_ids, - domains: self.domains.to_snapshot(), - roles: self.roles.to_snapshot(), - account_permission_tokens: self.account_permission_tokens.to_snapshot(), - account_roles: self.account_roles.to_snapshot(), - permission_token_schema: &self.permission_token_schema, - triggers: &self.triggers, - executor: &self.executor, - } - } - /// Get `Domain` with an ability to modify it. /// /// # Errors @@ -913,8 +876,6 @@ impl WorldTransaction<'_, '_> { } events_buffer.extend(data_events.into_iter().map(Into::into)); } - - insert_world_read_only_methods! {} } impl TransactionEventBuffer<'_> { @@ -941,29 +902,6 @@ impl Drop for TransactionEventBuffer<'_> { } } -impl WorldView<'_> { - insert_world_read_only_methods! {} - - /// Convert [`Self`] to [`WorldSnapshot`] - pub fn to_snapshot(&self) -> WorldSnapshot<'_> { - WorldSnapshot { - parameters: &self.parameters, - trusted_peers_ids: &self.trusted_peers_ids, - domains: self.domains.to_snapshot(), - roles: self.roles.to_snapshot(), - account_permission_tokens: self.account_permission_tokens.to_snapshot(), - account_roles: self.account_roles.to_snapshot(), - permission_token_schema: &self.permission_token_schema, - triggers: &self.triggers, - executor: &self.executor, - } - } -} - -impl WorldSnapshot<'_> { - insert_world_read_only_methods! {} -} - impl State { /// Construct [`State`] with given [`World`]. #[must_use] @@ -1022,63 +960,63 @@ impl State { } } -macro_rules! world_state_read_only_methods { - ($($tt:tt)*) => { - macro_rules! insert_world_state_read_only_methods { - () => { - $($tt)* - } - } - } -} +/// Trait to perform read-only operations on [`StateBlock`], [`StateTransaction`] and [`StateView`] +#[allow(missing_docs)] +pub trait StateReadOnly { + fn world(&self) -> &impl WorldReadOnly; + fn config(&self) -> &Config; + fn block_hashes(&self) -> &[HashOf]; + fn transactions(&self) -> &impl StorageReadOnly, u64>; + fn engine(&self) -> &wasmtime::Engine; + fn kura(&self) -> &Kura; + fn query_handle(&self) -> &LiveQueryStoreHandle; + fn new_tx_amounts(&self) -> &Mutex>; -// Read-only methods reused across `StateBlock`, `StateTransaction`, `StateView` -world_state_read_only_methods! { // Block-related methods /// Get a reference to the latest block. Returns none if genesis is not committed. #[inline] - pub fn latest_block_ref(&self) -> Option> { - self.kura - .get_block_by_height(self.block_hashes.len() as u64) + fn latest_block_ref(&self) -> Option> { + self.kura() + .get_block_by_height(self.block_hashes().len() as u64) } /// Return the hash of the latest block - pub fn latest_block_hash(&self) -> Option> { - self.block_hashes.iter().nth_back(0).copied() + fn latest_block_hash(&self) -> Option> { + self.block_hashes().iter().nth_back(0).copied() } /// Return the view change index of the latest block - pub fn latest_block_view_change_index(&self) -> u64 { - self.kura + fn latest_block_view_change_index(&self) -> u64 { + self.kura() .get_block_by_height(self.height()) .map_or(0, |block| block.header().view_change_index) } /// Return the hash of the block one before the latest block - pub fn previous_block_hash(&self) -> Option> { - self.block_hashes.iter().nth_back(1).copied() + fn previous_block_hash(&self) -> Option> { + self.block_hashes().iter().nth_back(1).copied() } /// Load all blocks in the block chain from disc - pub fn all_blocks(&self) -> impl DoubleEndedIterator> + '_ { - let block_count = self.block_hashes.len() as u64; + fn all_blocks(&self) -> impl DoubleEndedIterator> + '_ { + let block_count = self.block_hashes().len() as u64; (1..=block_count).map(|height| { - self.kura + self.kura() .get_block_by_height(height) .expect("Failed to load block.") }) } /// Return a vector of blockchain blocks after the block with the given `hash` - pub fn block_hashes_after_hash( + fn block_hashes_after_hash( &self, hash: Option>, ) -> Vec> { hash.map_or_else( - || self.block_hashes.clone(), + || self.block_hashes().to_vec(), |block_hash| { - self.block_hashes + self.block_hashes() .iter() .skip_while(|&x| *x != block_hash) .skip(1) @@ -1089,8 +1027,8 @@ world_state_read_only_methods! { } /// Return an iterator over blockchain block hashes starting with the block of the given `height` - pub fn block_hashes_from_height(&self, height: usize) -> Vec> { - self.block_hashes + fn block_hashes_from_height(&self, height: usize) -> Vec> { + self.block_hashes() .iter() .skip(height.saturating_sub(1)) .copied() @@ -1099,25 +1037,25 @@ world_state_read_only_methods! { /// Height of blockchain #[inline] - pub fn height(&self) -> u64 { - self.block_hashes.len() as u64 + fn height(&self) -> u64 { + self.block_hashes().len() as u64 } /// Find a [`SignedBlock`] by hash. - pub fn block_with_tx(&self, hash: &HashOf) -> Option> { - let height = *self.transactions.get(hash)?; - self.kura.get_block_by_height(height) + fn block_with_tx(&self, hash: &HashOf) -> Option> { + let height = *self.transactions().get(hash)?; + self.kura().get_block_by_height(height) } /// Returns [`Some`] milliseconds since the genesis block was /// committed, or [`None`] if it wasn't. #[inline] - pub fn genesis_timestamp(&self) -> Option { - if self.block_hashes.is_empty() { + fn genesis_timestamp(&self) -> Option { + if self.block_hashes().is_empty() { None } else { let opt = self - .kura + .kura() .get_block_by_height(1) .map(|genesis_block| genesis_block.header().timestamp()); @@ -1130,16 +1068,51 @@ world_state_read_only_methods! { /// Check if this [`SignedTransaction`] is already committed or rejected. #[inline] - pub fn has_transaction(&self, hash: HashOf) -> bool { - self.transactions.get(&hash).is_some() + fn has_transaction(&self, hash: HashOf) -> bool { + self.transactions().get(&hash).is_some() } /// Get transaction executor - pub fn transaction_executor(&self) -> TransactionExecutor { - TransactionExecutor::new(self.config.transaction_limits) + fn transaction_executor(&self) -> TransactionExecutor { + TransactionExecutor::new(self.config().transaction_limits) } } +macro_rules! impl_state_ro { + ($($ident:ty),*) => {$( + impl StateReadOnly for $ident { + fn world(&self) -> &impl WorldReadOnly { + &self.world + } + fn config(&self) -> &Config { + &self.config + } + fn block_hashes(&self) -> &[HashOf] { + &self.block_hashes + } + fn transactions(&self) -> &impl StorageReadOnly, u64> { + &self.transactions + } + fn engine(&self) -> &wasmtime::Engine { + &self.engine + } + fn kura(&self) -> &Kura { + &self.kura + } + fn query_handle(&self) -> &LiveQueryStoreHandle { + &self.query_handle + } + fn new_tx_amounts(&self) -> &Mutex> { + &self.new_tx_amounts + } + } + )*}; +} + +impl_state_ro! { + StateBlock<'_>, StateTransaction<'_, '_>, StateView<'_> +} + impl<'state> StateBlock<'state> { /// Create struct to store changes during transaction or trigger execution pub fn transaction(&mut self) -> StateTransaction<'_, 'state> { @@ -1163,20 +1136,6 @@ impl<'state> StateBlock<'state> { self.world.commit(); } - /// Convert [`Self`] to [`WorldStateSnapshot`] - pub fn to_snapshot(&self) -> StateSnapshot<'_> { - StateSnapshot { - world: self.world.to_snapshot(), - config: &self.config, - block_hashes: &self.block_hashes, - transactions: self.transactions.to_snapshot(), - engine: self.engine, - kura: self.kura, - query_handle: self.query_handle, - new_tx_amounts: self.new_tx_amounts, - } - } - /// Commit `CommittedBlock` with changes in form of **Iroha Special /// Instructions** to `self`. /// @@ -1356,8 +1315,6 @@ impl<'state> StateBlock<'state> { TRANSACTION_LIMITS => self.config.transaction_limits, } } - - insert_world_state_read_only_methods! {} } impl StateTransaction<'_, '_> { @@ -1369,20 +1326,6 @@ impl StateTransaction<'_, '_> { self.world.apply(); } - /// Convert [`Self`] to [`WorldStateSnapshot`] - pub fn to_snapshot(&self) -> StateSnapshot<'_> { - StateSnapshot { - world: self.world.to_snapshot(), - config: &self.config, - block_hashes: &self.block_hashes, - transactions: self.transactions.to_snapshot(), - engine: self.engine, - kura: self.kura, - query_handle: self.query_handle, - new_tx_amounts: self.new_tx_amounts, - } - } - fn process_executable(&mut self, executable: &Executable, authority: AccountId) -> Result<()> { match executable { Executable::Instructions(instructions) => { @@ -1435,30 +1378,6 @@ impl StateTransaction<'_, '_> { } } } - - insert_world_state_read_only_methods! {} -} - -impl StateView<'_> { - /// Convert [`Self`] to [`WorldStateSnapshot`] - pub fn to_snapshot(&self) -> StateSnapshot<'_> { - StateSnapshot { - world: self.world.to_snapshot(), - config: &self.config, - block_hashes: &self.block_hashes, - transactions: self.transactions.to_snapshot(), - engine: self.engine, - kura: self.kura, - query_handle: self.query_handle, - new_tx_amounts: self.new_tx_amounts, - } - } - - insert_world_state_read_only_methods! {} -} - -impl StateSnapshot<'_> { - insert_world_state_read_only_methods! {} } /// Bounds for `range` queries diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index 2084fabbc97..b5c6cdd91ba 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -15,6 +15,7 @@ use iroha_genesis::GenesisNetwork; use iroha_logger::prelude::*; use iroha_telemetry::metrics::Metrics; use network_topology::{Role, Topology}; +use storage::storage::StorageReadOnly; use crate::{ block::ValidBlock, @@ -141,8 +142,8 @@ impl SumeragiHandle { self.metrics .domains - .set(state_view.world.domains.len() as u64); - for domain in state_view.world.domains() { + .set(state_view.world().domains().len() as u64); + for domain in state_view.world().domains_iter() { self.metrics .accounts .get_metric_with_label_values(&[domain.id().name.as_ref()]) diff --git a/core/src/tx.rs b/core/src/tx.rs index 1dbe083d776..26e0858a4e5 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -22,7 +22,7 @@ use iroha_macro::FromVariant; use crate::{ smartcontracts::wasm, - state::{StateBlock, StateTransaction}, + state::{StateBlock, StateTransaction, WorldReadOnly}, }; /// `AcceptedTransaction` — a transaction accepted by iroha peer. diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index f5e76492fbf..012f475eda0 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -13,6 +13,7 @@ use iroha_client::{ data_model::{isi::Instruction, peer::Peer as DataModelPeer, prelude::*, query::Query, Level}, }; use iroha_config::parameters::actual::Root as Config; +pub use iroha_core::state::StateReadOnly; use iroha_crypto::prelude::*; use iroha_data_model::{query::QueryOutputBox, ChainId}; use iroha_genesis::{GenesisNetwork, RawGenesisBlockFile}; diff --git a/telemetry/derive/src/lib.rs b/telemetry/derive/src/lib.rs index 6ce4c5cdb10..471260e9ee3 100644 --- a/telemetry/derive/src/lib.rs +++ b/telemetry/derive/src/lib.rs @@ -27,8 +27,19 @@ fn type_has_metrics_field(ty: &Type) -> bool { .last() .expect("Should have at least one segment") .ident; - *type_name == "StateSnapshot" || *type_name == "StateTransaction" + *type_name == "StateTransaction" } + Type::ImplTrait(impl_trait) => impl_trait.bounds.iter().any(|bounds| match bounds { + syn::TypeParamBound::Trait(trt) => { + let Path { segments, .. } = trt.path.clone(); + let type_name = &segments + .last() + .expect("Should have at least one segment") + .ident; + *type_name == "StateReadOnly" + } + _ => false, + }), _ => false, } } @@ -161,7 +172,7 @@ pub fn metrics(attr: TokenStream, item: TokenStream) -> TokenStream { emit!( emitter, func.sig, - "Function must have at least one argument of type `StateTransaction` or `StateSnapshot`." + "Function must have at least one argument of type `StateTransaction` or `StateReadOnly`." ); return emitter.finish_token_stream(); } @@ -219,7 +230,7 @@ fn impl_metrics(emitter: &mut Emitter, _specs: &MetricSpecs, func: &syn::ItemFn) emit!( emitter, args, - "At least one argument must be a `StateTransaction` or `StateSnapshot`." + "At least one argument must be a `StateTransaction` or `StateReadOnly`." ); return quote!(); } diff --git a/telemetry/derive/tests/ui_fail/args_no_wsv.stderr b/telemetry/derive/tests/ui_fail/args_no_wsv.stderr index efe4a8f09a3..03e687d5aba 100644 --- a/telemetry/derive/tests/ui_fail/args_no_wsv.stderr +++ b/telemetry/derive/tests/ui_fail/args_no_wsv.stderr @@ -1,4 +1,4 @@ -error: At least one argument must be a `StateTransaction` or `StateSnapshot`. +error: At least one argument must be a `StateTransaction` or `StateReadOnly`. --> tests/ui_fail/args_no_wsv.rs:4:12 | 4 | fn execute(_state: &World) -> Result<(), ()> { diff --git a/telemetry/derive/tests/ui_fail/no_args.stderr b/telemetry/derive/tests/ui_fail/no_args.stderr index db72e9a9c2b..247d11cee47 100644 --- a/telemetry/derive/tests/ui_fail/no_args.stderr +++ b/telemetry/derive/tests/ui_fail/no_args.stderr @@ -1,4 +1,4 @@ -error: Function must have at least one argument of type `StateTransaction` or `StateSnapshot`. +error: Function must have at least one argument of type `StateTransaction` or `StateReadOnly`. --> tests/ui_fail/no_args.rs:4:1 | 4 | fn execute() -> Result<(), ()> { diff --git a/torii/src/routing.rs b/torii/src/routing.rs index 87a164c8398..89095543651 100644 --- a/torii/src/routing.rs +++ b/torii/src/routing.rs @@ -106,7 +106,6 @@ pub async fn handle_queries( ) -> Result>> { let handle = task::spawn_blocking(move || { let state_view = state.view(); - let state_snapshot = state_view.to_snapshot(); match query_request.0 { QueryRequest::Query(QueryWithParameters { query: signed_query, @@ -114,8 +113,8 @@ pub async fn handle_queries( pagination, fetch_size, }) => { - let valid_query = ValidQueryRequest::validate(signed_query, &state_snapshot)?; - let query_output = valid_query.execute(&state_snapshot)?; + let valid_query = ValidQueryRequest::validate(signed_query, &state_view)?; + let query_output = valid_query.execute(&state_view)?; live_query_store .handle_query_output(query_output, &sorting, pagination, fetch_size) .map_err(ValidationFail::from)