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::smt::{PartialSmt, SmtProof};
20use miden_protocol::crypto::merkle::{MerkleError, SparseMerklePath};
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 if has_duplicate_storage_map_keys(&keys) {
280 return Err(ConversionError::message(
281 "storage map key request contains duplicate keys",
282 ));
283 }
284 SlotData::MapKeys(keys)
285 },
286 })
287 }
288}
289
290fn has_duplicate_storage_map_keys(keys: &[StorageMapKey]) -> bool {
291 keys.iter().enumerate().any(|(index, key)| keys[..index].contains(key))
292}
293
294impl TryFrom<proto::account::AccountHeader> for AccountHeader {
298 type Error = ConversionError;
299
300 fn try_from(value: proto::account::AccountHeader) -> Result<Self, Self::Error> {
301 let decoder = value.decoder();
302 let proto::account::AccountHeader {
303 account_id,
304 vault_root,
305 storage_commitment,
306 code_commitment,
307 nonce,
308 } = value;
309
310 let account_id = decode!(decoder, account_id)?;
311 let vault_root = decode!(decoder, vault_root)?;
312 let storage_commitment = decode!(decoder, storage_commitment)?;
313 let code_commitment = decode!(decoder, code_commitment)?;
314 let nonce = nonce
315 .try_into()
316 .map_err(|e| ConversionError::message(format!("{e}")))
317 .context("nonce")?;
318
319 Ok(AccountHeader::new(
320 account_id,
321 nonce,
322 vault_root,
323 storage_commitment,
324 code_commitment,
325 ))
326 }
327}
328
329impl From<AccountHeader> for proto::account::AccountHeader {
330 fn from(header: AccountHeader) -> Self {
331 proto::account::AccountHeader {
332 account_id: Some(header.id().into()),
333 vault_root: Some(header.vault_root().into()),
334 storage_commitment: Some(header.storage_commitment().into()),
335 code_commitment: Some(header.code_commitment().into()),
336 nonce: header.nonce().as_canonical_u64(),
337 }
338 }
339}
340
341impl From<AccountStorageHeader> for proto::account::AccountStorageHeader {
342 fn from(value: AccountStorageHeader) -> Self {
343 let slots = value
344 .slots()
345 .map(|slot_header| proto::account::account_storage_header::StorageSlot {
346 slot_name: slot_header.name().to_string(),
347 slot_type: storage_slot_type_to_raw(slot_header.slot_type()),
348 commitment: Some(proto::primitives::Digest::from(slot_header.value())),
349 })
350 .collect();
351
352 Self { slots }
353 }
354}
355
356#[derive(Debug, Clone, PartialEq, Eq)]
366pub enum AccountVaultDetails {
367 LimitExceeded,
370
371 Assets(Vec<Asset>),
373}
374
375impl AccountVaultDetails {
376 pub const MAX_RETURN_ENTRIES: usize = 1000;
379
380 pub fn empty() -> Self {
381 Self::Assets(Vec::new())
382 }
383
384 pub fn from_assets(assets: Vec<Asset>) -> Self {
386 if assets.len() > Self::MAX_RETURN_ENTRIES {
387 Self::LimitExceeded
388 } else {
389 Self::Assets(assets)
390 }
391 }
392}
393
394impl TryFrom<proto::rpc::AccountVaultDetails> for AccountVaultDetails {
395 type Error = ConversionError;
396
397 fn try_from(value: proto::rpc::AccountVaultDetails) -> Result<Self, Self::Error> {
398 let proto::rpc::AccountVaultDetails { too_many_assets, assets } = value;
399
400 if too_many_assets {
401 Ok(Self::LimitExceeded)
402 } else {
403 let parsed_assets = assets
404 .into_iter()
405 .map(Asset::try_from)
406 .collect::<Result<Vec<_>, ConversionError>>()?;
407 Ok(Self::Assets(parsed_assets))
408 }
409 }
410}
411
412impl From<AccountVaultDetails> for proto::rpc::AccountVaultDetails {
413 fn from(value: AccountVaultDetails) -> Self {
414 match value {
415 AccountVaultDetails::LimitExceeded => Self {
416 too_many_assets: true,
417 assets: Vec::new(),
418 },
419 AccountVaultDetails::Assets(assets) => Self {
420 too_many_assets: false,
421 assets: assets.into_iter().map(proto::primitives::Asset::from).collect::<Vec<_>>(),
422 },
423 }
424 }
425}
426
427#[derive(Debug, Clone, PartialEq, Eq)]
432pub struct AccountStorageMapDetails {
433 pub slot_name: StorageSlotName,
434 pub entries: StorageMapEntries,
435}
436
437#[derive(Debug, Clone, PartialEq, Eq)]
444pub enum StorageMapEntries {
445 LimitExceeded,
448
449 AllEntries(Vec<(StorageMapKey, Word)>),
452
453 PartialMap {
456 map_keys: Vec<StorageMapKey>,
457 partial_smt: PartialSmt,
458 },
459}
460
461impl AccountStorageMapDetails {
462 pub const MAX_RETURN_ENTRIES: usize = 1000;
464
465 pub const MAX_SMT_PROOF_ENTRIES: usize = QueryParamStorageMapKeyTotalLimit::LIMIT;
473
474 pub fn from_all_entries(slot_name: StorageSlotName, storage_map: &StorageMap) -> Self {
479 if storage_map.num_entries() > Self::MAX_RETURN_ENTRIES {
480 Self {
481 slot_name,
482 entries: StorageMapEntries::LimitExceeded,
483 }
484 } else {
485 let entries = storage_map.entries().map(|(k, v)| (*k, *v)).collect::<Vec<_>>();
486 Self {
487 slot_name,
488 entries: StorageMapEntries::AllEntries(entries),
489 }
490 }
491 }
492
493 pub fn from_forest_entries(
497 slot_name: StorageSlotName,
498 entries: Vec<(StorageMapKey, Word)>,
499 ) -> Self {
500 if entries.len() > Self::MAX_RETURN_ENTRIES {
501 Self {
502 slot_name,
503 entries: StorageMapEntries::LimitExceeded,
504 }
505 } else {
506 Self {
507 slot_name,
508 entries: StorageMapEntries::AllEntries(entries),
509 }
510 }
511 }
512
513 pub fn from_proofs(
518 slot_name: StorageSlotName,
519 map_root: Word,
520 map_keys: Vec<StorageMapKey>,
521 proofs: Vec<SmtProof>,
522 ) -> Result<Self, MerkleError> {
523 if map_keys.len() != proofs.len() {
524 return Err(MerkleError::InternalError(format!(
525 "storage map key count {} does not match proof count {}",
526 map_keys.len(),
527 proofs.len()
528 )));
529 }
530 if has_duplicate_storage_map_keys(&map_keys) {
531 return Err(MerkleError::InternalError(
532 "storage map key list contains duplicate keys".into(),
533 ));
534 }
535
536 if map_keys.len() > Self::MAX_SMT_PROOF_ENTRIES {
537 return Ok(Self {
538 slot_name,
539 entries: StorageMapEntries::LimitExceeded,
540 });
541 }
542
543 let partial_smt = if proofs.is_empty() {
544 PartialSmt::new(map_root)
545 } else {
546 PartialSmt::from_proofs(proofs)?
547 };
548
549 if partial_smt.root() != map_root {
550 return Err(MerkleError::ConflictingRoots {
551 expected_root: map_root,
552 actual_root: partial_smt.root(),
553 });
554 }
555
556 for map_key in &map_keys {
557 partial_smt.get_value(&map_key.hash().as_word())?;
558 }
559
560 Ok(Self {
561 slot_name,
562 entries: StorageMapEntries::PartialMap { map_keys, partial_smt },
563 })
564 }
565
566 pub fn limit_exceeded(slot_name: StorageSlotName) -> Self {
568 Self {
569 slot_name,
570 entries: StorageMapEntries::LimitExceeded,
571 }
572 }
573}
574
575impl TryFrom<proto::rpc::account_storage_details::AccountStorageMapDetails>
576 for AccountStorageMapDetails
577{
578 type Error = ConversionError;
579
580 fn try_from(
581 value: proto::rpc::account_storage_details::AccountStorageMapDetails,
582 ) -> Result<Self, Self::Error> {
583 use proto::rpc::account_storage_details::account_storage_map_details::{
584 AllMapEntries,
585 PartialStorageMap,
586 Result as ProtoResult,
587 };
588
589 let decoder = value.decoder();
590 let proto::rpc::account_storage_details::AccountStorageMapDetails { slot_name, result } =
591 value;
592
593 let slot_name = StorageSlotName::new(slot_name).context("slot_name")?;
594
595 let entries = match decode!(decoder, result)? {
596 ProtoResult::TooManyEntries(true) => StorageMapEntries::LimitExceeded,
597 ProtoResult::TooManyEntries(false) => {
598 return Err(ConversionError::message("too_many_entries must be true when set"));
599 },
600 ProtoResult::AllEntries(AllMapEntries { entries }) => {
601 let entries = entries
602 .into_iter()
603 .map(|entry| {
604 let decoder = entry.decoder();
605 let key = StorageMapKey::new(decode!(decoder, entry.key)?);
606 let value = decode!(decoder, entry.value)?;
607 Ok((key, value))
608 })
609 .collect::<Result<Vec<_>, ConversionError>>()
610 .context("entries")?;
611 StorageMapEntries::AllEntries(entries)
612 },
613 ProtoResult::PartialMap(PartialStorageMap { map_keys, partial_smt }) => {
614 if map_keys.len() > Self::MAX_SMT_PROOF_ENTRIES {
615 return Err(ConversionError::message(format!(
616 "partial storage map contains {} keys, exceeding the limit of {}",
617 map_keys.len(),
618 Self::MAX_SMT_PROOF_ENTRIES
619 )));
620 }
621 let map_keys = map_keys
622 .into_iter()
623 .map(|key| Word::try_from(key).map(StorageMapKey::new))
624 .collect::<Result<Vec<_>, _>>()
625 .context("map_keys")?;
626 if has_duplicate_storage_map_keys(&map_keys) {
627 return Err(ConversionError::message(
628 "partial storage map contains duplicate keys",
629 ));
630 }
631 let partial_smt: PartialSmt =
632 decode!(decoder, partial_smt).context("partial_smt")?;
633 for map_key in &map_keys {
634 partial_smt.get_value(&map_key.hash().as_word()).context("map_keys")?;
635 }
636 StorageMapEntries::PartialMap { map_keys, partial_smt }
637 },
638 };
639
640 Ok(Self { slot_name, entries })
641 }
642}
643
644impl From<AccountStorageMapDetails>
645 for proto::rpc::account_storage_details::AccountStorageMapDetails
646{
647 fn from(value: AccountStorageMapDetails) -> Self {
648 use proto::rpc::account_storage_details::account_storage_map_details::{
649 AllMapEntries,
650 PartialStorageMap,
651 Result as ProtoResult,
652 };
653
654 let AccountStorageMapDetails { slot_name, entries } = value;
655
656 let result = match entries {
657 StorageMapEntries::LimitExceeded => ProtoResult::TooManyEntries(true),
658 StorageMapEntries::AllEntries(entries) => {
659 let all = AllMapEntries {
660 entries: entries.into_iter().map(|(key, value)| {
661 proto::rpc::account_storage_details::account_storage_map_details::all_map_entries::StorageMapEntry {
662 key: Some(key.into()),
663 value: Some(value.into()),
664 }
665 }).collect::<Vec<_>>(),
666 };
667 ProtoResult::AllEntries(all)
668 },
669 StorageMapEntries::PartialMap { map_keys, partial_smt } => {
670 ProtoResult::PartialMap(PartialStorageMap {
671 map_keys: map_keys.into_iter().map(Into::into).collect(),
672 partial_smt: Some(partial_smt.into()),
673 })
674 },
675 };
676
677 Self {
678 slot_name: slot_name.to_string(),
679 result: Some(result),
680 }
681 }
682}
683
684#[derive(Debug, Clone, PartialEq)]
685pub struct AccountStorageDetails {
686 pub header: AccountStorageHeader,
687 pub map_details: Vec<AccountStorageMapDetails>,
688}
689
690impl AccountStorageDetails {
691 pub fn all_limits_exceeded(
693 header: AccountStorageHeader,
694 slot_names: impl IntoIterator<Item = StorageSlotName>,
695 ) -> Self {
696 Self {
697 header,
698 map_details: slot_names
699 .into_iter()
700 .map(AccountStorageMapDetails::limit_exceeded)
701 .collect::<Vec<_>>(),
702 }
703 }
704}
705
706impl TryFrom<proto::rpc::AccountStorageDetails> for AccountStorageDetails {
707 type Error = ConversionError;
708
709 fn try_from(value: proto::rpc::AccountStorageDetails) -> Result<Self, Self::Error> {
710 let decoder = value.decoder();
711 let proto::rpc::AccountStorageDetails { header, map_details } = value;
712
713 let header: AccountStorageHeader = decode!(decoder, header)?;
714
715 let map_details: Vec<AccountStorageMapDetails> =
716 try_convert(map_details).collect::<Result<Vec<_>, _>>().context("map_details")?;
717
718 for map_detail in &map_details {
719 let StorageMapEntries::PartialMap { partial_smt, .. } = &map_detail.entries else {
720 continue;
721 };
722
723 let slot = header.find_slot_header_by_name(&map_detail.slot_name).ok_or_else(|| {
724 ConversionError::message(format!(
725 "partial storage map references unknown slot {}",
726 map_detail.slot_name
727 ))
728 })?;
729 if slot.slot_type() != StorageSlotType::Map {
730 return Err(ConversionError::message(format!(
731 "partial storage map references non-map slot {}",
732 map_detail.slot_name
733 )));
734 }
735 if partial_smt.root() != slot.value() {
736 return Err(ConversionError::message(format!(
737 "partial storage map root for slot {} does not match storage header",
738 map_detail.slot_name
739 )));
740 }
741 }
742
743 Ok(Self { header, map_details })
744 }
745}
746
747impl From<AccountStorageDetails> for proto::rpc::AccountStorageDetails {
748 fn from(value: AccountStorageDetails) -> Self {
749 let AccountStorageDetails { header, map_details } = value;
750
751 Self {
752 header: Some(header.into()),
753 map_details: map_details.into_iter().map(Into::into).collect(),
754 }
755 }
756}
757
758fn storage_slot_type_from_raw(slot_type: u32) -> Result<StorageSlotType, ConversionError> {
759 Ok(match slot_type {
760 0 => StorageSlotType::Value,
761 1 => StorageSlotType::Map,
762 _ => {
763 return Err(ConversionError::message("enum variant discriminant out of range"));
764 },
765 })
766}
767
768const fn storage_slot_type_to_raw(slot_type: StorageSlotType) -> u32 {
769 match slot_type {
770 StorageSlotType::Value => 0,
771 StorageSlotType::Map => 1,
772 }
773}
774
775pub struct AccountResponse {
780 pub block_num: BlockNumber,
781 pub witness: AccountWitness,
782 pub details: Option<AccountDetails>,
783}
784
785impl TryFrom<proto::rpc::AccountResponse> for AccountResponse {
786 type Error = ConversionError;
787
788 fn try_from(value: proto::rpc::AccountResponse) -> Result<Self, Self::Error> {
789 let decoder = value.decoder();
790 let proto::rpc::AccountResponse { block_num, witness, details } = value;
791
792 let block_num = decode!(decoder, block_num)?;
793
794 let witness = decode!(decoder, witness)?;
795
796 let details = details.map(TryFrom::try_from).transpose().context("details")?;
797
798 Ok(AccountResponse { block_num, witness, details })
799 }
800}
801
802impl From<AccountResponse> for proto::rpc::AccountResponse {
803 fn from(value: AccountResponse) -> Self {
804 let AccountResponse { block_num, witness, details } = value;
805
806 Self {
807 witness: Some(witness.into()),
808 details: details.map(Into::into),
809 block_num: Some(block_num.into()),
810 }
811 }
812}
813
814pub struct AccountDetails {
819 pub account_header: AccountHeader,
820 pub account_code: Option<Vec<u8>>,
821 pub vault_details: AccountVaultDetails,
822 pub storage_details: AccountStorageDetails,
823}
824
825impl AccountDetails {
826 pub fn with_storage_limits_exceeded(
828 account_header: AccountHeader,
829 account_code: Option<Vec<u8>>,
830 vault_details: AccountVaultDetails,
831 storage_header: AccountStorageHeader,
832 slot_names: impl IntoIterator<Item = StorageSlotName>,
833 ) -> Self {
834 Self {
835 account_header,
836 account_code,
837 vault_details,
838 storage_details: AccountStorageDetails::all_limits_exceeded(storage_header, slot_names),
839 }
840 }
841}
842
843impl TryFrom<proto::rpc::account_response::AccountDetails> for AccountDetails {
844 type Error = ConversionError;
845
846 fn try_from(value: proto::rpc::account_response::AccountDetails) -> Result<Self, Self::Error> {
847 let decoder = value.decoder();
848 let proto::rpc::account_response::AccountDetails {
849 header,
850 code,
851 vault_details,
852 storage_details,
853 } = value;
854
855 let account_header = decode!(decoder, header)?;
856
857 let storage_details = decode!(decoder, storage_details)?;
858
859 let vault_details = decode!(decoder, vault_details)?;
860 let account_code = code;
861
862 Ok(AccountDetails {
863 account_header,
864 account_code,
865 vault_details,
866 storage_details,
867 })
868 }
869}
870
871impl From<AccountDetails> for proto::rpc::account_response::AccountDetails {
872 fn from(value: AccountDetails) -> Self {
873 let AccountDetails {
874 account_header,
875 storage_details,
876 account_code,
877 vault_details,
878 } = value;
879
880 let header = Some(proto::account::AccountHeader::from(account_header));
881 let storage_details = Some(storage_details.into());
882 let code = account_code;
883 let vault_details = Some(vault_details.into());
884
885 Self {
886 header,
887 storage_details,
888 code,
889 vault_details,
890 }
891 }
892}
893
894impl TryFrom<proto::account::AccountWitness> for AccountWitness {
898 type Error = ConversionError;
899
900 fn try_from(account_witness: proto::account::AccountWitness) -> Result<Self, Self::Error> {
901 let decoder = account_witness.decoder();
902 let witness_id = decode!(decoder, account_witness.witness_id)?;
903 let commitment = decode!(decoder, account_witness.commitment)?;
904 let path = decode!(decoder, account_witness.path)?;
905
906 AccountWitness::new(witness_id, commitment, path).map_err(|err| {
907 ConversionError::deserialization(
908 "AccountWitness",
909 DeserializationError::InvalidValue(err.to_string()),
910 )
911 })
912 }
913}
914
915impl From<AccountWitness> for proto::account::AccountWitness {
916 fn from(witness: AccountWitness) -> Self {
917 Self {
918 account_id: Some(witness.id().into()),
919 witness_id: Some(witness.id().into()),
920 commitment: Some(witness.state_commitment().into()),
921 path: Some(witness.into_proof().into_parts().0.into()),
922 }
923 }
924}
925
926#[derive(Clone, Debug, PartialEq, Eq)]
930pub struct AccountWitnessRecord {
931 pub account_id: AccountId,
932 pub witness: AccountWitness,
933}
934
935impl TryFrom<proto::account::AccountWitness> for AccountWitnessRecord {
936 type Error = ConversionError;
937
938 fn try_from(
939 account_witness_record: proto::account::AccountWitness,
940 ) -> Result<Self, Self::Error> {
941 let decoder = account_witness_record.decoder();
942 let witness_id = decode!(decoder, account_witness_record.witness_id)?;
943 let commitment = decode!(decoder, account_witness_record.commitment)?;
944 let account_id = decode!(decoder, account_witness_record.account_id)?;
945 let path: SparseMerklePath = decode!(decoder, account_witness_record.path)?;
946
947 let witness = AccountWitness::new(witness_id, commitment, path).map_err(|err| {
948 ConversionError::deserialization(
949 "AccountWitness",
950 DeserializationError::InvalidValue(err.to_string()),
951 )
952 })?;
953
954 Ok(Self { account_id, witness })
955 }
956}
957
958impl From<AccountWitnessRecord> for proto::account::AccountWitness {
959 fn from(from: AccountWitnessRecord) -> Self {
960 Self {
961 account_id: Some(from.account_id.into()),
962 witness_id: Some(from.witness.id().into()),
963 commitment: Some(from.witness.state_commitment().into()),
964 path: Some(from.witness.path().clone().into()),
965 }
966 }
967}
968
969impl TryFrom<proto::primitives::Asset> for Asset {
973 type Error = ConversionError;
974
975 fn try_from(asset: proto::primitives::Asset) -> Result<Self, Self::Error> {
976 let decoder = asset.decoder();
977 let key_word: Word = decode!(decoder, asset.key)?;
978 let value_word: Word = decode!(decoder, asset.value)?;
979
980 let asset = Asset::from_id_and_value_words(key_word, value_word)?;
981 Ok(asset)
982 }
983}
984
985impl From<Asset> for proto::primitives::Asset {
986 fn from(asset_from: Asset) -> Self {
987 proto::primitives::Asset {
988 key: Some(asset_from.to_id_word().into()),
989 value: Some(asset_from.to_value_word().into()),
990 }
991 }
992}