Expand description
Contains high-level traits that translate to on-chain transaction interactions
§Actions
The main concept is an “action”, which a node can perform and results into an on-chain operation. These actions are all on the external interface of this crate which is represented by the ChainActions type. There are 3 classes of actions implemented in submodules of this crate:
Each action is represented by a method (or methods) that are imported into the ChainActions type through a trait from the respective module (e.g. ChannelActions trait for channel actions). Each action will eventually translate to an on-chain transaction. An action will always return a PendingAction future. This future can be awaited or not, depending if the caller wishes to obtain the ActionConfirmation of the submitted action. If the action’s caller wishes to await the confirmation, this process can end in one of 3 possible states:
- the action gets confirmed, meaning it has been successfully executed.
- awaiting the confirmation returns an error, which typically means a failure during action prerequisite checks, an invalid state to execute the action or invalid arguments given to the action
- awaiting the confirmation times out, meaning the execution failed on-chain and the “action expectations” did not yield (see below for details on how “action expectations work”).
Not awaiting the returned PendingAction future does not give the caller any guarantees on how the action has executed, although this might be perfectly fine for certain cases (fire & forget).
§How are actions executed and make it on-chain ?
Call to any ChainAction’s method is eventually represented as an Action enum with parameters that already closely resemble the required on-chain transaction input for that action to be The Action enum instance is then passed via an ActionSender into the ActionQueue. The ActionQueue takes care of ensuring the FIFO order of the actions which is driven by a standalone action loop and must be instantiated before ChainActions, so that it can provide it with an ActionSender.
§Queueing of actions
The ActionQueue operates a MPSC queue, which picks up the Actions submitted to it one by one. With each such action it will:
- transform Action into a TypedTransaction via a PayloadGenerator
- submit the TypedTransaction on-chain via a TransactionExecutor
- generate an IndexerExpectation from the submitted action
- submit the IndexerExpectation in an ActionState implementation
- wait for expectation to be resolved (or timeout, see ActionQueueConfig and resolve the action submitter’s PendingAction.
In other words, the ActionQueue takes care of two important mappings:
The first one makes it possible for an action to make it on-chain, the second one allows to be informed of the action’s result and effect.
See the action_queue module for details.
§On-chain expectations after an action is submitted
The action_state module defines the ActionState trait which is responsible
for registering IndexerExpectation done by the ActionQueue.
The implementor of the ActionState should be monitoring the state of the block chain (reading
event logs contained inside newly mined blocks) and with each on-chain event that matches a registered expectation,
mark it as resolved to allow the bound action to be confirmed in the ActionQueue.
Therefore, the two components which interact with an ActionState implementation
are the ActionQueue and the on-chain Indexer (see chain-indexer
crate for details).
There’s an exception on construction of an expectation for the withdraw
NodeAction:
Since the current implementation of the Indexer does not track native token transfers, but only smart contract
events, it is impossible to detect the native token’s transfer confirmation.
Since the withdraw
action is not very common, its confirmation is tracked via direct polling of the RPC
provider until the transaction is confirmed. The confirmation horizon is set in the TransactionExecutor.
See the action_state module for details.
§Payload generators
As described above, the ActionQueue needs a PayloadGenerator implementation to be able to translate the Action into the TypedTransaction. There are currently two possible ways of constructing the action’s transaction:
- via plain EIP1559 payload
- via EIP1559 payload containing a SAFE transaction that embeds the actual payload
The former one is implemented via BasicPayloadGenerator, the latter is implemented in SafePayloadGenerator.
In most situations, the transaction payload an action translates to, typically constitutes a smart contract call of one of the HOPR smart contracts deployed on-chain.
See the payload module for details.
Modules§
- action_
queue - Defines the main FIFO MPSC queue for actions - the ActionQueue type.
- action_
state - This module adds functionality of tracking the action results via expectations.
- channels
- This module contains the ChannelActions trait defining HOPR channels operations.
- errors
- Contains all errors used in this crate.
- node
- This module contains the NodeActions trait defining action which relate to HOPR node itself.
- payload
- Module defining various Ethereum transaction payload generators for the actions.
- redeem
- This module contains the TicketRedeemActions trait defining actions regarding ticket redemption.
Structs§
- Chain
Actions - Contains all actions that a node can execute on-chain.