1#[derive(Debug, Serialize)]
6pub struct SessionState {
7 pub sid: SessionId,
9 pub roles: Vec<String>,
11 #[serde(skip)]
13 role_ids: BTreeMap<String, u16>,
14 pub local_types: BTreeMap<Endpoint, TypeEntry>,
18 pub buffers: BTreeMap<Edge, SignedBuffer<Signature>>,
20 #[serde(skip)]
22 edge_lookup: BTreeMap<(u16, u16), Edge>,
23 #[serde(skip)]
25 handler_ids: BTreeMap<HandlerId, HandlerNumericId>,
26 #[serde(skip)]
28 handlers_by_id: Vec<HandlerId>,
29 #[serde(skip)]
31 edge_handler_lookup: BTreeMap<(u16, u16), HandlerNumericId>,
32 #[serde(skip)]
34 default_handler_id: Option<HandlerNumericId>,
35 #[serde(skip)]
37 label_ids: BTreeMap<String, LabelNumericId>,
38 #[serde(skip)]
40 labels_by_id: Vec<String>,
41 #[serde(skip)]
43 branch_lookup: BTreeMap<Endpoint, BTreeMap<LabelNumericId, CachedBranch>>,
44 pub auth_leaves: BTreeMap<Edge, Vec<Hash>>,
46 #[serde(default)]
48 pub auth_trees: BTreeMap<Edge, AuthTree>,
49 pub auth_roots: BTreeMap<Edge, Hash>,
51 pub edge_handlers: BTreeMap<Edge, HandlerId>,
53 #[serde(default = "default_handler_id")]
55 pub default_handler: HandlerId,
56 pub edge_traces: BTreeMap<Edge, Vec<ValType>>,
58 pub status: SessionStatus,
60 pub epoch: usize,
62}
63
64impl SessionState {
65 pub(crate) fn from_open_plan(
66 sid: SessionId,
67 plan: &SessionOpenPlan,
68 buffer_config: &BufferConfig,
69 ) -> Self {
70 let mut local_type_entries = Vec::with_capacity(plan.initial_types.len());
71 for (role, current, original) in &plan.initial_types {
72 local_type_entries.push((
73 Endpoint {
74 sid,
75 role: role.clone(),
76 },
77 TypeEntry {
78 current: current.clone(),
79 original: original.clone(),
80 },
81 ));
82 }
83 let local_types = local_type_entries.into_iter().collect();
84
85 let mut edge_entries = Vec::with_capacity(plan.edge_blueprint().len());
86 let mut buffer_entries = Vec::with_capacity(plan.edge_blueprint().len());
87 for (key, from, to) in plan.edge_blueprint() {
88 let edge = Edge::new(sid, from.clone(), to.clone());
89 edge_entries.push((*key, edge.clone()));
90 buffer_entries.push((edge, BoundedBuffer::new(buffer_config)));
91 }
92 let edge_lookup = edge_entries.into_iter().collect();
93 let buffers = buffer_entries.into_iter().collect();
94
95 let default_handler = default_handler_id();
96 let (handler_ids, handlers_by_id, edge_handler_lookup, default_handler_id) =
97 Self::build_handler_indexes(&plan.role_ids, &default_handler, &BTreeMap::new());
98
99 let mut state = Self {
100 sid,
101 roles: plan.roles.clone(),
102 role_ids: plan.role_ids.clone(),
103 local_types,
104 buffers,
105 edge_lookup,
106 handler_ids,
107 handlers_by_id,
108 edge_handler_lookup,
109 default_handler_id,
110 label_ids: BTreeMap::new(),
111 labels_by_id: Vec::new(),
112 branch_lookup: BTreeMap::new(),
113 auth_leaves: BTreeMap::new(),
114 auth_trees: BTreeMap::new(),
115 auth_roots: BTreeMap::new(),
116 edge_handlers: BTreeMap::new(),
117 default_handler,
118 edge_traces: BTreeMap::new(),
119 status: SessionStatus::Active,
120 epoch: 0,
121 };
122 for role in &plan.active_branch_roles {
123 state.refresh_endpoint_branch_lookup(&Endpoint {
124 sid,
125 role: role.clone(),
126 });
127 }
128 state
129 }
130
131 fn retained_session_core_bytes(&self) -> usize {
132 std::mem::size_of::<Self>()
133 .saturating_add(serialized_bytes(&self.sid))
134 .saturating_add(serialized_bytes(&self.roles))
135 .saturating_add(serialized_bytes(&self.role_ids))
136 .saturating_add(serialized_bytes(&self.edge_lookup))
137 .saturating_add(serialized_bytes(&self.handler_ids))
138 .saturating_add(serialized_bytes(&self.handlers_by_id))
139 .saturating_add(serialized_bytes(&self.edge_handler_lookup))
140 .saturating_add(serialized_bytes(&self.default_handler_id))
141 .saturating_add(serialized_bytes(&self.label_ids))
142 .saturating_add(serialized_bytes(&self.labels_by_id))
143 .saturating_add(serialized_bytes(&self.branch_lookup))
144 .saturating_add(serialized_bytes(&self.status))
145 .saturating_add(serialized_bytes(&self.epoch))
146 }
147
148 fn retained_local_type_bytes(&self) -> usize {
149 serialized_bytes(&self.local_types)
150 }
151
152 fn retained_buffer_bytes(&self) -> usize {
153 serialized_bytes(&self.buffers)
154 }
155
156 fn retained_trace_bytes(&self) -> usize {
157 serialized_bytes(&self.edge_traces)
158 }
159
160 fn retained_auth_bytes(&self) -> usize {
161 serialized_bytes(&self.auth_leaves)
162 .saturating_add(serialized_bytes(&self.auth_trees))
163 .saturating_add(serialized_bytes(&self.auth_roots))
164 }
165
166 fn retained_handler_bytes(&self) -> usize {
167 serialized_bytes(&self.edge_handlers)
168 .saturating_add(serialized_bytes(&self.default_handler))
169 }
170
171 fn rebuild_derived_indexes(&mut self) {
172 self.role_ids = Self::build_role_ids(&self.roles);
173 self.edge_lookup = Self::build_edge_lookup_from_buffers(&self.role_ids, &self.buffers);
174 self.refresh_handler_indexes();
175 self.label_ids = BTreeMap::new();
176 self.labels_by_id = Vec::new();
177 self.branch_lookup = BTreeMap::new();
178 let endpoints: Vec<Endpoint> = self.local_types.keys().cloned().collect();
179 for endpoint in endpoints {
180 self.refresh_endpoint_branch_lookup(&endpoint);
181 }
182 }
183
184 pub(crate) fn refresh_handler_indexes(&mut self) {
185 let (handler_ids, handlers_by_id, edge_handler_lookup, default_handler_id) =
186 Self::build_handler_indexes(&self.role_ids, &self.default_handler, &self.edge_handlers);
187 self.handler_ids = handler_ids;
188 self.handlers_by_id = handlers_by_id;
189 self.edge_handler_lookup = edge_handler_lookup;
190 self.default_handler_id = default_handler_id;
191 }
192
193 pub(crate) fn build_role_ids(roles: &[String]) -> BTreeMap<String, u16> {
194 roles
195 .iter()
196 .enumerate()
197 .map(|(idx, role)| {
198 (
199 role.clone(),
200 u16::try_from(idx).expect("role count should fit in u16"),
201 )
202 })
203 .collect()
204 }
205
206 pub(crate) fn build_edge_lookup_from_buffers(
207 role_ids: &BTreeMap<String, u16>,
208 buffers: &BTreeMap<Edge, SignedBuffer<Signature>>,
209 ) -> BTreeMap<EdgeKey, Edge> {
210 let mut lookup = BTreeMap::new();
211 for edge in buffers.keys() {
212 let Some(from_id) = role_ids.get(&edge.sender) else {
213 continue;
214 };
215 let Some(to_id) = role_ids.get(&edge.receiver) else {
216 continue;
217 };
218 lookup.insert((*from_id, *to_id), edge.clone());
219 }
220 lookup
221 }
222
223 pub(crate) fn build_handler_indexes(
224 role_ids: &BTreeMap<String, u16>,
225 default_handler: &str,
226 edge_handlers: &BTreeMap<Edge, HandlerId>,
227 ) -> HandlerIndexBuild {
228 let mut handler_ids = BTreeMap::new();
229 let mut handlers_by_id = Vec::new();
230 let intern_handler = |handler: &str,
231 handler_ids: &mut BTreeMap<HandlerId, HandlerNumericId>,
232 handlers_by_id: &mut Vec<HandlerId>|
233 -> HandlerNumericId {
234 if let Some(id) = handler_ids.get(handler) {
235 return *id;
236 }
237 let id = u16::try_from(handlers_by_id.len()).expect("handler count should fit in u16");
238 let owned = handler.to_string();
239 handler_ids.insert(owned.clone(), id);
240 handlers_by_id.push(owned);
241 id
242 };
243
244 let default_handler_id = (!default_handler.is_empty())
245 .then(|| intern_handler(default_handler, &mut handler_ids, &mut handlers_by_id));
246
247 let mut edge_handler_lookup = BTreeMap::new();
248 for (edge, handler) in edge_handlers {
249 let Some(from_id) = role_ids.get(&edge.sender) else {
250 continue;
251 };
252 let Some(to_id) = role_ids.get(&edge.receiver) else {
253 continue;
254 };
255 let handler_id = intern_handler(handler, &mut handler_ids, &mut handlers_by_id);
256 edge_handler_lookup.insert((*from_id, *to_id), handler_id);
257 }
258
259 (
260 handler_ids,
261 handlers_by_id,
262 edge_handler_lookup,
263 default_handler_id,
264 )
265 }
266
267 fn edge_for_roles(&self, from: &str, to: &str) -> Option<&Edge> {
268 let from_id = self.role_ids.get(from)?;
269 let to_id = self.role_ids.get(to)?;
270 self.edge_lookup.get(&(*from_id, *to_id))
271 }
272
273 fn edge_key_for_roles(&self, from: &str, to: &str) -> Option<(u16, u16)> {
274 let from_id = self.role_ids.get(from)?;
275 let to_id = self.role_ids.get(to)?;
276 Some((*from_id, *to_id))
277 }
278
279 fn intern_label(&mut self, label: &str) -> LabelNumericId {
280 if let Some(id) = self.label_ids.get(label) {
281 return *id;
282 }
283 let id = u16::try_from(self.labels_by_id.len()).expect("label count should fit in u16");
284 let owned = label.to_string();
285 self.label_ids.insert(owned.clone(), id);
286 self.labels_by_id.push(owned);
287 id
288 }
289
290 fn intern_handler_binding(&mut self, handler: &str) -> HandlerNumericId {
291 if let Some(id) = self.handler_ids.get(handler) {
292 return *id;
293 }
294 let id = u16::try_from(self.handlers_by_id.len()).expect("handler count should fit in u16");
295 let owned = handler.to_string();
296 self.handler_ids.insert(owned.clone(), id);
297 self.handlers_by_id.push(owned);
298 id
299 }
300
301 fn handler_by_id(&self, handler_id: HandlerNumericId) -> Option<&HandlerId> {
302 self.handlers_by_id.get(usize::from(handler_id))
303 }
304
305 fn branch_shape(local_type: &LocalTypeR) -> Option<(BranchDirection, &str, LocalBranches<'_>)> {
306 match local_type {
307 LocalTypeR::Send { partner, branches } => {
308 Some((BranchDirection::Send, partner.as_str(), branches.as_slice()))
309 }
310 LocalTypeR::Recv { partner, branches } => {
311 Some((BranchDirection::Recv, partner.as_str(), branches.as_slice()))
312 }
313 _ => None,
314 }
315 }
316
317 pub(crate) fn refresh_endpoint_branch_lookup(&mut self, ep: &Endpoint) {
318 self.branch_lookup.remove(ep);
319 let Some(entry) = self.local_types.get(ep) else {
320 return;
321 };
322 let Some((direction, partner, branches)) = Self::branch_shape(&entry.current) else {
323 return;
324 };
325 let partner = partner.to_string();
326 let branches: Vec<(String, Option<ValType>, LocalTypeR)> = branches
327 .iter()
328 .map(|(label, expected_type, continuation)| {
329 (
330 label.name.clone(),
331 expected_type.clone(),
332 continuation.clone(),
333 )
334 })
335 .collect();
336
337 let mut endpoint_lookup = BTreeMap::new();
338 for (label, expected_type, continuation) in branches {
339 let label_id = self.intern_label(&label);
340 endpoint_lookup.insert(
341 label_id,
342 CachedBranch {
343 direction,
344 partner: partner.clone(),
345 expected_type,
346 continuation,
347 },
348 );
349 }
350 if !endpoint_lookup.is_empty() {
351 self.branch_lookup.insert(ep.clone(), endpoint_lookup);
352 }
353 }
354
355 #[must_use]
357 pub(crate) fn lookup_branch_resolution(
358 &self,
359 ep: &Endpoint,
360 label: &str,
361 ) -> Option<&CachedBranch> {
362 let label_id = self.label_ids.get(label)?;
363 self.branch_lookup.get(ep)?.get(label_id)
364 }
365
366 fn update_auth_tree(&mut self, edge: &Edge, signed: &SignedValue<Signature>) {
367 let bytes = bincode::serialize(signed).unwrap_or_default();
368 let leaf = DefaultVerificationModel::hash(HashTag::MerkleLeaf, &bytes);
369 self.auth_leaves.entry(edge.clone()).or_default().push(leaf);
370 let tree = self
371 .auth_trees
372 .entry(edge.clone())
373 .or_insert_with(|| AuthTree::new(Vec::new()));
374 tree.append_leaf(leaf);
375 self.auth_roots.insert(edge.clone(), tree.root());
376 }
377
378 pub fn send_signed(
384 &mut self,
385 from: &str,
386 to: &str,
387 signed: &SignedValue<Signature>,
388 ) -> Result<crate::buffer::EnqueueResult, String> {
389 let edge = self
390 .edge_for_roles(from, to)
391 .cloned()
392 .ok_or_else(|| format!("no buffer for edge {from} → {to}"))?;
393 let buf = self
394 .buffers
395 .get_mut(&edge)
396 .ok_or_else(|| format!("no buffer for edge {from} → {to}"))?;
397 let result = buf.enqueue(signed.clone());
398 if matches!(result, crate::buffer::EnqueueResult::Ok) {
399 self.update_auth_tree(&edge, signed);
400 }
401 Ok(result)
402 }
403
404 pub fn send(
412 &mut self,
413 from: &str,
414 to: &str,
415 val: Value,
416 ) -> Result<crate::buffer::EnqueueResult, String> {
417 let signer = signing_key_for_endpoint(&Endpoint {
418 sid: self.sid,
419 role: from.to_string(),
420 });
421 let signature = signValue(&val, &signer);
422 self.send_signed(
423 from,
424 to,
425 &SignedValue {
426 payload: val,
427 signature,
428 sequence_no: 0,
429 },
430 )
431 }
432
433 pub fn send_with_sequence(
439 &mut self,
440 from: &str,
441 to: &str,
442 val: Value,
443 sequence_no: u64,
444 ) -> Result<crate::buffer::EnqueueResult, String> {
445 let signer = signing_key_for_endpoint(&Endpoint {
446 sid: self.sid,
447 role: from.to_string(),
448 });
449 let signature = signValue(&val, &signer);
450 self.send_signed(
451 from,
452 to,
453 &SignedValue {
454 payload: val,
455 signature,
456 sequence_no,
457 },
458 )
459 }
460
461 pub fn recv_signed(&mut self, from: &str, to: &str) -> Option<SignedValue<Signature>> {
463 let edge = self.edge_for_roles(from, to)?.clone();
464 self.buffers.get_mut(&edge).and_then(|buf| buf.dequeue())
465 }
466
467 pub fn recv_verified_signed(
473 &mut self,
474 from: &str,
475 to: &str,
476 ) -> Result<Option<SignedValue<Signature>>, String> {
477 let sender = Endpoint {
478 sid: self.sid,
479 role: from.to_string(),
480 };
481 let verifying = verifying_key_for_endpoint(&sender);
482 let signed = self.recv_signed(from, to);
483 let Some(signed) = signed else {
484 return Ok(None);
485 };
486 if !verifySignedValue(&signed.payload, &signed.signature, &verifying) {
487 return Err(format!(
488 "signature verification failed on edge {from} -> {to}"
489 ));
490 }
491 Ok(Some(signed))
492 }
493
494 pub fn recv_verified(&mut self, from: &str, to: &str) -> Result<Option<Value>, String> {
500 Ok(self
501 .recv_verified_signed(from, to)?
502 .map(|signed| signed.payload))
503 }
504
505 pub fn recv(&mut self, from: &str, to: &str) -> Option<Value> {
507 self.recv_verified(from, to).ok().flatten()
508 }
509
510 #[must_use]
512 pub fn has_message(&self, from: &str, to: &str) -> bool {
513 let Some(edge) = self.edge_for_roles(from, to) else {
514 return false;
515 };
516 self.buffers.get(edge).is_some_and(|buf| !buf.is_empty())
517 }
518
519 #[must_use]
521 pub fn lookup_handler_for_roles(&self, from: &str, to: &str) -> Option<&HandlerId> {
522 if self.edge_handlers.is_empty() {
523 return None;
524 }
525 let edge_key = self.edge_key_for_roles(from, to)?;
526 let handler_id = self.edge_handler_lookup.get(&edge_key)?;
527 self.handler_by_id(*handler_id)
528 }
529
530 #[must_use]
532 pub fn default_handler_binding(&self) -> Option<&HandlerId> {
533 if self.default_handler.is_empty() {
534 return None;
535 }
536 let handler_id = self.default_handler_id?;
537 self.handler_by_id(handler_id)
538 }
539
540 #[must_use]
542 pub fn has_bound_handler(&self) -> bool {
543 !self.default_handler.is_empty() || !self.edge_handlers.is_empty()
544 }
545}
546
547#[derive(Debug, Deserialize)]
548struct SessionStateSerde {
549 sid: SessionId,
550 roles: Vec<String>,
551 local_types: BTreeMap<Endpoint, TypeEntry>,
552 buffers: BTreeMap<Edge, SignedBuffer<Signature>>,
553 auth_leaves: BTreeMap<Edge, Vec<Hash>>,
554 #[serde(default)]
555 auth_trees: BTreeMap<Edge, AuthTree>,
556 auth_roots: BTreeMap<Edge, Hash>,
557 edge_handlers: BTreeMap<Edge, HandlerId>,
558 #[serde(default = "default_handler_id")]
559 default_handler: HandlerId,
560 edge_traces: BTreeMap<Edge, Vec<ValType>>,
561 status: SessionStatus,
562 epoch: usize,
563}