Skip to main content

miden_protocol/account/component/
code.rs

1use miden_assembly::Library;
2use miden_assembly::library::ProcedureExport;
3use miden_processor::mast::{MastForest, MastNodeExt};
4
5use crate::account::AccountProcedureRoot;
6use crate::vm::AdviceMap;
7
8// ACCOUNT COMPONENT CODE
9// ================================================================================================
10
11/// A [`Library`] that has been assembled for use as component code.
12#[derive(Debug, Clone, PartialEq, Eq)]
13pub struct AccountComponentCode(Library);
14
15impl AccountComponentCode {
16    /// Returns a reference to the underlying [`Library`]
17    pub fn as_library(&self) -> &Library {
18        &self.0
19    }
20
21    /// Returns a reference to the code's [`MastForest`]
22    pub fn mast_forest(&self) -> &MastForest {
23        self.0.mast_forest().as_ref()
24    }
25
26    /// Consumes `self` and returns the underlying [`Library`]
27    pub fn into_library(self) -> Library {
28        self.0
29    }
30
31    /// Returns an iterator over the [`AccountProcedureRoot`]s of this component's exported
32    /// procedures.
33    pub fn procedure_roots(&self) -> impl Iterator<Item = AccountProcedureRoot> + '_ {
34        self.0.exports().filter_map(|export| {
35            export.as_procedure().map(|proc_export| {
36                let digest = self.0.mast_forest()[proc_export.node].digest();
37                AccountProcedureRoot::from_raw(digest)
38            })
39        })
40    }
41
42    /// Returns the procedure exports of this component.
43    pub fn exports(&self) -> impl Iterator<Item = &ProcedureExport> + '_ {
44        self.0.exports().filter_map(|export| export.as_procedure())
45    }
46
47    /// Returns a new [AccountComponentCode] with the provided advice map entries merged into the
48    /// underlying [Library]'s [MastForest].
49    ///
50    /// This allows adding advice map entries to an already-compiled account component,
51    /// which is useful when the entries are determined after compilation.
52    pub fn with_advice_map(self, advice_map: AdviceMap) -> Self {
53        if advice_map.is_empty() {
54            return self;
55        }
56
57        Self(self.0.with_advice_map(advice_map))
58    }
59}
60
61impl AsRef<Library> for AccountComponentCode {
62    fn as_ref(&self) -> &Library {
63        self.as_library()
64    }
65}
66
67// CONVERSIONS
68// ================================================================================================
69
70impl From<Library> for AccountComponentCode {
71    fn from(value: Library) -> Self {
72        Self(value)
73    }
74}
75
76impl From<AccountComponentCode> for Library {
77    fn from(value: AccountComponentCode) -> Self {
78        value.into_library()
79    }
80}
81
82// TESTS
83// ================================================================================================
84
85#[cfg(test)]
86mod tests {
87    use miden_core::{Felt, Word};
88
89    use super::*;
90    use crate::assembly::Assembler;
91
92    #[test]
93    fn test_account_component_code_with_advice_map() {
94        let assembler = Assembler::default();
95        let library = assembler
96            .assemble_library(["pub proc test nop end"])
97            .expect("failed to assemble library");
98        let component_code = AccountComponentCode::from(library);
99
100        assert!(component_code.mast_forest().advice_map().is_empty());
101
102        // Empty advice map should be a no-op (digest stays the same)
103        let cloned = component_code.clone();
104        let original_digest = cloned.as_library().digest();
105        let component_code = component_code.with_advice_map(AdviceMap::default());
106        assert_eq!(original_digest, component_code.as_library().digest());
107
108        // Non-empty advice map should add entries
109        let key = Word::from([10u32, 20, 30, 40]);
110        let value = vec![Felt::new(200)];
111        let mut advice_map = AdviceMap::default();
112        advice_map.insert(key, value.clone());
113
114        let component_code = component_code.with_advice_map(advice_map);
115
116        let mast = component_code.mast_forest();
117        let stored = mast.advice_map().get(&key).expect("entry should be present");
118        assert_eq!(stored.as_ref(), value.as_slice());
119    }
120}