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.foreign_account_code.verify()?;
53        let mut names = alloc::collections::BTreeMap::new();
54        for name in self.foreign_account_slot_names.into_inner() {
55            let (id, name) = name.verify()?;
56            if names.insert(id, name).is_some() {
57                return Err(TransactionInputsError::DuplicateSlot(id).into());
58            }
59        }
60        Ok(Self::Output::try_from_parts(
61            account, header, config, chain, notes, args, advice, code, names,
62        )?)
63    }
64}
65
66#[derive(Debug, thiserror::Error)]
67pub enum TransactionInputsError {
68    #[error("duplicate foreign account storage slot ID {0}")]
69    DuplicateSlot(miden_protocol::account::StorageSlotId),
70}
71
72pub use proto::transaction::DecodedTransactionInputs as TransactionInputs;
73
74/// Dispatches the decoded version without adding trust to the supplied headers or chain.
75impl crate::BuildUnchecked for TransactionInputs {
76    type Output = miden_protocol::transaction::TransactionInputs;
77    type Error = VerificationError;
78    fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
79        let proto::transaction::transaction_inputs::DecodedVersion::V1(inputs) = self.version;
80        inputs.build_unchecked()
81    }
82}