Skip to main content

miden_base_sys/bindings/
output_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        Asset, NoteId, NoteIdx, NoteMetadata, NoteType, RawCommitmentWithCount, RawFoundIndex,
11        Recipient, Tag,
12    },
13};
14
15#[allow(improper_ctypes)]
16unsafe extern "C" {
17    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
18    #[link_name = "miden::protocol::output_note::create"]
19    pub fn extern_output_note_create(
20        tag: Tag,
21        note_type: NoteType,
22        recipient_f0: Felt,
23        recipient_f1: Felt,
24        recipient_f2: Felt,
25        recipient_f3: Felt,
26    ) -> NoteIdx;
27    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
28    #[link_name = "miden::protocol::output_note::add_asset"]
29    pub fn extern_output_note_add_asset(
30        asset_id_f0: Felt,
31        asset_id_f1: Felt,
32        asset_id_f2: Felt,
33        asset_id_f3: Felt,
34        asset_value_f0: Felt,
35        asset_value_f1: Felt,
36        asset_value_f2: Felt,
37        asset_value_f3: Felt,
38        note_idx: NoteIdx,
39    );
40    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
41    #[link_name = "miden::protocol::output_note::get_assets_info"]
42    pub(crate) fn extern_output_note_get_assets_info(
43        note_index: Felt,
44        ptr: *mut RawCommitmentWithCount,
45    );
46    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
47    #[link_name = "miden::protocol::output_note::get_assets"]
48    pub fn extern_output_note_get_assets(dest_ptr: *mut Felt, note_index: Felt) -> usize;
49    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
50    #[link_name = "miden::protocol::output_note::get_attachments_commitment"]
51    pub fn extern_output_note_get_attachments_commitment(note_index: Felt, ptr: *mut Word);
52    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
53    #[link_name = "miden::protocol::output_note::get_recipient"]
54    pub fn extern_output_note_get_recipient(note_index: Felt, ptr: *mut Recipient);
55    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
56    #[link_name = "miden::protocol::output_note::get_metadata"]
57    pub fn extern_output_note_get_metadata(note_index: Felt, ptr: *mut NoteMetadata);
58    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
59    #[link_name = "miden::protocol::output_note::add_word_attachment"]
60    pub fn extern_output_note_add_word_attachment(
61        attachment_scheme: Felt,
62        attachment_f0: Felt,
63        attachment_f1: Felt,
64        attachment_f2: Felt,
65        attachment_f3: Felt,
66        note_idx: NoteIdx,
67    );
68    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
69    #[link_name = "miden::protocol::output_note::add_attachment"]
70    pub fn extern_output_note_add_attachment(
71        attachment_scheme: Felt,
72        attachment_f0: Felt,
73        attachment_f1: Felt,
74        attachment_f2: Felt,
75        attachment_f3: Felt,
76        note_idx: NoteIdx,
77    );
78    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
79    #[link_name = "miden::protocol::output_note::add_attachment_from_memory"]
80    pub fn extern_output_note_add_attachment_from_memory(
81        attachment_scheme: Felt,
82        num_words: usize,
83        attachment_ptr: *const Felt,
84        note_idx: NoteIdx,
85    );
86    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
87    #[link_name = "miden::protocol::output_note::find_attachment"]
88    pub(crate) fn extern_output_note_find_attachment(
89        attachment_scheme: Felt,
90        note_index: Felt,
91        ptr: *mut RawFoundIndex,
92    );
93    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
94    #[link_name = "miden::protocol::output_note::write_attachment_commitments_to_memory"]
95    pub fn extern_output_note_write_attachment_commitments_to_memory(
96        dest_ptr: *mut Felt,
97        note_index: Felt,
98    ) -> usize;
99    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
100    #[link_name = "miden::protocol::output_note::write_attachment_to_memory"]
101    pub fn extern_output_note_write_attachment_to_memory(
102        dest_ptr: *mut Felt,
103        attachment_idx: Felt,
104        note_index: Felt,
105    ) -> usize;
106    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
107    #[link_name = "miden::protocol::output_note::compute_note_id"]
108    fn extern_output_note_compute_note_id(note_idx: Felt, ptr: *mut NoteId);
109    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
110    #[link_name = "miden::protocol::output_note::seal"]
111    fn extern_output_note_seal(note_index: Felt);
112    #[cfg_attr(target_family = "wasm", linkage = "extern_weak")]
113    #[link_name = "miden::protocol::output_note::is_sealed"]
114    fn extern_output_note_is_sealed(note_index: Felt) -> Felt;
115}
116
117/// Creates a new output note and returns its index.
118///
119/// # Examples
120///
121/// Create a note and add a single asset to it:
122///
123/// ```rust,ignore
124/// // before using `Vec`/`vec!`.
125/// extern crate alloc;
126///
127/// use miden::{felt, note, output_note, Asset, NoteType, Tag, Word};
128///
129/// // Values used to derive the note recipient.
130/// let serial_num = Word::from_u64_unchecked(1, 2, 3, 4);
131/// let note_script_root = Word::from_u64_unchecked(0, 0, 0, 0);
132///
133/// let storage = alloc::vec![felt!(0); 2];
134/// let recipient = note::build_recipient(serial_num, note_script_root, storage);
135///
136/// let tag = Tag::from(felt!(0));
137/// let note_type = NoteType::from(felt!(1)); // public note type (0b01)
138///
139/// let note_idx = output_note::create(tag, note_type, recipient);
140/// output_note::add_asset(
141///     Asset::new(
142///         [felt!(0), felt!(0), felt!(0), felt!(1)],
143///         [felt!(1), felt!(0), felt!(0), felt!(0)],
144///     ),
145///     note_idx,
146/// );
147/// ```
148pub fn create(tag: Tag, note_type: NoteType, recipient: Recipient) -> NoteIdx {
149    unsafe {
150        extern_output_note_create(
151            tag,
152            note_type,
153            recipient.inner[0],
154            recipient.inner[1],
155            recipient.inner[2],
156            recipient.inner[3],
157        )
158    }
159}
160
161/// Adds a single-word attachment to the output note specified by `note_idx`.
162pub fn add_word_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
163    unsafe {
164        extern_output_note_add_word_attachment(
165            attachment_scheme,
166            attachment[0],
167            attachment[1],
168            attachment[2],
169            attachment[3],
170            note_idx,
171        );
172    }
173}
174
175/// Adds an attachment commitment to the output note specified by `note_idx`.
176///
177/// The advice map must contain an entry for the attachment elements committed to by `attachment`.
178pub fn add_attachment(note_idx: NoteIdx, attachment_scheme: Felt, attachment: Word) {
179    unsafe {
180        extern_output_note_add_attachment(
181            attachment_scheme,
182            attachment[0],
183            attachment[1],
184            attachment[2],
185            attachment[3],
186            note_idx,
187        );
188    }
189}
190
191/// Adds a multi-word attachment from linear memory to the output note specified by `note_idx`.
192///
193/// Panics if `attachment` is empty or contains more than `MAX_ATTACHMENT_WORDS` (256) words;
194/// the kernel rejects both.
195pub fn add_attachment_from_memory(note_idx: NoteIdx, attachment_scheme: Felt, attachment: &[Word]) {
196    assert!(!attachment.is_empty(), "note attachment cannot be empty");
197    assert_attachment_word_count(attachment.len());
198    let ptr = (attachment.as_ptr().addr() / 4) as u32;
199
200    unsafe {
201        extern_output_note_add_attachment_from_memory(
202            attachment_scheme,
203            attachment.len(),
204            ptr as *const Felt,
205            note_idx,
206        );
207    }
208}
209
210/// Adds the asset to the output note specified by `note_idx`.
211///
212/// # Examples
213///
214/// ```rust,ignore
215/// use miden::{felt, output_note, Asset, NoteIdx, Word};
216///
217/// // `note_idx` is returned by `output_note::create(...)`.
218/// let note_idx: NoteIdx = /* ... */
219///
220/// let asset = Asset::new(
221///     [felt!(0), felt!(0), felt!(0), felt!(1)],
222///     [felt!(1), felt!(0), felt!(0), felt!(0)],
223/// );
224/// output_note::add_asset(asset, note_idx);
225/// ```
226pub fn add_asset(asset: Asset, note_idx: NoteIdx) {
227    let id = asset.id.inner;
228    unsafe {
229        extern_output_note_add_asset(
230            id[0],
231            id[1],
232            id[2],
233            id[3],
234            asset.value[0],
235            asset.value[1],
236            asset.value[2],
237            asset.value[3],
238            note_idx,
239        );
240    }
241}
242
243/// Seals the output note at `note_index`, so that its assets and attachments can no longer be
244/// changed for the rest of the transaction.
245///
246/// Sealing an already sealed note has no effect.
247///
248/// # Panics
249///
250/// Panics if the active account is not the native account, or if `note_index` is out of bounds
251/// for the transaction's output notes.
252pub fn seal(note_index: NoteIdx) {
253    unsafe { extern_output_note_seal(note_index.inner) }
254}
255
256/// Returns `true` if the output note at `note_index` is sealed against asset and attachment
257/// changes.
258///
259/// # Panics
260///
261/// Panics if `note_index` is out of bounds for the transaction's output notes.
262pub fn is_sealed(note_index: NoteIdx) -> bool {
263    unsafe { extern_output_note_is_sealed(note_index.inner) != Felt::new(0).unwrap() }
264}
265
266/// Contains summary information about the assets of an output note.
267pub struct OutputNoteAssetsInfo {
268    pub commitment: Word,
269    pub num_assets: u32,
270}
271
272/// Retrieves the assets commitment and asset count for the output note at `note_index`.
273pub fn get_assets_info(note_index: NoteIdx) -> OutputNoteAssetsInfo {
274    unsafe {
275        let mut ret_area =
276            WordAligned::new(::core::mem::MaybeUninit::<RawCommitmentWithCount>::uninit());
277        extern_output_note_get_assets_info(note_index.inner, ret_area.as_mut_ptr());
278        let raw = ret_area.into_inner().assume_init();
279        OutputNoteAssetsInfo {
280            commitment: raw.commitment,
281            num_assets: raw.num_items(),
282        }
283    }
284}
285
286/// Returns the assets contained in the output note at `note_index`.
287pub fn get_assets(note_index: NoteIdx) -> Vec<Asset> {
288    const MAX_ASSETS: usize = 256;
289    let mut assets: Vec<Asset> = Vec::with_capacity(MAX_ASSETS);
290    let num_assets = unsafe {
291        let ptr = (assets.as_mut_ptr() as usize) / 4;
292        extern_output_note_get_assets(ptr as *mut Felt, note_index.inner)
293    };
294    unsafe {
295        assets.set_len(num_assets);
296    }
297    assets
298}
299
300/// Returns the commitment over all attachments of the output note at `note_index`.
301pub fn get_attachments_commitment(note_index: NoteIdx) -> Word {
302    unsafe {
303        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Word>::uninit());
304        extern_output_note_get_attachments_commitment(note_index.inner, ret_area.as_mut_ptr());
305        ret_area.into_inner().assume_init()
306    }
307}
308
309/// Returns the recipient of the output note at `note_index`.
310pub fn get_recipient(note_index: NoteIdx) -> Recipient {
311    unsafe {
312        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<Recipient>::uninit());
313        extern_output_note_get_recipient(note_index.inner, ret_area.as_mut_ptr());
314        ret_area.into_inner().assume_init()
315    }
316}
317
318/// Returns the metadata header of the output note at `note_index`.
319pub fn get_metadata(note_index: NoteIdx) -> NoteMetadata {
320    unsafe {
321        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteMetadata>::uninit());
322        extern_output_note_get_metadata(note_index.inner, ret_area.as_mut_ptr());
323        ret_area.into_inner().assume_init()
324    }
325}
326
327/// Searches the output note metadata for `attachment_scheme`.
328pub fn find_attachment(note_index: NoteIdx, attachment_scheme: Felt) -> Option<u32> {
329    unsafe {
330        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<RawFoundIndex>::uninit());
331        extern_output_note_find_attachment(
332            attachment_scheme,
333            note_index.inner,
334            ret_area.as_mut_ptr(),
335        );
336        ret_area.into_inner().assume_init().into_attachment_index()
337    }
338}
339
340/// Returns the attachment commitments of the output note at `note_index`.
341///
342/// The name mirrors the kernel procedure, which fills the buffer this function returns.
343pub fn write_attachment_commitments_to_memory(note_index: NoteIdx) -> Vec<Word> {
344    let mut commitments: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENTS_PER_NOTE);
345    let num_attachments = unsafe {
346        let ptr = (commitments.as_mut_ptr() as usize) / 4;
347        extern_output_note_write_attachment_commitments_to_memory(
348            ptr as *mut Felt,
349            note_index.inner,
350        )
351    };
352    assert_attachment_count(num_attachments);
353    unsafe {
354        commitments.set_len(num_attachments);
355    }
356    commitments
357}
358
359/// Returns the attachment at `attachment_idx` of the output note at `note_index` as protocol
360/// words.
361///
362/// The name mirrors the kernel procedure, which fills the buffer this function returns.
363pub fn write_attachment_to_memory(note_index: NoteIdx, attachment_idx: u32) -> Vec<Word> {
364    let mut attachment: Vec<Word> = Vec::with_capacity(MAX_ATTACHMENT_WORDS);
365    let num_words = unsafe {
366        let ptr = (attachment.as_mut_ptr() as usize) / 4;
367        extern_output_note_write_attachment_to_memory(
368            ptr as *mut Felt,
369            Felt::from_u32(attachment_idx),
370            note_index.inner,
371        )
372    };
373    assert_attachment_word_count(num_words);
374    unsafe {
375        attachment.set_len(num_words);
376    }
377    attachment
378}
379
380/// Computes the ID of the output note at `note_index`.
381///
382/// The ID is only final once the note has been fully constructed, that is, once all of its assets
383/// and attachments have been added.
384///
385/// # Panics
386///
387/// Panics if `note_index` is out of bounds for the transaction's output notes.
388pub fn compute_note_id(note_index: NoteIdx) -> NoteId {
389    unsafe {
390        let mut ret_area = WordAligned::new(::core::mem::MaybeUninit::<NoteId>::uninit());
391        extern_output_note_compute_note_id(note_index.inner, ret_area.as_mut_ptr());
392        ret_area.into_inner().assume_init()
393    }
394}