miden_client/transaction/request/
foreign.rs1use alloc::string::ToString;
3use alloc::vec::Vec;
4use core::cmp::Ordering;
5
6use miden_objects::account::{AccountId, PartialAccount, PartialStorage, PartialStorageMap};
7use miden_objects::asset::PartialVault;
8use miden_objects::crypto::merkle::PartialSmt;
9use miden_objects::transaction::AccountInputs;
10use miden_tx::utils::{Deserializable, DeserializationError, Serializable};
11
12use super::TransactionRequestError;
13use crate::rpc::domain::account::{AccountProof, AccountStorageRequirements, StateHeaders};
14
15#[derive(Clone, Debug, PartialEq, Eq)]
20#[allow(clippy::large_enum_variant)]
21pub enum ForeignAccount {
22 Public(AccountId, AccountStorageRequirements),
26 Private(PartialAccount),
30}
31
32impl ForeignAccount {
33 pub fn public(
37 account_id: AccountId,
38 storage_requirements: AccountStorageRequirements,
39 ) -> Result<Self, TransactionRequestError> {
40 if !account_id.is_public() {
41 return Err(TransactionRequestError::InvalidForeignAccountId(account_id));
42 }
43
44 Ok(Self::Public(account_id, storage_requirements))
45 }
46
47 pub fn private(account: impl Into<PartialAccount>) -> Result<Self, TransactionRequestError> {
50 let partial_account: PartialAccount = account.into();
51 if partial_account.id().is_public() {
52 return Err(TransactionRequestError::InvalidForeignAccountId(partial_account.id()));
53 }
54
55 Ok(Self::Private(partial_account))
56 }
57
58 pub fn storage_slot_requirements(&self) -> AccountStorageRequirements {
59 match self {
60 ForeignAccount::Public(_, account_storage_requirements) => {
61 account_storage_requirements.clone()
62 },
63 ForeignAccount::Private(_) => AccountStorageRequirements::default(),
64 }
65 }
66
67 pub fn account_id(&self) -> AccountId {
69 match self {
70 ForeignAccount::Public(account_id, _) => *account_id,
71 ForeignAccount::Private(partial_account) => partial_account.id(),
72 }
73 }
74}
75
76impl Ord for ForeignAccount {
77 fn cmp(&self, other: &Self) -> Ordering {
78 self.account_id().cmp(&other.account_id())
79 }
80}
81
82impl PartialOrd for ForeignAccount {
83 fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
84 Some(self.cmp(other))
85 }
86}
87
88impl Serializable for ForeignAccount {
89 fn write_into<W: miden_tx::utils::ByteWriter>(&self, target: &mut W) {
90 match self {
91 ForeignAccount::Public(account_id, storage_requirements) => {
92 target.write(0u8);
93 account_id.write_into(target);
94 storage_requirements.write_into(target);
95 },
96 ForeignAccount::Private(partial_account) => {
97 target.write(1u8);
98 partial_account.write_into(target);
99 },
100 }
101 }
102}
103
104impl Deserializable for ForeignAccount {
105 fn read_from<R: miden_tx::utils::ByteReader>(
106 source: &mut R,
107 ) -> Result<Self, miden_tx::utils::DeserializationError> {
108 let account_type: u8 = source.read_u8()?;
109 match account_type {
110 0 => {
111 let account_id = AccountId::read_from(source)?;
112 let storage_requirements = AccountStorageRequirements::read_from(source)?;
113 Ok(ForeignAccount::Public(account_id, storage_requirements))
114 },
115 1 => {
116 let foreign_inputs = PartialAccount::read_from(source)?;
117 Ok(ForeignAccount::Private(foreign_inputs))
118 },
119 _ => Err(DeserializationError::InvalidValue("Invalid account type".to_string())),
120 }
121 }
122}
123
124impl TryFrom<AccountProof> for AccountInputs {
125 type Error = TransactionRequestError;
126
127 fn try_from(value: AccountProof) -> Result<Self, Self::Error> {
128 let (witness, state_headers) = value.into_parts();
129
130 if let Some(StateHeaders {
131 account_header,
132 storage_header,
133 code,
134 storage_slots,
135 }) = state_headers
136 {
137 let mut storage_map_proofs = Vec::with_capacity(storage_slots.len());
139 for (_, slots) in storage_slots {
140 let storage_map = PartialStorageMap::new(PartialSmt::from_proofs(slots)?);
141 storage_map_proofs.push(storage_map);
142 }
143
144 return Ok(AccountInputs::new(
145 PartialAccount::new(
146 account_header.id(),
147 account_header.nonce(),
148 code,
149 PartialStorage::new(storage_header, storage_map_proofs.into_iter())?,
150 PartialVault::new(PartialSmt::new())
152 .expect("Empty partial vault shouldn't fail"),
153 ),
154 witness,
155 ));
156 }
157 Err(TransactionRequestError::ForeignAccountDataMissing)
158 }
159}