Sitemap

Building AVM: My Rust Journey Through a RISC-V Smart Contract Virtual Machine

6 min readJul 3, 2025

--

“Ethereum should someday adopt RISC-V” — Vitalik Buterin

Note: This project and blog are heavily assisted by leading AI tools — including OpenAI’s ChatGPT, GitHub Copilot, and Cursor.ai — for code generation, documentation, and design guidance. The codebase itself is extensively documented with comments generated by Cursor.ai.

In June 2025, I began a journey to learn Rust through building something ambitious: a full RISC-V virtual machine (VM) that could run smart contracts. I call it AVM — Alon’s Virtual Machine. What started as a side project to teach myself a systems language quickly spiraled into a multi-week deep dive into instruction decoding, state machines, and blockchain virtual machines. In this blog post, I’ll share what AVM is, why I built it, how it works, and what I learned along the way.

[This is a really dumb way to build a RISC-V ethereum VM; It’s purely educational!]

link to repo at the bottom

High-Level Overview

AVM is composed of several layers, each with a distinct role:

  • RISC-V 32-bit CPU: A pure implementation of the RV32IMAC instruction set, capable of executing real RISC-V binaries.
  • The VM: A general-purpose virtual machine that executes instructions through a CPU struct and decodes RISC-V binaries via a custom ELF loader.
  • AVM: A wrapper around the VM that adds state management and contract deployment, turning it into a blockchain-like runtime.
  • Program: A dev-friendly SDK for building smart contracts (“programs”) with macros, storage helpers, and logging.
  • State: A blockchain-like account layer supporting balances, storage, and function routing.

Why AVM?

The genesis of AVM is rooted in three motivations:

  1. Learning Rust Properly: Rust has long fascinated me for its safety guarantees, expressive type system, and performance. I had used it occasionally, but I wanted a deep dive. No better way than writing a VM from scratch.
  2. Experimenting with RISC-V: As an open, extensible ISA, RISC-V is gaining momentum in the systems and crypto worlds. Its simplicity and modularity make it a perfect playground.
  3. Inspired by Vitalik’s Call to Arms: Vitalik Buterin’s suggestion that Ethereum should someday adopt a RISC-V based VM (instead of sticking with EVM or WASM) lit a fire in me. If Ethereum’s long-term vision includes RISC-V, why not explore what that future could look like?

This project is not intended for production or security-critical environments. There are no unit tests (yet), and the mantra is to move fast and break things. My goal was to get my hands dirty and make the core VM work — then refine later if needed.

The Core Components of AVM

AVM is organized into modular crates, with the most critical being:

1. vm: The Heart of the Machine

This crate implements the actual virtual machine. It supports the RV32IMAC RISC-V spec — that is:

  • RV32I: Base integer instructions
  • M: Multiplication and division
  • A: Atomic operations (partially implemented)
  • C: Compressed 16-bit instructions

I spent significant time writing a custom instruction decoder to support both 16-bit (compressed) and 32-bit instructions, as many RISC-V guests use compressed opcodes.

The VM struct handles memory, registers, and execution loop. Features include:

  • Memory-paged architecture (inspired by OS-level VMs)
  • Syscalls for state access, panic messages, and contract interop
  • Simple panic system using ebreak and ecall

2. compiler: ELF Loader & Rust Guest Integration

To run actual smart contracts, AVM loads compiled Rust programs as ELF binaries. This crate contains:

  • A custom ELF parser
  • Memory loader that maps segments into VM memory
  • Helpers for setting up a VM with the guest’s code

This was surprisingly complex but rewarding. I learned how Rust compiles to ELF and how memory segments work.

3. program: Guest SDK

I wanted devs (including myself) to write guest programs easily. This crate is a no_std SDK with:

  • Macros for defining entrypoints
  • Persistent storage helpers (using a custom attribute macro I built)
  • Logging macros (printed via syscalls)
  • Panic handler with ebreak fallback

Much of this SDK is heavily commented, thanks to cursor.ai autogenerating in-depth documentation. It made re-reading my own code much easier.

4. state: Blockchain-Like Account Layer

Inspired by Ethereum and Solana, AVM includes a state machine with the following features:

  • Accounts with balance, code, and storage
  • Contract deployment by writing code to an address
  • Function routing via a selector-based mechanism
  • Multi-transaction batch execution

Contracts are routed using Solana-style selector bytes (e.g. 0x01 = init, 0x02 = write, etc.). This enables dynamic dispatch based on encoded transaction input.

Dev Experience: Copilot, Cursor, and ChatGPT

Though I wrote the code myself, I didn’t do it alone.

Copilot

GitHub Copilot was incredibly helpful when writing low-level Rust — especially tedious boilerplate like instruction decoding and bit masking. It would often suggest correct register access or opcode formats before I even looked them up.

Cursor.ai

I configured Cursor to automatically comment every major function and component. The comments it generated were more than superficial — they provided high-level explanations of control flow, memory layout, and design rationale. This not only helps future contributors (or future me), but also forced me to reason more clearly about each component.

ChatGPT (OpenAI)

ChatGPT was like a Rust mentor who never slept. I frequently asked:

  • How to implement a no_std panic handler?
  • What is the difference between core::arch::asm! and std::arch::asm!?
  • How to implement persistent structs via macros?

The answers weren’t always perfect, but they gave me enough clues to continue. It was a collaborative experience.

Current Capabilities

AVM currently supports:

  • 🧠 Full RV32IMAC instruction decoding and execution
  • 🧾 Executing Rust guest contracts compiled to ELF
  • 🧱 Blockchain-like state with account storage
  • 🔁 Multi-transaction bundles
  • 📦 Contract deployment
  • 📞 Function routing via selectors
  • 🧰 Program SDK with macros, logs, and storage
  • 🧼 no_std compliant guest programs
  • 🔊 Logging support
  • ⚠️ Panic control using ebreak

Example Guest Program

Here’s what a guest contract looks like:

#![no_std]
use program::{entrypoint, log, persist};
#[persist("counter")]
pub struct Counter {
pub value: u32,
}
entrypoint!(|call| {
match call.selector {
0x00 => {
let mut counter = Counter::load();
counter.value += 1;
counter.store();
log!("Incremented to: {}", counter.value);
},
_ => log!("Unknown selector: {}", call.selector),
}
});
cargo build --target riscv32i-unknown-none

and run inside AVM.

Want to See It in Action?

To try out AVM with some real guest programs, you can run the test suite that demonstrates execution flows:

cargo test --test program_exec --package avm

This test runs several example programs end-to-end, showcasing contract execution, function routing, and storage interaction. It’s a great way to get a feel for what the AVM can do today.

What’s Next?

I’m actively working on several future features:

  • 🔗 Program-to-Program Calls: Allow guest programs to call each other directly
  • Gas Metering: Add gas cost to each instruction and track it during execution
  • 🔍 Debugging Tools: Memory dumps, register traces, interactive stepping
  • 🌐 More Syscalls: For IO, cryptography, hashing, etc.
  • 🧪 Optional Unit Tests: Especially for decoder and state logic

I also want to explore:

  • ZK integration for proving VM execution
  • Mapping AVM opcodes to zkVM-compatible R1CS/PLONK circuits
  • Running AVM in-browser using WASM

Final Thoughts

AVM is not perfect. It’s buggy, hacky, and lacks tests. But it’s mine.

Through it, I learned:

  • Real-world Rust — lifetimes, ownership, no_std, embedded tooling
  • ELF format internals
  • RISC-V decoding from scratch
  • Writing macros and SDKs for other devs

I believe RISC-V is a promising future for blockchain execution. If Ethereum ever adopts a RISC-V VM, I hope projects like AVM help pave the way.

If you’re curious, the repo is open: github.com/alonmuroch/rust-vm

In the next post, I’ll go deeper into the instruction decoder — how I handled compressed instructions, edge cases, and how I validated correctness without unit tests.

Stay tuned.

--

--