miden_objects/transaction/inputs/
mod.rs1use alloc::vec::Vec;
2use core::fmt::Debug;
3
4use miden_core::utils::{Deserializable, Serializable};
5
6use super::PartialBlockchain;
7use crate::TransactionInputError;
8use crate::account::{AccountCode, PartialAccount};
9use crate::block::{BlockHeader, BlockNumber};
10use crate::note::{Note, NoteInclusionProof};
11use crate::transaction::{TransactionArgs, TransactionScript};
12
13mod account;
14pub use account::AccountInputs;
15
16mod notes;
17use miden_processor::AdviceInputs;
18pub use notes::{InputNote, InputNotes, ToInputNoteCommitments};
19
20#[derive(Debug, Clone, PartialEq, Eq)]
25pub struct TransactionInputs {
26 account: PartialAccount,
27 block_header: BlockHeader,
28 blockchain: PartialBlockchain,
29 input_notes: InputNotes<InputNote>,
30 tx_args: TransactionArgs,
31 advice_inputs: AdviceInputs,
32 foreign_account_code: Vec<AccountCode>,
33}
34
35impl TransactionInputs {
36 pub fn new(
47 account: PartialAccount,
48 block_header: BlockHeader,
49 blockchain: PartialBlockchain,
50 input_notes: InputNotes<InputNote>,
51 ) -> Result<Self, TransactionInputError> {
52 if blockchain.chain_length() != block_header.block_num() {
54 return Err(TransactionInputError::InconsistentChainLength {
55 expected: block_header.block_num(),
56 actual: blockchain.chain_length(),
57 });
58 }
59 if blockchain.peaks().hash_peaks() != block_header.chain_commitment() {
60 return Err(TransactionInputError::InconsistentChainCommitment {
61 expected: block_header.chain_commitment(),
62 actual: blockchain.peaks().hash_peaks(),
63 });
64 }
65 for note in input_notes.iter() {
67 if let InputNote::Authenticated { note, proof } = note {
68 let note_block_num = proof.location().block_num();
69 let block_header = if note_block_num == block_header.block_num() {
70 &block_header
71 } else {
72 blockchain.get_block(note_block_num).ok_or(
73 TransactionInputError::InputNoteBlockNotInPartialBlockchain(note.id()),
74 )?
75 };
76 validate_is_in_block(note, proof, block_header)?;
77 }
78 }
79
80 Ok(Self {
81 account,
82 block_header,
83 blockchain,
84 input_notes,
85 tx_args: TransactionArgs::default(),
86 advice_inputs: AdviceInputs::default(),
87 foreign_account_code: Vec::new(),
88 })
89 }
90
91 pub fn with_foreign_account_code(mut self, foreign_account_code: Vec<AccountCode>) -> Self {
93 self.foreign_account_code = foreign_account_code;
94 self
95 }
96
97 pub fn with_tx_args(mut self, tx_args: TransactionArgs) -> Self {
99 self.tx_args = tx_args;
100 self
101 }
102
103 pub fn with_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
105 self.advice_inputs = advice_inputs;
106 self
107 }
108
109 pub fn set_input_notes(&mut self, new_notes: Vec<Note>) {
114 self.input_notes = new_notes.into();
115 }
116
117 pub fn set_advice_inputs(&mut self, new_advice_inputs: AdviceInputs) {
119 self.advice_inputs = new_advice_inputs;
120 }
121
122 #[cfg(feature = "testing")]
124 pub fn set_tx_args(&mut self, tx_args: TransactionArgs) {
125 self.tx_args = tx_args;
126 }
127
128 pub fn account(&self) -> &PartialAccount {
133 &self.account
134 }
135
136 pub fn block_header(&self) -> &BlockHeader {
138 &self.block_header
139 }
140
141 pub fn blockchain(&self) -> &PartialBlockchain {
144 &self.blockchain
145 }
146
147 pub fn input_notes(&self) -> &InputNotes<InputNote> {
149 &self.input_notes
150 }
151
152 pub fn ref_block(&self) -> BlockNumber {
154 self.block_header.block_num()
155 }
156
157 pub fn tx_script(&self) -> Option<&TransactionScript> {
159 self.tx_args.tx_script()
160 }
161
162 pub fn foreign_account_code(&self) -> &[AccountCode] {
164 &self.foreign_account_code
165 }
166
167 pub fn advice_inputs(&self) -> &AdviceInputs {
169 &self.advice_inputs
170 }
171
172 pub fn tx_args(&self) -> &TransactionArgs {
174 &self.tx_args
175 }
176
177 pub fn into_parts(
182 self,
183 ) -> (
184 PartialAccount,
185 BlockHeader,
186 PartialBlockchain,
187 InputNotes<InputNote>,
188 TransactionArgs,
189 ) {
190 (self.account, self.block_header, self.blockchain, self.input_notes, self.tx_args)
191 }
192}
193
194impl Serializable for TransactionInputs {
195 fn write_into<W: miden_core::utils::ByteWriter>(&self, target: &mut W) {
196 self.account.write_into(target);
197 self.block_header.write_into(target);
198 self.blockchain.write_into(target);
199 self.input_notes.write_into(target);
200 self.tx_args.write_into(target);
201 self.advice_inputs.write_into(target);
202 self.foreign_account_code.write_into(target);
203 }
204}
205
206impl Deserializable for TransactionInputs {
207 fn read_from<R: miden_core::utils::ByteReader>(
208 source: &mut R,
209 ) -> Result<Self, miden_core::utils::DeserializationError> {
210 let account = PartialAccount::read_from(source)?;
211 let block_header = BlockHeader::read_from(source)?;
212 let blockchain = PartialBlockchain::read_from(source)?;
213 let input_notes = InputNotes::read_from(source)?;
214 let tx_args = TransactionArgs::read_from(source)?;
215 let advice_inputs = AdviceInputs::read_from(source)?;
216 let foreign_account_code = Vec::<AccountCode>::read_from(source)?;
217
218 Ok(TransactionInputs {
219 account,
220 block_header,
221 blockchain,
222 input_notes,
223 tx_args,
224 advice_inputs,
225 foreign_account_code,
226 })
227 }
228}
229
230fn validate_is_in_block(
235 note: &Note,
236 proof: &NoteInclusionProof,
237 block_header: &BlockHeader,
238) -> Result<(), TransactionInputError> {
239 let note_index = proof.location().node_index_in_block().into();
240 let note_commitment = note.commitment();
241 proof
242 .note_path()
243 .verify(note_index, note_commitment, &block_header.note_root())
244 .map_err(|_| {
245 TransactionInputError::InputNoteNotInBlock(note.id(), proof.location().block_num())
246 })
247}