diff --git a/Cargo.lock b/Cargo.lock index 19d94018060..faa9751796b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2896,6 +2896,7 @@ name = "iroha_data_model" version = "2.0.0-pre-rc.20" dependencies = [ "base64", + "cfg-if", "criterion", "derive_more", "displaydoc", diff --git a/client/tests/integration/triggers/data_trigger.rs b/client/tests/integration/triggers/data_trigger.rs index 2c197c9da18..00b473f31af 100644 --- a/client/tests/integration/triggers/data_trigger.rs +++ b/client/tests/integration/triggers/data_trigger.rs @@ -21,15 +21,10 @@ fn must_execute_both_triggers() -> Result<()> { Repeats::Indefinitely, account_id.clone(), // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByDomain(BySome( - DomainFilter::new( - AcceptAll, - BySome(DomainEventFilter::ByAccount(BySome(AccountFilter::new( - AcceptAll, - BySome(AccountEventFilter::ByCreated), - )))), - ), - )))), + TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(AccountEventFilter { + id_matcher: None, + event_matcher: Some(AccountEventMatcher::ByCreated), + }))), ), )); test_client.submit_blocking(register_trigger)?; @@ -40,9 +35,10 @@ fn must_execute_both_triggers() -> Result<()> { [instruction], Repeats::Indefinitely, account_id, - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByDomain(BySome( - DomainFilter::new(AcceptAll, BySome(DomainEventFilter::ByCreated)), - )))), + TriggeringFilterBox::Data(BySome(DataEntityFilter::ByDomain(DomainEventFilter { + id_matcher: None, + event_matcher: Some(DomainEventMatcher::ByCreated), + }))), ), )); test_client.submit_blocking(register_trigger)?; @@ -94,15 +90,10 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu Repeats::Indefinitely, account_id, // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByDomain(BySome( - DomainFilter::new( - AcceptAll, - BySome(DomainEventFilter::ByAccount(BySome(AccountFilter::new( - AcceptAll, - BySome(AccountEventFilter::ByCreated), - )))), - ), - )))), + TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(AccountEventFilter { + id_matcher: None, + event_matcher: Some(AccountEventMatcher::ByCreated), + }))), ), )); test_client.submit_blocking(register_trigger)?; diff --git a/client/tests/integration/triggers/event_trigger.rs b/client/tests/integration/triggers/event_trigger.rs index bc340775aff..4064ad9c9db 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -25,17 +25,12 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { Repeats::Indefinitely, account_id, // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByDomain(BySome( - DomainFilter::new( - AcceptAll, - BySome(DomainEventFilter::ByAssetDefinition(BySome( - AssetDefinitionFilter::new( - AcceptAll, - BySome(AssetDefinitionEventFilter::ByCreated), - ), - ))), - ), - )))), + TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAssetDefinition( + AssetDefinitionEventFilter { + id_matcher: None, + event_matcher: Some(AssetDefinitionEventMatcher::ByCreated), + }, + ))), ), )); test_client.submit(register_trigger)?; diff --git a/core/src/smartcontracts/isi/triggers/mod.rs b/core/src/smartcontracts/isi/triggers/mod.rs index fd5459cacad..b8d41dc2b4a 100644 --- a/core/src/smartcontracts/isi/triggers/mod.rs +++ b/core/src/smartcontracts/isi/triggers/mod.rs @@ -13,7 +13,7 @@ pub mod set; /// - TODO: authority permissions. pub mod isi { use iroha_data_model::{ - events::Filter, + events::EventFilter, isi::error::{InvalidParameterError, RepetitionError}, trigger::prelude::*, }; diff --git a/core/src/smartcontracts/isi/triggers/set.rs b/core/src/smartcontracts/isi/triggers/set.rs index b8a41ea0b3e..6af4480ca82 100644 --- a/core/src/smartcontracts/isi/triggers/set.rs +++ b/core/src/smartcontracts/isi/triggers/set.rs @@ -14,7 +14,7 @@ use std::{fmt, num::NonZeroU64}; use indexmap::{map::Entry, IndexMap}; use iroha_crypto::HashOf; use iroha_data_model::{ - events::Filter as EventFilter, + events::EventFilter, isi::error::{InstructionExecutionError, MathError}, prelude::*, query::error::FindError, @@ -94,7 +94,7 @@ pub trait LoadedActionTrait { fn clone_and_box(&self) -> LoadedAction; } -impl + Clone> LoadedActionTrait for LoadedAction { +impl + Clone> LoadedActionTrait for LoadedAction { fn executable(&self) -> &LoadedExecutable { &self.executable } @@ -405,7 +405,7 @@ impl Set { /// # Errors /// /// Return [`Err`] if failed to preload wasm trigger - fn add_to( + fn add_to( &mut self, engine: &wasmtime::Engine, trigger: Trigger, @@ -705,7 +705,7 @@ impl Set { /// Note that this function doesn't remove the trigger from [`Set::ids`]. /// /// Returns `true` if trigger was removed and `false` otherwise. - fn remove_from( + fn remove_from( original_contracts: &mut WasmSmartContractMap, triggers: &mut IndexMap>, trigger_id: &TriggerId, @@ -884,7 +884,7 @@ impl Set { } /// Remove actions with zero execution count from `triggers` - fn remove_zeros( + fn remove_zeros( ids: &mut IndexMap, original_contracts: &mut WasmSmartContractMap, triggers: &mut IndexMap>, diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml index 9b80ee2b6fc..7ecd549f937 100644 --- a/data_model/Cargo.toml +++ b/data_model/Cargo.toml @@ -54,6 +54,8 @@ strum = { workspace = true, features = ["derive"] } base64 = { workspace = true, features = ["alloc"] } once_cell = { workspace = true, optional = true } +cfg-if = "1.0.0" + [dev-dependencies] trybuild = { workspace = true } criterion = { workspace = true } diff --git a/data_model/src/events/data/events.rs b/data_model/src/events/data/events.rs index c08b9e504c0..f4a18f29c43 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -2,7 +2,7 @@ #![allow(missing_docs)] use getset::Getters; -use iroha_data_model_derive::{model, Filter, HasOrigin}; +use iroha_data_model_derive::{model, HasOrigin}; pub use self::model::*; use super::*; @@ -17,7 +17,6 @@ macro_rules! data_event { Eq, PartialOrd, Ord, - Filter, HasOrigin, parity_scale_codec::Decode, parity_scale_codec::Encode, @@ -587,7 +586,7 @@ mod executor { } #[cfg(feature = "transparent_api")] - impl super::Filter for ExecutorFilter { + impl super::EventFilter for ExecutorFilter { type Event = ExecutorEvent; fn matches(&self, event: &Self::Event) -> bool { @@ -641,24 +640,18 @@ impl DataEvent { pub mod prelude { pub use super::{ - account::{ - AccountEvent, AccountEventFilter, AccountFilter, AccountPermissionChanged, - AccountRoleChanged, - }, + account::{AccountEvent, AccountPermissionChanged, AccountRoleChanged}, asset::{ - AssetChanged, AssetDefinitionEvent, AssetDefinitionEventFilter, AssetDefinitionFilter, - AssetDefinitionOwnerChanged, AssetDefinitionTotalQuantityChanged, AssetEvent, - AssetEventFilter, AssetFilter, + AssetChanged, AssetDefinitionEvent, AssetDefinitionOwnerChanged, + AssetDefinitionTotalQuantityChanged, AssetEvent, }, config::ConfigurationEvent, - domain::{DomainEvent, DomainEventFilter, DomainFilter, DomainOwnerChanged}, + domain::{DomainEvent, DomainOwnerChanged}, executor::{ExecutorEvent, ExecutorFilter}, - peer::{PeerEvent, PeerEventFilter, PeerFilter}, + peer::PeerEvent, permission::PermissionTokenSchemaUpdateEvent, - role::{PermissionRemoved, RoleEvent, RoleEventFilter, RoleFilter}, - trigger::{ - TriggerEvent, TriggerEventFilter, TriggerFilter, TriggerNumberOfExecutionsChanged, - }, + role::{PermissionRemoved, RoleEvent}, + trigger::{TriggerEvent, TriggerNumberOfExecutionsChanged}, DataEvent, HasOrigin, MetadataChanged, }; } diff --git a/data_model/src/events/data/filters.rs b/data_model/src/events/data/filters.rs index 9a4d760ea5b..d5ab3c382cb 100644 --- a/data_model/src/events/data/filters.rs +++ b/data_model/src/events/data/filters.rs @@ -1,8 +1,12 @@ //! This module contains `EventFilter` and entities for filter +// TODO write code documentation +// - possible topics to cover: EventFilter vs EventMatcher +// - how this maps to event hierarchy (events are hierarchical, but event filters are flat) +// - how to construct event filters (should be done with builder API when they are implemented) + use core::fmt::Debug; -use derive_more::Constructor; use iroha_data_model_derive::model; pub use self::model::*; @@ -45,42 +49,131 @@ pub mod model { #[derive( Debug, Clone, PartialEq, Eq, FromVariant, Decode, Encode, Deserialize, Serialize, IntoSchema, )] - #[allow(clippy::enum_variant_names)] - /// Filters event by entity pub enum DataEntityFilter { - /// Filter by Peer entity. `AcceptAll` value will accept all `Peer` events - ByPeer(FilterOpt), - /// Filter by Domain entity. `AcceptAll` value will accept all `Domain` events - ByDomain(FilterOpt), - /// Filter by Trigger entity. `AcceptAll` value will accept all `Trigger` events - ByTrigger(FilterOpt), - /// Filter by Role entity. `AcceptAll` value will accept all `Role` events - ByRole(FilterOpt), + ByPeer(PeerEventFilter), + ByDomain(DomainEventFilter), + ByAccount(AccountEventFilter), + ByAsset(AssetEventFilter), + ByAssetDefinition(AssetDefinitionEventFilter), + ByTrigger(TriggerEventFilter), + ByRole(RoleEventFilter), + // We didn't have filters for these events before the refactor. Should we? + // Configuration(ConfigurationEventFilter), + // Executor(ExecutorEventFilter), } - /// Filter that accepts a data event with the matching origin. - #[derive( - Clone, - PartialOrd, - Ord, - Eq, - Debug, - Constructor, - Decode, - Encode, - Serialize, - Deserialize, - IntoSchema, - )] - #[serde(bound( - deserialize = "<::Origin as Identifiable>::Id: Deserialize<'de>" - ))] - #[serde(transparent)] - #[repr(transparent)] - pub struct OriginFilter(pub(super) ::Id) - where - ::Id: - Debug + Clone + Eq + Ord + Decode + Encode + Serialize + IntoSchema; + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct PeerEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum PeerEventMatcher { + ByAdded, + ByRemoved, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct DomainEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum DomainEventMatcher { + ByCreated, + ByDeleted, + ByMetadataInserted, + ByMetadataRemoved, + ByOwnerChanged, + // we allow filtering for nested events, but if you need to specify an id matcher for, for example, AccountId, you need to use AccountFilter + // nested events + ByAccount, + ByAssetDefinition, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct AccountEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum AccountEventMatcher { + ByCreated, + ByDeleted, + ByAuthenticationAdded, + ByAuthenticationRemoved, + ByPermissionAdded, + ByPermissionRemoved, + ByRoleRevoked, + ByRoleGranted, + ByMetadataInserted, + ByMetadataRemoved, + // nested events + ByAsset, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct AssetEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum AssetEventMatcher { + ByCreated, + ByDeleted, + ByAdded, + ByRemoved, + ByMetadataInserted, + ByMetadataRemoved, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct AssetDefinitionEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum AssetDefinitionEventMatcher { + ByCreated, + ByMintabilityChanged, + ByOwnerChanged, + ByDeleted, + ByMetadataInserted, + ByMetadataRemoved, + ByTotalQuantityChanged, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct TriggerEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum TriggerEventMatcher { + ByCreated, + ByDeleted, + ByExtended, + ByShortened, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub struct RoleEventFilter { + pub id_matcher: Option, + pub event_matcher: Option, + } + + #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] + pub enum RoleEventMatcher { + ByCreated, + ByDeleted, + ByPermissionRemoved, + } } mod accept_all_as_string { @@ -120,7 +213,7 @@ mod accept_all_as_string { } #[cfg(feature = "transparent_api")] -impl Filter for FilterOpt { +impl EventFilter for FilterOpt { type Event = F::Event; fn matches(&self, item: &Self::Event) -> bool { @@ -132,61 +225,246 @@ impl Filter for FilterOpt { } #[cfg(feature = "transparent_api")] -impl Filter for DataEntityFilter { - type Event = DataEvent; +impl EventFilter for PeerEventFilter { + type Event = super::PeerEvent; - fn matches(&self, event: &DataEvent) -> bool { - match (self, event) { - (Self::ByPeer(filter_opt), DataEvent::Peer(peer)) => filter_opt.matches(peer), - (Self::ByDomain(filter_opt), DataEvent::Domain(domain)) => filter_opt.matches(domain), - (Self::ByTrigger(filter_opt), DataEvent::Trigger(trigger)) => { - filter_opt.matches(trigger) + fn matches(&self, event: &Self::Event) -> bool { + use PeerEventMatcher::*; + + use super::PeerEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; } - (Self::ByRole(filter_opt), DataEvent::Role(role)) => filter_opt.matches(role), - _ => false, + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByAdded, Added(_)) => true, + (ByRemoved, Removed(_)) => true, + _ => false, + } + } else { + true } } } -impl OriginFilter -where - ::Id: - Debug + Clone + Eq + Ord + Decode + Encode + Serialize + IntoSchema, -{ - /// Get the id of the origin of the data event that this filter accepts. - pub fn origin_id(&self) -> &::Id { - &self.0 +#[cfg(feature = "transparent_api")] +impl EventFilter for DomainEventFilter { + type Event = super::DomainEvent; + + fn matches(&self, event: &Self::Event) -> bool { + use DomainEventMatcher::*; + + use super::DomainEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; + } + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByCreated, Created(_)) => true, + (ByDeleted, Deleted(_)) => true, + (ByMetadataInserted, MetadataInserted(_)) => true, + (ByMetadataRemoved, MetadataRemoved(_)) => true, + (ByOwnerChanged, OwnerChanged(_)) => true, + (ByAccount, Account(_)) => true, + (ByAssetDefinition, AssetDefinition(_)) => true, + _ => false, + } + } else { + true + } } } #[cfg(feature = "transparent_api")] -impl Filter for OriginFilter -where - ::Id: - Debug + Clone + Eq + Ord + Decode + Encode + Serialize + IntoSchema, -{ - type Event = T; - - fn matches(&self, event: &T) -> bool { - event.origin_id() == self.origin_id() +impl super::EventFilter for AccountEventFilter { + type Event = super::AccountEvent; + + fn matches(&self, event: &Self::Event) -> bool { + use AccountEventMatcher::*; + + use super::AccountEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; + } + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByCreated, Created(_)) => true, + (ByDeleted, Deleted(_)) => true, + (ByAuthenticationAdded, AuthenticationAdded(_)) => true, + (ByAuthenticationRemoved, AuthenticationRemoved(_)) => true, + (ByPermissionAdded, PermissionAdded(_)) => true, + (ByPermissionRemoved, PermissionRemoved(_)) => true, + (ByRoleRevoked, RoleRevoked(_)) => true, + (ByRoleGranted, RoleGranted(_)) => true, + (ByMetadataInserted, MetadataInserted(_)) => true, + (ByMetadataRemoved, MetadataRemoved(_)) => true, + (ByAsset, Asset(_)) => true, + _ => false, + } + } else { + true + } + } +} + +#[cfg(feature = "transparent_api")] +impl super::EventFilter for AssetEventFilter { + type Event = super::AssetEvent; + + fn matches(&self, event: &Self::Event) -> bool { + use AssetEventMatcher::*; + + use super::AssetEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; + } + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByCreated, Created(_)) => true, + (ByDeleted, Deleted(_)) => true, + (ByAdded, Added(_)) => true, + (ByRemoved, Removed(_)) => true, + (ByMetadataInserted, MetadataInserted(_)) => true, + (ByMetadataRemoved, MetadataRemoved(_)) => true, + _ => false, + } + } else { + true + } + } +} + +#[cfg(feature = "transparent_api")] +impl super::EventFilter for AssetDefinitionEventFilter { + type Event = super::AssetDefinitionEvent; + + fn matches(&self, event: &Self::Event) -> bool { + use AssetDefinitionEventMatcher::*; + + use super::AssetDefinitionEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; + } + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByCreated, Created(_)) => true, + (ByMintabilityChanged, MintabilityChanged(_)) => true, + (ByOwnerChanged, OwnerChanged(_)) => true, + (ByDeleted, Deleted(_)) => true, + (ByMetadataInserted, MetadataInserted(_)) => true, + (ByMetadataRemoved, MetadataRemoved(_)) => true, + (ByTotalQuantityChanged, TotalQuantityChanged(_)) => true, + _ => false, + } + } else { + true + } + } +} + +#[cfg(feature = "transparent_api")] +impl super::EventFilter for TriggerEventFilter { + type Event = super::TriggerEvent; + + fn matches(&self, event: &Self::Event) -> bool { + use TriggerEventMatcher::*; + + use super::TriggerEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; + } + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByCreated, Created(_)) => true, + (ByDeleted, Deleted(_)) => true, + (ByExtended, Extended(_)) => true, + (ByShortened, Shortened(_)) => true, + _ => false, + } + } else { + true + } } } -impl PartialEq for OriginFilter -where - ::Id: - Debug + Clone + Eq + Ord + Decode + Encode + Serialize + IntoSchema, -{ - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 +#[cfg(feature = "transparent_api")] +impl super::EventFilter for RoleEventFilter { + type Event = super::RoleEvent; + + fn matches(&self, event: &Self::Event) -> bool { + use RoleEventMatcher::*; + + use super::RoleEvent::*; + + if let Some(id_matcher) = &self.id_matcher { + if id_matcher != event.origin_id() { + return false; + } + } + if let Some(event_matcher) = &self.event_matcher { + match (event_matcher, event) { + (ByCreated, Created(_)) => true, + (ByDeleted, Deleted(_)) => true, + (ByPermissionRemoved, PermissionRemoved(_)) => true, + _ => false, + } + } else { + true + } + } +} + +#[cfg(feature = "transparent_api")] +impl EventFilter for DataEntityFilter { + type Event = DataEvent; + + fn matches(&self, event: &DataEvent) -> bool { + use DataEntityFilter::*; + use DataEvent::*; + + match (self, event) { + (ByPeer(filter), Peer(event)) => filter.matches(event), + (ByDomain(filter), Domain(event)) => filter.matches(event), + (ByAccount(filter), Domain(DomainEvent::Account(event))) => filter.matches(event), + (ByAsset(filter), Domain(DomainEvent::Account(AccountEvent::Asset(event)))) => { + filter.matches(event) + } + (ByAssetDefinition(filter), Domain(DomainEvent::AssetDefinition(event))) => { + filter.matches(event) + } + (ByTrigger(filter), Trigger(event)) => filter.matches(event), + (ByRole(filter), Role(event)) => filter.matches(event), + _ => false, + } } } pub mod prelude { pub use super::{ - DataEntityFilter, DataEventFilter, + AccountEventFilter, AccountEventMatcher, AssetDefinitionEventFilter, + AssetDefinitionEventMatcher, AssetEventFilter, AssetEventMatcher, DataEntityFilter, + DataEventFilter, DomainEventFilter, DomainEventMatcher, FilterOpt::{self, *}, - OriginFilter, + PeerEventFilter, PeerEventMatcher, RoleEventFilter, RoleEventMatcher, TriggerEventFilter, + TriggerEventMatcher, }; } @@ -247,30 +525,18 @@ mod tests { // test how the differently nested filters with with the events // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - let domain_filter = BySome(DataEntityFilter::ByDomain(BySome(DomainFilter::new( - BySome(OriginFilter(domain_id)), - AcceptAll, - )))); - let account_filter = BySome(DataEntityFilter::ByDomain(BySome(DomainFilter::new( - // kind of unfortunately, we have to specify the domain id filter, - // even though we will filter it with the account id filter (account id contains domain id with and account name) - // FIXME: maybe make this more orthogonal by introducing a partial id (in account event filter only by account name) - AcceptAll, - BySome(DomainEventFilter::ByAccount(BySome(AccountFilter::new( - BySome(OriginFilter(account_id)), - AcceptAll, - )))), - )))); - let asset_filter = BySome(DataEntityFilter::ByDomain(BySome(DomainFilter::new( - AcceptAll, - BySome(DomainEventFilter::ByAccount(BySome(AccountFilter::new( - AcceptAll, - BySome(AccountEventFilter::ByAsset(BySome(AssetFilter::new( - BySome(OriginFilter(asset_id)), - AcceptAll, - )))), - )))), - )))); + let domain_filter = BySome(DataEntityFilter::ByDomain(DomainEventFilter { + id_matcher: Some(domain_id), + event_matcher: None, + })); + let account_filter = BySome(DataEntityFilter::ByAccount(AccountEventFilter { + id_matcher: Some(account_id), + event_matcher: None, + })); + let asset_filter = BySome(DataEntityFilter::ByAsset(AssetEventFilter { + id_matcher: Some(asset_id), + event_matcher: None, + })); // domain filter matches all of those, because all of those events happened in the same domain assert!(domain_filter.matches(&domain_created)); diff --git a/data_model/src/events/data/mod.rs b/data_model/src/events/data/mod.rs index 1c1ab8494f8..44eab65a95e 100644 --- a/data_model/src/events/data/mod.rs +++ b/data_model/src/events/data/mod.rs @@ -11,7 +11,7 @@ use parity_scale_codec::{Decode, Encode}; use serde::{Deserialize, Serialize}; #[cfg(feature = "transparent_api")] -use super::Filter; +use super::EventFilter; use crate::prelude::*; pub use crate::Registered; diff --git a/data_model/src/events/execute_trigger.rs b/data_model/src/events/execute_trigger.rs index 9b05dde3163..4825c1141b2 100644 --- a/data_model/src/events/execute_trigger.rs +++ b/data_model/src/events/execute_trigger.rs @@ -60,7 +60,7 @@ pub mod model { } #[cfg(feature = "transparent_api")] -impl Filter for ExecuteTriggerEventFilter { +impl EventFilter for ExecuteTriggerEventFilter { type Event = ExecuteTriggerEvent; /// Check if `event` matches filter diff --git a/data_model/src/events/mod.rs b/data_model/src/events/mod.rs index 37382ddcc8a..21b17ae7652 100644 --- a/data_model/src/events/mod.rs +++ b/data_model/src/events/mod.rs @@ -106,7 +106,7 @@ pub mod model { /// Trait for filters #[cfg(feature = "transparent_api")] -pub trait Filter { +pub trait EventFilter { /// Type of event that can be filtered type Event; @@ -133,7 +133,7 @@ pub trait Filter { } #[cfg(feature = "transparent_api")] -impl Filter for FilterBox { +impl EventFilter for FilterBox { type Event = Event; /// Apply filter to event. @@ -162,7 +162,7 @@ impl Filter for FilterBox { } #[cfg(feature = "transparent_api")] -impl Filter for TriggeringFilterBox { +impl EventFilter for TriggeringFilterBox { type Event = Event; /// Apply filter to event. @@ -225,7 +225,7 @@ pub mod prelude { #[cfg(feature = "http")] pub use super::stream::{EventMessage, EventSubscriptionRequest}; #[cfg(feature = "transparent_api")] - pub use super::Filter; + pub use super::EventFilter; pub use super::{ data::prelude::*, execute_trigger::prelude::*, notification::prelude::*, pipeline::prelude::*, time::prelude::*, Event, FilterBox, TriggeringEventType, diff --git a/data_model/src/events/notification.rs b/data_model/src/events/notification.rs index 8f98f3f0c73..b030edf0962 100644 --- a/data_model/src/events/notification.rs +++ b/data_model/src/events/notification.rs @@ -145,7 +145,7 @@ pub mod model { } #[cfg(feature = "transparent_api")] -impl super::Filter for NotificationEventFilter { +impl super::EventFilter for NotificationEventFilter { type Event = NotificationEvent; /// Check if `self` accepts the `event`. @@ -161,7 +161,7 @@ impl super::Filter for NotificationEventFilter { } #[cfg(feature = "transparent_api")] -impl super::Filter for TriggerCompletedEventFilter { +impl super::EventFilter for TriggerCompletedEventFilter { type Event = TriggerCompletedEvent; /// Check if `self` accepts the `event`. @@ -200,7 +200,7 @@ pub mod prelude { #[cfg(feature = "transparent_api")] mod tests { use super::*; - use crate::events::Filter; + use crate::events::EventFilter; #[test] fn trigger_completed_events_filter() { diff --git a/data_model/src/events/pipeline.rs b/data_model/src/events/pipeline.rs index 62a208fb0d9..49b43d4f0a7 100644 --- a/data_model/src/events/pipeline.rs +++ b/data_model/src/events/pipeline.rs @@ -193,7 +193,7 @@ impl PipelineEventFilter { } #[cfg(feature = "transparent_api")] -impl super::Filter for PipelineEventFilter { +impl super::EventFilter for PipelineEventFilter { type Event = PipelineEvent; /// Check if `self` accepts the `event`. @@ -230,7 +230,7 @@ mod tests { #[cfg(not(feature = "std"))] use alloc::{string::ToString as _, vec, vec::Vec}; - use super::{super::Filter, PipelineRejectionReason::*, *}; + use super::{super::EventFilter, PipelineRejectionReason::*, *}; use crate::{transaction::error::TransactionRejectionReason::*, ValidationFail}; #[test] diff --git a/data_model/src/events/time.rs b/data_model/src/events/time.rs index dc676145f78..65ed91682ad 100644 --- a/data_model/src/events/time.rs +++ b/data_model/src/events/time.rs @@ -132,7 +132,7 @@ pub mod model { } #[cfg(feature = "transparent_api")] -impl Filter for TimeEventFilter { +impl EventFilter for TimeEventFilter { type Event = TimeEvent; /// Isn't useful for time-triggers diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index 7de02949e9e..9a26c60bf2c 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -83,6 +83,18 @@ ] }, "AccountEventFilter": { + "Struct": [ + { + "name": "id_matcher", + "type": "Option" + }, + { + "name": "event_matcher", + "type": "Option" + } + ] + }, + "AccountEventMatcher": { "Enum": [ { "tag": "ByCreated", @@ -126,20 +138,7 @@ }, { "tag": "ByAsset", - "discriminant": 10, - "type": "FilterOpt" - } - ] - }, - "AccountFilter": { - "Struct": [ - { - "name": "origin_filter", - "type": "FilterOpt>" - }, - { - "name": "event_filter", - "type": "FilterOpt" + "discriminant": 10 } ] }, @@ -378,6 +377,18 @@ ] }, "AssetDefinitionEventFilter": { + "Struct": [ + { + "name": "id_matcher", + "type": "Option" + }, + { + "name": "event_matcher", + "type": "Option" + } + ] + }, + "AssetDefinitionEventMatcher": { "Enum": [ { "tag": "ByCreated", @@ -409,18 +420,6 @@ } ] }, - "AssetDefinitionFilter": { - "Struct": [ - { - "name": "origin_filter", - "type": "FilterOpt>" - }, - { - "name": "event_filter", - "type": "FilterOpt" - } - ] - }, "AssetDefinitionId": { "Struct": [ { @@ -492,6 +491,18 @@ ] }, "AssetEventFilter": { + "Struct": [ + { + "name": "id_matcher", + "type": "Option" + }, + { + "name": "event_matcher", + "type": "Option" + } + ] + }, + "AssetEventMatcher": { "Enum": [ { "tag": "ByCreated", @@ -519,18 +530,6 @@ } ] }, - "AssetFilter": { - "Struct": [ - { - "name": "origin_filter", - "type": "FilterOpt>" - }, - { - "name": "event_filter", - "type": "FilterOpt" - } - ] - }, "AssetId": { "Struct": [ { @@ -875,22 +874,37 @@ { "tag": "ByPeer", "discriminant": 0, - "type": "FilterOpt" + "type": "PeerEventFilter" }, { "tag": "ByDomain", "discriminant": 1, - "type": "FilterOpt" + "type": "DomainEventFilter" }, { - "tag": "ByTrigger", + "tag": "ByAccount", "discriminant": 2, - "type": "FilterOpt" + "type": "AccountEventFilter" }, { - "tag": "ByRole", + "tag": "ByAsset", "discriminant": 3, - "type": "FilterOpt" + "type": "AssetEventFilter" + }, + { + "tag": "ByAssetDefinition", + "discriminant": 4, + "type": "AssetDefinitionEventFilter" + }, + { + "tag": "ByTrigger", + "discriminant": 5, + "type": "TriggerEventFilter" + }, + { + "tag": "ByRole", + "discriminant": 6, + "type": "RoleEventFilter" } ] }, @@ -1005,6 +1019,18 @@ ] }, "DomainEventFilter": { + "Struct": [ + { + "name": "id_matcher", + "type": "Option" + }, + { + "name": "event_matcher", + "type": "Option" + } + ] + }, + "DomainEventMatcher": { "Enum": [ { "tag": "ByCreated", @@ -1028,25 +1054,11 @@ }, { "tag": "ByAccount", - "discriminant": 5, - "type": "FilterOpt" + "discriminant": 5 }, { "tag": "ByAssetDefinition", - "discriminant": 6, - "type": "FilterOpt" - } - ] - }, - "DomainFilter": { - "Struct": [ - { - "name": "origin_filter", - "type": "FilterOpt>" - }, - { - "name": "event_filter", - "type": "FilterOpt" + "discriminant": 6 } ] }, @@ -1233,84 +1245,6 @@ } ] }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "AccountEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "AccountFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "AssetDefinitionEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "AssetDefinitionFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "AssetEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "AssetFilter" - } - ] - }, "FilterOpt": { "Enum": [ { @@ -1324,201 +1258,6 @@ } ] }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "DomainEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "DomainFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt>": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "OriginFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "PeerEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "PeerFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "RoleEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "RoleFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "TriggerEventFilter" - } - ] - }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "TriggerFilter" - } - ] - }, "FindAccountById": { "Struct": [ { @@ -2794,6 +2533,27 @@ } ] }, + "Option": { + "Option": "AccountEventMatcher" + }, + "Option": { + "Option": "AccountId" + }, + "Option": { + "Option": "AssetDefinitionEventMatcher" + }, + "Option": { + "Option": "AssetDefinitionId" + }, + "Option": { + "Option": "AssetEventMatcher" + }, + "Option": { + "Option": "AssetId" + }, + "Option": { + "Option": "DomainEventMatcher" + }, "Option": { "Option": "DomainId" }, @@ -2818,12 +2578,24 @@ "Option>": { "Option": "NonZero" }, + "Option": { + "Option": "PeerEventMatcher" + }, + "Option": { + "Option": "PeerId" + }, "Option": { "Option": "PipelineEntityKind" }, "Option": { "Option": "PipelineStatusKind" }, + "Option": { + "Option": "RoleEventMatcher" + }, + "Option": { + "Option": "RoleId" + }, "Option": { "Option": "String" }, @@ -2836,16 +2608,12 @@ "Option": { "Option": "TriggerCompletedOutcomeType" }, + "Option": { + "Option": "TriggerEventMatcher" + }, "Option": { "Option": "TriggerId" }, - "OriginFilter": "AccountId", - "OriginFilter": "AssetDefinitionId", - "OriginFilter": "AssetId", - "OriginFilter": "DomainId", - "OriginFilter": "PeerId", - "OriginFilter": "RoleId", - "OriginFilter": "TriggerId", "Parameter": { "Struct": [ { @@ -2889,26 +2657,26 @@ ] }, "PeerEventFilter": { - "Enum": [ + "Struct": [ { - "tag": "ByAdded", - "discriminant": 0 + "name": "id_matcher", + "type": "Option" }, { - "tag": "ByRemoved", - "discriminant": 1 + "name": "event_matcher", + "type": "Option" } ] }, - "PeerFilter": { - "Struct": [ + "PeerEventMatcher": { + "Enum": [ { - "name": "origin_filter", - "type": "FilterOpt>" + "tag": "ByAdded", + "discriminant": 0 }, { - "name": "event_filter", - "type": "FilterOpt" + "tag": "ByRemoved", + "discriminant": 1 } ] }, @@ -3635,6 +3403,18 @@ ] }, "RoleEventFilter": { + "Struct": [ + { + "name": "id_matcher", + "type": "Option" + }, + { + "name": "event_matcher", + "type": "Option" + } + ] + }, + "RoleEventMatcher": { "Enum": [ { "tag": "ByCreated", @@ -3650,18 +3430,6 @@ } ] }, - "RoleFilter": { - "Struct": [ - { - "name": "origin_filter", - "type": "FilterOpt>" - }, - { - "name": "event_filter", - "type": "FilterOpt" - } - ] - }, "RoleId": { "Struct": [ { @@ -4411,6 +4179,18 @@ ] }, "TriggerEventFilter": { + "Struct": [ + { + "name": "id_matcher", + "type": "Option" + }, + { + "name": "event_matcher", + "type": "Option" + } + ] + }, + "TriggerEventMatcher": { "Enum": [ { "tag": "ByCreated", @@ -4430,18 +4210,6 @@ } ] }, - "TriggerFilter": { - "Struct": [ - { - "name": "origin_filter", - "type": "FilterOpt>" - }, - { - "name": "event_filter", - "type": "FilterOpt" - } - ] - }, "TriggerId": { "Struct": [ { diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index fa572e164f6..7eab8f0d201 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -64,7 +64,7 @@ types!( Account, AccountEvent, AccountEventFilter, - AccountFilter, + AccountEventMatcher, AccountId, AccountMintBox, AccountPermissionChanged, @@ -77,13 +77,13 @@ types!( AssetDefinition, AssetDefinitionEvent, AssetDefinitionEventFilter, - AssetDefinitionFilter, + AssetDefinitionEventMatcher, AssetDefinitionId, AssetDefinitionOwnerChanged, AssetDefinitionTotalQuantityChanged, AssetEvent, AssetEventFilter, - AssetFilter, + AssetEventMatcher, AssetId, AssetMintBox, AssetTransferBox, @@ -118,7 +118,7 @@ types!( Domain, DomainEvent, DomainEventFilter, - DomainFilter, + DomainEventMatcher, DomainId, Duration, Event, @@ -133,27 +133,6 @@ types!( ExecutorEvent, Fail, FilterBox, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt>, - FilterOpt>, - FilterOpt>, - FilterOpt>, - FilterOpt>, - FilterOpt>, - FilterOpt>, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, - FilterOpt, FindAccountById, FindAccountKeyValueByIdAndKey, FindAccountsByDomainId, @@ -246,19 +225,12 @@ types!( Option, Option, Option, - OriginFilter, - OriginFilter, - OriginFilter, - OriginFilter, - OriginFilter, - OriginFilter, - OriginFilter, Parameter, ParameterId, Peer, PeerEvent, PeerEventFilter, - PeerFilter, + PeerEventMatcher, PeerId, PermissionRemoved, PermissionToken, @@ -283,7 +255,7 @@ types!( Role, RoleEvent, RoleEventFilter, - RoleFilter, + RoleEventMatcher, RoleId, SemiInterval, SemiInterval, @@ -322,7 +294,7 @@ types!( TriggerCompletedOutcomeType, TriggerEvent, TriggerEventFilter, - TriggerFilter, + TriggerEventMatcher, TriggerId, TriggerNumberOfExecutionsChanged, TriggeringFilterBox, diff --git a/tools/parity_scale_decoder/Cargo.toml b/tools/parity_scale_decoder/Cargo.toml index e2cb948ff7a..462f17d5bea 100644 --- a/tools/parity_scale_decoder/Cargo.toml +++ b/tools/parity_scale_decoder/Cargo.toml @@ -33,5 +33,5 @@ colored = "2.0.4" iroha_data_model = { workspace = true } parity-scale-codec = { workspace = true } -serde_json = { workspace = true } +serde_json = { workspace = true, features = ["std"] } serde = { workspace = true } diff --git a/tools/parity_scale_decoder/samples/trigger.bin b/tools/parity_scale_decoder/samples/trigger.bin index 4617851317f..34d021e5fe2 100644 Binary files a/tools/parity_scale_decoder/samples/trigger.bin and b/tools/parity_scale_decoder/samples/trigger.bin differ diff --git a/tools/parity_scale_decoder/src/main.rs b/tools/parity_scale_decoder/src/main.rs index 6a60e0396ad..6dea97524b6 100644 --- a/tools/parity_scale_decoder/src/main.rs +++ b/tools/parity_scale_decoder/src/main.rs @@ -265,9 +265,10 @@ mod tests { Repeats::Indefinitely, account_id, // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - FilterBox::Data(BySome(DataEntityFilter::ByDomain(BySome( - DomainFilter::new(AcceptAll, BySome(DomainEventFilter::ByAccount(AcceptAll))), - )))), + FilterBox::Data(BySome(DataEntityFilter::ByDomain(DomainEventFilter { + id_matcher: None, + event_matcher: None, + }))), ); let trigger = Trigger::new(trigger_id, action);