Asentum

Concepts

Architecture

The whole stack at a glance · Estimated read time: 8 minutes

Updated 2026-09-09: the consensus layer is Aura block production plus GRANDPA finality, replacing the earlier Tendermint-style BFT description.

TL;DR

Asentum is five layers stacked on JavaScript: ANT plus HTTP networking at the bottom, Aura block production with GRANDPA finality on top of that, a Sparse Merkle Tree for state, a Hardened JavaScript sandbox for contract execution, and a JSON-RPC interface at the top. Every layer is JavaScript, every layer uses post-quantum cryptography for signatures, and the whole thing runs as a single Node.js process that fits on a Raspberry Pi 4.

The stack

┌─────────────────────────────────────────────┐
│  JSON-RPC (HTTP + WebSocket)                │
├─────────────────────────────────────────────┤
│  Hardened JavaScript VM (SES Compartments)  │
├─────────────────────────────────────────────┤
│  Sparse Merkle Tree state · LevelDB         │
├─────────────────────────────────────────────┤
│  Aura + GRANDPA · ML-DSA-65 sigs            │
├─────────────────────────────────────────────┤
│  ANT (consensus) + HTTP (sync, RPC)         │
└─────────────────────────────────────────────┘

Each layer is small enough to read in an afternoon. None of the layers depend on C++ native modules - the whole chain runs on pure Node.js with a handful of WASM crypto primitives for hot-path hashing and signing.

Networking, ANT + HTTP

Two transports, layered. Consensus votes (the hot path) ride ANT, the Asentum Native Transport: a persistent-TCP, length-prefixed protocol with a per-peer state machine that we built from scratch after libp2p kept dropping the consensus mesh under load. ANT runs in a worker thread so consensus storms can't starve the keep-alive loop. Full mesh between baked validators, content-fingerprint dedup at the receive path, and zero disconnects across a 24h soak.

Block sync, RPC, and everything client-facing runs over plain HTTP using the same JSON-RPC endpoint nodes serve to wallets. Replicas poll a configured peer's /block-raw/:n endpoint in batches of 32 and feed the results into apply as they land. NAT-friendly, firewall-friendly, no peer discovery needed for clients.

The split is on purpose. Consensus needs a tight, reliable, low-latency mesh between a small known set of validators, ANT's job. Block sync needs to work from anywhere, including behind aggressive NAT and corporate firewalls, HTTP's job. We tried unifying them under libp2p in mid-2026 and burned weeks on it. Backed it out and ANT is what we run now.

Consensus - Aura + GRANDPA

Consensus is split in two. Aura produces blocks: each validator in the active set is assigned timed slots (~2 second slots) and produces a block when its slot comes up. GRANDPA finalizes them: a block is final once validators representing two thirds of staked weight have voted for it. Finality is stake weighted, not headcount weighted, and it trails the chain head by a few blocks rather than gating every block on a vote. Finalized blocks do not reorg. The set scales to hundreds of validators.

Every block and every finality vote is signed with ML-DSA-65 (Dilithium3). Dilithium signatures are ~3.3 KB each and do not aggregate yet, so stake-weighted finality is what keeps the proof bounded: the chain finalizes on the votes of the highest-weight validators without waiting on every small one.

State - Sparse Merkle Tree

Account balances, nonces, contract code, and contract storage all live in a single Sparse Merkle Tree keyed by hash. The root of the tree after every block is part of the block header, so every validator agrees on exactly the same state at every height.

Underneath, we persist to LevelDB - the same storage engine Ethereum clients use. State is pruned opportunistically on full nodes; archive mode keeps every historical state root queryable.

Execution - Hardened JavaScript

Contract bodies are plain JavaScript source. When a transaction calls a method, the VM evaluates the source inside a fresh SES Compartment and invokes the named function. Storage, events, and cross-contract calls are injected as globals; everything that could break determinism is removed.

Gas metering runs on a simple cost model - per-tx-kind base cost, plus per-storage-write, per-event-byte, and a cold-load surcharge for large modules. See the fee market.

Interface - JSON-RPC

At the top of the stack sits a JSON-RPC 2.0 interface deliberately shaped like Ethereum's. Most eth_* methods work unchanged - MetaMask, ethers.js, viem, and every Ethereum-ecosystem explorer can read Asentum without modification.

Signing is the one place compatibility breaks: MetaMask produces ECDSA, Asentum requires Dilithium3. For that, use the Asentum Wallet extension or the SDK.

How a transaction flows

  1. A wallet builds an SSZ-encoded transaction and signs it with Dilithium3.
  2. The wallet POSTs eth_sendRawTransaction to any full node.
  3. The node validates the signature, nonce, balance, and gas, then fans the tx out over HTTP to every configured peer.
  4. The validator whose Aura slot is current picks mempool txs into a candidate block and broadcasts it. Other validators import it and build on it, so production never waits on a vote.
  5. GRANDPA finality runs alongside. Validators vote on the chain they have seen, all signed with Dilithium3. Once votes representing two thirds of staked weight agree on a block, that block and everything before it is finalized.
  6. The VM executes each tx in the finalized block, updating the SMT state.
  7. Receipts, events, and the new state root are committed to LevelDB and streamed over JSON-RPC.

Read next