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;
6
7use super::{Digest, Felt, Word};
8use crate::{
9 MastForest, MastNodeId, TransactionScriptError,
10 note::{NoteDetails, NoteId},
11 utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
12 vm::{AdviceInputs, AdviceMap, Program},
13};
14
15#[derive(Clone, Debug, Default, PartialEq, Eq)]
27pub struct TransactionArgs {
28 tx_script: Option<TransactionScript>,
29 note_args: BTreeMap<NoteId, Word>,
30 advice_inputs: AdviceInputs,
31}
32
33impl TransactionArgs {
34 pub fn new(
43 tx_script: Option<TransactionScript>,
44 note_args: Option<BTreeMap<NoteId, Word>>,
45 advice_map: AdviceMap,
46 ) -> Self {
47 let mut advice_inputs = AdviceInputs::default().with_map(advice_map);
48 if let Some(ref tx_script) = tx_script {
50 advice_inputs
51 .extend_map(tx_script.inputs().iter().map(|(hash, input)| (*hash, input.clone())))
52 }
53
54 Self {
55 tx_script,
56 note_args: note_args.unwrap_or_default(),
57 advice_inputs,
58 }
59 }
60
61 pub fn with_tx_script(tx_script: TransactionScript) -> Self {
63 Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default())
64 }
65
66 pub fn with_note_args(note_args: BTreeMap<NoteId, Word>) -> Self {
68 Self::new(None, Some(note_args), AdviceMap::default())
69 }
70
71 pub fn with_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
74 self.advice_inputs.extend(advice_inputs);
75 self
76 }
77
78 pub fn tx_script(&self) -> Option<&TransactionScript> {
83 self.tx_script.as_ref()
84 }
85
86 pub fn get_note_args(&self, note_id: NoteId) -> Option<&Word> {
88 self.note_args.get(¬e_id)
89 }
90
91 pub fn advice_inputs(&self) -> &AdviceInputs {
93 &self.advice_inputs
94 }
95
96 pub fn add_expected_output_note<T: Deref<Target = NoteDetails>>(&mut self, note: &T) {
108 let recipient = note.recipient();
109 let inputs = note.inputs();
110 let script = note.script();
111 let script_encoded: Vec<Felt> = script.into();
112
113 let new_elements = [
114 (recipient.digest(), recipient.to_elements()),
115 (inputs.commitment(), inputs.format_for_advice()),
116 (script.root(), script_encoded),
117 ];
118
119 self.advice_inputs.extend_map(new_elements);
120 }
121
122 pub fn extend_expected_output_notes<T, L>(&mut self, notes: L)
131 where
132 L: IntoIterator<Item = T>,
133 T: Deref<Target = NoteDetails>,
134 {
135 for note in notes {
136 self.add_expected_output_note(¬e);
137 }
138 }
139
140 pub fn extend_advice_map<T: IntoIterator<Item = (Digest, Vec<Felt>)>>(&mut self, iter: T) {
142 self.advice_inputs.extend_map(iter)
143 }
144
145 pub fn extend_merkle_store<I: Iterator<Item = InnerNodeInfo>>(&mut self, iter: I) {
147 self.advice_inputs.extend_merkle_store(iter)
148 }
149}
150
151impl Serializable for TransactionArgs {
152 fn write_into<W: ByteWriter>(&self, target: &mut W) {
153 self.tx_script.write_into(target);
154 self.note_args.write_into(target);
155 self.advice_inputs.write_into(target);
156 }
157}
158
159impl Deserializable for TransactionArgs {
160 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
161 let tx_script = Option::<TransactionScript>::read_from(source)?;
162 let note_args = BTreeMap::<NoteId, Word>::read_from(source)?;
163 let advice_inputs = AdviceInputs::read_from(source)?;
164
165 Ok(Self { tx_script, note_args, advice_inputs })
166 }
167}
168
169#[derive(Clone, Debug, PartialEq, Eq)]
182pub struct TransactionScript {
183 mast: Arc<MastForest>,
184 entrypoint: MastNodeId,
185 inputs: BTreeMap<Digest, Vec<Felt>>,
186}
187
188impl TransactionScript {
189 pub fn new(code: Program, inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>) -> Self {
194 Self {
195 entrypoint: code.entrypoint(),
196 mast: code.mast_forest().clone(),
197 inputs: inputs.into_iter().map(|(k, v)| (k.into(), v)).collect(),
198 }
199 }
200
201 pub fn compile(
207 source_code: impl Compile,
208 inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>,
209 assembler: Assembler,
210 ) -> Result<Self, TransactionScriptError> {
211 let program = assembler
212 .assemble_program(source_code)
213 .map_err(TransactionScriptError::AssemblyError)?;
214 Ok(Self::new(program, inputs))
215 }
216
217 pub fn from_parts(
222 mast: Arc<MastForest>,
223 entrypoint: MastNodeId,
224 inputs: BTreeMap<Digest, Vec<Felt>>,
225 ) -> Self {
226 assert!(mast.get_node_by_id(entrypoint).is_some());
227 Self { mast, entrypoint, inputs }
228 }
229
230 pub fn mast(&self) -> Arc<MastForest> {
235 self.mast.clone()
236 }
237
238 pub fn root(&self) -> Digest {
240 self.mast[self.entrypoint].digest()
241 }
242
243 pub fn inputs(&self) -> &BTreeMap<Digest, Vec<Felt>> {
245 &self.inputs
246 }
247}
248
249impl Serializable for TransactionScript {
253 fn write_into<W: ByteWriter>(&self, target: &mut W) {
254 self.mast.write_into(target);
255 target.write_u32(self.entrypoint.as_u32());
256 self.inputs.write_into(target);
257 }
258}
259
260impl Deserializable for TransactionScript {
261 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
262 let mast = MastForest::read_from(source)?;
263 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast)?;
264 let inputs = BTreeMap::<Digest, Vec<Felt>>::read_from(source)?;
265
266 Ok(Self::from_parts(Arc::new(mast), entrypoint, inputs))
267 }
268}
269
270#[cfg(test)]
271mod tests {
272 use vm_core::{
273 AdviceMap,
274 utils::{Deserializable, Serializable},
275 };
276
277 use crate::transaction::TransactionArgs;
278
279 #[test]
280 fn test_tx_args_serialization() {
281 let args = TransactionArgs::new(None, None, AdviceMap::default());
282 let bytes: std::vec::Vec<u8> = args.to_bytes();
283 let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap();
284
285 assert_eq!(args, decoded);
286 }
287}