Skip to main content

miden_base_sys/bindings/
input_note.rs

1extern crate alloc;
2use alloc::vec::Vec;
3
4use miden_stdlib_sys::{Felt, Word, WordAligned};
5
6use super::{
7    MAX_ATTACHMENT_WORDS, MAX_ATTACHMENTS_PER_NOTE, assert_attachment_count,
8    assert_attachment_word_count,
9    types::{
10        AccountId, Asset, NoteId, NoteIdx, NoteMetadata, RawAccountId, RawCommitmentWithCount,
11        RawFoundIndex, Recipient,
12    },
13};
14
15#[allow(improper_ctypes)]
16unsafe extern "C" {
17    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
18    #[link_name = "miden::protocol::input_note::get_initial_assets_info"]
19    fn extern_input_note_get_initial_assets_info(
20        note_index: Felt,
21        ptr: *mut RawCommitmentWithCount,
22    );
23    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
24    #[link_name = "miden::protocol::input_note::get_initial_assets"]
25    fn extern_input_note_get_initial_assets(dest_ptr: *mut Felt, note_index: Felt) -> usize;
26    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
27    #[link_name = "miden::protocol::input_note::get_recipient"]
28    fn extern_input_note_get_recipient(note_index: Felt, ptr: *mut Recipient);
29    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
30    #[link_name = "miden::protocol::input_note::get_metadata"]
31    fn extern_input_note_get_metadata(note_index: Felt, ptr: *mut NoteMetadata);
32    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
33    #[link_name = "miden::protocol::input_note::get_sender"]
34    fn extern_input_note_get_sender(note_index: Felt, ptr: *mut RawAccountId);
35    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
36    #[link_name = "miden::protocol::input_note::get_storage_info"]
37    fn extern_input_note_get_storage_info(note_index: Felt, ptr: *mut RawCommitmentWithCount);
38    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
39    #[link_name = "miden::protocol::input_note::get_script_root"]
40    fn extern_input_note_get_script_root(note_index: Felt, ptr: *mut Word);
41    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
42    #[link_name = "miden::protocol::input_note::get_serial_number"]
43    fn extern_input_note_get_serial_number(note_index: Felt, ptr: *mut Word);
44    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
45    #[link_name = "miden::protocol::input_note::get_attachments_commitment"]
46    fn extern_input_note_get_attachments_commitment(note_index: Felt, ptr: *mut Word);
47    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
48    #[link_name = "miden::protocol::input_note::write_attachment_commitments_to_memory"]
49    fn extern_input_note_write_attachment_commitments_to_memory(
50        dest_ptr: *mut Felt,
51        note_index: Felt,
52    ) -> usize;
53    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
54    #[link_name = "miden::protocol::input_note::write_attachment_to_memory"]
55    fn extern_input_note_write_attachment_to_memory(
56        dest_ptr: *mut Felt,
57        attachment_idx: Felt,
58        note_index: Felt,
59    ) -> usize;
60    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
61    #[link_name = "miden::protocol::input_note::find_attachment"]
62    fn extern_input_note_find_attachment(
63        attachment_scheme: Felt,
64        note_index: Felt,
65        ptr: *mut RawFoundIndex,
66    );
67    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
68    #[link_name = "miden::protocol::input_note::get_initial_num_assets"]
69    fn extern_input_note_get_initial_num_assets(note_index: Felt) -> Felt;
70    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
71    #[link_name = "miden::protocol::input_note::get_asset"]
72    fn extern_input_note_get_asset(asset_index: Felt, note_index: Felt, ptr: *mut Asset);
73    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
74    #[link_name = "miden::protocol::input_note::remove_asset"]
75    fn extern_input_note_remove_asset(
76        asset_id_0: Felt,
77        asset_id_1: Felt,
78        asset_id_2: Felt,
79        asset_id_3: Felt,
80        asset_value_0: Felt,
81        asset_value_1: Felt,
82        asset_value_2: Felt,
83        asset_value_3: Felt,
84        note_index: Felt,
85        ptr: *mut Word,
86    );
87    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
88    #[link_name = "miden::protocol::input_note::get_note_id"]
89    fn extern_input_note_get_note_id(note_index: Felt, ptr: *mut NoteId);
90    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
91    #[link_name = "miden::protocol::input_note::find_note"]
92    fn extern_input_note_find_note(
93        note_id_0: Felt,
94        note_id_1: Felt,
95        note_id_2: Felt,
96        note_id_3: Felt,
97        ptr: *mut RawFoundIndex,
98    );
99}
100
101/// Contains summary information about the assets stored in an input note.
102pub struct InputNoteAssetsInfo {
103    pub commitment: Word,
104    pub num_assets: u32,
105}
106
107/// Contains summary information about the storage stored in an input note.
108pub struct InputNoteStorageInfo {
109    pub commitment: Word,
110    pub num_storage_items: u32,
111}
112
113/// Returns the initial assets commitment and asset count for the input note at `note_index`.
114///
115/// These describe the note's assets at creation time, unaffected by in-transaction removal.
116pub fn get_initial_assets_info(note_index: NoteIdx) -> InputNoteAssetsInfo {
117    unsafe {
118        let mut ret_area =
119            WordAligned::new(::core::mem::MaybeUninit::<RawCommitmentWithCount>::uninit());
120        extern_input_note_get_initial_assets_info(note_index.inner, ret_area.as_mut_ptr());
121        let raw = ret_area.into_inner().assume_init();
122        InputNoteAssetsInfo {
123            commitment: raw.commitment,
124            num_assets: raw.num_items(),
125        }
126    }
127}
128
129/// Returns the initial assets contained in the input note at `note_index`.
130///
131/// These are the note's assets at creation time, unaffected by in-transaction removal.
132pub fn get_initial_assets(note_index: NoteIdx) -> Vec<Asset> {
133    const MAX_ASSETS: usize = 256;
134    let mut assets: Vec<Asset> = Vec::with_capacity(MAX_ASSETS);
135    let num_assets = unsafe {
136        let ptr = (assets.as_mut_ptr() as usize) / 4;
137        extern_input_note_get_initial_assets(ptr as *mut Felt, note_index.inner)
138    };
139    unsafe {
140        assets.set_len(num_assets);
141    }
142    assets
143}
144
145/// Returns the recipient of the input note at `note_index`.
146pub fn get_recipient(note_index: NoteIdx) -> Recipient {
147    unsafe {
148        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Recipient>::uninit());
149        extern_input_note_get_recipient(note_index.inner, ret_area.as_mut_ptr());
150        ret_area.into_inner().assume_init()
151    }
152}
153
154/// Returns the metadata header of the input note at `note_index`.
155pub fn get_metadata(note_index: NoteIdx) -> NoteMetadata {
156    unsafe {
157        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteMetadata>::uninit());
158        extern_input_note_get_metadata(note_index.inner, ret_area.as_mut_ptr());
159        ret_area.into_inner().assume_init()
160    }
161}
162
163/// Returns the sender of the input note at `note_index`.
164pub fn get_sender(note_index: NoteIdx) -> AccountId {
165    unsafe {
166        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawAccountId>::uninit());
167        extern_input_note_get_sender(note_index.inner, ret_area.as_mut_ptr());
168        ret_area.into_inner().assume_init().into_account_id()
169    }
170}
171
172/// Returns the storage commitment and storage item count for the input note at `note_index`.
173pub fn get_storage_info(note_index: NoteIdx) -> InputNoteStorageInfo {
174    unsafe {
175        let mut ret_area =
176            WordAligned::new(::core::mem::MaybeUninit::<RawCommitmentWithCount>::uninit());
177        extern_input_note_get_storage_info(note_index.inner, ret_area.as_mut_ptr());
178        let raw = ret_area.into_inner().assume_init();
179        InputNoteStorageInfo {
180            commitment: raw.commitment,
181            num_storage_items: raw.num_items(),
182        }
183    }
184}
185
186/// Returns the script root of the input note at `note_index`.
187pub fn get_script_root(note_index: NoteIdx) -> Word {
188    unsafe {
189        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
190        extern_input_note_get_script_root(note_index.inner, ret_area.as_mut_ptr());
191        ret_area.into_inner().assume_init()
192    }
193}
194
195/// Returns the serial number of the input note at `note_index`.
196pub fn get_serial_number(note_index: NoteIdx) -> Word {
197    unsafe {
198        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
199        extern_input_note_get_serial_number(note_index.inner, ret_area.as_mut_ptr());
200        ret_area.into_inner().assume_init()
201    }
202}
203
204/// Returns the commitment over all attachments of the input note at `note_index`.
205pub fn get_attachments_commitment(note_index: NoteIdx) -> Word {
206    unsafe {
207        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
208        extern_input_note_get_attachments_commitment(note_index.inner, ret_area.as_mut_ptr());
209        ret_area.into_inner().assume_init()
210    }
211}
212
213/// Returns the attachment commitment of the active note when `is_active_note` is one, or of
214/// the indexed input note when it is zero.
215///
216/// # Panics
217///
218/// Panics if `is_active_note` is neither zero nor one.
219pub fn get_attachments_commitment_raw(is_active_note: Felt, note_index: NoteIdx) -> Word {
220    assert!(
221        is_active_note == Felt::from_u32(0) || is_active_note == Felt::from_u32(1),
222        "is_active_note must be zero or one"
223    );
224    if is_active_note == Felt::from_u32(1) {
225        super::active_note::get_attachments_commitment()
226    } else {
227        get_attachments_commitment(note_index)
228    }
229}
230
231/// Returns the attachment commitments of the input note at `note_index`.
232///
233/// The name mirrors the kernel procedure, which fills the buffer this function returns.
234pub fn write_attachment_commitments_to_memory(note_index: NoteIdx) -> Vec<Word> {
235    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
236    let num_attachments = unsafe {
237        let ptr = (commitments.as_mut_ptr() as usize) / 4;
238        extern_input_note_write_attachment_commitments_to_memory(ptr as *mut Felt, note_index.inner)
239    };
240    assert_attachment_count(num_attachments);
241    unsafe {
242        commitments.set_len(num_attachments);
243    }
244    commitments
245}
246
247/// Returns the attachment at `attachment_idx` of the input note at `note_index` as protocol words.
248///
249/// The name mirrors the kernel procedure, which fills the buffer this function returns.
250pub fn write_attachment_to_memory(note_index: NoteIdx, attachment_idx: u32) -> Vec<Word> {
251    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
252    let num_words = unsafe {
253        let ptr = (attachment.as_mut_ptr() as usize) / 4;
254        extern_input_note_write_attachment_to_memory(
255            ptr as *mut Felt,
256            Felt::from_u32(attachment_idx),
257            note_index.inner,
258        )
259    };
260    assert_attachment_word_count(num_words);
261    unsafe {
262        attachment.set_len(num_words);
263    }
264    attachment
265}
266
267/// Searches the input note metadata for `attachment_scheme`.
268pub fn find_attachment(note_index: NoteIdx, attachment_scheme: Felt) -> Option<u32> {
269    unsafe {
270        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawFoundIndex>::uninit());
271        extern_input_note_find_attachment(
272            attachment_scheme,
273            note_index.inner,
274            ret_area.as_mut_ptr(),
275        );
276        ret_area.into_inner().assume_init().into_attachment_index()
277    }
278}
279
280/// Returns the number of assets the input note at `note_index` was created with.
281///
282/// The count is unaffected by in-transaction removal.
283#[inline]
284pub fn get_initial_num_assets(note_index: NoteIdx) -> u32 {
285    // The transaction kernel guarantees asset counts fit in a u32.
286    let count = unsafe { extern_input_note_get_initial_num_assets(note_index.inner) };
287    count.as_canonical_u64() as u32
288}
289
290/// Returns the asset at `asset_index` in the input note at `note_index`.
291///
292/// The asset is returned as it currently is: an asset that was already removed from the note reads
293/// back with both words empty.
294///
295/// # Panics
296///
297/// Panics if either index is out of bounds.
298pub fn get_asset(note_index: NoteIdx, asset_index: u32) -> Asset {
299    unsafe {
300        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Asset>::uninit());
301        extern_input_note_get_asset(
302            Felt::from_u32(asset_index),
303            note_index.inner,
304            ret_area.as_mut_ptr(),
305        );
306        ret_area.into_inner().assume_init()
307    }
308}
309
310/// Removes `asset` from the input note at `note_index` and returns the asset value left in it.
311///
312/// The returned value is empty when the entire asset was removed.
313///
314/// # Panics
315///
316/// Panics if `note_index` is out of bounds, if the call does not originate from the native
317/// account's context, if the asset is not present in the note, if a non-composable asset is not
318/// present with the exact value, if the note holds less of a fungible asset than is removed, if the
319/// asset id is empty or malformed, or if the asset's composition is `Custom`.
320pub fn remove_asset(note_index: NoteIdx, asset: Asset) -> Word {
321    unsafe {
322        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
323        let id = asset.id.inner;
324        extern_input_note_remove_asset(
325            id[0],
326            id[1],
327            id[2],
328            id[3],
329            asset.value[0],
330            asset.value[1],
331            asset.value[2],
332            asset.value[3],
333            note_index.inner,
334            ret_area.as_mut_ptr(),
335        );
336        ret_area.into_inner().assume_init()
337    }
338}
339
340/// Returns the ID of the input note at `note_index`, as cached by the transaction prologue.
341pub fn get_note_id(note_index: NoteIdx) -> NoteId {
342    unsafe {
343        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteId>::uninit());
344        extern_input_note_get_note_id(note_index.inner, ret_area.as_mut_ptr());
345        ret_area.into_inner().assume_init()
346    }
347}
348
349/// Returns the index of the input note with the given ID, or `None` when the transaction does not
350/// consume it.
351///
352/// # Panics
353///
354/// Panics if the host's answer contradicts the transaction's input notes: it reports an index
355/// whose note has a different ID, or reports the note as absent although it is consumed.
356pub fn find_note(note_id: NoteId) -> Option<NoteIdx> {
357    unsafe {
358        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawFoundIndex>::uninit());
359        let id = note_id.inner;
360        extern_input_note_find_note(id[0], id[1], id[2], id[3], ret_area.as_mut_ptr());
361        ret_area.into_inner().assume_init().into_note_index()
362    }
363}