miden_objects/note/
script.rs1use alloc::sync::Arc;
2use alloc::vec::Vec;
3use core::fmt::Display;
4
5use miden_processor::MastNodeExt;
6
7use super::Felt;
8use crate::assembly::mast::{MastForest, MastNodeId};
9use crate::utils::serde::{
10 ByteReader,
11 ByteWriter,
12 Deserializable,
13 DeserializationError,
14 Serializable,
15};
16use crate::vm::Program;
17use crate::{NoteError, PrettyPrint, Word};
18
19#[derive(Debug, Clone, PartialEq, Eq)]
27pub struct NoteScript {
28 mast: Arc<MastForest>,
29 entrypoint: MastNodeId,
30}
31
32impl NoteScript {
33 pub fn new(code: Program) -> Self {
38 Self {
39 entrypoint: code.entrypoint(),
40 mast: code.mast_forest().clone(),
41 }
42 }
43
44 pub fn from_bytes(bytes: &[u8]) -> Result<Self, NoteError> {
49 Self::read_from_bytes(bytes).map_err(NoteError::NoteScriptDeserializationError)
50 }
51
52 pub fn from_parts(mast: Arc<MastForest>, entrypoint: MastNodeId) -> Self {
57 assert!(mast.get_node_by_id(entrypoint).is_some());
58 Self { mast, entrypoint }
59 }
60
61 pub fn root(&self) -> Word {
66 self.mast[self.entrypoint].digest()
67 }
68
69 pub fn mast(&self) -> Arc<MastForest> {
71 self.mast.clone()
72 }
73
74 pub fn entrypoint(&self) -> MastNodeId {
76 self.entrypoint
77 }
78}
79
80impl From<&NoteScript> for Vec<Felt> {
84 fn from(script: &NoteScript) -> Self {
85 let mut bytes = script.mast.to_bytes();
86 let len = bytes.len();
87
88 let missing = if !len.is_multiple_of(4) { 4 - (len % 4) } else { 0 };
90 bytes.resize(bytes.len() + missing, 0);
91
92 let final_size = 2 + bytes.len();
93 let mut result = Vec::with_capacity(final_size);
94
95 result.push(Felt::from(u32::from(script.entrypoint)));
97 result.push(Felt::new(len as u64));
98
99 let mut encoded: &[u8] = &bytes;
101 while encoded.len() >= 4 {
102 let (data, rest) =
103 encoded.split_first_chunk::<4>().expect("The length has been checked");
104 let number = u32::from_le_bytes(*data);
105 result.push(Felt::new(number.into()));
106
107 encoded = rest;
108 }
109
110 result
111 }
112}
113
114impl From<NoteScript> for Vec<Felt> {
115 fn from(value: NoteScript) -> Self {
116 (&value).into()
117 }
118}
119
120impl AsRef<NoteScript> for NoteScript {
121 fn as_ref(&self) -> &NoteScript {
122 self
123 }
124}
125
126impl TryFrom<&[Felt]> for NoteScript {
130 type Error = DeserializationError;
131
132 fn try_from(elements: &[Felt]) -> Result<Self, Self::Error> {
133 if elements.len() < 2 {
134 return Err(DeserializationError::UnexpectedEOF);
135 }
136
137 let entrypoint: u32 = elements[0].try_into().map_err(DeserializationError::InvalidValue)?;
138 let len = elements[1].as_int();
139 let mut data = Vec::with_capacity(elements.len() * 4);
140
141 for &felt in &elements[2..] {
142 let v: u32 = felt.try_into().map_err(DeserializationError::InvalidValue)?;
143 data.extend(v.to_le_bytes())
144 }
145 data.shrink_to(len as usize);
146
147 let mast = MastForest::read_from_bytes(&data)?;
148 let entrypoint = MastNodeId::from_u32_safe(entrypoint, &mast)?;
149 Ok(NoteScript::from_parts(Arc::new(mast), entrypoint))
150 }
151}
152
153impl TryFrom<Vec<Felt>> for NoteScript {
154 type Error = DeserializationError;
155
156 fn try_from(value: Vec<Felt>) -> Result<Self, Self::Error> {
157 value.as_slice().try_into()
158 }
159}
160
161impl Serializable for NoteScript {
165 fn write_into<W: ByteWriter>(&self, target: &mut W) {
166 self.mast.write_into(target);
167 target.write_u32(u32::from(self.entrypoint));
168 }
169}
170
171impl Deserializable for NoteScript {
172 fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
173 let mast = MastForest::read_from(source)?;
174 let entrypoint = MastNodeId::from_u32_safe(source.read_u32()?, &mast)?;
175
176 Ok(Self::from_parts(Arc::new(mast), entrypoint))
177 }
178}
179
180impl PrettyPrint for NoteScript {
184 fn render(&self) -> miden_core::prettier::Document {
185 use miden_core::prettier::*;
186 let entrypoint = self.mast[self.entrypoint].to_pretty_print(&self.mast);
187
188 indent(4, const_text("begin") + nl() + entrypoint.render()) + nl() + const_text("end")
189 }
190}
191
192impl Display for NoteScript {
193 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
194 self.pretty_print(f)
195 }
196}
197
198#[cfg(test)]
202mod tests {
203 use super::{Felt, NoteScript, Vec};
204 use crate::assembly::Assembler;
205 use crate::testing::note::DEFAULT_NOTE_CODE;
206
207 #[test]
208 fn test_note_script_to_from_felt() {
209 let assembler = Assembler::default();
210 let tx_script_src = DEFAULT_NOTE_CODE;
211 let program = assembler.assemble_program(tx_script_src).unwrap();
212 let note_script = NoteScript::new(program);
213
214 let encoded: Vec<Felt> = (¬e_script).into();
215 let decoded: NoteScript = encoded.try_into().unwrap();
216
217 assert_eq!(note_script, decoded);
218 }
219}