Radix Engine: A Better Model for “Enshrinement” | The Radix Blog | Radix DLT

Opinion Post by Josh Primero Head Protocol Architect at RDX Works

In my previous article, I went over how Radix Engine avoided some of the flaws in Sui’s MoveVM. To summarize:

Sui’s MoveVM follows the original Ethereum philosophy of a “clean, simple, beautiful” protocol which delegates everything to the application layer. This allows developers the freedom to explore any domain, including unknown ones at the time.

A protocol which is too simple and unstructured, though, creates significant compromises. For example, common system features like authorization would require a complex implementation in the application space, standard interfaces may become more fragmented, and performance optimization becomes more difficult.

Radix Engine, on the other hand, is designed to execute non-generic, system-wide logic as a core technical goal as it allows us to do the following:

Vitalik recently touched on this idea with the term “enshrinement”, or the idea of selectively breaking away from abstraction in order to gain benefits of protocol-enforced logic. Stealing one of his images, he frames the problem as a tradeoff between abstraction vs. enshrinement:

Vitalik’s abstraction vs. enshrinement tradeoff

This balance of supporting abstraction (i.e. future/diverse user needs) while maintaining performance/security/usability (i.e. enshrinement) is actually a very old computer science problem. The design of Operating Systems specifically has been trying to solve a similar problem for the past decades: How do we support a range of abstract applications while maintaining a fast, secure, usable system?

In this article I will go over how Radix Engine uses the Operating System model to create a framework capable of all types of “enshrinement” without the load to protocol complexity or loss of flexibility that Vitalik fears.

Let’s start by looking at the current industry standard, the Ethereum Virtual Machine (“EVM”).

EVM as a VM

The EVM is basic enough that it can be modeled as a virtual machine (“VM”) with the following opcodes:

Smart contracts compiled into EVM bytecode can then be executed on top of such a VM.

EVM model

In this model, any form of “enshrinement” requires changes to the EVM, or the VM hardware. For example, enshrining BLS signature support would require adding a new precompile. Or implementing EIP-2938 would require the addition of new opcodes. Expanding on what is enshrined inevitably results in a larger, more complicated VM and forces the protocol designer into the choose one-or-the-other decision Vitalik describes.

Enshrinement in the EVM model

The general problem with this model is that the Abstraction/Enshrinement dichotomy is too coupled with the Software/Hardware dichotomy. That is, enshrining any logic into the protocol forces it to be embedded into the VM. There is no way to express “enshrined software” or software which is part of the system.

Operating Systems solved this dichotomy with the notion of “system software”.

Let’s take a closer look.

The Operating System Model

One of the main goals of an Operating System is to manage the software/hardware dichotomy – or more specifically the application/hardware dichotomy. The core part of any Operating System is the kernel, software which manages user space applications and their access to hardware. Kernel modules and drivers are additional pieces of system software that expand the set of supported hardware or extend kernel functionality.

Operating System Model

From an “enshrinement” perspective, the kernel and its modules are enshrined parts of the system, but have the flexibility of software. Kernel modules, virtual machines (“VMs”), and user-space system processes are even more “soft” since these are abstracted from the kernel itself.

Enshrinement in the Operating System Model

In this model, the layer of indirection between applications and hardware allows the software/hardware dichotomy to be decoupled from the abstraction/enshrinement dichotomy.

“System software” allows for enshrinement without overburdening the hardware.

Radix Engine as an Operating System

Using this Operating System model as inspiration, Radix Engine includes multiple layers where each layer has specific responsibilities and abstractions allowing for system modularity and pluggability.

Radix Engine Layers

Such a modular design allows for system logic to be enforced while also allowing the following:

Let’s now go over each of these layers and see what their responsibilities are.

Application Layer

The application layer is responsible for defining high level logic. Bytecode that describes this logic, along with other static information, is bundled up in an executable format called a Package. Packages are then stored on-ledger and available for execution.

Applications written in Scrypto, the Rust-based language we’ve built for DeFi development, live in this layer. Scrypto programs get compiled into WASM programs with access to a set of function exports which allows the program to access system/kernel services. This System Call API is similar to the Linux system calls which provide access to shared I/O.

VM Layer

Moving to the next layer down, the VM Layer is responsible for providing the computing environment to the application layer. This includes a Turing-complete VM as well as the interface to access the system layer.

Radix Engine currently supports two VMs: a Scrypto WASM VM used to execute Scrypto applications and a native VM which executes native packages which are compiled to the host’s environment.

If we take a look at the Scrypto WASM VM specifically it looks like:

Scrypto WASM VM Model

This may look essentially the same as the EVM model but there are two crucial differences:

System Layer

The System Layer is responsible for maintaining a set of System Modules, or pluggable software which can extend the functionality of the system. These are similar to Linux’s kernel modules.

On every system call, each system module gets called before the system layer passes control to the kernel layer. When called, each system module may update some particular state (e.g. update fees spent) or panic to end the transaction (e.g. if the type checker fails).

This pattern allows functionality such as authorization, royalties or type checking to be implemented by the system while being decoupled from both the application and kernel layers.

A System Call must pass through the filters of several system modules before being passed onto the kernel

Kernel Layer

The kernel layer is responsible for the two core functionalities of Radix Engine: storage access and communication between applications. This is somewhat similar to the traditional Operating System’s responsibility for disk and network access.

For Radix Engine, this includes the following low-level management:

Enshrined Software

How do these layers relate to enshrinement in a DLT protocol? Similar to the kernel layer in Operating Systems, these middle layers of Radix Engine provide the indirection required to decouple the abstraction/enshrinement dichotomy from the software/hardware dichotomy and create the notion of “enshrined software”.

Decoupling of abstraction/enshrinement vs. software/hardware

Enshrined software has the flexibility and security properties of software while maintaining the ability to enforce system-wide logic.

Radix Engine’s Enshrined Software

Let’s go over a few enshrinement examples that are currently running on the Radix network and see how they are implemented.

Enshrined Resources

The core differentiator of the Radix DeFi/Web3 platform is the idea that a resource (i.e. asset) is a fundamental primitive which should be understood separately from business logic. Enshrining this concept allows all dApps, wallets and tooling to have a common understanding of what an asset’s interface and behavior looks like making composability much easier.

Though resources are one of the most ingrained parts of the system, implementing its enshrinement only requires two modular pieces of software:

Radix Engine’s Enshrined Resources

The fact that Radix Engine could express the deep concept of a standardized, movable resource while being abstracted from the system/kernel shows the power of a modular system software framework.

Enshrined Authorization and Royalties

Radix Engine standardizes authorization and royalties by decoupling this logic from business logic and implementing these as system features. This allows users and developers to have a built-in common way of understanding the requirements to access any function on-ledger.

The modularity from decoupling business logic from system logic also allows for convenient development/debugging options like the ability to preview a transaction without the normal auth checks (want to simulate the result of sending 10 million USDC somewhere? With authorization disabled, your preview transaction can do the minting!).

Enshrining auth and royalties requires four pieces of modular software:

Radix Engine’s Enshrined Authorization and Royalties

Enshrined Transaction

The correct interface between user and system is paramount for any system to be usable. And to be usable the interface must find the right balance between ease-of-use and power/flexibility.

In the Operating System world, the most common interface is the terminal, a user space process which gives a user a command line tool to call and compose various system calls.

In the DLT world, this interface is the transaction. The industry standard for a transaction is to use a single low-level, generic invocation call. Unfortunately this is too simple in that it makes it hard to understand what one is actually doing when interacting with the system.

Radix Engine, on the other hand, uses the traditional OS pattern and enshrines an application language (similar to a terminal scripting language such as bash) to call and compose system calls in a single transaction.

Because the entrypoint of a transaction operates in the application layer, implementing the language interpreter is done by adding a Transaction Processor native package.

Radix Engine’s Enshrined Transaction

Enshrined BLS

BLS signatures are an important crypto primitive as it allows for the possibility of threshold signatures. Unfortunately running such logic in WASM quickly uses up the maximum cost unit amount. In the recent “Anemone” update, we enshrined BLS by executing it natively and found a 500x gain in performance when compared to WASM.

Because BLS logic is stateless, it is easily added as an additional precompile to the Scrypto WASM VM.

Radix Engine’s Enshrined BLS

Conclusion

What to enshrine and what not to enshrine is important for any DLT protocol. Unfortunately, the industry’s existing VM model makes every enshrinement decision a high stakes decision.

With the Operating System model as inspiration, Radix Engine solves this problem by adding a layer of indirection between “software” and “hardware”. This allows Radix Engine to express the notion of “enshrined software” and makes it easy for the protocol to add, modify and express new enshrined systems without making high stakes compromise decisions.

Originally the operating system was meant to be a small piece of software designed for the sole purpose of managing shared resources for multiple applications. As user demands for a better, faster, more secure platform grew, it has taken on more and more responsibility with a larger and larger suite of software.

DeFi will be no different.  As demand for a faster, more secure, and more usable DeFi platform grows, increased enshrinement will follow. Radix Engine was designed with this in mind and provides the scalable and secure framework needed for expanding enshrinement into the future.