-
Notifications
You must be signed in to change notification settings - Fork 89
feat: Support foreign accounts #1486
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 13 commits
8638784
9df9847
7a13e15
485f543
014ffb4
8135b4f
454043f
ae1b914
d22e32e
be374a1
5d92060
c025849
aa59a0e
31a30c5
a07d656
5b0e863
95faf66
243a28e
27f7919
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -6,10 +6,11 @@ use miden_protocol::account::{ | |
| Account, | ||
| AccountId, | ||
| PartialAccount, | ||
| StorageMap, | ||
| StorageMapWitness, | ||
| StorageSlotContent, | ||
| }; | ||
| use miden_protocol::asset::{AssetVaultKey, AssetWitness}; | ||
| use miden_protocol::asset::{AssetVault, AssetVaultKey, AssetWitness}; | ||
| use miden_protocol::block::{BlockHeader, BlockNumber}; | ||
| use miden_protocol::note::{Note, NoteScript}; | ||
| use miden_protocol::transaction::{ | ||
|
|
@@ -339,9 +340,45 @@ impl DataStore for NtxDataStore { | |
| fn get_foreign_account_inputs( | ||
| &self, | ||
| foreign_account_id: AccountId, | ||
| _ref_block: BlockNumber, | ||
| ref_block: BlockNumber, | ||
| ) -> impl FutureMaybeSend<Result<AccountInputs, DataStoreError>> { | ||
| async move { Err(DataStoreError::AccountNotFound(foreign_account_id)) } | ||
| let store = self.store.clone(); | ||
| async move { | ||
| if foreign_account_id == self.account.id() { | ||
| return Err(DataStoreError::Other { | ||
| error_msg: format!( | ||
| "requested account with id {foreign_account_id} is local, not foreign" | ||
| ) | ||
| .into(), | ||
| source: None, | ||
| }); | ||
| } | ||
|
|
||
| // Retrieve the account proof from the store. | ||
| let account_proof = store | ||
| .get_account(foreign_account_id, Some(ref_block.as_u32())) | ||
| .await | ||
| .map_err(|err| DataStoreError::Other { | ||
| error_msg: format!("failed to get account proof from store: {err}").into(), | ||
| source: Some(Box::new(err)), | ||
| })?; | ||
|
|
||
| // Construct account from account proof account details. | ||
| let account_details = account_proof.details.ok_or_else(|| DataStoreError::Other { | ||
| error_msg: "account proof does not contain account details".into(), | ||
| source: None, | ||
| })?; | ||
| let account = | ||
| Account::try_from(&account_details).map_err(|err| DataStoreError::Other { | ||
| error_msg: format!("failed to convert account details to account: {err}") | ||
| .into(), | ||
| source: Some(Box::new(err)), | ||
| })?; | ||
|
|
||
| // Return partial account and witness. | ||
| let partial_account = PartialAccount::from(&account); | ||
sergerad marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
| Ok(AccountInputs::new(partial_account, account_proof.witness)) | ||
| } | ||
| } | ||
|
|
||
| fn get_vault_asset_witnesses( | ||
|
|
@@ -350,26 +387,41 @@ impl DataStore for NtxDataStore { | |
| vault_root: Word, | ||
| vault_keys: BTreeSet<AssetVaultKey>, | ||
| ) -> impl FutureMaybeSend<Result<Vec<AssetWitness>, DataStoreError>> { | ||
| let store = self.store.clone(); | ||
| async move { | ||
| if self.account.id() != account_id { | ||
| return Err(DataStoreError::AccountNotFound(account_id)); | ||
| } | ||
|
|
||
| if self.account.vault().root() != vault_root { | ||
| return Err(DataStoreError::Other { | ||
| error_msg: "vault root mismatch".into(), | ||
| source: None, | ||
| }); | ||
| } | ||
|
|
||
| Result::<Vec<_>, _>::from_iter(vault_keys.into_iter().map(|vault_key| { | ||
| AssetWitness::new(self.account.vault().open(vault_key).into()).map_err(|err| { | ||
| if self.account.id() == account_id { | ||
| if self.account.vault().root() != vault_root { | ||
| return Err(DataStoreError::Other { | ||
| error_msg: "vault root mismatch".into(), | ||
| source: None, | ||
| }); | ||
| } | ||
| get_asset_witnesses(vault_keys, self.account.vault()) | ||
| } else { | ||
| // Get foreign account. | ||
| let account_proof = store.get_account(account_id, None).await.map_err(|err| { | ||
| DataStoreError::Other { | ||
| error_msg: "failed to open vault asset tree".into(), | ||
| error_msg: format!("Failed to get account inputs from store: {err}").into(), | ||
| source: Some(Box::new(err)), | ||
| } | ||
| }) | ||
| })) | ||
| })?; | ||
|
|
||
| // Construct vault from account details. | ||
| let account_details = | ||
| account_proof.details.ok_or_else(|| DataStoreError::Other { | ||
| error_msg: "account proof does not contain account details".into(), | ||
| source: None, | ||
| })?; | ||
| let asset_vault = | ||
| AssetVault::new(&account_details.vault_details.assets).map_err(|err| { | ||
| DataStoreError::Other { | ||
| error_msg: format!("failed to create asset vault: {err}").into(), | ||
| source: Some(Box::new(err)), | ||
| } | ||
| })?; | ||
|
|
||
| get_asset_witnesses(vault_keys, &asset_vault) | ||
|
||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -379,28 +431,52 @@ impl DataStore for NtxDataStore { | |
| map_root: Word, | ||
| map_key: Word, | ||
| ) -> impl FutureMaybeSend<Result<StorageMapWitness, DataStoreError>> { | ||
| let store = self.store.clone(); | ||
| async move { | ||
| if self.account.id() != account_id { | ||
| return Err(DataStoreError::AccountNotFound(account_id)); | ||
| } | ||
|
|
||
| let mut map_witness = None; | ||
| for slot in self.account.storage().slots() { | ||
| if let StorageSlotContent::Map(map) = slot.content() { | ||
| if map.root() == map_root { | ||
| map_witness = Some(map.open(&map_key)); | ||
| let map_witness = if self.account.id() == account_id { | ||
| // Search through local account's storage slots. | ||
| self.account.storage().slots().iter().find_map(|slot| { | ||
| if let StorageSlotContent::Map(map) = slot.content() { | ||
| if map.root() == map_root { | ||
| Some(map.open(&map_key)) | ||
| } else { | ||
| None | ||
| } | ||
| } else { | ||
| None | ||
| } | ||
| } | ||
| } | ||
|
|
||
| if let Some(map_witness) = map_witness { | ||
| Ok(map_witness) | ||
| }) | ||
| } else { | ||
| Err(DataStoreError::Other { | ||
| error_msg: "account storage does not contain the expected root".into(), | ||
| source: None, | ||
| // Get foreign account. | ||
| let account_proof = store.get_account(account_id, None).await.map_err(|err| { | ||
| DataStoreError::Other { | ||
| error_msg: format!("failed to get account proof from store: {err}").into(), | ||
| source: Some(Box::new(err)), | ||
| } | ||
| })?; | ||
| let account_details = | ||
| account_proof.details.ok_or_else(|| DataStoreError::Other { | ||
| error_msg: "account proof does not contain account details".into(), | ||
| source: None, | ||
| })?; | ||
|
|
||
| // Search through foreign account's storage maps. | ||
| account_details.storage_details.map_details.iter().find_map(|map_details| { | ||
| let storage_map = | ||
| StorageMap::with_entries(map_details.map_entries.iter().copied()) | ||
| .expect("no duplicate entries"); | ||
| if storage_map.root() == map_root { | ||
| Some(storage_map.open(&map_key)) | ||
| } else { | ||
| None | ||
| } | ||
| }) | ||
| } | ||
| }; | ||
|
|
||
| map_witness.ok_or_else(|| DataStoreError::Other { | ||
| error_msg: "account storage does not contain the expected root".into(), | ||
| source: None, | ||
| }) | ||
| } | ||
| } | ||
|
|
||
|
|
@@ -445,3 +521,18 @@ impl MastForestStore for NtxDataStore { | |
| self.mast_store.get(procedure_hash) | ||
| } | ||
| } | ||
|
|
||
| // HELPERS | ||
| // ================================================================================================ | ||
|
|
||
| fn get_asset_witnesses( | ||
| vault_keys: BTreeSet<AssetVaultKey>, | ||
| vault: &AssetVault, | ||
| ) -> Result<Vec<AssetWitness>, DataStoreError> { | ||
| Result::<Vec<_>, _>::from_iter(vault_keys.into_iter().map(|vault_key| { | ||
| AssetWitness::new(vault.open(vault_key).into()).map_err(|err| DataStoreError::Other { | ||
| error_msg: "failed to open vault asset tree".into(), | ||
| source: Some(Box::new(err)), | ||
| }) | ||
| })) | ||
| } | ||
Uh oh!
There was an error while loading. Please reload this page.