miden_protocol/account/component/
code.rs1use miden_mast_package::{Package as Library, ProcedureExport};
2use miden_processor::mast::{MastForest, MastNodeExt};
3
4use crate::account::AccountProcedureRoot;
5use crate::assembly::Path;
6use crate::vm::AdviceMap;
7
8#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct AccountComponentCode(Library);
14
15impl AccountComponentCode {
16 pub fn as_library(&self) -> &Library {
18 &self.0
19 }
20
21 pub fn mast_forest(&self) -> &MastForest {
23 self.0.mast_forest().as_ref()
24 }
25
26 pub fn into_library(self) -> Library {
28 self.0
29 }
30
31 pub fn procedure_roots(&self) -> impl Iterator<Item = AccountProcedureRoot> + '_ {
34 self.exports().map(|proc_export| {
35 let digest = if let Some(node) = proc_export.node {
36 self.0.mast_forest()[node].digest()
37 } else {
38 proc_export.digest
39 };
40 AccountProcedureRoot::from_raw(digest)
41 })
42 }
43
44 pub fn exports(&self) -> impl Iterator<Item = &ProcedureExport> + '_ {
49 self.0
50 .manifest
51 .exports()
52 .filter_map(|export| export.as_procedure())
53 .filter(|proc_export| {
54 proc_export.attributes.has(super::ACCOUNT_PROCEDURE_ATTRIBUTE)
55 || proc_export.attributes.has(super::AUTH_SCRIPT_ATTRIBUTE)
56 })
57 }
58
59 pub fn get_procedure_root_by_path(
62 &self,
63 proc_name: impl AsRef<Path>,
64 ) -> Option<AccountProcedureRoot> {
65 let proc_name = proc_name.as_ref();
66 let absolute_proc_name = proc_name.to_absolute().ok();
67 self.0
68 .manifest
69 .exports()
70 .filter_map(|export| export.as_procedure())
71 .find(|export| {
72 absolute_proc_name.as_ref().is_some_and(|absolute_proc_name| {
73 export.path.as_ref() == absolute_proc_name.as_ref()
74 })
75 })
76 .map(|export| AccountProcedureRoot::from_raw(export.digest))
77 }
78
79 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
85 if advice_map.is_empty() {
86 return self;
87 }
88
89 Self(self.0.with_advice_map(advice_map))
90 }
91}
92
93impl AsRef<Library> for AccountComponentCode {
94 fn as_ref(&self) -> &Library {
95 self.as_library()
96 }
97}
98
99impl From<Library> for AccountComponentCode {
103 fn from(value: Library) -> Self {
104 Self(value)
105 }
106}
107
108impl From<AccountComponentCode> for Library {
109 fn from(value: AccountComponentCode) -> Self {
110 value.into_library()
111 }
112}
113
114#[cfg(test)]
118mod tests {
119 use alloc::string::ToString;
120
121 use miden_core::{Felt, Word};
122
123 use super::*;
124 use crate::testing::assembler::assemble_test_library;
125
126 #[test]
127 fn test_account_component_code_with_advice_map() {
128 let library = assemble_test_library(
129 "test-component-code-advice-map",
130 "test::component_code_advice_map",
131 "@account_procedure pub proc test nop end",
132 );
133 let component_code = AccountComponentCode::from(library);
134
135 assert!(component_code.mast_forest().advice_map().is_empty());
136
137 let cloned = component_code.clone();
139 let original_digest = cloned.as_library().digest();
140 let component_code = component_code.with_advice_map(AdviceMap::default());
141 assert_eq!(original_digest, component_code.as_library().digest());
142
143 let key = Word::from([10u32, 20, 30, 40]);
145 let value = vec![Felt::from(200_u8)];
146 let mut advice_map = AdviceMap::default();
147 advice_map.insert(key, value.clone());
148
149 let component_code = component_code.with_advice_map(advice_map);
150
151 let mast = component_code.mast_forest();
152 let stored = mast.advice_map().get(&key).expect("entry should be present");
153 assert_eq!(stored.as_ref(), value.as_slice());
154 }
155
156 #[test]
157 fn test_get_procedure_root_by_path() {
158 let library = assemble_test_library(
159 "test-component-code-procedure-root",
160 "test::component_code_procedure_root",
161 "@account_procedure pub proc test_proc nop end",
162 );
163 let component_code = AccountComponentCode::from(library);
164
165 assert_eq!(component_code.procedure_roots().count(), 1);
167 let expected = component_code.procedure_roots().next().expect("one procedure exported");
168
169 let library_namespace = component_code
170 .as_library()
171 .module_infos()
172 .next()
173 .expect("library should have one module")
174 .path()
175 .to_string();
176 let proc_path = alloc::format!("{library_namespace}::test_proc");
177
178 let root = component_code
179 .get_procedure_root_by_path(&*proc_path)
180 .expect("test_proc should be present");
181 assert_eq!(root, expected);
182
183 let relative_proc_path =
184 proc_path.strip_prefix("::").expect("test procedure path should be absolute");
185 let root = component_code
186 .get_procedure_root_by_path(relative_proc_path)
187 .expect("relative test_proc path should be present");
188 assert_eq!(root, expected);
189
190 assert!(component_code.get_procedure_root_by_path("bogus::missing").is_none());
191 }
192}