miden_tx/host/
account_procedures.rs

1use miden_protocol::account::AccountCode;
2
3use super::{BTreeMap, Word};
4use crate::errors::TransactionKernelError;
5
6// ACCOUNT PROCEDURE INDEX MAP
7// ================================================================================================
8
9/// A map of maps { acct_code_commitment |-> { proc_root |-> proc_index } } for all known
10/// procedures of account interfaces for all accounts expected to be invoked during transaction
11/// execution.
12#[derive(Debug, Clone, Default)]
13pub struct AccountProcedureIndexMap(BTreeMap<Word, BTreeMap<Word, u8>>);
14
15impl AccountProcedureIndexMap {
16    /// Returns a new [`AccountProcedureIndexMap`] instantiated with account procedures from the
17    /// provided iterator of [`AccountCode`].
18    pub fn new<'code>(account_codes: impl IntoIterator<Item = &'code AccountCode>) -> Self {
19        let mut index_map = Self::default();
20
21        for account_code in account_codes {
22            // Insert each account procedures only once.
23            if !index_map.0.contains_key(&account_code.commitment()) {
24                index_map.insert_code(account_code);
25            }
26        }
27
28        index_map
29    }
30
31    /// Inserts the procedures from the provided [`AccountCode`] into the advice inputs, using
32    /// [`AccountCode::commitment`] as the key.
33    ///
34    /// The resulting instance will map the account code commitment to a mapping of
35    /// `proc_root |-> proc_index` for any account that is expected to be involved in the
36    /// transaction, enabling fast procedure index lookups at runtime.
37    pub fn insert_code(&mut self, code: &AccountCode) {
38        let mut procedure_map = BTreeMap::new();
39        for (proc_idx, proc_root) in code.procedures().iter().enumerate() {
40            // SAFETY: AccountCode::MAX_NUM_PROCEDURES is 256 and so the highest possible index is
41            // 255.
42            let proc_idx =
43                u8::try_from(proc_idx).expect("account code should contain at most 256 procedures");
44            procedure_map.insert(*proc_root.mast_root(), proc_idx);
45        }
46
47        self.0.insert(code.commitment(), procedure_map);
48    }
49
50    /// Returns the index of the requested procedure root in the account code identified by the
51    /// provided commitment.
52    ///
53    /// # Errors
54    ///
55    /// Returns an error if:
56    /// - the requested procedure is not present in this map.
57    pub fn get_proc_index(
58        &self,
59        code_commitment: Word,
60        procedure_root: Word,
61    ) -> Result<u8, TransactionKernelError> {
62        self.0
63            .get(&code_commitment)
64            .ok_or(TransactionKernelError::UnknownCodeCommitment(code_commitment))?
65            .get(&procedure_root)
66            .cloned()
67            .ok_or(TransactionKernelError::UnknownAccountProcedure(procedure_root))
68    }
69}