Skip to content

Limits, capabilities & roles

This is a reference page of the fixed numbers and bitsets a Calimero context enforces: how big a value can be, how large a signed governance op may grow, what each role is allowed to do, and which bits make up a capability or an operation mask. Every figure here is sourced from a named constant in the codebase — when the code and this page disagree, the code wins.

Cross-links: Build gotchas (the limits you hit in practice), Governance (how roles and capabilities are assigned), and Capability inheritance (how capability bits flow through subgroups).

These bound a single WASM execution. Defaults live in crates/runtime/src/logic.rs (VMLimits::default); a node may override them, but these are what ship.

Limit (VMLimits field)DefaultNotes
max_memory_pages1024 pages = 64 MiBOne WASM page is 64 KiB; 1024 × 64 KiB.
max_stack_size200 KiBGuest call stack.
max_registers100Number of host-call registers.
max_register_size100 MiBPer-register data cap (constrained < u64::MAX).
max_registers_capacity1 GiBTotal across all registers.
max_logs1024Log-line count per execution.
max_log_size16 KiBPer line; an over-long line traps (LogLengthOverflow), it is not truncated.
max_events100Emitted events per execution.
max_event_kind_size100 bytesEvent “kind” string.
max_event_data_size16 KiBEvent data payload.
max_xcalls100Cross-context calls per execution.
max_xcall_function_size100 bytesCross-context call function name.
max_xcall_params_size16 KiBCross-context call params.
max_storage_key_size1 MiBPer storage key (NonZeroU64).
max_storage_value_size10 MiBPer storage value (NonZeroU64).
max_blob_handles100Concurrent open blob handles.
max_blob_chunk_size10 MiBPer read/write chunk against a blob.
max_method_name_length256 bytesEntrypoint method name.
max_module_size20 MiBWASM module size before compilation (anti-DoS).
max_artifact_size16 MiBCommit artifact copied out of guest memory onto the Outcome (anti-DoS); over-size traps with ArtifactSizeOverflow.

Caps on what crosses the network — RPC requests, signed governance ops, sync snapshot transfers, and DAG-head sets. Snapshot constants are in crates/node/primitives/src/sync/snapshot.rs; the governance DAG-head cap is in crates/context/config/src/types.rs; request-validation caps are in crates/server/primitives/src/validation.rs.

LimitValueConstant / source
RPC call args (args_json)10 MiB (10 × 1024 × 1024)MAX_ARGS_JSON_SIZE (validation.rs)
Signed governance-op payload64 KiB (64 × 1024)MAX_SIGNED_GROUP_OP_PAYLOAD_BYTES (snapshot.rs)
Group/member/context metadata64 KiBMAX_METADATA_SIZE (validation.rs)
TEE quote (base64)64 KiBMAX_QUOTE_B64_LENGTH (validation.rs)
Governance DAG heads32MAX_GOVERNANCE_DAG_HEADS (context/config/types.rs)
Sync DAG heads (per snapshot)100MAX_DAG_HEADS (snapshot.rs)
Snapshot page size — default256 KiB (256 × 1024)DEFAULT_SNAPSHOT_PAGE_SIZE
Snapshot page size — max4 MiB (4 × 1024 × 1024)MAX_SNAPSHOT_PAGE_SIZE
Entities per snapshot page1000MAX_ENTITIES_PER_PAGE
Entity data size (per record)1 MiBMAX_ENTITY_DATA_SIZE
Total pages per snapshot10 000MAX_SNAPSHOT_PAGES (≈2.5 GB at 256 KiB/page)
Compressed page payload8 MiBMAX_COMPRESSED_PAYLOAD_SIZE

Bounds on the sync subsystem: how many in-flight deltas a node buffers while it catches up, how long a buffered delta waits for governance before it is dropped, and the per-message / per-session ceilings the incremental state-transfer protocols enforce so a peer cannot demand an unbounded walk. These are about liveness and DoS resistance, not the wire-format sizes above.

While a node is uninitialized or applying a snapshot, incoming gossip deltas are held in a FIFO buffer and replayed once the node has the state to apply them against. A separate buffer holds deltas whose authorizing governance hasn’t been folded yet.

CapValueBehaviour at the limitConstant / source
Snapshot-sync delta buffer10 000 deltas / contextOldest evicted first (FIFO); the drops counter incrementsDEFAULT_BUFFER_CAPACITY (node/primitives/delta_buffer.rs:29)
Minimum recommended buffer100Below this a startup warning is logged — small buffers drop under normal loadMIN_RECOMMENDED_CAPACITY (delta_buffer.rs:35)
Zero-capacity buffer0Valid but drops every delta immediately (DroppedZeroCapacity)delta_buffer.rs (push, the capacity == 0 arm)
Governance-pending drain attempts16After 16 re-buffer passes the delta is permanently dropped with a warn (dropped_max_attempts)MAX_GOVERNANCE_DRAIN_ATTEMPTS (delta_buffer.rs:158), enforced in handlers/state_delta/buffering.rs:195

The drain counter advances on both drain triggers — a governance op applying and new state-delta traffic arriving — so 16 attempts is well past any legitimate partition-recovery delay; a still-orphaned delta is dropped rather than retained forever (a later gossip rebroadcast or snapshot would re-deliver it if valid).

Incremental state transfer (HashComparison / LevelWise)

Section titled “Incremental state transfer (HashComparison / LevelWise)”

The two tree-walking protocols clamp every request and response so a malicious or buggy peer cannot force an arbitrarily expensive traversal. Note the two depth caps differ by protocol.

CapValueBehaviour at the limitConstant / source
HashComparison nodes per response1000Response with more nodes is rejected as invalidMAX_NODES_PER_RESPONSE (node/primitives/sync/hash_comparison.rs:20)
HashComparison request depth16max_depth MUST be validated against this before processingMAX_TREE_REQUEST_DEPTH (node/primitives/sync/wire.rs:47)
LevelWise nodes per level10 000Responder bails (errors the session) if a level response exceeds itMAX_NODES_PER_LEVEL (sync/levelwise.rs:83; checked in sync/level_sync.rs:306)
LevelWise parents per request1000Truncated to the cap and truncation_occurred is set — sync may be incompleteMAX_PARENTS_PER_REQUEST (levelwise.rs:77; clamped in level_sync.rs:523)
LevelWise requests per session128Further requests are refused, bounding how long a peer can hold the session openMAX_REQUESTS_PER_SESSION (levelwise.rs:90; checked in level_sync.rs:813)
LevelWise traversal depth64max_depth clamped to this (LevelWise targets depth ≤ 2; the ceiling is headroom)MAX_LEVELWISE_DEPTH (levelwise.rs:71)

A member’s capabilities are a u32 bitset (crates/context/config/src/lib.rs, also exported via crates/primitives/src/context.rs). These gate governance actions beyond the implicit default-write that membership already grants. Capabilities flow through open subgroups — see Capability inheritance.

BitConstantGrants
1 << 0CAN_CREATE_CONTEXTCreate a context within the group.
1 << 1CAN_INVITE_MEMBERSIssue invitations to the group.
1 << 2CAN_JOIN_OPEN_SUBGROUPSBe inherited as a member of Open subgroups beneath this group. Granted to non-admins by default; admins revoke it as a deny-list.
1 << 3MANAGE_MEMBERSAdd/remove members and manage their roles.
1 << 4MANAGE_APPLICATIONManage the group’s application (e.g. upgrades).
1 << 5CAN_CREATE_SUBGROUPCreate a subgroup directly under the namespace root (the “any member can start a channel” knob).
1 << 6CAN_DELETE_SUBGROUPCascade-delete a subgroup and its subtree. A delegation knob, not a default.
1 << 7CAN_MANAGE_VISIBILITYFlip a subgroup’s OpenRestricted visibility without full admin.
1 << 8CAN_MANAGE_METADATASet group/member/context metadata (*MetadataSet ops) without full admin. A member may always set their own member metadata regardless.

A member’s role (crates/primitives/src/context.rs) is the coarse classification; capability bits refine what a non-admin can additionally do.

RoleReadWrite default dataGovernanceNotes
AdminYesYesYes — holds management capabilities implicitly (add/remove members, roles, metadata, visibility).Removal is guarded so a group is never left without another admin.
MemberYesYes (DEFAULT_MEMBER_MASK on non-restricted entities)Only what their capability bits grant.The ordinary participant; the write boundary for default data.
ReadOnlyYesNoNoHolds the group key to decrypt and read, but cannot author write ops.
ReadOnlyTeeYesNoNoA TEE-attested fleet read replica admitted by hardware attestation, not invitation. Removal cascades an in-band self-purge. See TEE Attestation.

Separate from governance capabilities, the data plane authorizes individual writes through a 3-bit OpMask (crates/storage/src/entities.rs). It answers “may this author perform this kind of operation on this entity?”

BitConstantMeaning
0b001OpMask::WRITECreate/update (upsert) an entity.
0b010OpMask::DELETEDelete an entity.
0b100OpMask::ADMINChange an entity’s writer set (rotate its ACL / ownership).
0b000OpMask::NONENo rights.
0b111OpMask::FULLWRITE + DELETE + ADMIN.

Membership implicitly grants WRITE | DELETE (DEFAULT_MEMBER_MASK) on any non-restricted entity — but not ADMIN, so a plain member can write and delete default data yet cannot lock others out by rotating an object’s writer set. Restricted objects override this with an explicit per-object ACL. The full authorization story is in Governance and the Security & threat model.