sim/runtime/reference_device/
route.rs1use sim_kernel::{Error, EventKind, EventLedger, Expr, Ref, Result, Symbol};
2use sim_value::build;
3
4use super::{reference_edge_id, reference_glance_profile, reference_pose_receipt};
5
6#[derive(Clone, Debug, PartialEq, Eq)]
8pub struct RouteSwapProof {
9 pub same_session_id: bool,
11 pub same_ledger: bool,
13 pub consent_survived: bool,
15 pub events_advanced: bool,
17 pub peer_surface_registered: bool,
19}
20
21impl RouteSwapProof {
22 pub fn to_expr(&self) -> Expr {
24 build::map(vec![
25 ("kind", build::qsym("device/reference", "route-swap-proof")),
26 ("same-session-id", Expr::Bool(self.same_session_id)),
27 ("same-ledger", Expr::Bool(self.same_ledger)),
28 ("consent-survived", Expr::Bool(self.consent_survived)),
29 ("events-advanced", Expr::Bool(self.events_advanced)),
30 (
31 "peer-surface-registered",
32 Expr::Bool(self.peer_surface_registered),
33 ),
34 ])
35 }
36}
37
38pub fn prove_route_swap() -> Result<RouteSwapProof> {
40 let edge = reference_edge_id();
41 let id = edge.as_symbol().clone();
42 let receipt = reference_pose_receipt(9, 100);
43 let consent_expr = receipt.to_expr();
44 let mut session = ReferenceRouteSession::new(id.clone(), reference_link_symbol("direct"))?;
45 session.bind_consent(consent_expr.clone())?;
46 let ledger = session.ledger.clone();
47 let events_before = session.events.len_for_run(&ledger);
48
49 let mut hub = sim_lib_web_bridge::SurfaceHub::new();
50 let peer =
51 sim_lib_web_bridge::register_device_peer(&mut hub, &edge, &reference_glance_profile());
52
53 session.rebind(reference_link_symbol("relay"))?;
54
55 Ok(RouteSwapProof {
56 same_session_id: session.id == id,
57 same_ledger: session.ledger == ledger,
58 consent_survived: session.consent.as_ref() == Some(&consent_expr),
59 events_advanced: session.events.len_for_run(&ledger) == events_before + 1,
60 peer_surface_registered: peer.namespace.as_deref() == Some("device/peer"),
61 })
62}
63
64#[derive(Clone, Debug)]
65struct ReferenceRouteSession {
66 id: Symbol,
67 link: Symbol,
68 ledger: Ref,
69 events: EventLedger,
70 consent: Option<Expr>,
71}
72
73impl ReferenceRouteSession {
74 fn new(id: Symbol, link: Symbol) -> Result<Self> {
75 let ledger = Ref::Symbol(id.clone());
76 let mut session = Self {
77 id,
78 link,
79 ledger,
80 events: EventLedger::new(),
81 consent: None,
82 };
83 session.record_event("open")?;
84 Ok(session)
85 }
86
87 fn bind_consent(&mut self, consent: Expr) -> Result<()> {
88 match sim_value::access::field_sym(&consent, "session") {
89 Some(session) if session == self.id => {}
90 Some(session) => {
91 return Err(Error::HostError(format!(
92 "consent session '{session}' does not match device edge session '{}'",
93 self.id
94 )));
95 }
96 None => {
97 return Err(Error::HostError(
98 "device edge consent is missing session".to_owned(),
99 ));
100 }
101 }
102 self.consent = Some(consent);
103 self.record_event("consent-bound")
104 }
105
106 fn rebind(&mut self, link: Symbol) -> Result<()> {
107 self.link = link;
108 self.record_event("rebind")
109 }
110
111 fn record_event(&mut self, name: &str) -> Result<()> {
112 self.events.push(
113 self.ledger.clone(),
114 EventKind::Trace(Ref::Symbol(Symbol::qualified("device/edge", name))),
115 )?;
116 Ok(())
117 }
118}
119
120fn reference_link_symbol(name: &str) -> Symbol {
121 Symbol::qualified("device/link", name.to_owned())
122}