1use alloc::collections::BTreeMap;
2use alloc::vec::Vec;
3use core::fmt::{self, Debug, Display, Formatter};
4
5use miden_protocol::account::{
6 Account, AccountCode, AccountHeader, AccountId, AccountStorage, AccountStorageHeader,
7 StorageMap, StorageMapKey, StorageSlot, StorageSlotHeader, StorageSlotName, StorageSlotType,
8};
9use miden_protocol::asset::{Asset, AssetVault};
10use miden_protocol::block::BlockNumber;
11use miden_protocol::block::account_tree::AccountWitness;
12use miden_protocol::crypto::merkle::SparseMerklePath;
13use miden_protocol::crypto::merkle::smt::SmtProof;
14use miden_protocol::{EMPTY_WORD, Word};
15use miden_tx::utils::ToHex;
16use miden_tx::utils::serde::{Deserializable, Serializable};
17use thiserror::Error;
18
19use crate::alloc::string::ToString;
20use crate::rpc::{AccountStateAt, RpcError};
21use crate::rpc::domain::MissingFieldHelper;
22use crate::rpc::errors::RpcConversionError;
23use crate::rpc::generated::rpc::account_request::account_detail_request::storage_map_detail_request::{MapKeys, SlotData};
24use crate::rpc::generated::rpc::account_request::account_detail_request::{
25 StorageMapDetailRequest, StorageMapDetailRequests, StorageRequest,
26};
27use crate::rpc::generated::{self as proto};
28
29impl Display for proto::account::AccountId {
33 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
34 f.write_fmt(format_args!("0x{}", self.id.to_hex()))
35 }
36}
37
38impl Debug for proto::account::AccountId {
39 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
40 Display::fmt(self, f)
41 }
42}
43
44impl From<AccountId> for proto::account::AccountId {
48 fn from(account_id: AccountId) -> Self {
49 Self { id: account_id.to_bytes() }
50 }
51}
52
53impl TryFrom<proto::account::AccountId> for AccountId {
57 type Error = RpcConversionError;
58
59 fn try_from(account_id: proto::account::AccountId) -> Result<Self, Self::Error> {
60 AccountId::read_from_bytes(&account_id.id).map_err(|_| RpcConversionError::NotAValidFelt)
61 }
62}
63
64impl TryInto<AccountHeader> for proto::account::AccountHeader {
68 type Error = crate::rpc::RpcError;
69
70 fn try_into(self) -> Result<AccountHeader, Self::Error> {
71 use miden_protocol::Felt;
72
73 use crate::rpc::domain::MissingFieldHelper;
74
75 let proto::account::AccountHeader {
76 account_id,
77 nonce,
78 vault_root,
79 storage_commitment,
80 code_commitment,
81 } = self;
82
83 let account_id: AccountId = account_id
84 .ok_or(proto::account::AccountHeader::missing_field(stringify!(account_id)))?
85 .try_into()?;
86 let vault_root = vault_root
87 .ok_or(proto::account::AccountHeader::missing_field(stringify!(vault_root)))?
88 .try_into()?;
89 let storage_commitment = storage_commitment
90 .ok_or(proto::account::AccountHeader::missing_field(stringify!(storage_commitment)))?
91 .try_into()?;
92 let code_commitment = code_commitment
93 .ok_or(proto::account::AccountHeader::missing_field(stringify!(code_commitment)))?
94 .try_into()?;
95
96 let nonce = Felt::new(nonce).map_err(|_| RpcConversionError::NotAValidFelt)?;
97 Ok(AccountHeader::new(
98 account_id,
99 nonce,
100 vault_root,
101 storage_commitment,
102 code_commitment,
103 ))
104 }
105}
106
107impl TryInto<AccountStorageHeader> for proto::account::AccountStorageHeader {
111 type Error = crate::rpc::RpcError;
112
113 fn try_into(self) -> Result<AccountStorageHeader, Self::Error> {
114 use crate::rpc::RpcError;
115 use crate::rpc::domain::MissingFieldHelper;
116
117 let mut header_slots: Vec<StorageSlotHeader> = Vec::with_capacity(self.slots.len());
118
119 for slot in self.slots {
120 let slot_value: Word = slot
121 .commitment
122 .ok_or(proto::account::account_storage_header::StorageSlot::missing_field(
123 stringify!(commitment),
124 ))?
125 .try_into()?;
126
127 let slot_type = u8::try_from(slot.slot_type)
128 .map_err(|e| RpcError::InvalidResponse(e.to_string()))
129 .and_then(|v| {
130 StorageSlotType::try_from(v)
131 .map_err(|e| RpcError::InvalidResponse(e.to_string()))
132 })?;
133 let slot_name = StorageSlotName::new(slot.slot_name)
134 .map_err(|err| RpcError::InvalidResponse(err.to_string()))?;
135
136 header_slots.push(StorageSlotHeader::new(slot_name, slot_type, slot_value));
137 }
138
139 header_slots.sort_by_key(StorageSlotHeader::id);
140 AccountStorageHeader::new(header_slots)
141 .map_err(|err| RpcError::InvalidResponse(err.to_string()))
142 }
143}
144
145#[cfg(feature = "tonic")]
149impl proto::rpc::account_response::AccountDetails {
150 pub fn into_domain(
160 self,
161 known_account_codes: &BTreeMap<Word, AccountCode>,
162 storage_requirements: &AccountStorageRequirements,
163 ) -> Result<AccountDetails, crate::rpc::RpcError> {
164 use crate::rpc::RpcError;
165 use crate::rpc::domain::MissingFieldHelper;
166
167 let proto::rpc::account_response::AccountDetails {
168 header,
169 storage_details,
170 code,
171 vault_details,
172 } = self;
173 let header: AccountHeader = header
174 .ok_or(proto::rpc::account_response::AccountDetails::missing_field(stringify!(header)))?
175 .try_into()?;
176
177 let storage_details: AccountStorageDetails = storage_details
178 .ok_or(proto::rpc::account_response::AccountDetails::missing_field(stringify!(
179 storage_details
180 )))?
181 .try_into()?;
182
183 for map_detail in &storage_details.map_details {
187 let requested_keys = storage_requirements
188 .inner()
189 .get(&map_detail.slot_name)
190 .map(Vec::as_slice)
191 .unwrap_or_default();
192
193 if let StorageMapEntries::EntriesWithProofs(proofs) = &map_detail.entries {
194 if proofs.len() != requested_keys.len() {
195 return Err(RpcError::InvalidResponse(format!(
196 "expected {} proofs for storage map slot '{}', got {}",
197 requested_keys.len(),
198 map_detail.slot_name,
199 proofs.len(),
200 )));
201 }
202 for (proof, raw_key) in proofs.iter().zip(requested_keys.iter()) {
203 if proof.get(&raw_key.hash().as_word()).is_none() {
204 return Err(RpcError::InvalidResponse(format!(
205 "proof for storage map key {} does not match the requested key",
206 raw_key.to_hex(),
207 )));
208 }
209 }
210 }
211 }
212
213 let code = {
217 let received_code = code.map(|c| AccountCode::read_from_bytes(&c)).transpose()?;
218 match received_code {
219 Some(code) => code,
220 None => known_account_codes
221 .get(&header.code_commitment())
222 .ok_or(RpcError::InvalidResponse(
223 "Account code was not provided, but the response did not contain it either"
224 .into(),
225 ))?
226 .clone(),
227 }
228 };
229
230 let vault_details = vault_details
231 .ok_or(proto::rpc::AccountVaultDetails::missing_field(stringify!(vault_details)))?
232 .try_into()?;
233
234 Ok(AccountDetails {
235 header,
236 storage_details,
237 code,
238 vault_details,
239 })
240 }
241}
242
243pub type AccountProofs = (BlockNumber, Vec<AccountProof>);
248
249#[derive(Clone, Debug)]
254pub struct AccountDetails {
255 pub header: AccountHeader,
256 pub storage_details: AccountStorageDetails,
257 pub code: AccountCode,
258 pub vault_details: AccountVaultDetails,
259}
260
261impl TryFrom<&AccountDetails> for Account {
262 type Error = RpcError;
263
264 fn try_from(details: &AccountDetails) -> Result<Self, Self::Error> {
270 if details.vault_details.too_many_assets {
271 return Err(RpcError::ExpectedDataMissing(
272 "cannot build account: vault has too many assets".into(),
273 ));
274 }
275
276 if let Some(slot_name) = details
277 .storage_details
278 .map_details
279 .iter()
280 .find(|m| m.too_many_entries)
281 .map(|m| &m.slot_name)
282 {
283 return Err(RpcError::ExpectedDataMissing(format!(
284 "cannot build account: storage map slot '{slot_name}' has too many entries",
285 )));
286 }
287
288 let mut slots: Vec<StorageSlot> = Vec::new();
289
290 for slot_header in details.storage_details.header.slots() {
291 match slot_header.slot_type() {
292 StorageSlotType::Value => {
293 slots.push(StorageSlot::with_value(
294 slot_header.name().clone(),
295 slot_header.value(),
296 ));
297 },
298 StorageSlotType::Map => {
299 let map_details = details
300 .storage_details
301 .find_map_details(slot_header.name())
302 .ok_or_else(|| {
303 RpcError::ExpectedDataMissing(format!(
304 "slot '{}' is a map but has no map_details in response",
305 slot_header.name()
306 ))
307 })?;
308
309 let storage_map = map_details
310 .entries
311 .clone()
312 .into_storage_map()
313 .ok_or_else(|| {
314 RpcError::ExpectedDataMissing(
315 "expected AllEntries for full account fetch, got EntriesWithProofs"
316 .into(),
317 )
318 })?
319 .map_err(|err| {
320 RpcError::InvalidResponse(format!(
321 "the rpc api returned a non-valid map entry: {err}"
322 ))
323 })?;
324
325 slots.push(StorageSlot::with_map(slot_header.name().clone(), storage_map));
326 },
327 }
328 }
329
330 let asset_vault = AssetVault::new(&details.vault_details.assets).map_err(|err| {
331 RpcError::InvalidResponse(format!("rpc api returned non-valid assets: {err}"))
332 })?;
333
334 let account_storage = AccountStorage::new(slots).map_err(|err| {
335 RpcError::InvalidResponse(format!("rpc api returned non-valid storage slots: {err}"))
336 })?;
337
338 Account::new(
339 details.header.id(),
340 asset_vault,
341 account_storage,
342 details.code.clone(),
343 details.header.nonce(),
344 None,
345 )
346 .map_err(|err| {
347 RpcError::InvalidResponse(format!(
348 "failed to construct account from rpc api response: {err}"
349 ))
350 })
351 }
352}
353
354#[derive(Clone, Debug)]
359pub struct AccountStorageDetails {
360 pub header: AccountStorageHeader,
362 pub map_details: Vec<AccountStorageMapDetails>,
364}
365
366impl AccountStorageDetails {
367 pub fn find_map_details(&self, target: &StorageSlotName) -> Option<&AccountStorageMapDetails> {
371 self.map_details.iter().find(|map_detail| map_detail.slot_name == *target)
372 }
373}
374
375impl TryFrom<proto::rpc::AccountStorageDetails> for AccountStorageDetails {
376 type Error = RpcError;
377
378 fn try_from(value: proto::rpc::AccountStorageDetails) -> Result<Self, Self::Error> {
379 let header = value
380 .header
381 .ok_or(proto::account::AccountStorageHeader::missing_field(stringify!(header)))?
382 .try_into()?;
383 let map_details = value
384 .map_details
385 .into_iter()
386 .map(core::convert::TryInto::try_into)
387 .collect::<Result<Vec<AccountStorageMapDetails>, RpcError>>()?;
388
389 Ok(Self { header, map_details })
390 }
391}
392
393#[derive(Clone, Debug)]
397pub struct AccountStorageMapDetails {
398 pub slot_name: StorageSlotName,
400 pub too_many_entries: bool,
404 pub entries: StorageMapEntries,
407}
408
409impl TryFrom<proto::rpc::account_storage_details::AccountStorageMapDetails>
410 for AccountStorageMapDetails
411{
412 type Error = RpcError;
413
414 fn try_from(
415 value: proto::rpc::account_storage_details::AccountStorageMapDetails,
416 ) -> Result<Self, Self::Error> {
417 use proto::rpc::account_storage_details::account_storage_map_details::Entries;
418
419 let slot_name = StorageSlotName::new(value.slot_name)
420 .map_err(|err| RpcError::ExpectedDataMissing(err.to_string()))?;
421 let too_many_entries = value.too_many_entries;
422
423 let entries = match value.entries {
424 Some(Entries::AllEntries(all_entries)) => {
425 let entries = all_entries
426 .entries
427 .into_iter()
428 .map(core::convert::TryInto::try_into)
429 .collect::<Result<Vec<StorageMapEntry>, RpcError>>()?;
430 StorageMapEntries::AllEntries(entries)
431 },
432 Some(Entries::EntriesWithProofs(entries_with_proofs)) => {
433 let proofs = entries_with_proofs
434 .entries
435 .into_iter()
436 .map(|entry| {
437 let proof: SmtProof = entry
438 .proof
439 .ok_or(RpcError::ExpectedDataMissing("proof".into()))?
440 .try_into()?;
441 Ok(proof)
442 })
443 .collect::<Result<Vec<SmtProof>, RpcError>>()?;
444 StorageMapEntries::EntriesWithProofs(proofs)
445 },
446 None => StorageMapEntries::AllEntries(Vec::new()),
447 };
448
449 Ok(Self { slot_name, too_many_entries, entries })
450 }
451}
452
453#[derive(Clone, Debug)]
458pub struct StorageMapEntry {
459 pub key: StorageMapKey,
460 pub value: Word,
461}
462
463impl TryFrom<proto::rpc::account_storage_details::account_storage_map_details::all_map_entries::StorageMapEntry>
464 for StorageMapEntry
465{
466 type Error = RpcError;
467
468 fn try_from(value: proto::rpc::account_storage_details::account_storage_map_details::all_map_entries::StorageMapEntry) -> Result<Self, Self::Error> {
469 let key: StorageMapKey =
470 value.key.ok_or(RpcError::ExpectedDataMissing("key".into()))?.try_into()?;
471 let value = value.value.ok_or(RpcError::ExpectedDataMissing("value".into()))?.try_into()?;
472 Ok(Self { key, value })
473 }
474}
475
476#[derive(Clone, Debug)]
482pub enum StorageMapEntries {
483 AllEntries(Vec<StorageMapEntry>),
485 EntriesWithProofs(Vec<SmtProof>),
487}
488
489impl StorageMapEntries {
490 pub fn into_storage_map(
495 self,
496 ) -> Option<Result<StorageMap, miden_protocol::errors::StorageMapError>> {
497 match self {
498 StorageMapEntries::AllEntries(entries) => {
499 Some(StorageMap::with_entries(entries.into_iter().map(|e| (e.key, e.value))))
500 },
501 StorageMapEntries::EntriesWithProofs(_) => None,
502 }
503 }
504}
505
506#[derive(Clone, Debug)]
510pub struct AccountVaultDetails {
511 pub too_many_assets: bool,
515 pub assets: Vec<Asset>,
518}
519
520impl TryFrom<proto::rpc::AccountVaultDetails> for AccountVaultDetails {
521 type Error = RpcError;
522
523 fn try_from(value: proto::rpc::AccountVaultDetails) -> Result<Self, Self::Error> {
524 let too_many_assets = value.too_many_assets;
525 let assets = value
526 .assets
527 .into_iter()
528 .map(Asset::try_from)
529 .collect::<Result<Vec<Asset>, _>>()?;
530
531 Ok(Self { too_many_assets, assets })
532 }
533}
534
535#[derive(Clone, Debug)]
540pub struct AccountProof {
541 account_witness: AccountWitness,
543 state_headers: Option<AccountDetails>,
545}
546
547impl AccountProof {
548 pub fn new(
550 account_witness: AccountWitness,
551 account_details: Option<AccountDetails>,
552 ) -> Result<Self, AccountProofError> {
553 if let Some(AccountDetails {
554 header: account_header,
555 storage_details: _,
556 code,
557 ..
558 }) = &account_details
559 {
560 if account_header.to_commitment() != account_witness.state_commitment() {
561 return Err(AccountProofError::InconsistentAccountCommitment);
562 }
563 if account_header.id() != account_witness.id() {
564 return Err(AccountProofError::InconsistentAccountId);
565 }
566 if code.commitment() != account_header.code_commitment() {
567 return Err(AccountProofError::InconsistentCodeCommitment);
568 }
569 }
570
571 Ok(Self {
572 account_witness,
573 state_headers: account_details,
574 })
575 }
576
577 pub fn account_id(&self) -> AccountId {
579 self.account_witness.id()
580 }
581
582 pub fn account_header(&self) -> Option<&AccountHeader> {
584 self.state_headers.as_ref().map(|account_details| &account_details.header)
585 }
586
587 pub fn storage_header(&self) -> Option<&AccountStorageHeader> {
589 self.state_headers
590 .as_ref()
591 .map(|account_details| &account_details.storage_details.header)
592 }
593
594 pub fn storage_details(&self) -> Option<&AccountStorageDetails> {
596 self.state_headers.as_ref().map(|d| &d.storage_details)
597 }
598
599 pub fn vault_details(&self) -> Option<&AccountVaultDetails> {
601 self.state_headers.as_ref().map(|d| &d.vault_details)
602 }
603
604 pub fn find_map_details(
606 &self,
607 slot_name: &StorageSlotName,
608 ) -> Option<&AccountStorageMapDetails> {
609 self.state_headers
610 .as_ref()
611 .and_then(|details| details.storage_details.find_map_details(slot_name))
612 }
613
614 pub fn account_code(&self) -> Option<&AccountCode> {
616 self.state_headers.as_ref().map(|headers| &headers.code)
617 }
618
619 pub fn code_commitment(&self) -> Option<Word> {
621 self.account_code().map(AccountCode::commitment)
622 }
623
624 pub fn account_commitment(&self) -> Word {
626 self.account_witness.state_commitment()
627 }
628
629 pub fn account_witness(&self) -> &AccountWitness {
630 &self.account_witness
631 }
632
633 pub fn merkle_proof(&self) -> &SparseMerklePath {
635 self.account_witness.path()
636 }
637
638 pub fn into_parts(self) -> (AccountWitness, Option<AccountDetails>) {
640 (self.account_witness, self.state_headers)
641 }
642
643 pub fn into_details(self) -> Option<AccountDetails> {
645 self.state_headers
646 }
647
648 pub fn details_mut(&mut self) -> Option<&mut AccountDetails> {
654 self.state_headers.as_mut()
655 }
656}
657
658#[cfg(feature = "tonic")]
659impl TryFrom<proto::rpc::AccountResponse> for AccountProof {
660 type Error = RpcError;
661 fn try_from(account_proof: proto::rpc::AccountResponse) -> Result<Self, Self::Error> {
662 let Some(witness) = account_proof.witness else {
663 return Err(RpcError::ExpectedDataMissing(
664 "GetAccount returned an account without witness".to_string(),
665 ));
666 };
667
668 let details: Option<AccountDetails> = {
669 match account_proof.details {
670 None => None,
671 Some(details) => Some(
672 details
673 .into_domain(&BTreeMap::new(), &AccountStorageRequirements::default())?,
674 ),
675 }
676 };
677 AccountProof::new(witness.try_into()?, details)
678 .map_err(|err| RpcError::InvalidResponse(format!("{err}")))
679 }
680}
681
682impl TryFrom<proto::account::AccountWitness> for AccountWitness {
686 type Error = RpcError;
687
688 fn try_from(account_witness: proto::account::AccountWitness) -> Result<Self, Self::Error> {
689 let state_commitment = account_witness
690 .commitment
691 .ok_or(proto::account::AccountWitness::missing_field(stringify!(state_commitment)))?
692 .try_into()?;
693 let merkle_path = account_witness
694 .path
695 .ok_or(proto::account::AccountWitness::missing_field(stringify!(merkle_path)))?
696 .try_into()?;
697 let account_id = account_witness
698 .witness_id
699 .ok_or(proto::account::AccountWitness::missing_field(stringify!(witness_id)))?
700 .try_into()?;
701
702 let witness = AccountWitness::new(account_id, state_commitment, merkle_path)
703 .map_err(|err| RpcError::InvalidResponse(format!("{err}")))?;
704 Ok(witness)
705 }
706}
707
708#[derive(Clone, Debug, Default, Eq, PartialEq)]
717pub struct AccountStorageRequirements(BTreeMap<StorageSlotName, Vec<StorageMapKey>>);
718
719impl AccountStorageRequirements {
720 pub fn new<'a>(
723 slots_and_keys: impl IntoIterator<
724 Item = (StorageSlotName, impl IntoIterator<Item = &'a StorageMapKey>),
725 >,
726 ) -> Self {
727 let map = slots_and_keys
728 .into_iter()
729 .map(|(slot_name, keys_iter)| {
730 let keys_vec: Vec<StorageMapKey> = keys_iter.into_iter().copied().collect();
731 (slot_name, keys_vec)
732 })
733 .collect();
734
735 AccountStorageRequirements(map)
736 }
737
738 pub fn all_entries(slot_names: &[StorageSlotName]) -> Self {
741 AccountStorageRequirements(
742 slot_names.iter().map(|name| (name.clone(), Vec::new())).collect(),
743 )
744 }
745
746 pub fn inner(&self) -> &BTreeMap<StorageSlotName, Vec<StorageMapKey>> {
747 &self.0
748 }
749
750 pub fn keys_for_slot(&self, slot_name: &StorageSlotName) -> &[StorageMapKey] {
752 self.0.get(slot_name).map_or(&[], Vec::as_slice)
753 }
754}
755
756impl From<AccountStorageRequirements> for Vec<StorageMapDetailRequest> {
757 fn from(value: AccountStorageRequirements) -> Vec<StorageMapDetailRequest> {
758 let request_map = value.0;
759 let mut requests = Vec::with_capacity(request_map.len());
760 for (slot_name, map_keys) in request_map {
761 let slot_data = if map_keys.is_empty() {
762 Some(SlotData::AllEntries(true))
763 } else {
764 let keys = map_keys.into_iter().map(|key| Word::from(key).into()).collect();
765 Some(SlotData::MapKeys(MapKeys { map_keys: keys }))
766 };
767 requests.push(StorageMapDetailRequest {
768 slot_name: slot_name.to_string(),
769 slot_data,
770 });
771 }
772 requests
773 }
774}
775
776impl Serializable for AccountStorageRequirements {
777 fn write_into<W: miden_tx::utils::serde::ByteWriter>(&self, target: &mut W) {
778 target.write(&self.0);
779 }
780}
781
782impl Deserializable for AccountStorageRequirements {
783 fn read_from<R: miden_tx::utils::serde::ByteReader>(
784 source: &mut R,
785 ) -> Result<Self, miden_tx::utils::serde::DeserializationError> {
786 Ok(AccountStorageRequirements(source.read()?))
787 }
788}
789
790#[derive(Clone, Debug, Default)]
795pub enum VaultFetch {
796 #[default]
798 Skip,
799 Always,
801 IfChangedFrom(Word),
803}
804
805impl From<VaultFetch> for Option<proto::primitives::Digest> {
806 fn from(vault: VaultFetch) -> Self {
809 match vault {
810 VaultFetch::Skip => None,
811 VaultFetch::Always => Some(EMPTY_WORD.into()),
812 VaultFetch::IfChangedFrom(commitment) => Some(commitment.into()),
813 }
814 }
815}
816
817#[derive(Clone, Debug, Default)]
823pub enum StorageMapFetch {
824 #[default]
826 Skip,
827 All,
831 Slots(AccountStorageRequirements),
834}
835
836impl From<StorageMapFetch> for Option<StorageRequest> {
837 fn from(storage: StorageMapFetch) -> Self {
838 match storage {
839 StorageMapFetch::Skip => None,
840 StorageMapFetch::All => Some(StorageRequest::AllStorageMaps(true)),
841 StorageMapFetch::Slots(reqs) => {
842 Some(StorageRequest::StorageMaps(StorageMapDetailRequests {
843 storage_maps: reqs.into(),
844 }))
845 },
846 }
847 }
848}
849
850#[derive(Clone, Debug, Default)]
852pub struct GetAccountRequest {
853 pub storage: StorageMapFetch,
855 pub at: AccountStateAt,
857 pub known_code: Option<AccountCode>,
860 pub vault: VaultFetch,
862}
863
864impl GetAccountRequest {
865 #[must_use]
869 pub fn new() -> Self {
870 Self {
871 storage: StorageMapFetch::Skip,
872 at: AccountStateAt::ChainTip,
873 known_code: None,
874 vault: VaultFetch::Skip,
875 }
876 }
877
878 #[must_use]
880 pub fn with_storage(mut self, storage: StorageMapFetch) -> Self {
881 self.storage = storage;
882 self
883 }
884
885 #[must_use]
887 pub fn at(mut self, at: AccountStateAt) -> Self {
888 self.at = at;
889 self
890 }
891
892 #[must_use]
895 pub fn with_known_code(mut self, known_code: Option<AccountCode>) -> Self {
896 self.known_code = known_code;
897 self
898 }
899
900 #[must_use]
902 pub fn with_vault(mut self, vault: VaultFetch) -> Self {
903 self.vault = vault;
904 self
905 }
906}
907
908#[derive(Debug, Error)]
912pub enum AccountProofError {
913 #[error(
914 "the received account commitment doesn't match the received account header's commitment"
915 )]
916 InconsistentAccountCommitment,
917 #[error("the received account id doesn't match the received account header's id")]
918 InconsistentAccountId,
919 #[error(
920 "the received code commitment doesn't match the received account header's code commitment"
921 )]
922 InconsistentCodeCommitment,
923}