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