jar_kernel/
kernel_assist.rs1use std::collections::HashMap;
15
16use javm::{KernelAssist, MeterId, QuotaId};
17use javm_cap::{Blake2b256, CapHash, CapHashOrRef, Hash};
18
19pub struct SigmaKernelAssist {
21 gas_meters: HashMap<MeterId, u64>,
23 storage_quotas: HashMap<QuotaId, u64>,
25 yield_catchers: HashMap<CapHash, Vec<CapHash>>,
27 next_yc_nonce: u64,
29 files: HashMap<u64, CapHashOrRef>,
32 next_file_id: u64,
33}
34
35impl SigmaKernelAssist {
36 pub fn new() -> Self {
37 Self {
38 gas_meters: HashMap::new(),
39 storage_quotas: HashMap::new(),
40 yield_catchers: HashMap::new(),
41 next_yc_nonce: 0,
42 files: HashMap::new(),
43 next_file_id: 1,
44 }
45 }
46
47 pub fn reset_block_state(&mut self) {
50 self.gas_meters.clear();
51 self.storage_quotas.clear();
52 self.yield_catchers.clear();
53 }
54
55 pub fn seed_root_gas(&mut self, budget: u64) {
58 self.gas_meters.insert(0, budget);
59 }
60
61 pub fn seed_root_quota(&mut self, budget: u64) {
63 self.storage_quotas.insert(0, budget);
64 }
65}
66
67impl Default for SigmaKernelAssist {
68 fn default() -> Self {
69 Self::new()
70 }
71}
72
73impl KernelAssist for SigmaKernelAssist {
74 fn gas_meter_get(&self, meter_id: MeterId) -> u64 {
76 self.gas_meters.get(&meter_id).copied().unwrap_or(0)
77 }
78 fn gas_meter_set(&mut self, meter_id: MeterId, value: u64) -> u64 {
79 self.gas_meters.insert(meter_id, value).unwrap_or(0)
80 }
81
82 fn storage_quota_get(&self, quota_id: QuotaId) -> u64 {
84 self.storage_quotas.get("a_id).copied().unwrap_or(0)
85 }
86 fn storage_quota_set(&mut self, quota_id: QuotaId, value: u64) -> u64 {
87 self.storage_quotas.insert(quota_id, value).unwrap_or(0)
88 }
89
90 fn yield_catcher_markers(&self, catcher_hash: CapHash) -> Vec<CapHash> {
92 self.yield_catchers
93 .get(&catcher_hash)
94 .cloned()
95 .unwrap_or_default()
96 }
97 fn yield_catcher_add(&mut self, catcher_hash: CapHash, marker_instance_hash: CapHash) {
98 let entry = self.yield_catchers.entry(catcher_hash).or_default();
99 if !entry.contains(&marker_instance_hash) {
100 entry.push(marker_instance_hash);
101 }
102 }
103 fn yield_catcher_remove(&mut self, catcher_hash: CapHash, marker_instance_hash: CapHash) {
104 if let Some(entry) = self.yield_catchers.get_mut(&catcher_hash) {
105 entry.retain(|m| *m != marker_instance_hash);
106 }
107 }
108 fn yield_catcher_new(&mut self) -> CapHash {
109 let nonce = self.next_yc_nonce;
110 self.next_yc_nonce += 1;
111 let hash = Blake2b256::hash(&nonce.to_le_bytes());
112 self.yield_catchers.insert(hash, Vec::new());
113 hash
114 }
115
116 fn host_open(&mut self, file_id: u64) -> Option<CapHashOrRef> {
118 self.files.get(&file_id).cloned()
119 }
120
121 fn host_save(&mut self, data: CapHashOrRef, quota_id: u64, size: u64) -> Option<u64> {
122 let current = self.storage_quotas.get("a_id).copied().unwrap_or(0);
123 if current < size {
124 return None;
125 }
126 self.storage_quotas.insert(quota_id, current - size);
127 let file_id = self.next_file_id;
128 self.next_file_id += 1;
129 self.files.insert(file_id, data);
130 Some(file_id)
131 }
132}
133
134#[cfg(test)]
135mod tests {
136 use super::*;
137
138 #[test]
139 fn host_save_debits_quota_and_allocates_file_id() {
140 let mut ka = SigmaKernelAssist::new();
141 ka.seed_root_quota(1000);
142 let file_id = ka.host_save(CapHashOrRef::Hash([0u8; 32]), 0, 32).unwrap();
143 assert_eq!(file_id, 1); assert_eq!(ka.storage_quota_get(0), 968);
145 assert_eq!(ka.host_open(file_id), Some(CapHashOrRef::Hash([0u8; 32])));
146 }
147
148 #[test]
149 fn host_save_exhausted_quota_returns_none() {
150 let mut ka = SigmaKernelAssist::new();
151 assert!(ka.host_save(CapHashOrRef::Hash([0u8; 32]), 0, 1).is_none());
153 }
154
155 #[test]
156 fn reset_block_state_clears_ephemeral_tables() {
157 let mut ka = SigmaKernelAssist::new();
158 ka.seed_root_gas(1000);
159 ka.seed_root_quota(2000);
160 ka.reset_block_state();
161 assert_eq!(ka.gas_meter_get(0), 0);
162 assert_eq!(ka.storage_quota_get(0), 0);
163 }
164
165 #[test]
166 fn yield_catcher_round_trip() {
167 let mut ka = SigmaKernelAssist::new();
168 let yc = ka.yield_catcher_new();
169 let marker = [0xAA; 32];
170 ka.yield_catcher_add(yc, marker);
171 assert_eq!(ka.yield_catcher_markers(yc), vec![marker]);
172 ka.yield_catcher_remove(yc, marker);
173 assert!(ka.yield_catcher_markers(yc).is_empty());
174 }
175}