Storage Schema
Every key/value type across all 11 columns with byte layouts
Column Enum
All persistent data is partitioned into 11 column families. Each variant maps to a dedicated RocksDB column family with independent compaction and bloom filters.
Meta, // schema version, node id
Config, // node configuration
Identity, // keypairs per context
State, // shared context state KV
PrivateState, // per-node private KV (not synced)
Delta, // causal deltas (DAG)
Blobs, // content-addressed binary data
Application, // WASM binaries + metadata
Alias, // human-readable name → id
Generic, // uncategorized data
Group, // governance: 20 prefix-partitioned sub-namespaces
}
Context Column Types
Key/value types for the columns that store per-context data: metadata, configuration, shared state, private state, identity, and deltas.
Meta Column
| Key Struct | Key Layout | Value Type | Codec | Description |
|---|---|---|---|---|
| ContextMeta | context_id (32) | ContextMetaValue | Borsh | Context metadata including application info and DAG state |
application: ApplicationMeta, // app_id + version
root_hash: Hash, // Merkle root of context state
dag_heads: Vec<[u8; 32]>, // current DAG head delta IDs
}
Config Column
| Key Struct | Key Layout | Value Type | Codec | Description |
|---|---|---|---|---|
| ContextConfig | context_id (32) | ContextConfigValue | Borsh | Per-context revision counters |
application_revision: u64, // incremented on app upgrades
members_revision: u64, // incremented on membership changes
}
Identity Column
| Key Struct | Key Layout | Value Type | Codec | Description |
|---|---|---|---|---|
| ContextIdentity | context_id (32) | ContextIdentityValue | Borsh | Keypair for this node's identity within a context |
private_key: Option<[u8; 32]>, // Ed25519 private key
sender_key: Option<[u8; 32]>, // sender public key
}
State & PrivateState Columns
| Key Struct | Key Layout | Value Type | Codec | Description |
|---|---|---|---|---|
| ContextState | context_id (32)+app_key (var) | Slice | Identity | Shared context state — raw bytes, no serialization overhead |
| ContextPrivateState | context_id (32)+app_key (var) | Slice | Identity | Per-node private state — NOT synced to other nodes |
Delta Column
| Key Struct | Key Layout | Value Type | Codec | Description |
|---|---|---|---|---|
| ContextDagDelta | context_id (32)+delta_id (32) | ContextDagDeltaValue | Borsh | Causal delta with parents, actions, and verification data |
delta_id: [u8; 32],
parents: Vec<[u8; 32]>, // causal parent IDs
actions: Vec<Action>, // state mutations
hlc: HybridTimestamp, // hybrid logical clock
applied: bool, // has been applied to state
expected_root_hash: Hash, // post-apply verification
events: Vec<Event>, // emitted events
}
Group Column Detail
The Group column uses a single-byte prefix to partition 20 logical sub-namespaces within one RocksDB column family. Each prefix isolates a governance concern — membership, capabilities, operations log, upgrades, and aliases.
Membership & Metadata (0x20–0x23)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x20 | GroupMeta | 0x20+group_id (32) | GroupMetaValue | Group metadata (app_key, target_app, upgrade_policy, admin, migration) |
| 0x21 | GroupMember | 0x21+group_id (32)+identity (32) | GroupMemberRole | Member role in group |
| 0x22 | GroupContextIndex | 0x22+group_id (32)+context_id (32) | () | Context belongs to group (presence key) |
| 0x23 | ContextGroupRef | 0x23+context_id (32) | [u8; 32] | Reverse index: context → group_id |
GroupMetaValue definition
app_key: [u8; 32], // application identity
target_application_id: [u8; 32], // target WASM application
upgrade_policy: UpgradePolicy, // auto / manual / frozen
created_at: u64, // unix timestamp
admin_identity: [u8; 32], // group administrator
migration: Option<String>, // migration method name
}
Upgrades & Signing (0x24–0x25)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x24 | GroupUpgradeKey | 0x24+group_id (32) | GroupUpgradeValue | Active upgrade state |
| 0x25 | GroupSigningKey | 0x25+group_id (32)+key_id (32) | GroupSigningKeyValue | Ed25519 signing key for group |
GroupUpgradeValue & GroupUpgradeStatus definitions
from_version: u64,
to_version: u64,
migration: Option<String>, // migration method name
initiated_at: u64, // unix timestamp
initiated_by: [u8; 32], // admin identity
status: GroupUpgradeStatus,
}
InProgress {
total: u64, // total contexts to migrate
completed: u64, // successfully migrated
failed: u64, // failed migrations
},
Completed {
completed_at: u64, // unix timestamp
},
}
private_key: [u8; 32], // Ed25519 private key bytes
}
Capabilities & Visibility (0x26–0x2A)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x26 | GroupMemberCapability | 0x26+group_id (32)+identity (32) | GroupMemberCapabilityValue | Per-member capability bitmask |
| 0x27 | GroupContextVisibility | 0x27+group_id (32)+context_id (32) | GroupContextVisibilityValue | Per-context visibility (mode + creator) |
| 0x28 | GroupContextAllowlist | 0x28+group_id (32)+context_id (32)+identity (32) | () | Allowlist entry for restricted context (presence key) |
| 0x29 | GroupDefaultCaps | 0x29+group_id (32) | GroupDefaultCapsValue | Default capabilities for new members |
| 0x2A | GroupDefaultVis | 0x2A+group_id (32) | GroupDefaultVisValue | Default visibility for new contexts |
Capability & visibility value definitions
capabilities: u32, // bitmask: bit 0 = manage_members, bit 1 = manage_contexts, ...
}
mode: u8, // 0 = public, 1 = restricted, 2 = private
creator: [u8; 32], // identity that created the context
}
capabilities: u32, // default bitmask for new members
}
mode: u8, // default visibility mode for new contexts
}
Migration & Nonce (0x2B–0x2C)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x2B | GroupContextLastMigration | 0x2B+group_id (32)+context_id (32) | GroupContextLastMigrationValue | Last migration method applied to this context |
| 0x2C | GroupLocalGovNonce | 0x2C+group_id (32)+signer (32) | u64 | Per-signer monotonic nonce for replay protection |
GroupContextLastMigrationValue definition
method: String, // WASM method name used for migration
}
Aliases (0x2D–0x2F)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x2D | GroupMemberAlias | 0x2D+group_id (32)+identity (32) | String | Human-readable member alias |
| 0x2E | GroupAlias | 0x2E+group_id (32) | String | Group alias (human-readable name) |
| 0x2F | GroupContextAlias | 0x2F+group_id (32)+context_id (32) | String | Context alias within group |
Operation Log & DAG (0x30–0x31)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x30 | GroupOpLog | 0x30+group_id (32)+seq (8 BE) | Vec<u8> | Serialized SignedGroupOp — the governance operation DAG |
| 0x31 | GroupOpHead | 0x31+group_id (32) | GroupOpHeadValue | Latest sequence number + DAG heads |
GroupOpHeadValue definition
sequence: u64, // latest sequence number
dag_heads: Vec<[u8; 32]>, // current DAG head op IDs
}
The sequence number is stored as 8-byte big-endian in the key to enable efficient range scans in chronological order. The DAG heads track the frontier of the governance operation graph for catch-up protocol.
Member-Context Tracking (0x32–0x33)
| Prefix | Key Struct | Key Layout | Value Type | Description |
|---|---|---|---|---|
| 0x32 | GroupMemberContext | 0x32+group_id (32)+identity (32)+context_id (32) | [u8; 32] | Member-context join tracking |
| 0x33 | GroupContextMemberCap | 0x33+group_id (32)+context_id (32)+identity (32) | u8 | Per-context member capability override |
Key Model
All keys are statically typed via Key<T>, a newtype over GenericArray<u8, T::Size>. The AsKeyParts / FromKeyParts traits define how a key is decomposed into column + byte components, giving compile-time column assignment and fixed-size key guarantees.
Key<T> struct
GenericArray<u8, T::Size>
);
The key's byte length is determined at compile time by the associated Size type (a typenum unsigned integer). This means key construction is zero-allocation and key comparison is a simple memcmp.
Column Assignment
type Size: ArrayLength<u8>;
const COLUMN: Column;
fn as_key(&self) -> Key<Self>;
}
pub trait FromKeyParts: AsKeyParts {
fn from_key(key: Key<Self>) -> Self;
}
Each key type declares its COLUMN at the type level. The storage layer uses this to route operations to the correct RocksDB column family without runtime dispatch.
How It Works
Type-Level Sizing
A key type like GroupMember declares Size = U65 (1 prefix + 32 group_id + 32 identity). The compiler enforces this — you can't accidentally write a 64-byte key into a 65-byte slot.
Column Routing
When you call db.get::<GroupMember>(key), the COLUMN associated constant resolves to Column::Group at compile time. No runtime map lookups needed.
Prefix Scans
For iteration within a column, the prefix byte enables efficient set_iterate_range scans. For example, scanning all members of a group uses prefix 0x21 || group_id as the range start.
Codec Selection
Values use Borsh serialization by default. State and PrivateState columns use Identity codec (raw bytes) to avoid serialization overhead for application-controlled data.
Example: GroupMember key implementation
group_id: [u8; 32],
identity: [u8; 32],
}
impl AsKeyParts for GroupMember {
type Size = U65; // 1 (prefix) + 32 + 32
const COLUMN: Column = Column::Group;
fn as_key(&self) -> Key<Self> {
let mut arr = GenericArray::default();
arr[0] = 0x21; // prefix byte
arr[1..33].copy_from_slice(&self.group_id);
arr[33..65].copy_from_slice(&self.identity);
Key(arr)
}
}
Byte layout legend
The byte layout diagrams throughout this page use the following color scheme: