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