miden_node_proto/domain/
note.rs1use std::sync::Arc;
2
3use miden_protocol::crypto::merkle::SparseMerklePath;
4use miden_protocol::note::{
5 Note,
6 NoteAttachment,
7 NoteDetails,
8 NoteId,
9 NoteInclusionProof,
10 NoteMetadata,
11 NoteScript,
12 NoteTag,
13 NoteType,
14};
15use miden_protocol::utils::{Deserializable, Serializable};
16use miden_protocol::{MastForest, MastNodeId, Word};
17use miden_standards::note::AccountTargetNetworkNote;
18
19use crate::errors::{ConversionError, MissingFieldHelper};
20use crate::generated as proto;
21
22impl From<NoteType> for proto::note::NoteType {
26 fn from(note_type: NoteType) -> Self {
27 match note_type {
28 NoteType::Public => proto::note::NoteType::Public,
29 NoteType::Private => proto::note::NoteType::Private,
30 }
31 }
32}
33
34impl TryFrom<proto::note::NoteType> for NoteType {
35 type Error = ConversionError;
36
37 fn try_from(note_type: proto::note::NoteType) -> Result<Self, Self::Error> {
38 match note_type {
39 proto::note::NoteType::Public => Ok(NoteType::Public),
40 proto::note::NoteType::Private => Ok(NoteType::Private),
41 proto::note::NoteType::Unspecified => Err(ConversionError::EnumDiscriminantOutOfRange),
42 }
43 }
44}
45
46impl TryFrom<proto::note::NoteMetadata> for NoteMetadata {
50 type Error = ConversionError;
51
52 fn try_from(value: proto::note::NoteMetadata) -> Result<Self, Self::Error> {
53 let sender = value
54 .sender
55 .ok_or_else(|| proto::note::NoteMetadata::missing_field(stringify!(sender)))?
56 .try_into()?;
57 let note_type = proto::note::NoteType::try_from(value.note_type)
58 .map_err(|_| ConversionError::EnumDiscriminantOutOfRange)?
59 .try_into()?;
60 let tag = NoteTag::new(value.tag);
61
62 let attachment = if value.attachment.is_empty() {
64 NoteAttachment::default()
65 } else {
66 NoteAttachment::read_from_bytes(&value.attachment)
67 .map_err(|err| ConversionError::deserialization_error("NoteAttachment", err))?
68 };
69
70 Ok(NoteMetadata::new(sender, note_type).with_tag(tag).with_attachment(attachment))
71 }
72}
73
74impl From<Note> for proto::note::NetworkNote {
75 fn from(note: Note) -> Self {
76 Self {
77 metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())),
78 details: NoteDetails::from(note).to_bytes(),
79 }
80 }
81}
82
83impl From<Note> for proto::note::Note {
84 fn from(note: Note) -> Self {
85 Self {
86 metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())),
87 details: Some(NoteDetails::from(note).to_bytes()),
88 }
89 }
90}
91
92impl From<AccountTargetNetworkNote> for proto::note::NetworkNote {
93 fn from(note: AccountTargetNetworkNote) -> Self {
94 let note = note.into_note();
95 Self {
96 metadata: Some(proto::note::NoteMetadata::from(note.metadata().clone())),
97 details: NoteDetails::from(note).to_bytes(),
98 }
99 }
100}
101
102impl TryFrom<proto::note::NetworkNote> for AccountTargetNetworkNote {
103 type Error = ConversionError;
104
105 fn try_from(value: proto::note::NetworkNote) -> Result<Self, Self::Error> {
106 let details = NoteDetails::read_from_bytes(&value.details)
107 .map_err(|err| ConversionError::deserialization_error("NoteDetails", err))?;
108 let (assets, recipient) = details.into_parts();
109 let metadata: NoteMetadata = value
110 .metadata
111 .ok_or_else(|| proto::note::NetworkNote::missing_field(stringify!(metadata)))?
112 .try_into()?;
113 let note = Note::new(assets, metadata, recipient);
114 AccountTargetNetworkNote::new(note).map_err(ConversionError::NetworkNoteError)
115 }
116}
117
118impl From<NoteMetadata> for proto::note::NoteMetadata {
119 fn from(val: NoteMetadata) -> Self {
120 let sender = Some(val.sender().into());
121 let note_type = proto::note::NoteType::from(val.note_type()) as i32;
122 let tag = val.tag().as_u32();
123 let attachment = val.attachment().to_bytes();
124
125 proto::note::NoteMetadata { sender, note_type, tag, attachment }
126 }
127}
128
129impl From<Word> for proto::note::NoteId {
130 fn from(digest: Word) -> Self {
131 Self { id: Some(digest.into()) }
132 }
133}
134
135impl TryFrom<proto::note::NoteId> for Word {
136 type Error = ConversionError;
137
138 fn try_from(note_id: proto::note::NoteId) -> Result<Self, Self::Error> {
139 note_id
140 .id
141 .as_ref()
142 .ok_or(proto::note::NoteId::missing_field(stringify!(id)))?
143 .try_into()
144 }
145}
146
147impl From<&NoteId> for proto::note::NoteId {
148 fn from(note_id: &NoteId) -> Self {
149 Self { id: Some(note_id.into()) }
150 }
151}
152
153impl From<(&NoteId, &NoteInclusionProof)> for proto::note::NoteInclusionInBlockProof {
154 fn from((note_id, proof): (&NoteId, &NoteInclusionProof)) -> Self {
155 Self {
156 note_id: Some(note_id.into()),
157 block_num: proof.location().block_num().as_u32(),
158 note_index_in_block: proof.location().node_index_in_block().into(),
159 inclusion_path: Some(proof.note_path().clone().into()),
160 }
161 }
162}
163
164impl TryFrom<&proto::note::NoteInclusionInBlockProof> for (NoteId, NoteInclusionProof) {
165 type Error = ConversionError;
166
167 fn try_from(
168 proof: &proto::note::NoteInclusionInBlockProof,
169 ) -> Result<(NoteId, NoteInclusionProof), Self::Error> {
170 let inclusion_path = SparseMerklePath::try_from(
171 proof
172 .inclusion_path
173 .as_ref()
174 .ok_or(proto::note::NoteInclusionInBlockProof::missing_field(stringify!(
175 inclusion_path
176 )))?
177 .clone(),
178 )?;
179
180 let note_id = Word::try_from(
181 proof
182 .note_id
183 .as_ref()
184 .ok_or(proto::note::NoteInclusionInBlockProof::missing_field(stringify!(note_id)))?
185 .id
186 .as_ref()
187 .ok_or(proto::note::NoteId::missing_field(stringify!(id)))?,
188 )?;
189
190 Ok((
191 NoteId::from_raw(note_id),
192 NoteInclusionProof::new(
193 proof.block_num.into(),
194 proof.note_index_in_block.try_into()?,
195 inclusion_path,
196 )?,
197 ))
198 }
199}
200
201impl TryFrom<proto::note::Note> for Note {
202 type Error = ConversionError;
203
204 fn try_from(proto_note: proto::note::Note) -> Result<Self, Self::Error> {
205 let metadata: NoteMetadata = proto_note
206 .metadata
207 .ok_or(proto::note::Note::missing_field(stringify!(metadata)))?
208 .try_into()?;
209
210 let details = proto_note
211 .details
212 .ok_or(proto::note::Note::missing_field(stringify!(details)))?;
213
214 let note_details = NoteDetails::read_from_bytes(&details)
215 .map_err(|err| ConversionError::deserialization_error("NoteDetails", err))?;
216
217 let (assets, recipient) = note_details.into_parts();
218 Ok(Note::new(assets, metadata, recipient))
219 }
220}
221
222impl From<NoteScript> for proto::note::NoteScript {
226 fn from(script: NoteScript) -> Self {
227 Self {
228 entrypoint: script.entrypoint().into(),
229 mast: script.mast().to_bytes(),
230 }
231 }
232}
233
234impl TryFrom<proto::note::NoteScript> for NoteScript {
235 type Error = ConversionError;
236
237 fn try_from(value: proto::note::NoteScript) -> Result<Self, Self::Error> {
238 let proto::note::NoteScript { entrypoint, mast } = value;
239
240 let mast = MastForest::read_from_bytes(&mast)
241 .map_err(|err| Self::Error::deserialization_error("note_script.mast", err))?;
242 let entrypoint = MastNodeId::from_u32_safe(entrypoint, &mast)
243 .map_err(|err| Self::Error::deserialization_error("note_script.entrypoint", err))?;
244
245 Ok(Self::from_parts(Arc::new(mast), entrypoint))
246 }
247}