miden_client/transaction/request/
foreign.rs1use alloc::string::ToString;
3use alloc::vec::Vec;
4use core::cmp::Ordering;
5
6use miden_objects::account::{
7 AccountId,
8 PartialAccount,
9 PartialStorage,
10 PartialStorageMap,
11 StorageMap,
12};
13use miden_objects::asset::{AssetVault, PartialVault};
14use miden_objects::transaction::AccountInputs;
15use miden_tx::utils::{Deserializable, DeserializationError, Serializable};
16
17use super::TransactionRequestError;
18use crate::rpc::domain::account::{AccountDetails, AccountProof, AccountStorageRequirements};
19
20#[derive(Clone, Debug, PartialEq, Eq)]
25#[allow(clippy::large_enum_variant)]
26pub enum ForeignAccount {
27 Public(AccountId, AccountStorageRequirements),
31 Private(PartialAccount),
35}
36
37impl ForeignAccount {
38 pub fn public(
42 account_id: AccountId,
43 storage_requirements: AccountStorageRequirements,
44 ) -> Result<Self, TransactionRequestError> {
45 if !account_id.is_public() {
46 return Err(TransactionRequestError::InvalidForeignAccountId(account_id));
47 }
48
49 Ok(Self::Public(account_id, storage_requirements))
50 }
51
52 pub fn private(account: impl Into<PartialAccount>) -> Result<Self, TransactionRequestError> {
55 let partial_account: PartialAccount = account.into();
56 if partial_account.id().is_public() {
57 return Err(TransactionRequestError::InvalidForeignAccountId(partial_account.id()));
58 }
59
60 Ok(Self::Private(partial_account))
61 }
62
63 pub fn storage_slot_requirements(&self) -> AccountStorageRequirements {
64 match self {
65 ForeignAccount::Public(_, account_storage_requirements) => {
66 account_storage_requirements.clone()
67 },
68 ForeignAccount::Private(_) => AccountStorageRequirements::default(),
69 }
70 }
71
72 pub fn account_id(&self) -> AccountId {
74 match self {
75 ForeignAccount::Public(account_id, _) => *account_id,
76 ForeignAccount::Private(partial_account) => partial_account.id(),
77 }
78 }
79}
80
81impl Ord for ForeignAccount {
82 fn cmp(&self, other: &Self) -> Ordering {
83 self.account_id().cmp(&other.account_id())
84 }
85}
86
87impl PartialOrd for ForeignAccount {
88 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
89 Some(self.cmp(other))
90 }
91}
92
93impl Serializable for ForeignAccount {
94 fn write_into<W: miden_tx::utils::ByteWriter>(&self, target: &mut W) {
95 match self {
96 ForeignAccount::Public(account_id, storage_requirements) => {
97 target.write(0u8);
98 account_id.write_into(target);
99 storage_requirements.write_into(target);
100 },
101 ForeignAccount::Private(partial_account) => {
102 target.write(1u8);
103 partial_account.write_into(target);
104 },
105 }
106 }
107}
108
109impl Deserializable for ForeignAccount {
110 fn read_from<R: miden_tx::utils::ByteReader>(
111 source: &mut R,
112 ) -> Result<Self, miden_tx::utils::DeserializationError> {
113 let account_type: u8 = source.read_u8()?;
114 match account_type {
115 0 => {
116 let account_id = AccountId::read_from(source)?;
117 let storage_requirements = AccountStorageRequirements::read_from(source)?;
118 Ok(ForeignAccount::Public(account_id, storage_requirements))
119 },
120 1 => {
121 let foreign_inputs = PartialAccount::read_from(source)?;
122 Ok(ForeignAccount::Private(foreign_inputs))
123 },
124 _ => Err(DeserializationError::InvalidValue("Invalid account type".to_string())),
125 }
126 }
127}
128
129impl TryFrom<AccountProof> for AccountInputs {
130 type Error = TransactionRequestError;
131
132 fn try_from(value: AccountProof) -> Result<Self, Self::Error> {
133 let (witness, account_details) = value.into_parts();
134
135 if let Some(AccountDetails {
136 header: account_header,
137 code,
138 storage_details,
139 vault_details,
140 }) = account_details
141 {
142 let account_storage_map_details = storage_details.map_details;
144 let mut storage_map_proofs = Vec::with_capacity(account_storage_map_details.len());
145 for account_storage_detail in account_storage_map_details {
146 let storage_entries_iter =
147 account_storage_detail.entries.iter().map(|e| (e.key, e.value));
148 let partial_storage = PartialStorageMap::new_full(
149 StorageMap::with_entries(storage_entries_iter)
150 .map_err(TransactionRequestError::StorageMapError)?,
151 );
152 storage_map_proofs.push(partial_storage);
153 }
154
155 let vault = AssetVault::new(&vault_details.assets)?;
156 return Ok(AccountInputs::new(
157 PartialAccount::new(
158 account_header.id(),
159 account_header.nonce(),
160 code,
161 PartialStorage::new(storage_details.header, storage_map_proofs.into_iter())?,
162 PartialVault::new_full(vault),
163 None,
164 )?,
165 witness,
166 ));
167 }
168 Err(TransactionRequestError::ForeignAccountDataMissing)
169 }
170}