miden_node_proto/domain/
note.rs1use miden_objects::crypto::merkle::SparseMerklePath;
2use miden_objects::note::{
3 Note,
4 NoteDetails,
5 NoteExecutionHint,
6 NoteId,
7 NoteInclusionProof,
8 NoteMetadata,
9 NoteScript,
10 NoteTag,
11 NoteType,
12 Nullifier,
13};
14use miden_objects::utils::{Deserializable, Serializable};
15use miden_objects::{Felt, Word};
16use thiserror::Error;
17
18use super::account::NetworkAccountPrefix;
19use crate::errors::{ConversionError, MissingFieldHelper};
20use crate::generated as proto;
21
22impl TryFrom<proto::note::NoteMetadata> for NoteMetadata {
23 type Error = ConversionError;
24
25 fn try_from(value: proto::note::NoteMetadata) -> Result<Self, Self::Error> {
26 let sender = value
27 .sender
28 .ok_or_else(|| proto::note::NoteMetadata::missing_field(stringify!(sender)))?
29 .try_into()?;
30 let note_type = NoteType::try_from(u64::from(value.note_type))?;
31 let tag = NoteTag::from(value.tag);
32
33 let execution_hint = NoteExecutionHint::try_from(value.execution_hint)?;
34
35 let aux = Felt::try_from(value.aux).map_err(|_| ConversionError::NotAValidFelt)?;
36
37 Ok(NoteMetadata::new(sender, note_type, tag, execution_hint, aux)?)
38 }
39}
40
41impl From<Note> for proto::note::NetworkNote {
42 fn from(note: Note) -> Self {
43 Self {
44 metadata: Some(proto::note::NoteMetadata::from(*note.metadata())),
45 details: NoteDetails::from(note).to_bytes(),
46 }
47 }
48}
49
50impl From<Note> for proto::note::Note {
51 fn from(note: Note) -> Self {
52 Self {
53 metadata: Some(proto::note::NoteMetadata::from(*note.metadata())),
54 details: Some(NoteDetails::from(note).to_bytes()),
55 }
56 }
57}
58
59impl From<NetworkNote> for proto::note::NetworkNote {
60 fn from(note: NetworkNote) -> Self {
61 let note = Note::from(note);
62 Self {
63 metadata: Some(proto::note::NoteMetadata::from(*note.metadata())),
64 details: NoteDetails::from(note).to_bytes(),
65 }
66 }
67}
68
69impl From<NoteMetadata> for proto::note::NoteMetadata {
70 fn from(val: NoteMetadata) -> Self {
71 let sender = Some(val.sender().into());
72 let note_type = val.note_type() as u32;
73 let tag = val.tag().into();
74 let execution_hint: u64 = val.execution_hint().into();
75 let aux = val.aux().into();
76
77 proto::note::NoteMetadata {
78 sender,
79 note_type,
80 tag,
81 execution_hint,
82 aux,
83 }
84 }
85}
86
87impl From<Word> for proto::note::NoteId {
88 fn from(digest: Word) -> Self {
89 Self { id: Some(digest.into()) }
90 }
91}
92
93impl TryFrom<proto::note::NoteId> for Word {
94 type Error = ConversionError;
95
96 fn try_from(note_id: proto::note::NoteId) -> Result<Self, Self::Error> {
97 note_id
98 .id
99 .as_ref()
100 .ok_or(proto::note::NoteId::missing_field(stringify!(id)))?
101 .try_into()
102 }
103}
104
105impl From<&NoteId> for proto::note::NoteId {
106 fn from(note_id: &NoteId) -> Self {
107 Self { id: Some(note_id.into()) }
108 }
109}
110
111impl From<(&NoteId, &NoteInclusionProof)> for proto::note::NoteInclusionInBlockProof {
112 fn from((note_id, proof): (&NoteId, &NoteInclusionProof)) -> Self {
113 Self {
114 note_id: Some(note_id.into()),
115 block_num: proof.location().block_num().as_u32(),
116 note_index_in_block: proof.location().node_index_in_block().into(),
117 inclusion_path: Some(proof.note_path().clone().into()),
118 }
119 }
120}
121
122impl TryFrom<&proto::note::NoteInclusionInBlockProof> for (NoteId, NoteInclusionProof) {
123 type Error = ConversionError;
124
125 fn try_from(
126 proof: &proto::note::NoteInclusionInBlockProof,
127 ) -> Result<(NoteId, NoteInclusionProof), Self::Error> {
128 let inclusion_path = SparseMerklePath::try_from(
129 proof
130 .inclusion_path
131 .as_ref()
132 .ok_or(proto::note::NoteInclusionInBlockProof::missing_field(stringify!(
133 inclusion_path
134 )))?
135 .clone(),
136 )?;
137
138 Ok((
139 Word::try_from(
140 proof
141 .note_id
142 .as_ref()
143 .ok_or(proto::note::NoteInclusionInBlockProof::missing_field(stringify!(
144 note_id
145 )))?
146 .id
147 .as_ref()
148 .ok_or(proto::note::NoteId::missing_field(stringify!(id)))?,
149 )?
150 .into(),
151 NoteInclusionProof::new(
152 proof.block_num.into(),
153 proof.note_index_in_block.try_into()?,
154 inclusion_path,
155 )?,
156 ))
157 }
158}
159
160impl TryFrom<proto::note::Note> for Note {
161 type Error = ConversionError;
162
163 fn try_from(proto_note: proto::note::Note) -> Result<Self, Self::Error> {
164 let metadata: NoteMetadata = proto_note
165 .metadata
166 .ok_or(proto::note::Note::missing_field(stringify!(metadata)))?
167 .try_into()?;
168
169 let details = proto_note
170 .details
171 .ok_or(proto::note::Note::missing_field(stringify!(details)))?;
172
173 let note_details = NoteDetails::read_from_bytes(&details)
174 .map_err(|err| ConversionError::deserialization_error("NoteDetails", err))?;
175
176 let (assets, recipient) = note_details.into_parts();
177 Ok(Note::new(assets, metadata, recipient))
178 }
179}
180
181#[derive(Clone, Debug, PartialEq, Eq)]
186pub enum NetworkNote {
187 SingleTarget(SingleTargetNetworkNote),
188 MultiTarget(MultiTargetNetworkNote),
189}
190
191impl NetworkNote {
192 pub fn inner(&self) -> &Note {
193 match self {
194 NetworkNote::SingleTarget(note) => ¬e.0,
195 NetworkNote::MultiTarget(note) => ¬e.0,
196 }
197 }
198
199 pub fn metadata(&self) -> &NoteMetadata {
200 self.inner().metadata()
201 }
202
203 pub fn nullifier(&self) -> Nullifier {
204 self.inner().nullifier()
205 }
206
207 pub fn id(&self) -> NoteId {
208 self.inner().id()
209 }
210}
211
212impl From<NetworkNote> for Note {
213 fn from(value: NetworkNote) -> Self {
214 match value {
215 NetworkNote::SingleTarget(note) => note.0,
216 NetworkNote::MultiTarget(note) => note.0,
217 }
218 }
219}
220
221impl TryFrom<Note> for NetworkNote {
222 type Error = NetworkNoteError;
223
224 fn try_from(note: Note) -> Result<Self, Self::Error> {
225 if note.is_network_note() {
226 if note.metadata().tag().is_single_target() {
227 Ok(NetworkNote::SingleTarget(SingleTargetNetworkNote(note)))
228 } else {
229 Ok(NetworkNote::MultiTarget(MultiTargetNetworkNote(note)))
230 }
231 } else {
232 Err(NetworkNoteError::InvalidExecutionMode(note.metadata().tag()))
233 }
234 }
235}
236
237impl TryFrom<proto::note::NetworkNote> for NetworkNote {
238 type Error = ConversionError;
239
240 fn try_from(proto_note: proto::note::NetworkNote) -> Result<Self, Self::Error> {
241 from_proto(proto_note)
242 }
243}
244
245#[derive(Clone, Debug, PartialEq, Eq)]
250pub struct MultiTargetNetworkNote(Note);
251
252impl TryFrom<Note> for MultiTargetNetworkNote {
253 type Error = NetworkNoteError;
254
255 fn try_from(note: Note) -> Result<Self, Self::Error> {
256 if note.is_network_note() && !note.metadata().tag().is_single_target() {
257 Ok(Self(note))
258 } else {
259 Err(NetworkNoteError::InvalidExecutionMode(note.metadata().tag()))
260 }
261 }
262}
263
264impl TryFrom<proto::note::NetworkNote> for MultiTargetNetworkNote {
265 type Error = ConversionError;
266
267 fn try_from(proto_note: proto::note::NetworkNote) -> Result<Self, Self::Error> {
268 from_proto(proto_note)
269 }
270}
271
272#[derive(Clone, Debug, PartialEq, Eq)]
277pub struct SingleTargetNetworkNote(Note);
278
279impl SingleTargetNetworkNote {
280 pub fn inner(&self) -> &Note {
281 &self.0
282 }
283
284 pub fn metadata(&self) -> &NoteMetadata {
285 self.inner().metadata()
286 }
287
288 pub fn nullifier(&self) -> Nullifier {
289 self.inner().nullifier()
290 }
291
292 pub fn id(&self) -> NoteId {
293 self.inner().id()
294 }
295
296 pub fn account_prefix(&self) -> NetworkAccountPrefix {
298 self.metadata()
299 .tag()
300 .try_into()
301 .expect("Single target network note's tag should contain an account prefix")
302 }
303}
304
305impl From<SingleTargetNetworkNote> for Note {
306 fn from(value: SingleTargetNetworkNote) -> Self {
307 value.0
308 }
309}
310
311impl TryFrom<Note> for SingleTargetNetworkNote {
312 type Error = NetworkNoteError;
313
314 fn try_from(note: Note) -> Result<Self, Self::Error> {
315 if note.is_network_note() && note.metadata().tag().is_single_target() {
316 Ok(Self(note))
317 } else {
318 Err(NetworkNoteError::InvalidExecutionMode(note.metadata().tag()))
319 }
320 }
321}
322
323impl TryFrom<proto::note::NetworkNote> for SingleTargetNetworkNote {
324 type Error = ConversionError;
325
326 fn try_from(proto_note: proto::note::NetworkNote) -> Result<Self, Self::Error> {
327 from_proto(proto_note)
328 }
329}
330
331fn from_proto<T>(proto_note: proto::note::NetworkNote) -> Result<T, ConversionError>
333where
334 T: TryFrom<Note>,
335 T::Error: Into<ConversionError>,
336{
337 let details = NoteDetails::read_from_bytes(&proto_note.details)
338 .map_err(|err| ConversionError::deserialization_error("NoteDetails", err))?;
339 let (assets, recipient) = details.into_parts();
340 let metadata: NoteMetadata = proto_note
341 .metadata
342 .ok_or_else(|| proto::note::NetworkNote::missing_field(stringify!(metadata)))?
343 .try_into()?;
344 let note = Note::new(assets, metadata, recipient);
345 T::try_from(note).map_err(Into::into)
346}
347
348#[derive(Debug, Error)]
349pub enum NetworkNoteError {
350 #[error("note tag {0} is not a valid network note tag")]
351 InvalidExecutionMode(NoteTag),
352}
353
354impl From<NoteScript> for proto::note::NoteScript {
358 fn from(script: NoteScript) -> Self {
359 Self {
360 entrypoint: script.entrypoint().into(),
361 mast: script.mast().to_bytes(),
362 }
363 }
364}