miden_protocol/account/component/
code.rs1use miden_assembly::Library;
2use miden_assembly::library::ProcedureExport;
3use miden_processor::mast::{MastForest, MastNodeExt};
4
5use crate::account::AccountProcedureRoot;
6use crate::assembly::Path;
7use crate::vm::AdviceMap;
8
9#[derive(Debug, Clone, PartialEq, Eq)]
14pub struct AccountComponentCode(Library);
15
16impl AccountComponentCode {
17 pub fn as_library(&self) -> &Library {
19 &self.0
20 }
21
22 pub fn mast_forest(&self) -> &MastForest {
24 self.0.mast_forest().as_ref()
25 }
26
27 pub fn into_library(self) -> Library {
29 self.0
30 }
31
32 pub fn procedure_roots(&self) -> impl Iterator<Item = AccountProcedureRoot> + '_ {
35 self.0.exports().filter_map(|export| {
36 export.as_procedure().map(|proc_export| {
37 let digest = self.0.mast_forest()[proc_export.node].digest();
38 AccountProcedureRoot::from_raw(digest)
39 })
40 })
41 }
42
43 pub fn exports(&self) -> impl Iterator<Item = &ProcedureExport> + '_ {
45 self.0.exports().filter_map(|export| export.as_procedure())
46 }
47
48 pub fn get_procedure_root_by_path(
51 &self,
52 proc_name: impl AsRef<Path>,
53 ) -> Option<AccountProcedureRoot> {
54 self.0.get_procedure_root_by_path(proc_name).map(AccountProcedureRoot::from_raw)
55 }
56
57 pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
63 if advice_map.is_empty() {
64 return self;
65 }
66
67 Self(self.0.with_advice_map(advice_map))
68 }
69}
70
71impl AsRef<Library> for AccountComponentCode {
72 fn as_ref(&self) -> &Library {
73 self.as_library()
74 }
75}
76
77impl From<Library> for AccountComponentCode {
81 fn from(value: Library) -> Self {
82 Self(value)
83 }
84}
85
86impl From<AccountComponentCode> for Library {
87 fn from(value: AccountComponentCode) -> Self {
88 value.into_library()
89 }
90}
91
92#[cfg(test)]
96mod tests {
97 use alloc::string::ToString;
98 use alloc::sync::Arc;
99
100 use miden_core::{Felt, Word};
101
102 use super::*;
103 use crate::assembly::Assembler;
104
105 #[test]
106 fn test_account_component_code_with_advice_map() {
107 let assembler = Assembler::default();
108 let library = Arc::unwrap_or_clone(
109 assembler
110 .assemble_library(["pub proc test nop end"])
111 .expect("failed to assemble library"),
112 );
113 let component_code = AccountComponentCode::from(library);
114
115 assert!(component_code.mast_forest().advice_map().is_empty());
116
117 let cloned = component_code.clone();
119 let original_digest = cloned.as_library().digest();
120 let component_code = component_code.with_advice_map(AdviceMap::default());
121 assert_eq!(original_digest, component_code.as_library().digest());
122
123 let key = Word::from([10u32, 20, 30, 40]);
125 let value = vec![Felt::from(200_u8)];
126 let mut advice_map = AdviceMap::default();
127 advice_map.insert(key, value.clone());
128
129 let component_code = component_code.with_advice_map(advice_map);
130
131 let mast = component_code.mast_forest();
132 let stored = mast.advice_map().get(&key).expect("entry should be present");
133 assert_eq!(stored.as_ref(), value.as_slice());
134 }
135
136 #[test]
137 fn test_get_procedure_root_by_path() {
138 let assembler = Assembler::default();
139 let library = Arc::unwrap_or_clone(
140 assembler
141 .assemble_library(["pub proc test_proc nop end"])
142 .expect("failed to assemble library"),
143 );
144 let component_code = AccountComponentCode::from(library);
145
146 assert_eq!(component_code.procedure_roots().count(), 1);
148 let expected = component_code.procedure_roots().next().expect("one procedure exported");
149
150 let library_namespace = component_code
151 .as_library()
152 .module_infos()
153 .next()
154 .expect("library should have one module")
155 .path()
156 .to_string();
157 let proc_path = alloc::format!("{library_namespace}::test_proc");
158
159 let root = component_code
160 .get_procedure_root_by_path(proc_path.as_str())
161 .expect("test_proc should be present");
162 assert_eq!(root, expected);
163
164 assert!(component_code.get_procedure_root_by_path("bogus::missing").is_none());
165 }
166}