1use std::fmt::{Debug, Display, Formatter};
2
3use miden_node_utils::limiter::{QueryParamLimiter, QueryParamStorageMapKeyTotalLimit};
4use miden_protocol::Word;
5use miden_protocol::account::{
6 Account,
7 AccountHeader,
8 AccountId,
9 AccountStorageHeader,
10 StorageMap,
11 StorageMapKey,
12 StorageSlotHeader,
13 StorageSlotName,
14 StorageSlotType,
15};
16use miden_protocol::asset::Asset;
17use miden_protocol::block::BlockNumber;
18use miden_protocol::block::account_tree::AccountWitness;
19use miden_protocol::crypto::merkle::SparseMerklePath;
20use miden_protocol::crypto::merkle::smt::SmtProof;
21use miden_protocol::utils::serde::{Deserializable, DeserializationError, Serializable};
22
23use super::try_convert;
24use crate::decode;
25use crate::decode::{ConversionResultExt, GrpcDecodeExt};
26use crate::errors::ConversionError;
27use crate::generated::{self as proto};
28
29#[cfg(test)]
30mod tests;
31
32impl Display for proto::account::AccountId {
36 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
37 write!(f, "0x")?;
38 for byte in &self.id {
39 write!(f, "{byte:02x}")?;
40 }
41 Ok(())
42 }
43}
44
45impl Debug for proto::account::AccountId {
46 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
47 Display::fmt(self, f)
48 }
49}
50
51impl TryFrom<proto::account::AccountId> for AccountId {
55 type Error = ConversionError;
56
57 fn try_from(account_id: proto::account::AccountId) -> Result<Self, Self::Error> {
58 AccountId::read_from_bytes(&account_id.id)
59 .map_err(|_| ConversionError::message("value is not in the range 0..MODULUS"))
60 }
61}
62
63impl From<&AccountId> for proto::account::AccountId {
67 fn from(account_id: &AccountId) -> Self {
68 (*account_id).into()
69 }
70}
71
72impl From<AccountId> for proto::account::AccountId {
73 fn from(account_id: AccountId) -> Self {
74 Self { id: account_id.to_bytes() }
75 }
76}
77
78#[derive(Debug, PartialEq)]
82pub struct AccountSummary {
83 pub account_id: AccountId,
84 pub account_commitment: Word,
85 pub block_num: BlockNumber,
86}
87
88impl From<&AccountSummary> for proto::account::AccountSummary {
89 fn from(update: &AccountSummary) -> Self {
90 Self {
91 account_id: Some(update.account_id.into()),
92 account_commitment: Some(update.account_commitment.into()),
93 block_num: update.block_num.as_u32(),
94 }
95 }
96}
97
98#[derive(Debug, PartialEq)]
99pub struct AccountInfo {
100 pub summary: AccountSummary,
101 pub details: Option<Account>,
102}
103
104impl From<&AccountInfo> for proto::account::AccountDetails {
105 fn from(AccountInfo { summary, details }: &AccountInfo) -> Self {
106 Self {
107 summary: Some(summary.into()),
108 details: details.as_ref().map(Serializable::to_bytes),
109 }
110 }
111}
112
113impl TryFrom<proto::account::AccountStorageHeader> for AccountStorageHeader {
117 type Error = ConversionError;
118
119 fn try_from(value: proto::account::AccountStorageHeader) -> Result<Self, Self::Error> {
120 let proto::account::AccountStorageHeader { slots } = value;
121
122 let slot_headers = slots
123 .into_iter()
124 .map(|slot| {
125 let decoder = slot.decoder();
126 let slot_name = StorageSlotName::new(slot.slot_name)?;
127 let slot_type = storage_slot_type_from_raw(slot.slot_type)?;
128 let commitment = decode!(decoder, slot.commitment)?;
129 Ok(StorageSlotHeader::new(slot_name, slot_type, commitment))
130 })
131 .collect::<Result<Vec<_>, ConversionError>>()
132 .context("slots")?;
133
134 Ok(AccountStorageHeader::new(slot_headers)?)
135 }
136}
137
138#[derive(Debug)]
143pub struct AccountRequest {
144 pub account_id: AccountId,
145 pub block_num: Option<BlockNumber>,
147 pub details: Option<AccountDetailRequest>,
148}
149
150impl TryFrom<proto::rpc::AccountRequest> for AccountRequest {
151 type Error = ConversionError;
152
153 fn try_from(value: proto::rpc::AccountRequest) -> Result<Self, Self::Error> {
154 let decoder = value.decoder();
155 let proto::rpc::AccountRequest { account_id, block_num, details } = value;
156
157 let account_id = decode!(decoder, account_id)?;
158 let block_num = block_num.map(Into::into);
159
160 let details = details.map(TryFrom::try_from).transpose().context("details")?;
161
162 Ok(AccountRequest { account_id, block_num, details })
163 }
164}
165
166#[derive(Debug)]
168pub struct AccountDetailRequest {
169 pub code_commitment: Option<Word>,
170 pub asset_vault_commitment: Option<Word>,
171 pub storage_request: AccountStorageRequest,
172}
173
174#[derive(Debug, Clone, PartialEq, Eq)]
175pub enum AccountStorageRequest {
176 None,
177 AllStorageMaps,
178 Explicit(Vec<StorageMapRequest>),
179}
180
181impl TryFrom<proto::rpc::account_request::AccountDetailRequest> for AccountDetailRequest {
182 type Error = ConversionError;
183
184 fn try_from(
185 value: proto::rpc::account_request::AccountDetailRequest,
186 ) -> Result<Self, Self::Error> {
187 use proto::rpc::account_request::account_detail_request::StorageRequest as ProtoStorageRequest;
188
189 let proto::rpc::account_request::AccountDetailRequest {
190 code_commitment,
191 asset_vault_commitment,
192 storage_request,
193 } = value;
194
195 let code_commitment =
196 code_commitment.map(TryFrom::try_from).transpose().context("code_commitment")?;
197 let asset_vault_commitment = asset_vault_commitment
198 .map(TryFrom::try_from)
199 .transpose()
200 .context("asset_vault_commitment")?;
201
202 let storage_request = match storage_request {
203 None => AccountStorageRequest::None,
204 Some(ProtoStorageRequest::AllStorageMaps(true)) => {
205 AccountStorageRequest::AllStorageMaps
206 },
207 Some(ProtoStorageRequest::AllStorageMaps(false)) => {
208 return Err(ConversionError::message("all_storage_maps must be true when set"));
209 },
210 Some(ProtoStorageRequest::StorageMaps(requests)) => {
211 let requests = try_convert(requests.storage_maps)
212 .collect::<Result<_, _>>()
213 .context("storage_maps")?;
214 AccountStorageRequest::Explicit(requests)
215 },
216 };
217
218 Ok(AccountDetailRequest {
219 code_commitment,
220 asset_vault_commitment,
221 storage_request,
222 })
223 }
224}
225
226#[derive(Debug, Clone, PartialEq, Eq)]
227pub struct StorageMapRequest {
228 pub slot_name: StorageSlotName,
229 pub slot_data: SlotData,
230}
231
232impl TryFrom<proto::rpc::account_request::account_detail_request::StorageMapDetailRequest>
233 for StorageMapRequest
234{
235 type Error = ConversionError;
236
237 fn try_from(
238 value: proto::rpc::account_request::account_detail_request::StorageMapDetailRequest,
239 ) -> Result<Self, Self::Error> {
240 let decoder = value.decoder();
241 let proto::rpc::account_request::account_detail_request::StorageMapDetailRequest {
242 slot_name,
243 slot_data,
244 } = value;
245
246 let slot_name = StorageSlotName::new(slot_name).context("slot_name")?;
247 let slot_data = decode!(decoder, slot_data)?;
248
249 Ok(StorageMapRequest { slot_name, slot_data })
250 }
251}
252
253#[derive(Debug, Clone, PartialEq, Eq)]
255pub enum SlotData {
256 All,
257 MapKeys(Vec<StorageMapKey>),
258}
259
260impl
261 TryFrom<
262 proto::rpc::account_request::account_detail_request::storage_map_detail_request::SlotData,
263 > for SlotData
264{
265 type Error = ConversionError;
266
267 fn try_from(
268 value: proto::rpc::account_request::account_detail_request::storage_map_detail_request::SlotData,
269 ) -> Result<Self, Self::Error> {
270 use proto::rpc::account_request::account_detail_request::storage_map_detail_request::SlotData as ProtoSlotData;
271
272 Ok(match value {
273 ProtoSlotData::AllEntries(true) => SlotData::All,
274 ProtoSlotData::AllEntries(false) => {
275 return Err(ConversionError::message("enum variant discriminant out of range"));
276 },
277 ProtoSlotData::MapKeys(keys) => {
278 let keys = try_convert(keys.map_keys).collect::<Result<Vec<_>, _>>()?;
279 SlotData::MapKeys(keys)
280 },
281 })
282 }
283}
284
285impl TryFrom<proto::account::AccountHeader> for AccountHeader {
289 type Error = ConversionError;
290
291 fn try_from(value: proto::account::AccountHeader) -> Result<Self, Self::Error> {
292 let decoder = value.decoder();
293 let proto::account::AccountHeader {
294 account_id,
295 vault_root,
296 storage_commitment,
297 code_commitment,
298 nonce,
299 } = value;
300
301 let account_id = decode!(decoder, account_id)?;
302 let vault_root = decode!(decoder, vault_root)?;
303 let storage_commitment = decode!(decoder, storage_commitment)?;
304 let code_commitment = decode!(decoder, code_commitment)?;
305 let nonce = nonce
306 .try_into()
307 .map_err(|e| ConversionError::message(format!("{e}")))
308 .context("nonce")?;
309
310 Ok(AccountHeader::new(
311 account_id,
312 nonce,
313 vault_root,
314 storage_commitment,
315 code_commitment,
316 ))
317 }
318}
319
320impl From<AccountHeader> for proto::account::AccountHeader {
321 fn from(header: AccountHeader) -> Self {
322 proto::account::AccountHeader {
323 account_id: Some(header.id().into()),
324 vault_root: Some(header.vault_root().into()),
325 storage_commitment: Some(header.storage_commitment().into()),
326 code_commitment: Some(header.code_commitment().into()),
327 nonce: header.nonce().as_canonical_u64(),
328 }
329 }
330}
331
332impl From<AccountStorageHeader> for proto::account::AccountStorageHeader {
333 fn from(value: AccountStorageHeader) -> Self {
334 let slots = value
335 .slots()
336 .map(|slot_header| proto::account::account_storage_header::StorageSlot {
337 slot_name: slot_header.name().to_string(),
338 slot_type: storage_slot_type_to_raw(slot_header.slot_type()),
339 commitment: Some(proto::primitives::Digest::from(slot_header.value())),
340 })
341 .collect();
342
343 Self { slots }
344 }
345}
346
347#[derive(Debug, Clone, PartialEq, Eq)]
357pub enum AccountVaultDetails {
358 LimitExceeded,
361
362 Assets(Vec<Asset>),
364}
365
366impl AccountVaultDetails {
367 pub const MAX_RETURN_ENTRIES: usize = 1000;
370
371 pub fn empty() -> Self {
372 Self::Assets(Vec::new())
373 }
374
375 pub fn from_assets(assets: Vec<Asset>) -> Self {
377 if assets.len() > Self::MAX_RETURN_ENTRIES {
378 Self::LimitExceeded
379 } else {
380 Self::Assets(assets)
381 }
382 }
383}
384
385impl TryFrom<proto::rpc::AccountVaultDetails> for AccountVaultDetails {
386 type Error = ConversionError;
387
388 fn try_from(value: proto::rpc::AccountVaultDetails) -> Result<Self, Self::Error> {
389 let proto::rpc::AccountVaultDetails { too_many_assets, assets } = value;
390
391 if too_many_assets {
392 Ok(Self::LimitExceeded)
393 } else {
394 let parsed_assets = Result::<Vec<_>, ConversionError>::from_iter(
395 assets.into_iter().map(Asset::try_from),
396 )?;
397 Ok(Self::Assets(parsed_assets))
398 }
399 }
400}
401
402impl From<AccountVaultDetails> for proto::rpc::AccountVaultDetails {
403 fn from(value: AccountVaultDetails) -> Self {
404 match value {
405 AccountVaultDetails::LimitExceeded => Self {
406 too_many_assets: true,
407 assets: Vec::new(),
408 },
409 AccountVaultDetails::Assets(assets) => Self {
410 too_many_assets: false,
411 assets: Vec::from_iter(assets.into_iter().map(proto::primitives::Asset::from)),
412 },
413 }
414 }
415}
416
417#[derive(Debug, Clone, PartialEq, Eq)]
422pub struct AccountStorageMapDetails {
423 pub slot_name: StorageSlotName,
424 pub entries: StorageMapEntries,
425}
426
427#[derive(Debug, Clone, PartialEq, Eq)]
434pub enum StorageMapEntries {
435 LimitExceeded,
438
439 AllEntries(Vec<(StorageMapKey, Word)>),
442
443 EntriesWithProofs(Vec<SmtProof>),
446}
447
448impl AccountStorageMapDetails {
449 pub const MAX_RETURN_ENTRIES: usize = 1000;
451
452 pub const MAX_SMT_PROOF_ENTRIES: usize = QueryParamStorageMapKeyTotalLimit::LIMIT;
460
461 pub fn from_all_entries(slot_name: StorageSlotName, storage_map: &StorageMap) -> Self {
466 if storage_map.num_entries() > Self::MAX_RETURN_ENTRIES {
467 Self {
468 slot_name,
469 entries: StorageMapEntries::LimitExceeded,
470 }
471 } else {
472 let entries = Vec::from_iter(storage_map.entries().map(|(k, v)| (*k, *v)));
473 Self {
474 slot_name,
475 entries: StorageMapEntries::AllEntries(entries),
476 }
477 }
478 }
479
480 pub fn from_forest_entries(
484 slot_name: StorageSlotName,
485 entries: Vec<(StorageMapKey, Word)>,
486 ) -> Self {
487 if entries.len() > Self::MAX_RETURN_ENTRIES {
488 Self {
489 slot_name,
490 entries: StorageMapEntries::LimitExceeded,
491 }
492 } else {
493 Self {
494 slot_name,
495 entries: StorageMapEntries::AllEntries(entries),
496 }
497 }
498 }
499
500 pub fn from_proofs(slot_name: StorageSlotName, proofs: Vec<SmtProof>) -> Self {
505 if proofs.len() > Self::MAX_SMT_PROOF_ENTRIES {
506 Self {
507 slot_name,
508 entries: StorageMapEntries::LimitExceeded,
509 }
510 } else {
511 Self {
512 slot_name,
513 entries: StorageMapEntries::EntriesWithProofs(proofs),
514 }
515 }
516 }
517
518 pub fn limit_exceeded(slot_name: StorageSlotName) -> Self {
520 Self {
521 slot_name,
522 entries: StorageMapEntries::LimitExceeded,
523 }
524 }
525}
526
527impl TryFrom<proto::rpc::account_storage_details::AccountStorageMapDetails>
528 for AccountStorageMapDetails
529{
530 type Error = ConversionError;
531
532 fn try_from(
533 value: proto::rpc::account_storage_details::AccountStorageMapDetails,
534 ) -> Result<Self, Self::Error> {
535 use proto::rpc::account_storage_details::account_storage_map_details::{
536 AllMapEntries,
537 Entries as ProtoEntries,
538 MapEntriesWithProofs,
539 };
540
541 let proto::rpc::account_storage_details::AccountStorageMapDetails {
542 slot_name,
543 too_many_entries,
544 entries,
545 } = value;
546
547 let slot_name = StorageSlotName::new(slot_name).context("slot_name")?;
548
549 let entries = if too_many_entries {
550 StorageMapEntries::LimitExceeded
551 } else {
552 match entries {
553 None => {
554 return Err(ConversionError::missing_field::<
555 proto::rpc::account_storage_details::AccountStorageMapDetails,
556 >("entries"));
557 },
558 Some(ProtoEntries::AllEntries(AllMapEntries { entries })) => {
559 let entries = entries
560 .into_iter()
561 .map(|entry| {
562 let decoder = entry.decoder();
563 let key = StorageMapKey::new(decode!(decoder, entry.key)?);
564 let value = decode!(decoder, entry.value)?;
565 Ok((key, value))
566 })
567 .collect::<Result<Vec<_>, ConversionError>>()
568 .context("entries")?;
569 StorageMapEntries::AllEntries(entries)
570 },
571 Some(ProtoEntries::EntriesWithProofs(MapEntriesWithProofs { entries })) => {
572 let proofs = entries
573 .into_iter()
574 .map(|entry| {
575 let decoder = entry.decoder();
576 decode!(decoder, entry.proof)
577 })
578 .collect::<Result<Vec<_>, ConversionError>>()
579 .context("entries")?;
580 StorageMapEntries::EntriesWithProofs(proofs)
581 },
582 }
583 };
584
585 Ok(Self { slot_name, entries })
586 }
587}
588
589impl From<AccountStorageMapDetails>
590 for proto::rpc::account_storage_details::AccountStorageMapDetails
591{
592 fn from(value: AccountStorageMapDetails) -> Self {
593 use proto::rpc::account_storage_details::account_storage_map_details::{
594 AllMapEntries,
595 Entries as ProtoEntries,
596 MapEntriesWithProofs,
597 };
598
599 let AccountStorageMapDetails { slot_name, entries } = value;
600
601 let (too_many_entries, proto_entries) = match entries {
602 StorageMapEntries::LimitExceeded => (true, None),
603 StorageMapEntries::AllEntries(entries) => {
604 let all = AllMapEntries {
605 entries: Vec::from_iter(entries.into_iter().map(|(key, value)| {
606 proto::rpc::account_storage_details::account_storage_map_details::all_map_entries::StorageMapEntry {
607 key: Some(key.into()),
608 value: Some(value.into()),
609 }
610 })),
611 };
612 (false, Some(ProtoEntries::AllEntries(all)))
613 },
614 StorageMapEntries::EntriesWithProofs(proofs) => {
615 use miden_protocol::crypto::merkle::smt::SmtLeaf;
616
617 let with_proofs = MapEntriesWithProofs {
618 entries: Vec::from_iter(proofs.into_iter().map(|proof| {
619 let (key, value) = match proof.leaf() {
621 SmtLeaf::Empty(_) => {
622 (miden_protocol::EMPTY_WORD, miden_protocol::EMPTY_WORD)
623 },
624 SmtLeaf::Single((k, v)) => (*k, *v),
625 SmtLeaf::Multiple(entries) => entries.iter().next().map_or(
626 (miden_protocol::EMPTY_WORD, miden_protocol::EMPTY_WORD),
627 |(k, v)| (*k, *v),
628 ),
629 };
630 let smt_opening = proto::primitives::SmtOpening::from(proof);
631 proto::rpc::account_storage_details::account_storage_map_details::map_entries_with_proofs::StorageMapEntryWithProof {
632 key: Some(key.into()),
633 value: Some(value.into()),
634 proof: Some(smt_opening),
635 }
636 })),
637 };
638 (false, Some(ProtoEntries::EntriesWithProofs(with_proofs)))
639 },
640 };
641
642 Self {
643 slot_name: slot_name.to_string(),
644 too_many_entries,
645 entries: proto_entries,
646 }
647 }
648}
649
650#[derive(Debug, Clone, PartialEq)]
651pub struct AccountStorageDetails {
652 pub header: AccountStorageHeader,
653 pub map_details: Vec<AccountStorageMapDetails>,
654}
655
656impl AccountStorageDetails {
657 pub fn all_limits_exceeded(
659 header: AccountStorageHeader,
660 slot_names: impl IntoIterator<Item = StorageSlotName>,
661 ) -> Self {
662 Self {
663 header,
664 map_details: Vec::from_iter(
665 slot_names.into_iter().map(AccountStorageMapDetails::limit_exceeded),
666 ),
667 }
668 }
669}
670
671impl TryFrom<proto::rpc::AccountStorageDetails> for AccountStorageDetails {
672 type Error = ConversionError;
673
674 fn try_from(value: proto::rpc::AccountStorageDetails) -> Result<Self, Self::Error> {
675 let decoder = value.decoder();
676 let proto::rpc::AccountStorageDetails { header, map_details } = value;
677
678 let header = decode!(decoder, header)?;
679
680 let map_details =
681 try_convert(map_details).collect::<Result<Vec<_>, _>>().context("map_details")?;
682
683 Ok(Self { header, map_details })
684 }
685}
686
687impl From<AccountStorageDetails> for proto::rpc::AccountStorageDetails {
688 fn from(value: AccountStorageDetails) -> Self {
689 let AccountStorageDetails { header, map_details } = value;
690
691 Self {
692 header: Some(header.into()),
693 map_details: map_details.into_iter().map(Into::into).collect(),
694 }
695 }
696}
697
698fn storage_slot_type_from_raw(slot_type: u32) -> Result<StorageSlotType, ConversionError> {
699 Ok(match slot_type {
700 0 => StorageSlotType::Value,
701 1 => StorageSlotType::Map,
702 _ => {
703 return Err(ConversionError::message("enum variant discriminant out of range"));
704 },
705 })
706}
707
708const fn storage_slot_type_to_raw(slot_type: StorageSlotType) -> u32 {
709 match slot_type {
710 StorageSlotType::Value => 0,
711 StorageSlotType::Map => 1,
712 }
713}
714
715pub struct AccountResponse {
720 pub block_num: BlockNumber,
721 pub witness: AccountWitness,
722 pub details: Option<AccountDetails>,
723}
724
725impl TryFrom<proto::rpc::AccountResponse> for AccountResponse {
726 type Error = ConversionError;
727
728 fn try_from(value: proto::rpc::AccountResponse) -> Result<Self, Self::Error> {
729 let decoder = value.decoder();
730 let proto::rpc::AccountResponse { block_num, witness, details } = value;
731
732 let block_num = block_num
733 .ok_or(ConversionError::missing_field::<proto::rpc::AccountResponse>("block_num"))?
734 .into();
735
736 let witness = decode!(decoder, witness)?;
737
738 let details = details.map(TryFrom::try_from).transpose().context("details")?;
739
740 Ok(AccountResponse { block_num, witness, details })
741 }
742}
743
744impl From<AccountResponse> for proto::rpc::AccountResponse {
745 fn from(value: AccountResponse) -> Self {
746 let AccountResponse { block_num, witness, details } = value;
747
748 Self {
749 witness: Some(witness.into()),
750 details: details.map(Into::into),
751 block_num: Some(block_num.into()),
752 }
753 }
754}
755
756pub struct AccountDetails {
761 pub account_header: AccountHeader,
762 pub account_code: Option<Vec<u8>>,
763 pub vault_details: AccountVaultDetails,
764 pub storage_details: AccountStorageDetails,
765}
766
767impl AccountDetails {
768 pub fn with_storage_limits_exceeded(
770 account_header: AccountHeader,
771 account_code: Option<Vec<u8>>,
772 vault_details: AccountVaultDetails,
773 storage_header: AccountStorageHeader,
774 slot_names: impl IntoIterator<Item = StorageSlotName>,
775 ) -> Self {
776 Self {
777 account_header,
778 account_code,
779 vault_details,
780 storage_details: AccountStorageDetails::all_limits_exceeded(storage_header, slot_names),
781 }
782 }
783}
784
785impl TryFrom<proto::rpc::account_response::AccountDetails> for AccountDetails {
786 type Error = ConversionError;
787
788 fn try_from(value: proto::rpc::account_response::AccountDetails) -> Result<Self, Self::Error> {
789 let decoder = value.decoder();
790 let proto::rpc::account_response::AccountDetails {
791 header,
792 code,
793 vault_details,
794 storage_details,
795 } = value;
796
797 let account_header = decode!(decoder, header)?;
798
799 let storage_details = decode!(decoder, storage_details)?;
800
801 let vault_details = decode!(decoder, vault_details)?;
802 let account_code = code;
803
804 Ok(AccountDetails {
805 account_header,
806 account_code,
807 vault_details,
808 storage_details,
809 })
810 }
811}
812
813impl From<AccountDetails> for proto::rpc::account_response::AccountDetails {
814 fn from(value: AccountDetails) -> Self {
815 let AccountDetails {
816 account_header,
817 storage_details,
818 account_code,
819 vault_details,
820 } = value;
821
822 let header = Some(proto::account::AccountHeader::from(account_header));
823 let storage_details = Some(storage_details.into());
824 let code = account_code;
825 let vault_details = Some(vault_details.into());
826
827 Self {
828 header,
829 storage_details,
830 code,
831 vault_details,
832 }
833 }
834}
835
836impl TryFrom<proto::account::AccountWitness> for AccountWitness {
840 type Error = ConversionError;
841
842 fn try_from(account_witness: proto::account::AccountWitness) -> Result<Self, Self::Error> {
843 let decoder = account_witness.decoder();
844 let witness_id = decode!(decoder, account_witness.witness_id)?;
845 let commitment = decode!(decoder, account_witness.commitment)?;
846 let path = decode!(decoder, account_witness.path)?;
847
848 AccountWitness::new(witness_id, commitment, path).map_err(|err| {
849 ConversionError::deserialization(
850 "AccountWitness",
851 DeserializationError::InvalidValue(err.to_string()),
852 )
853 })
854 }
855}
856
857impl From<AccountWitness> for proto::account::AccountWitness {
858 fn from(witness: AccountWitness) -> Self {
859 Self {
860 account_id: Some(witness.id().into()),
861 witness_id: Some(witness.id().into()),
862 commitment: Some(witness.state_commitment().into()),
863 path: Some(witness.into_proof().into_parts().0.into()),
864 }
865 }
866}
867
868#[derive(Clone, Debug, PartialEq, Eq)]
872pub struct AccountWitnessRecord {
873 pub account_id: AccountId,
874 pub witness: AccountWitness,
875}
876
877impl TryFrom<proto::account::AccountWitness> for AccountWitnessRecord {
878 type Error = ConversionError;
879
880 fn try_from(
881 account_witness_record: proto::account::AccountWitness,
882 ) -> Result<Self, Self::Error> {
883 let decoder = account_witness_record.decoder();
884 let witness_id = decode!(decoder, account_witness_record.witness_id)?;
885 let commitment = decode!(decoder, account_witness_record.commitment)?;
886 let account_id = decode!(decoder, account_witness_record.account_id)?;
887 let path: SparseMerklePath = decode!(decoder, account_witness_record.path)?;
888
889 let witness = AccountWitness::new(witness_id, commitment, path).map_err(|err| {
890 ConversionError::deserialization(
891 "AccountWitness",
892 DeserializationError::InvalidValue(err.to_string()),
893 )
894 })?;
895
896 Ok(Self { account_id, witness })
897 }
898}
899
900impl From<AccountWitnessRecord> for proto::account::AccountWitness {
901 fn from(from: AccountWitnessRecord) -> Self {
902 Self {
903 account_id: Some(from.account_id.into()),
904 witness_id: Some(from.witness.id().into()),
905 commitment: Some(from.witness.state_commitment().into()),
906 path: Some(from.witness.path().clone().into()),
907 }
908 }
909}
910
911impl TryFrom<proto::primitives::Asset> for Asset {
915 type Error = ConversionError;
916
917 fn try_from(asset: proto::primitives::Asset) -> Result<Self, Self::Error> {
918 let decoder = asset.decoder();
919 let key_word: Word = decode!(decoder, asset.key)?;
920 let value_word: Word = decode!(decoder, asset.value)?;
921
922 let asset = Asset::from_key_value_words(key_word, value_word)?;
923 Ok(asset)
924 }
925}
926
927impl From<Asset> for proto::primitives::Asset {
928 fn from(asset_from: Asset) -> Self {
929 proto::primitives::Asset {
930 key: Some(asset_from.to_key_word().into()),
931 value: Some(asset_from.to_value_word().into()),
932 }
933 }
934}