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.set_tx_args_inner(tx_args);
100 self
101 }
102
103 pub fn with_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
105 self.set_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) {
121 let AdviceInputs { map, store, .. } = new_advice_inputs;
122 self.advice_inputs = AdviceInputs { stack: Default::default(), map, store };
123 self.tx_args.extend_advice_inputs(self.advice_inputs.clone());
124 }
125
126 #[cfg(feature = "testing")]
128 pub fn set_tx_args(&mut self, tx_args: TransactionArgs) {
129 self.set_tx_args_inner(tx_args);
130 }
131
132 pub fn account(&self) -> &PartialAccount {
137 &self.account
138 }
139
140 pub fn block_header(&self) -> &BlockHeader {
142 &self.block_header
143 }
144
145 pub fn blockchain(&self) -> &PartialBlockchain {
148 &self.blockchain
149 }
150
151 pub fn input_notes(&self) -> &InputNotes<InputNote> {
153 &self.input_notes
154 }
155
156 pub fn ref_block(&self) -> BlockNumber {
158 self.block_header.block_num()
159 }
160
161 pub fn tx_script(&self) -> Option<&TransactionScript> {
163 self.tx_args.tx_script()
164 }
165
166 pub fn foreign_account_code(&self) -> &[AccountCode] {
168 &self.foreign_account_code
169 }
170
171 pub fn advice_inputs(&self) -> &AdviceInputs {
173 &self.advice_inputs
174 }
175
176 pub fn tx_args(&self) -> &TransactionArgs {
178 &self.tx_args
179 }
180
181 pub fn into_parts(
186 self,
187 ) -> (
188 PartialAccount,
189 BlockHeader,
190 PartialBlockchain,
191 InputNotes<InputNote>,
192 TransactionArgs,
193 ) {
194 (self.account, self.block_header, self.blockchain, self.input_notes, self.tx_args)
195 }
196
197 fn set_tx_args_inner(&mut self, tx_args: TransactionArgs) {
205 self.tx_args = tx_args;
206 self.tx_args.extend_advice_inputs(self.advice_inputs.clone());
207 }
208}
209
210impl Serializable for TransactionInputs {
211 fn write_into<W: miden_core::utils::ByteWriter>(&self, target: &mut W) {
212 self.account.write_into(target);
213 self.block_header.write_into(target);
214 self.blockchain.write_into(target);
215 self.input_notes.write_into(target);
216 self.tx_args.write_into(target);
217 self.advice_inputs.write_into(target);
218 self.foreign_account_code.write_into(target);
219 }
220}
221
222impl Deserializable for TransactionInputs {
223 fn read_from<R: miden_core::utils::ByteReader>(
224 source: &mut R,
225 ) -> Result<Self, miden_core::utils::DeserializationError> {
226 let account = PartialAccount::read_from(source)?;
227 let block_header = BlockHeader::read_from(source)?;
228 let blockchain = PartialBlockchain::read_from(source)?;
229 let input_notes = InputNotes::read_from(source)?;
230 let tx_args = TransactionArgs::read_from(source)?;
231 let advice_inputs = AdviceInputs::read_from(source)?;
232 let foreign_account_code = Vec::<AccountCode>::read_from(source)?;
233
234 Ok(TransactionInputs {
235 account,
236 block_header,
237 blockchain,
238 input_notes,
239 tx_args,
240 advice_inputs,
241 foreign_account_code,
242 })
243 }
244}
245
246fn validate_is_in_block(
251 note: &Note,
252 proof: &NoteInclusionProof,
253 block_header: &BlockHeader,
254) -> Result<(), TransactionInputError> {
255 let note_index = proof.location().node_index_in_block().into();
256 let note_commitment = note.commitment();
257 proof
258 .note_path()
259 .verify(note_index, note_commitment, &block_header.note_root())
260 .map_err(|_| {
261 TransactionInputError::InputNoteNotInBlock(note.id(), proof.location().block_num())
262 })
263}