1use std::collections::BTreeMap;
4use std::sync::Arc;
5
6use async_trait::async_trait;
7use aura_core::effects::{AdmissionError, CapabilityKey, RuntimeCapabilityEffects};
8
9#[cfg(feature = "telltale-runtime-capability")]
10use telltale_machine::capabilities::protocol_critical_capability_boundary;
11
12#[cfg(not(feature = "telltale-runtime-capability"))]
13const PROTOCOL_SURFACE_RUNTIME_ADMISSION: &str = "runtime_admission";
14#[cfg(not(feature = "telltale-runtime-capability"))]
15const PROTOCOL_SURFACE_THEOREM_PACK_CAPABILITIES: &str = "theorem_pack_capabilities";
16#[cfg(any(test, not(feature = "telltale-runtime-capability")))]
17const PROTOCOL_SURFACE_OWNERSHIP_CAPABILITY: &str = "ownership_capability";
18#[cfg(not(feature = "telltale-runtime-capability"))]
19const PROTOCOL_SURFACE_READINESS_WITNESS: &str = "readiness_witness";
20#[cfg(not(feature = "telltale-runtime-capability"))]
21const PROTOCOL_SURFACE_AUTHORITATIVE_READ: &str = "authoritative_read";
22#[cfg(not(feature = "telltale-runtime-capability"))]
23const PROTOCOL_SURFACE_MATERIALIZATION_PROOF: &str = "materialization_proof";
24#[cfg(not(feature = "telltale-runtime-capability"))]
25const PROTOCOL_SURFACE_CANONICAL_HANDLE: &str = "canonical_handle";
26const PROTOCOL_SURFACE_OWNERSHIP_RECEIPT: &str = "ownership_receipt";
27const PROTOCOL_SURFACE_SEMANTIC_HANDOFF: &str = "semantic_handoff";
28const PROTOCOL_SURFACE_RECONFIGURATION_TRANSITION: &str = "reconfiguration_transition";
29
30#[derive(Debug, Clone, Default)]
32pub struct RuntimeCapabilityHandler {
33 inventory: Arc<BTreeMap<CapabilityKey, bool>>,
34 protocol_critical_surfaces: Arc<BTreeMap<String, bool>>,
35}
36
37impl RuntimeCapabilityHandler {
38 pub fn new(snapshot: Vec<(CapabilityKey, bool)>) -> Self {
40 let mut inventory = snapshot.into_iter().collect::<BTreeMap<_, _>>();
41 let protocol_critical_surfaces =
42 protocol_surface_inventory_from_aura_capabilities(&inventory);
43 merge_protocol_surfaces_into_inventory(&mut inventory, &protocol_critical_surfaces);
44 Self {
45 inventory: Arc::new(inventory),
46 protocol_critical_surfaces: Arc::new(protocol_critical_surfaces),
47 }
48 }
49
50 pub fn from_pairs(
52 snapshot: impl IntoIterator<Item = (impl Into<CapabilityKey>, bool)>,
53 ) -> Self {
54 let mut inventory = snapshot
55 .into_iter()
56 .map(|(key, admitted)| (key.into(), admitted))
57 .collect::<BTreeMap<_, _>>();
58 let protocol_critical_surfaces =
59 protocol_surface_inventory_from_aura_capabilities(&inventory);
60 merge_protocol_surfaces_into_inventory(&mut inventory, &protocol_critical_surfaces);
61 Self {
62 protocol_critical_surfaces: Arc::new(protocol_critical_surfaces),
63 inventory: Arc::new(inventory),
64 }
65 }
66
67 pub fn len(&self) -> usize {
69 self.inventory.len()
70 }
71
72 pub fn is_empty(&self) -> bool {
74 self.inventory.is_empty()
75 }
76
77 pub fn protocol_critical_surface_admitted(&self, surface: &str) -> bool {
79 self.protocol_critical_surfaces
80 .get(surface)
81 .copied()
82 .unwrap_or(false)
83 }
84
85 pub fn require_protocol_critical_surfaces(
87 &self,
88 required: &[&str],
89 ) -> Result<(), AdmissionError> {
90 for surface in required {
91 if !self.protocol_critical_surface_admitted(surface) {
92 return Err(AdmissionError::MissingCapability {
93 capability: CapabilityKey::new(*surface),
94 });
95 }
96 }
97 Ok(())
98 }
99}
100
101#[cfg(feature = "telltale-runtime-capability")]
102impl RuntimeCapabilityHandler {
103 pub fn from_protocol_machine_runtime_contracts(
105 contracts: &telltale_machine::runtime_contracts::RuntimeContracts,
106 ) -> Self {
107 let mut inventory =
108 telltale_machine::runtime_contracts::runtime_capability_snapshot(contracts)
109 .into_iter()
110 .map(|(key, admitted)| (CapabilityKey::new(key), admitted))
111 .collect::<BTreeMap<_, _>>();
112 for (key, admitted) in &contracts.execution_profile.theorem_pack_eligibility {
113 inventory.insert(CapabilityKey::new(key.as_str()), *admitted);
114 }
115 let reconfiguration_enabled = contracts
116 .capabilities
117 .contains(&telltale_machine::runtime_contracts::RuntimeCapability::LiveMigration)
118 && contracts.capabilities.contains(
119 &telltale_machine::runtime_contracts::RuntimeCapability::PlacementRefinement,
120 );
121 let protocol_critical_surfaces =
122 protocol_surface_inventory_from_runtime_contracts(contracts);
123
124 inventory.insert(
125 CapabilityKey::new("byzantine_envelope"),
126 contracts.determinism_artifacts.full,
127 );
128 inventory.insert(
129 CapabilityKey::new("termination_bounded"),
130 contracts.determinism_artifacts.replay || contracts.determinism_artifacts.full,
131 );
132 inventory.insert(
133 CapabilityKey::new("reconfiguration"),
134 contracts
135 .capabilities
136 .contains(&telltale_machine::runtime_contracts::RuntimeCapability::LiveMigration)
137 && contracts.capabilities.contains(
138 &telltale_machine::runtime_contracts::RuntimeCapability::PlacementRefinement,
139 ),
140 );
141 inventory.insert(
142 CapabilityKey::new("mixed_determinism"),
143 contracts.can_use_mixed_determinism_profiles,
144 );
145 inventory.insert(
146 CapabilityKey::new("vmEnvelopeAdherence"),
147 contracts.determinism_artifacts.full,
148 );
149 inventory.insert(
150 CapabilityKey::new("reconfiguration_safety"),
151 reconfiguration_enabled,
152 );
153 merge_protocol_surfaces_into_inventory(&mut inventory, &protocol_critical_surfaces);
154
155 Self {
156 inventory: Arc::new(inventory),
157 protocol_critical_surfaces: Arc::new(protocol_critical_surfaces),
158 }
159 }
160}
161
162fn protocol_surface_inventory_from_aura_capabilities(
163 inventory: &BTreeMap<CapabilityKey, bool>,
164) -> BTreeMap<String, bool> {
165 let reconfiguration_enabled = inventory
166 .get(&CapabilityKey::new("reconfiguration"))
167 .copied()
168 .unwrap_or(false);
169 #[cfg(feature = "telltale-runtime-capability")]
170 {
171 protocol_surface_inventory_from_boundary(reconfiguration_enabled)
172 }
173 #[cfg(not(feature = "telltale-runtime-capability"))]
174 {
175 protocol_surface_inventory_from_known_surfaces(reconfiguration_enabled)
176 }
177}
178
179fn merge_protocol_surfaces_into_inventory(
180 inventory: &mut BTreeMap<CapabilityKey, bool>,
181 protocol_critical_surfaces: &BTreeMap<String, bool>,
182) {
183 for (surface, admitted) in protocol_critical_surfaces {
184 inventory.insert(CapabilityKey::new(surface.as_str()), *admitted);
185 }
186}
187
188#[cfg(feature = "telltale-runtime-capability")]
189fn protocol_surface_inventory_from_runtime_contracts(
190 contracts: &telltale_machine::runtime_contracts::RuntimeContracts,
191) -> BTreeMap<String, bool> {
192 let reconfiguration_enabled = contracts
193 .capabilities
194 .contains(&telltale_machine::runtime_contracts::RuntimeCapability::LiveMigration)
195 && contracts
196 .capabilities
197 .contains(&telltale_machine::runtime_contracts::RuntimeCapability::PlacementRefinement);
198 protocol_surface_inventory_from_boundary(reconfiguration_enabled)
199}
200
201#[cfg(feature = "telltale-runtime-capability")]
202fn protocol_surface_inventory_from_boundary(
203 reconfiguration_enabled: bool,
204) -> BTreeMap<String, bool> {
205 protocol_critical_capability_boundary()
206 .into_iter()
207 .map(|entry| {
208 let admitted = match entry.surface.as_str() {
209 PROTOCOL_SURFACE_OWNERSHIP_RECEIPT
210 | PROTOCOL_SURFACE_SEMANTIC_HANDOFF
211 | PROTOCOL_SURFACE_RECONFIGURATION_TRANSITION => reconfiguration_enabled,
212 _ => true,
213 };
214 (entry.surface, admitted)
215 })
216 .collect()
217}
218
219#[cfg(not(feature = "telltale-runtime-capability"))]
220fn protocol_surface_inventory_from_known_surfaces(
221 reconfiguration_enabled: bool,
222) -> BTreeMap<String, bool> {
223 let always_admitted = [
224 PROTOCOL_SURFACE_RUNTIME_ADMISSION,
225 PROTOCOL_SURFACE_THEOREM_PACK_CAPABILITIES,
226 PROTOCOL_SURFACE_OWNERSHIP_CAPABILITY,
227 PROTOCOL_SURFACE_READINESS_WITNESS,
228 PROTOCOL_SURFACE_AUTHORITATIVE_READ,
229 PROTOCOL_SURFACE_MATERIALIZATION_PROOF,
230 PROTOCOL_SURFACE_CANONICAL_HANDLE,
231 ];
232 let transition_surfaces = [
233 PROTOCOL_SURFACE_OWNERSHIP_RECEIPT,
234 PROTOCOL_SURFACE_SEMANTIC_HANDOFF,
235 PROTOCOL_SURFACE_RECONFIGURATION_TRANSITION,
236 ];
237
238 let mut admitted = always_admitted
239 .into_iter()
240 .map(|surface| (surface.to_string(), true))
241 .collect::<BTreeMap<_, _>>();
242 for surface in transition_surfaces {
243 admitted.insert(surface.to_string(), reconfiguration_enabled);
244 }
245 admitted
246}
247
248#[async_trait]
249impl RuntimeCapabilityEffects for RuntimeCapabilityHandler {
250 async fn capability_inventory(&self) -> Result<Vec<(CapabilityKey, bool)>, AdmissionError> {
251 Ok(self
252 .inventory
253 .iter()
254 .map(|(key, admitted)| (key.clone(), *admitted))
255 .collect())
256 }
257
258 async fn require_capabilities(&self, required: &[CapabilityKey]) -> Result<(), AdmissionError> {
259 for required_key in required {
260 let admitted = self.inventory.get(required_key).copied().unwrap_or(false);
261 if !admitted {
262 return Err(AdmissionError::MissingCapability {
263 capability: required_key.clone(),
264 });
265 }
266 }
267 Ok(())
268 }
269}
270
271#[cfg(test)]
272#[allow(clippy::expect_used)]
273mod tests {
274 use super::*;
275
276 #[tokio::test]
277 async fn missing_capability_is_rejected() {
278 let handler = RuntimeCapabilityHandler::from_pairs([
279 ("vmEnvelopeAdherence", true),
280 ("byzantineSafety", false),
281 ]);
282 let result = handler
283 .require_capabilities(&[
284 CapabilityKey::new("vmEnvelopeAdherence"),
285 CapabilityKey::new("byzantineSafety"),
286 ])
287 .await;
288 assert!(matches!(
289 result,
290 Err(AdmissionError::MissingCapability { capability })
291 if capability == CapabilityKey::new("byzantineSafety")
292 ));
293 }
294
295 #[tokio::test]
296 async fn inventory_round_trip_is_stable() {
297 let handler =
298 RuntimeCapabilityHandler::from_pairs([("capA", true), ("capB", false), ("capC", true)]);
299 let inventory = handler
300 .capability_inventory()
301 .await
302 .expect("inventory should be available");
303 assert!(inventory.contains(&(CapabilityKey::new("capA"), true)));
304 assert!(inventory.contains(&(CapabilityKey::new("capB"), false)));
305 assert!(inventory.contains(&(CapabilityKey::new("capC"), true)));
306 assert!(inventory.contains(&(CapabilityKey::new("theorem_pack_capabilities"), true)));
307 assert!(inventory.contains(&(CapabilityKey::new("authoritative_read"), true)));
308 assert!(inventory.contains(&(CapabilityKey::new("reconfiguration_transition"), false)));
309 }
310
311 #[cfg(feature = "telltale-runtime-capability")]
312 #[test]
313 fn protocol_machine_runtime_contract_mapping_exposes_derived_aura_capabilities() {
314 let contracts = telltale_machine::runtime_contracts::RuntimeContracts::full();
315 let handler = RuntimeCapabilityHandler::from_protocol_machine_runtime_contracts(&contracts);
316 assert!(
317 handler
318 .inventory
319 .get(&CapabilityKey::new("byzantine_envelope"))
320 .copied()
321 .unwrap_or(false),
322 "full contracts should admit byzantine_envelope"
323 );
324 assert!(
325 handler
326 .inventory
327 .contains_key(&CapabilityKey::new("termination_bounded")),
328 "derived termination_bounded key should be present"
329 );
330 assert!(
331 handler
332 .inventory
333 .contains_key(&CapabilityKey::new("mixed_determinism")),
334 "derived mixed_determinism key should be present"
335 );
336 assert!(
337 handler.protocol_critical_surface_admitted(PROTOCOL_SURFACE_OWNERSHIP_CAPABILITY),
338 "public ownership capability surface should be tracked"
339 );
340 assert!(
341 handler.protocol_critical_surface_admitted(PROTOCOL_SURFACE_RECONFIGURATION_TRANSITION),
342 "full contracts should admit public reconfiguration transition surface"
343 );
344 }
345
346 #[test]
347 fn missing_public_protocol_surface_is_rejected() {
348 let handler = RuntimeCapabilityHandler::from_pairs([("reconfiguration", false)]);
349 let result = handler
350 .require_protocol_critical_surfaces(&[PROTOCOL_SURFACE_RECONFIGURATION_TRANSITION]);
351 assert!(matches!(
352 result,
353 Err(AdmissionError::MissingCapability { capability })
354 if capability == CapabilityKey::new(PROTOCOL_SURFACE_RECONFIGURATION_TRANSITION)
355 ));
356 }
357}