miden_objects/transaction/
tx_args.rs1use alloc::{
2 collections::{BTreeMap, BTreeSet},
3 sync::Arc,
4 vec::Vec,
5};
6
7use assembly::{Assembler, Compile};
8use miden_crypto::merkle::InnerNodeInfo;
9
10use super::{AccountInputs, Digest, Felt, Word};
11use crate::{
12 MastForest, MastNodeId, TransactionScriptError,
13 note::{NoteId, NoteRecipient},
14 utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
15 vm::{AdviceInputs, AdviceMap, Program},
16};
17
18#[derive(Clone, Debug, Default, PartialEq, Eq)]
31pub struct TransactionArgs {
32 tx_script: Option<TransactionScript>,
33 note_args: BTreeMap<NoteId, Word>,
34 advice_inputs: AdviceInputs,
35 foreign_account_inputs: Vec<AccountInputs>,
36}
37
38impl TransactionArgs {
39 pub fn new(
48 tx_script: Option<TransactionScript>,
49 note_args: Option<BTreeMap<NoteId, Word>>,
50 advice_map: AdviceMap,
51 foreign_account_inputs: Vec<AccountInputs>,
52 ) -> Self {
53 let mut advice_inputs = AdviceInputs::default().with_map(advice_map);
54 if let Some(ref tx_script) = tx_script {
56 advice_inputs
57 .extend_map(tx_script.inputs().iter().map(|(hash, input)| (*hash, input.clone())))
58 }
59
60 Self {
61 tx_script,
62 note_args: note_args.unwrap_or_default(),
63 advice_inputs,
64 foreign_account_inputs,
65 }
66 }
67
68 #[must_use]
70 pub fn with_tx_script(mut self, tx_script: TransactionScript) -> Self {
71 self.tx_script = Some(tx_script);
72 self
73 }
74
75 #[must_use]
77 pub fn with_note_args(mut self, note_args: BTreeMap<NoteId, Word>) -> Self {
78 self.note_args = note_args;
79 self
80 }
81
82 pub fn tx_script(&self) -> Option<&TransactionScript> {
87 self.tx_script.as_ref()
88 }
89
90 pub fn get_note_args(&self, note_id: NoteId) -> Option<&Word> {
92 self.note_args.get(¬e_id)
93 }
94
95 pub fn advice_inputs(&self) -> &AdviceInputs {
97 &self.advice_inputs
98 }
99
100 pub fn foreign_account_inputs(&self) -> &[AccountInputs] {
102 &self.foreign_account_inputs
103 }
104
105 pub fn foreign_account_code_commitments(&self) -> BTreeSet<Digest> {
107 self.foreign_account_inputs()
108 .iter()
109 .map(|acc| acc.code().commitment())
110 .collect()
111 }
112
113 pub fn add_output_note_recipient<T: AsRef<NoteRecipient>>(&mut self, note_recipient: T) {
124 let note_recipient = note_recipient.as_ref();
125 let inputs = note_recipient.inputs();
126 let script = note_recipient.script();
127 let script_encoded: Vec<Felt> = script.into();
128
129 let new_elements = [
130 (note_recipient.digest(), note_recipient.format_for_advice()),
131 (inputs.commitment(), inputs.format_for_advice()),
132 (script.root(), script_encoded),
133 ];
134
135 self.advice_inputs.extend_map(new_elements);
136 }
137
138 pub fn extend_output_note_recipients<T, L>(&mut self, notes: L)
146 where
147 L: IntoIterator<Item = T>,
148 T: AsRef<NoteRecipient>,
149 {
150 for note in notes {
151 self.add_output_note_recipient(note);
152 }
153 }
154
155 pub fn extend_advice_inputs(&mut self, advice_inputs: AdviceInputs) {
157 self.advice_inputs.extend(advice_inputs);
158 }
159
160 pub fn extend_advice_map<T: IntoIterator<Item = (Digest, Vec<Felt>)>>(&mut self, iter: T) {
162 self.advice_inputs.extend_map(iter)
163 }
164
165 pub fn extend_merkle_store<I: Iterator<Item = InnerNodeInfo>>(&mut self, iter: I) {
167 self.advice_inputs.extend_merkle_store(iter)
168 }
169}
170
171impl Serializable for TransactionArgs {
172 fn write_into<W: ByteWriter>(&self, target: &mut W) {
173 self.tx_script.write_into(target);
174 self.note_args.write_into(target);
175 self.advice_inputs.write_into(target);
176 self.foreign_account_inputs.write_into(target);
177 }
178}
179
180impl Deserializable for TransactionArgs {
181 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
182 let tx_script = Option::<TransactionScript>::read_from(source)?;
183 let note_args = BTreeMap::<NoteId, Word>::read_from(source)?;
184 let advice_inputs = AdviceInputs::read_from(source)?;
185 let foreign_account_inputs = Vec::<AccountInputs>::read_from(source)?;
186
187 Ok(Self {
188 tx_script,
189 note_args,
190 advice_inputs,
191 foreign_account_inputs,
192 })
193 }
194}
195
196#[derive(Clone, Debug, PartialEq, Eq)]
209pub struct TransactionScript {
210 mast: Arc<MastForest>,
211 entrypoint: MastNodeId,
212 inputs: BTreeMap<Digest, Vec<Felt>>,
213}
214
215impl TransactionScript {
216 pub fn new(code: Program, inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>) -> Self {
221 Self {
222 entrypoint: code.entrypoint(),
223 mast: code.mast_forest().clone(),
224 inputs: inputs.into_iter().map(|(k, v)| (k.into(), v)).collect(),
225 }
226 }
227
228 pub fn compile(
234 source_code: impl Compile,
235 inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>,
236 assembler: Assembler,
237 ) -> Result<Self, TransactionScriptError> {
238 let program = assembler
239 .assemble_program(source_code)
240 .map_err(TransactionScriptError::AssemblyError)?;
241 Ok(Self::new(program, inputs))
242 }
243
244 pub fn from_parts(
249 mast: Arc<MastForest>,
250 entrypoint: MastNodeId,
251 inputs: BTreeMap<Digest, Vec<Felt>>,
252 ) -> Self {
253 assert!(mast.get_node_by_id(entrypoint).is_some());
254 Self { mast, entrypoint, inputs }
255 }
256
257 pub fn mast(&self) -> Arc<MastForest> {
262 self.mast.clone()
263 }
264
265 pub fn root(&self) -> Digest {
267 self.mast[self.entrypoint].digest()
268 }
269
270 pub fn inputs(&self) -> &BTreeMap<Digest, Vec<Felt>> {
272 &self.inputs
273 }
274}
275
276impl Serializable for TransactionScript {
280 fn write_into<W: ByteWriter>(&self, target: &mut W) {
281 self.mast.write_into(target);
282 target.write_u32(self.entrypoint.as_u32());
283 self.inputs.write_into(target);
284 }
285}
286
287impl Deserializable for TransactionScript {
288 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
289 let mast = MastForest::read_from(source)?;
290 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast)?;
291 let inputs = BTreeMap::<Digest, Vec<Felt>>::read_from(source)?;
292
293 Ok(Self::from_parts(Arc::new(mast), entrypoint, inputs))
294 }
295}
296
297#[cfg(test)]
298mod tests {
299 use vm_core::{
300 AdviceMap,
301 utils::{Deserializable, Serializable},
302 };
303
304 use crate::transaction::TransactionArgs;
305
306 #[test]
307 fn test_tx_args_serialization() {
308 let args = TransactionArgs::new(None, None, AdviceMap::default(), std::vec::Vec::default());
309 let bytes: std::vec::Vec<u8> = args.to_bytes();
310 let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap();
311
312 assert_eq!(args, decoded);
313 }
314}