[−][src]Module exonum::runtime
Common building blocks that compose runtimes for the Exonum blockchain.
Each runtime contains specific services that execute transactions, process events, provide user APIs, etc. A unified dispatcher redirects all the calls and requests to an appropriate runtime environment. Thus, a blockchain interacts with the dispatcher, and not with specific runtime instances.
Artifacts
An artifact creates service instances similar to classes in object-oriented programming. Artifacts reflect the assumption that deploying business logic onto the blockchain may take a long time, may fail, end up with differing results on different nodes, etc. Thus, artifacts decouple the complex deployment of the business logic from its instantiation (which we assume is simple / non-fallible).
Depending on the runtime, an artifact may have an additional specification required for its deployment; e.g., files to be compiled.
Each runtime has its own artifacts registry. Users can create services from the stored artifacts. An artifact identifier is required by the runtime to construct service instances. In other words, an artifact identifier is similar to a class name, and a specific service instance - to a class instance. A single artifact may be used to instantiate zero or more services.
The format of the artifact ID is uniform across runtimes - it is essentially a string. But the runtime may customize artifact deployment via runtime-specific deployment arguments.
Artifact Lifecycle
-
An artifact is assembled in a way specific to the runtime. For example, an artifact may be compiled from sources and packaged using an automated build system.
-
The artifact with the service is deployed on the blockchain. The decision to deploy the artifact and the deployment spec are usually performed by the blockchain administrators. The corresponding logic is customizable via the supervisor service. What deployment entails depends on the runtime; e.g., the artifact may be downloaded by each Exonum node, verified for integrity and then added into the execution environment.
-
For each node, an artifact may be deployed either asynchronously or synchronously, that is in a blocking manner. The supervisor usually first commands a node to deploy the artifact asynchronously via
Mailbox
, once the decision to start deployment is reached by the blockchain administrators. Asynchronous deployment speed and outcome may differ among nodes. -
The supervisor translates the local deployment outcomes into a consensus-agreed result. For example, the supervisor may collect confirmations from the validator nodes that have successfully deployed the artifact. Once all the validator nodes have sent their confirmations, the artifact is committed. As a part of the service logic, artifact commitment is completely deterministic, agreed via consensus, and occurs at the same blockchain height for all nodes in the network.
-
Once the artifact is committed, every node in the network must have it deployed in order to continue functioning. If a node has not deployed the artifact previously, deployment becomes blocking. The node does not participate in consensus or block processing until the deployment is completed successfully. If the deployment is unsuccessful, the node stops indefinitely. The deployment confirmation mechanics is built into the supervisor. Thus, it is reasonable to assume that a deployment failure at this stage is local to the node and could be fixed by the node admin.
-
If the artifact is not associated with any services, it can be unloaded. Unloading the artifact may free resources associated with it in the corresponding runtime. Like other lifecycle events, unloading an artifact is controlled by the supervisor service.
Service Lifecycle
-
Once the artifact is committed, it is possible to instantiate the corresponding service. Each instantiation request contains an ID of the previously deployed artifact, a string instance ID, and instantiation arguments in a binary encoding (by convention, Protobuf). As with the artifacts, the logic that controls instantiation is encapsulated in the supervisor service.
-
During instantiation the service gets a numeric ID, which is used to reference the service in transactions. The runtime can execute initialization logic defined in the service artifact; e.g., the service may store some initial data in the storage, check service dependencies, etc. If the service (or the enclosing runtime) signals that the initialization failed, the service is considered not instantiated.
-
Once the service is instantiated, it can process transactions and interact with the external users in other ways. Different services instantiated from the same artifact are independent and have separate blockchain storages. Users can distinguish services by their IDs; both numeric and string IDs are unique within a blockchain. (Note that the transition to the "active" state is not immediate; see Service State Transitions section below.)
-
Active service instances can be stopped or frozen by a corresponding request to the dispatcher.
The dispatcher is responsible for persisting artifacts and services across node restarts.
A stopped service no longer participates in business logic, i.e., it does not process transactions or hooks, and does not interact with the users in any way. Service data becomes unavailable for the other services, but still exists. The service name and identifier remain reserved for the stopped service and can't be used again for adding new services.
Frozen service state is similar to the stopped one, except the service state can be read both by internal readers (other services) and external ones (HTTP API handlers).
Service Hooks
Each active service is called before any transactions in the block are processed;
we call this before_transactions
hook. The service may modify the blockchain state in this hook.
Likewise, each active service is called after all transactions in the block have been processed
(we call this after_transactions
hook). These calls are quite similar to transactions:
- Each call is isolated
- Service logic may return an error, meaning that all state changes made within the hook are rolled back
- The service may call other services within the hook
Service State Transitions
Transitions between service states (including service creation) occur once the block
with the transition is committed; the effect of a transition is not immediate. This means
that, for example, an instantiated service cannot process transactions or internal calls
in the block with instantiation, but can in the following block. Likewise, the service hooks
(before_transactions
/ after_transactions
) are not called in the block with service
instantiation.
When the service is stopped or frozen, the reverse is true:
- The service continues processing transactions until the end of the block containing the stop command
- The service hooks are called for the service in this block
Transaction Lifecycle
-
An Exonum client creates a transaction message which includes two parts. The first part is the
CallInfo
- information about a method to call. The second part is the serialized method parameters as a payload. The client then signs the message using the Ed25519 signature system. -
The client transmits the message to one of the Exonum nodes in the network.
-
The node verifies correctness of the transaction signature and retransmits it to the other network nodes if it is correct.
-
When the consensus algorithm finds a feasible candidate for the next block of transactions, transactions in this block are passed to the dispatcher for execution.
-
The dispatcher uses a lookup table to find the corresponding
Runtime
for each transaction by theinstance_id
recorded in the transaction message. If the corresponding runtime exists, the dispatcher passes the transaction into this runtime for immediate execution. -
After execution the transaction execution status is written into the blockchain.
Data Migration Lifecycle
Service data can be migrated to a newer version of the service artifact.
See migrations
module docs for details.
Supervisor Service
A supervisor service is a service that has additional privileges. This service allows deploying artifacts and instantiating new services after the blockchain is launched and running. Moreover the Supervisor service allows update the configuration or stop the active service instances. Other than that, it looks like an ordinary service.
To enable adding new artifacts / services to the blockchain after its start, the supervisor must be one of the builtin service instances.
The supervisor service is distinguished by its numerical ID, which must be set
to SUPERVISOR_INSTANCE_ID
. Services may assume that transactions originating from
the supervisor service are authorized by the blockchain administrators. This can be used
in services: if a certain transaction originates from a service with SUPERVISOR_INSTANCE_ID
,
it is authorized by the administrators.
See Also
Modules
migrations | Data migration tools. |
oneshot | A channel for sending a deployment status between threads. |
versioning | Versioning tools for Exonum artifacts. |
Structs
AnyTx | Transaction with the information required to dispatch it to a service. |
ArtifactId | The artifact identifier is required to construct service instances. In other words, an artifact identifier is similar to a class name, and a specific service instance is similar to a class instance. |
ArtifactSpec | Exhaustive artifact specification. This information is enough to deploy an artifact. |
ArtifactState | Current state of an artifact. |
BlockchainData | Provides access to blockchain data for the executing service. |
CallInfo | Information sufficient to route a transaction to a service. |
CallSite | Site of a call where an |
CallerAddress | Uniform presentation of a |
DispatcherSchema | Schema of the dispatcher, used to store information about pending artifacts / service instances, and to reload artifacts / instances on node restart. |
ErrorMatch | Matcher for |
ExecutionContext | Provides the current state of the blockchain and the caller information for the call which is being executed. |
ExecutionError | Result of unsuccessful runtime execution. |
ExecutionStatus | Status of a call execution in a way it is stored in the blockchain.
This result may be either an empty unit type, in case of success,
or an |
InstanceDescriptor | Instance descriptor contains information to access the running service instance. |
InstanceSpec | Exhaustive service instance specification. |
InstanceState | Current state of service instance in dispatcher. |
Mailbox | Mailbox accumulating |
MigrationStatus | Result of execution of a migration script. |
RuntimeInstance | Instance of |
Enums
ArtifactStatus | Status of an artifact deployment. |
CallType | Type of a call to a service. |
Caller | The authorization information for a service call. |
CommonError | List of possible common errors. |
CoreError | List of possible core errors. |
DispatcherAction | Action to be performed by the dispatcher. |
ErrorKind | Kind of execution error, divided into several distinct sub-groups. |
InstanceQuery | Allows to query a service instance by either of the two identifiers. |
InstanceStatus | Status of a service instance. |
RuntimeFeature | Optional features that may or may not be supported by a particular |
RuntimeIdentifier | List of predefined runtimes. |
Constants
SUPERVISOR_INSTANCE_ID | Persistent identifier of a supervisor service instance. |
Traits
ExecutionFail | Trait representing an error type defined in the service or runtime code. |
Runtime | Runtime environment for Exonum services. |
SnapshotExt | Extension trait for |
WellKnownRuntime | A subset of |
Functions
catch_panic | Invokes closure, capturing the cause of the unwinding panic if one occurs. |
Type Definitions
InstanceId | Unique service instance identifier. |
MethodId | Identifier of the method in the service interface required for the call. |