Skip to main content

jar_kernel/
state.rs

1//! σ — the v3 chain state.
2//!
3//! σ is a `CacheDirectory` plus the validator set. Data blobs, image
4//! blobs, cnode blobs, and chain Instance blobs all live in the cache
5//! as `Cap` values, addressed by content hash.
6//!
7//! The state root is the SSZ `hash_tree_root` of the cache's blobs,
8//! each represented as a `(blob_hash, cap_hash)` leaf container.
9
10use javm_cap::{CacheDirectory, CapHash, cap_hash};
11use ssz::{Encode, HashTreeRoot};
12
13/// PoA validator key (placeholder — 32-byte public key).
14pub type ValidatorKey = [u8; 32];
15
16/// One state-root leaf: a `(blob_hash, cap_hash)` pair.
17///
18/// Encoded as the SSZ container `{ blob_hash: [u8;32], cap_hash: [u8;32] }`.
19/// The leaf's `hash_tree_root` is `merkleize([blob_hash, cap_hash], 2) =
20/// hash(blob_hash || cap_hash)` — equivalent to the legacy BMT leaf
21/// protocol but with SHA-256 instead of Blake2b.
22#[derive(Clone, Copy, Debug, PartialEq, Eq, Encode, HashTreeRoot)]
23pub struct StateLeaf {
24    pub blob_hash: CapHash,
25    pub cap_hash: CapHash,
26}
27
28/// The chain's σ-resident state.
29///
30/// All cap content lives in `caps` (a `CacheDirectory`). The validator
31/// set is kept alongside as a Vec for now; future revisions may move
32/// it into a dedicated registry cap.
33pub struct State {
34    pub caps: CacheDirectory,
35    pub validators: Vec<ValidatorKey>,
36}
37
38impl State {
39    pub fn new() -> Self {
40        Self {
41            caps: CacheDirectory::new(),
42            validators: Vec::new(),
43        }
44    }
45}
46
47impl Default for State {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53/// State-root: SSZ `hash_tree_root` of the cache's blobs.
54///
55/// Each leaf is a `StateLeaf { blob_hash, cap_hash }` container. The
56/// full state root is `hash_tree_root` of the `Vec<StateLeaf>`, which
57/// merkleizes the per-leaf roots, pads to the next power of two, and
58/// mixes in the length per SSZ `List` semantics.
59///
60/// Leaves are sorted by `blob_hash` explicitly so the result is
61/// independent of insertion order (the cap store is a HashMap, whose
62/// iteration order is unspecified). Empty caches reduce to the SSZ
63/// canonical empty-list root.
64pub fn state_root(state: &State) -> CapHash {
65    let mut leaves: Vec<StateLeaf> = state
66        .caps
67        .iter_blobs()
68        .into_iter()
69        .map(|(hash, cap)| StateLeaf {
70            blob_hash: hash,
71            cap_hash: cap_hash(&cap),
72        })
73        .collect();
74    leaves.sort_by_key(|l| l.blob_hash);
75    ssz::hash_tree_root(&leaves)
76}
77
78#[cfg(test)]
79mod tests {
80    use super::*;
81
82    #[test]
83    fn empty_state_root_is_deterministic() {
84        let s1 = State::new();
85        let s2 = State::new();
86        assert_eq!(state_root(&s1), state_root(&s2));
87    }
88
89    #[test]
90    fn state_root_changes_with_published_data() {
91        let s = State::new();
92        let r0 = state_root(&s);
93        s.caps
94            .put_cap(&javm_cap::Cap::data_inline(b"hello"))
95            .unwrap();
96        let r1 = state_root(&s);
97        assert_ne!(r0, r1);
98    }
99}