Skip to content

Nervos State-Root Contract

This page freezes the nervos-smt-v2 state-root engine contract for NOOSChain. It is the contract validators must execute once a chain activates this engine through a protocol-versioned activation boundary.

The Nervos sidecar is a state-root engine. It is not a consensus engine and it is not the HashiCorp Raft sidecar. Raft orders committed block envelopes. NOOSChain executes those blocks and asks the selected state-root engine to fold deterministic state leaves into a block state root.

Frozen Identifiers

FieldFrozen value
Engine idnervos-smt-v2
Migration modelnew_root_scheme
Sidecar protocol version1
Checkpoint format version1
Empty root0000000000000000000000000000000000000000000000000000000000000000
Readiness probe root29ad010662d67dfdeecc36ea09d5ed7ac0030535afda3fe0a9dd99bf9ee8e4bc
Key encodinglowercase 32-byte hex H256
Value encodinglowercase 32-byte hex H256
HasherNervos sparse-merkle-tree crate with Blake2bHasher
Delete valueNoosValue::zero() / H256::zero()
Mutation orderingcaller-provided block_state_changes order

These values are mirrored in src/chain/state-root-engine-contract.ts and in the Rust sidecar constants. Changing any of them changes state-root semantics and requires a new engine id or an explicit protocol migration decision.

nervos-smt-v2 is not an iden3-equivalent implementation. It is a new state-root scheme. Operators must not use it as a transparent replacement for iden3-v1; existing chains can move to it only through an explicit activation height recorded in consensus state and persisted on block/checkpoint metadata.

Consensus-Critical Inputs

The sidecar input is the ordered mutation stream emitted by deterministic NOOSChain block execution:

json
{
  "type": "apply_batch",
  "mutations": [
    {
      "kind": "set",
      "stateKey": "<64 lowercase hex chars>",
      "valueHash": "<64 lowercase hex chars>"
    },
    {
      "kind": "delete",
      "stateKey": "<64 lowercase hex chars>"
    }
  ]
}

The following are consensus-critical:

  • the engine id stored on blocks, snapshots, and checkpoints;
  • the sidecar protocol version accepted by readiness checks;
  • the order of mutations inside apply_batch;
  • the stateKey bytes;
  • the valueHash bytes;
  • the delete behavior;
  • the empty root;
  • the hasher/tree implementation;
  • checkpoint format when a checkpoint becomes part of restore/replay flow;
  • the root returned after each committed block.

The TypeScript executor must not sort, deduplicate, merge, or otherwise rewrite the mutation stream before sending it to the sidecar. If two mutations affect the same key in one block, the sidecar applies them in caller order.

Lifecycle Boundary

Production nodes run a continuous state-root sidecar supervisor for Nervos readiness, health polling, version checks, restart/backoff, operator observability, and block execution leases. The lifecycle service itself is not consensus state, but the checkpoint/load behavior used by execution is part of the frozen engine contract.

For each Nervos block, the TypeScript executor loads the latest verified local Nervos checkpoint or hydrates from materialized leaves, applies the ordered mutation stream, reads the root, exports a new checkpoint, hashes the checkpoint file, and records verified metadata. A degraded continuous supervisor at or after activation is a fail-closed condition; it is never permission to fall back to iden3-v1.

Verified checkpoint metadata must match the frozen engine id, sidecar protocol version, checkpoint format version, file hash, and loaded root. A mismatch is a local fail-closed condition because the checkpoint is only an acceleration cache for a consensus root already recorded on blocks.

Key Encoding

stateKey is a 32-byte hash encoded as exactly 64 lowercase hexadecimal characters. It is parsed as an H256.

The sidecar rejects malformed hex and non-32-byte values with stable error codes:

  • INVALID_HEX_HASH
  • INVALID_HASH_LENGTH

NOOSChain must treat these as execution failures. A validator must not invent a replacement key encoding locally.

Value Encoding

valueHash is a 32-byte hash encoded as exactly 64 lowercase hexadecimal characters. It is parsed into the sidecar NoosValue, whose to_h256() method returns those 32 bytes directly.

For set mutations, the parsed value is inserted at stateKey.

For delete mutations, the sidecar updates the key with NoosValue::zero() and removes the key from its checkpoint leaf map.

Empty Root

The empty tree root is:

text
0000000000000000000000000000000000000000000000000000000000000000

Pinned vector tests enforce this value. If an upstream crate change changes the empty root, nervos-smt-v2 is no longer the same engine contract.

Checkpoint Format

The checkpoint document format version is 1.

Current checkpoint files are JSON documents:

json
{
  "engineVersion": "nervos-smt-v2",
  "protocolVersion": 1,
  "checkpointFormatVersion": 1,
  "chainId": "<chain id>",
  "root": "<64 lowercase hex root>",
  "leaves": [
    {
      "stateKey": "<64 lowercase hex chars>",
      "valueHash": "<64 lowercase hex chars>"
    }
  ]
}

Checkpoint load rules:

  • engineVersion must be nervos-smt-v2;
  • protocolVersion must be 1;
  • checkpointFormatVersion must be 1;
  • every leaf key/value must parse as a 32-byte hex value;
  • the recomputed root from leaves must match root;
  • leaves are rebuilt through the same tree update semantics used by runtime mutation application.

The sidecar rejects mismatches with stable error codes:

  • CHECKPOINT_ENGINE_VERSION_MISMATCH
  • CHECKPOINT_FORMAT_VERSION_MISMATCH
  • CHECKPOINT_ROOT_MISMATCH

Stable Error Codes

The current sidecar protocol emits these stable error codes:

CodeMeaning
SIDE_CAR_NOT_INITIALIZEDA stateful operation was requested before init or load_checkpoint.
CHECKPOINT_ENGINE_VERSION_MISMATCHCheckpoint engine id differs from nervos-smt-v2.
CHECKPOINT_FORMAT_VERSION_MISMATCHCheckpoint protocol or format version differs from the frozen contract.
CHECKPOINT_ROOT_MISMATCHCheckpoint leaves do not recompute to the stored root.
INVALID_HEX_HASHA key or value is not valid hex.
INVALID_HASH_LENGTHA key or value is not exactly 32 bytes.
REQUEST_DECODE_FAILEDThe sidecar request JSON could not be decoded into a known request.
INVALID_PROOF_FORMATA supplied proof document is not the frozen nervos-smt-v2-proof-v1 format.
PROOF_VERIFICATION_FAILEDThe sidecar could not verify the supplied compiled proof.
INTERNAL_ERRORThe sidecar failed without a more specific stable code.

Operators may see these codes in sidecar diagnostics. Validators must not convert them into a successful state-root result.

Sidecar Request Contract

The current sidecar transport is newline-delimited JSON over stdin/stdout. The supported request types are:

  • version
  • health
  • init
  • load_checkpoint
  • apply_batch
  • get_root
  • export_checkpoint
  • generate_proof
  • verify_proof
  • shutdown

generate_proof returns a nervos-smt-v2-proof-v1 document containing the engine id, protocol version, canonical 32-byte state key, value hash, root, inclusion flag, and a hex-encoded compiled Nervos SMT proof.

verify_proof is stateless. It verifies the supplied proof document against the supplied root, state key, and value hash without trusting local database rows or sidecar state. Missing-leaf proofs use the zero value hash and inclusion=false.

What Requires A New Engine Id

Use a new engine id instead of silently changing nervos-smt-v2 if any of the following changes:

  • sidecar protocol version;
  • checkpoint format version;
  • key encoding;
  • value encoding;
  • mutation ordering;
  • delete semantics;
  • empty root;
  • hasher or tree crate behavior;
  • checkpoint rebuild semantics;
  • proof format or proof encoding;
  • deterministic root vectors.

There is no allowed "compatible enough" implementation for an activated nervos-smt-v2 block. A node that cannot satisfy this contract must fail closed instead of producing a block with another state-root engine.

Validation

Run:

powershell
npm run build:state-root-sidecar-nervos
npm run test:state-root-nervos-vectors
npm run test:state-root-persistent-sidecar
npm run test:state-root-engine-safety
npm run test:state-root-activation-readiness

test:state-root-nervos-vectors pins the empty root and ordered mutation roots. test:state-root-persistent-sidecar verifies checkpoint version metadata, checkpoint reload, crash recovery at checkpoint boundaries, and corrupt or wrong-version checkpoint rejection.

Audience-first NOOSChain documentation.