Skip to main content

miden_base_sys/bindings/
active_note.rs

1extern crate alloc;
2use alloc::vec::Vec;
3
4use miden_stdlib_sys::{Felt, Word, WordAligned};
5
6use super::{
7    AccountId, Asset, MAX_ATTACHMENT_WORDS, MAX_ATTACHMENTS_PER_NOTE, NoteMetadata, RawAccountId,
8    RawAttachmentLocation, Recipient, assert_attachment_count, assert_attachment_word_count,
9};
10
11#[allow(improper_ctypes)]
12unsafe extern "C" {
13    // NOTE: In protocol v0.14, note "inputs" are exposed via `active_note::get_storage`.
14    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
15    #[link_name = "miden::protocol::active_note::get_storage"]
16    fn extern_note_get_storage(ptr: *mut Felt) -> usize;
17    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
18    #[link_name = "miden::protocol::active_note::get_initial_assets"]
19    fn extern_note_get_initial_assets(ptr: *mut Felt) -> usize;
20    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
21    #[link_name = "miden::protocol::active_note::get_sender"]
22    fn extern_note_get_sender(ptr: *mut RawAccountId);
23    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
24    #[link_name = "miden::protocol::active_note::get_recipient"]
25    fn extern_note_get_recipient(ptr: *mut Recipient);
26    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
27    #[link_name = "miden::protocol::active_note::get_script_root"]
28    fn extern_note_get_script_root(ptr: *mut Word);
29    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
30    #[link_name = "miden::protocol::active_note::get_serial_number"]
31    fn extern_note_get_serial_number(ptr: *mut Word);
32    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
33    #[link_name = "miden::protocol::active_note::get_metadata"]
34    fn extern_note_get_metadata(ptr: *mut NoteMetadata);
35    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
36    #[link_name = "miden::protocol::active_note::is_public"]
37    fn extern_note_is_public() -> Felt;
38    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
39    #[link_name = "miden::protocol::active_note::is_private"]
40    fn extern_note_is_private() -> Felt;
41    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
42    #[link_name = "miden::protocol::active_note::get_attachments_commitment"]
43    fn extern_note_get_attachments_commitment(ptr: *mut Word);
44    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
45    #[link_name = "miden::protocol::active_note::write_attachment_commitments_to_memory"]
46    fn extern_note_write_attachment_commitments_to_memory(dest_ptr: *mut Felt) -> usize;
47    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
48    #[link_name = "miden::protocol::active_note::write_attachment_to_memory"]
49    fn extern_note_write_attachment_to_memory(dest_ptr: *mut Felt, attachment_idx: Felt) -> usize;
50    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
51    #[link_name = "miden::protocol::active_note::find_attachment"]
52    fn extern_note_find_attachment(attachment_scheme: Felt, ptr: *mut RawAttachmentLocation);
53}
54
55/// Returns the storage of the currently executing note.
56///
57/// # Examples
58///
59/// Parse a note storage layout into domain types:
60///
61/// ```rust,ignore
62/// use miden::{active_note, AccountId, Asset};
63///
64/// let storage = active_note::get_storage();
65///
66/// // Example layout: first two values store a target `AccountId`.
67/// let target = AccountId::from(storage[0], storage[1]);
68/// ```
69pub fn get_storage() -> Vec<Felt> {
70    const MAX_INPUTS: usize = 1024;
71    let mut inputs: Vec<Felt> = Vec::with_capacity(MAX_INPUTS);
72    let num_inputs = unsafe {
73        // Ensure the pointer is a valid Miden pointer
74        //
75        // NOTE: This relies on the fact that BumpAlloc makes all allocations
76        // minimally word-aligned. Each word consists of 4 elements of 4 bytes.
77        // Since Miden VM is field element-addressable, to get a Miden address from a Rust address,
78        // we divide it by 4 to get the address in field elements.
79        let ptr = (inputs.as_mut_ptr() as usize) / 4;
80        // The protocol `active_note::get_storage` procedure writes the note's storage into memory
81        // starting at `dest_ptr` and returns the number of storage items written.
82        extern_note_get_storage(ptr as *mut Felt)
83    };
84    unsafe {
85        inputs.set_len(num_inputs);
86    }
87    inputs
88}
89
90/// Get the initial assets of the currently executing note.
91///
92/// These are the note's assets at creation time, unaffected by in-transaction removal.
93pub fn get_initial_assets() -> Vec<Asset> {
94    const MAX_INPUTS: usize = 256;
95    let mut inputs: Vec<Asset> = Vec::with_capacity(MAX_INPUTS);
96    let num_inputs = unsafe {
97        let ptr = (inputs.as_mut_ptr() as usize) / 4;
98        extern_note_get_initial_assets(ptr as *mut Felt)
99    };
100    unsafe {
101        inputs.set_len(num_inputs);
102    }
103    inputs
104}
105
106/// Returns the sender [`AccountId`] of the note that is currently executing.
107pub fn get_sender() -> AccountId {
108    unsafe {
109        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawAccountId>::uninit());
110        extern_note_get_sender(ret_area.as_mut_ptr());
111        ret_area.into_inner().assume_init().into_account_id()
112    }
113}
114
115/// Returns the recipient of the note that is currently executing.
116pub fn get_recipient() -> Recipient {
117    unsafe {
118        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Recipient>::uninit());
119        extern_note_get_recipient(ret_area.as_mut_ptr());
120        ret_area.into_inner().assume_init()
121    }
122}
123
124/// Returns the script root of the currently executing note.
125pub fn get_script_root() -> Word {
126    unsafe {
127        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
128        extern_note_get_script_root(ret_area.as_mut_ptr());
129        ret_area.into_inner().assume_init()
130    }
131}
132
133/// Returns the serial number of the currently executing note.
134pub fn get_serial_number() -> Word {
135    unsafe {
136        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
137        extern_note_get_serial_number(ret_area.as_mut_ptr());
138        ret_area.into_inner().assume_init()
139    }
140}
141
142/// Returns the metadata header of the note that is currently executing.
143pub fn get_metadata() -> NoteMetadata {
144    unsafe {
145        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteMetadata>::uninit());
146        extern_note_get_metadata(ret_area.as_mut_ptr());
147        ret_area.into_inner().assume_init()
148    }
149}
150
151/// Returns whether the note currently executing is public.
152#[inline]
153pub fn is_public() -> bool {
154    unsafe { extern_note_is_public() != Felt::new(0).unwrap() }
155}
156
157/// Returns whether the note currently executing is private.
158#[inline]
159pub fn is_private() -> bool {
160    unsafe { extern_note_is_private() != Felt::new(0).unwrap() }
161}
162
163/// Returns the commitment over all attachments of the note currently executing.
164pub fn get_attachments_commitment() -> Word {
165    unsafe {
166        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
167        extern_note_get_attachments_commitment(ret_area.as_mut_ptr());
168        ret_area.into_inner().assume_init()
169    }
170}
171
172/// Writes attachment commitments to memory and returns them as protocol words.
173pub fn write_attachment_commitments_to_memory() -> Vec<Word> {
174    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
175    let num_attachments = unsafe {
176        let ptr = (commitments.as_mut_ptr() as usize) / 4;
177        extern_note_write_attachment_commitments_to_memory(ptr as *mut Felt)
178    };
179    assert_attachment_count(num_attachments);
180    unsafe {
181        commitments.set_len(num_attachments);
182    }
183    commitments
184}
185
186/// Writes the selected attachment to memory and returns it as protocol words.
187pub fn write_attachment_to_memory(attachment_idx: u32) -> Vec<Word> {
188    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
189    let num_words = unsafe {
190        let ptr = (attachment.as_mut_ptr() as usize) / 4;
191        extern_note_write_attachment_to_memory(ptr as *mut Felt, Felt::from_u32(attachment_idx))
192    };
193    assert_attachment_word_count(num_words);
194    unsafe {
195        attachment.set_len(num_words);
196    }
197    attachment
198}
199
200/// Searches the active note metadata for `attachment_scheme`.
201pub fn find_attachment(attachment_scheme: Felt) -> Option<u32> {
202    unsafe {
203        let mut ret_area =
204            WordAligned::new(::core::mem::MaybeUninit::<RawAttachmentLocation>::uninit());
205        extern_note_find_attachment(attachment_scheme, ret_area.as_mut_ptr());
206        ret_area.into_inner().assume_init().into_attachment_index()
207    }
208}
209
210/// Trait that provides active-note operations for note scripts.
211///
212/// This trait is automatically implemented for the note input struct marked with the `#[note]`
213/// macro, so a `#[note_script]` entrypoint can call the operations directly on `self`, e.g.
214/// `self.get_sender()`.
215///
216/// The operations read the note that is currently executing. Call them only during note-script
217/// execution: a note value constructed outside of it (for example in a `#[note_constructor]`)
218/// has no active note, and the transaction kernel rejects the calls at run time.
219///
220/// `get_storage` is intentionally not part of this trait: the `#[note]` macro decodes the note
221/// storage into the struct fields, so the values are available directly on `self`.
222///
223/// An inherent method of the note struct with the same name shadows the trait method; the trait
224/// method stays reachable with UFCS, e.g. `<MyNote as ActiveNote>::get_sender(&note)`.
225pub trait ActiveNote {
226    /// Get the initial assets of the currently executing note.
227    ///
228    /// These are the note's assets at creation time, unaffected by in-transaction removal.
229    #[inline]
230    fn get_initial_assets(&self) -> Vec<Asset> {
231        get_initial_assets()
232    }
233
234    /// Returns the sender [`AccountId`] of the note that is currently executing.
235    #[inline]
236    fn get_sender(&self) -> AccountId {
237        get_sender()
238    }
239
240    /// Returns the recipient of the note that is currently executing.
241    #[inline]
242    fn get_recipient(&self) -> Recipient {
243        get_recipient()
244    }
245
246    /// Returns the script root of the currently executing note.
247    #[inline]
248    fn get_script_root(&self) -> Word {
249        get_script_root()
250    }
251
252    /// Returns the serial number of the currently executing note.
253    #[inline]
254    fn get_serial_number(&self) -> Word {
255        get_serial_number()
256    }
257
258    /// Returns the metadata header of the note that is currently executing.
259    #[inline]
260    fn get_metadata(&self) -> NoteMetadata {
261        get_metadata()
262    }
263
264    /// Returns whether the note currently executing is public.
265    #[inline]
266    fn is_public(&self) -> bool {
267        is_public()
268    }
269
270    /// Returns whether the note currently executing is private.
271    #[inline]
272    fn is_private(&self) -> bool {
273        is_private()
274    }
275
276    /// Returns the commitment over all attachments of the note currently executing.
277    #[inline]
278    fn get_attachments_commitment(&self) -> Word {
279        get_attachments_commitment()
280    }
281
282    /// Writes attachment commitments to memory and returns them as protocol words.
283    #[inline]
284    fn write_attachment_commitments_to_memory(&self) -> Vec<Word> {
285        write_attachment_commitments_to_memory()
286    }
287
288    /// Writes the selected attachment to memory and returns it as protocol words.
289    #[inline]
290    fn write_attachment_to_memory(&self, attachment_idx: u32) -> Vec<Word> {
291        write_attachment_to_memory(attachment_idx)
292    }
293
294    /// Searches the active note metadata for `attachment_scheme`.
295    #[inline]
296    fn find_attachment(&self, attachment_scheme: Felt) -> Option<u32> {
297        find_attachment(attachment_scheme)
298    }
299}