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 bincode::serialize(program).expect("program serialization for cache key should succeed")
50 }
51
52 pub fn reserve(&mut self, additional: usize) {
54 self.programs.reserve(additional);
55 }
56
57 pub fn intern(&mut self, program: Vec<Instr>) -> usize {
59 self.ensure_cache_initialized();
60 let key = Self::cache_key(&program);
61 if let Some(existing) = self.cache.get(&key) {
62 return *existing;
63 }
64 let program_id = self.programs.len();
65 self.programs.push(program.into_boxed_slice());
66 self.cache.insert(key, program_id);
67 program_id
68 }
69
70 #[must_use]
72 pub fn get(&self, program_id: usize) -> Option<&Program> {
73 self.programs.get(program_id)
74 }
75
76 #[must_use]
78 pub fn len(&self) -> usize {
79 self.programs.len()
80 }
81
82 #[must_use]
84 pub fn is_empty(&self) -> bool {
85 self.programs.is_empty()
86 }
87
88 #[must_use]
90 pub fn instruction_count(&self) -> usize {
91 self.programs.iter().map(|program| program.len()).sum()
92 }
93
94 #[cfg(test)]
95 fn replace_for_test(&mut self, program_id: usize, program: Vec<Instr>) {
96 self.ensure_cache_initialized();
97 if let Some(existing) = self.programs.get(program_id) {
98 let key = Self::cache_key(existing);
99 self.cache.remove(&key);
100 }
101 self.programs[program_id] = program.into_boxed_slice();
102 let new_key = Self::cache_key(&self.programs[program_id]);
103 self.cache.insert(new_key, program_id);
104 }
105}
106
107type BranchList = Vec<(
109 telltale_types::Label,
110 Option<telltale_types::ValType>,
111 LocalTypeR,
112)>;
113
114pub(crate) fn runtime_value_val_type(value: &Value) -> ValType {
116 match value {
117 Value::Unit => ValType::Unit,
118 Value::Nat(_) => ValType::Nat,
119 Value::Bool(_) => ValType::Bool,
120 Value::Str(_) => ValType::String,
121 Value::Prod(left, right) => ValType::Prod(
122 Box::new(runtime_value_val_type(left)),
123 Box::new(runtime_value_val_type(right)),
124 ),
125 Value::Endpoint(endpoint) => ValType::Chan {
126 sid: endpoint.sid,
127 role: endpoint.role.clone(),
128 },
129 }
130}
131
132pub(crate) fn runtime_value_wire_size_bytes(value: &Value) -> usize {
134 match value {
135 Value::Unit => 1,
136 Value::Nat(_) => 8,
137 Value::Bool(_) => 1,
138 Value::Str(text) => 8_usize.saturating_add(text.len()),
139 Value::Prod(left, right) => 1_usize
140 .saturating_add(runtime_value_wire_size_bytes(left))
141 .saturating_add(runtime_value_wire_size_bytes(right)),
142 Value::Endpoint(endpoint) => 8_usize
143 .saturating_add(8_usize)
144 .saturating_add(endpoint.role.len()),
145 }
146}
147
148pub(crate) fn runtime_value_matches_val_type(value: &Value, expected: &ValType) -> bool {
150 match (value, expected) {
151 (Value::Unit, ValType::Unit) => true,
152 (Value::Nat(_), ValType::Nat) => true,
153 (Value::Bool(_), ValType::Bool) => true,
154 (Value::Str(_), ValType::String) => true,
155 (Value::Prod(left, right), ValType::Prod(expected_left, expected_right)) => {
156 runtime_value_matches_val_type(left, expected_left)
157 && runtime_value_matches_val_type(right, expected_right)
158 }
159 (Value::Endpoint(endpoint), ValType::Chan { sid, role }) => {
160 endpoint.sid == *sid && endpoint.role == *role
161 }
162 _ => false,
163 }
164}
165
166#[derive(Debug, Clone, Serialize, Deserialize, Default)]
168pub struct ResourceState {
169 commitments: BTreeSet<crate::verification::Commitment>,
170 nullifiers: BTreeSet<crate::verification::Nullifier>,
171}
172
173impl ResourceState {
174 #[must_use]
176 pub fn commit(&mut self, value: &Value) -> crate::verification::Commitment {
177 let commitment = crate::verification::DefaultVerificationModel::commitment(value);
178 self.commitments.insert(commitment);
179 commitment
180 }
181
182 pub fn consume(&mut self, value: &Value) -> Result<crate::verification::Nullifier, String> {
188 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
189 if self.nullifiers.contains(&nullifier) {
190 return Err("resource already consumed".to_string());
191 }
192 self.nullifiers.insert(nullifier);
193 Ok(nullifier)
194 }
195
196 #[must_use]
198 pub fn verify_uncommitted(&self, value: &Value) -> bool {
199 let nullifier = crate::verification::DefaultVerificationModel::nullifier(value);
200 !self.nullifiers.contains(&nullifier)
201 }
202}