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