Skip to content

Commit

Permalink
Web Client Account Integration Tests
Browse files Browse the repository at this point in the history
  • Loading branch information
Dennis Garcia committed Sep 26, 2024
1 parent 5fd982d commit b1f5494
Show file tree
Hide file tree
Showing 23 changed files with 902 additions and 236 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## 0.6.0 (TBD)

* Add Account Integration Tests for Web Client (#532)
* Fix Broken WASM (#519).
* [BREAKING] Changed `PaymentTransactionData` and `TransactionRequest` to allow for multiple assets per note (#525).
* [BREAKING] Removed serde's de/serialization from `NoteRecordDetails` and `NoteStatus` (#514).
Expand Down
98 changes: 68 additions & 30 deletions crates/rust-client/src/store/web_store/accounts/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use miden_objects::{
assets::{Asset, AssetVault},
Digest, Word,
};
use miden_tx::utils::{Deserializable, Serializable};
use miden_tx::utils::{Deserializable, DeserializationError, Serializable};
use serde_wasm_bindgen::from_value;
use wasm_bindgen_futures::*;

Expand Down Expand Up @@ -42,16 +42,28 @@ impl WebStore {
&self,
) -> Result<Vec<(AccountHeader, Option<Word>)>, StoreError> {
let promise = idxdb_get_account_headers();
let js_value = JsFuture::from(promise).await.unwrap();
let account_headers_idxdb: Vec<AccountRecordIdxdbOjbect> = from_value(js_value).unwrap();

let account_headers: Result<Vec<(AccountHeader, Option<Word>)>, StoreError> =
account_headers_idxdb
.into_iter()
.map(parse_account_record_idxdb_object)
.collect(); // Collect results into a single Result

account_headers
match JsFuture::from(promise).await {
Ok(js_value) => {
let account_headers_idxdb: Vec<AccountRecordIdxdbOjbect> = from_value(js_value)
.map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(
format!("Failed to deserialize {:?}", err),
))
})?;
let account_headers: Result<Vec<(AccountHeader, Option<Word>)>, StoreError> =
account_headers_idxdb
.into_iter()
.map(parse_account_record_idxdb_object)
.collect(); // Collect results into a single Result

account_headers
},
Err(js_error) => Err(StoreError::DatabaseError(format!(
"Failed to fetch account headers: {:?}",
js_error
))),
}
}

pub(crate) async fn get_account_header(
Expand All @@ -61,10 +73,21 @@ impl WebStore {
let account_id_str = account_id.to_string();

let promise = idxdb_get_account_header(account_id_str);
let js_value = JsFuture::from(promise).await.unwrap();
let account_header_idxdb: AccountRecordIdxdbOjbect = from_value(js_value).unwrap();

parse_account_record_idxdb_object(account_header_idxdb)
match JsFuture::from(promise).await {
Ok(js_value) => {
let account_header_idxdb: AccountRecordIdxdbOjbect =
from_value(js_value).map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(
format!("Failed to deserialize {:?}", err),
))
})?;
let parsed_account_record =
parse_account_record_idxdb_object(account_header_idxdb)?;
Ok(parsed_account_record)
},
Err(_) => Err(StoreError::AccountDataNotFound(account_id)),
}
}

pub(crate) async fn get_account_header_by_hash(
Expand All @@ -91,7 +114,7 @@ impl WebStore {
&self,
account_id: AccountId,
) -> Result<(Account, Option<Word>), StoreError> {
let (account_header, seed) = self.get_account_header(account_id).await.unwrap();
let (account_header, seed) = self.get_account_header(account_id).await?;
let account_code = self.get_account_code(account_header.code_commitment()).await.unwrap();

let account_storage =
Expand Down Expand Up @@ -155,15 +178,22 @@ impl WebStore {
account_id: AccountId,
) -> Result<AuthSecretKey, StoreError> {
let account_id_str = account_id.to_string();

let promise = idxdb_get_account_auth(account_id_str);
let js_value = JsFuture::from(promise).await.unwrap();
let auth_info_idxdb: AccountAuthIdxdbObject = from_value(js_value).unwrap();

// Convert the auth_info to the appropriate AuthInfo enum variant
let auth_info = AuthSecretKey::read_from_bytes(&auth_info_idxdb.auth_info)?;

Ok(auth_info)
match JsFuture::from(promise).await {
Ok(js_value) => {
let account_auth_idxdb: AccountAuthIdxdbObject =
from_value(js_value).map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(
format!("Failed to deserialize {:?}", err),
))
})?;
let auth_info = AuthSecretKey::read_from_bytes(&account_auth_idxdb.auth_info)?;

Ok(auth_info)
},
Err(_) => Err(StoreError::AccountDataNotFound(account_id)),
}
}

pub(crate) async fn insert_account(
Expand Down Expand Up @@ -202,15 +232,23 @@ impl WebStore {
/// store. This is used in the web_client so adding this to ignore the dead code warning.
pub async fn fetch_and_cache_account_auth_by_pub_key(
&self,
account_id: String,
account_id: &str,
) -> Result<AuthSecretKey, StoreError> {
let promise = idxdb_fetch_and_cache_account_auth_by_pub_key(account_id);
let js_value = JsFuture::from(promise).await.unwrap();
let account_auth_idxdb: AccountAuthIdxdbObject = from_value(js_value).unwrap();

// Convert the auth_info to the appropriate AuthInfo enum variant
let auth_info = AuthSecretKey::read_from_bytes(&account_auth_idxdb.auth_info)?;

Ok(auth_info)
let promise = idxdb_fetch_and_cache_account_auth_by_pub_key(account_id.to_string());

match JsFuture::from(promise).await {
Ok(js_value) => {
let account_auth_idxdb: AccountAuthIdxdbObject =
from_value(js_value).map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(
format!("Failed to deserialize {:?}", err),
))
})?;
let auth_info = AuthSecretKey::read_from_bytes(&account_auth_idxdb.auth_info)?;

Ok(auth_info)
},
Err(_) => Err(StoreError::AccountDataNotFound(AccountId::from_hex(account_id)?)),
}
}
}
6 changes: 3 additions & 3 deletions crates/rust-client/src/store/web_store/js/accounts.js
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ export async function getAccountHeader(

if (allMatchingRecords.length === 0) {
console.log('No records found for given ID.');
return null; // No records found
throw new Error("No records found for given ID.")
}

// Convert nonce to BigInt and sort
Expand Down Expand Up @@ -262,7 +262,7 @@ export async function getAccountAuth(

if (allMatchingRecords.length === 0) {
console.log('No records found for given account ID.');
return null; // No records found
throw new Error("No records found for given ID.")
}

// The first record is the only one due to the uniqueness constraint
Expand Down Expand Up @@ -317,7 +317,7 @@ export async function fetchAndCacheAccountAuthByPubKey(

if (allMatchingRecords.length === 0) {
console.log('No records found for given account ID.');
return null; // No records found
throw new Error("No records found for given ID.")
}

// The first record is the only one due to the uniqueness constraint
Expand Down
6 changes: 6 additions & 0 deletions crates/web-client/js/index.js
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
import wasm from "../dist/wasm.js";

const {
Account,
AccountHeader,
AccountId,
AccountStorageMode,
AdviceMap,
AuthSecretKey,
Felt,
Expand Down Expand Up @@ -33,7 +36,10 @@ const {
});

export {
Account,
AccountHeader,
AccountId,
AccountStorageMode,
AdviceMap,
AuthSecretKey,
Felt,
Expand Down
3 changes: 3 additions & 0 deletions crates/web-client/js/types/index.d.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
export {
Account,
AccountHeader,
AccountId,
AccountStorageMode,
AdviceMap,
AuthSecretKey,
Felt,
Expand Down
2 changes: 2 additions & 0 deletions crates/web-client/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"@rollup/plugin-commonjs": "^25.0.7",
"@rollup/plugin-node-resolve": "^15.2.3",
"@types/chai": "^4.3.17",
"@types/chai-as-promised": "^8.0.0",
"@types/mocha": "^10.0.7",
"@types/node": "^22.4.1",
"@wasm-tool/rollup-plugin-rust": "wasm-tool/rollup-plugin-rust",
Expand All @@ -42,6 +43,7 @@
"typescript": "^5.5.4"
},
"dependencies": {
"chai-as-promised": "^8.0.0",
"dexie": "^4.0.1",
"glob": "^11.0.0"
}
Expand Down
72 changes: 32 additions & 40 deletions crates/web-client/src/account.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,61 +2,51 @@ use miden_objects::accounts::AccountId as NativeAccountId;
use wasm_bindgen::prelude::*;

use crate::{
models::{
account_id::AccountId, accounts::SerializedAccountHeader, auth_secret_key::AuthSecretKey,
},
models::{account::Account, account_header::AccountHeader, auth_secret_key::AuthSecretKey},
WebClient,
};

#[wasm_bindgen]
impl WebClient {
pub async fn get_accounts(&mut self) -> Result<JsValue, JsValue> {
pub async fn get_accounts(&mut self) -> Result<Vec<AccountHeader>, JsValue> {
if let Some(client) = self.get_mut_inner() {
let account_tuples = client.get_account_headers().await.unwrap();
let accounts: Vec<SerializedAccountHeader> = account_tuples
.into_iter()
.map(|(account, _)| {
SerializedAccountHeader::new(
account.id().to_string(),
account.nonce().to_string(),
account.vault_root().to_string(),
account.storage_commitment().to_string(),
account.code_commitment().to_string(),
)
})
.collect();

let accounts_as_js_value =
serde_wasm_bindgen::to_value(&accounts).unwrap_or_else(|_| {
wasm_bindgen::throw_val(JsValue::from_str("Serialization error"))
});
let result = client
.get_account_headers()
.await
.map_err(|err| JsValue::from_str(&format!("Failed to get accounts: {}", err)))?;

Ok(accounts_as_js_value)
Ok(result.into_iter().map(|(header, _)| header.into()).collect())
} else {
Err(JsValue::from_str("Client not initialized"))
}
}

pub async fn get_account(&mut self, account_id: String) -> Result<JsValue, JsValue> {
pub async fn get_account(&mut self, account_id: &str) -> Result<Account, JsValue> {
if let Some(client) = self.get_mut_inner() {
let native_account_id = NativeAccountId::from_hex(&account_id).unwrap();

let result = client.get_account(native_account_id).await.unwrap();
let native_account_id = NativeAccountId::from_hex(account_id).map_err(|err| {
JsValue::from_str(&format!("Failed to parse account ID: {:?}", err))
})?;
let result = client
.get_account(native_account_id)
.await
.map_err(|err| JsValue::from_str(&format!("Failed to get account: {}", err)))?;

serde_wasm_bindgen::to_value(&result.0.id().to_string())
.map_err(|e| JsValue::from_str(&e.to_string()))
Ok(result.0.into())
} else {
Err(JsValue::from_str("Client not initialized"))
}
}

pub async fn get_account_auth(
&mut self,
account_id: &AccountId,
) -> Result<AuthSecretKey, JsValue> {
pub async fn get_account_auth(&mut self, account_id: &str) -> Result<AuthSecretKey, JsValue> {
if let Some(client) = self.get_mut_inner() {
let native_account_id: NativeAccountId = account_id.into();
let native_auth_secret_key = client.get_account_auth(native_account_id).await.unwrap();
let native_account_id = NativeAccountId::from_hex(account_id).map_err(|err| {
JsValue::from_str(&format!("Failed to parse account ID: {:?}", err))
})?;
let native_auth_secret_key =
client.get_account_auth(native_account_id).await.map_err(|err| {
JsValue::from_str(&format!("Failed to get account auth: {}", err))
})?;

Ok(native_auth_secret_key.into())
} else {
Err(JsValue::from_str("Client not initialized"))
Expand All @@ -65,16 +55,18 @@ impl WebClient {

pub async fn fetch_and_cache_account_auth_by_pub_key(
&mut self,
account_id: String,
) -> Result<JsValue, JsValue> {
account_id: &str,
) -> Result<AuthSecretKey, JsValue> {
if let Some(client) = self.get_mut_inner() {
let _ = client
let native_auth_secret_key = client
.store()
.fetch_and_cache_account_auth_by_pub_key(account_id)
.await
.unwrap();
.map_err(|err| {
JsValue::from_str(&format!("Failed to fetch and cache account auth: {}", err))
})?;

Ok(JsValue::from_str("Okay, it worked"))
Ok(native_auth_secret_key.into())
} else {
Err(JsValue::from_str("Client not initialized"))
}
Expand Down
Loading

0 comments on commit b1f5494

Please sign in to comment.