Storage & Events¶
KV storage model¶
Each contract has an isolated key-value namespace. Keys are strings; values are opaque byte vectors (list<u8>).
Host functions¶
| Function | Purpose |
|---|---|
kv-get(key) |
Read a value. Returns None if the key does not exist. |
kv-set(key, value) |
Write a value. Traps during queries. |
kv-delete(key) |
Delete a key. Traps during queries. |
kv-has(key) |
Check existence without reading the value. |
Namespace isolation¶
Contracts cannot read or write another contract's storage. Each contract's keys are scoped to its own address. Cross-contract data access must go through query-contract or dispatch.
Transactional overlay semantics¶
During execution, all reads and writes go through a KvOverlay:
- Reads check the overlay first, then fall through to committed chain state.
- Writes accumulate in the overlay.
- On success, the overlay is committed atomically.
- On failure (trap, out-of-fuel, error return), the overlay is discarded entirely.
For nested sub-messages, an OverlayStack extends this model. Each sub-message pushes a new frame. Reads search top-to-bottom through all frames before falling through to committed state. On sub-message success, the frame merges into its parent; on failure, it is discarded.
Storage limits¶
Per-contract storage is capped at 10 MiB (max_contract_storage_bytes in vm.toml).
Events¶
Emitting events¶
emit-event takes a kind string (type tag) and arbitrary data bytes. Events are included in the transaction receipt and are queryable by block height.
Event fees¶
Each byte of event data costs event_byte_price fuel units (default: 5). Keep event payloads small.
Discovering events¶
Events appear in transaction receipts, which can be retrieved via:
GET /v1/tx/{hash}-- receipt for a specific transactionGET /v1/block/{height}/txs-- all transaction receipts in a block
Filter by event kind on the client side.