Context & Groups
calimero-context + calimero-context-primitives + calimero-context-config
Purpose
ContextManager is an Actix actor that manages contexts (application instances), groups (governance units), and namespace governance DAGs. Every context belongs to a group within a namespace. The manager holds per-namespace DagStores (via HashMap<namespace_id, Arc<Mutex<DagStore>>>), handles 30+ message types, coordinates with a modular GroupStore for persistence, and runs lifecycle recovery and Prometheus metrics collection.
Module Structure
calimero-context
calimero-context-primitives
calimero-context-config
ContextManager Actor
The central actor for all context and group operations. Initialized on node start, it rebuilds in-memory state from persistent storage and starts background coordination tasks.
Key Fields
store: Arc<Store>,
node_client: NodeClient,
context_client: ContextClient,
group_dags: HashMap<GroupId, DagStore>,
contexts: HashMap<ContextId, ContextState>,
upgrade_propagators: HashMap<GroupId, UpgradeProp>,
// ... network, runtime refs
}
Startup Sequence
recover_in_progress_upgrades
Resume any application upgrades that were interrupted by a previous shutdown.
reload_group_dags
For each group in the store, read the full OpLog and rebuild the in-memory DagStore via restore_applied_delta.
start_group_heartbeat (30s)
Periodic timer publishes GroupStateHeartbeat with current dag_heads for every group, triggering catch-up on peers.
Handler Map
All 20+ ContextMessage variants, grouped by function. Each variant is handled by a dedicated file in handlers/.
Context Lifecycle
Group Governance
Membership & Access
Configuration & Sync
Governance Preflight & Signing Key Resolution
Every governance mutation handler calls governance_preflight() before signing and publishing. The common pattern is encapsulated in sign_and_publish_group_op() which handles the boilerplate.
governance_preflight Flow
Signing Key Hierarchy
When a child group is created via create_group_in_namespace, the signing key is stored only at the namespace root. Child groups resolve signing authority by walking up the parent chain:
for _ in 0..MAX_NAMESPACE_DEPTH {
if let Some(sk) = get_group_signing_key(store, ¤t, public_key)? {
return Ok(Some(sk));
}
current = get_parent_group(store, ¤t)?; // walk up
}
get_group_signing_key(store, ¤t, public_key) // final check at root
Key revocation at the namespace level automatically propagates — child groups lose access because the ancestor walk finds nothing. No stale copies to clean up.
sign_and_publish_group_op Helper
Encapsulates the governance handler boilerplate: preflight → clone datastore/node_client → build signer → sign, apply, publish via async actor response. Used by 7 handlers (set_group_alias, set_default_capabilities, set_default_visibility, update_group_settings, set_member_alias, set_member_capabilities, update_member_role).
GroupStore Deep-Dive
The authoritative persistence layer for all group and governance state. Handles signature verification, state-hash optimistic locking, nonce-based idempotency, DAG maintenance, and cascading side effects.
apply_local_signed_group_op Flow
Cap parent_op_hashes
Ensure parent hashes reference valid DAG heads (capped at 64 concurrent heads).
verify_signature
Ed25519 signature verification on the signable_bytes of the operation.
check state_hash
Optimistic lock — the op's state_hash must match the current computed group state hash.
check nonce (idempotent on duplicate)
Per-signer monotonic nonce. If the nonce was already seen, the op is silently treated as idempotent (no error, no re-apply).
dispatch GroupOp
Match on the GroupOp variant and apply the state mutation (add member, set visibility, cascade removal, etc.).
append OpLog
Serialize the SignedGroupOp via borsh and append to the persistent op log with an incrementing sequence number.
recompute dag_heads
Update the set of DAG head hashes — the new op becomes a head, its parents are removed from the head set.
set nonce
Record the signer's nonce for replay protection.
Key Storage Prefixes
All stored in Column::Group with typed key prefixes:
sign_apply_and_publish helper
Convenience function used by most handlers to emit governance ops. Combines three steps into one call:
&self,
group_id: GroupId,
op: GroupOp,
) -> Result<()> {
// 1. Sign op with node's Ed25519 key
// 2. apply_local_signed_group_op (persist + DAG)
// 3. Publish via gossipsub on group topic
}
ContextClient
Thin async façade wrapping LazyRecipient<ContextMessage>. Used by Server (for RPC execution) and NodeManager (for delta routing) to invoke context-level operations without importing Actix directly.
recipient: LazyRecipient<ContextMessage>,
}
impl ContextClient {
pub async fn send(&self, msg: ContextMessage) -> Result<ContextResponse>;
}
Context Operations
Group Operations
Membership
Configuration
Query
Dependencies
How the three context crates relate to other Calimero crates. Arrows show compile-time dependencies.