Skip to content

MultiVM Environment

At the moment, there are three VMs: the Ethereum Virtual Machine (EVM), the Multi Virtual Machine (MultiVM), and the Solana Virtual Machine (SolanaVM). Each of them is built either on top of RISC0 or integrated into RISC0. In terms of the RISC0, MultiVM environment can be divided into two parts: the host, which is a system on which zk vm runs, and the guest, which are user programs for that ZK proofs will be generated after execution. In this case, the guest programs are smart contracts.

Any VM can interact with another through what are called cross-VM calls. For users, this is similar to regular cross-contract calls. Regular cross-contract calls within a single VM are a subset of cross-VM calls, so in the further documentation, we will only consider cross-VM calls. The overall structure of the runtime is shown in the diagram below.

Loading graph...

Let’s take a closer look at the components of the runtime and how these parts can interact with each other.

Meta Contract

The main non-trivial part is the Meta Contract system contract. It serves as the entry point for any transaction, meaning the user interacts with this contract through a node for every call, but this happens invisibly to the user. The Meta Contract uses a transaction in native format that depends on the VM being used. The main functions performed by this contract are:

  • determining the further routing of the transaction for execution;
  • block formation: verifying the correctness of cross-VM calls, validating storage changes, managing user balances, verifying transaction signatures, and other auxiliary checks;
  • creating new accounts, managing account keys, and deploying other contracts.

The remaining components on the diagram are specific implementations of virtual machines.

MultiVM implementation

The implementation of MultiVM is native in terms of RISC0. Smart contracts compiled in ELF format serve as guest programs. They are represented as Elf_Contract_1 and Elf_Contract_N on the diagram. The execution of each transaction leads to an execution traceback - all data after the transaction is executed within the ZK vm, including the transaction result and ZK proof.

EVM implementation

For the implementation of the EVM, an open-source rust implementation was taken and run inside the RISC0 ZK VM. Therefore, it can be considered that the EVM is a smart contract within the RISC0 system, which allows the execution of other smart contracts deployed on the EVM smart contract. This is the only possible way to integrate EVM and Solidity into RISC0.

SolanaVM implementation

The implementation of SolanaVM is similar to the implementation of MultiVM, but with a small additional wrapper that takes responsibility for managing solana-specific storage. In the Solana blockchain, transaction execution occurs in parallel. However, with parallel execution, there is always a risk that different transactions will write data to the same storage location, which can lead to incorrect final results. Therefore, in Solana, developers must explicitly specify whether a transaction will only read or read/write from a specific storage area. This is exactly what the wrapper does: it adapts the format of the transaction received from the user into a format that SolanaVM can process.

It is worth noting that despite the support for parallel execution in SolanaVM, it is not possible to make a parallel execution in our system because ZK proof generation is a sequential process. The generation of the second ZK proof cannot begin until the first ZK proof is generated. Parallelization can only be applied to the generation of one proof, but not for different proofs.

Cross-VM calls

In a system with multiple communicating VMs, several technical challenges arise. The primary bottleneck is the cross-contract calls from one VM to another. This presents a potential vulnerability where a malicious node can pass incorrect arguments to the called contract via the runtime. Since this falls outside the scope of zero-knowledge proofs, it becomes impossible to detect during proof verification, which only verifies that “given input data results in such output data.” While this issue may be caught at the consensus stage when distinguishing between legitimate and unscrupulous nodes, an additional layer of protection is still necessary.

The proposed solution suggests expanding the receipt’s data to include not only the merkle root from the states but also all information about cross-contract calls. This approach would enable verification at the moment of verification, confirming that “the contract was called with specific data, received a particular final state, but in the process, it also called another contract with certain data.” Additionally, there would be proof that “another contract was called with specific input data,” allowing an on-chain verifier to easily compare the data from the two proofs for coincidence and reject any invalid transaction.

C1 = EVM.Contract()  # some contract on the EVM
C2 = MultiVM.Contract()  # some contract on the MultiVM

cc = ContractCall(method1, args1, ...)

# `contract_call()` returns `Commitment` object for the call;
# `Commitment` consists of the following fields:
	# call_hash - hash of the original/current call
	# response - result of the transaction
	# cross_calls_hashes - array of the tuples `(hash(call_hash), hash(cm))` for each cross-VM calls,
		# where call_hash - hash of the cross-VM call,
		# cm - commitment of the cross-VM call.

cm1 = user.contract_call(C1, cc)
		# this happens inside contract call `cc`
		cvmc = ContractCall(method2, args2, ...)
		cm2 = C1.cross_vm_call(C2, cvmc)

proof = cm1.prove()  # recursive generating ZK proofs for all commitments

# afterward, we verify the proofs for their validity
# and ensure the integrity of all call hashes.

SDK

By default, smart contracts on MultiVM use Borsh for serialization and deserialization of arguments. However, our SDK also provides the option to generate Ethereum Contracts ABI, enabling the contract to be called from EVM. In that case, the MultiVM contract can use both Borsh and Ethereum Contract ABI. To enable cross-VM calling from MultiVM to EVM, developers simply need to import the ABI of the contract they wish to interact with, and our SDK will assist with the rest.