miden_objects/transaction/
tx_args.rs1use alloc::{collections::BTreeMap, sync::Arc, vec::Vec};
2
3use assembly::{Assembler, Compile};
4use miden_crypto::merkle::InnerNodeInfo;
5
6use super::{Digest, Felt, Word};
7use crate::{
8 MastForest, MastNodeId, TransactionScriptError,
9 note::{NoteId, NoteRecipient},
10 utils::serde::{ByteReader, ByteWriter, Deserializable, DeserializationError, Serializable},
11 vm::{AdviceInputs, AdviceMap, Program},
12};
13
14#[derive(Clone, Debug, Default, PartialEq, Eq)]
26pub struct TransactionArgs {
27 tx_script: Option<TransactionScript>,
28 note_args: BTreeMap<NoteId, Word>,
29 advice_inputs: AdviceInputs,
30}
31
32impl TransactionArgs {
33 pub fn new(
42 tx_script: Option<TransactionScript>,
43 note_args: Option<BTreeMap<NoteId, Word>>,
44 advice_map: AdviceMap,
45 ) -> Self {
46 let mut advice_inputs = AdviceInputs::default().with_map(advice_map);
47 if let Some(ref tx_script) = tx_script {
49 advice_inputs
50 .extend_map(tx_script.inputs().iter().map(|(hash, input)| (*hash, input.clone())))
51 }
52
53 Self {
54 tx_script,
55 note_args: note_args.unwrap_or_default(),
56 advice_inputs,
57 }
58 }
59
60 pub fn with_tx_script(tx_script: TransactionScript) -> Self {
62 Self::new(Some(tx_script), Some(BTreeMap::default()), AdviceMap::default())
63 }
64
65 pub fn with_note_args(note_args: BTreeMap<NoteId, Word>) -> Self {
67 Self::new(None, Some(note_args), AdviceMap::default())
68 }
69
70 pub fn with_advice_inputs(mut self, advice_inputs: AdviceInputs) -> Self {
73 self.advice_inputs.extend(advice_inputs);
74 self
75 }
76
77 pub fn tx_script(&self) -> Option<&TransactionScript> {
82 self.tx_script.as_ref()
83 }
84
85 pub fn get_note_args(&self, note_id: NoteId) -> Option<&Word> {
87 self.note_args.get(¬e_id)
88 }
89
90 pub fn advice_inputs(&self) -> &AdviceInputs {
92 &self.advice_inputs
93 }
94
95 pub fn add_output_note_recipient<T: AsRef<NoteRecipient>>(&mut self, note_recipient: T) {
106 let note_recipient = note_recipient.as_ref();
107 let inputs = note_recipient.inputs();
108 let script = note_recipient.script();
109 let script_encoded: Vec<Felt> = script.into();
110
111 let new_elements = [
112 (note_recipient.digest(), note_recipient.to_elements()),
113 (inputs.commitment(), inputs.format_for_advice()),
114 (script.root(), script_encoded),
115 ];
116
117 self.advice_inputs.extend_map(new_elements);
118 }
119
120 pub fn extend_output_note_recipients<T, L>(&mut self, notes: L)
128 where
129 L: IntoIterator<Item = T>,
130 T: AsRef<NoteRecipient>,
131 {
132 for note in notes {
133 self.add_output_note_recipient(note);
134 }
135 }
136
137 pub fn extend_advice_map<T: IntoIterator<Item = (Digest, Vec<Felt>)>>(&mut self, iter: T) {
139 self.advice_inputs.extend_map(iter)
140 }
141
142 pub fn extend_merkle_store<I: Iterator<Item = InnerNodeInfo>>(&mut self, iter: I) {
144 self.advice_inputs.extend_merkle_store(iter)
145 }
146}
147
148impl Serializable for TransactionArgs {
149 fn write_into<W: ByteWriter>(&self, target: &mut W) {
150 self.tx_script.write_into(target);
151 self.note_args.write_into(target);
152 self.advice_inputs.write_into(target);
153 }
154}
155
156impl Deserializable for TransactionArgs {
157 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
158 let tx_script = Option::<TransactionScript>::read_from(source)?;
159 let note_args = BTreeMap::<NoteId, Word>::read_from(source)?;
160 let advice_inputs = AdviceInputs::read_from(source)?;
161
162 Ok(Self { tx_script, note_args, advice_inputs })
163 }
164}
165
166#[derive(Clone, Debug, PartialEq, Eq)]
179pub struct TransactionScript {
180 mast: Arc<MastForest>,
181 entrypoint: MastNodeId,
182 inputs: BTreeMap<Digest, Vec<Felt>>,
183}
184
185impl TransactionScript {
186 pub fn new(code: Program, inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>) -> Self {
191 Self {
192 entrypoint: code.entrypoint(),
193 mast: code.mast_forest().clone(),
194 inputs: inputs.into_iter().map(|(k, v)| (k.into(), v)).collect(),
195 }
196 }
197
198 pub fn compile(
204 source_code: impl Compile,
205 inputs: impl IntoIterator<Item = (Word, Vec<Felt>)>,
206 assembler: Assembler,
207 ) -> Result<Self, TransactionScriptError> {
208 let program = assembler
209 .assemble_program(source_code)
210 .map_err(TransactionScriptError::AssemblyError)?;
211 Ok(Self::new(program, inputs))
212 }
213
214 pub fn from_parts(
219 mast: Arc<MastForest>,
220 entrypoint: MastNodeId,
221 inputs: BTreeMap<Digest, Vec<Felt>>,
222 ) -> Self {
223 assert!(mast.get_node_by_id(entrypoint).is_some());
224 Self { mast, entrypoint, inputs }
225 }
226
227 pub fn mast(&self) -> Arc<MastForest> {
232 self.mast.clone()
233 }
234
235 pub fn root(&self) -> Digest {
237 self.mast[self.entrypoint].digest()
238 }
239
240 pub fn inputs(&self) -> &BTreeMap<Digest, Vec<Felt>> {
242 &self.inputs
243 }
244}
245
246impl Serializable for TransactionScript {
250 fn write_into<W: ByteWriter>(&self, target: &mut W) {
251 self.mast.write_into(target);
252 target.write_u32(self.entrypoint.as_u32());
253 self.inputs.write_into(target);
254 }
255}
256
257impl Deserializable for TransactionScript {
258 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
259 let mast = MastForest::read_from(source)?;
260 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast)?;
261 let inputs = BTreeMap::<Digest, Vec<Felt>>::read_from(source)?;
262
263 Ok(Self::from_parts(Arc::new(mast), entrypoint, inputs))
264 }
265}
266
267#[cfg(test)]
268mod tests {
269 use vm_core::{
270 AdviceMap,
271 utils::{Deserializable, Serializable},
272 };
273
274 use crate::transaction::TransactionArgs;
275
276 #[test]
277 fn test_tx_args_serialization() {
278 let args = TransactionArgs::new(None, None, AdviceMap::default());
279 let bytes: std::vec::Vec<u8> = args.to_bytes();
280 let decoded = TransactionArgs::read_from_bytes(&bytes).unwrap();
281
282 assert_eq!(args, decoded);
283 }
284}