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}