Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[refactor] #3068: remove flattened events #4170

Merged
merged 1 commit into from
Dec 25, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading