From f58fbe99ecafa677bdc3d0bc4fabb77fe9821426 Mon Sep 17 00:00:00 2001 From: Nikita Strygin Date: Fri, 2 Feb 2024 10:35:09 +0300 Subject: [PATCH] [refactor] #1981, #4195: Refactor the event filters (even further) - Remove the FilterOpt combinator, fuse it with DataEventFilter - Rename DataEntityFilter to DataEventFilter - Add `Any` suffix to nested events matchers - Add doc-comments to event filters & their variants Signed-off-by: Nikita Strygin --- client/tests/integration/events/data.rs | 4 +- .../tests/integration/events/notification.rs | 4 +- .../integration/triggers/data_trigger.rs | 14 +- .../integration/triggers/event_trigger.rs | 5 +- client_cli/src/main.rs | 4 +- configs/peer/executor.wasm | Bin 705875 -> 705640 bytes data_model/Cargo.toml | 2 - data_model/src/events/data/events.rs | 2 + data_model/src/events/data/filters.rs | 207 +++++++++--------- data_model/src/events/notification.rs | 8 +- docs/source/references/schema.json | 93 ++++---- schema/gen/src/lib.rs | 1 - .../parity_scale_decoder/samples/trigger.bin | Bin 77 -> 76 bytes .../parity_scale_decoder/samples/trigger.json | 6 +- tools/parity_scale_decoder/src/main.rs | 5 +- 15 files changed, 167 insertions(+), 188 deletions(-) diff --git a/client/tests/integration/events/data.rs b/client/tests/integration/events/data.rs index 7c6547cff9a..6bee1e7e9da 100644 --- a/client/tests/integration/events/data.rs +++ b/client/tests/integration/events/data.rs @@ -138,7 +138,7 @@ fn transaction_execution_should_produce_events( let listener = client.clone(); let (init_sender, init_receiver) = mpsc::channel(); let (event_sender, event_receiver) = mpsc::channel(); - let event_filter = DataEventFilter::AcceptAll.into(); + let event_filter = FilterBox::Data(DataEventFilter::ByAny); thread::spawn(move || -> Result<()> { let event_iterator = listener.listen_for_events(event_filter)?; init_sender.send(())?; @@ -184,7 +184,7 @@ fn produce_multiple_events() -> Result<()> { let listener = client.clone(); let (init_sender, init_receiver) = mpsc::channel(); let (event_sender, event_receiver) = mpsc::channel(); - let event_filter = DataEventFilter::AcceptAll.into(); + let event_filter = FilterBox::Data(DataEventFilter::ByAny); thread::spawn(move || -> Result<()> { let event_iterator = listener.listen_for_events(event_filter)?; init_sender.send(())?; diff --git a/client/tests/integration/events/notification.rs b/client/tests/integration/events/notification.rs index 2cd033e2b7c..dd23d83286e 100644 --- a/client/tests/integration/events/notification.rs +++ b/client/tests/integration/events/notification.rs @@ -35,7 +35,7 @@ fn trigger_completion_success_should_produce_event() -> Result<()> { let (sender, receiver) = mpsc::channel(); let _handle = thread::spawn(move || -> Result<()> { let mut event_it = thread_client.listen_for_events( - NotificationEventFilter::TriggerCompleted(TriggerCompletedEventFilter::new( + NotificationEventFilter::ByTriggerCompleted(TriggerCompletedEventFilter::new( Some(trigger_id), Some(TriggerCompletedOutcomeType::Success), )) @@ -84,7 +84,7 @@ fn trigger_completion_failure_should_produce_event() -> Result<()> { let (sender, receiver) = mpsc::channel(); let _handle = thread::spawn(move || -> Result<()> { let mut event_it = thread_client.listen_for_events( - NotificationEventFilter::TriggerCompleted(TriggerCompletedEventFilter::new( + NotificationEventFilter::ByTriggerCompleted(TriggerCompletedEventFilter::new( Some(trigger_id), Some(TriggerCompletedOutcomeType::Failure), )) diff --git a/client/tests/integration/triggers/data_trigger.rs b/client/tests/integration/triggers/data_trigger.rs index 00b473f31af..46417ded549 100644 --- a/client/tests/integration/triggers/data_trigger.rs +++ b/client/tests/integration/triggers/data_trigger.rs @@ -20,11 +20,10 @@ fn must_execute_both_triggers() -> Result<()> { [instruction.clone()], Repeats::Indefinitely, account_id.clone(), - // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(AccountEventFilter { + TriggeringFilterBox::Data(DataEventFilter::ByAccount(AccountEventFilter { id_matcher: None, event_matcher: Some(AccountEventMatcher::ByCreated), - }))), + })), ), )); test_client.submit_blocking(register_trigger)?; @@ -35,10 +34,10 @@ fn must_execute_both_triggers() -> Result<()> { [instruction], Repeats::Indefinitely, account_id, - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByDomain(DomainEventFilter { + TriggeringFilterBox::Data(DataEventFilter::ByDomain(DomainEventFilter { id_matcher: None, event_matcher: Some(DomainEventMatcher::ByCreated), - }))), + })), ), )); test_client.submit_blocking(register_trigger)?; @@ -89,11 +88,10 @@ fn domain_scoped_trigger_must_be_executed_only_on_events_in_its_domain() -> Resu [Mint::asset_quantity(1_u32, asset_id.clone())], Repeats::Indefinitely, account_id, - // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(AccountEventFilter { + TriggeringFilterBox::Data(DataEventFilter::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 4064ad9c9db..ad470b15120 100644 --- a/client/tests/integration/triggers/event_trigger.rs +++ b/client/tests/integration/triggers/event_trigger.rs @@ -24,13 +24,12 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> { vec![instruction], Repeats::Indefinitely, account_id, - // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAssetDefinition( + TriggeringFilterBox::Data(DataEventFilter::ByAssetDefinition( AssetDefinitionEventFilter { id_matcher: None, event_matcher: Some(AssetDefinitionEventMatcher::ByCreated), }, - ))), + )), ), )); test_client.submit(register_trigger)?; diff --git a/client_cli/src/main.rs b/client_cli/src/main.rs index 1c9f07ecfa1..a8a3901fe2b 100644 --- a/client_cli/src/main.rs +++ b/client_cli/src/main.rs @@ -334,8 +334,8 @@ mod events { fn run(self, context: &mut dyn RunContext) -> Result<()> { let filter = match self { Args::Pipeline => FilterBox::Pipeline(PipelineEventFilter::new()), - Args::Data => FilterBox::Data(DataEventFilter::AcceptAll), - Args::Notification => FilterBox::Notification(NotificationEventFilter::AcceptAll), + Args::Data => FilterBox::Data(DataEventFilter::ByAny), + Args::Notification => FilterBox::Notification(NotificationEventFilter::ByAny), }; listen(filter, context) } diff --git a/configs/peer/executor.wasm b/configs/peer/executor.wasm index da5dbbbb2b5ea6ede38febc5eeabf81588f20793..5405ab52fc5dd3387105f48f986939c0fa4f4a9e 100755 GIT binary patch delta 54099 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 delta 53787 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�ylEL>8nNCyJ*_J#a_qj8X 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 diff --git a/data_model/Cargo.toml b/data_model/Cargo.toml index 7ecd549f937..9b80ee2b6fc 100644 --- a/data_model/Cargo.toml +++ b/data_model/Cargo.toml @@ -54,8 +54,6 @@ 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 f4a18f29c43..06d5928885e 100644 --- a/data_model/src/events/data/events.rs +++ b/data_model/src/events/data/events.rs @@ -31,6 +31,8 @@ macro_rules! data_event { }; } +// NOTE: if adding/editing events here, make sure to update the corresponding event filter in [`super::filter`] + #[model] pub mod model { use super::*; diff --git a/data_model/src/events/data/filters.rs b/data_model/src/events/data/filters.rs index d5ab3c382cb..cfcb20f9079 100644 --- a/data_model/src/events/data/filters.rs +++ b/data_model/src/events/data/filters.rs @@ -1,9 +1,10 @@ -//! 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) +//! This module contains filters for data events. +//! +//! (almost) Each event in [`super::events`], there's two corresponding types in this module: +//! - `*EventMatcher` - matches one event kind (e.g. [`super::events::AccountEvent::Created`] with [`AccountEventMatcher::ByCreated`]) +//! - `*EventFilter` - struct combining an optional id matcher and an optional event matcher +//! +//! The ones not having a filter are [`super::events::ConfigurationEvent`] and [`super::events::ExecutorEvent`] (TODO: why?). use core::fmt::Debug; @@ -12,218 +13,214 @@ use iroha_data_model_derive::model; pub use self::model::*; use super::*; -/// Filter for all events -pub type DataEventFilter = FilterOpt; - #[model] pub mod model { use super::*; - /// Optional filter. May pass all items or may filter them by `F` - /// - /// It's better than `Optional` because `Optional` already has its own `filter` method and it - /// would be ugly to use fully qualified syntax to call `Filter::filter()` method on it. - /// Also `FilterOpt` variant names look better for filter needs - #[derive( - Debug, - Clone, - PartialEq, - Eq, - PartialOrd, - Ord, - Decode, - Encode, - Deserialize, - Serialize, - IntoSchema, - )] - #[serde(untagged)] // Unaffected by #3330 - pub enum FilterOpt { - /// Accept all items that will be passed to `filter()` method - #[serde(with = "accept_all_as_string")] - AcceptAll, - /// Use filter `F` to choose acceptable items passed to `filter()` method - BySome(F), - } - #[derive( Debug, Clone, PartialEq, Eq, FromVariant, Decode, Encode, Deserialize, Serialize, IntoSchema, )] - pub enum DataEntityFilter { + pub enum DataEventFilter { + /// Matches any data events ([`DataEvent`]) + ByAny, + /// Matches only [`PeerEvent`]s ByPeer(PeerEventFilter), + /// Matches only [`DomainEvent`]s ByDomain(DomainEventFilter), + /// Matches only [`AccountEvent`]s ByAccount(AccountEventFilter), + /// Matches only [`AssetEvent`]s ByAsset(AssetEventFilter), + /// Matches only [`AssetDefinitionEvent`]s ByAssetDefinition(AssetDefinitionEventFilter), + /// Matches only [`TriggerEvent`]s ByTrigger(TriggerEventFilter), + /// Matches only [`RoleEvent`]s ByRole(RoleEventFilter), // We didn't have filters for these events before the refactor. Should we? // Configuration(ConfigurationEventFilter), // Executor(ExecutorEventFilter), } + /// An event filter for [`PeerEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct PeerEventFilter { pub id_matcher: Option, pub event_matcher: Option, } + /// An event matcher for [`PeerEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum PeerEventMatcher { + /// Matches only [`PeerEvent::Added`] ByAdded, + /// Matches only [`PeerEvent::Removed`] ByRemoved, } + /// An event filter for [`DomainEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct DomainEventFilter { + /// If specified matches only events originating from this domain pub id_matcher: Option, + /// If specified matches only events of this type pub event_matcher: Option, } + /// An event matcher for [`DomainEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum DomainEventMatcher { + /// Matches only [`DomainEvent::Created`] ByCreated, + /// Matches only [`DomainEvent::Deleted`] ByDeleted, + /// Matches only [`DomainEvent::MetadataInserted`] ByMetadataInserted, + /// Matches only [`DomainEvent::MetadataRemoved`] ByMetadataRemoved, + /// Matches only [`DomainEvent::OwnerChanged`] 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, + /// Matches only [`DomainEvent::Account`] + ByAccountAny, + /// Matches only [`DomainEvent::AssetDefinition`] + ByAssetDefinitionAny, } + /// An event filter for [`AccountEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct AccountEventFilter { + /// If specified matches only events originating from this account pub id_matcher: Option, + /// If specified matches only events of this type pub event_matcher: Option, } + /// An event matcher for [`AccountEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum AccountEventMatcher { + /// Matches only [`AccountEvent::Created`] ByCreated, + /// Matches only [`AccountEvent::Deleted`] ByDeleted, + /// Matches only [`AccountEvent::AuthenticationAdded`] ByAuthenticationAdded, + /// Matches only [`AccountEvent::AuthenticationRemoved`] ByAuthenticationRemoved, + /// Matches only [`AccountEvent::PermissionAdded`] ByPermissionAdded, + /// Matches only [`AccountEvent::PermissionRemoved`] ByPermissionRemoved, + /// Matches only [`AccountEvent::RoleRevoked`] ByRoleRevoked, + /// Matches only [`AccountEvent::RoleGranted`] ByRoleGranted, + /// Matches only [`AccountEvent::MetadataInserted`] ByMetadataInserted, + /// Matches only [`AccountEvent::MetadataRemoved`] ByMetadataRemoved, // nested events - ByAsset, + /// Matches only [`AccountEvent::Asset`] + ByAssetAny, } + /// An event filter for [`AssetEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct AssetEventFilter { + /// If specified matches only events originating from this asset pub id_matcher: Option, + /// If specified matches only events of this type pub event_matcher: Option, } + /// An event matcher for [`AssetEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum AssetEventMatcher { + /// Matches only [`AssetEvent::Created`] ByCreated, + /// Matches only [`AssetEvent::Deleted`] ByDeleted, + /// Matches only [`AssetEvent::Added`] ByAdded, + /// Matches only [`AssetEvent::Removed`] ByRemoved, + /// Matches only [`AssetEvent::MetadataInserted`] ByMetadataInserted, + /// Matches only [`AssetEvent::MetadataRemoved`] ByMetadataRemoved, } + /// An event filter for [`AssetDefinitionEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct AssetDefinitionEventFilter { + /// If specified matches only events originating from this asset definition pub id_matcher: Option, + /// If specified matches only events of this type pub event_matcher: Option, } + /// An event matcher for [`AssetDefinitionEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum AssetDefinitionEventMatcher { + /// Matches only [`AssetDefinitionEvent::Created`] ByCreated, + /// Matches only [`AssetDefinitionEvent::MintabilityChanged`] ByMintabilityChanged, + /// Matches only [`AssetDefinitionEvent::OwnerChanged`] ByOwnerChanged, + /// Matches only [`AssetDefinitionEvent::Deleted`] ByDeleted, + /// Matches only [`AssetDefinitionEvent::MetadataInserted`] ByMetadataInserted, + /// Matches only [`AssetDefinitionEvent::MetadataRemoved`] ByMetadataRemoved, + /// Matches only [`AssetDefinitionEvent::TotalQuantityChanged`] ByTotalQuantityChanged, } + /// An event filter for [`TriggerEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct TriggerEventFilter { + /// If specified matches only events originating from this trigger pub id_matcher: Option, + /// If specified matches only events of this type pub event_matcher: Option, } + /// An event matcher for [`TriggerEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum TriggerEventMatcher { + /// Matches only [`TriggerEvent::Created`] ByCreated, + /// Matches only [`TriggerEvent::Deleted`] ByDeleted, + /// Matches only [`TriggerEvent::Extended`] ByExtended, + /// Matches only [`TriggerEvent::Shortened`] ByShortened, } + /// An event filter for [`RoleEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub struct RoleEventFilter { + /// If specified matches only events originating from this role pub id_matcher: Option, + /// If specified matches only events of this type pub event_matcher: Option, } + /// An event matcher for [`RoleEvent`]s #[derive(Debug, Clone, PartialEq, Eq, Decode, Encode, Deserialize, Serialize, IntoSchema)] pub enum RoleEventMatcher { + /// Matches only [`RoleEvent::Created`] ByCreated, + /// Matches only [`RoleEvent::Deleted`] ByDeleted, + /// Matches only [`RoleEvent::PermissionRemoved`] ByPermissionRemoved, } } -mod accept_all_as_string { - //! Module to (de-)serialize `FilterOpt::AcceptAll` variant as string - - #[cfg(not(feature = "std"))] - use alloc::format; - - use serde::{Deserializer, Serializer}; - - /// Serialize bytes using `base64` - pub fn serialize(serializer: S) -> Result { - serializer.serialize_str("AcceptAll") - } - - /// Deserialize bytes using `base64` - pub fn deserialize<'de, D: Deserializer<'de>>(deserializer: D) -> Result<(), D::Error> { - struct Vis; - - impl serde::de::Visitor<'_> for Vis { - type Value = (); - - fn expecting(&self, formatter: &mut core::fmt::Formatter) -> core::fmt::Result { - formatter.write_str("an AcceptAll string") - } - - fn visit_str(self, s: &str) -> Result { - if s == "AcceptAll" { - Ok(()) - } else { - Err(E::custom(format!("expected AcceptAll, got {s}"))) - } - } - } - deserializer.deserialize_str(Vis) - } -} - -#[cfg(feature = "transparent_api")] -impl EventFilter for FilterOpt { - type Event = F::Event; - - fn matches(&self, item: &Self::Event) -> bool { - match self { - Self::AcceptAll => true, - Self::BySome(filter) => filter.matches(item), - } - } -} - #[cfg(feature = "transparent_api")] impl EventFilter for PeerEventFilter { type Event = super::PeerEvent; @@ -271,8 +268,8 @@ impl EventFilter for DomainEventFilter { (ByMetadataInserted, MetadataInserted(_)) => true, (ByMetadataRemoved, MetadataRemoved(_)) => true, (ByOwnerChanged, OwnerChanged(_)) => true, - (ByAccount, Account(_)) => true, - (ByAssetDefinition, AssetDefinition(_)) => true, + (ByAccountAny, Account(_)) => true, + (ByAssetDefinitionAny, AssetDefinition(_)) => true, _ => false, } } else { @@ -307,7 +304,7 @@ impl super::EventFilter for AccountEventFilter { (ByRoleGranted, RoleGranted(_)) => true, (ByMetadataInserted, MetadataInserted(_)) => true, (ByMetadataRemoved, MetadataRemoved(_)) => true, - (ByAsset, Asset(_)) => true, + (ByAssetAny, Asset(_)) => true, _ => false, } } else { @@ -433,14 +430,15 @@ impl super::EventFilter for RoleEventFilter { } #[cfg(feature = "transparent_api")] -impl EventFilter for DataEntityFilter { +impl EventFilter for DataEventFilter { type Event = DataEvent; fn matches(&self, event: &DataEvent) -> bool { - use DataEntityFilter::*; use DataEvent::*; + use DataEventFilter::*; match (self, event) { + (ByAny, _) => true, (ByPeer(filter), Peer(event)) => filter.matches(event), (ByDomain(filter), Domain(event)) => filter.matches(event), (ByAccount(filter), Domain(DomainEvent::Account(event))) => filter.matches(event), @@ -460,11 +458,9 @@ impl EventFilter for DataEntityFilter { pub mod prelude { pub use super::{ AccountEventFilter, AccountEventMatcher, AssetDefinitionEventFilter, - AssetDefinitionEventMatcher, AssetEventFilter, AssetEventMatcher, DataEntityFilter, - DataEventFilter, DomainEventFilter, DomainEventMatcher, - FilterOpt::{self, *}, - PeerEventFilter, PeerEventMatcher, RoleEventFilter, RoleEventMatcher, TriggerEventFilter, - TriggerEventMatcher, + AssetDefinitionEventMatcher, AssetEventFilter, AssetEventMatcher, DataEventFilter, + DomainEventFilter, DomainEventMatcher, PeerEventFilter, PeerEventMatcher, RoleEventFilter, + RoleEventMatcher, TriggerEventFilter, TriggerEventMatcher, }; } @@ -524,19 +520,18 @@ mod tests { DomainEvent::Account(AccountEvent::Asset(AssetEvent::Created(asset))).into(); // 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(DomainEventFilter { + let domain_filter = DataEventFilter::ByDomain(DomainEventFilter { id_matcher: Some(domain_id), event_matcher: None, - })); - let account_filter = BySome(DataEntityFilter::ByAccount(AccountEventFilter { + }); + let account_filter = DataEventFilter::ByAccount(AccountEventFilter { id_matcher: Some(account_id), event_matcher: None, - })); - let asset_filter = BySome(DataEntityFilter::ByAsset(AssetEventFilter { + }); + let asset_filter = DataEventFilter::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/notification.rs b/data_model/src/events/notification.rs index b030edf0962..3eb484095b9 100644 --- a/data_model/src/events/notification.rs +++ b/data_model/src/events/notification.rs @@ -113,8 +113,8 @@ pub mod model { #[ffi_type] #[non_exhaustive] pub enum NotificationEventFilter { - AcceptAll, - TriggerCompleted(TriggerCompletedEventFilter), + ByAny, + ByTriggerCompleted(TriggerCompletedEventFilter), } /// Filter [`TriggerCompletedEvent`] by @@ -152,8 +152,8 @@ impl super::EventFilter for NotificationEventFilter { #[inline] fn matches(&self, event: &Self::Event) -> bool { match (self, event) { - (Self::AcceptAll, _) => true, - (Self::TriggerCompleted(filter), NotificationEvent::TriggerCompleted(event)) => { + (Self::ByAny, _) => true, + (Self::ByTriggerCompleted(filter), NotificationEvent::TriggerCompleted(event)) => { filter.matches(event) } } diff --git a/docs/source/references/schema.json b/docs/source/references/schema.json index ebc5245431f..805b1bf0bfa 100644 --- a/docs/source/references/schema.json +++ b/docs/source/references/schema.json @@ -137,7 +137,7 @@ "discriminant": 9 }, { - "tag": "ByAsset", + "tag": "ByAssetAny", "discriminant": 10 } ] @@ -864,81 +864,85 @@ } ] }, - "DataEntityFilter": { + "DataEvent": { "Enum": [ { - "tag": "ByPeer", + "tag": "Peer", "discriminant": 0, - "type": "PeerEventFilter" + "type": "PeerEvent" }, { - "tag": "ByDomain", + "tag": "Domain", "discriminant": 1, - "type": "DomainEventFilter" + "type": "DomainEvent" }, { - "tag": "ByAccount", + "tag": "Trigger", "discriminant": 2, - "type": "AccountEventFilter" + "type": "TriggerEvent" }, { - "tag": "ByAsset", + "tag": "Role", "discriminant": 3, - "type": "AssetEventFilter" + "type": "RoleEvent" }, { - "tag": "ByAssetDefinition", + "tag": "PermissionToken", "discriminant": 4, - "type": "AssetDefinitionEventFilter" + "type": "PermissionTokenSchemaUpdateEvent" }, { - "tag": "ByTrigger", + "tag": "Configuration", "discriminant": 5, - "type": "TriggerEventFilter" + "type": "ConfigurationEvent" }, { - "tag": "ByRole", + "tag": "Executor", "discriminant": 6, - "type": "RoleEventFilter" + "type": "ExecutorEvent" } ] }, - "DataEvent": { + "DataEventFilter": { "Enum": [ { - "tag": "Peer", - "discriminant": 0, - "type": "PeerEvent" + "tag": "ByAny", + "discriminant": 0 }, { - "tag": "Domain", + "tag": "ByPeer", "discriminant": 1, - "type": "DomainEvent" + "type": "PeerEventFilter" }, { - "tag": "Trigger", + "tag": "ByDomain", "discriminant": 2, - "type": "TriggerEvent" + "type": "DomainEventFilter" }, { - "tag": "Role", + "tag": "ByAccount", "discriminant": 3, - "type": "RoleEvent" + "type": "AccountEventFilter" }, { - "tag": "PermissionToken", + "tag": "ByAsset", "discriminant": 4, - "type": "PermissionTokenSchemaUpdateEvent" + "type": "AssetEventFilter" }, { - "tag": "Configuration", + "tag": "ByAssetDefinition", "discriminant": 5, - "type": "ConfigurationEvent" + "type": "AssetDefinitionEventFilter" }, { - "tag": "Executor", + "tag": "ByTrigger", "discriminant": 6, - "type": "ExecutorEvent" + "type": "TriggerEventFilter" + }, + { + "tag": "ByRole", + "discriminant": 7, + "type": "RoleEventFilter" } ] }, @@ -1048,11 +1052,11 @@ "discriminant": 4 }, { - "tag": "ByAccount", + "tag": "ByAccountAny", "discriminant": 5 }, { - "tag": "ByAssetDefinition", + "tag": "ByAssetDefinitionAny", "discriminant": 6 } ] @@ -1221,7 +1225,7 @@ { "tag": "Data", "discriminant": 1, - "type": "FilterOpt" + "type": "DataEventFilter" }, { "tag": "Time", @@ -1240,19 +1244,6 @@ } ] }, - "FilterOpt": { - "Enum": [ - { - "tag": "AcceptAll", - "discriminant": 0 - }, - { - "tag": "BySome", - "discriminant": 1, - "type": "DataEntityFilter" - } - ] - }, "FindAccountById": { "Struct": [ { @@ -2494,11 +2485,11 @@ "NotificationEventFilter": { "Enum": [ { - "tag": "AcceptAll", + "tag": "ByAny", "discriminant": 0 }, { - "tag": "TriggerCompleted", + "tag": "ByTriggerCompleted", "discriminant": 1, "type": "TriggerCompletedEventFilter" } @@ -4223,7 +4214,7 @@ { "tag": "Data", "discriminant": 1, - "type": "FilterOpt" + "type": "DataEventFilter" }, { "tag": "Time", diff --git a/schema/gen/src/lib.rs b/schema/gen/src/lib.rs index 7eab8f0d201..4118c9669cf 100644 --- a/schema/gen/src/lib.rs +++ b/schema/gen/src/lib.rs @@ -112,7 +112,6 @@ types!( ConfigurationEvent, ConstString, Container, - DataEntityFilter, DataEvent, DataEventFilter, Domain, diff --git a/tools/parity_scale_decoder/samples/trigger.bin b/tools/parity_scale_decoder/samples/trigger.bin index 34d021e5fe2be6714a7e97d0ebda2f0a9c0afc0a..57c9ef7d4e18d2ab8cac3e417b0141eb0fa3d20d 100644 GIT binary patch delta 9 QcmebEnc%^~#K6D+01DaxcmMzZ delta 10 RcmebAo#4UB$jHFJ000bD0eJub diff --git a/tools/parity_scale_decoder/samples/trigger.json b/tools/parity_scale_decoder/samples/trigger.json index 2cf26cf26f3..c743227478a 100644 --- a/tools/parity_scale_decoder/samples/trigger.json +++ b/tools/parity_scale_decoder/samples/trigger.json @@ -20,10 +20,8 @@ "filter": { "Data": { "ByDomain": { - "origin_filter": "AcceptAll", - "event_filter": { - "ByAccount": "AcceptAll" - } + "origin_filter": null, + "event_filter": "ByAccount" } } }, diff --git a/tools/parity_scale_decoder/src/main.rs b/tools/parity_scale_decoder/src/main.rs index 6dea97524b6..e7605be598e 100644 --- a/tools/parity_scale_decoder/src/main.rs +++ b/tools/parity_scale_decoder/src/main.rs @@ -264,11 +264,10 @@ mod tests { vec![Mint::asset_quantity(1_u32, rose_id)], Repeats::Indefinitely, account_id, - // FIXME: rewrite the filters using the builder DSL https://github.com/hyperledger/iroha/issues/3068 - FilterBox::Data(BySome(DataEntityFilter::ByDomain(DomainEventFilter { + FilterBox::Data(DataEventFilter::ByDomain(DomainEventFilter { id_matcher: None, event_matcher: None, - }))), + })), ); let trigger = Trigger::new(trigger_id, action);