Skip to content

State and state sync

Each module has a private key/value map, persisted by every validator. A module reads and writes it with the storage.* host functions; nothing else can touch it. Writes are journaled per call frame: a successful hive.call merges the callee’s writes into the caller’s, a failed one discards them, and only when the top-level call succeeds is the journal committed atomically.

State only exists for modules run through validator rounds (POST /v1/execute). Committee workers are stateless; to keep results of mined work, write them into a stateful module from your backend.

Every validator keeps, per module, a head (seq, state_root):

leaf(k, v) = keccak256(u32be(len k) ‖ k ‖ u32be(len v) ‖ v)
bucket(k) = u16be(keccak256(k)[0..2]) >> 4 // 0 ..= 4095
bucket_hash(b) = keccak256(leaf(k1,v1) ‖ leaf(k2,v2) ‖ …) // keys of bucket b, ascending
state_root = keccak256("necter-state-v1" ‖ u16be(b) ‖ bucket_hash(b) ‖ …) // non-empty buckets, ascending

seq advances by exactly one for every committed top-level execution that wrote the module. Validator votes carry the state transition (pre_seq, pre_root, post_seq, post_root) of every module the call touched, so a SecureWeave quorum of votes attests the module’s new state, not only the output.

A validator that was down, partitioned or crashed mid-round notices that its head differs from the attested state. It then answers that module’s rounds with 503 {"status": "syncing"} (which is not a vote), fetches the missing commits (diffs) or a frozen snapshot from its peers, verifies them against the attested root, and resumes voting. Other modules keep running. With 4 validators and a quorum of 3, the network keeps answering while one validator catches up.

The Hub never has two rounds touching the same module’s state in flight at once. It infers which state a round may touch from the module’s imports: modules with storage.set/storage.del and no hive.call are ordered per module; modules that use hive.call are ordered against every other stateful round; pure modules run in parallel. The ordering scope appears in the /v1/execute response as consensus.ordering.scope (state, call or pure).