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::{AccountId, Asset, AttachmentLocation, NoteMetadata, RawAccountId, Recipient};
7
8const MAX_ATTACHMENTS_PER_NOTE: usize = 4;
9const MAX_ATTACHMENT_WORDS: usize = 256;
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_assets"]
19    fn extern_note_get_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 AttachmentLocation);
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 assets of the currently executing note.
91pub fn get_assets() -> Vec<Asset> {
92    const MAX_INPUTS: usize = 256;
93    let mut inputs: Vec<Asset> = Vec::with_capacity(MAX_INPUTS);
94    let num_inputs = unsafe {
95        let ptr = (inputs.as_mut_ptr() as usize) / 4;
96        extern_note_get_assets(ptr as *mut Felt)
97    };
98    unsafe {
99        inputs.set_len(num_inputs);
100    }
101    inputs
102}
103
104/// Returns the sender [`AccountId`] of the note that is currently executing.
105pub fn get_sender() -> AccountId {
106    unsafe {
107        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawAccountId>::uninit());
108        extern_note_get_sender(ret_area.as_mut_ptr());
109        ret_area.into_inner().assume_init().into_account_id()
110    }
111}
112
113/// Returns the recipient of the note that is currently executing.
114pub fn get_recipient() -> Recipient {
115    unsafe {
116        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Recipient>::uninit());
117        extern_note_get_recipient(ret_area.as_mut_ptr());
118        ret_area.into_inner().assume_init()
119    }
120}
121
122/// Returns the script root of the currently executing note.
123pub fn get_script_root() -> Word {
124    unsafe {
125        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
126        extern_note_get_script_root(ret_area.as_mut_ptr());
127        ret_area.into_inner().assume_init()
128    }
129}
130
131/// Returns the serial number of the currently executing note.
132pub fn get_serial_number() -> Word {
133    unsafe {
134        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
135        extern_note_get_serial_number(ret_area.as_mut_ptr());
136        ret_area.into_inner().assume_init()
137    }
138}
139
140/// Returns the metadata header of the note that is currently executing.
141pub fn get_metadata() -> NoteMetadata {
142    unsafe {
143        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteMetadata>::uninit());
144        extern_note_get_metadata(ret_area.as_mut_ptr());
145        ret_area.into_inner().assume_init()
146    }
147}
148
149/// Returns whether the note currently executing is public.
150#[inline]
151pub fn is_public() -> bool {
152    unsafe { extern_note_is_public() != Felt::new(0).unwrap() }
153}
154
155/// Returns whether the note currently executing is private.
156#[inline]
157pub fn is_private() -> bool {
158    unsafe { extern_note_is_private() != Felt::new(0).unwrap() }
159}
160
161/// Returns the commitment over all attachments of the note currently executing.
162pub fn get_attachments_commitment() -> Word {
163    unsafe {
164        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
165        extern_note_get_attachments_commitment(ret_area.as_mut_ptr());
166        ret_area.into_inner().assume_init()
167    }
168}
169
170/// Writes attachment commitments to memory and returns them as protocol words.
171pub fn write_attachment_commitments_to_memory() -> Vec<Word> {
172    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
173    let num_attachments = unsafe {
174        let ptr = (commitments.as_mut_ptr() as usize) / 4;
175        extern_note_write_attachment_commitments_to_memory(ptr as *mut Felt)
176    };
177    assert!(
178        num_attachments <= MAX_ATTACHMENTS_PER_NOTE,
179        "note cannot contain more than {MAX_ATTACHMENTS_PER_NOTE} attachments"
180    );
181    unsafe {
182        commitments.set_len(num_attachments);
183    }
184    commitments
185}
186
187/// Writes the selected attachment to memory and returns it as protocol words.
188pub fn write_attachment_to_memory(attachment_idx: Felt) -> Vec<Word> {
189    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
190    let num_words = unsafe {
191        let ptr = (attachment.as_mut_ptr() as usize) / 4;
192        extern_note_write_attachment_to_memory(ptr as *mut Felt, attachment_idx)
193    };
194    assert!(
195        num_words <= MAX_ATTACHMENT_WORDS,
196        "note attachment cannot contain more than {MAX_ATTACHMENT_WORDS} words"
197    );
198    unsafe {
199        attachment.set_len(num_words);
200    }
201    attachment
202}
203
204/// Searches the active note metadata for `attachment_scheme`.
205pub fn find_attachment(attachment_scheme: Felt) -> AttachmentLocation {
206    unsafe {
207        let mut ret_area =
208            WordAligned::new(::core::mem::MaybeUninit::<AttachmentLocation>::uninit());
209        extern_note_find_attachment(attachment_scheme, ret_area.as_mut_ptr());
210        ret_area.into_inner().assume_init()
211    }
212}