diff --git a/Cargo.lock b/Cargo.lock index a7567ee68f5..35e4e1da2f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1827,6 +1827,7 @@ dependencies = [ "derive_more", "eyre", "futures", + "getset", "hex", "iroha_actor", "iroha_config", @@ -3571,7 +3572,6 @@ dependencies = [ name = "test_network" version = "2.0.0-pre-rc.5" dependencies = [ - "async-trait", "eyre", "futures", "iroha", @@ -3580,7 +3580,6 @@ dependencies = [ "iroha_core", "iroha_data_model", "iroha_logger", - "once_cell", "rand 0.8.5", "tempfile", "tokio", diff --git a/cli/derive/src/lib.rs b/cli/derive/src/lib.rs index cc46d4204c1..bd49187e859 100644 --- a/cli/derive/src/lib.rs +++ b/cli/derive/src/lib.rs @@ -35,7 +35,7 @@ use syn::{ /// 3) When the colon-separated form has spaces in the provided name. /// /// # Examples: -/// ```rust +/// ```no_run /// use warp::{Rejection, Filter}; /// use std::convert::Infallible; /// use iroha_cli::torii::utils::WarpResult; diff --git a/cli/src/lib.rs b/cli/src/lib.rs index a5c95d49d2e..f65f0a51304 100644 --- a/cli/src/lib.rs +++ b/cli/src/lib.rs @@ -18,7 +18,6 @@ use iroha_core::{ smartcontracts::permissions::{IsInstructionAllowedBoxed, IsQueryAllowedBoxed}, sumeragi::{Sumeragi, SumeragiTrait}, tx::{PeerId, TransactionValidator}, - wsv::WorldTrait, IrohaNetwork, }; use iroha_data_model::prelude::*; @@ -62,23 +61,17 @@ impl Default for Arguments { /// Iroha is an [Orchestrator](https://en.wikipedia.org/wiki/Orchestration_%28computing%29) of the /// system. It configures, coordinates and manages transactions and queries processing, work of consensus and storage. -pub struct Iroha< - W = World, - G = GenesisNetwork, - K = Kura, - S = Sumeragi, - B = BlockSynchronizer, -> where - W: WorldTrait, +pub struct Iroha, B = BlockSynchronizer> +where G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { /// World state view - pub wsv: Arc>, + pub wsv: Arc, /// Queue of transactions - pub queue: Arc>, + pub queue: Arc, /// Sumeragi consensus pub sumeragi: AlwaysAddr, /// Kura - block storage @@ -86,16 +79,15 @@ pub struct Iroha< /// Block synchronization actor pub block_sync: AlwaysAddr, /// Torii web server - pub torii: Option>, + pub torii: Option, } -impl Iroha +impl Iroha where - W: WorldTrait, G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { /// To make `Iroha` peer work all actors should be started first. /// After that moment it you can start it with listening to torii events. @@ -111,8 +103,8 @@ where #[allow(clippy::non_ascii_literal)] pub async fn new( args: &Arguments, - instruction_validator: IsInstructionAllowedBoxed, - query_validator: IsQueryAllowedBoxed, + instruction_validator: IsInstructionAllowedBoxed, + query_validator: IsQueryAllowedBoxed, ) -> Result { let broker = Broker::new(); let mut config = match Configuration::from_path(&args.config_path) { @@ -153,8 +145,8 @@ where pub async fn with_genesis( genesis: Option, config: Configuration, - instruction_validator: IsInstructionAllowedBoxed, - query_validator: IsQueryAllowedBoxed, + instruction_validator: IsInstructionAllowedBoxed, + query_validator: IsQueryAllowedBoxed, broker: Broker, telemetry: Option, ) -> Result { @@ -177,7 +169,7 @@ where let network_addr = network.start().await; let (events_sender, _) = broadcast::channel(100); - let world = W::with( + let world = World::with( domains(&config), config.sumeragi.trusted_peers.peers.clone(), ); @@ -187,6 +179,7 @@ where ); let query_validator = Arc::new(query_validator); + let transaction_validator = TransactionValidator::new( config.sumeragi.transaction_limits, Arc::new(instruction_validator), @@ -347,7 +340,7 @@ where /// /// # Errors /// - Genesis account public key not specified. -fn domains(configuration: &config::Configuration) -> impl Iterator { +fn domains(configuration: &config::Configuration) -> [Domain; 1] { let key = configuration.genesis.account_public_key.clone(); - [Domain::from(GenesisDomain::new(key))].into_iter() + [Domain::from(GenesisDomain::new(key))] } diff --git a/cli/src/torii/mod.rs b/cli/src/torii/mod.rs index e3f6e6d034f..291399b7f46 100644 --- a/cli/src/torii/mod.rs +++ b/cli/src/torii/mod.rs @@ -10,7 +10,6 @@ use iroha_core::{ prelude::*, queue::{self, Queue}, smartcontracts::{isi::query, permissions::IsQueryAllowedBoxed}, - wsv::WorldTrait, EventsSender, IrohaNetwork, }; use thiserror::Error; @@ -29,12 +28,12 @@ pub mod config; pub mod routing; /// Main network handler and the only entrypoint of the Iroha. -pub struct Torii { +pub struct Torii { iroha_cfg: super::Configuration, - wsv: Arc>, - queue: Arc>, + wsv: Arc, + queue: Arc, events: EventsSender, - query_validator: Arc>, + query_validator: Arc, network: iroha_actor::Addr, notify_shutdown: Arc, } diff --git a/cli/src/torii/routing.rs b/cli/src/torii/routing.rs index fa08c35c123..89f33aed4ec 100644 --- a/cli/src/torii/routing.rs +++ b/cli/src/torii/routing.rs @@ -12,11 +12,13 @@ use iroha_core::{ BlockPublisherMessage, BlockSubscriberMessage, VersionedBlockPublisherMessage, VersionedBlockSubscriberMessage, }, - smartcontracts::isi::{ - permissions::IsQueryAllowedBoxed, - query::{Error as QueryError, ValidQueryRequest}, + smartcontracts::{ + isi::{ + permissions::IsQueryAllowedBoxed, + query::{Error as QueryError, ValidQueryRequest}, + }, + permissions::IsAllowed as _, }, - wsv::WorldTrait, }; use iroha_crypto::SignatureOf; use iroha_data_model::{ @@ -52,10 +54,10 @@ impl VerifiedQueryRequest { /// - Account doesn't exist. /// - Account doesn't have the correct public key. /// - Account has incorrect permissions. - pub fn validate( + pub fn validate( self, - wsv: &WorldStateView, - query_validator: &IsQueryAllowedBoxed, + wsv: &WorldStateView, + query_validator: &IsQueryAllowedBoxed, ) -> Result<(ValidQueryRequest, PredicateBox), QueryError> { let account_has_public_key = wsv.map_account(&self.payload.account_id, |account| { account.contains_signatory(self.signature.public_key()) @@ -91,9 +93,9 @@ impl TryFrom for VerifiedQueryRequest { } #[iroha_futures::telemetry_future] -pub(crate) async fn handle_instructions( +pub(crate) async fn handle_instructions( iroha_cfg: Configuration, - queue: Arc>, + queue: Arc, transaction: VersionedTransaction, ) -> Result { let transaction: Transaction = transaction.into_v1(); @@ -114,9 +116,9 @@ pub(crate) async fn handle_instructions( } #[iroha_futures::telemetry_future] -pub(crate) async fn handle_queries( - wsv: Arc>, - query_validator: Arc>, +pub(crate) async fn handle_queries( + wsv: Arc, + query_validator: Arc, pagination: Pagination, request: VerifiedQueryRequest, ) -> Result> { @@ -162,8 +164,8 @@ async fn handle_schema() -> Json { } #[iroha_futures::telemetry_future] -async fn handle_pending_transactions( - queue: Arc>, +async fn handle_pending_transactions( + queue: Arc, pagination: Pagination, ) -> Result> { Ok(Scale( @@ -215,10 +217,7 @@ async fn handle_post_configuration( } #[iroha_futures::telemetry_future] -async fn handle_blocks_stream( - wsv: &WorldStateView, - mut stream: WebSocket, -) -> eyre::Result<()> { +async fn handle_blocks_stream(wsv: &WorldStateView, mut stream: WebSocket) -> eyre::Result<()> { let subscription_request: VersionedBlockSubscriberMessage = stream.recv().await?; let mut from_height = subscription_request.into_v1().try_into()?; @@ -237,9 +236,9 @@ async fn handle_blocks_stream( } } -async fn stream_blocks( +async fn stream_blocks( from_height: &mut u64, - wsv: &WorldStateView, + wsv: &WorldStateView, stream: &mut WebSocket, ) -> eyre::Result<()> { #[allow(clippy::expect_used)] @@ -348,7 +347,7 @@ mod subscription { #[iroha_futures::telemetry_future] #[cfg(feature = "telemetry")] -async fn handle_version(wsv: Arc>) -> Json { +async fn handle_version(wsv: Arc) -> Json { use iroha_version::Version; #[allow(clippy::expect_used)] @@ -363,29 +362,20 @@ async fn handle_version(wsv: Arc>) -> Json { } #[cfg(feature = "telemetry")] -async fn handle_metrics( - wsv: Arc>, - network: Addr, -) -> Result { +async fn handle_metrics(wsv: Arc, network: Addr) -> Result { update_metrics(&wsv, network).await?; wsv.metrics.try_to_string().map_err(Error::Prometheus) } #[cfg(feature = "telemetry")] -async fn handle_status( - wsv: Arc>, - network: Addr, -) -> Result { +async fn handle_status(wsv: Arc, network: Addr) -> Result { update_metrics(&wsv, network).await?; let status = Status::from(&wsv.metrics); Ok(reply::json(&status)) } #[cfg(feature = "telemetry")] -async fn update_metrics( - wsv: &WorldStateView, - network: Addr, -) -> Result<()> { +async fn update_metrics(wsv: &WorldStateView, network: Addr) -> Result<()> { let peers = network .send(iroha_p2p::network::GetConnectedPeers) .await @@ -413,13 +403,13 @@ async fn update_metrics( Ok(()) } -impl Torii { +impl Torii { /// Construct `Torii` from `ToriiConfiguration`. pub fn from_configuration( iroha_cfg: Configuration, - wsv: Arc>, - queue: Arc>, - query_validator: Arc>, + wsv: Arc, + queue: Arc, + query_validator: Arc, events: EventsSender, network: Addr, notify_shutdown: Arc, diff --git a/cli/src/torii/tests.rs b/cli/src/torii/tests.rs index 3e78e5127d0..ae96f310738 100644 --- a/cli/src/torii/tests.rs +++ b/cli/src/torii/tests.rs @@ -13,7 +13,7 @@ use iroha_core::{ BlockHeader, EmptyChainHash, }, queue::Queue, - smartcontracts::{isi::error::FindError, permissions::DenyAll}, + smartcontracts::{isi::error::FindError, permissions::combinators::DenyAll}, sumeragi::view_change::ProofChain, tx::TransactionValidator, wsv::World, @@ -29,7 +29,7 @@ use crate::{ stream::{Sink, Stream}, }; -async fn create_torii() -> (Torii, KeyPair) { +async fn create_torii() -> (Torii, KeyPair) { let mut config = crate::samples::get_config(crate::samples::get_trusted_peers(None), None); config.torii.p2p_addr = format!("127.0.0.1:{}", unique_port::get_unique_free_port().unwrap()); config.torii.api_url = format!("127.0.0.1:{}", unique_port::get_unique_free_port().unwrap()); @@ -54,7 +54,7 @@ async fn create_torii() -> (Torii, KeyPair) { .build() ) .is_none()); - wsv.world.domains.insert(domain_id, domain); + wsv.domains().insert(domain_id, domain); let queue = Arc::new(Queue::from_configuration(&config.queue, Arc::clone(&wsv))); let network = IrohaNetwork::new( Broker::new(), diff --git a/client/src/client.rs b/client/src/client.rs index 088cb97338b..007216643e1 100644 --- a/client/src/client.rs +++ b/client/src/client.rs @@ -1235,6 +1235,7 @@ mod tests { #[cfg(test)] mod query_errors_handling { use http::Response; + use iroha_core::smartcontracts::permissions::error::DenialReason; use super::*; @@ -1248,7 +1249,7 @@ mod tests { ), ( StatusCode::FORBIDDEN, - QueryError::Permission("whatever".to_owned()), + QueryError::Permission(DenialReason::Custom("whatever".to_owned())), ), ( StatusCode::NOT_FOUND, diff --git a/client/tests/integration/permissions.rs b/client/tests/integration/permissions.rs index 7190f2cb255..913d174d39e 100644 --- a/client/tests/integration/permissions.rs +++ b/client/tests/integration/permissions.rs @@ -3,7 +3,7 @@ use std::{str::FromStr as _, thread}; use iroha_client::client::{self, Client}; -use iroha_core::smartcontracts::isi::permissions::DenyAll; +use iroha_core::smartcontracts::isi::permissions::combinators::DenyAll; use iroha_data_model::prelude::*; use iroha_permissions_validators::{private_blockchain, public_blockchain}; use test_network::{PeerBuilder, *}; diff --git a/client/tests/integration/roles.rs b/client/tests/integration/roles.rs index 9aafd69ee4d..dd25b572f6e 100644 --- a/client/tests/integration/roles.rs +++ b/client/tests/integration/roles.rs @@ -4,7 +4,7 @@ use std::{str::FromStr as _, time::Duration}; use eyre::{eyre, Result}; use iroha_client::client::{self, Client}; -use iroha_core::{prelude::AllowAll, smartcontracts::permissions::ValidatorBuilder}; +use iroha_core::prelude::*; use iroha_data_model::prelude::*; use iroha_permissions_validators::public_blockchain::{ key_value::{CanRemoveKeyValueInUserMetadata, CanSetKeyValueInUserMetadata}, @@ -21,9 +21,9 @@ fn add_role_to_limit_transfer_count() -> Result<()> { // Peer has a special permission validator we need for this test let (_rt, _peer, mut test_client) = ::new() .with_instruction_validator( - ValidatorBuilder::new() - .with_recursive_validator(transfer::ExecutionCountFitsInLimit) - .all_should_succeed(), + ValidatorBuilder::with_recursive_validator(transfer::ExecutionCountFitsInLimit) + .all_should_succeed() + .build(), ) .with_query_validator(AllowAll) .start_with_runtime(); diff --git a/config/derive/src/lib.rs b/config/derive/src/lib.rs index 92dd0271f32..21f2d0b9fcf 100644 --- a/config/derive/src/lib.rs +++ b/config/derive/src/lib.rs @@ -166,7 +166,7 @@ fn impl_load_env( quote! { fn load_environment( &'_ mut self - ) -> std::result::Result<(), iroha_config::derive::Error> { + ) -> core::result::Result<(), iroha_config::derive::Error> { #(#set_field)* Ok(()) } @@ -183,7 +183,7 @@ fn impl_get_doc_recursive( return quote! { fn get_doc_recursive<'a>( inner_field: impl AsRef<[&'a str]>, - ) -> std::result::Result, iroha_config::derive::Error> + ) -> core::result::Result, iroha_config::derive::Error> { Err(iroha_config::derive::Error::UnknownField( inner_field.as_ref().iter().map(ToString::to_string).collect() @@ -218,7 +218,7 @@ fn impl_get_doc_recursive( quote! { fn get_doc_recursive<'a>( inner_field: impl AsRef<[&'a str]>, - ) -> std::result::Result, iroha_config::derive::Error> + ) -> core::result::Result, iroha_config::derive::Error> { let inner_field = inner_field.as_ref(); let doc = match inner_field { @@ -313,7 +313,7 @@ fn impl_get_recursive( fn get_recursive<'a, T>( &self, inner_field: T, - ) -> iroha_config::BoxedFuture<'a, Result> + ) -> iroha_config::BoxedFuture<'a, core::result::Result> where T: AsRef<[&'a str]> + Send + 'a, { @@ -353,7 +353,7 @@ fn impl_get_recursive( fn get_recursive<'a, T>( &self, inner_field: T, - ) -> Result + ) -> core::result::Result where T: AsRef<[&'a str]> + Send + 'a, { diff --git a/core/Cargo.toml b/core/Cargo.toml index faefca74239..08b2582abe8 100644 --- a/core/Cargo.toml +++ b/core/Cargo.toml @@ -65,6 +65,7 @@ wasmtime = "0.36.0" # transitive dependencies anyhow = ">= 1.0" derive_more = "0.99.17" +getset = "0.1.2" [dev-dependencies] tempfile = "3" diff --git a/core/benches/validation.rs b/core/benches/validation.rs index e28fa54bc48..b5f351b38e0 100644 --- a/core/benches/validation.rs +++ b/core/benches/validation.rs @@ -7,7 +7,7 @@ use iroha_core::{ prelude::*, sumeragi::view_change, tx::{AcceptedTransaction, TransactionValidator}, - wsv::{World, WorldTrait}, + wsv::World, }; use iroha_data_model::prelude::*; @@ -58,7 +58,7 @@ fn build_test_transaction(keys: KeyPair) -> Transaction { .expect("Failed to sign.") } -fn build_test_wsv(keys: KeyPair) -> WorldStateView { +fn build_test_wsv(keys: KeyPair) -> WorldStateView { let (public_key, _) = keys.into(); WorldStateView::new({ diff --git a/core/src/block.rs b/core/src/block.rs index 17b3cd5e679..e53113d90a0 100644 --- a/core/src/block.rs +++ b/core/src/block.rs @@ -29,7 +29,6 @@ use crate::{ view_change::{Proof, ProofChain as ViewChangeProofs}, }, tx::{TransactionValidator, VersionedAcceptedTransaction}, - wsv::WorldTrait, }; const PIPELINE_TIME_MS: u64 = @@ -317,10 +316,7 @@ impl BlockHeader { impl ChainedBlock { /// Validate block transactions against current state of the world. - pub fn validate( - self, - transaction_validator: &TransactionValidator, - ) -> VersionedValidBlock { + pub fn validate(self, transaction_validator: &TransactionValidator) -> VersionedValidBlock { let mut txs = Vec::new(); let mut rejected = Vec::new(); @@ -406,10 +402,7 @@ impl VersionedValidBlock { /// Validate block transactions against current state of the world. #[must_use] - pub fn revalidate( - self, - transaction_validator: &TransactionValidator, - ) -> Self { + pub fn revalidate(self, transaction_validator: &TransactionValidator) -> Self { self.into_v1().revalidate(transaction_validator).into() } @@ -438,7 +431,7 @@ impl VersionedValidBlock { } /// Checks if block has transactions that are already in blockchain. - pub fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool { + pub fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool { self.as_v1().has_committed_transactions(wsv) } @@ -452,9 +445,9 @@ impl VersionedValidBlock { /// /// # Errors /// Returns the error description if validation doesn't work. - pub fn validation_check( + pub fn validation_check( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, latest_block: &HashOf, latest_view_change: &HashOf, block_height: u64, @@ -552,10 +545,7 @@ impl ValidBlock { /// Validate block transactions against current state of the world. #[must_use] - pub fn revalidate( - self, - transaction_validator: &TransactionValidator, - ) -> Self { + pub fn revalidate(self, transaction_validator: &TransactionValidator) -> Self { Self { signatures: self.signatures, ..ChainedBlock { @@ -603,7 +593,7 @@ impl ValidBlock { } /// Checks if block has transactions that are already in blockchain. - pub fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool { + pub fn has_committed_transactions(&self, wsv: &WorldStateView) -> bool { self.transactions .iter() .any(|transaction| transaction.is_in_blockchain(wsv)) diff --git a/core/src/block_sync.rs b/core/src/block_sync.rs index 786fe1b9d0c..cfc0d9682e4 100644 --- a/core/src/block_sync.rs +++ b/core/src/block_sync.rs @@ -19,7 +19,6 @@ use crate::{ network_topology::Role, SumeragiTrait, }, - wsv::WorldTrait, VersionedCommittedBlock, }; @@ -35,8 +34,8 @@ enum State { /// Structure responsible for block synchronization between peers. #[derive(Debug)] -pub struct BlockSynchronizer { - wsv: Arc>, +pub struct BlockSynchronizer { + wsv: Arc, sumeragi: AlwaysAddr, peer_id: PeerId, state: State, @@ -50,26 +49,23 @@ pub struct BlockSynchronizer { pub trait BlockSynchronizerTrait: Actor + Handler + Handler { /// Requires sumeragi for sending direct messages to it type Sumeragi: SumeragiTrait; - /// Requires world to read latest blocks commited - type World: WorldTrait; /// Constructs `BlockSync` fn from_configuration( config: &BlockSyncConfiguration, - wsv: Arc>, + wsv: Arc, sumeragi: AlwaysAddr, peer_id: PeerId, broker: Broker, ) -> Self; } -impl BlockSynchronizerTrait for BlockSynchronizer { +impl BlockSynchronizerTrait for BlockSynchronizer { type Sumeragi = S; - type World = W; fn from_configuration( config: &BlockSyncConfiguration, - wsv: Arc>, + wsv: Arc, sumeragi: AlwaysAddr, peer_id: PeerId, broker: Broker, @@ -98,7 +94,7 @@ pub struct ContinueSync; pub struct ReceiveUpdates; #[async_trait::async_trait] -impl Actor for BlockSynchronizer { +impl Actor for BlockSynchronizer { fn actor_channel_capacity(&self) -> u32 { self.actor_channel_capacity } @@ -111,7 +107,7 @@ impl Actor for BlockSynchronizer { } #[async_trait::async_trait] -impl Handler for BlockSynchronizer { +impl Handler for BlockSynchronizer { type Result = (); async fn handle(&mut self, ReceiveUpdates: ReceiveUpdates) { let rng = &mut rand::rngs::StdRng::from_entropy(); @@ -124,7 +120,7 @@ impl Handler for BlockSynchroni } #[async_trait::async_trait] -impl Handler for BlockSynchronizer { +impl Handler for BlockSynchronizer { type Result = (); async fn handle(&mut self, ContinueSync: ContinueSync) { self.continue_sync().await; @@ -132,14 +128,14 @@ impl Handler for BlockSynchronize } #[async_trait::async_trait] -impl Handler for BlockSynchronizer { +impl Handler for BlockSynchronizer { type Result = (); async fn handle(&mut self, message: Message) { message.handle(self).await; } } -impl BlockSynchronizer { +impl BlockSynchronizer { /// Sends request for latest blocks to a chosen peer async fn request_latest_blocks_from_peer(&mut self, peer_id: PeerId) { Message::GetBlocksAfter(GetBlocksAfter::new( @@ -218,9 +214,7 @@ pub mod message { use parity_scale_codec::{Decode, Encode}; use super::{BlockSynchronizer, State}; - use crate::{ - block::VersionedCommittedBlock, sumeragi::SumeragiTrait, wsv::WorldTrait, NetworkMessage, - }; + use crate::{block::VersionedCommittedBlock, sumeragi::SumeragiTrait, NetworkMessage}; declare_versioned_with_scale!(VersionedMessage 1..2, Debug, Clone, iroha_macro::FromVariant, iroha_actor::Message); @@ -292,10 +286,7 @@ pub mod message { impl Message { /// Handles the incoming message. #[iroha_futures::telemetry_future] - pub async fn handle( - &self, - block_sync: &mut BlockSynchronizer, - ) { + pub async fn handle(&self, block_sync: &mut BlockSynchronizer) { match self { Message::GetBlocksAfter(GetBlocksAfter { hash, peer_id }) => { if block_sync.block_batch_size == 0 { diff --git a/core/src/genesis.rs b/core/src/genesis.rs index b55bd25fe07..c789f8add6a 100644 --- a/core/src/genesis.rs +++ b/core/src/genesis.rs @@ -23,7 +23,6 @@ use crate::{ network_topology::{GenesisBuilder as GenesisTopologyBuilder, Topology}, }, tx::VersionedAcceptedTransaction, - wsv::WorldTrait, IrohaNetwork, }; @@ -70,11 +69,11 @@ pub trait GenesisNetworkTrait: /// /// # Errors /// Returns error if waiting for peers or genesis round itself fails - async fn submit_transactions( + async fn submit_transactions( &self, - sumeragi: &mut SumeragiWithFault, + sumeragi: &mut SumeragiWithFault, network: Addr, - ctx: &mut iroha_actor::Context>, + ctx: &mut iroha_actor::Context>, ) -> Result<()> { iroha_logger::debug!("Starting submit genesis"); let genesis_topology = self diff --git a/core/src/kura.rs b/core/src/kura.rs index dfbc8b3f76c..5cd32a5cb28 100644 --- a/core/src/kura.rs +++ b/core/src/kura.rs @@ -27,9 +27,7 @@ use tokio::{ }; use tokio_stream::wrappers::ReadDirStream; -use crate::{ - block::VersionedCommittedBlock, block_sync::ContinueSync, prelude::*, sumeragi, wsv::WorldTrait, -}; +use crate::{block::VersionedCommittedBlock, block_sync::ContinueSync, prelude::*, sumeragi}; /// Message for storing committed block #[derive(Clone, Debug, Message)] @@ -46,22 +44,22 @@ pub struct GetBlockHash { /// High level data storage representation. /// Provides all necessary methods to read and write data, hides implementation details. #[derive(Debug)] -pub struct KuraWithIO { +pub struct KuraWithIO { // TODO: Kura doesn't have different initialisation modes!!! #[allow(dead_code)] mode: Mode, block_store: BlockStore, merkle_tree: MerkleTree, - wsv: Arc>, + wsv: Arc, broker: Broker, actor_channel_capacity: u32, } /// Production qualification of `KuraWithIO` -pub type Kura = KuraWithIO; +pub type Kura = KuraWithIO; /// Generic implementation for tests - accepting IO mocks -impl KuraWithIO { +impl KuraWithIO { /// ctor /// # Errors /// Will forward error from `BlockStore` construction @@ -69,7 +67,7 @@ impl KuraWithIO { mode: Mode, block_store_path: &Path, blocks_per_file: NonZeroU64, - wsv: Arc>, + wsv: Arc, broker: Broker, actor_channel_capacity: u32, io: IO, @@ -93,9 +91,6 @@ pub trait KuraTrait: + ContextHandler>> + Debug { - /// World for applying blocks which have been stored on disk - type World: WorldTrait; - /// Construct [`Kura`]. /// Kura will not be ready to work with before `init()` method invocation. /// # Errors @@ -104,7 +99,7 @@ pub trait KuraTrait: mode: Mode, block_store_path: &Path, blocks_per_file: NonZeroU64, - wsv: Arc>, + wsv: Arc, broker: Broker, actor_channel_capacity: u32, ) -> Result; @@ -114,7 +109,7 @@ pub trait KuraTrait: /// Fails if call to new fails async fn from_configuration( configuration: &config::KuraConfiguration, - wsv: Arc>, + wsv: Arc, broker: Broker, ) -> Result { Self::new( @@ -130,14 +125,12 @@ pub trait KuraTrait: } #[async_trait] -impl KuraTrait for Kura { - type World = W; - +impl KuraTrait for Kura { async fn new( mode: Mode, block_store_path: &Path, blocks_per_file: NonZeroU64, - wsv: Arc>, + wsv: Arc, broker: Broker, mailbox: u32, ) -> Result { @@ -155,7 +148,7 @@ impl KuraTrait for Kura { } #[async_trait::async_trait] -impl Actor for KuraWithIO { +impl Actor for KuraWithIO { fn actor_channel_capacity(&self) -> u32 { self.actor_channel_capacity } @@ -186,7 +179,7 @@ impl Actor for KuraWithIO { } #[async_trait::async_trait] -impl Handler for KuraWithIO { +impl Handler for KuraWithIO { type Result = Option>; async fn handle(&mut self, GetBlockHash { height }: GetBlockHash) -> Self::Result { if height == 0 { @@ -198,7 +191,7 @@ impl Handler for KuraWithIO { } #[async_trait::async_trait] -impl Handler for KuraWithIO { +impl Handler for KuraWithIO { type Result = (); async fn handle(&mut self, StoreBlock(block): StoreBlock) { @@ -212,7 +205,7 @@ impl Handler for KuraWithIO { } } -impl KuraWithIO { +impl KuraWithIO { /// After constructing [`Kura`] it should be initialized to be ready to work with it. /// /// # Errors @@ -668,7 +661,7 @@ mod tests { #[tokio::test] async fn strict_init_kura() { let temp_dir = TempDir::new().expect("Failed to create temp dir."); - assert!(Kura::::new( + assert!(Kura::new( Mode::Strict, temp_dir.path(), NonZeroU64::new(TEST_STORAGE_FILE_SIZE).unwrap(), @@ -683,7 +676,7 @@ mod tests { .is_ok()); } - fn get_transaction_validator() -> TransactionValidator { + fn get_transaction_validator() -> TransactionValidator { let tx_limits = TransactionLimits { max_instruction_number: 4096, max_wasm_size_bytes: 0, @@ -775,7 +768,7 @@ mod tests { .expect("Failed to sign blocks.") .commit(); let dir = tempfile::tempdir().unwrap(); - let mut kura = Kura::::new( + let mut kura = Kura::new( Mode::Strict, dir.path(), NonZeroU64::new(tests::TEST_STORAGE_FILE_SIZE).unwrap(), diff --git a/core/src/lib.rs b/core/src/lib.rs index 0895de48c6e..f7c02ed79ec 100644 --- a/core/src/lib.rs +++ b/core/src/lib.rs @@ -19,7 +19,7 @@ use tokio::sync::broadcast; use crate::{ block_sync::message::VersionedMessage as BlockSyncMessage, prelude::*, - sumeragi::message::VersionedMessage as SumeragiMessage, wsv::WorldTrait, + sumeragi::message::VersionedMessage as SumeragiMessage, }; /// The interval at which sumeragi checks if there are tx in the `queue`. @@ -56,7 +56,7 @@ pub enum NetworkMessage { /// Check to see if the given item was included in the blockchain. pub trait IsInBlockchain { /// Checks if this item has already been committed or rejected. - fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool; + fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool; } pub mod prelude { @@ -71,7 +71,9 @@ pub mod prelude { CommittedBlock, PendingBlock, ValidBlock, VersionedCommittedBlock, VersionedValidBlock, DEFAULT_CONSENSUS_ESTIMATION_MS, }, - smartcontracts::permissions::AllowAll, + smartcontracts::permissions::{ + builder::Validator as ValidatorBuilder, combinators::AllowAll, + }, smartcontracts::ValidQuery, tx::{ AcceptedTransaction, ValidTransaction, VersionedAcceptedTransaction, diff --git a/core/src/queue.rs b/core/src/queue.rs index daee58b6f01..fcd90d48f5b 100644 --- a/core/src/queue.rs +++ b/core/src/queue.rs @@ -12,13 +12,13 @@ use rand::seq::IteratorRandom; use thiserror::Error; pub use self::config::Configuration; -use crate::{prelude::*, wsv::WorldTrait}; +use crate::prelude::*; /// Lockfree queue for transactions /// /// Multiple producers, single consumer #[derive(Debug)] -pub struct Queue { +pub struct Queue { queue: ArrayQueue>, txs: DashMap, VersionedAcceptedTransaction>, /// Length of dashmap. @@ -30,7 +30,7 @@ pub struct Queue { ttl: Duration, future_threshold: Duration, - wsv: Arc>, + wsv: Arc, } /// Queue push error @@ -53,9 +53,9 @@ pub enum Error { SignatureCondition(#[from] Report), } -impl Queue { +impl Queue { /// Makes queue from configuration - pub fn from_configuration(cfg: &Configuration, wsv: Arc>) -> Self { + pub fn from_configuration(cfg: &Configuration, wsv: Arc) -> Self { Self { queue: ArrayQueue::new(cfg.maximum_transactions_in_queue as usize), txs: DashMap::new(), diff --git a/core/src/smartcontracts/isi/account.rs b/core/src/smartcontracts/isi/account.rs index 9567711abcc..2b522a16870 100644 --- a/core/src/smartcontracts/isi/account.rs +++ b/core/src/smartcontracts/isi/account.rs @@ -1,5 +1,5 @@ //! This module contains implementations of smart-contract traits and instructions for [`Account`] structure -//! and implementations of [`Query`]'s to [`WorldStateView`] about [`Account`]. +//! and implementations of [`Query`]'s to [`WorldStateView`] about [`Account`]. use iroha_data_model::prelude::*; use iroha_telemetry::metrics; @@ -15,14 +15,14 @@ use crate::{ValidQuery, WorldStateView}; pub mod isi { use super::{super::prelude::*, *}; - impl Execute for Mint { + impl Execute for Mint { type Error = Error; #[metrics(+"mint_account_pubkey")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.destination_id; let public_key = self.object; @@ -40,14 +40,14 @@ pub mod isi { } } - impl Execute for Burn { + impl Execute for Burn { type Error = Error; #[metrics(+"burn_account_pubkey")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.destination_id; let public_key = self.object; @@ -67,14 +67,14 @@ pub mod isi { } } - impl Execute for Mint { + impl Execute for Mint { type Error = Error; #[metrics(+"mint_account_signature_check_condition")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.destination_id; let signature_check_condition = self.object; @@ -86,14 +86,14 @@ pub mod isi { } } - impl Execute for SetKeyValue { + impl Execute for SetKeyValue { type Error = Error; #[metrics(+"set_key_value_account_string_value")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.object_id; @@ -111,14 +111,14 @@ pub mod isi { } } - impl Execute for RemoveKeyValue { + impl Execute for RemoveKeyValue { type Error = Error; #[metrics(+"remove_account_key_value")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.object_id; @@ -133,14 +133,14 @@ pub mod isi { } } - impl Execute for Grant { + impl Execute for Grant { type Error = Error; #[metrics(+"grant_account_permission_token")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.destination_id; let permission = self.object; @@ -156,15 +156,11 @@ pub mod isi { } } - impl Execute for Revoke { + impl Execute for Revoke { type Error = Error; #[metrics(+"revoke_account_permission_token")] - fn execute( - self, - _authority: AccountId, - wsv: &WorldStateView, - ) -> Result<(), Self::Error> { + fn execute(self, _authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error> { let account_id = self.destination_id; let permission = self.object; @@ -178,14 +174,14 @@ pub mod isi { } } - impl Execute for Grant { + impl Execute for Grant { type Error = Error; #[metrics(+"grant_account_role")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.destination_id; let role_id = self.object; @@ -208,15 +204,11 @@ pub mod isi { } } - impl Execute for Revoke { + impl Execute for Revoke { type Error = Error; #[metrics(+"revoke_account_role")] - fn execute( - self, - _authority: AccountId, - wsv: &WorldStateView, - ) -> Result<(), Self::Error> { + fn execute(self, _authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error> { let account_id = self.destination_id; let role_id = self.object; @@ -242,11 +234,11 @@ pub mod query { use eyre::{Result, WrapErr}; use super::{super::Evaluate, *}; - use crate::smartcontracts::{isi::prelude::WorldTrait, query::Error, FindError}; + use crate::smartcontracts::{query::Error, FindError}; - impl ValidQuery for FindRolesByAccountId { + impl ValidQuery for FindRolesByAccountId { #[metrics(+"find_roles_by_account_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let account_id = self .id .evaluate(wsv, &Context::new()) @@ -260,9 +252,9 @@ pub mod query { } } - impl ValidQuery for FindPermissionTokensByAccountId { + impl ValidQuery for FindPermissionTokensByAccountId { #[metrics(+"find_permission_tokens_by_account_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let account_id = self .id .evaluate(wsv, &Context::new()) @@ -276,9 +268,9 @@ pub mod query { } } - impl ValidQuery for FindAllAccounts { + impl ValidQuery for FindAllAccounts { #[metrics(+"find_all_accounts")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let mut vec = Vec::new(); for domain in wsv.domains().iter() { for account in domain.accounts() { @@ -289,9 +281,9 @@ pub mod query { } } - impl ValidQuery for FindAccountById { + impl ValidQuery for FindAccountById { #[metrics(+"find_account_by_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -302,9 +294,9 @@ pub mod query { } } - impl ValidQuery for FindAccountsByName { + impl ValidQuery for FindAccountsByName { #[metrics(+"find_account_by_name")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let name = self .name .evaluate(wsv, &Context::default()) @@ -323,9 +315,9 @@ pub mod query { } } - impl ValidQuery for FindAccountsByDomainId { + impl ValidQuery for FindAccountsByDomainId { #[metrics(+"find_accounts_by_domain_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .domain_id .evaluate(wsv, &Context::default()) @@ -336,9 +328,9 @@ pub mod query { } } - impl ValidQuery for FindAccountKeyValueByIdAndKey { + impl ValidQuery for FindAccountKeyValueByIdAndKey { #[metrics(+"find_account_key_value_by_id_and_key")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -357,9 +349,9 @@ pub mod query { } } - impl ValidQuery for FindAccountsWithAsset { + impl ValidQuery for FindAccountsWithAsset { #[metrics(+"find_accounts_with_asset")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let asset_definition_id = self .asset_definition_id .evaluate(wsv, &Context::default()) diff --git a/core/src/smartcontracts/isi/asset.rs b/core/src/smartcontracts/isi/asset.rs index 4fdea09f782..741c465a3d4 100644 --- a/core/src/smartcontracts/isi/asset.rs +++ b/core/src/smartcontracts/isi/asset.rs @@ -16,14 +16,14 @@ use super::prelude::*; pub mod isi { use super::*; - impl Execute for SetKeyValue { + impl Execute for SetKeyValue { type Error = Error; #[metrics(+"asset_set_key_value")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let asset_id = self.object_id; @@ -43,14 +43,14 @@ pub mod isi { } } - impl Execute for RemoveKeyValue { + impl Execute for RemoveKeyValue { type Error = Error; #[metrics(+"asset_remove_key_value")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let asset_id = self.object_id; @@ -73,14 +73,14 @@ pub mod isi { ($ty:ty, $metrics:literal) => { impl InnerMint for $ty {} - impl Execute for Mint { + impl Execute for Mint { type Error = Error; #[metrics(+$metrics)] fn execute( self, authority: AccountId, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { <$ty as InnerMint>::execute(self, authority, wsv) } @@ -92,14 +92,14 @@ pub mod isi { ($ty:ty, $metrics:literal) => { impl InnerBurn for $ty {} - impl Execute for Burn { + impl Execute for Burn { type Error = Error; #[metrics(+$metrics)] fn execute( self, authority: AccountId, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { <$ty as InnerBurn>::execute(self, authority, wsv) } @@ -111,14 +111,14 @@ pub mod isi { ($ty:ty, $metrics:literal) => { impl InnerTransfer for $ty {} - impl Execute for Transfer { + impl Execute for Transfer { type Error = Error; #[metrics(+$metrics)] fn execute( self, authority: AccountId, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { <$ty as InnerTransfer>::execute(self, authority, wsv) } @@ -140,10 +140,10 @@ pub mod isi { /// Trait for blanket mint implementation. trait InnerMint { - fn execute( + fn execute( mint: Mint, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Err> where Self: AssetInstructionInfo + CheckedOp + IntoMetric + Copy, @@ -181,10 +181,10 @@ pub mod isi { /// Trait for blanket burn implementation. trait InnerBurn { - fn execute( + fn execute( burn: Burn, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Err> where Self: AssetInstructionInfo + CheckedOp + IntoMetric + Copy, @@ -218,10 +218,10 @@ pub mod isi { /// Trait for blanket transfer implementation. trait InnerTransfer { - fn execute( + fn execute( transfer: Transfer, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Err> where Self: AssetInstructionInfo + CheckedOp + IntoMetric + Copy, @@ -290,9 +290,9 @@ pub mod isi { impl_asset_instruction_info!(Fixed, AssetValueType::Fixed, Fixed::ZERO); /// Asserts that asset definition with [`definition_id`] has asset type [`expected_value_type`]. - fn assert_asset_type( + fn assert_asset_type( definition_id: &AssetDefinitionId, - wsv: &WorldStateView, + wsv: &WorldStateView, expected_value_type: AssetValueType, ) -> Result { let asset_definition = wsv.asset_definition_entry(definition_id)?; @@ -309,9 +309,9 @@ pub mod isi { } /// Assert that this asset is `mintable`. - fn assert_can_mint( + fn assert_can_mint( definition_id: &AssetDefinitionId, - wsv: &WorldStateView, + wsv: &WorldStateView, expected_value_type: AssetValueType, ) -> Result<(), Error> { let definition = assert_asset_type(definition_id, wsv, expected_value_type)?; @@ -331,10 +331,10 @@ pub mod isi { } /// Assert that the two assets have the same asset `definition_id`. - fn assert_matching_definitions( + fn assert_matching_definitions( source: &::Id, destination: &::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, value_type: AssetValueType, ) -> Result<(), Error> { if destination.definition_id != source.definition_id { @@ -363,9 +363,9 @@ pub mod query { use super::*; use crate::smartcontracts::query::Error; - impl ValidQuery for FindAllAssets { + impl ValidQuery for FindAllAssets { #[metrics(+"find_all_assets")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let mut vec = Vec::new(); for domain in wsv.domains().iter() { for account in domain.accounts() { @@ -378,9 +378,9 @@ pub mod query { } } - impl ValidQuery for FindAllAssetsDefinitions { + impl ValidQuery for FindAllAssetsDefinitions { #[metrics(+"find_all_asset_definitions")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let mut vec = Vec::new(); for domain in wsv.domains().iter() { for asset_definition_entry in domain.asset_definitions() { @@ -391,9 +391,9 @@ pub mod query { } } - impl ValidQuery for FindAssetById { + impl ValidQuery for FindAssetById { #[metrics(+"find_asset_by_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -411,9 +411,9 @@ pub mod query { } } - impl ValidQuery for FindAssetDefinitionById { + impl ValidQuery for FindAssetDefinitionById { #[metrics(+"find_asset_defintion_by_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -426,9 +426,9 @@ pub mod query { } } - impl ValidQuery for FindAssetsByName { + impl ValidQuery for FindAssetsByName { #[metrics(+"find_assets_by_name")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let name = self .name .evaluate(wsv, &Context::default()) @@ -449,9 +449,9 @@ pub mod query { } } - impl ValidQuery for FindAssetsByAccountId { + impl ValidQuery for FindAssetsByAccountId { #[metrics(+"find_assets_by_account_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .account_id .evaluate(wsv, &Context::default()) @@ -462,9 +462,9 @@ pub mod query { } } - impl ValidQuery for FindAssetsByAssetDefinitionId { + impl ValidQuery for FindAssetsByAssetDefinitionId { #[metrics(+"find_assets_by_asset_definition_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .asset_definition_id .evaluate(wsv, &Context::default()) @@ -485,9 +485,9 @@ pub mod query { } } - impl ValidQuery for FindAssetsByDomainId { + impl ValidQuery for FindAssetsByDomainId { #[metrics(+"find_assets_by_domain_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .domain_id .evaluate(wsv, &Context::default()) @@ -504,9 +504,9 @@ pub mod query { } } - impl ValidQuery for FindAssetsByDomainIdAndAssetDefinitionId { + impl ValidQuery for FindAssetsByDomainIdAndAssetDefinitionId { #[metrics(+"find_assets_by_domain_id_and_asset_definition_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let domain_id = self .domain_id .evaluate(wsv, &Context::default()) @@ -536,9 +536,9 @@ pub mod query { } } - impl ValidQuery for FindAssetQuantityById { + impl ValidQuery for FindAssetQuantityById { #[metrics(+"find_asset_quantity_by_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -560,9 +560,9 @@ pub mod query { } } - impl ValidQuery for FindAssetKeyValueByIdAndKey { + impl ValidQuery for FindAssetKeyValueByIdAndKey { #[metrics(+"find_asset_key_value_by_id_and_key")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) diff --git a/core/src/smartcontracts/isi/block.rs b/core/src/smartcontracts/isi/block.rs index 2ed2a3f5698..6388aae0018 100644 --- a/core/src/smartcontracts/isi/block.rs +++ b/core/src/smartcontracts/isi/block.rs @@ -5,9 +5,9 @@ use iroha_telemetry::metrics; use super::*; -impl ValidQuery for FindAllBlocks { +impl ValidQuery for FindAllBlocks { #[metrics(+"find_all_blocks")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let mut blocks: Vec = wsv .blocks() .map(|blk| blk.clone()) diff --git a/core/src/smartcontracts/isi/domain.rs b/core/src/smartcontracts/isi/domain.rs index ea290b4ea73..b7a7a0e226d 100644 --- a/core/src/smartcontracts/isi/domain.rs +++ b/core/src/smartcontracts/isi/domain.rs @@ -16,14 +16,14 @@ pub mod isi { use super::*; - impl Execute for Register { + impl Execute for Register { type Error = Error; #[metrics(+"register_account")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account: Account = self.object.build(); let account_id = account.id().clone(); @@ -47,14 +47,14 @@ pub mod isi { } } - impl Execute for Unregister { + impl Execute for Unregister { type Error = Error; #[metrics(+"unregister_account")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let account_id = self.object_id; @@ -68,14 +68,14 @@ pub mod isi { } } - impl Execute for Register { + impl Execute for Register { type Error = Error; #[metrics(+"register_asset_def")] fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let asset_definition = self.object.build(); asset_definition @@ -101,14 +101,14 @@ pub mod isi { } } - impl Execute for Unregister { + impl Execute for Unregister { type Error = Error; #[metrics(+"unregister_asset_def")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let asset_definition_id = self.object_id; @@ -155,14 +155,14 @@ pub mod isi { } } - impl Execute for SetKeyValue { + impl Execute for SetKeyValue { type Error = Error; #[metrics(+"set_key_value_asset_def")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let asset_definition_id = self.object_id; @@ -184,14 +184,14 @@ pub mod isi { } } - impl Execute for RemoveKeyValue { + impl Execute for RemoveKeyValue { type Error = Error; #[metrics(+"remove_key_value_asset_def")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let asset_definition_id = self.object_id; @@ -211,14 +211,14 @@ pub mod isi { } } - impl Execute for SetKeyValue { + impl Execute for SetKeyValue { type Error = Error; #[metrics(+"set_key_value_domain")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let domain_id = self.object_id; @@ -234,14 +234,14 @@ pub mod isi { } } - impl Execute for RemoveKeyValue { + impl Execute for RemoveKeyValue { type Error = Error; #[metrics(+"remove_key_value_domain")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let domain_id = self.object_id; @@ -264,9 +264,9 @@ pub mod query { use super::*; use crate::smartcontracts::query::Error; - impl ValidQuery for FindAllDomains { + impl ValidQuery for FindAllDomains { #[metrics(+"find_all_domains")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { Ok(wsv .domains() .iter() @@ -275,9 +275,9 @@ pub mod query { } } - impl ValidQuery for FindDomainById { + impl ValidQuery for FindDomainById { #[metrics(+"find_domain_by_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -288,9 +288,9 @@ pub mod query { } } - impl ValidQuery for FindDomainKeyValueByIdAndKey { + impl ValidQuery for FindDomainKeyValueByIdAndKey { #[metrics(+"find_domain_key_value_by_id_and_key")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) @@ -309,9 +309,9 @@ pub mod query { } } - impl ValidQuery for FindAssetDefinitionKeyValueByIdAndKey { + impl ValidQuery for FindAssetDefinitionKeyValueByIdAndKey { #[metrics(+"find_asset_definition_key_value_by_id_and_key")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::default()) diff --git a/core/src/smartcontracts/isi/expression.rs b/core/src/smartcontracts/isi/expression.rs index 4fc5574e9cb..0d699942112 100644 --- a/core/src/smartcontracts/isi/expression.rs +++ b/core/src/smartcontracts/isi/expression.rs @@ -7,12 +7,9 @@ use iroha_data_model::{ }; use super::{Error, Evaluate, FindError, MathError}; -use crate::{ - prelude::ValidQuery, - wsv::{WorldStateView, WorldTrait}, -}; +use crate::{prelude::ValidQuery, wsv::WorldStateView}; -impl, W: WorldTrait> Evaluate for EvaluatesTo +impl> Evaluate for EvaluatesTo where >::Error: Into, { @@ -21,7 +18,7 @@ where fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let expr = self.expression.evaluate(wsv, context)?; @@ -32,13 +29,13 @@ where } } -impl Evaluate for Expression { +impl Evaluate for Expression { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { use Expression::*; @@ -68,13 +65,13 @@ impl Evaluate for Expression { } } -impl Evaluate for ContextValue { +impl Evaluate for ContextValue { type Value = Value; type Error = Error; fn evaluate( &self, - _wsv: &WorldStateView, + _wsv: &WorldStateView, context: &Context, ) -> Result { context @@ -84,13 +81,13 @@ impl Evaluate for ContextValue { } } -impl Evaluate for Add { +impl Evaluate for Add { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -99,13 +96,13 @@ impl Evaluate for Add { } } -impl Evaluate for Subtract { +impl Evaluate for Subtract { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -114,13 +111,13 @@ impl Evaluate for Subtract { } } -impl Evaluate for Greater { +impl Evaluate for Greater { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -129,13 +126,13 @@ impl Evaluate for Greater { } } -impl Evaluate for Less { +impl Evaluate for Less { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -144,13 +141,13 @@ impl Evaluate for Less { } } -impl Evaluate for Not { +impl Evaluate for Not { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let expression = self.expression.evaluate(wsv, context)?; @@ -158,13 +155,13 @@ impl Evaluate for Not { } } -impl Evaluate for And { +impl Evaluate for And { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -173,13 +170,13 @@ impl Evaluate for And { } } -impl Evaluate for Or { +impl Evaluate for Or { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -188,13 +185,13 @@ impl Evaluate for Or { } } -impl Evaluate for IfExpression { +impl Evaluate for IfExpression { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let condition = self.condition.evaluate(wsv, context)?; @@ -206,13 +203,13 @@ impl Evaluate for IfExpression { } } -impl Evaluate for Contains { +impl Evaluate for Contains { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let collection = self.collection.evaluate(wsv, context)?; @@ -221,13 +218,13 @@ impl Evaluate for Contains { } } -impl Evaluate for ContainsAll { +impl Evaluate for ContainsAll { type Error = Error; type Value = Value; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let collection = self.collection.evaluate(wsv, context)?; @@ -239,13 +236,13 @@ impl Evaluate for ContainsAll { } } -impl Evaluate for ContainsAny { +impl Evaluate for ContainsAny { type Error = Error; type Value = Value; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let collection = self.collection.evaluate(wsv, context)?; @@ -257,13 +254,13 @@ impl Evaluate for ContainsAny { } } -impl Evaluate for Equal { +impl Evaluate for Equal { type Error = Error; type Value = Value; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -272,13 +269,13 @@ impl Evaluate for Equal { } } -impl Evaluate for Where { +impl Evaluate for Where { type Error = Error; type Value = Value; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let additional_context: Result = self @@ -302,13 +299,13 @@ impl Evaluate for Where { } } -impl Evaluate for Multiply { +impl Evaluate for Multiply { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -317,13 +314,13 @@ impl Evaluate for Multiply { } } -impl Evaluate for RaiseTo { +impl Evaluate for RaiseTo { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -332,13 +329,13 @@ impl Evaluate for RaiseTo { } } -impl Evaluate for Divide { +impl Evaluate for Divide { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left: u32 = self.left.evaluate(wsv, context)?; @@ -349,13 +346,13 @@ impl Evaluate for Divide { } } -impl Evaluate for Mod { +impl Evaluate for Mod { type Value = Value; type Error = Error; fn evaluate( &self, - wsv: &WorldStateView, + wsv: &WorldStateView, context: &Context, ) -> Result { let left = self.left.evaluate(wsv, context)?; @@ -417,7 +414,7 @@ mod tests { ) .with_value("signatories".to_owned(), teller_signatory_set) .build(); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); assert_eq!( expression.evaluate(&wsv, &Context::new())?, Value::Bool(true) @@ -458,7 +455,7 @@ mod tests { WhereBuilder::evaluate(ContextValue::new("test_value")) .with_value("test_value".to_owned(), Add::new(2_u32, 3_u32)) .build() - .evaluate(&WorldStateView::::new(World::new()), &Context::new())?, + .evaluate(&WorldStateView::new(World::new()), &Context::new())?, Value::U32(5) ); Ok(()) @@ -475,8 +472,7 @@ mod tests { .build() .into(); assert_eq!( - outer_expression - .evaluate(&WorldStateView::::new(World::new()), &Context::new())?, + outer_expression.evaluate(&WorldStateView::new(World::new()), &Context::new())?, Value::U32(6) ); Ok(()) @@ -501,7 +497,7 @@ mod tests { #[test] fn if_condition_branches_correctly() -> Result<()> { - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); assert_eq!( IfExpression::new(true, 1_u32, 2_u32).evaluate(&wsv, &Context::new())?, Value::U32(1) @@ -518,7 +514,7 @@ mod tests { fn incorrect_types_are_caught() -> Result<()> { fn assert_eval(inst: &I, err_msg: &str) where - I: Evaluate + Debug, + I: Evaluate + Debug, I::Value: Debug, E: StdError + Eq + Default + Send + Sync + 'static, { @@ -560,7 +556,7 @@ mod tests { #[test] fn operations_are_correctly_calculated() -> Result<()> { - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); assert_eq!( Add::new(1_u32, 2_u32).evaluate(&wsv, &Context::new())?, Value::U32(3) @@ -622,7 +618,7 @@ mod tests { serde_json::to_string(&expression).expect("Failed to serialize."); let deserialized_expression: ExpressionBox = serde_json::from_str(&serialized_expression).expect("Failed to de-serialize."); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); assert_eq!( expression .evaluate(&wsv, &Context::new()) @@ -639,7 +635,7 @@ mod tests { let serialized_expression: Vec = expression.encode(); let deserialized_expression = ExpressionBox::decode(&mut serialized_expression.as_slice()) .expect("Failed to decode."); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); assert_eq!( expression .evaluate(&wsv, &Context::new()) diff --git a/core/src/smartcontracts/isi/mod.rs b/core/src/smartcontracts/isi/mod.rs index 7c9b1b0e0c6..95c161440a8 100644 --- a/core/src/smartcontracts/isi/mod.rs +++ b/core/src/smartcontracts/isi/mod.rs @@ -18,10 +18,7 @@ use iroha_data_model::{expression::prelude::*, isi::*, prelude::*}; use iroha_logger::prelude::*; use super::{Evaluate, Execute}; -use crate::{ - prelude::*, - wsv::{WorldStateView, WorldTrait}, -}; +use crate::{prelude::*, wsv::WorldStateView}; pub mod error { //! Errors used in Iroha special instructions and @@ -157,8 +154,8 @@ pub mod error { } /// Generic structure used to represent a mismatch - #[derive(Debug, Clone, PartialEq, Eq, Error)] - #[error("Expected {expected:?}, actual {actual:?}")] + #[derive(Debug, Clone, PartialEq, Eq, Error, Decode, Encode, IntoSchema)] + #[error("Expected {expected:?}, actual {actual:?}")] pub struct Mismatch { /// The value that is needed for normal execution pub expected: T, @@ -217,13 +214,13 @@ pub mod error { } } -impl Execute for Instruction { +impl Execute for Instruction { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { use Instruction::*; match self { @@ -245,10 +242,10 @@ impl Execute for Instruction { } } -impl Execute for RegisterBox { +impl Execute for RegisterBox { type Error = Error; - fn execute(self, authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error> { + fn execute(self, authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error> { let context = Context::new(); let object_id = self.object.evaluate(wsv, &context)?; iroha_logger::trace!(?object_id); @@ -272,10 +269,10 @@ impl Execute for RegisterBox { } } -impl Execute for UnregisterBox { +impl Execute for UnregisterBox { type Error = Error; - fn execute(self, authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error> { + fn execute(self, authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error> { let context = Context::new(); let object_id = self.object_id.evaluate(wsv, &context)?; iroha_logger::trace!(?object_id, %authority); @@ -299,13 +296,13 @@ impl Execute for UnregisterBox { } } -impl Execute for MintBox { +impl Execute for MintBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let destination_id = self.destination_id.evaluate(wsv, &context)?; @@ -336,13 +333,13 @@ impl Execute for MintBox { } } -impl Execute for BurnBox { +impl Execute for BurnBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let destination_id = self.destination_id.evaluate(wsv, &context)?; @@ -373,13 +370,13 @@ impl Execute for BurnBox { } } -impl Execute for TransferBox { +impl Execute for TransferBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let (source_asset_id, destination_asset_id) = match ( @@ -407,13 +404,13 @@ impl Execute for TransferBox { } } -impl Execute for SetKeyValueBox { +impl Execute for SetKeyValueBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let key = self.key.evaluate(wsv, &context)?; @@ -439,13 +436,13 @@ impl Execute for SetKeyValueBox { } } -impl Execute for RemoveKeyValueBox { +impl Execute for RemoveKeyValueBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let key = self.key.evaluate(wsv, &context)?; @@ -466,13 +463,13 @@ impl Execute for RemoveKeyValueBox { } } -impl Execute for If { +impl Execute for If { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); iroha_logger::trace!(?self); @@ -485,13 +482,13 @@ impl Execute for If { } } -impl Execute for Pair { +impl Execute for Pair { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { iroha_logger::trace!(?self); @@ -501,13 +498,13 @@ impl Execute for Pair { } } -impl Execute for SequenceBox { +impl Execute for SequenceBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { iroha_logger::trace!(?self); @@ -518,13 +515,13 @@ impl Execute for SequenceBox { } } -impl Execute for FailBox { +impl Execute for FailBox { type Error = Error; fn execute( self, _authority: ::Id, - _wsv: &WorldStateView, + _wsv: &WorldStateView, ) -> Result<(), Self::Error> { iroha_logger::trace!(?self); @@ -532,13 +529,13 @@ impl Execute for FailBox { } } -impl Execute for GrantBox { +impl Execute for GrantBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let destination_id = self.destination_id.evaluate(wsv, &context)?; @@ -557,13 +554,13 @@ impl Execute for GrantBox { } } -impl Execute for RevokeBox { +impl Execute for RevokeBox { type Error = Error; fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let context = Context::new(); let destination_id = self.destination_id.evaluate(wsv, &context)?; @@ -616,7 +613,7 @@ mod tests { #[test] fn asset_store() -> Result<()> { - let wsv = WorldStateView::::new(world_with_test_domains()?); + let wsv = WorldStateView::new(world_with_test_domains()?); let account_id = AccountId::from_str("alice@wonderland")?; let asset_definition_id = AssetDefinitionId::from_str("rose#wonderland")?; let asset_id = AssetId::new(asset_definition_id, account_id.clone()); diff --git a/core/src/smartcontracts/isi/permissions.rs b/core/src/smartcontracts/isi/permissions.rs deleted file mode 100644 index 82e3537432e..00000000000 --- a/core/src/smartcontracts/isi/permissions.rs +++ /dev/null @@ -1,994 +0,0 @@ -#![allow(clippy::module_name_repetitions)] - -//! This module contains permissions related Iroha functionality. - -use std::{iter, sync::Arc}; - -use eyre::Result; -use iroha_data_model::{isi::RevokeBox, prelude::*}; - -use super::Evaluate; -use crate::wsv::{WorldStateView, WorldTrait}; - -/// Operation for which the permission should be checked. -pub trait NeedsPermission {} - -impl NeedsPermission for Instruction {} - -impl NeedsPermission for QueryBox {} - -// Expression might contain a query, therefore needs to be checked. -impl NeedsPermission for Expression {} - -/// Reason for prohibiting the execution of the particular instruction. -pub type DenialReason = String; - -/// Implement this to provide custom permission checks for the Iroha based blockchain. -pub trait IsAllowed { - /// Checks if the `authority` is allowed to perform `instruction` - /// given the current state of `wsv`. - /// - /// # Errors - /// If the execution of `instruction` under given `authority` with - /// the current state of `wsv` is disallowed. - fn check( - &self, - authority: &AccountId, - operation: &O, - wsv: &WorldStateView, - ) -> Result<(), DenialReason>; -} - -/// Box with permissions validator. -pub type IsAllowedBoxed = Box + Send + Sync>; - -/// Box with permissions validator for `Instruction`. -pub type IsInstructionAllowedBoxed = IsAllowedBoxed; - -/// Box with permissions validator for `Query`. -pub type IsQueryAllowedBoxed = IsAllowedBoxed; - -/// Trait for joining validators with `or` method, auto-implemented -/// for all types which convert to [`IsAllowedBoxed`]. -pub trait ValidatorApplyOr { - /// Combines two validators into [`Or`]. - fn or(self, another: impl Into>) -> Or; -} - -impl>> ValidatorApplyOr - for V -{ - fn or(self, another: impl Into>) -> Or { - Or { - first: self.into(), - second: another.into(), - } - } -} - -/// `check` succeeds if either `first` or `second` validator succeeds. -pub struct Or { - first: IsAllowedBoxed, - second: IsAllowedBoxed, -} - -impl IsAllowed for Or { - fn check( - &self, - authority: &AccountId, - operation: &O, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - self.first - .check(authority, operation, wsv) - .or_else(|first_error| { - self.second - .check(authority, operation, wsv) - .map_err(|second_error| { - format!( - "Failed to pass first check with {} and second check with {}.", - first_error, second_error - ) - }) - }) - } -} - -impl From> for IsAllowedBoxed { - fn from(validator: Or) -> Self { - Box::new(validator) - } -} - -/// Wraps validator to check nested permissions. Pay attention to -/// wrap only validators that do not check nested intructions by -/// themselves. -pub struct CheckNested { - validator: IsAllowedBoxed, -} - -impl CheckNested { - /// Wraps `validator` to check nested permissions. - pub fn new(validator: IsAllowedBoxed) -> Self { - CheckNested { validator } - } -} - -impl IsAllowed for CheckNested { - fn check( - &self, - authority: &AccountId, - instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - match instruction { - Instruction::Register(_) - | Instruction::Unregister(_) - | Instruction::Mint(_) - | Instruction::Burn(_) - | Instruction::SetKeyValue(_) - | Instruction::RemoveKeyValue(_) - | Instruction::Transfer(_) - | Instruction::Grant(_) - | Instruction::Revoke(_) - | Instruction::Fail(_) - | Instruction::ExecuteTrigger(_) => self.validator.check(authority, instruction, wsv), - Instruction::If(if_box) => { - self.check(authority, &if_box.then, wsv) - .and_then(|_| match &if_box.otherwise { - Some(this_instruction) => self.check(authority, this_instruction, wsv), - None => Ok(()), - }) - } - Instruction::Pair(pair_box) => self - .check(authority, &pair_box.left_instruction, wsv) - .and(self.check(authority, &pair_box.right_instruction, wsv)), - Instruction::Sequence(sequence_box) => sequence_box - .instructions - .iter() - .try_for_each(|this_instruction| self.check(authority, this_instruction, wsv)), - } - } -} - -/// Checks an expression recursively to evaluate if there is a query -/// inside of it and if the user has permission to execute this query. -/// -/// As the function is recursive, caution should be exercised to have -/// a limit of nestedness, that would not cause stack overflow. Up to -/// 2^13 calls were tested and are ok. This is within default -/// instruction limit. -/// -/// # Errors -/// If a user is not allowed to execute one of the inner queries, -/// given the current `validator`. -fn check_query_in_expression( - authority: &AccountId, - expression: &Expression, - wsv: &WorldStateView, - validator: &IsQueryAllowedBoxed, -) -> Result<(), DenialReason> { - macro_rules! check_binary_expression { - ($e:ident) => { - check_query_in_expression(authority, &($e).left.expression, wsv, validator).and( - check_query_in_expression(authority, &($e).right.expression, wsv, validator), - ) - }; - } - - match expression { - Expression::Add(expression) => check_binary_expression!(expression), - Expression::Subtract(expression) => check_binary_expression!(expression), - Expression::Multiply(expression) => check_binary_expression!(expression), - Expression::Divide(expression) => check_binary_expression!(expression), - Expression::Mod(expression) => check_binary_expression!(expression), - Expression::RaiseTo(expression) => check_binary_expression!(expression), - Expression::Greater(expression) => check_binary_expression!(expression), - Expression::Less(expression) => check_binary_expression!(expression), - Expression::Equal(expression) => check_binary_expression!(expression), - Expression::Not(expression) => { - check_query_in_expression(authority, &expression.expression.expression, wsv, validator) - } - Expression::And(expression) => check_binary_expression!(expression), - Expression::Or(expression) => check_binary_expression!(expression), - Expression::If(expression) => { - check_query_in_expression(authority, &expression.condition.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &expression.then_expression.expression, - wsv, - validator, - )) - .and(check_query_in_expression( - authority, - &expression.else_expression.expression, - wsv, - validator, - )) - } - Expression::Query(query) => validator.check(authority, query, wsv), - Expression::Contains(expression) => { - check_query_in_expression(authority, &expression.collection.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &expression.element.expression, - wsv, - validator, - )) - } - Expression::ContainsAll(expression) => { - check_query_in_expression(authority, &expression.collection.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &expression.elements.expression, - wsv, - validator, - )) - } - Expression::ContainsAny(expression) => { - check_query_in_expression(authority, &expression.collection.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &expression.elements.expression, - wsv, - validator, - )) - } - Expression::Where(expression) => { - check_query_in_expression(authority, &expression.expression.expression, wsv, validator) - } - Expression::ContextValue(_) | Expression::Raw(_) => Ok(()), - } -} - -/// Checks an instruction recursively to evaluate if there is a query -/// inside of it and if the user has permission to execute this query. -/// -/// As the function is recursive, caution should be exercised to have -/// a limit of nesting, that would not cause stack overflow. Up to -/// 2^13 calls were tested and are ok. This is within default -/// instruction limit. -/// -/// # Errors -/// If a user is not allowed to execute one of the inner queries, -/// given the current `validator`. -#[allow(clippy::too_many_lines)] -fn check_query_in_instruction( - authority: &AccountId, - instruction: &Instruction, - wsv: &WorldStateView, - validator: &IsQueryAllowedBoxed, -) -> Result<(), DenialReason> { - match instruction { - Instruction::Register(instruction) => { - check_query_in_expression(authority, &instruction.object.expression, wsv, validator) - } - Instruction::Unregister(instruction) => { - check_query_in_expression(authority, &instruction.object_id.expression, wsv, validator) - } - Instruction::Mint(instruction) => { - check_query_in_expression(authority, &instruction.object.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.destination_id.expression, - wsv, - validator, - )) - } - Instruction::Burn(instruction) => { - check_query_in_expression(authority, &instruction.object.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.destination_id.expression, - wsv, - validator, - )) - } - Instruction::Transfer(instruction) => { - check_query_in_expression(authority, &instruction.object.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.destination_id.expression, - wsv, - validator, - )) - .and(check_query_in_expression( - authority, - &instruction.source_id.expression, - wsv, - validator, - )) - } - Instruction::SetKeyValue(instruction) => { - check_query_in_expression(authority, &instruction.object_id.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.key.expression, - wsv, - validator, - )) - .and(check_query_in_expression( - authority, - &instruction.value.expression, - wsv, - validator, - )) - } - Instruction::RemoveKeyValue(instruction) => { - check_query_in_expression(authority, &instruction.object_id.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.key.expression, - wsv, - validator, - )) - } - Instruction::Grant(instruction) => { - check_query_in_expression(authority, &instruction.object.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.destination_id.expression, - wsv, - validator, - )) - } - Instruction::Revoke(instruction) => { - check_query_in_expression(authority, &instruction.object.expression, wsv, validator) - .and(check_query_in_expression( - authority, - &instruction.destination_id.expression, - wsv, - validator, - )) - } - Instruction::If(if_box) => { - check_query_in_instruction(authority, &if_box.then, wsv, validator).and_then(|_| { - match &if_box.otherwise { - Some(this_instruction) => { - check_query_in_instruction(authority, this_instruction, wsv, validator) - } - None => Ok(()), - } - }) - } - Instruction::Pair(pair_box) => { - check_query_in_instruction(authority, &pair_box.left_instruction, wsv, validator).and( - check_query_in_instruction(authority, &pair_box.right_instruction, wsv, validator), - ) - } - Instruction::Sequence(sequence_box) => { - sequence_box - .instructions - .iter() - .try_for_each(|this_instruction| { - check_query_in_instruction(authority, this_instruction, wsv, validator) - }) - } - Instruction::Fail(_) | Instruction::ExecuteTrigger(_) => Ok(()), - } -} - -impl From> for IsAllowedBoxed { - fn from(validator: CheckNested) -> Self { - Box::new(validator) - } -} - -/// A container for multiple permissions validators. It will succeed if all validators succeed. -pub struct AllShouldSucceed { - validators: Vec>, -} - -impl IsAllowed for AllShouldSucceed { - fn check( - &self, - authority: &AccountId, - operation: &O, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - for validator in &self.validators { - validator.check(authority, operation, wsv)? - } - Ok(()) - } -} - -impl From> - for IsAllowedBoxed -{ - fn from(validator: AllShouldSucceed) -> Self { - Box::new(validator) - } -} - -/// A container for multiple permissions validators. It will succeed if any validator succeeds. -pub struct AnyShouldSucceed { - name: String, - validators: Vec>, -} - -impl IsAllowed for AnyShouldSucceed { - fn check( - &self, - authority: &AccountId, - operation: &O, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - for validator in &self.validators { - if validator.check(authority, operation, wsv).is_ok() { - return Ok(()); - } - } - Err(format!( - "None of the instructions succeeded in Any permission check block with name: {}", - self.name - )) - } -} - -impl From> - for IsAllowedBoxed -{ - fn from(validator: AnyShouldSucceed) -> Self { - Box::new(validator) - } -} - -/// Builder to combine multiple validation checks into one. -#[derive(Default)] -#[must_use = ".build() not used"] -pub struct ValidatorBuilder { - validators: Vec>, -} - -impl ValidatorBuilder { - /// Returns new `ValidatorBuilder`, with empty set of validator checks. - pub fn new() -> Self { - ValidatorBuilder { - validators: Vec::new(), - } - } - - /// Adds a validator to the list. - pub fn with_validator(self, validator: impl Into>) -> Self { - ValidatorBuilder { - validators: self - .validators - .into_iter() - .chain(iter::once(validator.into())) - .collect(), - } - } - - /// Returns [`AllShouldSucceed`] that will check all the checks of previously supplied validators. - pub fn all_should_succeed(self) -> IsAllowedBoxed { - AllShouldSucceed { - validators: self.validators, - } - .into() - } - - /// Returns [`AnyShouldSucceed`] that will succeed if any of the checks of previously supplied validators succeds. - pub fn any_should_succeed(self, check_name: impl Into) -> IsAllowedBoxed { - AnyShouldSucceed { - name: check_name.into(), - validators: self.validators, - } - .into() - } -} - -impl ValidatorBuilder { - /// Adds a validator to the list and wraps it with `CheckNested` to check nested permissions. - pub fn with_recursive_validator( - self, - validator: impl Into>, - ) -> Self { - self.with_validator(CheckNested::new(validator.into())) - } -} - -/// Allows all operations to be executed for all possible values. Mostly for tests and simple cases. -#[derive(Debug, Clone, Copy)] -pub struct AllowAll; - -impl AllowAll { - /// Construct permission which allows all items - #[allow(clippy::new_ret_no_self)] - pub fn new() -> Arc - where - Self: Into, - { - Arc::new(Self.into()) - } -} - -/// Disallows all operations to be executed for all possible -/// values. Mostly for tests and simple cases. -#[derive(Debug, Clone, Copy)] -pub struct DenyAll; - -impl DenyAll { - /// Construct permission which denies all items - #[allow(clippy::new_ret_no_self)] - pub fn new() -> Arc - where - Self: Into, - { - Arc::new(Self.into()) - } -} - -impl IsAllowed for AllowAll { - fn check( - &self, - _authority: &AccountId, - _instruction: &O, - _wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - Ok(()) - } -} - -impl IsAllowed for DenyAll { - fn check( - &self, - _authority: &AccountId, - _instruction: &O, - _wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - Err("All operations are denied.".to_owned()) - } -} - -impl From for IsAllowedBoxed { - fn from(AllowAll: AllowAll) -> Self { - Box::new(AllowAll) - } -} - -impl From for IsAllowedBoxed { - fn from(DenyAll: DenyAll) -> Self { - Box::new(DenyAll) - } -} - -/// Boxed validator implementing [`HasToken`] validator trait. -pub type HasTokenBoxed = Box + Send + Sync>; - -/// Trait that should be implemented by validator that checks the need to have permission token for a certain action. -pub trait HasToken { - /// This function should return the token that `authority` should - /// possess, given the `instruction` they are planning to execute - /// on the current state of `wsv` - /// - /// # Errors - /// - /// In the case when it is impossible to deduce the required token - /// given current data (e.g. unexistent account or unaplicable - /// instruction). - fn token( - &self, - authority: &AccountId, - instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result; -} - -impl IsAllowed for HasTokenBoxed { - fn check( - &self, - authority: &AccountId, - instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - let permission_token = self - .token(authority, instruction, wsv) - .map_err(|err| format!("Unable to identify corresponding permission token: {}", err))?; - let contain = wsv - .map_account(authority, |account| { - account.contains_permission(&permission_token) - }) - .map_err(|e| e.to_string())?; - if contain { - Ok(()) - } else { - Err(format!( - "Account does not have the needed permission token: {:?}.", - permission_token - )) - } - } -} - -// TODO: rewrite when specialization reaches stable -// Currently we simply can't do the following: -// impl PermissionsValidator for T {} -// when we have -// impl PermissionsValidator for T {} -/// Boxed validator implementing [`IsGrantAllowed`] trait. -pub type IsGrantAllowedBoxed = Box + Send + Sync>; - -/// Checks the [`GrantBox`] instruction. -pub trait IsGrantAllowed { - /// Checks the [`GrantBox`] instruction. - /// - /// # Errors - /// If this validator doesn't approve this Grant instruction. - fn check_grant( - &self, - authority: &AccountId, - instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason>; -} - -/// Boxed validator implementing the [`IsRevokeAllowed`] trait. -pub type IsRevokeAllowedBoxed = Box + Send + Sync>; - -/// Checks the [`RevokeBox`] instruction. -pub trait IsRevokeAllowed { - /// Checks the [`RevokeBox`] instruction. - /// - /// # Errors - /// If this validator doesn't approve this Revoke instruction. - fn check_revoke( - &self, - authority: &AccountId, - instruction: &RevokeBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason>; -} - -impl IsAllowed for IsGrantAllowedBoxed { - fn check( - &self, - authority: &AccountId, - instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - if let Instruction::Grant(isi) = instruction { - self.check_grant(authority, isi, wsv) - } else { - Ok(()) - } - } -} - -impl IsAllowed for IsRevokeAllowedBoxed { - fn check( - &self, - authority: &AccountId, - instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { - if let Instruction::Revoke(isi) = instruction { - self.check_revoke(authority, isi, wsv) - } else { - Ok(()) - } - } -} - -impl From> for IsInstructionAllowedBoxed { - fn from(validator: IsGrantAllowedBoxed) -> Self { - Box::new(validator) - } -} - -impl From> for IsInstructionAllowedBoxed { - fn from(validator: IsRevokeAllowedBoxed) -> Self { - Box::new(validator) - } -} - -/// Unpacks instruction if it is Grant of a Role into several Grants -/// fo Permission Token. If instruction is not Grant of Role, returns -/// it as inly instruction inside the vec. Should be called before -/// permission checks by validators. -/// -/// Semantically means that user can grant a role only if they can -/// grant each of the permission tokens that the role consists of. -/// -/// # Errors -/// Evaluation failure of instruction fields. -fn unpack_if_role_grant( - instruction: Instruction, - wsv: &WorldStateView, -) -> Result> { - let grant = if let Instruction::Grant(grant) = &instruction { - grant - } else { - return Ok(vec![instruction]); - }; - let id = if let Value::Id(IdBox::RoleId(id)) = grant.object.evaluate(wsv, &Context::new())? { - id - } else { - return Ok(vec![instruction]); - }; - - let instructions = if let Some(role) = wsv.world.roles.get(&id) { - let destination_id = grant.destination_id.evaluate(wsv, &Context::new())?; - role.permissions() - .cloned() - .map(|permission_token| GrantBox::new(permission_token, destination_id.clone()).into()) - .collect() - } else { - Vec::new() - }; - Ok(instructions) -} - -/// Unpack instruction if it is a Revoke of a Role, into several -/// Revocations of Permission Tokens. If the instruction is not a -/// Revoke of Role, returns it as an internal instruction inside the -/// vec. -/// -/// This `fn` should be called before permission checks (by -/// validators). -/// -/// Semantically: the user can revoke a role only if they can revoke -/// each of the permission tokens that the role consists of of. -/// -/// # Errors -/// Evaluation failure of each of the instruction fields. -pub fn unpack_if_role_revoke( - instruction: Instruction, - wsv: &WorldStateView, -) -> Result> { - let revoke = if let Instruction::Revoke(revoke) = &instruction { - revoke - } else { - return Ok(vec![instruction]); - }; - let id = if let Value::Id(IdBox::RoleId(id)) = revoke.object.evaluate(wsv, &Context::new())? { - id - } else { - return Ok(vec![instruction]); - }; - - let instructions = if let Some(role) = wsv.world.roles.get(&id) { - let destination_id = revoke.destination_id.evaluate(wsv, &Context::new())?; - role.permissions() - .cloned() - .map(|permission_token| RevokeBox::new(permission_token, destination_id.clone()).into()) - .collect() - } else { - Vec::new() - }; - Ok(instructions) -} - -/// Verify that the given instruction is allowed to execute -/// -/// # Errors -/// -/// If given instruction is not permitted to execute -#[allow(clippy::expect_used)] -pub fn check_instruction_permissions( - account_id: &AccountId, - instruction: &Instruction, - is_instruction_allowed: &IsInstructionAllowedBoxed, - is_query_allowed: &IsQueryAllowedBoxed, - wsv: &WorldStateView, -) -> Result<(), TransactionRejectionReason> { - let granted_instructions = &unpack_if_role_grant(instruction.clone(), wsv) - .expect("Infallible. Evaluations have been checked by instruction execution."); - - for isi in granted_instructions { - is_instruction_allowed - .check(account_id, isi, wsv) - .map_err(|reason| NotPermittedFail { reason }) - .map_err(TransactionRejectionReason::NotPermitted)?; - } - check_query_in_instruction(account_id, instruction, wsv, is_query_allowed) - .map_err(|reason| NotPermittedFail { reason }) - .map_err(TransactionRejectionReason::NotPermitted)?; - - Ok(()) -} - -pub mod prelude { - //! Exports common types for permissions. - - pub use super::{ - AllowAll, DenialReason, HasTokenBoxed, IsAllowedBoxed, IsGrantAllowed, IsGrantAllowedBoxed, - IsRevokeAllowed, IsRevokeAllowedBoxed, - }; -} - -#[cfg(test)] -mod tests { - #![allow(clippy::restriction)] - - use std::{collections::BTreeSet, str::FromStr as _}; - - use iroha_data_model::{expression::prelude::*, isi::*}; - - use super::*; - use crate::wsv::World; - - struct DenyBurn; - - impl From for IsInstructionAllowedBoxed { - fn from(permissions: DenyBurn) -> Self { - Box::new(permissions) - } - } - - impl IsAllowed for DenyBurn { - fn check( - &self, - _authority: &AccountId, - instruction: &Instruction, - _wsv: &WorldStateView, - ) -> Result<(), super::DenialReason> { - match instruction { - Instruction::Burn(_) => Err("Denying sequence isi.".to_owned()), - _ => Ok(()), - } - } - } - - struct DenyAlice; - - impl From for IsInstructionAllowedBoxed { - fn from(permissions: DenyAlice) -> Self { - Box::new(permissions) - } - } - - impl IsAllowed for DenyAlice { - fn check( - &self, - authority: &AccountId, - _instruction: &Instruction, - _wsv: &WorldStateView, - ) -> Result<(), super::DenialReason> { - if authority.name.as_ref() == "alice" { - Err("Alice account is denied.".to_owned()) - } else { - Ok(()) - } - } - } - - struct GrantedToken; - - // TODO: ADD some Revoke tests. - - impl HasToken for GrantedToken { - fn token( - &self, - _authority: &AccountId, - _instruction: &Instruction, - _wsv: &WorldStateView, - ) -> Result { - Ok(PermissionToken::new( - Name::from_str("token").expect("Valid"), - )) - } - } - - fn asset_id( - asset_name: &str, - asset_domain: &str, - account_name: &str, - account_domain: &str, - ) -> IdBox { - IdBox::AssetId(AssetId::new( - AssetDefinitionId::new( - asset_name.parse().expect("Valid"), - asset_domain.parse().expect("Valid"), - ), - AccountId::new( - account_name.parse().expect("Valid"), - account_domain.parse().expect("Valid"), - ), - )) - } - - #[test] - pub fn multiple_validators_combined() { - let permissions_validator = ValidatorBuilder::new() - .with_validator(DenyBurn) - .with_validator(DenyAlice) - .all_should_succeed(); - let instruction_burn: Instruction = - BurnBox::new(Value::U32(10), asset_id("xor", "test", "alice", "test")).into(); - let instruction_fail = Instruction::Fail(FailBox { - message: "fail message".to_owned(), - }); - let account_bob = ::Id::from_str("bob@test").expect("Valid"); - let account_alice = ::Id::from_str("alice@test").expect("Valid"); - let wsv = WorldStateView::new(World::new()); - assert!(permissions_validator - .check(&account_bob, &instruction_burn, &wsv) - .is_err()); - assert!(permissions_validator - .check(&account_alice, &instruction_fail, &wsv) - .is_err()); - assert!(permissions_validator - .check(&account_alice, &instruction_burn, &wsv) - .is_err()); - assert!(permissions_validator - .check(&account_bob, &instruction_fail, &wsv) - .is_ok()); - } - - #[test] - pub fn recursive_validator() { - let permissions_validator = ValidatorBuilder::new() - .with_recursive_validator(DenyBurn) - .all_should_succeed(); - let instruction_burn: Instruction = - BurnBox::new(Value::U32(10), asset_id("xor", "test", "alice", "test")).into(); - let instruction_fail = Instruction::Fail(FailBox { - message: "fail message".to_owned(), - }); - let nested_instruction_sequence = - Instruction::If(If::new(true, instruction_burn.clone()).into()); - let account_alice = ::Id::from_str("alice@test").expect("Valid"); - let wsv = WorldStateView::new(World::new()); - assert!(permissions_validator - .check(&account_alice, &instruction_fail, &wsv) - .is_ok()); - assert!(permissions_validator - .check(&account_alice, &instruction_burn, &wsv) - .is_err()); - assert!(permissions_validator - .check(&account_alice, &nested_instruction_sequence, &wsv) - .is_err()); - } - - #[test] - pub fn granted_permission() -> Result<()> { - let alice_id = ::Id::from_str("alice@test")?; - let bob_id = ::Id::from_str("bob@test")?; - let alice_xor_id = ::Id::new( - AssetDefinitionId::from_str("xor#test").expect("Valid"), - AccountId::from_str("alice@test").expect("Valid"), - ); - let instruction_burn: Instruction = BurnBox::new(Value::U32(10), alice_xor_id).into(); - let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); - let mut bob_account = Account::new(bob_id.clone(), []).build(); - assert!(bob_account.add_permission(PermissionToken::new( - Name::from_str("token").expect("Valid") - ))); - assert!(domain.add_account(bob_account).is_none()); - let wsv = WorldStateView::new(World::with([domain], BTreeSet::new())); - let validator: HasTokenBoxed<_> = Box::new(GrantedToken); - assert!(validator.check(&alice_id, &instruction_burn, &wsv).is_err()); - assert!(validator.check(&bob_id, &instruction_burn, &wsv).is_ok()); - Ok(()) - } - - #[test] - pub fn check_query_permissions_nested() { - let instruction: Instruction = Pair::new( - TransferBox::new( - asset_id("btc", "crypto", "seller", "company"), - Expression::Add(Add::new( - Expression::Query( - FindAssetQuantityById::new(AssetId::new( - AssetDefinitionId::from_str("btc2eth_rate#exchange").expect("Valid"), - AccountId::from_str("dex@exchange").expect("Valid"), - )) - .into(), - ), - 10_u32, - )), - asset_id("btc", "crypto", "buyer", "company"), - ), - TransferBox::new( - asset_id("eth", "crypto", "buyer", "company"), - 15_u32, - asset_id("eth", "crypto", "seller", "company"), - ), - ) - .into(); - let wsv = WorldStateView::new(World::new()); - let alice_id = ::Id::from_str("alice@test").expect("Valid"); - assert!(check_query_in_instruction(&alice_id, &instruction, &wsv, &DenyAll.into()).is_err()) - } -} diff --git a/core/src/smartcontracts/isi/permissions/builder.rs b/core/src/smartcontracts/isi/permissions/builder.rs new file mode 100644 index 00000000000..2c8167fdbeb --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/builder.rs @@ -0,0 +1,136 @@ +//! This module contains validator builder to construct complex validator + +use super::{ + combinators::{AllShouldSucceed, AnyShouldSucceed, CheckNested}, + *, +}; + +/// Builder to combine multiple validation checks into one. +#[derive(Debug, Copy, Clone)] +pub struct Validator; + +/// Helper struct for [`Validator`]. +/// Makes sure there is at least one validator and all validators have the same type +#[derive(Debug)] +#[must_use] +pub struct WithValidators + Into> { + validators: Vec, + _phantom_operation: PhantomData, + _phantom_validator: PhantomData, +} + +/// Helper struct for [`Validator`]. +/// Contains final [`build()`] step +#[derive(Debug, Clone)] +#[must_use] +pub struct ShouldSucceedValidator< + O: NeedsPermission, + V: IsAllowed + Into, + S: TryInto, +> { + should_succeed: S, + _phantom_operation: PhantomData, + _phantom_validator: PhantomData, +} + +impl Validator { + /// Returns new [`ValidatorBuilderWithValidators`] with provided `validator` + pub fn with_validator(validator: impl Into) -> WithValidators + where + O: NeedsPermission, + V: IsAllowed + + Into + + TryFrom + + TryFrom, + E: Debug, + { + WithValidators::new(validator) + } + + /// Returns new [`ValidatorBuilderWithValidators`] + /// with provided recursive instruction `validator` + pub fn with_recursive_validator( + validator: impl Into, + ) -> WithValidators { + let instruction_validator: IsInstructionAllowedBoxed = + Box::new(CheckNested::new(validator.into())); + WithValidators::new(instruction_validator) + } +} + +#[allow(clippy::expect_used)] +impl WithValidators +where + O: NeedsPermission, + V: IsAllowed + + Into + + TryFrom + + TryFrom, + E: Debug, +{ + fn new(validator: impl Into) -> Self { + Self { + validators: vec![validator.into().into()], + _phantom_operation: PhantomData, + _phantom_validator: PhantomData, + } + } + + /// Adds a validator to the list. + pub fn with_validator(mut self, validator: impl Into) -> Self { + self.validators.push(validator.into().into()); + self + } + + /// Returns [`AllShouldSucceed`] *validator* builder + pub fn all_should_succeed(self) -> ShouldSucceedValidator { + let all_should_succeed = AllShouldSucceed::new(self.validators).expect( + "`ValidatorBuilder` guarantees that all validators have the same specified type", + ); + ShouldSucceedValidator::new(all_should_succeed) + } + + /// Returns [`AnyShouldSucceed`] *validator* builder + pub fn any_should_succeed( + self, + check_name: String, + ) -> ShouldSucceedValidator { + let any_should_succeed = AnyShouldSucceed::new(check_name, self.validators).expect( + "`ValidatorBuilder` guarantees that all validators have the same specified type", + ); + + ShouldSucceedValidator::new(any_should_succeed) + } +} + +impl WithValidators { + /// Adds a validator to the list and wraps it with `CheckNested` to check nested permissions. + pub fn with_recursive_validator(self, validator: impl Into) -> Self { + let instruction_validator: IsInstructionAllowedBoxed = + Box::new(CheckNested::new(validator.into())); + self.with_validator(instruction_validator) + } +} + +#[allow(clippy::expect_used)] +impl ShouldSucceedValidator +where + O: NeedsPermission, + V: IsAllowed + Into + TryFrom, + E: Debug, +{ + fn new(should_succeed: S) -> Self { + Self { + should_succeed, + _phantom_operation: PhantomData, + _phantom_validator: PhantomData, + } + } + + /// Builds *validator* + pub fn build(self) -> V { + self.should_succeed + .try_into() + .expect("`ValidatorBuilder` guarantees that there is at least one validator") + } +} diff --git a/core/src/smartcontracts/isi/permissions/checks.rs b/core/src/smartcontracts/isi/permissions/checks.rs new file mode 100644 index 00000000000..960040e7d3e --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/checks.rs @@ -0,0 +1,277 @@ +//! Contains functions to check permission + +use super::*; + +/// Verify that the given instruction is allowed to execute +/// +/// # Errors +/// +/// If given instruction is not permitted to execute +#[allow(clippy::expect_used)] +pub fn check_instruction_permissions( + account_id: &AccountId, + instruction: &Instruction, + is_instruction_allowed: &IsInstructionAllowedBoxed, + is_query_allowed: &IsQueryAllowedBoxed, + wsv: &WorldStateView, +) -> std::result::Result<(), TransactionRejectionReason> { + let granted_instructions = &super::roles::unpack_if_role_grant(instruction.clone(), wsv) + .expect("Infallible. Evaluations have been checked by instruction execution."); + check_permissions_directly( + account_id, + granted_instructions, + is_instruction_allowed, + wsv, + )?; + + let revoked_instructions = &super::roles::unpack_if_role_revoke(instruction.clone(), wsv) + .expect("Infallible. Evaluations have been checked by instruction execution."); + check_permissions_directly( + account_id, + revoked_instructions, + is_instruction_allowed, + wsv, + )?; + + check_query_in_instruction(account_id, instruction, wsv, is_query_allowed) + .map_err(|reason| NotPermittedFail { + reason: reason.to_string(), + }) + .map_err(TransactionRejectionReason::NotPermitted)?; + + Ok(()) +} + +fn check_permissions_directly( + account_id: &AccountId, + instructions: &[Instruction], + is_instruction_allowed: &IsInstructionAllowedBoxed, + wsv: &WorldStateView, +) -> std::result::Result<(), TransactionRejectionReason> { + for isi in instructions { + is_instruction_allowed + .check(account_id, isi, wsv) + .map_err(|reason| NotPermittedFail { + reason: reason.to_string(), + }) + .map_err(TransactionRejectionReason::NotPermitted)?; + } + Ok(()) +} + +/// Checks an expression recursively to evaluate if there is a query +/// inside of it and if the user has permission to execute this query. +/// +/// As the function is recursive, caution should be exercised to have +/// a limit of nestedness, that would not cause stack overflow. Up to +/// 2^13 calls were tested and are ok. This is within default +/// instruction limit. +/// +/// # Errors +/// If a user is not allowed to execute one of the inner queries, +/// given the current `validator`. +pub fn check_query_in_expression( + authority: &AccountId, + expression: &Expression, + wsv: &WorldStateView, + validator: &IsQueryAllowedBoxed, +) -> Result<()> { + macro_rules! check_binary_expression { + ($e:ident) => { + check_query_in_expression(authority, &($e).left.expression, wsv, validator).and( + check_query_in_expression(authority, &($e).right.expression, wsv, validator), + ) + }; + } + + match expression { + Expression::Add(expression) => check_binary_expression!(expression), + Expression::Subtract(expression) => check_binary_expression!(expression), + Expression::Multiply(expression) => check_binary_expression!(expression), + Expression::Divide(expression) => check_binary_expression!(expression), + Expression::Mod(expression) => check_binary_expression!(expression), + Expression::RaiseTo(expression) => check_binary_expression!(expression), + Expression::Greater(expression) => check_binary_expression!(expression), + Expression::Less(expression) => check_binary_expression!(expression), + Expression::Equal(expression) => check_binary_expression!(expression), + Expression::Not(expression) => { + check_query_in_expression(authority, &expression.expression.expression, wsv, validator) + } + Expression::And(expression) => check_binary_expression!(expression), + Expression::Or(expression) => check_binary_expression!(expression), + Expression::If(expression) => { + check_query_in_expression(authority, &expression.condition.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &expression.then_expression.expression, + wsv, + validator, + )) + .and(check_query_in_expression( + authority, + &expression.else_expression.expression, + wsv, + validator, + )) + } + Expression::Query(query) => validator.check(authority, query, wsv), + Expression::Contains(expression) => { + check_query_in_expression(authority, &expression.collection.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &expression.element.expression, + wsv, + validator, + )) + } + Expression::ContainsAll(expression) => { + check_query_in_expression(authority, &expression.collection.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &expression.elements.expression, + wsv, + validator, + )) + } + Expression::ContainsAny(expression) => { + check_query_in_expression(authority, &expression.collection.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &expression.elements.expression, + wsv, + validator, + )) + } + Expression::Where(expression) => { + check_query_in_expression(authority, &expression.expression.expression, wsv, validator) + } + Expression::ContextValue(_) | Expression::Raw(_) => Ok(()), + } +} + +/// Checks an instruction recursively to evaluate if there is a query +/// inside of it and if the user has permission to execute this query. +/// +/// As the function is recursive, caution should be exercised to have +/// a limit of nesting, that would not cause stack overflow. Up to +/// 2^13 calls were tested and are ok. This is within default +/// instruction limit. +/// +/// # Errors +/// If a user is not allowed to execute one of the inner queries, +/// given the current `validator`. +#[allow(clippy::too_many_lines)] +pub fn check_query_in_instruction( + authority: &AccountId, + instruction: &Instruction, + wsv: &WorldStateView, + validator: &IsQueryAllowedBoxed, +) -> Result<()> { + match instruction { + Instruction::Register(instruction) => { + check_query_in_expression(authority, &instruction.object.expression, wsv, validator) + } + Instruction::Unregister(instruction) => { + check_query_in_expression(authority, &instruction.object_id.expression, wsv, validator) + } + Instruction::Mint(instruction) => { + check_query_in_expression(authority, &instruction.object.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.destination_id.expression, + wsv, + validator, + )) + } + Instruction::Burn(instruction) => { + check_query_in_expression(authority, &instruction.object.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.destination_id.expression, + wsv, + validator, + )) + } + Instruction::Transfer(instruction) => { + check_query_in_expression(authority, &instruction.object.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.destination_id.expression, + wsv, + validator, + )) + .and(check_query_in_expression( + authority, + &instruction.source_id.expression, + wsv, + validator, + )) + } + Instruction::SetKeyValue(instruction) => { + check_query_in_expression(authority, &instruction.object_id.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.key.expression, + wsv, + validator, + )) + .and(check_query_in_expression( + authority, + &instruction.value.expression, + wsv, + validator, + )) + } + Instruction::RemoveKeyValue(instruction) => { + check_query_in_expression(authority, &instruction.object_id.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.key.expression, + wsv, + validator, + )) + } + Instruction::Grant(instruction) => { + check_query_in_expression(authority, &instruction.object.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.destination_id.expression, + wsv, + validator, + )) + } + Instruction::Revoke(instruction) => { + check_query_in_expression(authority, &instruction.object.expression, wsv, validator) + .and(check_query_in_expression( + authority, + &instruction.destination_id.expression, + wsv, + validator, + )) + } + Instruction::If(if_box) => { + check_query_in_instruction(authority, &if_box.then, wsv, validator).and_then(|_| { + match &if_box.otherwise { + Some(this_instruction) => { + check_query_in_instruction(authority, this_instruction, wsv, validator) + } + None => Ok(()), + } + }) + } + Instruction::Pair(pair_box) => { + check_query_in_instruction(authority, &pair_box.left_instruction, wsv, validator).and( + check_query_in_instruction(authority, &pair_box.right_instruction, wsv, validator), + ) + } + Instruction::Sequence(sequence_box) => { + sequence_box + .instructions + .iter() + .try_for_each(|this_instruction| { + check_query_in_instruction(authority, this_instruction, wsv, validator) + }) + } + Instruction::Fail(_) | Instruction::ExecuteTrigger(_) => Ok(()), + } +} diff --git a/core/src/smartcontracts/isi/permissions/combinators.rs b/core/src/smartcontracts/isi/permissions/combinators.rs new file mode 100644 index 00000000000..25587e25ea1 --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/combinators.rs @@ -0,0 +1,577 @@ +//! Module with combinators for permission validators + +use super::*; + +/// Checks if `validator` equals to `expected` +/// +/// # Errors +/// If `validator` doesn't equal to `expected` +pub fn check_equal( + validator: ValidatorType, + expected: ValidatorType, +) -> std::result::Result<(), ValidatorTypeMismatch> { + if validator != expected { + return Err(ValidatorTypeMismatch { + expected, + actual: validator, + }); + } + + Ok(()) +} + +/// Trait for joining validators with `or` method, auto-implemented +/// for all types which are convertible to a concrete type implementing [`IsAllowed`] +pub trait ValidatorApplyOr>: Into { + /// Combines two validators into [`Or`]. + /// + /// # Errors + /// If validators have different types + fn or(self, another: impl Into) -> Or; +} + +impl, I: Into> ValidatorApplyOr for I { + fn or(self, another: impl Into) -> Or { + Or::new(self, another) + } +} + +/// `check` succeeds if either `first` or `second` validator succeeds. +#[derive(Debug, Clone, Serialize)] +pub struct Or> { + first: V, + second: V, + #[serde(skip_serializing, default)] + _phantom_operation: PhantomData, +} + +impl> Or { + /// Constructs new [`Or`] + /// + /// # Errors + /// If validators have different types + pub fn new(first: impl Into, second: impl Into) -> Self { + Or { + first: first.into(), + second: second.into(), + _phantom_operation: PhantomData, + } + } +} + +impl IsAllowed for Or { + fn check( + &self, + authority: &AccountId, + operation: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + self.first + .check(authority, operation, wsv) + .or_else(|first_error| { + self.second + .check(authority, operation, wsv) + .map_err(|second_error| { + format!( + "Failed to pass first check with {} and second check with {}.", + first_error, second_error + ) + .into() + }) + }) + } +} + +impl From> for IsInstructionAllowedBoxed { + fn from(value: Or) -> Self { + Box::new(value) + } +} + +impl IsAllowed for Or { + fn check( + &self, + authority: &AccountId, + operation: &QueryBox, + wsv: &WorldStateView, + ) -> Result<()> { + self.first + .check(authority, operation, wsv) + .or_else(|first_error| { + self.second + .check(authority, operation, wsv) + .map_err(|second_error| { + format!( + "Failed to pass first check with {} and second check with {}.", + first_error, second_error + ) + .into() + }) + }) + } +} + +impl From> for IsQueryAllowedBoxed { + fn from(value: Or) -> Self { + Box::new(value) + } +} + +impl IsAllowed for Or { + fn check( + &self, + authority: &AccountId, + operation: &Expression, + wsv: &WorldStateView, + ) -> Result<()> { + self.first + .check(authority, operation, wsv) + .or_else(|first_error| { + self.second + .check(authority, operation, wsv) + .map_err(|second_error| { + format!( + "Failed to pass first check with {} and second check with {}.", + first_error, second_error + ) + .into() + }) + }) + } +} + +impl From> for IsExpressionAllowedBoxed { + fn from(value: Or) -> Self { + Box::new(value) + } +} + +/// Wraps validator to check nested permissions. Pay attention to +/// wrap only validators that do not check nested instructions by +/// themselves. +#[derive(Debug)] +pub struct CheckNested { + validator: IsInstructionAllowedBoxed, +} + +impl CheckNested { + /// Wraps `validator` to check nested permissions. + pub fn new(validator: IsInstructionAllowedBoxed) -> Self { + CheckNested { validator } + } +} + +impl IsAllowed for CheckNested { + fn check( + &self, + authority: &AccountId, + instruction: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + match instruction { + Instruction::Register(_) + | Instruction::Unregister(_) + | Instruction::Mint(_) + | Instruction::Burn(_) + | Instruction::SetKeyValue(_) + | Instruction::RemoveKeyValue(_) + | Instruction::Transfer(_) + | Instruction::Grant(_) + | Instruction::Revoke(_) + | Instruction::Fail(_) + | Instruction::ExecuteTrigger(_) => self.validator.check(authority, instruction, wsv), + Instruction::If(if_box) => { + self.check(authority, &if_box.then, wsv) + .and_then(|_| match &if_box.otherwise { + Some(this_instruction) => self.check(authority, this_instruction, wsv), + None => Ok(()), + }) + } + Instruction::Pair(pair_box) => self + .check(authority, &pair_box.left_instruction, wsv) + .and(self.check(authority, &pair_box.right_instruction, wsv)), + Instruction::Sequence(sequence_box) => sequence_box + .instructions + .iter() + .try_for_each(|this_instruction| self.check(authority, this_instruction, wsv)), + } + } +} + +fn check_all_validators_have_the_same_type(validators: &[IsAllowedBoxed]) -> Result<()> { + let first_type = if let Some(first) = validators.first() { + first.validator_type() + } else { + return Ok(()); + }; + + for validator in validators.iter().skip(1) { + let validator_type = validator.validator_type(); + if validator_type != first_type { + return Err(ValidatorTypeMismatch { + expected: first_type, + actual: validator_type, + } + .into()); + } + } + + Ok(()) +} + +/// A container for multiple permissions validators. It will succeed if all validators succeed. +#[derive(Debug)] +pub struct AllShouldSucceed { + validators: Vec, +} + +impl AllShouldSucceed { + /// Create new [`AllShouldSucceed`] + /// + /// # Errors + /// If provided validators have different types. + /// Type of the first element in the `validators` is considered exemplary + pub fn new(validators: Vec) -> Result { + check_all_validators_have_the_same_type(&validators)?; + Ok(Self { validators }) + } + + fn check_type(&self, validator_type: ValidatorType) -> Result<()> { + if let Ok(self_type) = self.validator_type() { + if self_type != validator_type { + return Err(ValidatorTypeMismatch { + expected: validator_type, + actual: self_type, + } + .into()); + } + } + + Ok(()) + } + + fn validator_type(&self) -> Result { + self.validators + .first() + .map_or(Err(DenialReason::NoValidatorsProvided), |first| { + Ok(first.validator_type()) + }) + } +} + +impl IsAllowed for AllShouldSucceed { + fn check( + &self, + authority: &AccountId, + operation: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + self.check_type(ValidatorType::Instruction)?; + + for validator in &self.validators { + validator.check(authority, operation, wsv)? + } + Ok(()) + } +} + +impl IsAllowed for AllShouldSucceed { + fn check( + &self, + authority: &AccountId, + operation: &QueryBox, + wsv: &WorldStateView, + ) -> Result<()> { + self.check_type(ValidatorType::Query)?; + + for validator in &self.validators { + validator.check(authority, operation, wsv)? + } + Ok(()) + } +} + +impl IsAllowed for AllShouldSucceed { + fn check( + &self, + authority: &AccountId, + operation: &Expression, + wsv: &WorldStateView, + ) -> Result<()> { + self.check_type(ValidatorType::Expression)?; + + for validator in &self.validators { + validator.check(authority, operation, wsv)? + } + Ok(()) + } +} + +impl TryFrom for IsAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AllShouldSucceed) -> std::result::Result { + match value.validator_type()? { + ValidatorType::Instruction => Ok(IsAllowedBoxed::Instruction(Box::new(value))), + ValidatorType::Query => Ok(IsAllowedBoxed::Query(Box::new(value))), + ValidatorType::Expression => Ok(IsAllowedBoxed::Expression(Box::new(value))), + } + } +} + +impl TryFrom for IsInstructionAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AllShouldSucceed) -> std::result::Result { + let validator_type = value.validator_type()?; + check_equal(validator_type, ValidatorType::Instruction)?; + + Ok(Box::new(value)) + } +} + +impl TryFrom for IsQueryAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AllShouldSucceed) -> std::result::Result { + let validator_type = value.validator_type()?; + check_equal(validator_type, ValidatorType::Query)?; + + Ok(Box::new(value)) + } +} + +impl TryFrom for IsExpressionAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AllShouldSucceed) -> std::result::Result { + let validator_type = value.validator_type()?; + check_equal(validator_type, ValidatorType::Expression)?; + + Ok(Box::new(value)) + } +} + +/// A container for multiple permissions validators. It will succeed if any validator succeeds. +#[derive(Debug)] +pub struct AnyShouldSucceed { + name: String, + validators: Vec, +} + +impl AnyShouldSucceed { + /// Creates new [`AnyShouldSucceed`] + /// + /// # Errors + /// If provided validators have different types. + /// Type of the first element in the `validators` is considered exemplary + pub fn new(name: String, validators: Vec) -> Result { + check_all_validators_have_the_same_type(&validators)?; + + Ok(Self { name, validators }) + } + + fn check_type(&self, validator_type: ValidatorType) -> Result<()> { + if let Ok(self_type) = self.validator_type() { + if self_type != validator_type { + return Err(ValidatorTypeMismatch { + expected: validator_type, + actual: self_type, + } + .into()); + } + } + + Ok(()) + } + + fn validator_type(&self) -> Result { + self.validators + .first() + .map_or(Err(DenialReason::NoValidatorsProvided), |first| { + Ok(first.validator_type()) + }) + } +} + +impl IsAllowed for AnyShouldSucceed { + fn check( + &self, + authority: &AccountId, + operation: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + self.check_type(ValidatorType::Instruction)?; + + for validator in &self.validators { + if validator.check(authority, operation, wsv).is_ok() { + return Ok(()); + } + } + Err(format!( + "None of the instructions succeeded in Any permission check block with name: {}", + self.name + ) + .into()) + } +} + +impl IsAllowed for AnyShouldSucceed { + fn check( + &self, + authority: &AccountId, + operation: &QueryBox, + wsv: &WorldStateView, + ) -> Result<()> { + self.check_type(ValidatorType::Query)?; + + for validator in &self.validators { + if validator.check(authority, operation, wsv).is_ok() { + return Ok(()); + } + } + Err(format!( + "None of the instructions succeeded in Any permission check block with name: {}", + self.name + ) + .into()) + } +} + +impl IsAllowed for AnyShouldSucceed { + fn check( + &self, + authority: &AccountId, + operation: &Expression, + wsv: &WorldStateView, + ) -> Result<()> { + self.check_type(ValidatorType::Expression)?; + + for validator in &self.validators { + if validator.check(authority, operation, wsv).is_ok() { + return Ok(()); + } + } + Err(format!( + "None of the instructions succeeded in Any permission check block with name: {}", + self.name + ) + .into()) + } +} + +impl TryFrom for IsAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AnyShouldSucceed) -> std::result::Result { + match value.validator_type()? { + ValidatorType::Instruction => Ok(IsAllowedBoxed::Instruction(Box::new(value))), + ValidatorType::Query => Ok(IsAllowedBoxed::Query(Box::new(value))), + ValidatorType::Expression => Ok(IsAllowedBoxed::Expression(Box::new(value))), + } + } +} + +impl TryFrom for IsInstructionAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AnyShouldSucceed) -> std::result::Result { + let validator_type = value.validator_type()?; + check_equal(validator_type, ValidatorType::Instruction)?; + + Ok(Box::new(value)) + } +} + +impl TryFrom for IsQueryAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AnyShouldSucceed) -> std::result::Result { + let validator_type = value.validator_type()?; + check_equal(validator_type, ValidatorType::Query)?; + + Ok(Box::new(value)) + } +} + +impl TryFrom for IsExpressionAllowedBoxed { + type Error = DenialReason; + + fn try_from(value: AnyShouldSucceed) -> std::result::Result { + let validator_type = value.validator_type()?; + check_equal(validator_type, ValidatorType::Expression)?; + + Ok(Box::new(value)) + } +} + +/// Allows all operations to be executed for all possible values. Mostly for tests and simple cases. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Deserialize, Serialize)] +pub struct AllowAll; + +impl AllowAll { + /// Construct permission which allows all items + #[allow(clippy::new_ret_no_self)] + pub fn new() -> Arc + where + Self: Into, + { + Arc::new(Self.into()) + } +} + +/// Disallows all operations to be executed for all possible +/// values. Mostly for tests and simple cases. +#[derive(Debug, Clone, Copy, Serialize)] +pub struct DenyAll; + +impl DenyAll { + /// Construct permission which denies all items + #[allow(clippy::new_ret_no_self)] + pub fn new() -> Arc + where + Self: Into, + { + Arc::new(Self.into()) + } +} + +/// Generate [`From`] implementations from type implementing [`IsAllowed`] to boxed types like: +/// [`IsInstructionAllowedBoxed`], [`IsQueryAllowedBoxed`] and [`IsExpressionAllowedBoxed`] +/// +/// See usage below +macro_rules! impl_from_for_allowed_boxed { + ($($t:ty => $b:ty),+ $(,)?) => { + $( + impl From<$t> for $b { + fn from(value: $t) -> Self { + Box::new(value) + } + } + )+ + }; +} + +impl IsAllowed for AllowAll { + fn check(&self, _authority: &AccountId, _instruction: &O, _wsv: &WorldStateView) -> Result<()> { + Ok(()) + } +} + +impl_from_for_allowed_boxed! { + AllowAll => IsInstructionAllowedBoxed, + AllowAll => IsQueryAllowedBoxed, + AllowAll => IsExpressionAllowedBoxed, +} + +impl IsAllowed for DenyAll { + fn check(&self, _authority: &AccountId, _instruction: &O, _wsv: &WorldStateView) -> Result<()> { + Err("All operations are denied.".to_owned().into()) + } +} + +impl_from_for_allowed_boxed! { + DenyAll => IsInstructionAllowedBoxed, + DenyAll => IsQueryAllowedBoxed, + DenyAll => IsExpressionAllowedBoxed, +} diff --git a/core/src/smartcontracts/isi/permissions/has_token.rs b/core/src/smartcontracts/isi/permissions/has_token.rs new file mode 100644 index 00000000000..37e42ecb8d3 --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/has_token.rs @@ -0,0 +1,52 @@ +//! Contains [`HasToken`] trait and box container for it + +use super::*; + +/// Boxed validator implementing [`HasToken`] validator trait. +pub type HasTokenBoxed = Box; + +/// Trait that should be implemented by validator that checks the need to have permission token for a certain action. +pub trait HasToken: Debug { + /// This function should return the token that `authority` should + /// possess, given the `instruction` they are planning to execute + /// on the current state of `wsv` + /// + /// # Errors + /// + /// In the case when it is impossible to deduce the required token + /// given current data (e.g. non-existent account or inapplicable + /// instruction). + fn token( + &self, + authority: &AccountId, + instruction: &Instruction, + wsv: &WorldStateView, + ) -> std::result::Result; +} + +impl IsAllowed for HasTokenBoxed { + fn check( + &self, + authority: &AccountId, + instruction: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + let permission_token = self + .token(authority, instruction, wsv) + .map_err(|err| format!("Unable to identify corresponding permission token: {}", err))?; + let contain = wsv + .map_account(authority, |account| { + account.contains_permission(&permission_token) + }) + .map_err(|e| e.to_string())?; + if contain { + Ok(()) + } else { + Err(format!( + "Account does not have the needed permission token: {:?}.", + permission_token + ) + .into()) + } + } +} diff --git a/core/src/smartcontracts/isi/permissions/is_allowed.rs b/core/src/smartcontracts/isi/permissions/is_allowed.rs new file mode 100644 index 00000000000..80406729b35 --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/is_allowed.rs @@ -0,0 +1,108 @@ +//! Module with [`IsAllowed`] trait and boxed containers + +use super::*; + +/// Implement this to provide custom permission checks for the Iroha based blockchain. +pub trait IsAllowed: Debug { + /// Checks if the `authority` is allowed to perform `instruction` + /// given the current state of `wsv`. + /// + /// # Errors + /// If the execution of `instruction` under given `authority` with + /// the current state of `wsv` is disallowed. + fn check(&self, authority: &AccountId, operation: &O, wsv: &WorldStateView) -> Result<()>; +} + +/// Box with permissions validator. +#[derive(Debug, FromVariant)] +pub enum IsAllowedBoxed { + /// [`Instruction`] validator + Instruction(IsInstructionAllowedBoxed), + /// [`QueryBox`] validator + Query(IsQueryAllowedBoxed), + /// [`Expression`] validator + Expression(IsExpressionAllowedBoxed), +} + +impl IsAllowedBoxed { + /// Get type of validator inside [`IsAllowedBoxed`] + pub fn validator_type(&self) -> ValidatorType { + match self { + IsAllowedBoxed::Instruction(_) => ValidatorType::Instruction, + IsAllowedBoxed::Query(_) => ValidatorType::Query, + IsAllowedBoxed::Expression(_) => ValidatorType::Expression, + } + } +} + +impl IsAllowed for IsAllowedBoxed { + fn check( + &self, + authority: &AccountId, + operation: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + if let IsAllowedBoxed::Instruction(instruction) = self { + instruction.check(authority, operation, wsv) + } else { + Err(ValidatorTypeMismatch { + expected: ValidatorType::Instruction, + actual: self.validator_type(), + } + .into()) + } + } +} + +impl IsAllowed for IsAllowedBoxed { + fn check( + &self, + authority: &AccountId, + operation: &QueryBox, + wsv: &WorldStateView, + ) -> Result<()> { + if let IsAllowedBoxed::Query(query) = self { + query.check(authority, operation, wsv) + } else { + Err(ValidatorTypeMismatch { + expected: ValidatorType::Query, + actual: self.validator_type(), + } + .into()) + } + } +} + +impl IsAllowed for IsAllowedBoxed { + fn check( + &self, + authority: &AccountId, + operation: &Expression, + wsv: &WorldStateView, + ) -> Result<()> { + if let IsAllowedBoxed::Expression(expression) = self { + expression.check(authority, operation, wsv) + } else { + Err(ValidatorTypeMismatch { + expected: ValidatorType::Expression, + actual: self.validator_type(), + } + .into()) + } + } +} + +impl IsAllowed for Box + Send + Sync> { + fn check(&self, authority: &AccountId, operation: &O, wsv: &WorldStateView) -> Result<()> { + IsAllowed::check(self.as_ref(), authority, operation, wsv) + } +} + +/// Box with permissions validator for [`Instruction`]. +pub type IsInstructionAllowedBoxed = Box + Send + Sync>; + +/// Box with permissions validator for [`QueryBox`]. +pub type IsQueryAllowedBoxed = Box + Send + Sync>; + +/// Box with permissions validator for [`Expression`]. +pub type IsExpressionAllowedBoxed = Box + Send + Sync>; diff --git a/core/src/smartcontracts/isi/permissions/mod.rs b/core/src/smartcontracts/isi/permissions/mod.rs new file mode 100644 index 00000000000..7154f70d7d4 --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/mod.rs @@ -0,0 +1,305 @@ +#![allow(clippy::module_name_repetitions)] + +//! This module contains permissions related Iroha functionality. + +use std::{fmt::Debug, marker::PhantomData, sync::Arc}; + +pub use checks::*; +pub use combinators::ValidatorApplyOr as _; +use error::*; +pub use has_token::*; +use iroha_data_model::prelude::*; +use iroha_macro::FromVariant; +use iroha_schema::IntoSchema; +pub use is_allowed::*; +use parity_scale_codec::{Decode, Encode}; +use serde::{Deserialize, Serialize}; + +use crate::wsv::WorldStateView; + +pub mod builder; +mod checks; +pub mod combinators; +mod has_token; +mod is_allowed; +pub mod roles; + +/// Result type for permission validators +pub type Result = std::result::Result; + +/// Operation for which the permission should be checked. +pub trait NeedsPermission: Debug {} + +impl NeedsPermission for Instruction {} + +impl NeedsPermission for QueryBox {} + +// Expression might contain a query, therefore needs to be checked. +impl NeedsPermission for Expression {} + +/// Type of object validator can check +#[derive(Debug, Copy, Clone, PartialEq, Eq, derive_more::Display, Encode, Decode, IntoSchema)] +pub enum ValidatorType { + /// [`Instruction`] variant + Instruction, + /// [`QueryBox`] variant + Query, + /// [`Expression`] variant + Expression, +} +pub mod error { + //! Contains errors structures + + use std::{convert::Infallible, str::FromStr}; + + use super::{Decode, Encode, IntoSchema, ValidatorType}; + use crate::smartcontracts::Mismatch; + + /// Wrong validator expectation error + /// + /// I.e. used when user tries to validate [`QueryBox`](super::QueryBox) with + /// [`IsAllowedBoxed`](super::IsAllowedBoxed) containing + /// [`IsAllowedBoxed::Instruction`](super::IsAllowedBoxed::Instruction) variant + pub type ValidatorTypeMismatch = Mismatch; + + /// Reason for prohibiting the execution of the particular instruction. + #[derive(Debug, Clone, thiserror::Error, Decode, Encode, IntoSchema)] + #[allow(variant_size_differences)] + pub enum DenialReason { + /// [`ValidatorTypeMismatch`] variant + #[error("Wrong validator type: {0}")] + ValidatorTypeMismatch(#[from] ValidatorTypeMismatch), + /// Variant for custom error + #[error("{0}")] + Custom(String), + /// Variant used when at least one [`Validator`](super::IsAllowed) should be provided + #[error("No validators provided")] + NoValidatorsProvided, + } + + impl From for DenialReason { + fn from(s: String) -> Self { + Self::Custom(s) + } + } + + impl FromStr for DenialReason { + type Err = Infallible; + + fn from_str(s: &str) -> Result { + Ok(Self::Custom(s.to_owned())) + } + } +} + +pub mod prelude { + //! Exports common types for permissions. + + pub use super::{ + builder::Validator as ValidatorBuilder, + combinators::{AllowAll, ValidatorApplyOr as _}, + error::DenialReason, + roles::{IsGrantAllowed, IsGrantAllowedBoxed, IsRevokeAllowed, IsRevokeAllowedBoxed}, + HasTokenBoxed, IsAllowedBoxed, + }; +} + +#[cfg(test)] +mod tests { + #![allow(clippy::restriction)] + + use std::{collections::BTreeSet, str::FromStr as _}; + + use iroha_data_model::{expression::prelude::*, isi::*}; + + use super::{builder::Validator as ValidatorBuilder, combinators::DenyAll, *}; + use crate::wsv::World; + + #[derive(Debug, Clone, Serialize)] + struct DenyBurn; + + impl From for IsInstructionAllowedBoxed { + fn from(permissions: DenyBurn) -> Self { + Box::new(permissions) + } + } + + impl IsAllowed for DenyBurn { + fn check( + &self, + _authority: &AccountId, + instruction: &Instruction, + _wsv: &WorldStateView, + ) -> Result<()> { + match instruction { + Instruction::Burn(_) => Err("Denying sequence isi.".to_owned().into()), + _ => Ok(()), + } + } + } + + #[derive(Debug, Clone, Serialize)] + struct DenyAlice; + + impl IsAllowed for DenyAlice { + fn check( + &self, + authority: &AccountId, + _instruction: &Instruction, + _wsv: &WorldStateView, + ) -> Result<()> { + if authority.name.as_ref() == "alice" { + Err("Alice account is denied.".to_owned().into()) + } else { + Ok(()) + } + } + } + + impl From for IsInstructionAllowedBoxed { + fn from(value: DenyAlice) -> Self { + Box::new(value) + } + } + + #[derive(Debug, Clone, Serialize)] + struct GrantedToken; + + // TODO: ADD some Revoke tests. + + impl HasToken for GrantedToken { + fn token( + &self, + _authority: &AccountId, + _instruction: &Instruction, + _wsv: &WorldStateView, + ) -> std::result::Result { + Ok(PermissionToken::new( + Name::from_str("token").expect("Valid"), + )) + } + } + + fn asset_id( + asset_name: &str, + asset_domain: &str, + account_name: &str, + account_domain: &str, + ) -> IdBox { + IdBox::AssetId(AssetId::new( + AssetDefinitionId::new( + asset_name.parse().expect("Valid"), + asset_domain.parse().expect("Valid"), + ), + AccountId::new( + account_name.parse().expect("Valid"), + account_domain.parse().expect("Valid"), + ), + )) + } + + #[test] + pub fn multiple_validators_combined() { + let permissions_validator: IsInstructionAllowedBoxed = + ValidatorBuilder::with_validator(DenyBurn) + .with_validator(DenyAlice) + .all_should_succeed() + .build(); + let instruction_burn: Instruction = + BurnBox::new(Value::U32(10), asset_id("xor", "test", "alice", "test")).into(); + let instruction_fail = Instruction::Fail(FailBox { + message: "fail message".to_owned(), + }); + let account_bob = ::Id::from_str("bob@test").expect("Valid"); + let account_alice = ::Id::from_str("alice@test").expect("Valid"); + let wsv = WorldStateView::new(World::new()); + assert!(permissions_validator + .check(&account_bob, &instruction_burn, &wsv) + .is_err()); + assert!(permissions_validator + .check(&account_alice, &instruction_fail, &wsv) + .is_err()); + assert!(permissions_validator + .check(&account_alice, &instruction_burn, &wsv) + .is_err()); + assert!(permissions_validator + .check(&account_bob, &instruction_fail, &wsv) + .is_ok()); + } + + #[test] + pub fn recursive_validator() { + let permissions_validator = ValidatorBuilder::with_recursive_validator(DenyBurn) + .all_should_succeed() + .build(); + let instruction_burn: Instruction = + BurnBox::new(Value::U32(10), asset_id("xor", "test", "alice", "test")).into(); + let instruction_fail = Instruction::Fail(FailBox { + message: "fail message".to_owned(), + }); + let nested_instruction_sequence = + Instruction::If(If::new(true, instruction_burn.clone()).into()); + let account_alice = ::Id::from_str("alice@test").expect("Valid"); + let wsv = WorldStateView::new(World::new()); + assert!(permissions_validator + .check(&account_alice, &instruction_fail, &wsv) + .is_ok()); + assert!(permissions_validator + .check(&account_alice, &instruction_burn, &wsv) + .is_err()); + assert!(permissions_validator + .check(&account_alice, &nested_instruction_sequence, &wsv) + .is_err()); + } + + #[test] + pub fn granted_permission() -> eyre::Result<()> { + let alice_id = ::Id::from_str("alice@test")?; + let bob_id = ::Id::from_str("bob@test")?; + let alice_xor_id = ::Id::new( + AssetDefinitionId::from_str("xor#test").expect("Valid"), + AccountId::from_str("alice@test").expect("Valid"), + ); + let instruction_burn: Instruction = BurnBox::new(Value::U32(10), alice_xor_id).into(); + let mut domain = Domain::new(DomainId::from_str("test").expect("Valid")).build(); + let mut bob_account = Account::new(bob_id.clone(), []).build(); + assert!(bob_account.add_permission(PermissionToken::new( + Name::from_str("token").expect("Valid") + ))); + assert!(domain.add_account(bob_account).is_none()); + let wsv = WorldStateView::new(World::with([domain], BTreeSet::new())); + let validator: HasTokenBoxed = Box::new(GrantedToken); + assert!(validator.check(&alice_id, &instruction_burn, &wsv).is_err()); + assert!(validator.check(&bob_id, &instruction_burn, &wsv).is_ok()); + Ok(()) + } + + #[test] + pub fn check_query_permissions_nested() { + let instruction: Instruction = Pair::new( + TransferBox::new( + asset_id("btc", "crypto", "seller", "company"), + Expression::Add(Add::new( + Expression::Query( + FindAssetQuantityById::new(AssetId::new( + AssetDefinitionId::from_str("btc2eth_rate#exchange").expect("Valid"), + AccountId::from_str("dex@exchange").expect("Valid"), + )) + .into(), + ), + 10_u32, + )), + asset_id("btc", "crypto", "buyer", "company"), + ), + TransferBox::new( + asset_id("eth", "crypto", "buyer", "company"), + 15_u32, + asset_id("eth", "crypto", "seller", "company"), + ), + ) + .into(); + let wsv = WorldStateView::new(World::new()); + let alice_id = ::Id::from_str("alice@test").expect("Valid"); + assert!(check_query_in_instruction(&alice_id, &instruction, &wsv, &DenyAll.into()).is_err()) + } +} diff --git a/core/src/smartcontracts/isi/permissions/roles.rs b/core/src/smartcontracts/isi/permissions/roles.rs new file mode 100644 index 00000000000..4bb8ed3296f --- /dev/null +++ b/core/src/smartcontracts/isi/permissions/roles.rs @@ -0,0 +1,159 @@ +//! Contains traits and function related to roles permission checking + +use super::{super::Evaluate, *}; + +// TODO: rewrite when specialization reaches stable +// Currently we simply can't do the following: +// impl PermissionsValidator for T {} +// when we have +// impl PermissionsValidator for T {} +/// Boxed validator implementing [`IsGrantAllowed`] trait. +pub type IsGrantAllowedBoxed = Box; + +/// Checks the [`GrantBox`] instruction. +pub trait IsGrantAllowed: Debug { + /// Checks the [`GrantBox`] instruction. + /// + /// # Errors + /// If this validator doesn't approve this Grant instruction. + fn check( + &self, + authority: &AccountId, + instruction: &GrantBox, + wsv: &WorldStateView, + ) -> Result<()>; +} + +impl IsGrantAllowed for IsGrantAllowedBoxed { + fn check( + &self, + authority: &AccountId, + instruction: &GrantBox, + wsv: &WorldStateView, + ) -> Result<()> { + IsGrantAllowed::check(self.as_ref(), authority, instruction, wsv) + } +} + +/// Boxed validator implementing the [`IsRevokeAllowed`] trait. +pub type IsRevokeAllowedBoxed = Box; + +/// Checks the [`RevokeBox`] instruction. +pub trait IsRevokeAllowed: Debug { + /// Checks the [`RevokeBox`] instruction. + /// + /// # Errors + /// If this validator doesn't approve this Revoke instruction. + fn check( + &self, + authority: &AccountId, + instruction: &RevokeBox, + wsv: &WorldStateView, + ) -> Result<()>; +} + +impl IsRevokeAllowed for IsRevokeAllowedBoxed { + fn check( + &self, + authority: &AccountId, + instruction: &RevokeBox, + wsv: &WorldStateView, + ) -> Result<()> { + IsRevokeAllowed::check(self.as_ref(), authority, instruction, wsv) + } +} + +impl IsAllowed for IsGrantAllowedBoxed { + fn check( + &self, + authority: &AccountId, + instruction: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + if let Instruction::Grant(isi) = instruction { + ::check(self, authority, isi, wsv) + } else { + Ok(()) + } + } +} + +impl IsAllowed for IsRevokeAllowedBoxed { + fn check( + &self, + authority: &AccountId, + instruction: &Instruction, + wsv: &WorldStateView, + ) -> Result<()> { + if let Instruction::Revoke(isi) = instruction { + ::check(self, authority, isi, wsv) + } else { + Ok(()) + } + } +} + +/// Used in `unpack_` function below +macro_rules! unpack { + ($i:ident, $w:ident, Instruction::$v:ident => $t:ty) => {{ + let operation = if let Instruction::$v(operation) = &$i { + operation + } else { + return Ok(vec![$i]); + }; + let id = + if let Value::Id(IdBox::RoleId(id)) = operation.object.evaluate($w, &Context::new())? { + id + } else { + return Ok(vec![$i]); + }; + + let instructions = if let Some(role) = $w.world.roles.get(&id) { + let destination_id = operation.destination_id.evaluate($w, &Context::new())?; + role.permissions() + .cloned() + .map(|permission_token| <$t>::new(permission_token, destination_id.clone()).into()) + .collect() + } else { + Vec::new() + }; + Ok(instructions) + }}; +} + +/// Unpacks instruction if it is Grant of a Role into several Grants +/// fo Permission Token. If instruction is not Grant of Role, returns +/// it as inly instruction inside the vec. Should be called before +/// permission checks by validators. +/// +/// Semantically means that user can grant a role only if they can +/// grant each of the permission tokens that the role consists of. +/// +/// # Errors +/// Evaluation failure of instruction fields. +pub fn unpack_if_role_grant( + instruction: Instruction, + wsv: &WorldStateView, +) -> eyre::Result> { + unpack!(instruction, wsv, Instruction::Grant => GrantBox) +} + +/// Unpack instruction if it is a Revoke of a Role, into several +/// Revocations of Permission Tokens. If the instruction is not a +/// Revoke of Role, returns it as an internal instruction inside the +/// vec. +/// +/// This `fn` should be called before permission checks (by +/// validators). +/// +/// Semantically: the user can revoke a role only if they can revoke +/// each of the permission tokens that the role consists of of. +/// +/// # Errors +/// Evaluation failure of each of the instruction fields. +pub fn unpack_if_role_revoke( + instruction: Instruction, + wsv: &WorldStateView, +) -> eyre::Result> { + unpack!(instruction, wsv, Instruction::Revoke => RevokeBox) +} diff --git a/core/src/smartcontracts/isi/query.rs b/core/src/smartcontracts/isi/query.rs index 29ddbef5573..953a0141747 100644 --- a/core/src/smartcontracts/isi/query.rs +++ b/core/src/smartcontracts/isi/query.rs @@ -7,8 +7,8 @@ use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; use thiserror::Error; -use super::FindError; -use crate::{prelude::ValidQuery, WorldStateView, WorldTrait}; +use super::{permissions::prelude::DenialReason, FindError}; +use crate::{prelude::ValidQuery, WorldStateView}; /// Query Request statefully validated on the Iroha node side. #[derive(Debug, Decode, Encode)] @@ -22,7 +22,7 @@ impl ValidQueryRequest { /// # Errors /// Forwards `self.query.execute` error. #[inline] - pub fn execute(&self, wsv: &WorldStateView) -> Result { + pub fn execute(&self, wsv: &WorldStateView) -> Result { self.query.execute(wsv) } @@ -44,7 +44,7 @@ pub enum Error { Signature(String), /// Query is not allowed. #[error("Query is not allowed: {0}")] - Permission(String), + Permission(DenialReason), /// Query has wrong expression. #[error("Query has a malformed expression: {0}")] Evaluate(String), @@ -62,8 +62,8 @@ impl From for Error { } } -impl ValidQuery for QueryBox { - fn execute(&self, wsv: &WorldStateView) -> Result { +impl ValidQuery for QueryBox { + fn execute(&self, wsv: &WorldStateView) -> Result { use QueryBox::*; match self { diff --git a/core/src/smartcontracts/isi/triggers.rs b/core/src/smartcontracts/isi/triggers.rs index e68e3af4fcb..283c3a1d292 100644 --- a/core/src/smartcontracts/isi/triggers.rs +++ b/core/src/smartcontracts/isi/triggers.rs @@ -14,7 +14,7 @@ pub mod isi { use super::{super::prelude::*, *}; - impl Execute for Register> { + impl Execute for Register> { type Error = Error; #[metrics(+"register_trigger")] @@ -22,7 +22,7 @@ pub mod isi { fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let new_trigger = self.object; @@ -71,14 +71,14 @@ pub mod isi { } } - impl Execute for Unregister> { + impl Execute for Unregister> { type Error = Error; #[metrics(+"unregister_trigger")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let trigger_id = self.object_id.clone(); wsv.modify_triggers(|triggers| { @@ -94,14 +94,14 @@ pub mod isi { } } - impl Execute for Mint, u32> { + impl Execute for Mint, u32> { type Error = Error; #[metrics(+"mint_trigger_repetitions")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let id = self.destination_id; @@ -125,14 +125,14 @@ pub mod isi { } } - impl Execute for Burn, u32> { + impl Execute for Burn, u32> { type Error = Error; #[metrics(+"burn_trigger_repetitions")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let trigger = self.destination_id; wsv.modify_triggers(|triggers| { @@ -147,14 +147,14 @@ pub mod isi { } } - impl Execute for ExecuteTriggerBox { + impl Execute for ExecuteTriggerBox { type Error = Error; #[metrics(+"execute_trigger")] fn execute( self, authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { wsv.execute_trigger(self.trigger_id, authority); Ok(()) @@ -168,19 +168,19 @@ pub mod query { use super::*; use crate::{ prelude::*, - smartcontracts::{isi::prelude::WorldTrait, query::Error, Evaluate as _, FindError}, + smartcontracts::{query::Error, Evaluate as _, FindError}, }; - impl ValidQuery for FindAllActiveTriggerIds { + impl ValidQuery for FindAllActiveTriggerIds { #[metrics(+"find_all_active_triggers")] - fn execute(&self, wsv: &WorldStateView) -> Result { - Ok(wsv.world.triggers.clone().ids()) + fn execute(&self, wsv: &WorldStateView) -> Result { + Ok(wsv.world.triggers.ids()) } } - impl ValidQuery for FindTriggerById { + impl ValidQuery for FindTriggerById { #[metrics(+"find_trigger_by_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::new()) @@ -199,9 +199,9 @@ pub mod query { } } - impl ValidQuery for FindTriggerKeyValueByIdAndKey { + impl ValidQuery for FindTriggerKeyValueByIdAndKey { #[metrics(+"find_trigger_key_value_by_id_and_key")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .id .evaluate(wsv, &Context::new()) @@ -224,9 +224,9 @@ pub mod query { } } - impl ValidQuery for FindTriggersByDomainId { + impl ValidQuery for FindTriggersByDomainId { #[metrics(+"find_triggers_by_domain_id")] - fn execute(&self, _wsv: &WorldStateView) -> eyre::Result { + fn execute(&self, _wsv: &WorldStateView) -> eyre::Result { iroha_logger::warn!("'find triggers by domain id' is implemented as a stub."); Ok(vec![]) } diff --git a/core/src/smartcontracts/isi/tx.rs b/core/src/smartcontracts/isi/tx.rs index 0c607f0a408..21629d04f75 100644 --- a/core/src/smartcontracts/isi/tx.rs +++ b/core/src/smartcontracts/isi/tx.rs @@ -6,18 +6,18 @@ use iroha_telemetry::metrics; use super::*; -impl ValidQuery for FindAllTransactions { +impl ValidQuery for FindAllTransactions { #[metrics(+"find_all_transactions")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let mut txs = wsv.transaction_values(); txs.reverse(); Ok(txs) } } -impl ValidQuery for FindTransactionsByAccountId { +impl ValidQuery for FindTransactionsByAccountId { #[metrics(+"find_transactions_by_account_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let id = self .account_id .evaluate(wsv, &Context::default()) @@ -28,9 +28,9 @@ impl ValidQuery for FindTransactionsByAccountId { } } -impl ValidQuery for FindTransactionByHash { +impl ValidQuery for FindTransactionByHash { #[metrics(+"find_transaction_by_hash")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let hash = self .hash .evaluate(wsv, &Context::default()) diff --git a/core/src/smartcontracts/isi/world.rs b/core/src/smartcontracts/isi/world.rs index 3c0a6a70261..007f3eddcd5 100644 --- a/core/src/smartcontracts/isi/world.rs +++ b/core/src/smartcontracts/isi/world.rs @@ -12,14 +12,14 @@ pub mod isi { use super::*; - impl Execute for Register { + impl Execute for Register { type Error = Error; #[metrics(+"register_peer")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let peer_id = self.object.id; @@ -36,14 +36,14 @@ pub mod isi { } } - impl Execute for Unregister { + impl Execute for Unregister { type Error = Error; #[metrics(+"unregister_peer")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let peer_id = self.object_id; wsv.modify_world(|world| { @@ -56,14 +56,14 @@ pub mod isi { } } - impl Execute for Register { + impl Execute for Register { type Error = Error; #[metrics("register_domain")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let domain: Domain = self.object.build(); let domain_id = domain.id().clone(); @@ -90,14 +90,14 @@ pub mod isi { } } - impl Execute for Unregister { + impl Execute for Unregister { type Error = Error; #[metrics("unregister_domain")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let domain_id = self.object_id; @@ -114,14 +114,14 @@ pub mod isi { } } - impl Execute for Register { + impl Execute for Register { type Error = Error; #[metrics(+"register_role")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let role = self.object; @@ -141,14 +141,14 @@ pub mod isi { } } - impl Execute for Unregister { + impl Execute for Unregister { type Error = Error; #[metrics("unregister_role")] fn execute( self, _authority: ::Id, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), Self::Error> { let role_id = self.object_id; @@ -194,9 +194,9 @@ pub mod query { use super::*; use crate::smartcontracts::query::Error; - impl ValidQuery for FindAllRoles { + impl ValidQuery for FindAllRoles { #[metrics(+"find_all_roles")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { Ok(wsv .world .roles @@ -206,9 +206,9 @@ pub mod query { } } - impl ValidQuery for FindAllRoleIds { + impl ValidQuery for FindAllRoleIds { #[metrics(+"find_all_role_ids")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { Ok(wsv .world .roles @@ -219,9 +219,9 @@ pub mod query { } } - impl ValidQuery for FindRoleByRoleId { + impl ValidQuery for FindRoleByRoleId { #[metrics(+"find_role_by_role_id")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { let role_id = self .id .evaluate(wsv, &Context::new()) @@ -235,9 +235,9 @@ pub mod query { } } - impl ValidQuery for FindAllPeers { + impl ValidQuery for FindAllPeers { #[metrics("find_all_peers")] - fn execute(&self, wsv: &WorldStateView) -> Result { + fn execute(&self, wsv: &WorldStateView) -> Result { Ok(wsv.peers()) } } diff --git a/core/src/smartcontracts/mod.rs b/core/src/smartcontracts/mod.rs index 0ca40feb06c..2e3c0e77e8f 100644 --- a/core/src/smartcontracts/mod.rs +++ b/core/src/smartcontracts/mod.rs @@ -10,10 +10,10 @@ pub mod wasm; use iroha_data_model::prelude::*; pub use isi::*; -use crate::wsv::{WorldStateView, WorldTrait}; +use crate::wsv::WorldStateView; /// Trait implementations should provide actions to apply changes on [`WorldStateView`]. -pub trait Execute { +pub trait Execute { /// Error type returned by execute function type Error: std::error::Error; @@ -21,11 +21,11 @@ pub trait Execute { /// /// # Errors /// Concrete to each implementer. - fn execute(self, authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error>; + fn execute(self, authority: AccountId, wsv: &WorldStateView) -> Result<(), Self::Error>; } /// Calculate the result of the expression without mutating the state. -pub trait Evaluate { +pub trait Evaluate { /// The resulting type of the expression. type Value; /// Error type returned if the evaluation fails. Typically just [`isi::error::Error`]. @@ -35,15 +35,12 @@ pub trait Evaluate { /// /// # Errors /// Concrete to each implementer. - fn evaluate( - &self, - wsv: &WorldStateView, - context: &Context, - ) -> Result; + fn evaluate(&self, wsv: &WorldStateView, context: &Context) + -> Result; } /// This trait should be implemented for all Iroha Queries. -pub trait ValidQuery: Query { +pub trait ValidQuery: Query { /// Execute query on the [`WorldStateView`]. /// Should not mutate [`WorldStateView`]! /// @@ -51,13 +48,13 @@ pub trait ValidQuery: Query { /// /// # Errors /// Concrete to each implementer - fn execute(&self, wsv: &WorldStateView) -> eyre::Result; + fn execute(&self, wsv: &WorldStateView) -> eyre::Result; /// Executes query and maps it into value /// /// # Errors /// Concrete to each implementer - fn execute_into_value(&self, wsv: &WorldStateView) -> eyre::Result { + fn execute_into_value(&self, wsv: &WorldStateView) -> eyre::Result { self.execute(wsv).map(Into::into) } } diff --git a/core/src/smartcontracts/wasm.rs b/core/src/smartcontracts/wasm.rs index 5e36bab9203..94cda7b3587 100644 --- a/core/src/smartcontracts/wasm.rs +++ b/core/src/smartcontracts/wasm.rs @@ -14,13 +14,13 @@ use wasmtime::{ Caller, Config, Engine, Linker, Module, Store, StoreLimits, StoreLimitsBuilder, Trap, TypedFunc, }; -use super::permissions::IsInstructionAllowedBoxed; +use super::permissions::{IsAllowed as _, IsInstructionAllowedBoxed}; use crate::{ smartcontracts::{ permissions::{check_instruction_permissions, IsQueryAllowedBoxed}, Execute, ValidQuery, }, - wsv::{WorldStateView, WorldTrait}, + wsv::WorldStateView, }; type WasmUsize = u32; @@ -70,20 +70,20 @@ impl From for Error { } } -struct Validator<'wrld, W: WorldTrait> { +struct Validator<'wrld> { /// Number of instructions in the smartcontract instruction_count: u64, /// Max allowed number of instructions in the smartcontract max_instruction_count: u64, /// If this particular instruction is allowed - is_instruction_allowed: Arc>, + is_instruction_allowed: Arc, /// If this particular query is allowed - is_query_allowed: Arc>, + is_query_allowed: Arc, /// Current [`WorldStateview`] - wsv: &'wrld WorldStateView, + wsv: &'wrld WorldStateView, } -impl Validator<'_, W> { +impl Validator<'_> { /// Checks if number of instructions in wasm smartcontract exceeds maximum /// /// # Errors @@ -123,20 +123,20 @@ impl Validator<'_, W> { fn validate_query(&self, account_id: &AccountId, query: &QueryBox) -> Result<(), Trap> { self.is_query_allowed .check(account_id, query, self.wsv) - .map_err(Trap::new) + .map_err(|err| Trap::new(err.to_string())) } } -struct State<'wrld, W: WorldTrait> { +struct State<'wrld> { account_id: AccountId, /// Ensures smartcontract adheres to limits - validator: Option>, + validator: Option>, store_limits: StoreLimits, - wsv: &'wrld WorldStateView, + wsv: &'wrld WorldStateView, } -impl<'wrld, W: WorldTrait> State<'wrld, W> { - fn new(wsv: &'wrld WorldStateView, account_id: AccountId, config: Configuration) -> Self { +impl<'wrld> State<'wrld> { + fn new(wsv: &'wrld WorldStateView, account_id: AccountId, config: Configuration) -> Self { Self { wsv, account_id, @@ -156,8 +156,8 @@ impl<'wrld, W: WorldTrait> State<'wrld, W> { fn with_validator( mut self, max_instruction_count: u64, - is_instruction_allowed: Arc>, - is_query_allowed: Arc>, + is_instruction_allowed: Arc, + is_query_allowed: Arc, ) -> Self { let validator = Validator { instruction_count: 0, @@ -173,13 +173,13 @@ impl<'wrld, W: WorldTrait> State<'wrld, W> { } /// `WebAssembly` virtual machine -pub struct Runtime<'wrld, W: WorldTrait> { +pub struct Runtime<'wrld> { engine: Engine, - linker: Linker>, + linker: Linker>, config: Configuration, } -impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { +impl<'wrld> Runtime<'wrld> { /// `Runtime` constructor with default configuration. /// /// # Errors @@ -221,10 +221,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { Engine::new(&Self::create_config()).map_err(Error::Initialization) } - fn create_store( - &self, - state: State<'wrld, W>, - ) -> Result>, anyhow::Error> { + fn create_store(&self, state: State<'wrld>) -> Result>, anyhow::Error> { let mut store = Store::new(&self.engine, state); store.limiter(|stat| &mut stat.store_limits); @@ -235,7 +232,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { fn create_smart_contract( &self, - store: &mut Store>, + store: &mut Store>, bytes: impl AsRef<[u8]>, ) -> Result { let module = Module::new(&self.engine, bytes)?; @@ -284,7 +281,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { /// /// If decoding or execution of the query fails fn execute_query( - mut caller: Caller>, + mut caller: Caller, offset: WasmUsize, len: WasmUsize, ) -> Result { @@ -341,7 +338,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { /// /// If decoding or execution of the ISI fails fn execute_instruction( - mut caller: Caller>, + mut caller: Caller, offset: WasmUsize, len: WasmUsize, ) -> Result<(), Trap> { @@ -380,7 +377,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { /// /// If string decoding fails #[allow(clippy::print_stdout)] - fn dbg(mut caller: Caller>, offset: WasmUsize, len: WasmUsize) -> Result<(), Trap> { + fn dbg(mut caller: Caller, offset: WasmUsize, len: WasmUsize) -> Result<(), Trap> { let memory = Self::get_memory(&mut caller)?; let string_mem_range = offset as usize..(offset + len) as usize; let mut string_bytes = &memory.data(&caller)[string_mem_range]; @@ -389,7 +386,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { Ok(()) } - fn create_linker(engine: &Engine) -> Result>, Error> { + fn create_linker(engine: &Engine) -> Result>, Error> { let mut linker = Linker::new(engine); linker @@ -404,9 +401,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { Ok(linker) } - fn get_alloc_fn( - caller: &mut Caller>, - ) -> Result, Trap> { + fn get_alloc_fn(caller: &mut Caller) -> Result, Trap> { caller .get_export(WASM_ALLOC_FN) .ok_or_else(|| Trap::new(format!("{}: export not found", WASM_ALLOC_FN)))? @@ -416,7 +411,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { .map_err(|_error| Trap::new(format!("{}: unexpected declaration", WASM_ALLOC_FN))) } - fn get_memory(caller: &mut Caller>) -> Result { + fn get_memory(caller: &mut Caller) -> Result { caller .get_export(WASM_MEMORY_NAME) .ok_or_else(|| Trap::new(format!("{}: export not found", WASM_MEMORY_NAME)))? @@ -433,12 +428,12 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { /// - if execution of the smartcontract fails (check ['execute']) pub fn validate( &mut self, - wsv: &WorldStateView, + wsv: &WorldStateView, account_id: &AccountId, bytes: impl AsRef<[u8]>, max_instruction_count: u64, - is_instruction_allowed: Arc>, - is_query_allowed: Arc>, + is_instruction_allowed: Arc, + is_query_allowed: Arc, ) -> Result<(), Error> { let state = State::new(wsv, account_id.clone(), self.config).with_validator( max_instruction_count, @@ -459,7 +454,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { /// - if the execution of the smartcontract fails pub fn execute( &mut self, - wsv: &WorldStateView, + wsv: &WorldStateView, account_id: &AccountId, bytes: impl AsRef<[u8]>, ) -> Result<(), Error> { @@ -471,7 +466,7 @@ impl<'wrld, W: WorldTrait> Runtime<'wrld, W> { &mut self, account_id: &AccountId, bytes: impl AsRef<[u8]>, - state: State, + state: State, ) -> Result<(), Error> { let mut store = self.create_store(state).map_err(Error::Instantiation)?; @@ -566,7 +561,7 @@ mod tests { use super::*; use crate::{ - smartcontracts::permissions::{AllowAll, DenyAll}, + smartcontracts::permissions::combinators::{AllowAll, DenyAll}, PeersIds, World, }; diff --git a/core/src/sumeragi/fault.rs b/core/src/sumeragi/fault.rs index 903944fbcb6..8ea50cbff2c 100644 --- a/core/src/sumeragi/fault.rs +++ b/core/src/sumeragi/fault.rs @@ -7,14 +7,13 @@ use super::{config::SumeragiConfiguration, *}; /// Fault injection for consensus tests pub trait FaultInjection: Send + Sync + Sized + 'static { /// A function to skip or modify a message. - fn faulty_message( - sumeragi: &SumeragiWithFault, + fn faulty_message( + sumeragi: &SumeragiWithFault, msg: Message, ) -> Option where G: GenesisNetworkTrait, - K: KuraTrait, - W: WorldTrait; + K: KuraTrait; /// Allows controlling Sumeragi rounds by sending `Voting` message /// manually. @@ -28,14 +27,10 @@ pub trait FaultInjection: Send + Sync + Sized + 'static { pub struct NoFault; impl FaultInjection for NoFault { - fn faulty_message( - _: &SumeragiWithFault, - msg: Message, - ) -> Option + fn faulty_message(_: &SumeragiWithFault, msg: Message) -> Option where G: GenesisNetworkTrait, K: KuraTrait, - W: WorldTrait, { Some(msg) } @@ -46,16 +41,15 @@ impl FaultInjection for NoFault { } /// `Sumeragi` is the implementation of the consensus. This struct allows also to add fault injection for tests. -pub struct SumeragiWithFault +pub struct SumeragiWithFault where G: GenesisNetworkTrait, K: KuraTrait, - W: WorldTrait, F: FaultInjection, { pub(crate) key_pair: KeyPair, /// Address of queue - pub queue: Arc>, + pub queue: Arc, /// The current topology of the peer to peer network. pub topology: Topology, /// The peer id of myself. @@ -65,7 +59,7 @@ where /// This field is used to count votes when the peer is a proxy tail role. pub(crate) votes_for_blocks: BTreeMap, VersionedValidBlock>, pub(crate) events_sender: EventsSender, - pub(crate) wsv: Arc>, + pub(crate) wsv: Arc, /// This field is used to count votes for a view change. pub(crate) votes_for_view_change: HashMap, Proof>, @@ -83,7 +77,7 @@ where /// Hashes of invalidated blocks pub invalidated_blocks_hashes: Vec>, pub(crate) transaction_limits: TransactionLimits, - pub(crate) transaction_validator: TransactionValidator, + pub(crate) transaction_validator: TransactionValidator, pub(crate) telemetry_started: bool, /// Genesis network pub genesis_network: Option, @@ -100,21 +94,20 @@ where pub(crate) gossip_period: Duration, } -impl, W: WorldTrait, F: FaultInjection> - SumeragiTrait for SumeragiWithFault +impl SumeragiTrait + for SumeragiWithFault { type GenesisNetwork = G; type Kura = K; - type World = W; fn from_configuration( configuration: &SumeragiConfiguration, events_sender: EventsSender, - wsv: Arc>, - transaction_validator: TransactionValidator, + wsv: Arc, + transaction_validator: TransactionValidator, telemetry_started: bool, genesis_network: Option, - queue: Arc>, + queue: Arc, broker: Broker, kura: AlwaysAddr, network: Addr, @@ -157,9 +150,7 @@ impl, W: WorldTrait, F: FaultInj } #[async_trait::async_trait] -impl Actor - for SumeragiWithFault -{ +impl Actor for SumeragiWithFault { fn actor_channel_capacity(&self) -> u32 { self.actor_channel_capacity } @@ -173,8 +164,8 @@ impl Act } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = Vec>; @@ -184,8 +175,8 @@ impl } #[async_trait::async_trait] -impl ContextHandler - for SumeragiWithFault +impl ContextHandler + for SumeragiWithFault { type Result = (); @@ -198,8 +189,8 @@ impl Con } #[async_trait::async_trait] -impl - ContextHandler for SumeragiWithFault +impl ContextHandler + for SumeragiWithFault { type Result = (); @@ -221,8 +212,8 @@ impl } #[async_trait::async_trait] -impl Handler - for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -235,8 +226,8 @@ impl Han } #[async_trait::async_trait] -impl Handler - for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -246,8 +237,8 @@ impl Han } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -275,8 +266,8 @@ impl } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = Topology; @@ -286,8 +277,8 @@ impl } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = Topology; @@ -297,8 +288,8 @@ impl } #[async_trait::async_trait] -impl Handler - for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -308,8 +299,8 @@ impl Han } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -324,8 +315,8 @@ impl } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -340,8 +331,8 @@ impl } #[async_trait::async_trait] -impl - Handler for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -355,8 +346,8 @@ impl } #[async_trait::async_trait] -impl Handler - for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = bool; @@ -366,8 +357,8 @@ impl Han } #[async_trait::async_trait] -impl Handler - for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = PeerId; @@ -377,8 +368,8 @@ impl Han } #[async_trait::async_trait] -impl Handler - for SumeragiWithFault +impl Handler + for SumeragiWithFault { type Result = (); @@ -393,9 +384,7 @@ impl Han } } -impl - SumeragiWithFault -{ +impl SumeragiWithFault { /// Initializes sumeragi with the `latest_block_hash` and `block_height` after Kura loads the blocks. pub fn init(&mut self, latest_block: HashOf, block_height: u64) { self.block_height = block_height; @@ -891,9 +880,7 @@ impl } } -impl Debug - for SumeragiWithFault -{ +impl Debug for SumeragiWithFault { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Sumeragi") .field("public_key", &self.key_pair.public_key()) @@ -905,8 +892,8 @@ impl Deb } #[async_trait::async_trait] -impl ContextHandler - for SumeragiWithFault +impl ContextHandler + for SumeragiWithFault { type Result = (); diff --git a/core/src/sumeragi/message.rs b/core/src/sumeragi/message.rs index 61455e8fd03..699f29fb629 100644 --- a/core/src/sumeragi/message.rs +++ b/core/src/sumeragi/message.rs @@ -26,7 +26,6 @@ use crate::{ kura::KuraTrait, queue, sumeragi::{NetworkMessage, Role, Sumeragi, Topology, VotingBlock}, - wsv::WorldTrait, VersionedAcceptedTransaction, VersionedCommittedBlock, VersionedValidBlock, }; @@ -162,10 +161,10 @@ impl VersionedMessage { /// # Errors /// Fails if message handling fails #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( self, - sumeragi: &mut Sumeragi, - ctx: &mut iroha_actor::Context>, + sumeragi: &mut Sumeragi, + ctx: &mut iroha_actor::Context>, ) -> Result<()> { self.into_v1().handle(sumeragi, ctx).await } @@ -197,10 +196,10 @@ impl Message { /// Fails if message handling fails #[log(skip(self, sumeragi, ctx))] #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( self, - sumeragi: &mut SumeragiWithFault, - ctx: &mut iroha_actor::Context>, + sumeragi: &mut SumeragiWithFault, + ctx: &mut iroha_actor::Context>, ) -> Result<()> { let message = if let Some(message) = F::faulty_message(sumeragi, self) { message @@ -250,9 +249,9 @@ impl ViewChangeSuggested { /// # Errors /// Can fail during signing. #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( &self, - sumeragi: &mut SumeragiWithFault, + sumeragi: &mut SumeragiWithFault, ) -> Result<()> { use view_change::Reason::*; sumeragi.update_view_changes(self.chain.clone()); @@ -290,10 +289,10 @@ impl BlockCreated { /// # Errors /// Can fail due to signing of block #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( &self, - sumeragi: &mut SumeragiWithFault, - ctx: &mut iroha_actor::Context>, + sumeragi: &mut SumeragiWithFault, + ctx: &mut iroha_actor::Context>, ) -> Result<()> { // There should be only one block in discussion during a round. if sumeragi.voting_block.is_some() { @@ -384,9 +383,9 @@ impl BlockSigned { /// # Errors /// Can fail due to signing of block #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( &self, - sumeragi: &mut SumeragiWithFault, + sumeragi: &mut SumeragiWithFault, ) -> Result<()> { sumeragi.update_view_changes(self.block.header().view_change_proofs.clone()); let network_topology = sumeragi.network_topology_current_or_genesis(self.block.header()); @@ -472,9 +471,9 @@ impl BlockCommitted { /// # Errors /// Actually infallible #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( &self, - sumeragi: &mut SumeragiWithFault, + sumeragi: &mut SumeragiWithFault, ) -> Result<()> { let network_topology = sumeragi.network_topology_current_or_genesis(self.block.header()); #[allow(clippy::expect_used)] @@ -542,9 +541,9 @@ impl TransactionForwarded { /// # Errors /// Can fail due to signing transaction #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( self, - sumeragi: &mut SumeragiWithFault, + sumeragi: &mut SumeragiWithFault, ) -> Result<()> { let transaction = VersionedAcceptedTransaction::from_transaction( self.transaction.clone().into_v1(), @@ -586,9 +585,9 @@ impl TransactionGossip { /// /// # Errors /// Can fail during signing. - pub async fn handle( + pub async fn handle( self, - sumeragi: &mut SumeragiWithFault, + sumeragi: &mut SumeragiWithFault, ) -> Result<()> { for transaction in self.txs { let tx = VersionedAcceptedTransaction::from_transaction( @@ -654,10 +653,10 @@ impl TransactionReceipt { /// # Errors /// Can fail due to signing of block #[iroha_futures::telemetry_future] - pub async fn handle( + pub async fn handle( &self, - sumeragi: &mut SumeragiWithFault, - ctx: &mut iroha_actor::Context>, + sumeragi: &mut SumeragiWithFault, + ctx: &mut iroha_actor::Context>, ) -> Result<()> { let now = current_time(); diff --git a/core/src/sumeragi/mod.rs b/core/src/sumeragi/mod.rs index 7f703c5b423..4afcde446ef 100644 --- a/core/src/sumeragi/mod.rs +++ b/core/src/sumeragi/mod.rs @@ -37,7 +37,6 @@ use crate::{ prelude::*, queue::Queue, tx::TransactionValidator, - wsv::WorldTrait, EventsSender, IrohaNetwork, NetworkMessage, VersionedValidBlock, }; @@ -49,7 +48,7 @@ trait Consensus { } /// `Sumeragi` is the implementation of the consensus. -pub type Sumeragi = SumeragiWithFault; +pub type Sumeragi = SumeragiWithFault; /// Generic sumeragi trait pub trait SumeragiTrait: @@ -68,9 +67,7 @@ pub trait SumeragiTrait: /// Genesis for sending genesis txs type GenesisNetwork: GenesisNetworkTrait; /// Data storage - type Kura: KuraTrait; - /// World for updating WSV after block commitment - type World: WorldTrait; + type Kura: KuraTrait; /// Construct [`Sumeragi`]. /// @@ -80,11 +77,11 @@ pub trait SumeragiTrait: fn from_configuration( configuration: &config::SumeragiConfiguration, events_sender: EventsSender, - wsv: Arc>, - transaction_validator: TransactionValidator, + wsv: Arc, + transaction_validator: TransactionValidator, telemetry_started: bool, genesis_network: Option, - queue: Arc>, + queue: Arc, broker: Broker, kura: AlwaysAddr, network: Addr, diff --git a/core/src/tx.rs b/core/src/tx.rs index 5e2d72d6ba7..4baa47116d6 100644 --- a/core/src/tx.rs +++ b/core/src/tx.rs @@ -24,31 +24,30 @@ use crate::{ }, wasm, Evaluate, Execute, FindError, }, - wsv::WorldTrait, }; /// Used to validate transaction and thus move transaction lifecycle forward /// /// Permission validation is skipped for genesis. #[derive(Clone)] -pub struct TransactionValidator { +pub struct TransactionValidator { transaction_limits: TransactionLimits, - is_instruction_allowed: Arc>, - is_query_allowed: Arc>, + is_instruction_allowed: Arc, + is_query_allowed: Arc, - wsv: Arc>, + wsv: Arc, } -impl TransactionValidator { +impl TransactionValidator { /// Construct [`TransactionValidator`] pub fn new( transaction_limits: TransactionLimits, - is_instruction_allowed: Arc>, - is_query_allowed: Arc>, + is_instruction_allowed: Arc, + is_query_allowed: Arc, - wsv: Arc>, + wsv: Arc, ) -> Self { Self { transaction_limits, @@ -226,10 +225,7 @@ impl VersionedAcceptedTransaction { /// /// # Errors /// Can fail if signature condition account fails or if account is not found - pub fn check_signature_condition( - &self, - wsv: &WorldStateView, - ) -> Result { + pub fn check_signature_condition(&self, wsv: &WorldStateView) -> Result { self.as_v1().check_signature_condition(wsv) } } @@ -282,10 +278,7 @@ impl AcceptedTransaction { /// # Errors /// - Account not found /// - Signature verification fails - pub fn check_signature_condition( - &self, - wsv: &WorldStateView, - ) -> Result { + pub fn check_signature_condition(&self, wsv: &WorldStateView) -> Result { let account_id = &self.payload.account_id; let signatories = self @@ -333,19 +326,19 @@ impl Txn for AcceptedTransaction { impl IsInBlockchain for VersionedAcceptedTransaction { #[inline] - fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool { + fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool { wsv.has_transaction(&self.hash()) } } impl IsInBlockchain for VersionedValidTransaction { #[inline] - fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool { + fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool { wsv.has_transaction(&self.hash()) } } impl IsInBlockchain for VersionedRejectedTransaction { #[inline] - fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool { + fn is_in_blockchain(&self, wsv: &WorldStateView) -> bool { wsv.has_transaction(&self.hash()) } } diff --git a/core/src/wsv.rs b/core/src/wsv.rs index d515e9747b8..041ded1fa1a 100644 --- a/core/src/wsv.rs +++ b/core/src/wsv.rs @@ -1,13 +1,7 @@ //! This module provides the [`WorldStateView`] - in-memory representations of the current blockchain //! state. -use std::{ - convert::Infallible, - fmt::Debug, - ops::{Deref, DerefMut}, - sync::Arc, - time::Duration, -}; +use std::{convert::Infallible, fmt::Debug, sync::Arc, time::Duration}; use config::Configuration; use dashmap::{ @@ -15,6 +9,7 @@ use dashmap::{ DashSet, }; use eyre::Result; +use getset::Getters; use iroha_crypto::HashOf; use iroha_data_model::{prelude::*, small::SmallVec}; use iroha_logger::prelude::*; @@ -33,53 +28,53 @@ pub type NewBlockNotificationSender = tokio::sync::watch::Sender<()>; /// Receiver type of the new block notification channel pub type NewBlockNotificationReceiver = tokio::sync::watch::Receiver<()>; -/// World trait for mocking -pub trait WorldTrait: - Deref + DerefMut + Send + Sync + 'static + Debug + Default + Sized + Clone -{ - /// Creates a [`World`] with these [`Domain`]s and trusted [`PeerId`]s. - fn with( - domains: impl IntoIterator, - trusted_peers_ids: impl IntoIterator, - ) -> Self; -} - /// The global entity consisting of `domains`, `triggers` and etc. /// For example registration of domain, will have this as an ISI target. -#[derive(Debug, Default, Clone)] +#[derive(Debug, Default, Clone, Getters)] pub struct World { /// Iroha parameters. - pub parameters: Vec, + /// TODO: Use this field + _parameters: Vec, /// Identifications of discovered trusted peers. - pub trusted_peers_ids: PeersIds, + pub(crate) trusted_peers_ids: PeersIds, /// Registered domains. - pub domains: DomainsMap, + pub(crate) domains: DomainsMap, /// Roles. [`Role`] pairs. - pub roles: crate::RolesMap, + pub(crate) roles: crate::RolesMap, /// Triggers - pub triggers: TriggerSet, + pub(crate) triggers: TriggerSet, } -impl Deref for World { - type Target = Self; - #[inline] - fn deref(&self) -> &Self::Target { - self +impl World { + /// Creates an empty `World`. + pub fn new() -> Self { + Self::default() } -} -impl DerefMut for World { - #[inline] - fn deref_mut(&mut self) -> &mut Self::Target { - self + /// Creates a [`World`] with these [`Domain`]s and trusted [`PeerId`]s. + pub fn with(domains: D, trusted_peers_ids: P) -> Self + where + D: IntoIterator, + P: IntoIterator, + { + let domains = domains + .into_iter() + .map(|domain| (domain.id().clone(), domain)) + .collect(); + let trusted_peers_ids = trusted_peers_ids.into_iter().collect(); + World { + domains, + trusted_peers_ids, + ..World::new() + } } } /// Current state of the blockchain aligned with `Iroha` module. #[derive(Debug)] -pub struct WorldStateView { +pub struct WorldStateView { /// The world - contains `domains`, `triggers`, etc.. - pub world: W, + pub world: World, /// Configuration of World State View. pub config: Configuration, /// Blockchain. @@ -94,14 +89,14 @@ pub struct WorldStateView { events_sender: Option, } -impl Default for WorldStateView { +impl Default for WorldStateView { #[inline] fn default() -> Self { - Self::new(W::default()) + Self::new(World::default()) } } -impl Clone for WorldStateView { +impl Clone for WorldStateView { #[allow(clippy::expect_used)] fn clone(&self) -> Self { Self { @@ -116,38 +111,12 @@ impl Clone for WorldStateView { } } -impl World { - /// Creates an empty `World`. - #[inline] - pub fn new() -> Self { - Self::default() - } -} - -impl WorldTrait for World { - fn with( - domains: impl IntoIterator, - trusted_peers_ids: impl IntoIterator, - ) -> Self { - let domains = domains - .into_iter() - .map(|domain| (domain.id().clone(), domain)) - .collect(); - let trusted_peers_ids = trusted_peers_ids.into_iter().collect(); - World { - domains, - trusted_peers_ids, - ..World::new() - } - } -} - /// WARNING!!! INTERNAL USE ONLY!!! -impl WorldStateView { +impl WorldStateView { /// Construct [`WorldStateView`] with given [`World`]. #[must_use] #[inline] - pub fn new(world: W) -> Self { + pub fn new(world: World) -> Self { Self::from_configuration(Configuration::default(), world) } @@ -521,7 +490,7 @@ impl WorldStateView { /// Construct [`WorldStateView`] with specific [`Configuration`]. #[inline] - pub fn from_configuration(config: Configuration, world: W) -> Self { + pub fn from_configuration(config: Configuration, world: World) -> Self { let (new_block_notifier, _) = tokio::sync::watch::channel(()); Self { @@ -783,10 +752,16 @@ impl WorldStateView { /// Get an immutable view of the `World`. #[must_use] #[inline] - pub fn world(&self) -> &W { + pub fn world(&self) -> &World { &self.world } + /// Returns reference for triggers + #[inline] + pub fn triggers(&self) -> &TriggerSet { + &self.world.triggers + } + /// Get triggers set and modify it with `f` /// /// Produces trigger event from `f` @@ -876,7 +851,7 @@ mod tests { const BLOCK_CNT: usize = 10; let mut block = ValidBlock::new_dummy().commit(); - let wsv = WorldStateView::::default(); + let wsv = WorldStateView::default(); let mut block_hashes = vec![]; for i in 1..=BLOCK_CNT { @@ -900,7 +875,7 @@ mod tests { const BLOCK_CNT: usize = 10; let mut block = ValidBlock::new_dummy().commit(); - let wsv = WorldStateView::::default(); + let wsv = WorldStateView::default(); for i in 1..=BLOCK_CNT { block.header.height = i as u64; diff --git a/core/test_network/Cargo.toml b/core/test_network/Cargo.toml index 6e8ccaed36e..04310b3547e 100644 --- a/core/test_network/Cargo.toml +++ b/core/test_network/Cargo.toml @@ -6,8 +6,6 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [features] -# Enable mock tests -mock = [] # Create a mock query for testing query = [] @@ -25,8 +23,3 @@ unique_port = "0.1.0" tokio = { version = "1.6.0", features = ["rt", "rt-multi-thread", "macros"]} rand = "0.8" futures = { version = "0.3.17", default-features = false, features = ["std", "async-await"] } - -[dev-dependencies] - -async-trait = "0.1" -once_cell = "1.8.0" diff --git a/core/test_network/src/lib.rs b/core/test_network/src/lib.rs index 4ed9fac8d28..c3d23770a5a 100644 --- a/core/test_network/src/lib.rs +++ b/core/test_network/src/lib.rs @@ -17,7 +17,6 @@ use iroha_core::{ prelude::*, smartcontracts::permissions::{IsInstructionAllowedBoxed, IsQueryAllowedBoxed}, sumeragi::{config::SumeragiConfiguration, Sumeragi, SumeragiTrait}, - wsv::{World, WorldTrait}, }; use iroha_data_model::{peer::Peer as DataModelPeer, prelude::*}; use iroha_logger::{Configuration as LoggerConfiguration, InstrumentFutures}; @@ -33,23 +32,17 @@ use tokio::{ struct ShutdownRuntime; /// Network of peers -pub struct Network< - W = World, - G = GenesisNetwork, - K = Kura, - S = Sumeragi, - B = BlockSynchronizer, -> where - W: WorldTrait, +pub struct Network, B = BlockSynchronizer> +where G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { /// Genesis peer which sends genesis block to everyone - pub genesis: Peer, + pub genesis: Peer, /// Peers excluding the `genesis` peer. Use [`Network::peers`] function to get all instead. - pub peers: HashMap>, + pub peers: HashMap>, } /// Get a standardised key-pair from the hard-coded literals. @@ -106,6 +99,9 @@ impl TestGenesis for G { ) .into(), ); + + configure_world(); + G::from_configuration( submit_genesis, genesis, @@ -116,13 +112,14 @@ impl TestGenesis for G { } } -impl Network +fn configure_world() {} + +impl Network where - W: WorldTrait, G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { /// Send message to an actor instance on peers. /// @@ -130,7 +127,7 @@ where /// Programmer error. `self.peers()` should already have `iroha`. pub async fn send_to_actor_on_peers( &self, - select_actor: impl Fn(&Iroha) -> &Addr, + select_actor: impl Fn(&Iroha) -> &Addr, msg: M, ) -> Vec<(M::Result, PeerId)> where @@ -250,7 +247,7 @@ where offline_peers: u32, ) -> Result { let n_peers = n_peers - 1; - let mut genesis = Peer::::new()?; + let mut genesis = Peer::::new()?; let mut peers = (0..n_peers) .map(|_| Peer::new()) .map(|result| result.map(|peer| (peer.id.clone(), peer))) @@ -267,7 +264,7 @@ where let online_peers = n_peers - offline_peers; let futures = FuturesUnordered::new(); - let builder = PeerBuilder::::new() + let builder = PeerBuilder::::new() .with_into_genesis(G::test(true)) .with_configuration(configuration.clone()); @@ -276,7 +273,7 @@ where .values_mut() .choose_multiple(rng, online_peers as usize) { - let builder = PeerBuilder::::new() + let builder = PeerBuilder::::new() .with_into_genesis(G::test(false)) .with_configuration(configuration.clone()); @@ -290,7 +287,7 @@ where } /// Returns all peers. - pub fn peers(&self) -> impl Iterator> + '_ { + pub fn peers(&self) -> impl Iterator> + '_ { std::iter::once(&self.genesis).chain(self.peers.values()) } @@ -302,7 +299,7 @@ where } /// Get peer by its Id. - pub fn peer_by_id(&self, id: &PeerId) -> Option<&Peer> { + pub fn peer_by_id(&self, id: &PeerId) -> Option<&Peer> { self.peers.get(id).or(if self.genesis.id == *id { Some(&self.genesis) } else { @@ -343,18 +340,12 @@ pub fn wait_for_genesis_committed(clients: &[Client], offline_peers: u32) { } /// Peer structure -pub struct Peer< - W = World, - G = GenesisNetwork, - K = Kura, - S = Sumeragi, - B = BlockSynchronizer, -> where - W: WorldTrait, +pub struct Peer, B = BlockSynchronizer> +where G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { /// The id of the peer pub id: PeerId, @@ -371,7 +362,7 @@ pub struct Peer< /// Shutdown handle shutdown: Option>, /// Iroha itself - pub iroha: Option>, + pub iroha: Option>, } impl From for Box { @@ -388,13 +379,12 @@ impl std::cmp::PartialEq for Peer { impl std::cmp::Eq for Peer {} -impl Drop for Peer +impl Drop for Peer where - W: WorldTrait, G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { fn drop(&mut self) { iroha_logger::info!( @@ -409,13 +399,12 @@ where } } -impl Peer +impl Peer where - W: WorldTrait, G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { /// Returns per peer config with all addresses, keys, and id set up. fn get_config(&self, configuration: Configuration) -> Configuration { @@ -446,8 +435,8 @@ where &mut self, configuration: Configuration, genesis: Option, - instruction_validator: IsInstructionAllowedBoxed, - query_validator: IsQueryAllowedBoxed, + instruction_validator: IsInstructionAllowedBoxed, + query_validator: IsQueryAllowedBoxed, temp_dir: Arc, ) { let mut configuration = self.get_config(configuration); @@ -470,7 +459,7 @@ where async move { // Prevent temporary directory deleting let _temp_dir = Arc::clone(&temp_dir); - let mut iroha = >::with_genesis( + let mut iroha = >::with_genesis( genesis, configuration, instruction_validator, @@ -550,21 +539,19 @@ impl From> for WithGenesis { } /// `PeerBuilder` structure that helps to create a peer. -pub struct PeerBuilder +pub struct PeerBuilder where - W: WorldTrait, G: GenesisNetworkTrait, { configuration: Option, genesis: WithGenesis, - instruction_validator: Option>, - query_validator: Option>, + instruction_validator: Option, + query_validator: Option, temp_dir: Option>, } -impl PeerBuilder +impl PeerBuilder where - W: WorldTrait, G: GenesisNetworkTrait, { /// Creates [`PeerBuilder`]. @@ -603,7 +590,7 @@ where #[must_use] pub fn with_instruction_validator( mut self, - instruction_validator: impl Into> + Send + 'static, + instruction_validator: impl Into + Send + 'static, ) -> Self { self.instruction_validator .replace(instruction_validator.into()); @@ -614,7 +601,7 @@ where #[must_use] pub fn with_query_validator( mut self, - query_validator: impl Into> + Send + 'static, + query_validator: impl Into + Send + 'static, ) -> Self { self.query_validator.replace(query_validator.into()); self @@ -628,11 +615,11 @@ where } /// Accepts a peer and starts it. - pub async fn start_with_peer(self, peer: &mut Peer) + pub async fn start_with_peer(self, peer: &mut Peer) where - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, + K: KuraTrait, + S: SumeragiTrait, + B: BlockSynchronizerTrait, { let configuration = self.configuration.unwrap_or_else(|| { let mut config = Configuration::test(); @@ -665,8 +652,7 @@ where /// Creates and starts a peer with preapplied arguments. pub async fn start( self, - ) -> Peer, Sumeragi, W>, BlockSynchronizer, W>, W>> - { + ) -> Peer, BlockSynchronizer>> { let mut peer = Peer::new().expect("Failed to create a peer."); self.start_with_peer(&mut peer).await; peer @@ -676,7 +662,7 @@ where pub async fn start_with_client( self, ) -> ( - Peer, Sumeragi, W>, BlockSynchronizer, W>, W>>, + Peer, BlockSynchronizer>>, Client, ) { let configuration = self @@ -697,22 +683,21 @@ where } /// Creates a peer with a client, creates a runtime, and synchronously starts the peer on the runtime. - pub fn start_with_runtime(self) -> PeerWithRuntimeAndClient { + pub fn start_with_runtime(self) -> PeerWithRuntimeAndClient { let rt = Runtime::test(); let (peer, client) = rt.block_on(self.start_with_client()); (rt, peer, client) } } -type PeerWithRuntimeAndClient = ( +type PeerWithRuntimeAndClient = ( Runtime, - Peer, Sumeragi, W>, BlockSynchronizer, W>, W>>, + Peer, BlockSynchronizer>>, Client, ); -impl Default for PeerBuilder +impl Default for PeerBuilder where - W: WorldTrait, G: GenesisNetworkTrait, { fn default() -> Self { @@ -785,7 +770,7 @@ pub trait TestClient: Sized { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug; @@ -800,7 +785,7 @@ pub trait TestClient: Sized { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug; @@ -814,7 +799,7 @@ pub trait TestClient: Sized { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug; @@ -830,7 +815,7 @@ pub trait TestClient: Sized { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug; } @@ -959,7 +944,7 @@ impl TestClient for Client { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug, { @@ -975,7 +960,7 @@ impl TestClient for Client { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug, { @@ -992,7 +977,7 @@ impl TestClient for Client { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug, { @@ -1013,7 +998,7 @@ impl TestClient for Client { f: impl Fn(&R::Output) -> bool, ) -> eyre::Result where - R: ValidQuery + Into + Debug + Clone, + R: ValidQuery + Into + Debug + Clone, >::Error: Into, R::Output: Clone + Debug, { diff --git a/core/test_network/tests/integration/mod.rs b/core/test_network/tests/integration/mod.rs deleted file mode 100644 index 23037bab9ea..00000000000 --- a/core/test_network/tests/integration/mod.rs +++ /dev/null @@ -1 +0,0 @@ -mod sumeragi_with_mock; diff --git a/core/test_network/tests/integration/sumeragi_with_mock.rs b/core/test_network/tests/integration/sumeragi_with_mock.rs deleted file mode 100644 index eaf875fbe2a..00000000000 --- a/core/test_network/tests/integration/sumeragi_with_mock.rs +++ /dev/null @@ -1,553 +0,0 @@ -#![allow( - clippy::restriction, - missing_debug_implementations, - clippy::future_not_send, - clippy::pedantic -)] - -use std::{fmt::Debug, ops::Deref, time::Duration}; - -use eyre::Result; -use iroha_actor::prelude::*; -use iroha_core::{ - block_sync::{BlockSynchronizer, BlockSynchronizerTrait}, - genesis::{config::GenesisConfiguration, GenesisNetworkTrait}, - kura::KuraTrait, - prelude::*, - sumeragi::{ - fault::SumeragiWithFault, - message::{Gossip, IsLeader, RetrieveTransactions}, - network_topology::Topology, - Sumeragi, SumeragiTrait, - }, - wsv::WorldTrait, -}; -use iroha_data_model::prelude::*; -use test_network::*; -use tokio::time; -use utils::{genesis, sumeragi, world}; - -pub mod utils { - use iroha_core::genesis::RawGenesisBlock; - - use super::*; - - pub mod genesis { - use iroha_core::IrohaNetwork; - - use super::*; - - #[derive(Debug, Clone, Copy, Default)] - pub struct NoGenesis; - - impl Deref for NoGenesis { - type Target = Vec; - - fn deref(&self) -> &Self::Target { - unreachable!() - } - } - - #[async_trait::async_trait] - impl GenesisNetworkTrait for NoGenesis { - fn from_configuration( - _submit_genesis: bool, - _block_path: RawGenesisBlock, - _genesis_config: &GenesisConfiguration, - _transaction_limits: &TransactionLimits, - ) -> Result> { - Ok(None) - } - - async fn wait_for_peers( - &self, - _: PeerId, - _: Topology, - _: Addr, - ) -> Result { - unreachable!() - } - - fn genesis_submission_delay_ms(&self) -> u64 { - 0 - } - } - } - - pub mod sumeragi { - use std::{fmt::Debug, marker::PhantomData}; - - use iroha_core::{ - genesis::GenesisNetworkTrait, - kura::KuraTrait, - sumeragi::{ - fault::{FaultInjection, SumeragiWithFault}, - message::Message as SumeragiMessage, - network_topology::Role, - }, - wsv::WorldTrait, - }; - - pub trait ConstRoleTrait: Debug + Send + 'static { - /// Returns true if this peer has this `role` - fn role(role: Role) -> bool; - } - - #[derive(Debug, Clone, Copy, Default)] - struct Not(PhantomData); - - impl ConstRoleTrait for Not { - fn role(role: Role) -> bool { - !R::role(role) - } - } - - macro_rules! impl_role { - ($($name:ident),* $(,)? ) => {$( - #[derive(Debug, Clone, Copy, Default)] - pub struct $name; - impl ConstRoleTrait for $name { - fn role(role: Role) -> bool { - Role::$name == role - } - } - )*}; - } - - impl_role!(Leader, ValidatingPeer, ObservingPeer, ProxyTail); - - #[derive(Debug, Clone, Copy, Default)] - pub struct Any; - - impl ConstRoleTrait for Any { - fn role(_: Role) -> bool { - true - } - } - - #[derive(Debug, Clone, Copy, Default)] - pub struct EmptyBlockCreated; - - impl FaultInjection for EmptyBlockCreated { - fn faulty_message( - _: &SumeragiWithFault, - msg: SumeragiMessage, - ) -> Option - where - G: GenesisNetworkTrait, - K: KuraTrait, - W: WorldTrait, - { - let msg = if let SumeragiMessage::BlockCreated(mut block) = msg { - block.block.as_mut_v1().transactions = Vec::new(); - SumeragiMessage::BlockCreated(block) - } else { - msg - }; - Some(msg) - } - } - - #[derive(Debug, Clone, Copy, Default)] - pub struct Skip(PhantomData, PhantomData); - - macro_rules! impl_skip { - ( $($name:ident),* $(,)? ) => {$( - #[derive(Debug, Clone, Copy, Default)] - pub struct $name; - - impl FaultInjection for Skip<$name, R> { - fn faulty_message( - sumeragi: &SumeragiWithFault, - msg: SumeragiMessage, - ) -> Option - where - G: GenesisNetworkTrait, - K: KuraTrait, - W: WorldTrait, - { - if let SumeragiMessage::$name(..) = msg { - if R::role(sumeragi.role()) { - iroha_logger::error!("Fault behaviour: Skipping {}", stringify!($name)); - None - } else { - Some(msg) - } - } else { - Some(msg) - } - } - } - )*}; - } - - impl_skip!( - BlockCreated, - BlockSigned, - BlockCommitted, - TransactionReceived, - TransactionForwarded, - ViewChangeSuggested - ); - - #[derive(Debug, Clone, Copy, Default)] - pub struct SkipTxForwardedAndGossipOnLeader; - - impl FaultInjection for SkipTxForwardedAndGossipOnLeader { - fn faulty_message( - sumeragi: &SumeragiWithFault, - msg: SumeragiMessage, - ) -> Option - where - G: GenesisNetworkTrait, - K: KuraTrait, - W: WorldTrait, - { - match (sumeragi.role(), msg) { - (Role::Leader, SumeragiMessage::TransactionForwarded(_)) - | (Role::Leader, SumeragiMessage::TransactionGossip(_)) => { - iroha_logger::error!( - "Fault behaviour: Skipping TransactionForwarded and TransactionGossip" - ); - None - } - (_, msg) => Some(msg), - } - } - } - } - - pub mod world { - use std::{ - ops::{Deref, DerefMut}, - str::FromStr as _, - }; - - use iroha_core::{prelude::*, tx::Domain, wsv::WorldTrait}; - use iroha_data_model::prelude::*; - use once_cell::sync::Lazy; - - #[derive(Debug, Clone, Default)] - pub struct WithAlice(World); - - impl Deref for WithAlice { - type Target = World; - fn deref(&self) -> &Self::Target { - &self.0 - } - } - - impl DerefMut for WithAlice { - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.0 - } - } - - pub static ALICE_KEYS: Lazy = - Lazy::new(|| KeyPair::generate().expect("doesn't fail")); - pub static ALICE: Lazy = Lazy::new(|| { - let account_id = AccountId::from_str("alice@wonderland").expect("valid account name."); - let mut account = Account::new(account_id, []).build(); - assert!(account.add_signatory(ALICE_KEYS.public_key().clone())); - account - }); - pub static WONDERLAND: Lazy = Lazy::new(|| { - let mut domain = - Domain::new(DomainId::from_str("wonderland").expect("valid domain name")).build(); - assert!(domain.add_account(ALICE.clone()).is_none()); - domain - }); - - impl WorldTrait for WithAlice { - /// Creates `World` with these `domains` and `trusted_peers_ids` - fn with( - domains: impl IntoIterator, - trusted_peers_ids: impl IntoIterator, - ) -> Self { - Self(World::with( - domains.into_iter().chain([WONDERLAND.clone()]), - trusted_peers_ids, - )) - } - } - - pub fn sign_tx(isi: impl IntoIterator) -> VersionedAcceptedTransaction { - let instructions: Vec<_> = isi.into_iter().collect(); - let tx = Transaction::new(ALICE.id().clone(), instructions.into(), 100_000) - .sign(ALICE_KEYS.clone()) - .expect("Sign shall not fail"); - let tx_limits = TransactionLimits { - max_instruction_number: 4096, - max_wasm_size_bytes: 0, - }; - VersionedAcceptedTransaction::from_transaction(tx, &tx_limits).expect("is valid") - } - } -} - -/// Checks if blocks applied on all peers -async fn blocks_applied(network: &Network, n_blocks: usize) -where - W: WorldTrait, - G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, -{ - for peer in network.peers() { - assert_eq!( - peer.iroha.as_ref().expect("Iroha initialised").wsv.height(), - n_blocks as u64 - ) - } -} - -async fn put_tx_in_queue_to_peer(network: &Network, to_leader: bool) -where - W: WorldTrait, - G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, -{ - let tx = world::sign_tx(vec![]); - let leader = network - .send_to_actor_on_peers(|iroha| &iroha.sumeragi, IsLeader) - .await; - let (_, peer) = leader - .into_iter() - .find(|(leader, _)| if to_leader { *leader } else { !*leader }) - .expect("guaranteed one leader"); - let peer = network.peer_by_id(&peer).expect("guaranteed, leader"); - peer.iroha - .as_ref() - .expect("Iroha initialised") - .queue - .push(tx) - .expect("queue is not full, and tx is correctly formed"); -} - -async fn put_tx_in_queue_to_all(network: &Network) -where - W: WorldTrait, - G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, -{ - let tx = world::sign_tx(vec![]); - for peer in network.peers() { - peer.iroha - .as_ref() - .expect("Iroha initialised") - .queue - .push(tx.clone()) - .expect("queue is not full, and tx is correctly formed"); - } -} - -async fn round(network: &Network) -where - W: WorldTrait, - G: GenesisNetworkTrait, - K: KuraTrait, - S: SumeragiTrait, - B: BlockSynchronizerTrait, -{ - for peer in network.peers() { - peer.iroha - .as_ref() - .expect("Iroha initialised") - .sumeragi - .do_send(RetrieveTransactions) - .await; - } -} - -#[tokio::test(flavor = "multi_thread")] -#[ignore = "mock"] -async fn all_peers_commit_block() { - iroha_logger::install_panic_hook().expect("first installation"); - let (network, _) = , - Sumeragi<_, _, _>, - BlockSynchronizer<_, _>, - >>::start_test(10, 1) - .await; - - // Send tx to leader - put_tx_in_queue_to_peer(&network, true).await; - round(&network).await; - time::sleep(Duration::from_secs(2)).await; - - blocks_applied(&network, 1).await; -} - -#[tokio::test(flavor = "multi_thread")] -#[ignore = "mock"] -async fn change_view_on_commit_timeout() { - iroha_logger::install_panic_hook().expect("first installation"); - let (network, _) = , - SumeragiWithFault<_, _, _, sumeragi::Skip>, - BlockSynchronizer<_, _>, - >>::start_test(10, 1) - .await; - - // Send tx to leader - put_tx_in_queue_to_peer(&network, true).await; - round(&network).await; - time::sleep(Duration::from_secs(4)).await; - - blocks_applied(&network, 0).await; - - let topologies = network - .send_to_actor_on_peers( - |iroha| &iroha.sumeragi, - iroha_core::sumeragi::message::CurrentNetworkTopology, - ) - .await; - let invalid_block_hashes = network - .send_to_actor_on_peers( - |iroha| &iroha.sumeragi, - iroha_core::sumeragi::message::InvalidatedBlockHashes, - ) - .await; - - for (topology, _) in topologies { - assert_eq!(topology.view_change_proofs().len(), 1); - } - for (hashes, _) in invalid_block_hashes { - assert_eq!(hashes.len(), 1); - } -} - -#[tokio::test(flavor = "multi_thread")] -#[ignore = "mock"] -async fn change_view_on_tx_receipt_timeout() { - iroha_logger::install_panic_hook().expect("first installation"); - let (network, _) = , - SumeragiWithFault<_, _, _, sumeragi::SkipTxForwardedAndGossipOnLeader>, - BlockSynchronizer<_, _>, - >>::start_test(10, 1) - .await; - - // send to not leader - put_tx_in_queue_to_peer(&network, false).await; - - // Let peers gossip tx. - for peer in network.peers() { - peer.iroha - .as_ref() - .expect("Iroha initialised") - .sumeragi - .do_send(Gossip) - .await; - } - - // Wait while tx is gossiped - time::sleep(Duration::from_millis(500)).await; - - // Let peers retrieve the gossiped tx and send to leader, so they can all understand the leader is unresponsive. - for peer in network.peers() { - peer.iroha - .as_ref() - .expect("Iroha initialised") - .sumeragi - .do_send(RetrieveTransactions) - .await; - } - - time::sleep(Duration::from_secs(3)).await; - - blocks_applied(&network, 0).await; - - let topologies = network - .send_to_actor_on_peers( - |iroha| &iroha.sumeragi, - iroha_core::sumeragi::message::CurrentNetworkTopology, - ) - .await; - for (topology, _) in topologies { - assert_eq!(topology.view_change_proofs().len(), 1); - } -} - -#[tokio::test(flavor = "multi_thread")] -#[ignore = "mock"] -async fn change_view_on_block_creation_timeout() { - iroha_logger::install_panic_hook().expect("first installation"); - let (network, _) = , - SumeragiWithFault<_, _, _, sumeragi::Skip>, - BlockSynchronizer<_, _>, - >>::start_test(10, 1) - .await; - - // send to not leader - put_tx_in_queue_to_all(&network).await; - round(&network).await; - time::sleep(Duration::from_secs(3)).await; - - blocks_applied(&network, 0).await; - - let topologies = network - .send_to_actor_on_peers( - |iroha| &iroha.sumeragi, - iroha_core::sumeragi::message::CurrentNetworkTopology, - ) - .await; - - for (topology, _) in topologies { - assert_eq!(topology.view_change_proofs().len(), 1); - } -} - -#[tokio::test(flavor = "multi_thread")] -#[ignore = "mock"] -async fn not_enough_votes() { - iroha_logger::install_panic_hook().expect("first installation"); - let (network, _) = , - SumeragiWithFault<_, _, _, sumeragi::EmptyBlockCreated>, - BlockSynchronizer<_, _>, - >>::start_test(10, 1) - .await; - - put_tx_in_queue_to_peer(&network, true).await; - round(&network).await; - time::sleep(Duration::from_secs(4)).await; - - blocks_applied(&network, 0).await; - - let topologies = network - .send_to_actor_on_peers( - |iroha| &iroha.sumeragi, - iroha_core::sumeragi::message::CurrentNetworkTopology, - ) - .await; - let invalid_block_hashes = network - .send_to_actor_on_peers( - |iroha| &iroha.sumeragi, - iroha_core::sumeragi::message::InvalidatedBlockHashes, - ) - .await; - - for (topology, _) in topologies { - assert_eq!(topology.view_change_proofs().len(), 1); - } - for (hashes, _) in invalid_block_hashes { - assert_eq!(hashes.len(), 1); - } -} diff --git a/core/test_network/tests/mod.rs b/core/test_network/tests/mod.rs deleted file mode 100644 index ecebd561003..00000000000 --- a/core/test_network/tests/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -#[cfg(not(coverage))] -mod integration; diff --git a/macro/README.md b/macro/README.md index e1af5c45640..a9ffcb4f973 100644 --- a/macro/README.md +++ b/macro/README.md @@ -17,6 +17,8 @@ iroha_derive = { git = "https://github.com/hyperledger/iroha/", branch="iroha2-d ```rust use iroha_derive::FromVariant; +trait MyTrait {} + // Use derive to derive the implementation of `FromVariant`: #[derive(FromVariant)] enum Obj { @@ -25,6 +27,8 @@ enum Obj { String(String), // You can also skip implementing `From` Vec(#[skip_from] Vec), + // You can also skip implementing `From` for item inside containers such as `Box` + Box(#[skip_container] Box) } // That would help you avoid doing this: diff --git a/macro/derive/src/lib.rs b/macro/derive/src/lib.rs index 3c49f446351..04299ea33f6 100644 --- a/macro/derive/src/lib.rs +++ b/macro/derive/src/lib.rs @@ -8,6 +8,8 @@ use quote::quote; /// Attribute for skipping from attribute const SKIP_FROM_ATTR: &str = "skip_from"; const SKIP_TRY_FROM_ATTR: &str = "skip_try_from"; +/// Attribute to skip inner container optimization. Useful for trait objects +const SKIP_CONTAINER: &str = "skip_container"; /// [`FromVariant`] is used for implementing `From for Enum` /// and `TryFrom for Variant`. @@ -15,13 +17,17 @@ const SKIP_TRY_FROM_ATTR: &str = "skip_try_from"; /// ```rust /// use iroha_derive::FromVariant; /// +/// trait MyTrait {} +/// /// #[derive(FromVariant)] /// enum Obj { /// Uint(u32), /// Int(i32), /// String(String), -/// // You can also skip implementing `From` +/// // You can skip implementing `From` /// Vec(#[skip_from] Vec), +/// // You can also skip implementing `From` for item inside containers such as `Box` +/// Box(#[skip_container] Box) /// } /// /// // For example, to avoid: @@ -34,7 +40,7 @@ const SKIP_TRY_FROM_ATTR: &str = "skip_try_from"; /// } /// } /// ``` -#[proc_macro_derive(FromVariant, attributes(skip_from, skip_try_from))] +#[proc_macro_derive(FromVariant, attributes(skip_from, skip_try_from, skip_container))] pub fn from_variant_derive(input: TokenStream) -> TokenStream { let ast = syn::parse(input).expect("Failed to parse input Token Stream."); impl_from_variant(&ast) @@ -96,12 +102,17 @@ fn from_variant( into_ty: &syn::Ident, into_variant: &syn::Ident, from_ty: &syn::Type, + skip_container: bool, ) -> proc_macro2::TokenStream { let from_orig = from_variant_internal(into_ty, into_variant, from_ty); if let syn::Type::Path(path) = from_ty { let mut code = from_orig; + if skip_container { + return code; + } + for container in CONTAINERS { if let Some(inner) = get_type_argument(container, path) { let segments = path @@ -180,8 +191,10 @@ fn impl_from_variant(ast: &syn::DeriveInput) -> TokenStream { }; let from = if attrs_have_ident(&unnamed.unnamed[0].attrs, SKIP_FROM_ATTR) { quote!() + } else if attrs_have_ident(&unnamed.unnamed[0].attrs, SKIP_CONTAINER) { + from_variant(name, &variant.ident, variant_type, true) } else { - from_variant(name, &variant.ident, variant_type) + from_variant(name, &variant.ident, variant_type, false) }; return Some(quote!( diff --git a/permissions_validators/src/lib.rs b/permissions_validators/src/lib.rs index d0d6404e781..f845a015276 100644 --- a/permissions_validators/src/lib.rs +++ b/permissions_validators/src/lib.rs @@ -7,19 +7,18 @@ use iroha_core::{ smartcontracts::{ permissions::{ prelude::*, HasToken, IsAllowed, IsInstructionAllowedBoxed, IsQueryAllowedBoxed, - ValidatorApplyOr, ValidatorBuilder, }, Evaluate, }, - wsv::WorldTrait, }; use iroha_data_model::{isi::*, prelude::*}; use iroha_macro::error::ErrorTryFromEnum; use once_cell::sync::Lazy; +use serde::Serialize; macro_rules! impl_from_item_for_instruction_validator_box { ( $ty:ty ) => { - impl From<$ty> for IsInstructionAllowedBoxed { + impl From<$ty> for IsInstructionAllowedBoxed { fn from(validator: $ty) -> Self { Box::new(validator) } @@ -29,7 +28,7 @@ macro_rules! impl_from_item_for_instruction_validator_box { macro_rules! impl_from_item_for_query_validator_box { ( $ty:ty ) => { - impl From<$ty> for IsQueryAllowedBoxed { + impl From<$ty> for IsQueryAllowedBoxed { fn from(validator: $ty) -> Self { Box::new(validator) } @@ -39,15 +38,15 @@ macro_rules! impl_from_item_for_query_validator_box { macro_rules! impl_from_item_for_granted_token_validator_box { ( $ty:ty ) => { - impl From<$ty> for HasTokenBoxed { + impl From<$ty> for HasTokenBoxed { fn from(validator: $ty) -> Self { Box::new(validator) } } - impl From<$ty> for IsInstructionAllowedBoxed { + impl From<$ty> for IsInstructionAllowedBoxed { fn from(validator: $ty) -> Self { - let validator: HasTokenBoxed = validator.into(); + let validator: HasTokenBoxed = validator.into(); Box::new(validator) } } @@ -56,15 +55,15 @@ macro_rules! impl_from_item_for_granted_token_validator_box { macro_rules! impl_from_item_for_grant_instruction_validator_box { ( $ty:ty ) => { - impl From<$ty> for IsGrantAllowedBoxed { + impl From<$ty> for IsGrantAllowedBoxed { fn from(validator: $ty) -> Self { Box::new(validator) } } - impl From<$ty> for IsInstructionAllowedBoxed { + impl From<$ty> for IsInstructionAllowedBoxed { fn from(validator: $ty) -> Self { - let validator: IsGrantAllowedBoxed = validator.into(); + let validator: IsGrantAllowedBoxed = validator.into(); Box::new(validator) } } @@ -73,15 +72,15 @@ macro_rules! impl_from_item_for_grant_instruction_validator_box { macro_rules! impl_from_item_for_revoke_instruction_validator_box { ( $ty:ty ) => { - impl From<$ty> for IsRevokeAllowedBoxed { + impl From<$ty> for IsRevokeAllowedBoxed { fn from(validator: $ty) -> Self { Box::new(validator) } } - impl From<$ty> for IsInstructionAllowedBoxed { + impl From<$ty> for IsInstructionAllowedBoxed { fn from(validator: $ty) -> Self { - let validator: IsRevokeAllowedBoxed = validator.into(); + let validator: IsRevokeAllowedBoxed = validator.into(); Box::new(validator) } } @@ -175,7 +174,7 @@ macro_rules! declare_token { fn try_from( token: iroha_data_model::permissions::PermissionToken - ) -> Result { + ) -> std::result::Result { if token.name() != Self::name() { return Err(Self::Error::Name(token.name().clone())) } diff --git a/permissions_validators/src/private_blockchain/mod.rs b/permissions_validators/src/private_blockchain/mod.rs index 252f67691a5..4624c3ded8d 100644 --- a/permissions_validators/src/private_blockchain/mod.rs +++ b/permissions_validators/src/private_blockchain/mod.rs @@ -1,4 +1,4 @@ -//! Permission checks asociated with use cases that can be summarized as private blockchains (e.g. CBDC). +//! Permission checks associated with use cases that can be summarized as private blockchains (e.g. CBDC). use super::*; @@ -6,35 +6,37 @@ pub mod query; pub mod register; /// A preconfigured set of permissions for simple use cases. -pub fn default_instructions_permissions() -> IsInstructionAllowedBoxed { - ValidatorBuilder::new() - .with_recursive_validator( - register::ProhibitRegisterDomains.or(register::GrantedAllowedRegisterDomains), - ) - .all_should_succeed() +pub fn default_instructions_permissions() -> IsInstructionAllowedBoxed { + ValidatorBuilder::with_recursive_validator( + register::ProhibitRegisterDomains.or(register::GrantedAllowedRegisterDomains), + ) + .all_should_succeed() + .build() } /// A preconfigured set of permissions for simple use cases. -pub fn default_query_permissions() -> IsQueryAllowedBoxed { - ValidatorBuilder::new().all_should_succeed() +pub fn default_query_permissions() -> IsQueryAllowedBoxed { + ValidatorBuilder::with_validator(AllowAll) + .all_should_succeed() + .build() } /// Prohibits using the [`Grant`] instruction at runtime. This means /// `Grant` instruction will only be used in genesis to specify /// rights. The rationale is that we don't want to be able to create a /// super-user in a blockchain. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct ProhibitGrant; impl_from_item_for_grant_instruction_validator_box!(ProhibitGrant); -impl IsGrantAllowed for ProhibitGrant { - fn check_grant( +impl IsGrantAllowed for ProhibitGrant { + fn check( &self, _authority: &AccountId, _instruction: &GrantBox, - _wsv: &WorldStateView, + _wsv: &WorldStateView, ) -> Result<(), DenialReason> { - Err("Granting at runtime is prohibited.".to_owned()) + Err("Granting at runtime is prohibited.".to_owned().into()) } } diff --git a/permissions_validators/src/private_blockchain/query.rs b/permissions_validators/src/private_blockchain/query.rs index 64240c0fb80..94b76c4334d 100644 --- a/permissions_validators/src/private_blockchain/query.rs +++ b/permissions_validators/src/private_blockchain/query.rs @@ -3,39 +3,45 @@ use super::*; /// Allow queries that only access the data of the domain of the signer. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyAccountsDomain; -impl IsAllowed for OnlyAccountsDomain { +impl IsAllowed for OnlyAccountsDomain { #[allow(clippy::too_many_lines, clippy::match_same_arms)] fn check( &self, authority: &AccountId, query: &QueryBox, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), DenialReason> { use QueryBox::*; let context = Context::new(); match query { FindAssetsByAssetDefinitionId(_) | FindAssetsByName(_) | FindAllAssets(_) => { - Err("Only access to the assets of the same domain is permitted.".to_owned()) - } - FindAllAccounts(_) | FindAccountsByName(_) | FindAccountsWithAsset(_) => { - Err("Only access to the accounts of the same domain is permitted.".to_owned()) - } + Err("Only access to the assets of the same domain is permitted." + .to_owned() + .into()) + } + FindAllAccounts(_) | FindAccountsByName(_) | FindAccountsWithAsset(_) => Err( + "Only access to the accounts of the same domain is permitted." + .to_owned() + .into(), + ), FindAllAssetsDefinitions(_) => Err( - "Only access to the asset definitions of the same domain is permitted.".to_owned(), + "Only access to the asset definitions of the same domain is permitted." + .to_owned() + .into(), ), - FindAllDomains(_) => { - Err("Only access to the domain of the account is permitted.".to_owned()) - } - FindAllRoles(_) => { - Err("Only access to roles of the same domain is permitted.".to_owned()) - } + FindAllDomains(_) => Err("Only access to the domain of the account is permitted." + .to_owned() + .into()), + FindAllRoles(_) => Err("Only access to roles of the same domain is permitted." + .to_owned() + .into()), FindAllRoleIds(_) => Ok(()), // In case you need to debug the permissions. - FindRoleByRoleId(_) => { - Err("Only access to roles of the same domain is permitted.".to_owned()) - } + FindRoleByRoleId(_) => Err("Only access to roles of the same domain is permitted." + .to_owned() + .into()), FindAllPeers(_) => Ok(()), // Can be obtained in other ways, so why hide it. FindAllActiveTriggerIds(_) => Ok(()), // Private blockchains should have debugging too, hence @@ -45,14 +51,14 @@ impl IsAllowed for OnlyAccountsDomain { .id .evaluate(wsv, &context) .map_err(|e| e.to_string())?; - wsv.world - .triggers + wsv.triggers() .inspect(&id, |action| { if action.technical_account() == authority { Ok(()) } else { Err("Cannot access Trigger if you're not the technical account." - .to_owned()) + .to_owned() + .into()) } }) .ok_or_else(|| { @@ -67,15 +73,14 @@ impl IsAllowed for OnlyAccountsDomain { .id .evaluate(wsv, &context) .map_err(|e| e.to_string())?; - wsv.world - .triggers + wsv.triggers() .inspect(&id, |action| { if action.technical_account() == authority { Ok(()) } else { Err( "Cannot access Trigger internal state if you're not the technical account." - .to_owned(), + .to_owned().into(), ) } }) @@ -99,7 +104,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access triggers with given domain {}, {} is permitted..", domain_id, authority.domain_id - )) + ) + .into()) } FindAccountById(query) => { let account_id = query @@ -112,7 +118,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access account {} as it is in a different domain.", account_id - )) + ) + .into()) } } FindAccountKeyValueByIdAndKey(query) => { @@ -126,7 +133,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access account {} as it is in a different domain.", account_id - )) + ) + .into()) } } FindAccountsByDomainId(query) => { @@ -140,7 +148,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access accounts from a different domain with name {}.", domain_id - )) + ) + .into()) } } FindAssetById(query) => { @@ -154,7 +163,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access asset {} as it is in a different domain.", asset_id - )) + ) + .into()) } } FindAssetsByAccountId(query) => { @@ -168,7 +178,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access account {} as it is in a different domain.", account_id - )) + ) + .into()) } } FindAssetsByDomainId(query) => { @@ -182,7 +193,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access assets from a different domain with name {}.", domain_id - )) + ) + .into()) } } FindAssetsByDomainIdAndAssetDefinitionId(query) => { @@ -196,7 +208,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access assets from a different domain with name {}.", domain_id - )) + ) + .into()) } } FindAssetDefinitionKeyValueByIdAndKey(query) => { @@ -211,7 +224,7 @@ impl IsAllowed for OnlyAccountsDomain { "Cannot access asset definition from a different domain. Asset definition domain: {}. Signer's account domain {}.", asset_definition_id.domain_id, authority.domain_id - )) + ).into()) } } FindAssetQuantityById(query) => { @@ -225,7 +238,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access asset {} as it is in a different domain.", asset_id - )) + ) + .into()) } } FindAssetKeyValueByIdAndKey(query) => { @@ -239,7 +253,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access asset {} as it is in a different domain.", asset_id - )) + ) + .into()) } } FindDomainById(query::FindDomainById { id }) @@ -248,13 +263,15 @@ impl IsAllowed for OnlyAccountsDomain { if domain_id == authority.domain_id { Ok(()) } else { - Err(format!("Cannot access a different domain: {}.", domain_id)) + Err(format!("Cannot access a different domain: {}.", domain_id).into()) } } - FindAllBlocks(_) => Err("Access to all blocks not permitted".to_owned()), - FindAllTransactions(_) => { - Err("Only access to transactions in the same domain is permitted.".to_owned()) - } + FindAllBlocks(_) => Err("Access to all blocks not permitted".to_owned().into()), + FindAllTransactions(_) => Err( + "Only access to transactions in the same domain is permitted." + .to_owned() + .into(), + ), FindTransactionsByAccountId(query) => { let account_id = query .account_id @@ -266,7 +283,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access account {} as it is in a different domain.", account_id - )) + ) + .into()) } } FindTransactionByHash(_query) => Ok(()), @@ -281,7 +299,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access account {} as it is in a different domain.", account_id - )) + ) + .into()) } } FindPermissionTokensByAccountId(query) => { @@ -295,7 +314,8 @@ impl IsAllowed for OnlyAccountsDomain { Err(format!( "Cannot access account {} as it is in a different domain.", account_id - )) + ) + .into()) } } FindAssetDefinitionById(query) => { @@ -311,7 +331,7 @@ impl IsAllowed for OnlyAccountsDomain { "Cannot access asset definition from a different domain. Asset definition domain: {}. Signer's account domain {}.", asset_definition_id.domain_id, authority.domain_id, - )) + ).into()) } } } @@ -321,16 +341,16 @@ impl IsAllowed for OnlyAccountsDomain { impl_from_item_for_query_validator_box!(OnlyAccountsDomain); /// Allow queries that only access the signers account data. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyAccountsData; -impl IsAllowed for OnlyAccountsData { +impl IsAllowed for OnlyAccountsData { #[allow(clippy::too_many_lines, clippy::match_same_arms)] fn check( &self, authority: &AccountId, query: &QueryBox, - wsv: &WorldStateView, + wsv: &WorldStateView, ) -> Result<(), DenialReason> { use QueryBox::*; @@ -340,12 +360,12 @@ impl IsAllowed for OnlyAccountsData { | FindAccountsByDomainId(_) | FindAccountsWithAsset(_) | FindAllAccounts(_) => { - Err("Other accounts are private.".to_owned()) + Err("Other accounts are private.".to_owned().into()) } | FindAllDomains(_) | FindDomainById(_) | FindDomainKeyValueByIdAndKey(_) => { - Err("Only access to your account's data is permitted.".to_owned()) + Err("Only access to your account's data is permitted.".to_owned().into()) }, FindAssetsByDomainIdAndAssetDefinitionId(_) | FindAssetsByName(_) // TODO: I think this is a mistake. @@ -355,16 +375,16 @@ impl IsAllowed for OnlyAccountsData { | FindAssetDefinitionById(_) | FindAssetDefinitionKeyValueByIdAndKey(_) | FindAllAssets(_) => { - Err("Only access to the assets of your account is permitted.".to_owned()) + Err("Only access to the assets of your account is permitted.".to_owned().into()) } FindAllRoles(_) | FindAllRoleIds(_) | FindRoleByRoleId(_) => { - Err("Only access to roles of the same account is permitted.".to_owned()) + Err("Only access to roles of the same account is permitted.".to_owned().into()) }, FindAllActiveTriggerIds(_) | FindTriggersByDomainId(_) => { - Err("Only access to the triggers of the same account is permitted.".to_owned()) + Err("Only access to the triggers of the same account is permitted.".to_owned().into()) } FindAllPeers(_) => { - Err("Only access to your account-local data is permitted.".to_owned()) + Err("Only access to your account-local data is permitted.".to_owned().into()) } FindTriggerById(query) => { // TODO: should differentiate between global and domain-local triggers. @@ -372,7 +392,7 @@ impl IsAllowed for OnlyAccountsData { .id .evaluate(wsv, &context) .map_err(|e| e.to_string())?; - if wsv.world.triggers.inspect(&id, |action| + if wsv.triggers().inspect(&id, |action| action.technical_account() == authority ) == Some(true) { return Ok(()) @@ -380,15 +400,15 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "A trigger with the specified Id: {} is not accessible to you", id - )) + ).into()) } FindTriggerKeyValueByIdAndKey(query) => { // TODO: should differentiate between global and domain-local triggers. let id = query .id .evaluate(wsv, &context) - .map_err(|e| e.to_string())?; - if wsv.world.triggers.inspect(&id, |action| + .map_err(|err| err.to_string())?; + if wsv.triggers().inspect(&id, |action| action.technical_account() == authority ) == Some(true) { return Ok(()) @@ -396,7 +416,7 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "A trigger with the specified Id: {} is not accessible to you", id - )) + ).into()) } FindAccountById(query) => { let account_id = query @@ -410,7 +430,7 @@ impl IsAllowed for OnlyAccountsData { "Cannot access account {} as only access to your own account, {} is permitted..", account_id, authority - )) + ).into()) } } FindAccountKeyValueByIdAndKey(query) => { @@ -424,7 +444,7 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "Cannot access account {} as only access to your own account is permitted..", account_id - )) + ).into()) } } FindAssetById(query) => { @@ -438,7 +458,7 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "Cannot access asset {} as it is in a different account.", asset_id - )) + ).into()) } } FindAssetsByAccountId(query) => { @@ -452,7 +472,7 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "Cannot access a different account: {}.", account_id - )) + ).into()) } } @@ -467,7 +487,7 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "Cannot access asset {} as it is in a different account.", asset_id - )) + ).into()) } } FindAssetKeyValueByIdAndKey(query) => { @@ -481,14 +501,14 @@ impl IsAllowed for OnlyAccountsData { Err(format!( "Cannot access asset {} as it is in a different account.", asset_id - )) + ).into()) } } FindAllBlocks(_) => { - Err("Access to all blocks not permitted".to_owned()) + Err("Access to all blocks not permitted".to_owned().into()) } FindAllTransactions(_) => { - Err("Only access to transactions of the same account is permitted.".to_owned()) + Err("Only access to transactions of the same account is permitted.".to_owned().into()) }, FindTransactionsByAccountId(query) => { let account_id = query @@ -498,7 +518,7 @@ impl IsAllowed for OnlyAccountsData { if &account_id == authority { Ok(()) } else { - Err(format!("Cannot access another account: {}.", account_id)) + Err(format!("Cannot access another account: {}.", account_id).into()) } } FindTransactionByHash(_query) => Ok(()), @@ -510,7 +530,7 @@ impl IsAllowed for OnlyAccountsData { if &account_id == authority { Ok(()) } else { - Err(format!("Cannot access another account: {}.", account_id)) + Err(format!("Cannot access another account: {}.", account_id).into()) } } FindPermissionTokensByAccountId(query) => { @@ -521,7 +541,7 @@ impl IsAllowed for OnlyAccountsData { if &account_id == authority { Ok(()) } else { - Err(format!("Cannot access another account: {}.", account_id)) + Err(format!("Cannot access another account: {}.", account_id).into()) } } } diff --git a/permissions_validators/src/private_blockchain/register.rs b/permissions_validators/src/private_blockchain/register.rs index c52118d19b4..2d8cec80f42 100644 --- a/permissions_validators/src/private_blockchain/register.rs +++ b/permissions_validators/src/private_blockchain/register.rs @@ -10,39 +10,39 @@ pub static CAN_REGISTER_DOMAINS_TOKEN: Lazy = Lazy::new(|| Name::from_str("can_register_domains").expect("this mustn't panic")); /// Prohibits registering domains. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct ProhibitRegisterDomains; impl_from_item_for_instruction_validator_box!(ProhibitRegisterDomains); -impl IsAllowed for ProhibitRegisterDomains { +impl IsAllowed for ProhibitRegisterDomains { fn check( &self, _authority: &AccountId, instruction: &Instruction, - _wsv: &WorldStateView, + _wsv: &WorldStateView, ) -> Result<(), DenialReason> { let _register_box = if let Instruction::Register(register) = instruction { register } else { return Ok(()); }; - Err("Domain registration is prohibited.".to_owned()) + Err("Domain registration is prohibited.".to_owned().into()) } } /// Validator that allows to register domains for accounts with the corresponding permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantedAllowedRegisterDomains; impl_from_item_for_granted_token_validator_box!(GrantedAllowedRegisterDomains); -impl HasToken for GrantedAllowedRegisterDomains { +impl HasToken for GrantedAllowedRegisterDomains { fn token( &self, _authority: &AccountId, _instruction: &Instruction, - _wsv: &WorldStateView, + _wsv: &WorldStateView, ) -> Result { Ok(PermissionToken::new(CAN_REGISTER_DOMAINS_TOKEN.clone())) } diff --git a/permissions_validators/src/public_blockchain/burn.rs b/permissions_validators/src/public_blockchain/burn.rs index d52a30130f7..31daed5e988 100644 --- a/permissions_validators/src/public_blockchain/burn.rs +++ b/permissions_validators/src/public_blockchain/burn.rs @@ -23,18 +23,18 @@ declare_token!( ); /// Checks that account can burn only the assets which were registered by this account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyAssetsCreatedByThisAccount; impl_from_item_for_instruction_validator_box!(OnlyAssetsCreatedByThisAccount); -impl IsAllowed for OnlyAssetsCreatedByThisAccount { +impl IsAllowed for OnlyAssetsCreatedByThisAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let burn_box = if let Instruction::Burn(burn) = instruction { burn } else { @@ -50,7 +50,9 @@ impl IsAllowed for OnlyAssetsCreatedByThisAccount .map(|asset_definition_entry| asset_definition_entry.registered_by() == authority) .unwrap_or(false); if !registered_by_signer_account { - return Err("Can't burn assets registered by other accounts.".to_owned()); + return Err("Can't burn assets registered by other accounts." + .to_owned() + .into()); } Ok(()) } @@ -58,18 +60,18 @@ impl IsAllowed for OnlyAssetsCreatedByThisAccount /// Allows burning assets from a different account than the creator's of this asset if the corresponding user granted the permission token /// for a specific asset. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize)] pub struct GrantedByAssetCreator; impl_from_item_for_granted_token_validator_box!(GrantedByAssetCreator); -impl HasToken for GrantedByAssetCreator { +impl HasToken for GrantedByAssetCreator { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let burn_box = if let Instruction::Burn(burn) = instruction { burn } else { @@ -91,18 +93,18 @@ impl HasToken for GrantedByAssetCreator { /// Validator that checks Grant instruction so that the access is granted to the assets /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantRegisteredByMeAccess; impl_from_item_for_grant_instruction_validator_box!(GrantRegisteredByMeAccess); -impl IsGrantAllowed for GrantRegisteredByMeAccess { - fn check_grant( +impl IsGrantAllowed for GrantRegisteredByMeAccess { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanBurnAssetWithDefinition = extract_specialized_token(instruction, wsv)?; check_asset_creator_for_asset_definition(&token.asset_definition_id, authority, wsv) @@ -110,18 +112,18 @@ impl IsGrantAllowed for GrantRegisteredByMeAccess { } /// Checks that account can burn only the assets that he currently owns. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyOwnedAssets; impl_from_item_for_instruction_validator_box!(OnlyOwnedAssets); -impl IsAllowed for OnlyOwnedAssets { +impl IsAllowed for OnlyOwnedAssets { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let burn_box = if let Instruction::Burn(burn) = instruction { burn } else { @@ -133,25 +135,25 @@ impl IsAllowed for OnlyOwnedAssets { .map_err(|e| e.to_string())?; let asset_id: AssetId = try_into_or_exit!(destination_id); if &asset_id.account_id != authority { - return Err("Can't burn assets from another account.".to_owned()); + return Err("Can't burn assets from another account.".to_owned().into()); } Ok(()) } } /// Allows burning user's assets from a different account if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantedByAssetOwner; impl_from_item_for_granted_token_validator_box!(GrantedByAssetOwner); -impl HasToken for GrantedByAssetOwner { +impl HasToken for GrantedByAssetOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let burn_box = if let Instruction::Burn(burn_box) = instruction { burn_box } else { @@ -172,22 +174,26 @@ impl HasToken for GrantedByAssetOwner { /// Validator that checks Grant instruction so that the access is granted to the assets /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyAssetAccess; impl_from_item_for_grant_instruction_validator_box!(GrantMyAssetAccess); -impl IsGrantAllowed for GrantMyAssetAccess { - fn check_grant( +impl IsGrantAllowed for GrantMyAssetAccess { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanBurnUserAssets = extract_specialized_token(instruction, wsv)?; if &token.asset_id.account_id != authority { - return Err("Asset specified in permission token is not owned by signer.".to_owned()); + return Err( + "Asset specified in permission token is not owned by signer." + .to_owned() + .into(), + ); } Ok(()) diff --git a/permissions_validators/src/public_blockchain/key_value.rs b/permissions_validators/src/public_blockchain/key_value.rs index f2b15f99fef..cc288c63f94 100644 --- a/permissions_validators/src/public_blockchain/key_value.rs +++ b/permissions_validators/src/public_blockchain/key_value.rs @@ -59,18 +59,18 @@ declare_token!( ); /// Checks that account can set keys for assets only for the signer account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct AssetSetOnlyForSignerAccount; impl_from_item_for_instruction_validator_box!(AssetSetOnlyForSignerAccount); -impl IsAllowed for AssetSetOnlyForSignerAccount { +impl IsAllowed for AssetSetOnlyForSignerAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let set_kv_box = if let Instruction::SetKeyValue(set_kv) = instruction { set_kv } else { @@ -83,7 +83,9 @@ impl IsAllowed for AssetSetOnlyForSignerAccount { match object_id { IdBox::AssetId(asset_id) if &asset_id.account_id != authority => { - Err("Can't set value to asset store from another account.".to_owned()) + Err("Can't set value to asset store from another account." + .to_owned() + .into()) } _ => Ok(()), } @@ -92,18 +94,18 @@ impl IsAllowed for AssetSetOnlyForSignerAccount { /// Allows setting user's assets key value map from a different account /// if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct SetGrantedByAssetOwner; impl_from_item_for_granted_token_validator_box!(SetGrantedByAssetOwner); -impl HasToken for SetGrantedByAssetOwner { +impl HasToken for SetGrantedByAssetOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let set_kv_box = if let Instruction::SetKeyValue(set_kv) = instruction { set_kv } else { @@ -124,22 +126,26 @@ impl HasToken for SetGrantedByAssetOwner { /// Validator that checks Grant instruction so that the access is granted to the assets /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyAssetAccessSet; impl_from_item_for_grant_instruction_validator_box!(GrantMyAssetAccessSet); -impl IsGrantAllowed for GrantMyAssetAccessSet { - fn check_grant( +impl IsGrantAllowed for GrantMyAssetAccessSet { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanSetKeyValueInUserAssets = extract_specialized_token(instruction, wsv)?; if &token.asset_id.account_id != authority { - return Err("Asset specified in permission token is not owned by signer.".to_owned()); + return Err( + "Asset specified in permission token is not owned by signer." + .to_owned() + .into(), + ); } Ok(()) @@ -147,18 +153,18 @@ impl IsGrantAllowed for GrantMyAssetAccessSet { } /// Checks that account can set keys only the for signer account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct AccountSetOnlyForSignerAccount; impl_from_item_for_instruction_validator_box!(AccountSetOnlyForSignerAccount); -impl IsAllowed for AccountSetOnlyForSignerAccount { +impl IsAllowed for AccountSetOnlyForSignerAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let set_kv_box = if let Instruction::SetKeyValue(set_kv) = instruction { set_kv } else { @@ -171,7 +177,9 @@ impl IsAllowed for AccountSetOnlyForSignerAccount match &object_id { IdBox::AccountId(account_id) if account_id != authority => { - Err("Can't set value to account store from another account.".to_owned()) + Err("Can't set value to account store from another account." + .to_owned() + .into()) } _ => Ok(()), } @@ -179,18 +187,18 @@ impl IsAllowed for AccountSetOnlyForSignerAccount } /// Allows setting user's metadata key value pairs from a different account if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct SetGrantedByAccountOwner; impl_from_item_for_granted_token_validator_box!(SetGrantedByAccountOwner); -impl HasToken for SetGrantedByAccountOwner { +impl HasToken for SetGrantedByAccountOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let set_kv_box = if let Instruction::SetKeyValue(set_kv) = instruction { set_kv } else { @@ -211,39 +219,43 @@ impl HasToken for SetGrantedByAccountOwner { /// Validator that checks Grant instruction so that the access is granted to the assets /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyMetadataAccessSet; impl_from_item_for_grant_instruction_validator_box!(GrantMyMetadataAccessSet); -impl IsGrantAllowed for GrantMyMetadataAccessSet { - fn check_grant( +impl IsGrantAllowed for GrantMyMetadataAccessSet { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanSetKeyValueInUserMetadata = extract_specialized_token(instruction, wsv)?; if &token.account_id != authority { - return Err("Account specified in permission token is not owned by signer.".to_owned()); + return Err( + "Account specified in permission token is not owned by signer." + .to_owned() + .into(), + ); } Ok(()) } } /// Checks that account can remove keys for assets only the for signer account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct AssetRemoveOnlyForSignerAccount; impl_from_item_for_instruction_validator_box!(AssetRemoveOnlyForSignerAccount); -impl IsAllowed for AssetRemoveOnlyForSignerAccount { +impl IsAllowed for AssetRemoveOnlyForSignerAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let rem_kv_box = if let Instruction::RemoveKeyValue(rem_kv) = instruction { rem_kv } else { @@ -255,7 +267,9 @@ impl IsAllowed for AssetRemoveOnlyForSignerAccoun .map_err(|e| e.to_string())?; match object_id { IdBox::AssetId(asset_id) if &asset_id.account_id != authority => { - Err("Can't remove value from asset store from another account.".to_owned()) + Err("Can't remove value from asset store from another account." + .to_owned() + .into()) } _ => Ok(()), } @@ -263,18 +277,18 @@ impl IsAllowed for AssetRemoveOnlyForSignerAccoun } /// Allows removing user's assets key value pairs from a different account if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct RemoveGrantedByAssetOwner; impl_from_item_for_granted_token_validator_box!(RemoveGrantedByAssetOwner); -impl HasToken for RemoveGrantedByAssetOwner { +impl HasToken for RemoveGrantedByAssetOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let rem_kv_box = if let Instruction::RemoveKeyValue(rem_kv) = instruction { rem_kv } else { @@ -295,40 +309,44 @@ impl HasToken for RemoveGrantedByAssetOwner { /// Validator that checks Grant instruction so that the access is granted to the assets /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyAssetAccessRemove; impl_from_item_for_grant_instruction_validator_box!(GrantMyAssetAccessRemove); -impl IsGrantAllowed for GrantMyAssetAccessRemove { - fn check_grant( +impl IsGrantAllowed for GrantMyAssetAccessRemove { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanRemoveKeyValueInUserAssets = extract_specialized_token(instruction, wsv)?; if &token.asset_id.account_id != authority { - return Err("Asset specified in permission token is not owned by signer.".to_owned()); + return Err( + "Asset specified in permission token is not owned by signer." + .to_owned() + .into(), + ); } Ok(()) } } /// Checks that account can remove keys only the for signer account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct AccountRemoveOnlyForSignerAccount; impl_from_item_for_instruction_validator_box!(AccountRemoveOnlyForSignerAccount); -impl IsAllowed for AccountRemoveOnlyForSignerAccount { +impl IsAllowed for AccountRemoveOnlyForSignerAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let rem_kv_box = if let Instruction::RemoveKeyValue(rem_kv) = instruction { rem_kv } else { @@ -340,27 +358,29 @@ impl IsAllowed for AccountRemoveOnlyForSignerAcco .map_err(|e| e.to_string())?; match object_id { - IdBox::AccountId(account_id) if &account_id != authority => { - Err("Can't remove value from account store from another account.".to_owned()) - } + IdBox::AccountId(account_id) if &account_id != authority => Err( + "Can't remove value from account store from another account." + .to_owned() + .into(), + ), _ => Ok(()), } } } /// Allows removing user's metadata key value pairs from a different account if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct RemoveGrantedByAccountOwner; impl_from_item_for_granted_token_validator_box!(RemoveGrantedByAccountOwner); -impl HasToken for RemoveGrantedByAccountOwner { +impl HasToken for RemoveGrantedByAccountOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let rem_kv_box = if let Instruction::RemoveKeyValue(rem_kv) = instruction { rem_kv } else { @@ -381,22 +401,26 @@ impl HasToken for RemoveGrantedByAccountOwner { /// Validator that checks Grant instruction so that the access is granted to the metadata /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyMetadataAccessRemove; impl_from_item_for_grant_instruction_validator_box!(GrantMyMetadataAccessRemove); -impl IsGrantAllowed for GrantMyMetadataAccessRemove { - fn check_grant( +impl IsGrantAllowed for GrantMyMetadataAccessRemove { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanRemoveKeyValueInUserMetadata = extract_specialized_token(instruction, wsv)?; if &token.account_id != authority { - return Err("Account specified in permission token is not owned by signer.".to_owned()); + return Err( + "Account specified in permission token is not owned by signer." + .to_owned() + .into(), + ); } Ok(()) } @@ -404,18 +428,18 @@ impl IsGrantAllowed for GrantMyMetadataAccessRemove { /// Validator that checks Grant instruction so that the access is granted to the assets defintion /// registered by signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyAssetDefinitionSet; impl_from_item_for_grant_instruction_validator_box!(GrantMyAssetDefinitionSet); -impl IsGrantAllowed for GrantMyAssetDefinitionSet { - fn check_grant( +impl IsGrantAllowed for GrantMyAssetDefinitionSet { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanSetKeyValueInAssetDefinition = extract_specialized_token(instruction, wsv)?; check_asset_creator_for_asset_definition(&token.asset_definition_id, authority, wsv) @@ -424,18 +448,18 @@ impl IsGrantAllowed for GrantMyAssetDefinitionSet { // Validator that checks Grant instruction so that the access is granted to the assets defintion /// registered by signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyAssetDefinitionRemove; impl_from_item_for_grant_instruction_validator_box!(GrantMyAssetDefinitionRemove); -impl IsGrantAllowed for GrantMyAssetDefinitionRemove { - fn check_grant( +impl IsGrantAllowed for GrantMyAssetDefinitionRemove { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanRemoveKeyValueInAssetDefinition = extract_specialized_token(instruction, wsv)?; @@ -444,18 +468,18 @@ impl IsGrantAllowed for GrantMyAssetDefinitionRemove { } /// Checks that account can set keys for asset definitions only registered by the signer account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct AssetDefinitionSetOnlyForSignerAccount; impl_from_item_for_instruction_validator_box!(AssetDefinitionSetOnlyForSignerAccount); -impl IsAllowed for AssetDefinitionSetOnlyForSignerAccount { +impl IsAllowed for AssetDefinitionSetOnlyForSignerAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let set_kv_box = if let Instruction::SetKeyValue(set_kv) = instruction { set_kv } else { @@ -473,7 +497,9 @@ impl IsAllowed for AssetDefinitionSetOnlyForSigne .unwrap_or(false); if !registered_by_signer_account { return Err( - "Can't set key value to asset definition registered by other accounts.".to_owned(), + "Can't set key value to asset definition registered by other accounts." + .to_owned() + .into(), ); } Ok(()) @@ -481,18 +507,18 @@ impl IsAllowed for AssetDefinitionSetOnlyForSigne } /// Checks that account can set keys for asset definitions only registered by the signer account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct AssetDefinitionRemoveOnlyForSignerAccount; impl_from_item_for_instruction_validator_box!(AssetDefinitionRemoveOnlyForSignerAccount); -impl IsAllowed for AssetDefinitionRemoveOnlyForSignerAccount { +impl IsAllowed for AssetDefinitionRemoveOnlyForSignerAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let rem_kv_box = if let Instruction::RemoveKeyValue(rem_kv) = instruction { rem_kv } else { @@ -511,7 +537,8 @@ impl IsAllowed for AssetDefinitionRemoveOnlyForSi if !registered_by_signer_account { return Err( "Can't remove key value to asset definition registered by other accounts." - .to_owned(), + .to_owned() + .into(), ); } Ok(()) @@ -519,18 +546,18 @@ impl IsAllowed for AssetDefinitionRemoveOnlyForSi } /// Allows setting asset definition's metadata key value pairs from a different account if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct SetGrantedByAssetDefinitionOwner; impl_from_item_for_granted_token_validator_box!(SetGrantedByAssetDefinitionOwner); -impl HasToken for SetGrantedByAssetDefinitionOwner { +impl HasToken for SetGrantedByAssetDefinitionOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let set_kv_box = if let Instruction::SetKeyValue(set_kv) = instruction { set_kv } else { @@ -550,18 +577,18 @@ impl HasToken for SetGrantedByAssetDefinitionOwner { } /// Allows setting asset definition's metadata key value pairs from a different account if the corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct RemoveGrantedByAssetDefinitionOwner; impl_from_item_for_granted_token_validator_box!(RemoveGrantedByAssetDefinitionOwner); -impl HasToken for RemoveGrantedByAssetDefinitionOwner { +impl HasToken for RemoveGrantedByAssetDefinitionOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let set_kv_box = if let Instruction::RemoveKeyValue(set_kv) = instruction { set_kv } else { diff --git a/permissions_validators/src/public_blockchain/mint.rs b/permissions_validators/src/public_blockchain/mint.rs index 446fa75c749..3ceb821506e 100644 --- a/permissions_validators/src/public_blockchain/mint.rs +++ b/permissions_validators/src/public_blockchain/mint.rs @@ -13,18 +13,18 @@ declare_token!( ); /// Checks that account can mint only the assets which were registered by this account. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyAssetsCreatedByThisAccount; impl_from_item_for_instruction_validator_box!(OnlyAssetsCreatedByThisAccount); -impl IsAllowed for OnlyAssetsCreatedByThisAccount { +impl IsAllowed for OnlyAssetsCreatedByThisAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let mint_box = if let Instruction::Mint(mint) = instruction { mint } else { @@ -40,7 +40,9 @@ impl IsAllowed for OnlyAssetsCreatedByThisAccount .map(|asset_definition_entry| asset_definition_entry.registered_by() == authority) .unwrap_or(false); if !registered_by_signer_account { - return Err("Can't mint assets registered by other accounts.".to_owned()); + return Err("Can't mint assets registered by other accounts." + .to_owned() + .into()); } Ok(()) } @@ -48,18 +50,18 @@ impl IsAllowed for OnlyAssetsCreatedByThisAccount /// Allows minting assets from a different account if the corresponding user granted the permission token /// for a specific asset. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantedByAssetCreator; impl_from_item_for_granted_token_validator_box!(GrantedByAssetCreator); -impl HasToken for GrantedByAssetCreator { +impl HasToken for GrantedByAssetCreator { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let mint_box = if let Instruction::Mint(mint) = instruction { mint } else { @@ -80,18 +82,18 @@ impl HasToken for GrantedByAssetCreator { /// Validator that checks Grant instruction so that the access is granted to the assets /// of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantRegisteredByMeAccess; impl_from_item_for_grant_instruction_validator_box!(GrantRegisteredByMeAccess); -impl IsGrantAllowed for GrantRegisteredByMeAccess { - fn check_grant( +impl IsGrantAllowed for GrantRegisteredByMeAccess { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanMintUserAssetDefinitions = extract_specialized_token(instruction, wsv)?; check_asset_creator_for_asset_definition(&token.asset_definition_id, authority, wsv) } diff --git a/permissions_validators/src/public_blockchain/mod.rs b/permissions_validators/src/public_blockchain/mod.rs index 474cc6793cc..6bf8e16577d 100644 --- a/permissions_validators/src/public_blockchain/mod.rs +++ b/permissions_validators/src/public_blockchain/mod.rs @@ -1,5 +1,6 @@ //! Permission checks asociated with use cases that can be summarized as public blockchains. +use iroha_core::smartcontracts::permissions::Result; use iroha_macro::FromVariant; use iroha_schema::IntoSchema; use parity_scale_codec::{Decode, Encode}; @@ -64,23 +65,23 @@ impl From for PermissionToken { } /// A preconfigured set of permissions for simple use cases. -pub fn default_permissions() -> IsInstructionAllowedBoxed { +pub fn default_permissions() -> IsInstructionAllowedBoxed { // Grant instruction checks are or unioned, so that if one permission validator approves this Grant it will succeed. - let grant_instruction_validator = ValidatorBuilder::new() - .with_validator(transfer::GrantMyAssetAccess) - .with_validator(unregister::GrantRegisteredByMeAccess) - .with_validator(mint::GrantRegisteredByMeAccess) - .with_validator(burn::GrantMyAssetAccess) - .with_validator(burn::GrantRegisteredByMeAccess) - .with_validator(key_value::GrantMyAssetAccessRemove) - .with_validator(key_value::GrantMyAssetAccessSet) - .with_validator(key_value::GrantMyMetadataAccessSet) - .with_validator(key_value::GrantMyMetadataAccessRemove) - .with_validator(key_value::GrantMyAssetDefinitionSet) - .with_validator(key_value::GrantMyAssetDefinitionRemove) - .any_should_succeed("Grant instruction validator."); - ValidatorBuilder::new() - .with_recursive_validator(grant_instruction_validator) + let grant_instruction_validator: IsInstructionAllowedBoxed = + ValidatorBuilder::with_validator(transfer::GrantMyAssetAccess) + .with_validator(unregister::GrantRegisteredByMeAccess) + .with_validator(mint::GrantRegisteredByMeAccess) + .with_validator(burn::GrantMyAssetAccess) + .with_validator(burn::GrantRegisteredByMeAccess) + .with_validator(key_value::GrantMyAssetAccessRemove) + .with_validator(key_value::GrantMyAssetAccessSet) + .with_validator(key_value::GrantMyMetadataAccessSet) + .with_validator(key_value::GrantMyMetadataAccessRemove) + .with_validator(key_value::GrantMyAssetDefinitionSet) + .with_validator(key_value::GrantMyAssetDefinitionRemove) + .any_should_succeed("Grant instruction validator.".to_owned()) + .build(); + ValidatorBuilder::with_recursive_validator(grant_instruction_validator) .with_recursive_validator(transfer::OnlyOwnedAssets.or(transfer::GrantedByAssetOwner)) .with_recursive_validator( unregister::OnlyAssetsCreatedByThisAccount.or(unregister::GrantedByAssetCreator), @@ -113,6 +114,7 @@ pub fn default_permissions() -> IsInstructionAllowedBoxed { .or(key_value::RemoveGrantedByAssetDefinitionOwner), ) .all_should_succeed() + .build() } /// Extracts specialized token from `GrantBox` @@ -121,13 +123,9 @@ pub fn default_permissions() -> IsInstructionAllowedBoxed { /// - Cannot evaluate `instruction` /// - `instruction` doesn't evaluate to `PermissionToken` /// - Generic `PermissionToken` can't be converted to requested specialized token. -pub fn extract_specialized_token( - instruction: &GrantBox, - wsv: &WorldStateView, -) -> Result +pub fn extract_specialized_token(instruction: &GrantBox, wsv: &WorldStateView) -> Result where T: TryFrom, - W: iroha_core::wsv::WorldTrait, { let permission_token: PermissionToken = instruction .object @@ -147,17 +145,21 @@ where /// /// # Errors /// - Asset creator is not `authority` -pub fn check_asset_creator_for_asset_definition( +pub fn check_asset_creator_for_asset_definition( definition_id: &AssetDefinitionId, authority: &AccountId, - wsv: &WorldStateView, -) -> Result<(), String> { + wsv: &WorldStateView, +) -> Result<()> { let registered_by_signer_account = wsv .asset_definition_entry(definition_id) .map(|asset_definition_entry| asset_definition_entry.registered_by() == authority) .unwrap_or(false); if !registered_by_signer_account { - return Err("Can not grant access for assets, registered by another account.".to_owned()); + return Err( + "Can not grant access for assets, registered by another account." + .to_owned() + .into(), + ); } Ok(()) } @@ -188,7 +190,7 @@ mod tests { AssetDefinitionId::from_str("xor#test").expect("Valid"), AccountId::from_str("bob@test").expect("Valid"), ); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let transfer = Instruction::Transfer(TransferBox { source_id: IdBox::AssetId(alice_xor_id).into(), object: Value::U32(10).into(), @@ -219,13 +221,13 @@ mod tests { assert!(bob_account .add_permission(transfer::CanTransferUserAssets::new(alice_xor_id.clone()).into())); assert!(domain.add_account(bob_account).is_none()); - let wsv = WorldStateView::::new(World::with([domain], BTreeSet::new())); + let wsv = WorldStateView::new(World::with([domain], BTreeSet::new())); let transfer = Instruction::Transfer(TransferBox { source_id: IdBox::AssetId(alice_xor_id).into(), object: Value::U32(10).into(), destination_id: IdBox::AssetId(bob_xor_id).into(), }); - let validator: IsInstructionAllowedBoxed = transfer::OnlyOwnedAssets + let validator: IsInstructionAllowedBoxed = transfer::OnlyOwnedAssets .or(transfer::GrantedByAssetOwner) .into(); assert!(validator.check(&alice_id, &transfer, &wsv).is_ok()); @@ -242,12 +244,12 @@ mod tests { ); let permission_token_to_alice: PermissionToken = transfer::CanTransferUserAssets::new(alice_xor_id).into(); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let grant = Instruction::Grant(GrantBox::new( permission_token_to_alice, IdBox::AccountId(bob_id.clone()), )); - let validator: IsInstructionAllowedBoxed = transfer::GrantMyAssetAccess.into(); + let validator: IsInstructionAllowedBoxed = transfer::GrantMyAssetAccess.into(); assert!(validator.check(&alice_id, &grant, &wsv).is_ok()); assert!(validator.check(&bob_id, &grant, &wsv).is_err()); } @@ -263,7 +265,7 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let unregister = Instruction::Unregister(UnregisterBox::new(IdBox::AssetDefinitionId(xor_id))); assert!(unregister::OnlyAssetsCreatedByThisAccount @@ -289,12 +291,11 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let instruction = Instruction::Unregister(UnregisterBox::new(xor_id)); - let validator: IsInstructionAllowedBoxed = - unregister::OnlyAssetsCreatedByThisAccount - .or(unregister::GrantedByAssetCreator) - .into(); + let validator: IsInstructionAllowedBoxed = unregister::OnlyAssetsCreatedByThisAccount + .or(unregister::GrantedByAssetCreator) + .into(); assert!(validator.check(&alice_id, &instruction, &wsv).is_ok()); assert!(validator.check(&bob_id, &instruction, &wsv).is_ok()); } @@ -312,13 +313,12 @@ mod tests { .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let grant = Instruction::Grant(GrantBox { object: permission_token_to_alice.into(), destination_id: IdBox::AccountId(bob_id.clone()).into(), }); - let validator: IsInstructionAllowedBoxed = - unregister::GrantRegisteredByMeAccess.into(); + let validator: IsInstructionAllowedBoxed = unregister::GrantRegisteredByMeAccess.into(); assert!(validator.check(&alice_id, &grant, &wsv).is_ok()); assert!(validator.check(&bob_id, &grant, &wsv).is_err()); } @@ -338,7 +338,7 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let mint = Instruction::Mint(MintBox { object: Value::U32(100).into(), destination_id: IdBox::AssetId(alice_xor_id).into(), @@ -368,12 +368,12 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let instruction = Instruction::Mint(MintBox { object: Value::U32(100).into(), destination_id: IdBox::AssetId(alice_xor_id).into(), }); - let validator: IsInstructionAllowedBoxed = mint::OnlyAssetsCreatedByThisAccount + let validator: IsInstructionAllowedBoxed = mint::OnlyAssetsCreatedByThisAccount .or(mint::GrantedByAssetCreator) .into(); assert!(validator.check(&alice_id, &instruction, &wsv).is_ok()); @@ -392,12 +392,12 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], vec![])); + let wsv = WorldStateView::new(World::with([domain], vec![])); let grant = Instruction::Grant(GrantBox { object: permission_token_to_alice.into(), destination_id: IdBox::AccountId(bob_id.clone()).into(), }); - let validator: IsInstructionAllowedBoxed = mint::GrantRegisteredByMeAccess.into(); + let validator: IsInstructionAllowedBoxed = mint::GrantRegisteredByMeAccess.into(); assert!(validator.check(&alice_id, &grant, &wsv).is_ok()); assert!(validator.check(&bob_id, &grant, &wsv).is_err()); } @@ -417,7 +417,7 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let burn = Instruction::Burn(BurnBox { object: Value::U32(100).into(), destination_id: IdBox::AssetId(alice_xor_id).into(), @@ -447,12 +447,12 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], vec![])); + let wsv = WorldStateView::new(World::with([domain], vec![])); let instruction = Instruction::Burn(BurnBox { object: Value::U32(100).into(), destination_id: IdBox::AssetId(alice_xor_id).into(), }); - let validator: IsInstructionAllowedBoxed = burn::OnlyAssetsCreatedByThisAccount + let validator: IsInstructionAllowedBoxed = burn::OnlyAssetsCreatedByThisAccount .or(burn::GrantedByAssetCreator) .into(); assert!(validator.check(&alice_id, &instruction, &wsv).is_ok()); @@ -471,12 +471,12 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], vec![])); + let wsv = WorldStateView::new(World::with([domain], vec![])); let grant = Instruction::Grant(GrantBox { object: permission_token_to_alice.into(), destination_id: IdBox::AccountId(bob_id.clone()).into(), }); - let validator: IsInstructionAllowedBoxed = burn::GrantRegisteredByMeAccess.into(); + let validator: IsInstructionAllowedBoxed = burn::GrantRegisteredByMeAccess.into(); assert!(validator.check(&alice_id, &grant, &wsv).is_ok()); assert!(validator.check(&bob_id, &grant, &wsv).is_err()); } @@ -489,7 +489,7 @@ mod tests { AssetDefinitionId::from_str("xor#test").expect("Valid"), AccountId::from_str("alice@test").expect("Valid"), ); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let burn = Instruction::Burn(BurnBox { object: Value::U32(100).into(), destination_id: IdBox::AssetId(alice_xor_id).into(), @@ -499,7 +499,7 @@ mod tests { } #[test] - fn burn_granted_assets() -> Result<(), String> { + fn burn_granted_assets() -> Result<()> { let alice_id = AccountId::from_str("alice@test").expect("Valid"); let bob_id = AccountId::from_str("bob@test").expect("Valid"); let alice_xor_id = ::Id::new( @@ -512,12 +512,12 @@ mod tests { bob_account.add_permission(burn::CanBurnUserAssets::new(alice_xor_id.clone()).into()) ); assert!(domain.add_account(bob_account).is_none()); - let wsv = WorldStateView::::new(World::with([domain], vec![])); + let wsv = WorldStateView::new(World::with([domain], vec![])); let transfer = Instruction::Burn(BurnBox { object: Value::U32(10).into(), destination_id: IdBox::AssetId(alice_xor_id).into(), }); - let validator: IsInstructionAllowedBoxed = + let validator: IsInstructionAllowedBoxed = burn::OnlyOwnedAssets.or(burn::GrantedByAssetOwner).into(); validator.check(&alice_id, &transfer, &wsv)?; assert!(validator.check(&bob_id, &transfer, &wsv).is_ok()); @@ -534,12 +534,12 @@ mod tests { ); let permission_token_to_alice: PermissionToken = burn::CanBurnUserAssets::new(alice_xor_id).into(); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let grant = Instruction::Grant(GrantBox::new( permission_token_to_alice, IdBox::AccountId(bob_id.clone()), )); - let validator: IsInstructionAllowedBoxed = burn::GrantMyAssetAccess.into(); + let validator: IsInstructionAllowedBoxed = burn::GrantMyAssetAccess.into(); assert!(validator.check(&alice_id, &grant, &wsv).is_ok()); assert!(validator.check(&bob_id, &grant, &wsv).is_err()); } @@ -552,7 +552,7 @@ mod tests { AssetDefinitionId::from_str("xor#test").expect("Valid"), AccountId::from_str("alice@test").expect("Valid"), ); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let set = Instruction::SetKeyValue(SetKeyValueBox::new( IdBox::AssetId(alice_xor_id), Value::from("key".to_owned()), @@ -574,7 +574,7 @@ mod tests { AssetDefinitionId::from_str("xor#test").expect("Valid"), AccountId::from_str("alice@test").expect("Valid"), ); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let set = Instruction::RemoveKeyValue(RemoveKeyValueBox::new( IdBox::AssetId(alice_xor_id), Value::from("key".to_owned()), @@ -591,7 +591,7 @@ mod tests { fn set_to_only_owned_account() { let alice_id = AccountId::from_str("alice@test").expect("Valid"); let bob_id = AccountId::from_str("bob@test").expect("Valid"); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let set = Instruction::SetKeyValue(SetKeyValueBox::new( IdBox::AccountId(alice_id.clone()), Value::from("key".to_owned()), @@ -609,7 +609,7 @@ mod tests { fn remove_to_only_owned_account() { let alice_id = AccountId::from_str("alice@test").expect("Valid"); let bob_id = AccountId::from_str("bob@test").expect("Valid"); - let wsv = WorldStateView::::new(World::new()); + let wsv = WorldStateView::new(World::new()); let set = Instruction::RemoveKeyValue(RemoveKeyValueBox::new( IdBox::AccountId(alice_id.clone()), Value::from("key".to_owned()), @@ -633,7 +633,7 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let set = Instruction::SetKeyValue(SetKeyValueBox::new( IdBox::AssetDefinitionId(xor_id), Value::from("key".to_owned()), @@ -658,7 +658,7 @@ mod tests { assert!(domain .add_asset_definition(xor_definition, alice_id.clone()) .is_none()); - let wsv = WorldStateView::::new(World::with([domain], [])); + let wsv = WorldStateView::new(World::with([domain], [])); let set = Instruction::RemoveKeyValue(RemoveKeyValueBox::new( IdBox::AssetDefinitionId(xor_id), Value::from("key".to_owned()), diff --git a/permissions_validators/src/public_blockchain/transfer.rs b/permissions_validators/src/public_blockchain/transfer.rs index 5f41a0c7923..d4796bc1dde 100644 --- a/permissions_validators/src/public_blockchain/transfer.rs +++ b/permissions_validators/src/public_blockchain/transfer.rs @@ -26,18 +26,18 @@ declare_token!( ); /// Checks that account transfers only the assets that he owns. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyOwnedAssets; impl_from_item_for_instruction_validator_box!(OnlyOwnedAssets); -impl IsAllowed for OnlyOwnedAssets { +impl IsAllowed for OnlyOwnedAssets { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let transfer_box = if let Instruction::Transfer(transfer) = instruction { transfer } else { @@ -50,7 +50,9 @@ impl IsAllowed for OnlyOwnedAssets { let source_id: AssetId = try_into_or_exit!(source_id); if &source_id.account_id != authority { - return Err("Can't transfer assets of the other account.".to_owned()); + return Err("Can't transfer assets of the other account." + .to_owned() + .into()); } Ok(()) } @@ -58,18 +60,18 @@ impl IsAllowed for OnlyOwnedAssets { /// Allows transfering user's assets from a different account if the /// corresponding user granted this permission token. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantedByAssetOwner; impl_from_item_for_granted_token_validator_box!(GrantedByAssetOwner); -impl HasToken for GrantedByAssetOwner { +impl HasToken for GrantedByAssetOwner { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let transfer_box = if let Instruction::Transfer(transfer_box) = instruction { transfer_box } else { @@ -90,22 +92,26 @@ impl HasToken for GrantedByAssetOwner { /// Validator that checks Grant instruction so that the access is /// granted to the assets of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantMyAssetAccess; impl_from_item_for_grant_instruction_validator_box!(GrantMyAssetAccess); -impl IsGrantAllowed for GrantMyAssetAccess { - fn check_grant( +impl IsGrantAllowed for GrantMyAssetAccess { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanTransferUserAssets = extract_specialized_token(instruction, wsv)?; if &token.asset_id.account_id != authority { - return Err("Asset specified in permission token is not owned by signer.".to_owned()); + return Err( + "Asset specified in permission token is not owned by signer." + .to_owned() + .into(), + ); } Ok(()) @@ -114,19 +120,19 @@ impl IsGrantAllowed for GrantMyAssetAccess { /// Validator that checks that `Transfer` instruction execution count /// fits well in some time period -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct ExecutionCountFitsInLimit; impl_from_item_for_instruction_validator_box!(ExecutionCountFitsInLimit); -impl IsAllowed for ExecutionCountFitsInLimit { +impl IsAllowed for ExecutionCountFitsInLimit { #[allow(clippy::expect_used, clippy::unwrap_in_result)] fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { if !matches!(instruction, Instruction::Transfer(_)) { return Ok(()); }; @@ -142,9 +148,9 @@ impl IsAllowed for ExecutionCountFitsInLimit { .try_into() .expect("`usize` should always fit in `u32`"); if executions_count >= count { - return Err(DenialReason::from( - "Transfer transaction limit for current period is exceed", - )); + return Err("Transfer transaction limit for current period is exceed" + .to_owned() + .into()); } Ok(()) } @@ -155,10 +161,10 @@ impl IsAllowed for ExecutionCountFitsInLimit { /// /// # Errors /// - Account doesn't exist -fn retrieve_permission_params( - wsv: &WorldStateView, +fn retrieve_permission_params( + wsv: &WorldStateView, authority: &AccountId, -) -> Result, DenialReason> { +) -> Result> { wsv.map_account(authority, |account| { wsv.account_permission_tokens(account) .iter() @@ -167,7 +173,7 @@ fn retrieve_permission_params( .map(|(name, value)| (name.clone(), value.clone())) .collect() }) - .map_err(|e| e.to_string()) + .map_err(|e| e.to_string().into()) } /// Retrieve period from `params` @@ -176,7 +182,7 @@ fn retrieve_permission_params( /// - There is no period parameter /// - Period has wrong value type /// - Failed conversion from `u128` to `u64` -fn retrieve_period(params: &BTreeMap) -> Result { +fn retrieve_period(params: &BTreeMap) -> Result { let period_param_name = CanTransferOnlyFixedNumberOfTimesPerPeriod::period(); match params .get(period_param_name) @@ -185,9 +191,10 @@ fn retrieve_period(params: &BTreeMap) -> Result Ok(Duration::from_millis( u64::try_from(*period).map_err(|e| e.to_string())?, )), - _ => Err(format!( - "`{period_param_name}` parameter has wrong value type. Expected `u128`", - )), + _ => Err( + format!("`{period_param_name}` parameter has wrong value type. Expected `u128`",) + .into(), + ), } } @@ -196,25 +203,21 @@ fn retrieve_period(params: &BTreeMap) -> Result) -> Result { +fn retrieve_count(params: &BTreeMap) -> Result { let count_param_name = CanTransferOnlyFixedNumberOfTimesPerPeriod::count(); match params .get(count_param_name) .ok_or_else(|| format!("Expected `{count_param_name}` parameter"))? { Value::U32(count) => Ok(*count), - _ => Err(format!( - "`{count_param_name}` parameter has wrong value type. Expected `u32`" - )), + _ => Err( + format!("`{count_param_name}` parameter has wrong value type. Expected `u32`").into(), + ), } } /// Counts the number of `Transfer`s which happened in the last `period` -fn count_executions( - wsv: &WorldStateView, - authority: &AccountId, - period: Duration, -) -> usize { +fn count_executions(wsv: &WorldStateView, authority: &AccountId, period: Duration) -> usize { let period_start_ms = current_time().saturating_sub(period).as_millis(); wsv.blocks() diff --git a/permissions_validators/src/public_blockchain/unregister.rs b/permissions_validators/src/public_blockchain/unregister.rs index 0a11b53dd80..c88d1732724 100644 --- a/permissions_validators/src/public_blockchain/unregister.rs +++ b/permissions_validators/src/public_blockchain/unregister.rs @@ -14,18 +14,18 @@ declare_token!( /// Checks that account can un-register only the assets which were /// registered by this account in the first place. -#[derive(Debug, Copy, Clone)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct OnlyAssetsCreatedByThisAccount; impl_from_item_for_instruction_validator_box!(OnlyAssetsCreatedByThisAccount); -impl IsAllowed for OnlyAssetsCreatedByThisAccount { +impl IsAllowed for OnlyAssetsCreatedByThisAccount { fn check( &self, authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let unregister_box = if let Instruction::Unregister(unregister) = instruction { unregister } else { @@ -41,7 +41,9 @@ impl IsAllowed for OnlyAssetsCreatedByThisAccount .map(|asset_definition_entry| asset_definition_entry.registered_by() == authority) .unwrap_or(false); if !registered_by_signer_account { - return Err("Can't unregister assets registered by other accounts.".to_owned()); + return Err("Can't unregister assets registered by other accounts." + .to_owned() + .into()); } Ok(()) } @@ -50,18 +52,18 @@ impl IsAllowed for OnlyAssetsCreatedByThisAccount /// Allows un-registering a user's assets from a different account if /// the corresponding user granted the permission token for a specific /// asset. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantedByAssetCreator; impl_from_item_for_granted_token_validator_box!(GrantedByAssetCreator); -impl HasToken for GrantedByAssetCreator { +impl HasToken for GrantedByAssetCreator { fn token( &self, _authority: &AccountId, instruction: &Instruction, - wsv: &WorldStateView, - ) -> Result { + wsv: &WorldStateView, + ) -> std::result::Result { let unregister_box = if let Instruction::Unregister(unregister) = instruction { unregister } else { @@ -82,18 +84,18 @@ impl HasToken for GrantedByAssetCreator { /// Validator that checks Grant instruction so that the access is /// granted to the assets of the signer account. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Copy, Clone, Serialize)] pub struct GrantRegisteredByMeAccess; impl_from_item_for_grant_instruction_validator_box!(GrantRegisteredByMeAccess); -impl IsGrantAllowed for GrantRegisteredByMeAccess { - fn check_grant( +impl IsGrantAllowed for GrantRegisteredByMeAccess { + fn check( &self, authority: &AccountId, instruction: &GrantBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let token: CanUnregisterAssetWithDefinition = extract_specialized_token(instruction, wsv)?; check_asset_creator_for_asset_definition(&token.asset_definition_id, authority, wsv) } @@ -102,18 +104,18 @@ impl IsGrantAllowed for GrantRegisteredByMeAccess { /// Validator that checks Revoke instructions, such that the access is /// revoked and the assets of the signer's account are no longer /// accessible. -#[derive(Debug, Clone, Copy)] +#[derive(Debug, Clone, Copy, Serialize)] pub struct RevokeRegisteredByMeAccess; impl_from_item_for_revoke_instruction_validator_box!(RevokeRegisteredByMeAccess); -impl IsRevokeAllowed for RevokeRegisteredByMeAccess { - fn check_revoke( +impl IsRevokeAllowed for RevokeRegisteredByMeAccess { + fn check( &self, authority: &AccountId, instruction: &RevokeBox, - wsv: &WorldStateView, - ) -> Result<(), DenialReason> { + wsv: &WorldStateView, + ) -> Result<()> { let permission_token: PermissionToken = instruction .object .evaluate(wsv, &Context::new()) diff --git a/telemetry/derive/src/lib.rs b/telemetry/derive/src/lib.rs index 4b8c93af23d..5dbab9cf2d2 100644 --- a/telemetry/derive/src/lib.rs +++ b/telemetry/derive/src/lib.rs @@ -140,7 +140,7 @@ impl ToTokens for MetricSpec { /// use iroha_telemetry_derive::metrics; /// /// #[metrics(+"test_query", "another_test_query_without_timing")] -/// fn execute(wsv: &WorldStateView) -> Result<(), ()> { +/// fn execute(wsv: &WorldStateView) -> Result<(), ()> { /// Ok(()) /// } /// ``` diff --git a/telemetry/derive/tests/ui_fail/args_no_wsv.rs b/telemetry/derive/tests/ui_fail/args_no_wsv.rs index 55d6accbfe6..362b2ade6e0 100644 --- a/telemetry/derive/tests/ui_fail/args_no_wsv.rs +++ b/telemetry/derive/tests/ui_fail/args_no_wsv.rs @@ -1,4 +1,4 @@ -use iroha_core::wsv::{World, WorldStateView}; +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", "another_test_query_without_timing")] @@ -7,5 +7,5 @@ fn execute(_wsv: &World) -> Result<(), ()> { } fn main() { - let _world = WorldStateView::::default(); + let _world = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/bare_spec.rs b/telemetry/derive/tests/ui_fail/bare_spec.rs index 9a866b63abf..fc2b56e7c30 100644 --- a/telemetry/derive/tests/ui_fail/bare_spec.rs +++ b/telemetry/derive/tests/ui_fail/bare_spec.rs @@ -1,11 +1,11 @@ -use iroha_core::wsv::{World, WorldStateView}; +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(test_query, "another_test_query_without_timing")] -fn execute(wsv: &iroha_core::wsv::WorldStateView) -> Result<(), ()> { +fn execute(wsv: &WorldStateView) -> Result<(), ()> { Ok(()) } fn main() { - let _world = WorldStateView::::default(); + let _world = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/doubled_plus.rs b/telemetry/derive/tests/ui_fail/doubled_plus.rs index 8c7abeb485e..59d028f1801 100644 --- a/telemetry/derive/tests/ui_fail/doubled_plus.rs +++ b/telemetry/derive/tests/ui_fail/doubled_plus.rs @@ -1,11 +1,11 @@ -use iroha_core::wsv::{World, WorldStateView}; +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", ++"another_test_query_without_timing")] -fn execute(wsv: &iroha_core::wsv::WorldStateView) -> Result<(), ()> { +fn execute(wsv: &WorldStateView) -> Result<(), ()> { Ok(()) } fn main() { - let _world = WorldStateView::::default(); + let _world = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/no_args.rs b/telemetry/derive/tests/ui_fail/no_args.rs index 76c779cfc52..af5b81013ba 100644 --- a/telemetry/derive/tests/ui_fail/no_args.rs +++ b/telemetry/derive/tests/ui_fail/no_args.rs @@ -1,4 +1,4 @@ -use iroha_core::wsv::{World, WorldStateView}; +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", "another_test_query_without_timing")] @@ -7,5 +7,5 @@ fn execute() -> Result<(), ()> { } fn main() { - let _world = WorldStateView::::default(); + let _world = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/non_snake_case_name.rs b/telemetry/derive/tests/ui_fail/non_snake_case_name.rs index 9cd16819b8c..065cf621c56 100644 --- a/telemetry/derive/tests/ui_fail/non_snake_case_name.rs +++ b/telemetry/derive/tests/ui_fail/non_snake_case_name.rs @@ -1,9 +1,9 @@ -#![allow(unused_imports)] -use iroha_core::wsv::{World, WorldStateView}; +#![allow(unused_imports)] // Unused because macro will no generate anything +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(+"test query", "another_test_query_without_timing")] -fn execute(wsv: &WorldStateView) -> Result<(), ()> { +fn execute(wsv: &WorldStateView) -> Result<(), ()> { Ok(()) } diff --git a/telemetry/derive/tests/ui_fail/not_execute.rs b/telemetry/derive/tests/ui_fail/not_execute.rs index 404a447ffe1..22ccfd434a5 100644 --- a/telemetry/derive/tests/ui_fail/not_execute.rs +++ b/telemetry/derive/tests/ui_fail/not_execute.rs @@ -2,11 +2,11 @@ use iroha_core::wsv::{World, WorldStateView}; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", "another_test_query_without_timing")] -fn exequte(wsv: &WorldStateView) -> Result<(), ()> { +fn exequte(wsv: &WorldStateView) -> Result<(), ()> { Ok(()) } fn main() { let _something: World = World::default(); - let _something_else = WorldStateView::::default(); + let _something_else = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/not_execute.stderr b/telemetry/derive/tests/ui_fail/not_execute.stderr index e7d37bc7cbe..4146a4ab62b 100644 --- a/telemetry/derive/tests/ui_fail/not_execute.stderr +++ b/telemetry/derive/tests/ui_fail/not_execute.stderr @@ -1,5 +1,5 @@ error: Function should be an `impl execute` --> tests/ui_fail/not_execute.rs:5:4 | -5 | fn exequte(wsv: &WorldStateView) -> Result<(), ()> { +5 | fn exequte(wsv: &WorldStateView) -> Result<(), ()> { | ^^^^^^^ diff --git a/telemetry/derive/tests/ui_fail/not_return_result.rs b/telemetry/derive/tests/ui_fail/not_return_result.rs index 80840ca9893..d1783da2177 100644 --- a/telemetry/derive/tests/ui_fail/not_return_result.rs +++ b/telemetry/derive/tests/ui_fail/not_return_result.rs @@ -2,12 +2,12 @@ use iroha_core::wsv::{World, WorldStateView}; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", "another_test_query_without_timing")] -fn execute(_wsv: &WorldStateView) -> iroha_core::RESULT { +fn execute(_wsv: &WorldStateView) -> iroha_core::RESULT { Ok(()) } fn main() { let _something: World = World::default(); - let _something_else = WorldStateView::::default(); + let _something_else = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/not_return_result.stderr b/telemetry/derive/tests/ui_fail/not_return_result.stderr index 1c91fe8b70d..37ef12869a2 100644 --- a/telemetry/derive/tests/ui_fail/not_return_result.stderr +++ b/telemetry/derive/tests/ui_fail/not_return_result.stderr @@ -1,5 +1,5 @@ error: Should return `Result`. Found RESULT - --> tests/ui_fail/not_return_result.rs:5:57 + --> tests/ui_fail/not_return_result.rs:5:50 | -5 | fn execute(_wsv: &WorldStateView) -> iroha_core::RESULT { - | ^^^^^^ +5 | fn execute(_wsv: &WorldStateView) -> iroha_core::RESULT { + | ^^^^^^ diff --git a/telemetry/derive/tests/ui_fail/return_nothing.rs b/telemetry/derive/tests/ui_fail/return_nothing.rs index 68b94a199b3..0a9bd4b25d1 100644 --- a/telemetry/derive/tests/ui_fail/return_nothing.rs +++ b/telemetry/derive/tests/ui_fail/return_nothing.rs @@ -1,11 +1,11 @@ -use iroha_core::wsv::{World, WorldStateView}; +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", "another_test_query_without_timing")] -fn execute(wsv: &iroha_core::wsv::WorldStateView) { +fn execute(wsv: &WorldStateView) { Ok(()) } fn main() { - let _world = WorldStateView::::default(); + let _world = WorldStateView::default(); } diff --git a/telemetry/derive/tests/ui_fail/trailing_plus.rs b/telemetry/derive/tests/ui_fail/trailing_plus.rs index d837e432187..b3cfa74f9aa 100644 --- a/telemetry/derive/tests/ui_fail/trailing_plus.rs +++ b/telemetry/derive/tests/ui_fail/trailing_plus.rs @@ -1,11 +1,11 @@ -use iroha_core::wsv::{World, WorldStateView}; +use iroha_core::wsv::WorldStateView; use iroha_telemetry_derive::metrics; #[metrics(+"test_query", "another_test_query_without_timing"+)] -fn execute(wsv: &iroha_core::wsv::WorldStateView) -> Result<(), ()> { +fn execute(wsv: &WorldStateView) -> Result<(), ()> { Ok(()) } fn main() { - let _world = WorldStateView::::default(); + let _world = WorldStateView::default(); } diff --git a/tools/parity_scale_decoder/src/generate_map.rs b/tools/parity_scale_decoder/src/generate_map.rs index 5116e2a4c55..d639a525d79 100644 --- a/tools/parity_scale_decoder/src/generate_map.rs +++ b/tools/parity_scale_decoder/src/generate_map.rs @@ -79,8 +79,6 @@ pub fn generate_map() -> DumpDecodedMap { AssetValue, AssetValueType, AtomicU32, - BlockValue, - BlockHeaderValue, BTreeMap, BTreeMap, BTreeMap, @@ -94,7 +92,9 @@ pub fn generate_map() -> DumpDecodedMap { BTreeSet>, BTreeSet>, BTreeSet, + BlockHeaderValue, BlockRejectionReason, + BlockValue, BurnBox, Contains, ContainsAll, @@ -144,16 +144,16 @@ pub fn generate_map() -> DumpDecodedMap { FindAccountsByName, FindAccountsWithAsset, FindAllAccounts, + FindAllActiveTriggerIds, FindAllAssets, FindAllAssetsDefinitions, + FindAllBlocks, FindAllDomains, FindAllParameters, FindAllPeers, - FindAllRoles, FindAllRoleIds, - FindAllBlocks, + FindAllRoles, FindAllTransactions, - FindAllActiveTriggerIds, FindAssetById, FindAssetDefinitionById, FindAssetDefinitionKeyValueByIdAndKey, @@ -167,20 +167,20 @@ pub fn generate_map() -> DumpDecodedMap { FindDomainById, FindDomainKeyValueByIdAndKey, FindPermissionTokensByAccountId, - FindRolesByAccountId, FindRoleByRoleId, + FindRolesByAccountId, FindTransactionByHash, FindTransactionsByAccountId, + FindTriggerById, FindTriggerKeyValueByIdAndKey, FindTriggersByDomainId, - FindTriggerById, GenesisDomain, GrantBox, Greater, Hash, + HashOf>, HashOf, HashOf, - HashOf>, HashOf, HashOf, IdBox, @@ -215,10 +215,10 @@ pub fn generate_map() -> DumpDecodedMap { Option, Option, Or, + PaginatedQueryResult, + Pagination, Pair, Parameter, - Pagination, - PaginatedQueryResult, Peer, PeerEvent, PeerEventFilter, @@ -291,22 +291,23 @@ pub fn generate_map() -> DumpDecodedMap { Vec, Vec, Vec, + Vec, Vec, Vec, - Vec, Vec, + VersionedPaginatedQueryResult, VersionedPendingTransactions, VersionedQueryResult, VersionedRejectedTransaction, VersionedSignedQueryRequest, VersionedTransaction, VersionedValidTransaction, - VersionedPaginatedQueryResult, WasmExecutionFail, Where, + [u8; 32], account::NewAccount, - asset::NewAssetDefinition, asset::Mintable, + asset::NewAssetDefinition, block::BlockHeader, block::CommittedBlock, block::ValidBlock, @@ -322,9 +323,9 @@ pub fn generate_map() -> DumpDecodedMap { domain::NewDomain, error::Error, events::Event, - events::FilterBox, events::EventPublisherMessage, events::EventSubscriberMessage, + events::FilterBox, events::VersionedEventPublisherMessage, events::VersionedEventSubscriberMessage, events::pipeline::StatusKind, @@ -336,17 +337,20 @@ pub fn generate_map() -> DumpDecodedMap { expression::EvaluatesTo, expression::EvaluatesTo, expression::EvaluatesTo, + expression::EvaluatesTo, + expression::EvaluatesTo, expression::EvaluatesTo, expression::EvaluatesTo>, expression::EvaluatesTo, expression::EvaluatesTo, - expression::EvaluatesTo, - expression::EvaluatesTo, fixed::FixNum, fixed::Fixed, i64, query::Payload, smartcontracts::isi::error::FindError, + smartcontracts::isi::error::Mismatch, + smartcontracts::isi::permissions::ValidatorType, + smartcontracts::isi::permissions::error::DenialReason, smartcontracts::isi::query::Error, sumeragi::network_topology::Topology, sumeragi::view_change::BlockCreationTimeout, @@ -374,7 +378,6 @@ pub fn generate_map() -> DumpDecodedMap { u32, u64, u8, - [u8; 32], }; map.insert(