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}