Skip to main content

miden_standards/account/inspection/
code_inspection.rs

1use miden_protocol::account::component::{AccountComponentCode, AccountComponentMetadata};
2use miden_protocol::account::{AccountComponent, AccountComponentName, AccountProcedureRoot};
3
4use crate::account::account_component_code;
5use crate::procedure_root;
6
7// CODE INSPECTION
8// ================================================================================================
9
10account_component_code!(CODE_INSPECTION_CODE, "miden-standards-inspection-code-inspection.masp");
11
12// PROCEDURE ROOTS
13// ================================================================================================
14
15/// MASL library namespace used for procedure-root lookups. Distinct from [`CodeInspection::NAME`],
16/// which mirrors the standards-side MASM module path.
17const CODE_INSPECTION_LIBRARY_PATH: &str =
18    "miden::standards::components::inspection::code_inspection";
19
20// Initialize the procedure root of the `has_procedure` procedure only once.
21procedure_root!(
22    CODE_INSPECTION_HAS_PROCEDURE,
23    CODE_INSPECTION_LIBRARY_PATH,
24    CodeInspection::HAS_PROCEDURE_PROC_NAME,
25    CodeInspection::code()
26);
27
28// Initialize the procedure root of the `get_code_commitment` procedure only once.
29procedure_root!(
30    CODE_INSPECTION_GET_CODE_COMMITMENT,
31    CODE_INSPECTION_LIBRARY_PATH,
32    CodeInspection::GET_CODE_COMMITMENT_PROC_NAME,
33    CodeInspection::code()
34);
35
36// Initialize the procedure root of the `get_num_procedures` procedure only once.
37procedure_root!(
38    CODE_INSPECTION_GET_NUM_PROCEDURES,
39    CODE_INSPECTION_LIBRARY_PATH,
40    CodeInspection::GET_NUM_PROCEDURES_PROC_NAME,
41    CodeInspection::code()
42);
43
44// Initialize the procedure root of the `get_procedure_root` procedure only once.
45procedure_root!(
46    CODE_INSPECTION_GET_PROCEDURE_ROOT,
47    CODE_INSPECTION_LIBRARY_PATH,
48    CodeInspection::GET_PROCEDURE_ROOT_PROC_NAME,
49    CodeInspection::code()
50);
51
52/// An [`AccountComponent`] exposing read-only introspection over the account's own code.
53///
54/// It reexports the procedures from `miden::standards::inspection::code_inspection`, which wrap the
55/// account-related kernel procedures. When linking against this component, the `miden` library
56/// (i.e. [`ProtocolLib`](miden_protocol::ProtocolLib)) must be available to the assembler which is
57/// the case when using [`CodeBuilder`][builder]. The procedures of this component are:
58/// - `has_procedure`, which returns whether a procedure with the given root is available on the
59///   account.
60/// - `get_code_commitment`, which returns the commitment to the account's code.
61/// - `get_num_procedures`, which returns the number of procedures in the account.
62/// - `get_procedure_root`, which returns the procedure root at the given index.
63///
64/// Exposing these procedures lets external callers (note scripts, transaction scripts, or foreign
65/// accounts via FPI) verify what an account can do without being granted access to its storage or
66/// vault. The component carries no storage of its own.
67///
68/// [builder]: crate::code_builder::CodeBuilder
69pub struct CodeInspection;
70
71impl CodeInspection {
72    // CONSTANTS
73    // --------------------------------------------------------------------------------------------
74
75    /// The name of the component.
76    pub const NAME: &'static str = "miden::standards::inspection::code_inspection";
77
78    const HAS_PROCEDURE_PROC_NAME: &str = "has_procedure";
79    const GET_CODE_COMMITMENT_PROC_NAME: &str = "get_code_commitment";
80    const GET_NUM_PROCEDURES_PROC_NAME: &str = "get_num_procedures";
81    const GET_PROCEDURE_ROOT_PROC_NAME: &str = "get_procedure_root";
82
83    /// Returns the canonical [`AccountComponentName`] of this component.
84    pub const fn name() -> AccountComponentName {
85        AccountComponentName::from_static_str(Self::NAME)
86    }
87
88    // PUBLIC ACCESSORS
89    // --------------------------------------------------------------------------------------------
90
91    /// Returns the [`AccountComponentCode`] of this component.
92    pub fn code() -> &'static AccountComponentCode {
93        &CODE_INSPECTION_CODE
94    }
95
96    /// Returns the procedure root of the `has_procedure` procedure.
97    pub fn has_procedure_root() -> AccountProcedureRoot {
98        *CODE_INSPECTION_HAS_PROCEDURE
99    }
100
101    /// Returns the procedure root of the `get_code_commitment` procedure.
102    pub fn get_code_commitment_root() -> AccountProcedureRoot {
103        *CODE_INSPECTION_GET_CODE_COMMITMENT
104    }
105
106    /// Returns the procedure root of the `get_num_procedures` procedure.
107    pub fn get_num_procedures_root() -> AccountProcedureRoot {
108        *CODE_INSPECTION_GET_NUM_PROCEDURES
109    }
110
111    /// Returns the procedure root of the `get_procedure_root` procedure.
112    pub fn get_procedure_root_root() -> AccountProcedureRoot {
113        *CODE_INSPECTION_GET_PROCEDURE_ROOT
114    }
115
116    /// Returns the [`AccountComponentMetadata`] for this component.
117    pub fn component_metadata() -> AccountComponentMetadata {
118        AccountComponentMetadata::new(Self::NAME)
119            .with_description("Read-only introspection over the account's own code")
120    }
121}
122
123impl From<CodeInspection> for AccountComponent {
124    fn from(_: CodeInspection) -> Self {
125        let metadata = CodeInspection::component_metadata();
126
127        AccountComponent::new(CodeInspection::code().clone(), vec![], metadata).expect(
128            "code inspection component should satisfy the requirements of a valid account component",
129        )
130    }
131}
132
133// TESTS
134// ================================================================================================
135
136#[cfg(test)]
137mod tests {
138    use miden_protocol::account::{AccountBuilder, AccountType};
139
140    use super::CodeInspection;
141    use crate::account::auth::NoAuth;
142
143    /// Check that obtaining the code inspection procedure roots does not panic.
144    #[test]
145    fn get_code_inspection_procedures() {
146        let _has_procedure_root = CodeInspection::has_procedure_root();
147        let _get_code_commitment_root = CodeInspection::get_code_commitment_root();
148        let _get_num_procedures_root = CodeInspection::get_num_procedures_root();
149        let _get_procedure_root_root = CodeInspection::get_procedure_root_root();
150    }
151
152    /// Check that the component can be added to an account and that the resulting account exposes
153    /// the code inspection procedures.
154    #[test]
155    fn account_exposes_code_inspection_procedures() -> anyhow::Result<()> {
156        let account = AccountBuilder::new([1; 32])
157            .account_type(AccountType::Public)
158            .with_component(NoAuth)
159            .with_component(CodeInspection)
160            .build_existing()?;
161
162        let code = account.code();
163        assert!(code.has_procedure(*CodeInspection::has_procedure_root().mast_root()));
164        assert!(code.has_procedure(*CodeInspection::get_code_commitment_root().mast_root()));
165        assert!(code.has_procedure(*CodeInspection::get_num_procedures_root().mast_root()));
166        assert!(code.has_procedure(*CodeInspection::get_procedure_root_root().mast_root()));
167
168        Ok(())
169    }
170}