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