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