linera_execution/
applications.rs1use std::collections::{HashMap, HashSet};
5
6use linera_base::{data_types::UserApplicationDescription, identifiers::UserApplicationId};
7use linera_views::{
8 context::Context,
9 map_view::HashedMapView,
10 views::{ClonableView, HashableView},
11};
12#[cfg(with_testing)]
13use {
14 linera_views::context::{create_test_memory_context, MemoryContext},
15 linera_views::views::View,
16 std::collections::BTreeMap,
17};
18
19use crate::SystemExecutionError;
20
21#[cfg(test)]
22#[path = "unit_tests/applications_tests.rs"]
23mod applications_tests;
24
25#[derive(Debug, ClonableView, HashableView)]
26pub struct ApplicationRegistryView<C> {
27 pub known_applications: HashedMapView<C, UserApplicationId, UserApplicationDescription>,
29}
30
31#[cfg(with_testing)]
32#[derive(Default, Eq, PartialEq, Debug, Clone)]
33pub struct ApplicationRegistry {
34 pub known_applications: BTreeMap<UserApplicationId, UserApplicationDescription>,
35}
36
37impl<C> ApplicationRegistryView<C>
38where
39 C: Context + Clone + Send + Sync + 'static,
40{
41 #[cfg(with_testing)]
42 pub fn import(&mut self, registry: ApplicationRegistry) -> Result<(), SystemExecutionError> {
43 for (id, description) in registry.known_applications {
44 self.known_applications.insert(&id, description)?;
45 }
46 Ok(())
47 }
48
49 pub async fn register_application(
53 &mut self,
54 application: UserApplicationDescription,
55 ) -> Result<UserApplicationId, SystemExecutionError> {
56 for required_id in &application.required_application_ids {
58 self.describe_application(*required_id).await?;
59 }
60 let id = UserApplicationId::from(&application);
61 self.known_applications.insert(&id, application)?;
62 Ok(id)
63 }
64
65 pub async fn register_new_application(
67 &mut self,
68 application_id: UserApplicationId,
69 parameters: Vec<u8>,
70 required_application_ids: Vec<UserApplicationId>,
71 ) -> Result<(), SystemExecutionError> {
72 for required_id in &required_application_ids {
74 self.describe_application(*required_id).await?;
75 }
76 let UserApplicationId {
78 bytecode_id,
79 creation,
80 } = application_id;
81 let description = UserApplicationDescription {
82 bytecode_id,
83 parameters,
84 creation,
85 required_application_ids,
86 };
87 self.known_applications
88 .insert(&application_id, description)?;
89 Ok(())
90 }
91
92 pub async fn describe_application(
94 &self,
95 id: UserApplicationId,
96 ) -> Result<UserApplicationDescription, SystemExecutionError> {
97 self.known_applications
98 .get(&id)
99 .await?
100 .ok_or_else(|| SystemExecutionError::UnknownApplicationId(Box::new(id)))
101 }
102
103 pub async fn find_dependencies(
105 &self,
106 mut stack: Vec<UserApplicationId>,
107 registered_apps: &HashMap<UserApplicationId, UserApplicationDescription>,
108 ) -> Result<Vec<UserApplicationId>, SystemExecutionError> {
109 let mut result = Vec::new();
111 let mut sorted = HashSet::new();
113 let mut seen = HashSet::new();
115
116 while let Some(id) = stack.pop() {
117 if sorted.contains(&id) {
118 continue;
119 }
120 if seen.contains(&id) {
121 sorted.insert(id);
124 result.push(id);
125 continue;
126 }
127 seen.insert(id);
130 stack.push(id);
132 let app = if let Some(app) = registered_apps.get(&id) {
133 app.clone()
134 } else {
135 self.describe_application(id).await?
136 };
137 for child in app.required_application_ids.iter().rev() {
138 if !seen.contains(child) {
139 stack.push(*child);
140 }
141 }
142 }
143 Ok(result)
144 }
145
146 pub async fn describe_applications_with_dependencies(
148 &self,
149 ids: Vec<UserApplicationId>,
150 extra_registered_apps: &HashMap<UserApplicationId, UserApplicationDescription>,
151 ) -> Result<Vec<UserApplicationDescription>, SystemExecutionError> {
152 let ids_with_deps = self.find_dependencies(ids, extra_registered_apps).await?;
153 let mut result = Vec::new();
154 for id in ids_with_deps {
155 let description = if let Some(description) = extra_registered_apps.get(&id) {
156 description.clone()
157 } else {
158 self.describe_application(id).await?
159 };
160 result.push(description);
161 }
162 Ok(result)
163 }
164}
165
166#[cfg(with_testing)]
167impl ApplicationRegistryView<MemoryContext<()>>
168where
169 MemoryContext<()>: Context + Clone + Send + Sync + 'static,
170{
171 pub async fn new() -> Self {
172 let context = create_test_memory_context();
173 Self::load(context)
174 .await
175 .expect("Loading from memory should work")
176 }
177}