Skip to main content

miden_protocol/note/
mod.rs

1use miden_crypto::Word;
2
3use crate::account::AccountId;
4use crate::errors::NoteError;
5use crate::utils::serde::{
6    ByteReader,
7    ByteWriter,
8    Deserializable,
9    DeserializationError,
10    Serializable,
11};
12use crate::{Felt, Hasher, ZERO};
13
14mod assets;
15pub use assets::NoteAssets;
16
17mod details;
18pub use details::NoteDetails;
19
20mod header;
21pub use header::NoteHeader;
22
23mod storage;
24pub use storage::NoteStorage;
25
26mod metadata;
27pub use metadata::{NoteMetadata, PartialNoteMetadata};
28
29mod attachment;
30pub use attachment::{
31    NoteAttachment,
32    NoteAttachmentContent,
33    NoteAttachmentHeader,
34    NoteAttachmentScheme,
35    NoteAttachments,
36};
37
38mod note_id;
39pub use note_id::NoteId;
40
41mod note_details_commitment;
42pub use note_details_commitment::NoteDetailsCommitment;
43
44mod note_tag;
45pub use note_tag::NoteTag;
46
47mod note_type;
48pub use note_type::NoteType;
49
50mod nullifier;
51pub use nullifier::Nullifier;
52
53mod location;
54pub use location::{NoteInclusionProof, NoteLocation};
55
56mod partial;
57pub use partial::PartialNote;
58
59mod recipient;
60pub use recipient::NoteRecipient;
61
62mod script;
63pub use script::{NoteScript, NoteScriptRoot};
64
65// NOTE
66// ================================================================================================
67
68/// A note with all the data required for it to be consumed by executing it against the transaction
69/// kernel.
70///
71/// Notes consist of note metadata, attachments and details. Note metadata and attachments are
72/// always public, but details are either private or public, depending on the note type. Note
73/// details consist of note assets, script, storage, and a serial number, the three latter grouped
74/// into a recipient object.
75///
76/// Note details can be reduced to a [NoteDetailsCommitment]. Together with the note metadata,
77/// this commitment determines the public [NoteId]. Full note details and metadata can also be
78/// reduced to a [Nullifier], which is known only to entities which have access to full note data.
79///
80/// Fungible and non-fungible asset transfers are done by moving assets to the note's assets. The
81/// note's script determines the conditions required for the note consumption, i.e. the target
82/// account of a P2ID or conditions of a SWAP, and the effects of the note. The serial number has
83/// a double duty of preventing double spend, and providing unlikability to the consumer of a note.
84/// The note's storage allows for customization of its script.
85///
86/// To create a note, the kernel does not require all the information above, a user can create a
87/// note only with the commitment to the script, storage, the serial number (i.e., the recipient),
88/// and the kernel only verifies the source account has the assets necessary for the note creation.
89/// See [NoteRecipient] for more details.
90#[derive(Clone, Debug, PartialEq, Eq)]
91pub struct Note {
92    header: NoteHeader,
93    details: NoteDetails,
94    attachments: NoteAttachments,
95
96    nullifier: Nullifier,
97}
98
99impl Note {
100    // CONSTRUCTOR
101    // --------------------------------------------------------------------------------------------
102
103    /// Returns a new [Note] created with the specified parameters and empty attachments.
104    pub fn new(
105        assets: NoteAssets,
106        partial_metadata: PartialNoteMetadata,
107        recipient: NoteRecipient,
108    ) -> Self {
109        Self::with_attachments(assets, partial_metadata, recipient, NoteAttachments::default())
110    }
111
112    /// Returns a new [Note] created with the specified parameters and attachments.
113    pub fn with_attachments(
114        assets: NoteAssets,
115        partial_metadata: PartialNoteMetadata,
116        recipient: NoteRecipient,
117        attachments: NoteAttachments,
118    ) -> Self {
119        let details = NoteDetails::new(assets, recipient);
120        let metadata = NoteMetadata::new(partial_metadata, &attachments);
121        let header = NoteHeader::new(details.commitment(), metadata);
122        let nullifier = Nullifier::from_details_and_metadata(&details, &metadata);
123
124        Self { header, details, attachments, nullifier }
125    }
126
127    // PUBLIC ACCESSORS
128    // --------------------------------------------------------------------------------------------
129
130    /// Returns the note's header.
131    pub fn header(&self) -> &NoteHeader {
132        &self.header
133    }
134
135    /// Returns the note's unique identifier.
136    ///
137    /// This value commits to the note details and metadata.
138    pub fn id(&self) -> NoteId {
139        self.header.id()
140    }
141
142    /// Returns the commitment to the note's details, excluding metadata.
143    pub fn details_commitment(&self) -> NoteDetailsCommitment {
144        self.header.details_commitment()
145    }
146
147    /// Returns the note's assets.
148    pub fn assets(&self) -> &NoteAssets {
149        self.details.assets()
150    }
151
152    /// Returns the note's recipient serial_num, the secret required to consume the note.
153    pub fn serial_num(&self) -> Word {
154        self.details.serial_num()
155    }
156
157    /// Returns the note's recipient script which locks the assets of this note.
158    pub fn script(&self) -> &NoteScript {
159        self.details.script()
160    }
161
162    /// Returns the note's recipient storage which customizes the script's behavior.
163    pub fn storage(&self) -> &NoteStorage {
164        self.details.storage()
165    }
166
167    /// Returns the note's recipient.
168    pub fn recipient(&self) -> &NoteRecipient {
169        self.details.recipient()
170    }
171
172    /// Returns the note's nullifier.
173    ///
174    /// This is public data, used to prevent double spend.
175    pub fn nullifier(&self) -> Nullifier {
176        self.nullifier
177    }
178
179    /// Returns the note's attachments.
180    pub fn attachments(&self) -> &NoteAttachments {
181        &self.attachments
182    }
183
184    /// Returns `true` if the note has at least one attachment.
185    pub fn has_attachments(&self) -> bool {
186        !self.attachments.is_empty()
187    }
188
189    /// Returns a reference to the note's metadata.
190    pub fn metadata(&self) -> &NoteMetadata {
191        self.header.metadata()
192    }
193
194    // MUTATORS
195    // --------------------------------------------------------------------------------------------
196
197    /// Reduces the size of the note script by stripping all debug info from it.
198    pub fn clear_debug_info(&mut self) {
199        self.details.clear_debug_info();
200    }
201
202    /// Consumes self and returns the underlying parts of the [`Note`].
203    pub fn into_parts(self) -> (NoteAssets, NoteMetadata, NoteRecipient, NoteAttachments) {
204        let (assets, recipient) = self.details.into_parts();
205        let metadata = self.header.into_metadata();
206        (assets, metadata, recipient, self.attachments)
207    }
208}
209
210// AS REF
211// ================================================================================================
212
213impl AsRef<NoteRecipient> for Note {
214    fn as_ref(&self) -> &NoteRecipient {
215        self.recipient()
216    }
217}
218
219// CONVERSIONS FROM NOTE
220// ================================================================================================
221
222impl From<Note> for NoteHeader {
223    fn from(note: Note) -> Self {
224        note.header
225    }
226}
227
228impl From<&Note> for NoteDetails {
229    fn from(note: &Note) -> Self {
230        note.details.clone()
231    }
232}
233
234impl From<Note> for NoteDetails {
235    fn from(note: Note) -> Self {
236        note.details
237    }
238}
239
240impl From<Note> for PartialNote {
241    fn from(note: Note) -> Self {
242        let (assets, recipient, ..) = note.details.into_parts();
243        PartialNote::new(
244            note.header.into_metadata().into_partial_metadata(),
245            recipient.digest(),
246            assets,
247            note.attachments,
248        )
249    }
250}
251
252impl From<&Note> for NoteHeader {
253    fn from(note: &Note) -> Self {
254        note.header
255    }
256}
257
258// SERIALIZATION
259// ================================================================================================
260
261impl Serializable for Note {
262    fn write_into<W: ByteWriter>(&self, target: &mut W) {
263        let Self {
264            header,
265            details,
266            attachments,
267
268            // nullifier is not serialized as it can be computed from the rest of the data
269            nullifier: _,
270        } = self;
271
272        // Serialize only partial metadata since note ID can be recomputed from the note details and
273        // attachment schemes and commitments can be reconstructed from attachments
274        header.metadata().partial_metadata().write_into(target);
275        details.write_into(target);
276        attachments.write_into(target);
277    }
278
279    fn get_size_hint(&self) -> usize {
280        self.header.metadata().partial_metadata().get_size_hint()
281            + self.details.get_size_hint()
282            + self.attachments.get_size_hint()
283    }
284}
285
286impl Deserializable for Note {
287    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
288        let partial_metadata = PartialNoteMetadata::read_from(source)?;
289        let details = NoteDetails::read_from(source)?;
290        let attachments = NoteAttachments::read_from(source)?;
291        let (assets, recipient) = details.into_parts();
292
293        Ok(Self::with_attachments(assets, partial_metadata, recipient, attachments))
294    }
295}