miden_objects/transaction/
tx_args.rs1use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
2use core::ops::Deref;
3
4use assembly::{Assembler, Compile};
5use miden_crypto::merkle::InnerNodeInfo;
6use vm_core::{
7 mast::{MastForest, MastNodeId},
8 utils::{ByteReader, ByteWriter, Deserializable, Serializable},
9 AdviceMap, Program,
10};
11use vm_processor::{AdviceInputs, DeserializationError};
12
13use super::{Digest, Felt, Word};
14use crate::{
15 note::{NoteDetails, NoteId},
16 TransactionScriptError,
17};
18
19#[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}
36
37impl TransactionArgs {
38 pub fn new(
47 tx_script: Option<TransactionScript>,
48 note_args: Option<BTreeMap<NoteId, Word>>,
49 advice_map: AdviceMap,
50 ) -> Self {
51 let mut advice_inputs = AdviceInputs::default().with_map(advice_map);
52 if let Some(ref tx_script) = tx_script {
54 advice_inputs
55 .extend_map(tx_script.inputs().iter().map(|(hash, input)| (*hash, input.clone())))
56 }
57
58 Self {
59 tx_script,
60 note_args: note_args.unwrap_or_default(),
61 advice_inputs,
62 }
63 }
64
65 pub fn with_tx_script(tx_script: TransactionScript) -> Self {
67 Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default())
68 }
69
70 pub fn with_note_args(note_args: BTreeMap<NoteId, Word>) -> Self {
72 Self::new(None, Some(note_args), AdviceMap::default())
73 }
74
75 pub fn with_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
78 self.advice_inputs.extend(advice_inputs);
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 add_expected_output_note<T: Deref<Target = NoteDetails>>(&mut self, note: &T) {
112 let recipient = note.recipient();
113 let inputs = note.inputs();
114 let script = note.script();
115 let script_encoded: Vec<Felt> = script.into();
116
117 let new_elements = [
118 (recipient.digest(), recipient.to_elements()),
119 (inputs.commitment(), inputs.format_for_advice()),
120 (script.hash(), script_encoded),
121 ];
122
123 self.advice_inputs.extend_map(new_elements);
124 }
125
126 pub fn extend_expected_output_notes<T, L>(&mut self, notes: L)
135 where
136 L: IntoIterator<Item = T>,
137 T: Deref<Target = NoteDetails>,
138 {
139 for note in notes {
140 self.add_expected_output_note(¬e);
141 }
142 }
143
144 pub fn extend_advice_map<T: IntoIterator<Item = (Digest, Vec<Felt>)>>(&mut self, iter: T) {
146 self.advice_inputs.extend_map(iter)
147 }
148
149 pub fn extend_merkle_store<I: Iterator<Item = InnerNodeInfo>>(&mut self, iter: I) {
151 self.advice_inputs.extend_merkle_store(iter)
152 }
153}
154
155impl Serializable for TransactionArgs {
156 fn write_into<W: ByteWriter>(&self, target: &mut W) {
157 self.tx_script.write_into(target);
158 self.note_args.write_into(target);
159 self.advice_inputs.write_into(target);
160 }
161}
162
163impl Deserializable for TransactionArgs {
164 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
165 let tx_script = Option::<TransactionScript>::read_from(source)?;
166 let note_args = BTreeMap::<NoteId, Word>::read_from(source)?;
167 let advice_inputs = AdviceInputs::read_from(source)?;
168
169 Ok(Self { tx_script, note_args, advice_inputs })
170 }
171}
172
173#[derive(Clone, Debug, PartialEq, Eq)]
186pub struct TransactionScript {
187 mast: Arc<MastForest>,
188 entrypoint: MastNodeId,
189 inputs: BTreeMap<Digest, Vec<Felt>>,
190}
191
192impl TransactionScript {
193 pub fn new(code: Program, inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>) -> Self {
198 Self {
199 entrypoint: code.entrypoint(),
200 mast: code.mast_forest().clone(),
201 inputs: inputs.into_iter().map(|(k, v)| (k.into(), v)).collect(),
202 }
203 }
204
205 pub fn compile(
211 source_code: impl Compile,
212 inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>,
213 assembler: Assembler,
214 ) -> Result<Self, TransactionScriptError> {
215 let program = assembler
216 .assemble_program(source_code)
217 .map_err(TransactionScriptError::AssemblyError)?;
218 Ok(Self::new(program, inputs))
219 }
220
221 pub fn from_parts(
226 mast: Arc<MastForest>,
227 entrypoint: MastNodeId,
228 inputs: BTreeMap<Digest, Vec<Felt>>,
229 ) -> Self {
230 assert!(mast.get_node_by_id(entrypoint).is_some());
231 Self { mast, entrypoint, inputs }
232 }
233
234 pub fn mast(&self) -> Arc<MastForest> {
239 self.mast.clone()
240 }
241
242 pub fn hash(&self) -> Digest {
244 self.mast[self.entrypoint].digest()
245 }
246
247 pub fn inputs(&self) -> &BTreeMap<Digest, Vec<Felt>> {
249 &self.inputs
250 }
251}
252
253impl Serializable for TransactionScript {
257 fn write_into<W: ByteWriter>(&self, target: &mut W) {
258 self.mast.write_into(target);
259 target.write_u32(self.entrypoint.as_u32());
260 self.inputs.write_into(target);
261 }
262}
263
264impl Deserializable for TransactionScript {
265 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
266 let mast = MastForest::read_from(source)?;
267 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast)?;
268 let inputs = BTreeMap::<Digest, Vec<Felt>>::read_from(source)?;
269
270 Ok(Self::from_parts(Arc::new(mast), entrypoint, inputs))
271 }
272}
273
274#[cfg(test)]
275mod tests {
276 use vm_core::{
277 utils::{Deserializable, Serializable},
278 AdviceMap,
279 };
280
281 use crate::transaction::TransactionArgs;
282
283 #[test]
284 fn test_tx_args_serialization() {
285 let args = TransactionArgs::new(None, None, AdviceMap::default());
286 let bytes: std::vec::Vec<u8> = args.to_bytes();
287 let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap();
288
289 assert_eq!(args, decoded);
290 }
291}