Introduction / Architecture

Architecture

Five JavaScript layers, one Node.js process, no C++ dependencies — everything from consensus wire format to the RPC interface your wallet already speaks.

7 min read

TL;DR. ANT + HTTP networking, Tendermint-style BFT consensus, a Sparse Merkle Tree state, a Hardened JavaScript sandbox for contracts, and a JSON-RPC interface on top — all post-quantum, all running as a single Node.js process light enough for a Raspberry Pi 4.

Aevum is five JavaScript layers stacked on top of each other, all running inside a single Node.js process light enough for a Raspberry Pi 4.

The stack

  • JSON-RPC (HTTP + WebSocket) at the top
  • Hardened JavaScript VM using SES Compartments
  • Sparse Merkle Tree state, backed by LevelDB
  • Tendermint-style BFT consensus, signed with ML-DSA-65
  • Aevum Native Transport (ANT) + HTTP at the bottom

Every layer is independently readable, with no C++ dependencies — pure Node.js, with WASM for the cryptography primitives.

Networking: ANT + HTTP

Two transports do two different jobs. ANT is a persistent-TCP, length-prefixed protocol built specifically for consensus votes between a small, known set of validators. It runs in its own worker thread so a burst of consensus traffic can never starve the keep-alive loop.

HTTP handles everything else: block sync, RPC queries, and client interactions through the same JSON-RPC endpoint. Full nodes pull blocks in batches of 32 from peers via a /block-raw/:n endpoint. Consensus needs a tight, low-latency channel between known validators; block sync needs to work from behind a restrictive corporate firewall. One transport can't do both well, so Aevum doesn't ask it to.

Consensus: BFT

A Tendermint-style BFT committee of roughly 100 validators finalizes each block across four stages — propose, pre-vote, pre-commit, finality — each requiring 2/3 of voting power. Every vote is an ML-DSA-65 (Dilithium3) signature. At ~3.3KB per signature, ~100 signatures per block is close to the practical ceiling for a committee this size — see Consensus & Validators for the full picture.

State: Sparse Merkle Tree

Account balances, nonces, contract code, and contract storage all live in a single Sparse Merkle Tree, indexed by hash. The tree root goes in every block header, so every validator can check they're looking at the same state. LevelDB handles persistence underneath; full nodes prune opportunistically, and archive nodes keep every historical root.

Execution: Hardened JavaScript

Contracts are plain JavaScript source. Each transaction executes inside a fresh SES Compartment, with storage, events, and cross-contract calls injected as globals — and anything that would break determinism (wall-clock time, randomness, network access) simply isn't there to call.

Gas is metered per transaction type rather than per opcode: a base cost, plus charges for storage writes, event bytes, and a cold-load surcharge for large modules on their first call in a block.

Interface: JSON-RPC

Aevum exposes a JSON-RPC 2.0 interface modeled on Ethereum's. Most eth_* methods behave identically, so MetaMask, ethers.js, viem, and existing block explorers mostly just work. The one place compatibility breaks is signing: MetaMask produces ECDSA signatures, and Aevum needs Dilithium3 — so signing goes through the Aevum Wallet extension or SDK instead.

Transaction flow

  1. A wallet builds an SSZ-encoded transaction and signs it with Dilithium3
  2. The wallet submits it via eth_sendRawTransaction to any full node
  3. The node validates signature, nonce, balance, and gas, then broadcasts it over HTTP
  4. The current proposer assembles mempool transactions into a candidate block
  5. The committee pre-votes, pre-commits, and finalizes it with Dilithium3 signatures
  6. The VM executes each transaction, updating the Sparse Merkle Tree
  7. Receipts, events, and the new state root are persisted and streamed over JSON-RPC