Skip to main content

miden_objects/decoded/account/
patch.rs

1use miden_protobuf::unwrap_infallible;
2pub use proto::account::DecodedAccountVaultPatchEntry as AccountVaultPatchEntry;
3
4use crate::decoded::VerificationError;
5use crate::{Verify, proto};
6
7#[cfg(test)]
8mod tests;
9
10impl Verify for AccountVaultPatchEntry {
11    type Verified = (miden_protocol::asset::AssetId, miden_protocol::Word);
12    type Error = miden_protocol::errors::AssetError;
13    fn verify(self) -> Result<Self::Verified, Self::Error> {
14        Ok((self.asset_id.try_into()?, self.value))
15    }
16}
17
18pub use proto::account::DecodedAccountVaultPatch as AccountVaultPatch;
19
20impl Verify for AccountVaultPatch {
21    type Verified = miden_protocol::account::AccountVaultPatch;
22    type Error = VerificationError;
23    fn verify(self) -> Result<Self::Verified, Self::Error> {
24        let mut entries = alloc::collections::BTreeMap::new();
25        for entry in self.entries.into_inner() {
26            let (id, value) = entry.verify()?;
27            if entries.insert(id, value).is_some() {
28                return Err(VaultPatchError::DuplicateAssetId(id).into());
29            }
30        }
31        Ok(Self::Verified::new(entries)?)
32    }
33}
34
35#[derive(Debug, thiserror::Error)]
36pub enum VaultPatchError {
37    #[error("duplicate vault asset ID {0}")]
38    DuplicateAssetId(miden_protocol::asset::AssetId),
39}
40
41pub use proto::account::DecodedAccountCodePatch as AccountCodePatch;
42
43impl Verify for AccountCodePatch {
44    type Verified = miden_protocol::account::AccountCodePatch;
45    type Error = VerificationError;
46    fn verify(self) -> Result<Self::Verified, Self::Error> {
47        Ok(Self::Verified::new(self.code.verify()?))
48    }
49}
50
51pub use proto::account::DecodedPrivateAccountUpdate as PrivateAccountUpdate;
52
53impl Verify for PrivateAccountUpdate {
54    type Verified = miden_protocol::account::AccountUpdateDetails;
55    type Error = core::convert::Infallible;
56    fn verify(self) -> Result<Self::Verified, Self::Error> {
57        Ok(Self::Verified::Private)
58    }
59}
60
61pub use proto::account::DecodedStorageMapPatchEntries as StorageMapPatchEntries;
62
63impl Verify for StorageMapPatchEntries {
64    type Verified = miden_protocol::account::StorageMapPatchEntries;
65    type Error = StorageMapPatchError;
66    fn verify(self) -> Result<Self::Verified, Self::Error> {
67        let mut entries = alloc::collections::BTreeMap::new();
68        for entry in self.entries.into_inner() {
69            let (key, value) = unwrap_infallible(entry.verify());
70            if entries.insert(key, value).is_some() {
71                return Err(StorageMapPatchError::DuplicateKey(key));
72            }
73        }
74        Ok(Self::Verified::from_raw(entries))
75    }
76}
77
78pub use proto::account::DecodedStorageMapPatch as StorageMapPatch;
79
80impl Verify for StorageMapPatch {
81    type Verified = miden_protocol::account::StorageMapPatch;
82    type Error = StorageMapPatchError;
83    fn verify(self) -> Result<Self::Verified, Self::Error> {
84        use proto::account::storage_map_patch::DecodedOperation;
85        match self.operation {
86            DecodedOperation::Create(entries) => {
87                Ok(Self::Verified::Create { entries: entries.verify()? })
88            },
89            DecodedOperation::Update(entries) => {
90                let entries = entries.verify()?;
91                if entries.is_empty() {
92                    return Err(StorageMapPatchError::EmptyUpdate);
93                }
94                Ok(Self::Verified::Update { entries })
95            },
96            DecodedOperation::Remove(()) => Ok(Self::Verified::Remove),
97        }
98    }
99}
100
101#[derive(Debug, thiserror::Error)]
102pub enum StorageMapPatchError {
103    #[error("entries must be non-empty for an update operation")]
104    EmptyUpdate,
105    #[error("duplicate storage map key {0:?}")]
106    DuplicateKey(miden_protocol::account::StorageMapKey),
107}
108
109pub use proto::account::DecodedStorageValuePatch as StorageValuePatch;
110
111impl Verify for StorageValuePatch {
112    type Verified = miden_protocol::account::StorageValuePatch;
113    type Error = core::convert::Infallible;
114    fn verify(self) -> Result<Self::Verified, Self::Error> {
115        use proto::account::storage_value_patch::DecodedOperation;
116        Ok(match self.operation {
117            DecodedOperation::Create(value) => Self::Verified::Create { value },
118            DecodedOperation::Update(value) => Self::Verified::Update { value },
119            DecodedOperation::Remove(()) => Self::Verified::Remove,
120        })
121    }
122}
123
124pub use proto::account::DecodedStorageSlotPatch as StorageSlotPatch;
125
126impl Verify for StorageSlotPatch {
127    type Verified = (
128        miden_protocol::account::StorageSlotName,
129        miden_protocol::account::StorageSlotPatch,
130    );
131    type Error = VerificationError;
132    fn verify(self) -> Result<Self::Verified, Self::Error> {
133        use miden_protocol::account::{StorageSlotName, StorageSlotPatch};
134        use proto::account::storage_slot_patch::DecodedPatch;
135        let name = StorageSlotName::new(self.slot_name)?;
136        let patch = match self.patch {
137            DecodedPatch::Value(value) => {
138                StorageSlotPatch::Value(unwrap_infallible(value.verify()))
139            },
140            DecodedPatch::Map(map) => StorageSlotPatch::Map(map.verify()?),
141        };
142        Ok((name, patch))
143    }
144}
145
146pub use proto::account::DecodedAccountStoragePatch as AccountStoragePatch;
147
148impl Verify for AccountStoragePatch {
149    type Verified = miden_protocol::account::AccountStoragePatch;
150    type Error = VerificationError;
151    fn verify(self) -> Result<Self::Verified, Self::Error> {
152        let slots = self.slots.verify()?;
153        Ok(Self::Verified::from_entries(slots)?)
154    }
155}
156
157pub use proto::account::DecodedAccountPatch as AccountPatch;
158
159impl Verify for AccountPatch {
160    type Verified = miden_protocol::account::AccountPatch;
161    type Error = VerificationError;
162    fn verify(self) -> Result<Self::Verified, Self::Error> {
163        if self.version != proto::account::AccountPatchVersion::V1 {
164            return Err(AccountPatchError::UnspecifiedVersion.into());
165        }
166        Ok(Self::Verified::new(
167            self.account_id.verify()?,
168            self.storage.verify()?,
169            self.vault.verify()?,
170            self.code.verify()?,
171            self.final_nonce.into_inner(),
172        )?)
173    }
174}
175
176#[derive(Debug, thiserror::Error)]
177pub enum AccountPatchError {
178    #[error("account patch version is unspecified")]
179    UnspecifiedVersion,
180}
181
182pub use proto::account::DecodedAccountUpdateDetails as AccountUpdateDetails;
183
184impl Verify for AccountUpdateDetails {
185    type Verified = miden_protocol::account::AccountUpdateDetails;
186    type Error = VerificationError;
187    fn verify(self) -> Result<Self::Verified, Self::Error> {
188        use proto::account::account_update_details::DecodedUpdate;
189        match self.update {
190            DecodedUpdate::Private(value) => Ok(unwrap_infallible(value.verify())),
191            DecodedUpdate::Public(patch) => Ok(Self::Verified::Public(patch.verify()?)),
192        }
193    }
194}