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