Skip to content

Commit

Permalink
[refactor] hyperledger-iroha#3068: remove flattened events
Browse files Browse the repository at this point in the history
Signed-off-by: Nikita Strygin <[email protected]>
  • Loading branch information
DCNick3 committed Dec 25, 2023
1 parent 83de555 commit 5a8bdfc
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 162 deletions.
16 changes: 8 additions & 8 deletions client/tests/integration/events/data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -181,46 +181,46 @@ fn produce_multiple_events() -> Result<()> {
}

let expected_domain_events: Vec<DataEvent> = [
WorldEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded(
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_1.definition_id.clone(),
},
))),
WorldEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded(
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionAdded(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_2.definition_id.clone(),
},
))),
WorldEvent::Domain(DomainEvent::Account(AccountEvent::RoleGranted(
DataEvent::Domain(DomainEvent::Account(AccountEvent::RoleGranted(
AccountRoleChanged {
account_id: bob_id.clone(),
role_id: role_id.clone(),
},
))),
WorldEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved(
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_1.definition_id,
},
))),
WorldEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved(
DataEvent::Domain(DomainEvent::Account(AccountEvent::PermissionRemoved(
AccountPermissionChanged {
account_id: bob_id.clone(),
permission_id: token_2.definition_id,
},
))),
WorldEvent::Domain(DomainEvent::Account(AccountEvent::RoleRevoked(
DataEvent::Domain(DomainEvent::Account(AccountEvent::RoleRevoked(
AccountRoleChanged {
account_id: bob_id,
role_id: role_id.clone(),
},
))),
WorldEvent::Role(RoleEvent::Deleted(role_id)),
DataEvent::Role(RoleEvent::Deleted(role_id)),
]
.into_iter()
.flat_map(WorldEvent::flatten)
.map(Into::into)
.collect();

for expected_event in expected_domain_events {
Expand Down
22 changes: 18 additions & 4 deletions client/tests/integration/triggers/data_trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,15 @@ fn must_execute_both_triggers() -> Result<()> {
[instruction.clone()],
Repeats::Indefinitely,
account_id.clone(),
TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(BySome(
AccountFilter::new(AcceptAll, BySome(AccountEventFilter::ByCreated)),
// 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),
)))),
),
)))),
),
));
Expand Down Expand Up @@ -86,8 +93,15 @@ 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,
TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAccount(BySome(
AccountFilter::new(AcceptAll, BySome(AccountEventFilter::ByCreated)),
// 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),
)))),
),
)))),
),
));
Expand Down
12 changes: 9 additions & 3 deletions client/tests/integration/triggers/event_trigger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,10 +24,16 @@ fn test_mint_asset_when_new_asset_definition_created() -> Result<()> {
vec![instruction],
Repeats::Indefinitely,
account_id,
TriggeringFilterBox::Data(BySome(DataEntityFilter::ByAssetDefinition(BySome(
AssetDefinitionFilter::new(
// 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(AssetDefinitionEventFilter::ByCreated),
BySome(DomainEventFilter::ByAssetDefinition(BySome(
AssetDefinitionFilter::new(
AcceptAll,
BySome(AssetDefinitionEventFilter::ByCreated),
),
))),
),
)))),
),
Expand Down
Binary file modified configs/peer/executor.wasm
Binary file not shown.
2 changes: 1 addition & 1 deletion core/src/smartcontracts/isi/domain.rs
Original file line number Diff line number Diff line change
Expand Up @@ -179,7 +179,7 @@ pub mod isi {

domain.remove_asset_total_quantity(&asset_definition_id);

events.push(WorldEvent::from(DomainEvent::AssetDefinition(
events.push(DataEvent::from(DomainEvent::AssetDefinition(
AssetDefinitionEvent::Deleted(asset_definition_id),
)));

Expand Down
8 changes: 4 additions & 4 deletions core/src/wsv.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1252,7 +1252,7 @@ impl WorldStateView {
/// The function puts events produced by iterator into `events_buffer`.
/// Events should be produced in the order of expanding scope: from specific to general.
/// Example: account events before domain events.
pub fn emit_events<I: IntoIterator<Item = T>, T: Into<WorldEvent>>(&mut self, world_events: I) {
pub fn emit_events<I: IntoIterator<Item = T>, T: Into<DataEvent>>(&mut self, world_events: I) {
Self::emit_events_impl(
&mut self.world.triggers,
&mut self.events_buffer,
Expand All @@ -1263,15 +1263,15 @@ impl WorldStateView {
/// Implementation of [`Self::emit_events()`].
///
/// Usable when you can't call [`Self::emit_events()`] due to mutable reference to self.
fn emit_events_impl<I: IntoIterator<Item = T>, T: Into<WorldEvent>>(
fn emit_events_impl<I: IntoIterator<Item = T>, T: Into<DataEvent>>(
triggers: &mut TriggerSet,
events_buffer: &mut Vec<Event>,
world_events: I,
) {
let data_events: SmallVec<[DataEvent; 3]> = world_events
.into_iter()
.map(Into::into)
.flat_map(WorldEvent::flatten)
.map(Into::into)
.collect();

for event in data_events.iter() {
Expand All @@ -1285,7 +1285,7 @@ impl WorldStateView {
/// Produces [`PermissionTokenSchemaUpdateEvent`].
pub fn set_permission_token_schema(&mut self, schema: PermissionTokenSchema) {
let old_schema = std::mem::replace(&mut self.world.permission_token_schema, schema.clone());
self.emit_events(std::iter::once(WorldEvent::PermissionTokenSchemaUpdate(
self.emit_events(std::iter::once(DataEvent::PermissionToken(
PermissionTokenSchemaUpdateEvent {
old_schema,
new_schema: schema,
Expand Down
80 changes: 4 additions & 76 deletions data_model/src/events/data/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@

use getset::Getters;
use iroha_data_model_derive::{model, Filter, HasOrigin};
use iroha_primitives::small::SmallVec;

pub use self::model::*;
use super::*;
Expand Down Expand Up @@ -61,22 +60,6 @@ pub mod model {
pub value: Box<Value>,
}

/// World event
///
/// Does not participate in `Event`, but useful for events warranties when modifying `wsv`
#[derive(
Debug, Clone, PartialEq, Eq, FromVariant, Decode, Encode, Deserialize, Serialize, IntoSchema,
)]
pub enum WorldEvent {
Peer(peer::PeerEvent),
Domain(domain::DomainEvent),
Role(role::RoleEvent),
Trigger(trigger::TriggerEvent),
PermissionTokenSchemaUpdate(permission::PermissionTokenSchemaUpdateEvent),
Configuration(config::ConfigurationEvent),
Executor(executor::ExecutorEvent),
}

/// Event
#[derive(
Debug,
Expand All @@ -98,12 +81,6 @@ pub mod model {
Peer(peer::PeerEvent),
/// Domain event
Domain(domain::DomainEvent),
/// Account event
Account(account::AccountEvent),
/// Asset definition event
AssetDefinition(asset::AssetDefinitionEvent),
/// Asset event
Asset(asset::AssetEvent),
/// Trigger event
Trigger(trigger::TriggerEvent),
/// Role event
Expand Down Expand Up @@ -629,65 +606,19 @@ pub trait HasOrigin {
fn origin_id(&self) -> &<Self::Origin as Identifiable>::Id;
}

impl WorldEvent {
/// Unfold [`Self`] and return vector of [`Event`]s in the expanding scope order: from specific to general.
/// E.g [`AssetEvent`] -> [`AccountEvent`] -> [`DomainEvent`]
pub fn flatten(self) -> SmallVec<[DataEvent; 3]> {
let mut events = SmallVec::new();

match self {
WorldEvent::Domain(domain_event) => {
match &domain_event {
DomainEvent::Account(account_event) => {
if let AccountEvent::Asset(asset_event) = account_event {
events.push(DataEvent::Asset(asset_event.clone()));
}
events.push(DataEvent::Account(account_event.clone()));
}
DomainEvent::AssetDefinition(asset_definition_event) => {
events.push(DataEvent::AssetDefinition(asset_definition_event.clone()));
}
_ => (),
}
events.push(DataEvent::Domain(domain_event));
}
WorldEvent::Peer(peer_event) => {
events.push(DataEvent::Peer(peer_event));
}
WorldEvent::Role(role_event) => {
events.push(DataEvent::Role(role_event));
}
WorldEvent::Trigger(trigger_event) => {
events.push(DataEvent::Trigger(trigger_event));
}
WorldEvent::PermissionTokenSchemaUpdate(token_event) => {
events.push(DataEvent::PermissionToken(token_event));
}
WorldEvent::Configuration(config_event) => {
events.push(DataEvent::Configuration(config_event));
}
WorldEvent::Executor(executor_event) => {
events.push(DataEvent::Executor(executor_event));
}
}

events
}
}

impl From<AccountEvent> for WorldEvent {
impl From<AccountEvent> for DataEvent {
fn from(value: AccountEvent) -> Self {
DomainEvent::Account(value).into()
}
}

impl From<AssetDefinitionEvent> for WorldEvent {
impl From<AssetDefinitionEvent> for DataEvent {
fn from(value: AssetDefinitionEvent) -> Self {
DomainEvent::AssetDefinition(value).into()
}
}

impl From<AssetEvent> for WorldEvent {
impl From<AssetEvent> for DataEvent {
fn from(value: AssetEvent) -> Self {
AccountEvent::Asset(value).into()
}
Expand All @@ -698,9 +629,6 @@ impl DataEvent {
pub fn domain_id(&self) -> Option<&DomainId> {
match self {
Self::Domain(event) => Some(event.origin_id()),
Self::Account(event) => Some(&event.origin_id().domain_id),
Self::AssetDefinition(event) => Some(&event.origin_id().domain_id),
Self::Asset(event) => Some(&event.origin_id().definition_id.domain_id),
Self::Trigger(event) => event.origin_id().domain_id.as_ref(),
Self::Peer(_)
| Self::Configuration(_)
Expand Down Expand Up @@ -731,6 +659,6 @@ pub mod prelude {
trigger::{
TriggerEvent, TriggerEventFilter, TriggerFilter, TriggerNumberOfExecutionsChanged,
},
DataEvent, HasOrigin, MetadataChanged, WorldEvent,
DataEvent, HasOrigin, MetadataChanged,
};
}
78 changes: 53 additions & 25 deletions data_model/src/events/data/filters.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,12 +52,6 @@ pub mod model {
ByPeer(FilterOpt<PeerFilter>),
/// Filter by Domain entity. `AcceptAll` value will accept all `Domain` events
ByDomain(FilterOpt<DomainFilter>),
/// Filter by Account entity. `AcceptAll` value will accept all `Account` events
ByAccount(FilterOpt<AccountFilter>),
/// Filter by AssetDefinition entity. `AcceptAll` value will accept all `AssetDefinition` events
ByAssetDefinition(FilterOpt<AssetDefinitionFilter>),
/// Filter by Asset entity. `AcceptAll` value will accept all `Asset` events
ByAsset(FilterOpt<AssetFilter>),
/// Filter by Trigger entity. `AcceptAll` value will accept all `Trigger` events
ByTrigger(FilterOpt<TriggerFilter>),
/// Filter by Role entity. `AcceptAll` value will accept all `Role` events
Expand Down Expand Up @@ -145,13 +139,9 @@ impl Filter for DataEntityFilter {
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::ByAccount(filter_opt), DataEvent::Account(account)) => {
filter_opt.matches(account)
(Self::ByTrigger(filter_opt), DataEvent::Trigger(trigger)) => {
filter_opt.matches(trigger)
}
(Self::ByAssetDefinition(filter_opt), DataEvent::AssetDefinition(asset_definition)) => {
filter_opt.matches(asset_definition)
}
(Self::ByAsset(filter_opt), DataEvent::Asset(asset)) => filter_opt.matches(asset),
(Self::ByRole(filter_opt), DataEvent::Role(role)) => filter_opt.matches(role),
_ => false,
}
Expand Down Expand Up @@ -241,22 +231,60 @@ mod tests {
metadata: Metadata::default(),
};
let asset_id = AssetId::new(
AssetDefinitionId::new(asset_name, domain_id),
AssetDefinitionId::new(asset_name, domain_id.clone()),
account_id.clone(),
);
let asset = Asset::new(asset_id, 0u32);

let domain_created = DomainEvent::Created(domain);
let account_created = AccountEvent::Created(account);
let asset_created = AssetEvent::Created(asset);
let account_asset_created = AccountEvent::Asset(asset_created.clone());
let account_filter = BySome(DataEntityFilter::ByAccount(BySome(AccountFilter::new(
BySome(OriginFilter(account_id)),
let asset = Asset::new(asset_id.clone(), 0u32);

// Create three events with three levels of nesting
// the first one is just a domain event
// the second one is an account event with a domain event inside
// the third one is an asset event with an account event with a domain event inside
let domain_created = DomainEvent::Created(domain).into();
let account_created = DomainEvent::Account(AccountEvent::Created(account)).into();
let asset_created =
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(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,
)))),
))));
assert!(!account_filter.matches(&domain_created.into()));
assert!(!account_filter.matches(&asset_created.into()));
assert!(account_filter.matches(&account_created.into()));
assert!(account_filter.matches(&account_asset_created.into()));
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,
)))),
)))),
))));

// domain filter matches all of those, because all of those events happened in the same domain
assert!(domain_filter.matches(&domain_created));
assert!(domain_filter.matches(&account_created));
assert!(domain_filter.matches(&asset_created));

// account event does not match the domain created event, as it is not an account event
assert!(!account_filter.matches(&domain_created));
assert!(account_filter.matches(&account_created));
assert!(account_filter.matches(&asset_created));

// asset event matches only the domain->account->asset event
assert!(!asset_filter.matches(&domain_created));
assert!(!asset_filter.matches(&account_created));
assert!(asset_filter.matches(&asset_created));
}
}
Loading

0 comments on commit 5a8bdfc

Please sign in to comment.