Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

A named rule that gives the privilege to perform a command. Permission cannot be granted to an account directly, instead, account has roles, which are collections of permissions. Although, there is an exception, see Grantable Permission.

...

This whole concept can be used for event listeners, `Instruction::Listener` can be executed for their configuration, but additionally to storing them in assets components of the account we need to find a way to store global Listeners (Domain level, Peer level) and define cases where we need time based listeners.

"Listeners" store

Current design assumes that we provide instructions with a mutable reference to `WorldStateView` after their validation and store on the block chain. So the only way to trigger Listeners of Conditions (changes in World State View) and Blocks and, possibly, Time is to store them in `WorldStateView`:


No Format
  6 /// Current state of the blockchain alligned with `Iroha` module.
  7 #[derive(Debug, Clone)]
  8 pub struct WorldStateView {
  9     peer: Peer,
        listeners: Vec<ListenerInstruction>,
 10 }
 11 
 12 impl WorldStateView {
 13     /// Default `WorldStateView` constructor.
 14 +---  3 lines: pub fn new(peer: Peer) -> Self {··························································································································
 17 
 18     /// Put `ValidBlock` of information with changes in form of **Iroha Special Instructions**
 19     /// into the world.
 20     pub async fn put(&mut self, block: &CommittedBlock) {
 21         for transaction in &block.transactions {
 22             if let Err(e) = &transaction.proceed(self) {
 23                 eprintln!("Failed to procced transaction on WSV: {}", e);
 24             }
 25         }
 26     }

As you can see - `put` method may invoke (trigger) listeners execution (because they are just a set of out of the box instructions). The question is - should we execute them here or send a new transaction to the ledger?

ASAP execution

Let's imagine as soon as possible execution and consequences:


No Format
 12 impl WorldStateView {
 13     /// Default `WorldStateView` constructor.
 14 +---  3 lines: pub fn new(peer: Peer) -> Self {··························································································································
 17 
 18     /// Put `ValidBlock` of information with changes in form of **Iroha Special Instructions**
 19     /// into the world.
 20     pub async fn put(&mut self, block: &CommittedBlock) {
 21         for transaction in &block.transactions {
 22             if let Err(e) = &transaction.proceed(self) {
 23                 eprintln!("Failed to procced transaction on WSV: {}", e);
 24             }
                for listener in self.listeners {
                  listener.execute(self);
                }
 25         }
 26     }

First question - how should listener understand was it triggered or not? It has only current state, not the delta of changes.

Second one - how should we spread results of it's execution between peers and synchronize I/O actions like notifications, etc.?

Third one - how should we check that listener execution will not break next transactions?

This questions gave us following requirements:

  • Listeners should be executed only once in the ledger
  • Listeners should be able to track changes (in time, blockchain and world_state_view)
  • Listeners should be not executed during validation phase (to prevent unexpected I/O)
  • Listeners should be executed after all block's transactions execution

Follow-up execution

What if instead of asap execution we will only form a new transaction with a set of instructions to execute?

No Format
 18     /// Put `ValidBlock` of information with changes in form of **Iroha Special Instructions**
 19     /// into the world.
 20     pub async fn put(&mut self, block: &CommittedBlock) {
 21         for transaction in &block.transactions {
 22             if let Err(e) = &transaction.proceed(self) {
 23                 eprintln!("Failed to procced transaction on WSV: {}", e);
 24             }
 25         }
            client.submit_all(
                listeners.execute(self, block)
            );
 26     }

But almost all requirements stay open with this solution.

Results