Skip to content

NDSR: the runtime

NDSR (Necter Distributed State Runtime) is the engine under everything on Necter. It loads .hbc modules, executes one exported function per call, meters gas, keeps per-module persistent state, and signs a receipt whose hash is identical on every honest node. Its consensus layer, SecureWeave, aggregates validator votes into quorum-backed, final results.

The same code runs in three places:

Where How
Validators ndsr serve: an HTTP node that executes consensus rounds, gossips votes, finalizes committee rounds, keeps module state and attests reward receipts.
Miners The Necter Miner embeds NDSR as a library and runs committee tasks with exactly the code validators use to check them.
Your machine ndsr run executes a module locally and prints the signed receipt, ndsr inspect validates an artifact. Every HiveKit hivec run calls it.
  • Sandbox. A module sees only its own linear memory and a small set of host functions. There is no WASI, no clock, no randomness, no filesystem and no network. Every pointer is bounds-checked; memory, tables, call depth, inputs, outputs, events and state writes are capped.
  • Determinism. NaN results are canonicalized, non-deterministic instruction-set features are disabled, the engine version is pinned, and a deterministic stack limit is injected into every module, so runaway recursion stops at the same gas on every machine. Details
  • Same results on every CPU. On x86_64 and aarch64 NDSR runs modules on its native engine; on 32-bit ARM phones it uses its portable engine (an interpreter). Both consume the same fuel-instrumented code, so output, events, gas and receipt hash are identical. A network can mix both.
  • Integrity. Modules are content-addressed and re-verified on every fetch and cache read. Receipts are signed with the node’s ed25519 key.
  • Atomic state. State writes and events are committed only if the whole top-level call succeeds. State

The portable engine is slower than the native engine. Measured on an Apple M-series host (release build, per call):

Workload native engine Mgas/s portable engine Mgas/s
tight loop 1 483 285
integer mix 2 978 250
float mix with NaNs 2 301 45
Go math.multiply 92 54
AssemblyScript / Rust counter.increment 87 / 46 40 / 35

Small calls are dominated by fixed per-call work (loading, receipt, signing), so the portable engine’s cost shows mainly in compute-heavy calls. A project can exclude slow engines in its scheduling requirements.

Terminal window
ndsr inspect dist/my_module.hbc # manifest, address, function ids, ABI check
ndsr run dist/my_module.hbc addNumbers --input '{"a":2,"b":3}'
ndsr run dist/my_module.hbc increment --input '{"by":2}' --data-dir ./node # state persists in ./node

ndsr run prints the result and the signed receipt (abridged):

{
"error": null,
"gas_limit": 1000000,
"gas_used": 10570,
"output": "{\"total\":5}",
"receipt": {
"node_id": "ndsr-eedd6fd9d0db3736",
"public_key": "0xfdc31b7a…7d39c96",
"receipt": {
"events": [],
"events_hash": "0x518674ab…a73d70",
"function": "addNumbers",
"gas_used": 10570,
"input_hash": "0x52377ca4…570060",
"module_address": "0x9cf5a3ab…be6127",
"output_hash": "0xd7b6e5ab…6029dd",
"receipt_hash": "0x38b6fb0c…ffb69d",
"success": true,
"v": 1
},
"signature": "0x32beca0f…014b0c",
"timestamp": 1791473539
},
"success": true
}

See Install the tools. Validators run the same binary with ndsr serve; see Run a validator.