Icon HelpCircleForumIcon Link

⌘K

Icon HelpCircleForumIcon Link

Icon LinkThe FuelVM

Highlights:

  • The FuelVM serves as the core of the Fuel stack, informed by insights from various virtual machine designs like the EVM and Solana's SVM.

  • It supports state-minimized application development through features such as native assets and ephemeral scripting, promoting decentralized and accessible architecture.

  • The UTXO model facilitates parallelized transaction execution, enhancing throughput and reducing latency by allowing concurrent processing of non-conflicting transactions. The FuelVM is a register-based virtual machine, providing better performance compared to traditional stack-based designs and offering a structured instruction set for efficient operations.

  • Predicates, scripts, and contracts are essential components of the FuelVM, enabling flexible spending conditions, transaction processing, and state management within its execution environments.

The FuelVM lies at the core of the whole Fuel stack; it was created by taking into account years of learning from other virtual machine designs, like the EVM, Solana’s SVM and more.

The FuelVM enables developers to move away from stateful application designs often enabled by smart contracts by providing more feature-rich state-minimized facilities such as native assets, ephemeral scripting, and ephemeral spending conditions. By offering alternative methods for developers to build state-minimized applications, we enhance full node sustainability while maintaining a decentralized and accessible architecture, aligning with Ethereum’s core values.

In the following sections, we will discuss the key features of the FuelVM in detail.

Icon LinkUTXO Model and Parallelization

Fuel’s parallelized transaction execution model serves as a cornerstone for its efficiency and scalability. Parallelization dramatically improves throughput and reduces latency compared to traditional sequential processing methods. It breaks tasks into smaller sub-tasks, executing them simultaneously across multiple processing units.

Parallelization is built upon a foundation of Access Lists Icon Link and the UTXO (Unspent Transaction Output) model, which works in tandem to enable concurrent processing of non-conflicting transactions.

Our tech leverages the UTXO model for performing transactions on Fuel. Transactions modeled through UTXOs handle everything from token transfers to smart contract calls.

Addresses on Fuel own unspent coins, allowing them to spend and perform transactions through the FuelVM.

2.1 UTXO Model and Parallelization

Using the UTXO model helps achieve transaction parallelization. At runtime, users provide the inputs and outputs for their transaction. Transactions without overlap process in parallel, enabling Fuel to scale horizontally with the number of cores per machine.

Icon LinkRegister based design

The FuelVM operates as a register-based virtual machine, unlike the EVM and many others, which use a stack-based architecture.

Register-based virtual machines consistently outperform stack-based virtual machines.

The FuelVM includes 64 registers, each 8 bytes, with 16 reserved and 6-bit addressable.

valueregisternamedescription
0x00$zerozeroContains zero (0), for convenience.
0x01$oneoneContains one (1), for convenience.
0x02$ofoverflowContains overflow/underflow of addition, subtraction, and multiplication.
0x03$pcprogram counterThe program counter. Memory address of the current instruction.
0x04$sspstack start pointerMemory address of bottom of current writable stack area.
0x05$spstack pointerMemory address on top of current writable stack area (points to free memory).
0x06$fpframe pointerMemory address of beginning of current call frame.
0x07$hpheap pointerMemory address below the current bottom of the heap (points to used/OOB memory).
0x08$errerrorError codes for particular operations.
0x09$ggasglobal gasRemaining gas globally.
0x0A$cgascontext gasRemaining gas in the context.
0x0B$balbalanceReceived balance for this context.
0x0C$isinstructions startPointer to the start of the currently-executing code.
0x0D$retreturn valueReturn value or pointer.
0x0E$retlreturn lengthReturn value length in bytes.
0x0F$flagflagsFlags register.

Icon LinkThe FuelVM Instruction Set

The FuelVM instructions are 4 bytes wide and have the following structure:

  • Opcode: 8 bits
  • Register Identifier: 6 bits
  • Immediate value: 12, 18, or 24 bits, depending on the operation.

The FuelVM instruction set has been documented in detail here: https://docs.fuel.network/docs/specs/fuel-vm/instruction-set Icon Link.

Icon LinkMemory

FuelVM uses byte-indexed memory, configurable with the VM_MAX_RAM parameter. Hence, each instance of FuelVM can decide how much memory it wants to allocate for the VM.

Memory follows a stack and heap model. The stack begins from the left, immediately after the initialized VM data and call frame in a call context, while the heap starts at the byte indexed by VM_MAX_RAM.

Each byte allocation on the Stack increases the stack index by 1, and each byte allocation on the heap decreases its writable index by 1. Hence, the stack grows upwards, and the heap grows downwards.

2.1 FuelVM Memory

The stack and the heap have the following essential registers associated with them:

  • $ssp ( 0x05 ): Memory address of bottom of the current writable stack area.
  • $sp ( 0x06 ): Memory address on top of current writable stack area (points to free memory).
  • $hp ( 0x07 ): Memory address below the current bottom of the heap (points to used/OOB memory).

The FuelVM has ownership checks to ensure that contexts have a defined sense of ownership over particular regions in the memory and can only access memory from the region they own. We will elaborate more on this topic in later sections.

Icon LinkPredicates, Scripts and Contracts

Understanding further concepts for Fuel requires grasping:

  • Predicates
  • Scripts
  • Contracts

Let’s dive deeper.

Icon LinkPredicates

Predicates are stateless programs that define spending conditions for native assets. Native assets go to predicates, and to determine whether they are spendable in a transaction, the FuelVM executes the bytecode and checks the boolean return value. If the returned value is true, the asset can be spent; if the returned value is false, then the transaction is invalid!

People can program various spending conditions, such as spending only if three out of five approve a transaction or if a transaction includes specific desired inputs and outputs, commonly known as intents.

Predicates operate statelessly, without persistent storage, and cannot call other smart contracts.

Icon LinkScripts

Scripts serve as the entry point for Fuel transactions, dictating the flow of the transaction. Like predicates, they lack persistent storage. However, they can call contract Inputs, which are part of the Fuel transaction and can have persistent storage of their own.

This enables Fuel to natively support advanced features such as multi-calls, conditional contract execution, and more.

Icon LinkContracts

Fuel provides support for smart contracts in its UTXO model. Smart contracts are stateful and can be called by other contracts. In Fuel, smart contracts are represented by the InputContract type. To learn more, refer to the section on InputContract.

The first call to a contract in a transaction occurs through a script, after which the contract can call other contracts.

Contracts have persistent storage, a key-value pair of 32-byte and 32-byte values. Various data structures are being considered to determine the optimal approach for committing to contract storage.

Icon LinkContexts

A context is a way to isolate the execution of various execution environments for predicate estimation and verification, scripts, and contracts. Each context has its memory ownership, which we will expand on later.

There are four types of contexts in Fuel:

  • Predicate Estimation
  • Predicate Verification
  • Script Execution
  • Calls

The first three are called External contexts, as the $fp is zero, while Calls are called Internal contexts and will have a non-zero value for $fp.

Icon LinkPredicate Estimation

Fuel transactions provide predicateGasUsed for each predicate used. During verification, if predicateGasUsed is less than the total gas consumed during verification, the transaction reverts.

2.1 Predicate Estimation

The user performs Predictive Estimation locally or by calling a remote full node, which executes the predicate in the FuelVM and returns the total gas consumed.

Predicate estimation context cannot do persistent storage or make calls to Contracts.

Icon LinkPredicate Verification

All predicate parts of the transaction are verified to return true before executing the transaction script. The FuelVM is used in the Predicate Verification context when verifying a transaction's predicates.

2.1 Predicate Verification

Predicate verification context cannot do persistent storage or make calls to contracts.

Icon LinkScript Execution

After verifying all predicates, the transaction script is executed; the script execution context cannot do persistent storage but can make calls to contract.

2.1 Script Execution

Icon LinkCalls

Call contexts execute contracts, offering flexibility, storing data persistently, and making contract calls.

Call context is created by either:

  1. Script calling a smart contract
  2. Contract calling a contract input

2.1 Call Context

Each call creates a “Call Frame”, which is pushed to the Stack. A call frame holds metadata on the stack, aiding the execution of the call context in the FuelVM. A call context cannot mutate the caller's state and only access its stack and heap.

bytestypevaluedescription
Unwritable area begins.
32byte[32]toContract ID for this call.
32byte[32]asset_idasset ID of forwarded coins.
8*64byte[8][64]regsSaved registers from previous context.
8uint64codesizeCode size in bytes, padded to the next word boundary.
8byte[8]param1First parameter.
8byte[8]param2Second parameter.
1*byte[]codeZero-padded to 8-byte alignment, but individual instructions are not aligned.
Unwritable area ends.
*Call frame's stack.

After a call context has successfully ended, its call frame is popped from the stack. However, any space allocated on the heap during the execution of the call context persists in memory.

A call context returns its value using the $ret and $retl registers. Large return values can be written to the heap and later read from the caller contexts.

Icon LinkMemory Policies

After understanding the various contexts for executing the FuelVM, we now discuss the policies for reading and writing to memory in contexts.

Icon LinkRead Policies for Context

A context can read any data from the stack in the range from the byte at index 0 (i.e., from the start of the memory ) to the highest ever $sp and between the current $hp and VM_MAX_RAM (i.e., until the end of the memory ) of the previous context that created the current context.

Any attempt to read from the region between the highest ever $sp during the context execution and the current $hp will return an error.

2.1 Memory Read Policies

What do we mean by the highest ever $sp?

Since the stack can be grown and shrunk in size, it is possible that during the execution of some context, the $sp went until, for example, index 1000, but then elements were popped out of the stack, and now the current $sp is 900. In this scenario, the highest ever $sp during the execution of this call context is 1000, and hence, the memory region until 1000 is readable for the stack!

Icon LinkWrite Policies for Context

A given context can write to any region between its $ssp and current $hp; hence, that memory region can be allocated and used for writing data.

Before writing to this memory region, allocate the bytes first. In the case of a stack, this is done using CFE and CFEI opcodes, while in the case of the heap, it is done via an ALOC opcode.

2.1 Memory Write Policies

Note: Remember that once a context completes, all values on the stack (i.e., the call frame and all values allocated on the stack during execution ) are wiped down. Still, heap allocation stays, and the following context can only write data below the $hp of the existing context.

Icon LinkVM Initialization & Configuration

Icon LinkConfiguration

The VM can be configured by setting the following parameters:

nametypevaluenote
CONTRACT_MAX_SIZEuint64Maximum contract size, in bytes.
VM_MAX_RAMuint642**2664 MiB.
MESSAGE_MAX_DATA_SIZEuint64Maximum size of message data, in bytes.

Icon LinkVM Initialization

This section outlines the process during VM initialization for every VM run. To initialize the VM, the following pushes to the stack sequentially:

  1. Transaction hash (byte[32], word-aligned), computed as defined here Icon Link.

  2. Base asset ID (byte[32], word-aligned)

  3. MAX_INPUTS Icon Link pairs of (asset_id: byte[32], balance: uint64), of:

    1. For predicate estimation Icon Link and predicate verification Icon Link, zeroes.

    2. For script execution Icon Link, the free balance for each asset ID seen in the transaction's inputs is ordered in ascending order. If there are fewer than MAX_INPUTS asset IDs, the pair has a zero value.

  4. Transaction length, in bytes (uint64, word-aligned).

  5. The transaction, serialized Icon Link.

The following registers are then initialized (without explicit initialization, all registers are initialized to zero):

  1. $ssp = 32 + 32 + MAX_INPUTS*(32+8) + size(tx)): the writable stack area starts immediately after the serialized transaction in memory (see above).

  2. $sp = $ssp: writable stack area is empty to start.

  3. $hp = VM_MAX_RAM: the heap area begins at the top and is empty to start.

Icon LinkFurther Readings