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, NoteMetadata, Recipient};
7
8#[allow(improper_ctypes)]
9unsafe extern "C" {
10    #[link_name = "miden::protocol::active_note::get_inputs"]
11    pub fn extern_note_get_inputs(ptr: *mut Felt) -> usize;
12    #[link_name = "miden::protocol::active_note::get_assets"]
13    pub fn extern_note_get_assets(ptr: *mut Felt) -> usize;
14    #[link_name = "miden::protocol::active_note::get_sender"]
15    pub fn extern_note_get_sender(ptr: *mut AccountId);
16    #[link_name = "miden::protocol::active_note::get_recipient"]
17    pub fn extern_note_get_recipient(ptr: *mut Recipient);
18    #[link_name = "miden::protocol::active_note::get_script_root"]
19    pub fn extern_note_get_script_root(ptr: *mut Word);
20    #[link_name = "miden::protocol::active_note::get_serial_number"]
21    pub fn extern_note_get_serial_number(ptr: *mut Word);
22    #[link_name = "miden::protocol::active_note::get_metadata"]
23    pub fn extern_note_get_metadata(ptr: *mut NoteMetadata);
24}
25
26/// Get the inputs of the currently executing note.
27///
28/// # Examples
29///
30/// Parse a note input layout into domain types:
31///
32/// ```rust,ignore
33/// use miden::{active_note, AccountId, Asset};
34///
35/// let inputs = active_note::get_inputs();
36///
37/// // Example layout: first two inputs store a target `AccountId`.
38/// let target = AccountId::from(inputs[0], inputs[1]);
39/// ```
40pub fn get_inputs() -> Vec<Felt> {
41    const MAX_INPUTS: usize = 1024;
42    let mut inputs: Vec<Felt> = Vec::with_capacity(MAX_INPUTS);
43    let num_inputs = unsafe {
44        // Ensure the pointer is a valid Miden pointer
45        //
46        // NOTE: This relies on the fact that BumpAlloc makes all allocations
47        // minimally word-aligned. Each word consists of 4 elements of 4 bytes.
48        // Since Miden VM is field element-addressable, to get a Miden address from a Rust address,
49        // we divide it by 4 to get the address in field elements.
50        let ptr = (inputs.as_mut_ptr() as usize) / 4;
51        // The MASM for this function is here:
52        // https://github.com/0xMiden/miden-base/blob/3cbe8d59dcf4ccc9c380b7c8417ac6178fc6b86a/miden-lib/asm/miden/note.masm#L69-L102
53        // #! Writes the inputs of the currently execute note into memory starting at the specified
54        // address. #!
55        // #! Inputs: [dest_ptr]
56        // #! Outputs: [num_inputs, dest_ptr]
57        // #!
58        // #! - dest_ptr is the memory address to write the inputs.
59        // Compiler generated adapter code at call site will drop the returned dest_ptr
60        // and return the number of inputs
61        extern_note_get_inputs(ptr as *mut Felt)
62    };
63    unsafe {
64        inputs.set_len(num_inputs);
65    }
66    inputs
67}
68
69/// Get the assets of the currently executing note.
70pub fn get_assets() -> Vec<Asset> {
71    const MAX_INPUTS: usize = 256;
72    let mut inputs: Vec<Asset> = Vec::with_capacity(MAX_INPUTS);
73    let num_inputs = unsafe {
74        let ptr = (inputs.as_mut_ptr() as usize) / 4;
75        extern_note_get_assets(ptr as *mut Felt)
76    };
77    unsafe {
78        inputs.set_len(num_inputs);
79    }
80    inputs
81}
82
83/// Returns the sender [`AccountId`] of the note that is currently executing.
84pub fn get_sender() -> AccountId {
85    unsafe {
86        let mut ret_area = ::core::mem::MaybeUninit::<AccountId>::uninit();
87        extern_note_get_sender(ret_area.as_mut_ptr());
88        ret_area.assume_init()
89    }
90}
91
92/// Returns the recipient of the note that is currently executing.
93pub fn get_recipient() -> Recipient {
94    unsafe {
95        let mut ret_area = ::core::mem::MaybeUninit::<Recipient>::uninit();
96        extern_note_get_recipient(ret_area.as_mut_ptr());
97        let mut recipient = ret_area.assume_init();
98        recipient.inner = recipient.inner.reverse();
99        recipient
100    }
101}
102
103/// Returns the script root of the currently executing note.
104pub fn get_script_root() -> Word {
105    unsafe {
106        let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
107        extern_note_get_script_root(ret_area.as_mut_ptr());
108        ret_area.assume_init().reverse()
109    }
110}
111
112/// Returns the serial number of the currently executing note.
113pub fn get_serial_number() -> Word {
114    unsafe {
115        let mut ret_area = ::core::mem::MaybeUninit::<Word>::uninit();
116        extern_note_get_serial_number(ret_area.as_mut_ptr());
117        ret_area.assume_init().reverse()
118    }
119}
120
121/// Returns the attachment and metadata header of the note that is currently executing.
122pub fn get_metadata() -> NoteMetadata {
123    unsafe {
124        let mut ret_area = ::core::mem::MaybeUninit::<NoteMetadata>::uninit();
125        extern_note_get_metadata(ret_area.as_mut_ptr());
126        ret_area.assume_init().reverse()
127    }
128}