Skip to content
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

Added Account Integration Tests for Web Client #532

Merged
merged 4 commits into from
Oct 1, 2024
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
6 changes: 3 additions & 3 deletions crates/rust-client/src/notes/script_roots.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@
/// This file was generated by build.rs.
/// Script root of the P2ID note script
pub const P2ID: &str = "0xc491aa07f9a0da9838de1ae841ea7dc8d45cd5641f74a89faeb2ff8fa8cf801b";
pub const P2ID: &str = "0x02b82f685d19d8c0f11c1db33f0b4ae21b2c404010c6ea5292fb6980e5147759";

/// Script root of the P2IDR note script
pub const P2IDR: &str = "0x143480f4ddf09a321c6373edd8ea4768d04ef4238aa41d221c0129f83e5c1d5a";
pub const P2IDR: &str = "0x657411c1353ca16641ae56faedd67d7c1751e0751134e38c4dcf33ab8fae8aa1";

/// Script root of the SWAP note script
pub const SWAP: &str = "0x4dd86dfc6ec16cef9d169480850d4e5e6d0de4eca662323f27be87486b2b7d21";
pub const SWAP: &str = "0x60a0ddbf22b315ad846505c496eb40f5edd1bcb32dd0827b8a062793c6fe14e3";
108 changes: 81 additions & 27 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,29 +42,48 @@ 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
let js_value = JsFuture::from(promise).await.map_err(|js_error| {
StoreError::DatabaseError(format!("Failed to fetch account headers: {:?}", js_error))
})?;

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: Vec<(AccountHeader, Option<Word>)> = account_headers_idxdb
.into_iter()
.map(parse_account_record_idxdb_object)
.collect::<Result<Vec<_>, StoreError>>()?;

account_headers
Ok(account_headers)
}

pub(crate) async fn get_account_header(
&self,
account_id: AccountId,
) -> Result<(AccountHeader, Option<Word>), StoreError> {
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)
let js_value = JsFuture::from(promise)
.await
.map_err(|_| StoreError::AccountDataNotFound(account_id))?;

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)
}

pub(crate) async fn get_account_header_by_hash(
Expand All @@ -91,7 +110,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,13 +174,26 @@ 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)?;
let js_value = JsFuture::from(promise)
.await
.map_err(|_| StoreError::AccountDataNotFound(account_id))?;

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).map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(format!(
"Failed to read auth info: {:?}",
err
)))
})?;

Ok(auth_info)
}
Expand Down Expand Up @@ -202,14 +234,36 @@ 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)?;
let promise = idxdb_fetch_and_cache_account_auth_by_pub_key(account_id.to_string());

// Separate the conversion of the account_id
let account_id = AccountId::from_hex(account_id).map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(format!(
"Failed to parse account_id from hex: {:?}",
err
)))
})?;

let js_value = JsFuture::from(promise)
.await
.map_err(|_| StoreError::AccountDataNotFound(account_id))?;

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).map_err(|err| {
StoreError::DataDeserializationError(DeserializationError::InvalidValue(format!(
"Failed to read auth info: {:?}",
err
)))
})?;

Ok(auth_info)
}
Expand Down
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
8 changes: 8 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 All @@ -22,6 +25,7 @@ const {
OutputNote,
OutputNotesArray,
Rpo256,
TestUtils,
TransactionRequest,
TransactionScriptInputPair,
TransactionScriptInputPairArray,
Expand All @@ -33,7 +37,10 @@ const {
});

export {
Account,
AccountHeader,
AccountId,
AccountStorageMode,
AdviceMap,
AuthSecretKey,
Felt,
Expand All @@ -54,6 +61,7 @@ export {
OutputNote,
OutputNotesArray,
Rpo256,
TestUtils,
TransactionRequest,
TransactionScriptInputPair,
TransactionScriptInputPairArray,
Expand Down
4 changes: 4 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 All @@ -23,6 +26,7 @@ export {
OutputNotesArray,
Rpo256,
SerializedAccountHeader,
TestUtils,
TransactionRequest,
TransactionScriptInputPair,
TransactionScriptInputPairArray,
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
63 changes: 27 additions & 36 deletions crates/web-client/src/account.rs
Original file line number Diff line number Diff line change
@@ -1,50 +1,36 @@
use miden_objects::accounts::AccountId as NativeAccountId;
use wasm_bindgen::prelude::*;

use crate::{
models::{
account_id::AccountId, accounts::SerializedAccountHeader, auth_secret_key::AuthSecretKey,
account::Account, account_header::AccountHeader, account_id::AccountId,
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: &AccountId) -> 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 result = client
.get_account(account_id.into())
.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"))
}
Expand All @@ -55,8 +41,11 @@ impl WebClient {
account_id: &AccountId,
) -> 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_auth_secret_key =
client.get_account_auth(account_id.into()).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 +54,18 @@ impl WebClient {

pub async fn fetch_and_cache_account_auth_by_pub_key(
&mut self,
account_id: String,
) -> Result<JsValue, JsValue> {
account_id: &AccountId,
) -> 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)
.fetch_and_cache_account_auth_by_pub_key(&account_id.to_string())
.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