Versions Compared

Key

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

...

Page properties
label



Background

Whitepaper gave some information about Triggers and initial requirements about this functionality, but a lot of open questions comes come into play when implementation details were discussed.

...

  1. Database triggers - Oracle example
  2. Substrate weight and fee handling use cases in `pre-dispatch` and `post-dispatch` stages of transaction processing

Problem

Iroha Special Instructions can not provide the fully fledged toolbox for all possible use cases because they lack an ability to react on changes in Iroha state. Iroha Triggers provide this functionality and in addition to Iroha Special Instructions give users full-scale functionality for almost any business scenario.

Triggers execution, in contrast to transaction execution, depends on condition.

  1. Smart contracts in other blockchains
  2. Event driven architecture

Problem

Currently we can submit transactions that can modify global state if they pass validation. These transactions can contain `Query`s inside of them, allowing them limited capability to execute logic on-chain.
Transactions can include:

  1. Iroha Special Instrucions
  2. (Unclear if needed and not yet implemented) WASM blobs

Independently of their content type they will have limited capability as they will only be able to execute the contained logic once.


Though as it is established in blockchain space current use cases require a more sophisticated functionality to efficiently support DeFi:

Use CaseNeeds *

Swaps

Triggered by user; Does several additional state validations; Manages liquidity;

Periodic Reward Distribution

Executed periodically; Distributes to all users satisfying certain condition;

Customizable and modifiable transaction fees

Executed for each transaction; Have ability to disallow transaction execution;
Stable coins contractsExecuted periodically or triggered by user; Possibly check external conditions provided by oracle contracts;
Oracle smart contractsTriggered  by user; Aggregate data from external world; Provide data to other contracts

*- Algorithms for all of these use cases need to be on chain for transparency and safety guarantees, which are provided by consensus.


Other use cases for permissioned blockchains might include (these use cases are proposed to be handled outside of the context of triggers, see `Outside of Triggers Scope` section):

Use CaseNeedsComments
Transaction Metadata ValidationExecuted for each transaction; Have ability to disallow transaction execution;
Transaction `Set` Instructions Validation for Account, Domain and Asset Definition metadataExecuted for each transaction; Have ability to disallow transaction execution; Have access to transaction ISI contents;

Permission Management

Executed for each transaction; Have ability to disallow transaction execution; Have access to transaction ISI contents;We can let all permissions be customizable and upgrade-able during runtime if we use Triggers.


Solution

To execute arbitrary logic on-chain for unrestricted number of times other popular blockchains have Smart Contracts. Our solution for introducing smart contract functionality is called Triggers.

This is how triggers are described in the whitepaper:

Triggers are Iroha Special Instructions that may be invoked based on condition. This is very powerful feature Triggers can be either based on time or on a confirmed transaction (event). This is very powerful and enables Turing complete computation for Iroha's smart contractsSpecial Instructions.

  • Trigger at timestamp (every 5 minutes or after one hour)
  • Trigger at blockchain (new block, reach of some height, etc.)
  • Trigger at condition (new account, transfer of an asset, etc.)

Also, for cases like Iroha Permissions Module we will  need to be able to manage Triggers execution order - for example to execute them before block/transaction/instruction or after.

Order Book case

Users send bid and ask limit orders into the order book. Every order in the order book should be executed when counter order with the same price will be received. Speaking other word it should happen when bid meets ask at the same price. In this case limit order should be notified that there is a matching order and swap should be executed with resulting funds sent to the owners of both orders. Looks like this notification is reasonable to implement using triggers.

  1.  Challenging here is that there might be really a lot of orders in the order book and every order should have a trigger and every trigger should be checked somehow if price counter order exists or not.
  2. Another challenge is that after one order executed using a certain amount of funds of counter order, other orders having the same price cannot be executed on the same amount of the counter order funds. Other orders even for the same price should wait for new free fund amounts of counter orders.

Impure Triggers and Instructions

Because impure (I/O to 3rd party systems) Instructions and Triggers will not be supported by Iroha 2 - Iroha Events can be used to receive information by Cloud Events Consumers.

Solution

Peer can be a place to store Iroha Triggers. We can register new Triggers by Register<Peer, Trigger> Iroha Special Instruction. 

Because we depend on triggers a lot, we will have tight coupling between transactions processing and their execution. Every Iroha Special Instruction that changes Iroha state (domain related instructions category from Set of OOB ISIs) can Trigger, so we need to check Iroha Triggers that depend on conditions every instruction, Iroha Triggers that depend on blockchain every block and Iroha Triggers that depend on timestamp every block also. 

It is suggested to:

  • Trigger at condition

Events

Before discussing Triggers in detail it is important to consider Events, which might play a big role in Trigger execution.

Events can originate from 2 places:

  1. Triggers can decide to emit events
  2. Events will be automatically emitted for WSV changes
    1. The events are based on WSV diff after particular transaction execution.
    2. Examples: AccountCreated(_), AcccountMetadataFieldSet(_), AccountBalanceChanged(_)  etc.

Events emitted during execution of entities in the current block are added to the block. Though Triggers can react to them only in the next block.

Representation

As you can see in the quote from the whitepaper the Triggers were initially planned to be represented as ISI.
But with the recent decision to introduce WASM, it is suggested to use it for Triggers. So that Triggers can be written in Rust* and compiled into WASM.
This way Triggers will benefit from a high level language features of an already established language and will be able to solve all the listed use cases with ease.
As discussed previously, solving listed use cases with ISI was impossible or very difficult and needed significant work on the language design side.

*- generally speaking any language could be used that can be compiled into WASM. But due to Rust being our primary development language it is suggested to focus on it.

Execution

1 - Leader creates a block out of transactions that it got from the queue

Image Added

2 - Leader adds trigger execution recommendations to the created block

Image Added

Leader also should add events, emitted by the transaction execution and triggers, to the block.

3 - Validators receive the block and check if they agree with leader trigger execution recommendations

  1. Yes - if other checks also pass then validator votes for the block

  2. No - validator does not vote for the block

4 - If block got enough votes - all peers execute block transactions and triggers in their order at block commit.

Triggers might just influence other transactions in a way that they are executed before them, but do not directly do anything to other transactions.

Trigger Failure Case

In the case that at Stage 2 leader notices Trigger failure. It should indicate in the execution recommendation that this Trigger failed and Trigger error code.

Validators will then check that they also have this trigger failing.

On block commit peers will not need to try to execute this trigger, as it was proven that it fails.

Place in the WSV hierarchy

Corresponding to their meaning Triggers can be stored in 2 ways:

  • Top Level Triggers - in the World entity
    • They can operate on any data in WSV
  • Domain Level Triggers - in the corresponding Domain
    • Their access is restricted only to their Domain
  • Asset Definition Level Triggers
    • Their access is restricted only to assets of this definition

Second option might be interesting for permission-ed blockchains.

Categories

By purpose:

  • System Level - Influence the whole blockchain system rules and features
    • Do not pay fees for execution*
    • Permissions are not checked for them (can freely modify WSV state)
    • In comparison with Substrate based chains: Similar to runtime in Substrate
  • User Level - Provide services to users and other apps
    • Pay fees for execution*
    • Act on behalf of their technical accounts and their permissions
    • In comparison with Substrate based chains: Similar to smart contracts in Substrate

*- for more on this see Execution Limits

Also Registration process is different for them.

By wake up condition:

  • Time-based - (System Level and User Level )
    • At timestamp
    • Each `duration`
    • For complex use cases Trigger might register itself again to execute at another timestamp
    • We should limit the granularity of possible timestamps, as network has a limit of how fast it can produce and commit blocks
    • Time based Triggers seem to be difficult task for synchronization between peers. The following approach is suggested:
      • Recommendations to execute them should be added by the leader to the block (even if there are no transactions - leader should generate a block with trigger execution recommendations for them)

      • They are best effort - Iroha does not guarantee them to be executed at exact time. But it guarantees execution at closest possible time if network is operational.

      • If a leader does not produce a block with appropriate time based triggers in the defined time period after those trigger's selected timestamps - view change happens - similar to how if leader does not produce block for ordinary transactions

      • Next leader in this case will need to include the previous time based trigger in a block (when a view change happens it will be given a new time window to do this)

    • Example: Periodic rewards, scheduled batch processing
  • Block number-based  - (System Level and User Level )
    • At block
    • Each `n_blocks`
    • For complex use cases Trigger might register itself again to execute at another height
    • Might not be needed as there are already time based triggers, and block time is not fixed in Iroha v2.
    • Example: Per block rewards, scheduled batch processing
  • Store Triggers under Peer entity
  • Have the following Triggers categories:
    • Time-based
    • Block number-based
    • Transaction-based (can have a condition of whether they need to execute, similar to Oracle `when` condition)
  • Triggers that are triggered by specific ISI call - ExecuteTrigger(Params) - (System Level and User Level )
  • Have an ability to configure trigger order for Transaction Based triggers:
    • Before (transaction execution) - have the ability to check and fail or allow transaction
    • After (transaction execution)
  • Triggers will be build on top of Iroha Special Instructions and WASM
    • For instruction-based Triggers condition will be of `Instruction::Execute(Query)` type
    • All changes are declared as a set of Iroha Special Instructions or WASM

Decisions

Alternatives

  • Store Triggers as Assets - to much complexity and runtime dependent code
  • Execute Triggers sending new set of transactions - require networking communications, can end up in missing triggers

Concerns

  • Some complexity for end users
  • Open question about parameters propagation (condition → execution)

Assumptions

  • We do not have impurity inside Iroha and all Triggers can be replayed on different peers resulting in the same state of each consensus participant
  • For triggers we assume that time on different peers in some sync state with delays less or equal to block build time

Risks

...

    • Similar to smart contracts as they are in Ethereum blockchain
    • Execute as part of the transaction instructions execution
    • For System Level - only admin can call the Trigger or through democracy pallet
    • Example: Swap with liquidity pool, locking funds (for bridges or stable coins for example)
  • Event-based - (System Level and User Level )
    • Triggered by events emitted from other triggers or transaction execution.
    • The triggers react to the events emitted in the previous block as shown in the `Execution` section.
    • If leader does not supply the needed trigger execution recommendations based on events from previous block -
      the block will be rejected and the next leader will have to do this.
    • Leader has to produce a block with event based triggers in time, even if it will contain no transactions.
      Or the view change will happen and the scenario proceeds similar to time based triggers.
    • Example: Reacting to currency flow, reacting to system events (events from system level triggers), keeping metadata in sync

Persistent State

Complex Triggers (such as Swap triggers managing Liquidity Pools) might need to store data between their invocations. For this purpose Triggers will have following persistent storage:

  • Key value Store (Similar to Account, Asset Definition, Domain and Tx metadata)
  • On demand technical accounts where they might keep transferred funds.
    • While of course technical accounts can be emulated with key value store.
      This might complicate usage of Transfer, Mint and other currency related features while using Triggers.
      This also loosens the more strict definition of Currency and therefore is more error-prone.
      Therefore is suggested to keep the technical accounts option.

Registration

Trigger is registered by Register<Trigger> instruction. Submitted inside of it as WASM blob.
We have to consider adding appropriate permissions for this instruction.

For private blockchain we might start with a simple permission that only user with corresponding Permission Token can register Triggers.

For public blockchain we need to consider two distinct cases for Trigger registration based on their purpose:

  1. System Level Triggers - should be registered with democracy voting module*
  2. User Level Triggers - users can freely register their own triggers if they can pay trigger registration fee (which might depend on WASM blob size)

*- democracy voting module is assumed to be similar to the one used in Substrate based chains for runtime upgrades.

For public blockchain use cases we can also introduce parachain like behavior for Triggers to be only registered for a fixed amount of time, after which they will need to be registered again.
This will prevent clogging blockchain with "dead" triggers - triggers that no longer have users.

Communication with other Triggers

Generally Triggers can communicate with other Triggers by changing the WSV state and also by calling other triggers through ExecuteTrigger ISI.

ExecuteTrigger ISI might be designed to return some value, therefore introducing a class of `Library Triggers` that are used by other Triggers for various features.

Triggers can also communicate by defining and emitting events at their execution.

Execution Limits

Trigger execution uses validators' processing resources and therefore has to be limited for the network to stay operational.
Limits would mainly apply to User Level triggers as they are registered freely and are not part of the system itself.

The following is proposed:

  1. Limit max number of WASM instructions that can be executed per Trigger
  2. Take network fees for Trigger execution:
    1. In general case fees can be taken from the Trigger's technical account balance.
    2. Fees can be taken for each WASM instruction that is executed - the concept is known as `fuel` in WASM runtimes.
    3. If technical account does not have enough funds - changes made by Trigger are reverted.
    4. For Triggers called by ExecuteTrigger(_) we might consider the same approach that is used in Ethereum - take funds from the account that called it.

There is also a question of how to limit their `condition` execution if condition is also in WASM. Possibly fees will be also taken just for condition checks, but in lesser amount than for the actual execution.

Misc

It might be good to provide Triggers with a way to `Unregister` themselves. Especially for public blockchain use cases.

Outside of Triggers Scope

The following topics are proposed not to be handled with Triggers but instead considered separately. Both of the topics need a separate RFC, but they are mentioned here in the context of their relation to Triggers.

In Triggers we wanted to both of these as part of Transaction Based Triggers (After/Before Transaction) - this proposal effectively removes this type of Triggers from design.

Instruction and Query Permissions

We considered moving our permission check into Triggers (for them to be runtime upgradeable), but this does not seem like a good idea due to the following reason.

If Triggers are used to check instructions' permissions during transaction execution, then how should Trigger permissions be checked.
If it is decided to:

  1. Handle transaction permission checks and trigger permission checks separately - this will create inconsistency.
  2. Use triggers to check execution of other triggers - this introduces a lot of complexity into the design.

Instead it is proposed to have Permissions as WASM plugin which is not a Trigger, but a separate part of the system. This will allow us to upgrade them at runtime, without the complexity that might be there with Triggers.

It is possible to either migrate current permission system simply to WASM and provide instructions to update them, or we can work on diff based permissioning - which will check WSV diffs after instruction/transaction/trigger execution.

Network Fees

We also considered using Triggers for handling network fees (transaction and trigger fees), but again there is a following issue.

If transaction based Triggers are used to calculate transaction fees, how should we calculate Trigger execution fees.
Here again there might arise either consistency or complexity problems.

Instead it is proposed to have either a highly configurable system where fee configuration can be done at runtime, or again do it through a separate WASM plugin (if fee handling logic might be changed at runtime).

Additional Information