diff --git a/src/RFC-0350_TariVM.md b/src/RFC-0350_TariVM.md new file mode 100644 index 0000000..f37fba2 --- /dev/null +++ b/src/RFC-0350_TariVM.md @@ -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. + + + + + + + + diff --git a/src/SUMMARY.md b/src/SUMMARY.md index 0321c0e..f0feb83 100644 --- a/src/SUMMARY.md +++ b/src/SUMMARY.md @@ -29,6 +29,7 @@ - [RFC-0303: The Tari Digital Assets Network](RFC-0303_DanOverview.md) - [RFC-0313: Validator Node Registration](RFC-0313_VNRegistration.md) - [RFC-0320: The turbine model](RFC-0320_TurbineModel.md) + - [RFC-0350: The Tari Virtual Machine](RFC-0350_TariVM.md) - [RFC-0305: The Tari Network Consensus Layer](RFC-0305_Consensus.md) - [RFC-0314: Validator node committee selection](RFC-0314_VNCSelection.md)