Skip to main content

ferrum_interfaces/vnext/event/
topology.rs

1use serde::Serialize;
2use std::collections::{BTreeMap, BTreeSet};
3
4use super::{
5    canonical_fingerprint, invalid_event, validate_sha256, DeviceId, ExecutionPlan, NodeId,
6    OperationId, PlanHash, PlanId, ProviderId, VNextError,
7};
8use crate::vnext::ProviderExecutionSemantics;
9
10#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
11pub struct TrustedNodeTopology {
12    pub(super) operation_id: OperationId,
13    pub(super) provider_id: ProviderId,
14    pub(super) provider_execution_semantics: ProviderExecutionSemantics,
15    pub(super) dependencies: BTreeSet<NodeId>,
16}
17
18impl TrustedNodeTopology {
19    pub fn operation_id(&self) -> &OperationId {
20        &self.operation_id
21    }
22
23    pub fn provider_id(&self) -> &ProviderId {
24        &self.provider_id
25    }
26
27    pub const fn provider_execution_semantics(&self) -> ProviderExecutionSemantics {
28        self.provider_execution_semantics
29    }
30
31    pub fn dependencies(&self) -> &BTreeSet<NodeId> {
32        &self.dependencies
33    }
34}
35
36#[derive(Debug, Clone, PartialEq, Eq, Serialize)]
37pub struct TrustedExecutionTopology {
38    plan_id: PlanId,
39    plan_hash: PlanHash,
40    device_id: DeviceId,
41    device_runtime_implementation_fingerprint: String,
42    pub(super) nodes: BTreeMap<NodeId, TrustedNodeTopology>,
43    #[serde(skip)]
44    fingerprint: String,
45}
46
47impl TrustedExecutionTopology {
48    pub fn from_plan(plan: &ExecutionPlan) -> Result<Self, VNextError> {
49        let mut nodes = BTreeMap::new();
50        for node in plan.payload().nodes() {
51            if nodes
52                .insert(
53                    node.id().clone(),
54                    TrustedNodeTopology {
55                        operation_id: node.operation_id().clone(),
56                        provider_id: node.selection().selected_provider().clone(),
57                        provider_execution_semantics: node.provider_execution_semantics(),
58                        dependencies: node.dependencies().iter().cloned().collect(),
59                    },
60                )
61                .is_some()
62            {
63                return Err(invalid_event("trusted plan has duplicate node ids"));
64            }
65        }
66        if nodes.is_empty() {
67            return Err(invalid_event("trusted execution topology is empty"));
68        }
69        let mut topology = Self {
70            plan_id: plan.payload().plan_id().clone(),
71            plan_hash: plan.plan_hash().clone(),
72            device_id: plan.payload().device_id().clone(),
73            device_runtime_implementation_fingerprint: plan
74                .payload()
75                .device_runtime_implementation_fingerprint()
76                .to_owned(),
77            nodes,
78            fingerprint: String::new(),
79        };
80        validate_sha256(
81            &topology.device_runtime_implementation_fingerprint,
82            "topology runtime implementation fingerprint",
83        )?;
84        topology.fingerprint = canonical_fingerprint(&topology);
85        Ok(topology)
86    }
87
88    pub fn plan_id(&self) -> &PlanId {
89        &self.plan_id
90    }
91
92    pub fn plan_hash(&self) -> &PlanHash {
93        &self.plan_hash
94    }
95
96    pub fn device_id(&self) -> &DeviceId {
97        &self.device_id
98    }
99
100    pub fn device_runtime_implementation_fingerprint(&self) -> &str {
101        &self.device_runtime_implementation_fingerprint
102    }
103
104    pub fn fingerprint(&self) -> &str {
105        &self.fingerprint
106    }
107
108    pub fn node_ids(&self) -> BTreeSet<NodeId> {
109        self.nodes.keys().cloned().collect()
110    }
111
112    pub fn node(&self, node_id: &NodeId) -> Option<&TrustedNodeTopology> {
113        self.nodes.get(node_id)
114    }
115}