Skip to main content

miden_objects/decoded/transaction/
inputs.rs

1use miden_protobuf::unwrap_infallible;
2pub use proto::transaction::DecodedForeignAccountSlotName as ForeignAccountSlotName;
3
4use crate::decoded::VerificationError;
5use crate::{Verify, proto};
6
7#[cfg(test)]
8mod tests;
9
10impl Verify for ForeignAccountSlotName {
11    type Verified =
12        (miden_protocol::account::StorageSlotId, miden_protocol::account::StorageSlotName);
13    type Error = VerificationError;
14    fn verify(self) -> Result<Self::Verified, Self::Error> {
15        let id = unwrap_infallible(self.slot_id.verify());
16        let name = miden_protocol::account::StorageSlotName::new(self.slot_name)?;
17        if name.id() != id {
18            return Err(ForeignAccountSlotNameError::IdMismatch {
19                expected: name.id(),
20                actual: id,
21            }
22            .into());
23        }
24        Ok((id, name))
25    }
26}
27
28#[derive(Debug, thiserror::Error)]
29pub enum ForeignAccountSlotNameError {
30    #[error("storage slot ID {actual} does not match the name's ID {expected}")]
31    IdMismatch {
32        expected: miden_protocol::account::StorageSlotId,
33        actual: miden_protocol::account::StorageSlotId,
34    },
35}
36
37pub use proto::transaction::DecodedTransactionInputsV1 as TransactionInputsV1;
38
39/// Checks input consistency and note inclusion against supplied headers, without authenticating the
40/// chain.
41impl crate::BuildUnchecked for TransactionInputsV1 {
42    type Output = miden_protocol::transaction::TransactionInputs;
43    type Error = VerificationError;
44    fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
45        let account = self.account.verify()?;
46        let header = self.block_header.build_unchecked()?;
47        let config = self.protocol_config.verify()?;
48        let chain = self.partial_blockchain.build_unchecked()?;
49        let notes = self.input_notes.verify()?;
50        let args = self.tx_args.verify()?;
51        let advice = self.advice_inputs.verify()?;
52        let code = self
53            .foreign_account_code
54            .into_iter()
55            .map(Verify::verify)
56            .collect::<Result<_, _>>()?;
57        let mut names = alloc::collections::BTreeMap::new();
58        for name in self.foreign_account_slot_names {
59            let (id, name) = name.verify()?;
60            if names.insert(id, name).is_some() {
61                return Err(TransactionInputsError::DuplicateSlot(id).into());
62            }
63        }
64        Ok(Self::Output::try_from_parts(
65            account, header, config, chain, notes, args, advice, code, names,
66        )?)
67    }
68}
69
70#[derive(Debug, thiserror::Error)]
71pub enum TransactionInputsError {
72    #[error("duplicate foreign account storage slot ID {0}")]
73    DuplicateSlot(miden_protocol::account::StorageSlotId),
74}
75
76pub use proto::transaction::DecodedTransactionInputs as TransactionInputs;
77
78/// Dispatches the decoded version without adding trust to the supplied headers or chain.
79impl crate::BuildUnchecked for TransactionInputs {
80    type Output = miden_protocol::transaction::TransactionInputs;
81    type Error = VerificationError;
82    fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
83        let proto::transaction::transaction_inputs::DecodedVersion::V1(inputs) = self.version;
84        inputs.build_unchecked()
85    }
86}