Deterministic execution
Necter’s whole security model rests on one property: the same call on the same state produces the same receipt hash on every honest machine. Committees can then vote on a hash, validators can audit by re-executing, and anyone can check a result later. NDSR enforces this at several layers.
A closed sandbox
Section titled “A closed sandbox”A Hive Bytecode module may import only the host functions of its ABI (hive-wasm-v1)
(hive.call, hive.emit, hive.abort, storage.get/set/del, console.log, crypto.hash, and
AssemblyScript’s env.abort). Any other import, including any WASI function, makes the module invalid. So
inside a module there is:
- no clock: pass timestamps in the input;
- no randomness: derive values from the input with
crypto.hash, or use a scheduled project’s slot seed; - no filesystem, network or environment: everything a call needs must be in its input or the module’s own state.
Pinned bytecode semantics
Section titled “Pinned bytecode semantics”| Rule | Why |
|---|---|
| Enabled: MVP, multi-value, bulk memory, reference types, sign-extension, saturating float→int, SIMD, tail calls | Deterministic features only |
| Disabled: threads/shared memory, relaxed SIMD, memory64, multi-memory, GC, exceptions, stack switching, … | Their results can differ between hardware or engines |
Every NaN result is canonicalized (f64 0/0 → 0x7ff8000000000000) |
Different CPUs produce different NaN bit patterns |
| NDSR’s engine and bytecode validator versions are pinned | Fuel accounting is defined by that implementation; upgrading is a network upgrade |
| A deterministic logical stack limit (65,536 units) is injected into every module | The native and portable engines’ stacks overflow at different depths; the injected limit is always reached first, at the same gas everywhere |
Native engine and portable engine
Section titled “Native engine and portable engine”On x86_64 and aarch64 (also riscv64, s390x), NDSR’s native engine compiles modules to machine code. 32-bit ARM phones have no
native backend, so NDSR uses its portable engine (an interpreter). Both are fed the same fuel-instrumented,
NaN-canonicalized code, so output, events, gas_used, success and receipt hash are identical. This is
tested side by side for every fixture, and it is why a phone can sit on the same committee as a server.
Canonical JSON everywhere
Section titled “Canonical JSON everywhere”Every hashed or signed structure uses canonical JSON: keys sorted by code point, no whitespace, UTF-8 without escaping non-ASCII characters, integers only (no floats), and strings for numbers that can exceed 2^53. Receipts exclude timestamps and node ids. Hashes are Keccak-256 (Ethereum’s, not SHA3-256).
Python equivalent:
json.dumps(obj, sort_keys=True, separators=(",", ":"), ensure_ascii=False).encode()Ordering of state changes
Section titled “Ordering of state changes”Within a node, executions are serializable: each module’s state transitions are totally ordered. Across nodes, the Hub never has two rounds touching the same module’s state in flight at once, so every validator applies them in the same order. Committee workers are stateless, so ordering never matters for them.
Practical rules for module authors
Section titled “Practical rules for module authors”See Determinism rules for the language-by-language list of what to avoid (for
example Math.random(), Date.now(), map iteration order, floats in events).