telltale_vm/vm/runtime_state/
program_store.rs1fn default_instruction_cost() -> usize {
2 1
3}
4
5fn default_initial_cost_budget() -> usize {
6 usize::MAX
7}
8
9fn default_config_schema_version() -> u32 {
10 1
11}
12
13fn default_max_payload_bytes() -> usize {
14 64 * 1024
15}
16
17pub type ScopeId = usize;
19
20pub type Program = Box<[Instr]>;
22
23#[derive(Debug, Clone, Default, Serialize, Deserialize)]
25pub struct ProgramStore {
26 programs: Vec<Program>,
27 #[serde(default)]
28 cache: BTreeMap<Vec<u8>, usize>,
29}
30
31impl ProgramStore {
32 #[must_use]
34 pub fn new() -> Self {
35 Self::default()
36 }
37
38 fn ensure_cache_initialized(&mut self) {
39 if self.cache.len() == self.programs.len() {
40 return;
41 }
42 self.cache.clear();
43 for (idx, program) in self.programs.iter().enumerate() {
44 self.cache.insert(Self::cache_key(program), idx);
45 }
46 }
47
48 fn cache_key(program: &[Instr]) -> Vec<u8> {
49 crate::serialization::binary_encode(program)
50 .expect("program serialization for cache key should succeed")
51 }
52
53 pub fn reserve(&mut self, additional: usize) {
55 self.programs.reserve(additional);
56 }
57
58 pub fn intern(&mut self, program: Vec<Instr>) -> usize {
60 self.ensure_cache_initialized();
61 let key = Self::cache_key(&program);
62 if let Some(existing) = self.cache.get(&key) {
63 return *existing;
64 }
65 let program_id = self.programs.len();
66 self.programs.push(program.into_boxed_slice());
67 self.cache.insert(key, program_id);
68 program_id
69 }
70
71 #[must_use]
73 pub fn get(&self, program_id: usize) -> Option<&Program> {
74 self.programs.get(program_id)
75 }
76
77 #[must_use]
79 pub fn len(&self) -> usize {
80 self.programs.len()
81 }
82
83 #[must_use]
85 pub fn is_empty(&self) -> bool {
86 self.programs.is_empty()
87 }
88
89 #[must_use]
91 pub fn instruction_count(&self) -> usize {
92 self.programs.iter().map(|program| program.len()).sum()
93 }
94
95 #[cfg(test)]
96 fn replace_for_test(&mut self, program_id: usize, program: Vec<Instr>) {
97 self.ensure_cache_initialized();
98 if let Some(existing) = self.programs.get(program_id) {
99 let key = Self::cache_key(existing);
100 self.cache.remove(&key);
101 }
102 self.programs[program_id] = program.into_boxed_slice();
103 let new_key = Self::cache_key(&self.programs[program_id]);
104 self.cache.insert(new_key, program_id);
105 }
106}
107
108type BranchList = Vec<(
110 telltale_types::Label,
111 Option<telltale_types::ValType>,
112 LocalTypeR,
113)>;
114
115pub(crate) fn runtime_value_val_type(value: &Value) -> ValType {
117 match value {
118 Value::Unit => ValType::Unit,
119 Value::Nat(_) => ValType::Nat,
120 Value::Bool(_) => ValType::Bool,
121 Value::Str(_) => ValType::String,
122 Value::Prod(left, right) => ValType::Prod(
123 Box::new(runtime_value_val_type(left)),
124 Box::new(runtime_value_val_type(right)),
125 ),
126 Value::Endpoint(endpoint) => ValType::Chan {
127 sid: endpoint.sid,
128 role: endpoint.role.clone(),
129 },
130 }
131}
132
133pub(crate) fn runtime_value_wire_size_bytes(value: &Value) -> usize {
135 match value {
136 Value::Unit => 1,
137 Value::Nat(_) => 8,
138 Value::Bool(_) => 1,
139 Value::Str(text) => 8_usize.saturating_add(text.len()),
140 Value::Prod(left, right) => 1_usize
141 .saturating_add(runtime_value_wire_size_bytes(left))
142 .saturating_add(runtime_value_wire_size_bytes(right)),
143 Value::Endpoint(endpoint) => 8_usize
144 .saturating_add(8_usize)
145 .saturating_add(endpoint.role.len()),
146 }
147}
148
149pub(crate) fn runtime_value_matches_val_type(value: &Value, expected: &ValType) -> bool {
151 match (value, expected) {
152 (Value::Unit, ValType::Unit) => true,
153 (Value::Nat(_), ValType::Nat) => true,
154 (Value::Bool(_), ValType::Bool) => true,
155 (Value::Str(_), ValType::String) => true,
156 (Value::Prod(left, right), ValType::Prod(expected_left, expected_right)) => {
157 runtime_value_matches_val_type(left, expected_left)
158 && runtime_value_matches_val_type(right, expected_right)
159 }
160 (Value::Endpoint(endpoint), ValType::Chan { sid, role }) => {
161 endpoint.sid == *sid && endpoint.role == *role
162 }
163 _ => false,
164 }
165}
166
167#[derive(Debug, Clone, Serialize, Deserialize, Default)]
169pub struct ResourceState {
170 commitments: BTreeSet<crate::verification::Commitment>,
171 nullifiers: BTreeSet<crate::verification::Nullifier>,
172}
173
174impl ResourceState {
175 #[must_use]
177 pub fn commit(&mut self, value: &Value) -> crate::verification::Commitment {
178 let commitment = crate::verification::DefaultVerificationModel::commitment(value);
179 self.commitments.insert(commitment);
180 commitment
181 }
182
183 pub fn consume(&mut self, value: &Value) -> Result<crate::verification::Nullifier, String> {
189 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
190 if self.nullifiers.contains(&nullifier) {
191 return Err("resource already consumed".to_string());
192 }
193 self.nullifiers.insert(nullifier);
194 Ok(nullifier)
195 }
196
197 #[must_use]
199 pub fn verify_uncommitted(&self, value: &Value) -> bool {
200 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
201 !self.nullifiers.contains(&nullifier)
202 }
203}