WebAssembly in Nitro
WebAssembly (WASM) is a binary instruction format that enables high-performance execution of programs in the Nitro virtual machine. This guide explains how WASM works in the context of Arbitrum Nitro and Stylus smart contract development.
What is WebAssembly?
WebAssembly is a portable, size-efficient binary format designed for safe execution at near-native speeds. Key characteristics include:
- Binary format: Compact representation that's faster to parse than text-based formats
- Stack-based VM: Simple execution model with operand stack
- Sandboxed execution: Memory-safe by design with explicit bounds checking
- Language-agnostic: Can be targeted by many programming languages (Rust, C, C++, etc.)
Why WebAssembly in Nitro?
Nitro uses WebAssembly as its execution environment for several reasons:
- Performance: WASM compiles to native machine code for fast execution
- Security: Sandboxed environment prevents unauthorized access
- Portability: Same bytecode runs identically across all nodes
- Language flexibility: Developers can use Rust, C, C++, or any language that compiles to WASM
- Determinism: Guaranteed identical execution across all validators
WASM Compilation Target
Stylus contracts are compiled to the wasm32-unknown-unknown target, which means:
- 32-bit addressing: Uses 32-bit pointers and memory addresses
- Unknown OS: No operating system dependencies
- Unknown environment: Minimal runtime assumptions (no std by default)
The .cargo/config.toml file in Stylus projects configures the WASM target:
[target.wasm32-unknown-unknown]
rustflags = [
"-C", "link-arg=-zstack-size=32768", # 32KB stack
"-C", "target-feature=-reference-types", # Disable reference types
"-C", "target-feature=+bulk-memory", # Enable bulk memory operations
]
Compilation flags
- Stack size: Limited to 32KB to ensure bounded memory usage
- Bulk memory: Enables efficient
memory.copyandmemory.filloperations - No reference types: Keeps the WASM simpler and more compatible
WASM Binary Structure
A Stylus WASM module consists of several sections:
Exports
Every Stylus contract exports a user_entrypoint function:
#[no_mangle]
pub extern "C" fn user_entrypoint(len: usize) -> usize {
// Entry point for all contract calls
// len: size of calldata in bytes
// returns: size of output data in bytes
}
This function is automatically generated by the #[entrypoint] macro and serves as the single entry point for all contract interactions.