-
Notifications
You must be signed in to change notification settings - Fork 17
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
A rough draft of the Tari network logic layer description. The logic layer has many moving parts and I'm trying to thread the needle of making it a useful roadmap for the code without simply rewriting the code in English, or being too vague as to make it useless. It will definitely need another pass or two.
- Loading branch information
Showing
2 changed files
with
267 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,266 @@ | ||
# RFC-0350/TariVM | ||
|
||
## The Tari Virtual Machine | ||
|
||
![status: draft](theme/images/status-draft.svg) | ||
|
||
**Maintainer(s)**: [Cayle Sharrock](https://github.com/CjS77) | ||
|
||
# Licence | ||
|
||
[The 3-Clause BSD Licence](https://opensource.org/licenses/BSD-3-Clause). | ||
|
||
Copyright 2023 The Tari Development Community | ||
|
||
Redistribution and use in source and binary forms, with or without modification, are permitted provided that the | ||
following conditions are met: | ||
|
||
1. Redistributions of this document must retain the above copyright notice, this list of conditions and the following | ||
disclaimer. | ||
2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following | ||
disclaimer in the documentation and/or other materials provided with the distribution. | ||
3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote products | ||
derived from this software without specific prior written permission. | ||
|
||
THIS DOCUMENT IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS", AND ANY EXPRESS OR IMPLIED WARRANTIES, | ||
INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE | ||
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | ||
SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR | ||
SERVICES; LOSS OF USE, DATA OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | ||
WHETHER IN CONTRACT, STRICT LIABILITY OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF | ||
THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
|
||
## Language | ||
|
||
The keywords "MUST", "MUST NOT", "REQUIRED", "SHALL", "SHALL NOT", "SHOULD", "SHOULD NOT", "RECOMMENDED", | ||
"NOT RECOMMENDED", "MAY" and "OPTIONAL" in this document are to be interpreted as described in | ||
[BCP 14](https://tools.ietf.org/html/bcp14) (covering RFC2119 and RFC8174) when, and only when, they appear in all capitals, as | ||
shown here. | ||
|
||
## Disclaimer | ||
|
||
This document and its content are intended for information purposes only and may be subject to change or update | ||
without notice. | ||
|
||
This document may include preliminary concepts that may or may not be in the process of being developed by the Tari | ||
community. The release of this document is intended solely for review and discussion by the community of the | ||
technological merits of the potential system outlined herein. | ||
|
||
## Goals | ||
|
||
This RFC describes the design goals and rationale for the Tari Virtual Machine (TVM). | ||
|
||
## Related Requests for Comment | ||
|
||
* [RFC-0303: Digital Assets Network](RFC-0303_DanOverview.md) | ||
* [RFC-305: The Tari Network Consensus Layer](RFC-0305_Consensus.md) | ||
|
||
## Description | ||
|
||
The Consensus Layer for the Tari network, described in [RFC-0305](RFC-0305_Consensus.md), is responsible for | ||
distributed and trust-minimised decision-making in the Tari digital assets network (DAN). | ||
|
||
The consensus layer is blind to any notions of smart contracts, or NFTs or stablecoins. It merely enforces that | ||
decision made by honest nodes are propagated to the rest of the network. | ||
|
||
The business logic is encapsulated in the Tari Logic layer. | ||
|
||
Figure 1 illustrates the relationship between the Tari Logic layer and the Tari Consensus layer. The key point is | ||
that the consensus layer delegates *all* business logic to the logic layer. However, _only_ the consensus layer has | ||
the ability to make changes to the state of the network (after reaching consensus). | ||
|
||
```mermaid | ||
flowchart LR | ||
Cl([Client]) --> |tx | ||
'Transfer JPG to Bob'| TM[Transaction\n Manifest] | ||
TM -->|Tx AST| C | ||
subgraph Logic Layer | ||
T[Template library] | ||
W[Wasm compiler] | ||
ABI[Contract interface] | ||
E[Tari engine] | ||
RT[Tari Runtime] | ||
SDK[Tari SDK] | ||
ABI <--> E | ||
E <--> RT | ||
end | ||
C --> |calls| ABI | ||
ABI --> |returns new substates| C | ||
subgraph Consensus Layer | ||
C[Validator node] | ||
EM[Epoch management] | ||
VNC[Validator committee\n management] | ||
HS[Cerberus-Hotstuff] | ||
end | ||
SS --> |reads| I | ||
I --> |reads| E | ||
C <--> |reads/writes| SS | ||
SS[(Substates)] | ||
I[[Indexer]] | ||
I --> Cl2([Clients]) | ||
``` | ||
|
||
The Tari Logic layer comprises several submodules: | ||
|
||
* **The Tari engine**. The Tari engine is responsible for the transaction execution process. This includes retrieving | ||
registered template code from the network, compiling it into a WASM binary and submitting it to a Tari runtime | ||
module for execution. The Tari engine also handles fee payments. | ||
* **The Tari runtime**. The Tari runtime wraps a [WASM virtual machine](#why-web-assembly) that executes the compiled | ||
contract code. The runtime is able to calculate the total compute requirements for every instruction, which determines the | ||
transaction fee. | ||
* **The contract interface (ABI)**. This is a list of functions, their arguments and return values that a particular | ||
contract is able to execute. The ABI is generated when the contract template is compiled. | ||
* **The transaction manifest**. This is a high-level set of instructions that a client application generates to achieve | ||
some user goal. For example, Alice may want to transfer a monkey JPG NFT to Bob. The transaction manifest collects | ||
all the information necessary to achieve this goal, including the contract(s) function(s) to call, their arguments, | ||
fee information and all the necessary signature and witness data to authorise the transaction. The transaction | ||
manifest get compiled into an abstract syntax tree (AST) by the Tari Logic layer that can be consumed by a | ||
validator node. | ||
|
||
### The Tari engine | ||
The Tari engine is the main executor in the Validator node codebase. It exposes a number of functions via a JSON-RPC | ||
interface that can be called by client applications. These functions include: | ||
|
||
* submit_transaction | ||
* get_transaction_result | ||
* get_state | ||
* get_substate | ||
* get_template | ||
* register_template | ||
* register_validator_node | ||
|
||
as well as several informational, status and node management function calls. | ||
|
||
A transaction contains the following information: | ||
|
||
* A list of input substate that will be downed (spent). | ||
* A list of input substates that are used as references, but their state is not altered. | ||
* The list of instructions to execute (call method, claim funds, emit logs etc.). | ||
* Signatures | ||
* Network metadata | ||
|
||
The transaction is added to the transaction cache (mempool). Transaction execution proceeds via the following | ||
high-level flow: | ||
|
||
* If a validator node is collecting fees, this is handled first. | ||
* The input substate data is retrieved. If any of the substates are down, or do not exist, the transaction is | ||
rejected. | ||
* With input data in hand, the transaction and input is handed over to the Tari Engine. | ||
* The Engine also determines the total fee for the transaction by charging for every operation | ||
executed within the WASM runtime, as per the [fee schedule](#the-tari-fee-schedule). | ||
* The engine then initializes the WASM runtime, which executes the instructions embedded in the transaction. For | ||
each instruction, a [template provider] will attempt to provide the WASM, or other compatible binary, to execute the | ||
instruction with the given input parameters. See also the [base node scanner](#base-node-scanner) | ||
* The result of execution -- the execution status, and the set of outputs -- is passed to the consensus layer. Note that | ||
outside of the vanishingly small chance of an output substate collision, even a | ||
failed execution attempt is a 'positive' (i.e. `COMMIT`ted) result in terms of consensus, as long as the | ||
super-majority of nodes agree that "failure" is the consensus result! | ||
|
||
#### Base node scanner | ||
|
||
The Tari engine maintains a service that scans the Minotari chain every few minutes looking for the following: | ||
* Burnt outputs that are eligible for redemption on the DAN. | ||
* Contract template registrations. | ||
* Validator node registrations. | ||
|
||
The scanner keeps the local database up-to-date with the latest information from the Minotari chain, not least of | ||
which, is that all code templates will be available locally by the time they are needed. | ||
|
||
### The Tari runtime | ||
|
||
The Tari runtime is a wrapper that provides common functionality for executing arbitrary smart contracts in WASM | ||
modules. Functionality includes: | ||
* calling a function, | ||
* calling a method, | ||
* emitting a log entry, | ||
* pushing an object into the workspace. | ||
|
||
In combination with a contract's ABI, the runtime is able to execute almost any contract code. | ||
|
||
Tari uses the [wasmer](https://wasmer.io/). | ||
|
||
## The contract interface (ABI) | ||
|
||
Rust is strongly-typed, yet we need to be able to call an unlimited variety of functions and methods from arbitrary | ||
contracts in a unified, consistent way. This is where the ABI comes in. It defines all the public methods and | ||
their arguments that a contract exposes. | ||
|
||
The ABI is generated when a contract template is compiled. | ||
|
||
## The transaction manifest | ||
|
||
When a client wants to interact with the DAN, it is often the case that she wants to invoke multiple functions | ||
across multiple contracts simultaneously. For example, Alice may want to buy a monkey NFT from Bob. Her transaction | ||
might lock funds in a cryptographic escrow (in the Tari contract) until she has proof that the NFT has landed in her | ||
NFT account (which is in a different contract). | ||
|
||
To achieve this we introduce the concept of a Transaction manifest. A manifest is simple a list of manifest | ||
_intents_ that are bundled together into an atomic whole. | ||
|
||
An intent is typically one of the following: | ||
* A template invocation or component invocation, indicating that the user wants to execute a function on a contract, | ||
supplying the necessary input arguments. | ||
* A log entry, providing the log level and message. | ||
|
||
## Why Web Assembly? | ||
|
||
The Smart contract execution environment is incredibly hostile. The runtime is effectively tasked to run _arbitrary | ||
code_ on a global system that has potentially billions of dollars of value at stake. | ||
|
||
It is therefore critical that the execution environment does not affect state in the broader network that it is | ||
not entitled to, but also, the code cannot be allowed to jailbreak the execution environment of the validator node | ||
itself and wreak havoc on the host system. | ||
|
||
Thus the runtime environment should | ||
* be strictly sandboxed, | ||
* support multiple concurrent VM without being a resource hog, | ||
* have no access to the host system internals, including disk storage, camera, microphones, etc. | ||
* be ephemeral and support rapid cold starts. | ||
|
||
Given these onerous requirements, Rather than reinvent the wheel, we considered several existing solutions, including | ||
|
||
* WebAssembly ([WASM](https://webassembly.org/)) | ||
* Extended Berkeley Packet Filter ([eBPF](https://en.wikipedia.org/wiki/EBPF)) | ||
* Full virtualisation, such as [KVM](https://www.linux-kvm.org/page/Main_Page) or | ||
* [VmWare](https://www.vmware.com/products/workstation-player.html) | ||
|
||
Full virtualisation was quickly discarded as being too heavy-weight. Validator nodes will be required to swap out | ||
contracts constantly, and so cold-starting a runtime environment must be as lightweight and as fast as possible. | ||
|
||
Surprisingly, there were very few options remaining, with eBPF and Wasm being the most mature and closest to our | ||
needs. In fact both runtimes are used in smart-contract execution environments today. WASM is used in Stellar, Near, | ||
Cosmos, Polkadot, Radix and a host of others. eBPF is used in Solana. | ||
|
||
We chose WASM for the following reasons: | ||
* WASM is a mature, well-supported standard. It is supported the major browsers, which means that trillion-dollar | ||
companies like Google, Microsoft and Apple have a vested interest in its success. | ||
* WASM was designed from the ground-up to be a highly performant, lightweight, sandboxed runtime. | ||
* There is fantastic tooling to convert Rust, C, Go, and \[insert favorite language here\] into WASM. | ||
* WASM can run almost anywhere, but especially in the browser. Thus, the path to running Dapps safely in the browser | ||
is likely much easier. | ||
|
||
On the other hand, eBPF was originally design as a packet-filter to protect networks from malicious data packets. | ||
It has since been extended to support a full-blown virtual machine, but it still feels a little like a square peg | ||
being banged into a round hole. | ||
|
||
Ultimately, it was a fairly straightforward decision to go forward with WASM. | ||
|
||
Independently, [Stellar](https://stellar.org/blog/developers/project-jump-cannon-choosing-wasm) reached the same | ||
conclusion, for much the same reasons. | ||
|
||
In contrast, while Polkadot does use WASM, there is an | ||
[active discussion](https://forum.polkadot.network/t/announcing-polkavm-a-new-risc-v-based-vm-for-smart-contracts-and-possibly-more/3811) | ||
to replace Wasm with RISC-V. This VM is being designed explicitly for smart-contract environments and is worth | ||
watching. | ||
|
||
For the time-being, WebAssembly is a pretty clear winner. | ||
|
||
|
||
|
||
|
||
|
||
|
||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters