Expand description
DataCap — backing (immutable dense page slab) + copy-on-write overlay.
A DataCap is { backing: Arc<PageSlab>, overlay }:
PageSlabis the immutable backing: a dense runtime-sized vector of pages (indexiis absolute pagei),Arc-shared soMGMT_COPYis one refcount bump. It is not a sparseRadixMapof 2 MiB groups and not raw bytes — it is a custom SSZ page-vector whosehash_tree_rootmerkleizes the page roots at the exact runtime depthceil_log2(page_count)(page_count = size / PAGE_SIZE).ssz::List<T, N>/VectorfixNat compile time; a cap’spage_countis a runtime value, soPageSlabis a bespoke type reusing [ssz::merkle::merkleize] withlimit = page_count.overlayis the copy-on-write working layer: the pages this cap has modified since the backing settled, keyed by absolute page index. A page present in the overlay shadows the backing; a clean cap has an empty overlay and is identical to its backing. During execution the engines write dirty pages straight into the overlay (no separate dirty-page list); at settleDataCap::flushfolds the overlay into a freshPageSlab.
Earlier drafts split this across a separate DataCap (immutable, sparse
groups) and DataViewCap (backing-by-hash + overlay). They are now one
type: DataViewCap == DataCap.
§The cap root (flat, size-scaled) — defined only on a flushed cap
hash_tree_root is the SSZ 2-field container { size, pages }:
cap_root = merkleize([ htr(size), pages_root ], 2) // depth-1 container
pages_root = merkleize([ page(0)..page(page_count) ], page_count) // = PageSlab::hash_tree_root
page_count = size / PAGE_SIZEThe cap root is only defined when the overlay is empty — the backing is
the hashable, content-addressed form; the overlay is transient working state.
Hashing a cap with a non-empty overlay is a usage error (it panics, like
hashing a cap graph that still holds an unresolved Ref): callers
flush first. The engines’ read path
(page_slot / page_at) and the
zero-copy slot return read effective bytes without hashing.
The pages-root tracks the cap’s actual size (depth ceil_log2(page_count)),
not a fixed compile-time capacity: ≤ 256 pages (≤ 1 MiB) is shallower than
depth 9; a 4 GiB cap is depth 20. size is committed in the cap’s own root
(the first container field) because SSZ merkleization is not self-describing.
§Page-alignment invariant
Each present page is a PageSlot::Loaded holding a refcounted
PageBytes whose bytes is a PAGE_SIZE-aligned 4 KiB slab
(alloc_page_aligned_zeroed) — load-bearing because the x86 recompiler
resolves each page’s physical address from its slab pointer and maps it
directly into a ring-3 page table. This holds for backing and overlay pages.
Structs§
- Archived
Data Cap - An archived
DataCap - Archived
Page Slab - An archived
PageSlab - DataCap
- Data cap: an
Arc-shared immutablePageSlabbacking plus a copy-on-write overlay of modified pages. The cap identity (when flushed) is the flat size-scaled{ size, pages }merkle (see the module docs). - Data
CapResolver - The resolver for an archived
DataCap - Page
Slab - The dense immutable backing of a
DataCap: a custom runtime-sized SSZ vector of pages. - Page
Slab Resolver - The resolver for an archived
PageSlab
Enums§
- Page
Resolution - Resolution of a single page within a
DataCap, shared by both engines so they materialize byte-identically.
Constants§
- GROUP_
PAGES - Pages per 2 MiB group (
512 = 2^9). Kept as the natural large-page / 2 MiB-cluster unit (architecture-portable large page; the read-only gas materialization unit), even though storage is no longer group-chunked. - GROUP_
SIZE - 2 MiB span in bytes (
512 * 4096 = 1 << 21). - PAGE_
SIZE - Cap-level page size. Mirrors the architecture’s 4 KiB page (must match
nub_arch_x86::paging::PAGE_SIZEfor direct PT mapping to work).
Functions§
- alloc_
page_ aligned_ zeroed - Allocate a zero-filled
Vec<u8>oflenbytes (rounded up to the next page boundary) withPAGE_SIZE-aligned backing storage. Page alignment is what lets the kernel map the buffer directly into a ring-3 PT. - page_
content_ hash - Content hash of a single page: the SSZ
hash_tree_rootof the page as aByteVector[PAGE_SIZE](zero-padded), under the cap digest (SHA-256). This is the value a materialized page contributes to the cap merkle and the precomputedPageBytes::hashkept by the substitution invariant.