Skip to main content

miden_objects/decoded/transaction/
core.rs

1use miden_protobuf::unwrap_infallible;
2pub use proto::transaction::DecodedTransactionId as TransactionId;
3
4use crate::decoded::VerificationError;
5use crate::{BuildUnchecked, Verify, proto};
6
7#[cfg(test)]
8mod tests;
9
10impl Verify for TransactionId {
11    type Verified = miden_protocol::transaction::TransactionId;
12    type Error = core::convert::Infallible;
13    fn verify(self) -> Result<Self::Verified, Self::Error> {
14        Ok(Self::Verified::from_raw(self.id))
15    }
16}
17
18pub use proto::transaction::DecodedTransactionHeader as TransactionHeader;
19
20/// Builds a header using unchecked input-note commitments. Input/output note uniqueness,
21/// note-header invariants, and the transmitted transaction ID are still checked. The caller must
22/// establish each input's nullifier/header consistency and authentication, the original note order,
23/// and the account ID's relationship to the transaction data.
24impl BuildUnchecked for TransactionHeader {
25    type Output = miden_protocol::transaction::TransactionHeader;
26    type Error = VerificationError;
27    fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
28        let transmitted = unwrap_infallible(self.transaction_id.verify());
29        let input_notes = self.input_notes.build_unchecked()?;
30        let input_notes = miden_protocol::transaction::InputNotes::new(input_notes)?;
31        let output_notes = self.output_notes.verify()?;
32        let header = Self::Output::new(
33            self.account_id.verify()?,
34            self.initial_state_commitment,
35            self.final_state_commitment,
36            input_notes,
37            output_notes,
38        )?;
39        if header.id() != transmitted {
40            return Err(TransactionHeaderBuildError::IdMismatch {
41                transmitted,
42                recomputed: header.id(),
43            }
44            .into());
45        }
46        Ok(header)
47    }
48}
49
50#[derive(Debug, thiserror::Error)]
51pub enum TransactionHeaderBuildError {
52    #[error("transaction ID mismatch: transmitted {transmitted}, recomputed {recomputed}")]
53    IdMismatch {
54        transmitted: miden_protocol::transaction::TransactionId,
55        recomputed: miden_protocol::transaction::TransactionId,
56    },
57}
58
59pub use proto::transaction::DecodedTxAccountUpdate as TxAccountUpdate;
60
61impl Verify for TxAccountUpdate {
62    type Verified = miden_protocol::transaction::TxAccountUpdate;
63    type Error = VerificationError;
64    fn verify(self) -> Result<Self::Verified, Self::Error> {
65        Ok(Self::Verified::new(
66            self.account_id.verify()?,
67            self.initial_state_commitment,
68            self.final_state_commitment,
69            self.account_patch_commitment,
70            self.details.verify()?,
71        )?)
72    }
73}
74
75pub use proto::transaction::DecodedProvenTransaction as ProvenTransaction;
76
77/// Checks transaction construction invariants, but not its proof or input-note authentication.
78impl crate::BuildUnchecked for ProvenTransaction {
79    type Output = miden_protocol::transaction::ProvenTransaction;
80    type Error = VerificationError;
81    fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
82        let inputs = self.input_notes.build_unchecked()?;
83        let outputs = self.output_notes.verify()?;
84        Ok(Self::Output::new(
85            self.account_update.verify()?,
86            inputs,
87            outputs,
88            unwrap_infallible(self.reference_block_num.verify()),
89            self.reference_block_commitment,
90            unwrap_infallible(self.expiration_block_num.verify()),
91            self.proof,
92        )?)
93    }
94}