Wire Protocol
Every message type with field-level documentation
BroadcastMessage gossipsub 10 variants
Top-level enum for all messages published via gossipsub topics. Each variant is Borsh-serialized before being sent as a gossipsub message payload. Context topics use context/<hex>, group topics use group/<hex>, namespace topics use namespace/<hex>.
StateDelta — application state replication
Carries a WASM execution result (state diff) to all peers in a context. Published on context gossipsub topics after a successful method execution and state commit.
HashHeartbeat — context state comparison
Periodic heartbeat published on context topics. Peers compare root_hash and dag_heads to detect divergence and trigger sync.
SpecializedNodeDiscovery — peer role announcement
SpecializedNodeJoinConfirmation — role join ack
GroupMutationNotification — group change signal
Lightweight notification that a group was mutated. Does not contain the full op — peers use this to decide whether to fetch details or update caches.
SignedGroupOpV1 — governance operation (v1 wire)
Carries a Borsh-serialized SignedGroupOp as an opaque byte vector. Published on group gossipsub topics. Receivers deserialize, verify signature, and apply.
GroupGovernanceDelta — governance DAG delta
Alternative governance replication format used by the DAG sync layer. Carries the same data as SignedGroupOpV1 but with explicit DAG metadata for the governance DAG.
GroupStateHeartbeat — group governance comparison
Periodic heartbeat for governance DAG state. Published every 30s on group topics. Peers compare dag_heads to detect missing ops and trigger governance catch-up.
NamespaceGovernanceDelta — namespace governance op
Carries a SignedNamespaceOp on namespace gossipsub topics. Published when a namespace governance operation is created (group creation, member join, key delivery, etc.). Receivers verify the signature, apply to the namespace DAG, and may trigger key delivery.
NamespaceStateHeartbeat — namespace governance comparison
Periodic heartbeat for namespace governance DAG state. Published every 30s on namespace topics. Peers compare dag_heads (capped at 256) to detect missing ops. Split logic: gossipsub for ops the peer needs, P2P stream for backfill of ops we need.
GroupMutationKind 14 variants
Enum carried inside GroupMutationNotification. Describes what kind of group mutation occurred, allowing receivers to react selectively without deserializing the full op.
StreamMessage stream 3 variants
Framing protocol for all point-to-point stream communication. Each stream begins with an Init message, followed by zero or more Message frames, and can terminate with OpaqueError.
InitPayload stream init 13 variants
Sent as the first message on a new stream. Determines the protocol/purpose of the stream and carries initial handshake data.
BlobShare — transfer application binary
KeyShare — exchange encryption key
DeltaRequest — fetch specific delta
DagHeadsRequest — get current heads
SnapshotBoundaryRequest — negotiate snapshot range
SnapshotStreamRequest — start full snapshot transfer
TreeNodeRequest — fetch Merkle tree node
LevelWiseRequest — level-wise tree comparison
EntityPush — push entities to peer
GroupDeltaRequest — fetch governance op
Requests a specific governance operation from the peer's op log. Used during governance catch-up when heartbeat reveals missing ops.
NamespaceBackfillRequest — fetch namespace governance ops
Requests one or more namespace governance operations by delta ID. Opened as a P2P stream when NamespaceStateHeartbeat comparison reveals ops we are missing. The peer responds with NamespaceBackfillResponse messages.
NamespaceJoinRequest — join namespace via invitation
Sent by a joiner to an existing namespace member after subscribing to the namespace topic and forming a mesh. The peer responds with the group key (wrapped via ECDH), a snapshot of governance ops, and a list of context IDs to auto-join.
MessagePayload stream data 14 variants
Subsequent data frames sent after the initial Init on a stream. The variant matches the stream type established by InitPayload.
DeltaResponse — delta fetch result
DagHeadsResponse — current DAG heads
SnapshotBoundaryResponse — snapshot range info
SnapshotStreamData — snapshot chunk
SnapshotStreamEnd — snapshot complete
TreeNodeResponse — Merkle tree node data
LevelWiseResponse — level comparison result
EntityPushAck — entity push acknowledgment
GroupDeltaResponse — governance op data
NamespaceBackfillResponse — namespace governance ops
BlobShareAck — blob received confirmation
KeyShareAck — key share confirmation
ContextStateCheckResponse — state check result
StateSyncChunk — incremental state sync data
StateSyncComplete — state sync finalization
GroupOp gossipsub 20 variants
The actual governance operation inside a SignedGroupOp. Each variant represents a specific group mutation. Applied deterministically on all nodes for convergence.
Member Management — 9 variants
Context Lifecycle — 3 variants
Access Control — 2 variants
Aliases — 3 variants
Group Lifecycle & Special — 4 variants
SignedGroupOp Schema v3
The complete signed governance operation structure. Each op is content-addressed (SHA-256 of signable bytes), Ed25519 signed, and forms a DAG via parent hashes.
Wire Layout
Signable Subset
Signing Process
1. Build signable: Construct SignableGroupOp (all fields except signature).
2. Domain prefix: Prepend domain separator b"calimero-signed-group-op-v3" to Borsh-serialized bytes.
3. Sign: signature = Ed25519::sign(private_key, domain_prefix ++ borsh(signable))
4. Content hash: op_hash = SHA-256(borsh(signable)) — used as the DAG delta ID.
Validation Order
- Signature verification (Ed25519)
- Schema version check (must be 3)
- Nonce ≥ last seen nonce for signer
- state_hash matches current group state (or all-zeros to bypass)
- Signer has sufficient role/capabilities for the op
- parent_op_hashes.len() ≤ 256
Key Invariants
- parent_op_hashes — capped at 256 entries
- nonce — monotonically increasing per signer
- state_hash — all-zeros means skip validation
- max_dag_heads — capped at 64 per group
- Content hash is deterministic: same signable bytes → same hash
SignedNamespaceOp Schema namespace governance
Namespace-level governance operations. Each namespace has a single DAG shared by all groups within it. Operations are either RootOps (cleartext, visible to all namespace members) or GroupOps (encrypted with the group key, only readable by group members).
NamespaceOp — RootOp Variants
Cleartext operations visible to all namespace members. Used for structural changes and key distribution.
NamespaceOp — GroupOp Variant
Encrypted operations only readable by members of the target group. Non-members store an opaque skeleton (preserving causal structure).
Key Delivery Flow
Signing Process (Namespace Ops)
1. Build SignedNamespaceOp with: namespace_id, parent_hashes, state_hash, nonce, op.
2. Sign with the node's namespace identity private key (not the group signing key).
3. Content hash delta_id = SHA-256(signable_bytes) for DAG identity.
NetworkMessage internal 15 variants
The Actix message enum sent to the NetworkManager actor. These are internal to the node — never serialized on the wire. Each variant triggers a specific libp2p operation.
NetworkEvent internal 11 variants
Events emitted by the NetworkManager actor and handled by NodeManager. These represent observed network activity — gossip messages, peer changes, stream events.