Namadillo Version: {version}
diff --git a/apps/namadillo/src/App/WorkerTest.tsx b/apps/namadillo/src/App/WorkerTest.tsx
index 7a26ea3a00..a6ac29d6dd 100644
--- a/apps/namadillo/src/App/WorkerTest.tsx
+++ b/apps/namadillo/src/App/WorkerTest.tsx
@@ -54,6 +54,7 @@ export function WorkerTest(): JSX.Element {
type: "sync",
payload: {
vks: [{ key: vk, birthday: 0 }],
+ chainId: chain!.id,
},
});
diff --git a/apps/namadillo/src/App/routes.ts b/apps/namadillo/src/App/routes.ts
index cf4519a6a8..611fb251c6 100644
--- a/apps/namadillo/src/App/routes.ts
+++ b/apps/namadillo/src/App/routes.ts
@@ -33,6 +33,7 @@ export const routes = {
settings: "/settings",
settingsAdvanced: "/settings/advanced",
settingsSignArbitrary: "/settings/sign-arbitrary",
+ settingsMASP: "/settings/masp",
settingsFeatures: "/settings/features",
// Other
diff --git a/apps/namadillo/src/atoms/balance/atoms.ts b/apps/namadillo/src/atoms/balance/atoms.ts
index a07c06d11e..f4f387591f 100644
--- a/apps/namadillo/src/atoms/balance/atoms.ts
+++ b/apps/namadillo/src/atoms/balance/atoms.ts
@@ -110,6 +110,7 @@ export const shieldedSyncAtom = atomWithQuery
(
const namTokenAddressQuery = get(nativeTokenAddressAtom);
const rpcUrl = get(rpcUrlAtom);
const maspIndexerUrl = get(maspIndexerUrlAtom);
+ const parametersQuery = get(chainParametersAtom);
return {
queryKey: [
@@ -122,7 +123,8 @@ export const shieldedSyncAtom = atomWithQuery(
...queryDependentFn(async () => {
const viewingKeys = viewingKeysQuery.data;
const namTokenAddress = namTokenAddressQuery.data;
- if (!namTokenAddress || !viewingKeys) {
+ const parameters = parametersQuery.data;
+ if (!namTokenAddress || !viewingKeys || !parameters) {
return null;
}
const [_, allViewingKeys] = viewingKeys;
@@ -130,9 +132,10 @@ export const shieldedSyncAtom = atomWithQuery(
rpcUrl,
maspIndexerUrl,
namTokenAddress,
- allViewingKeys
+ allViewingKeys,
+ parameters.chainId
);
- }, [viewingKeysQuery, namTokenAddressQuery]),
+ }, [viewingKeysQuery, namTokenAddressQuery, parametersQuery]),
};
}
);
@@ -147,6 +150,7 @@ export const shieldedBalanceAtom = atomWithQuery<
const rpcUrl = get(rpcUrlAtom);
const maspIndexerUrl = get(maspIndexerUrlAtom);
const shieldedSync = get(shieldedSyncAtom);
+ const chainParametersQuery = get(chainParametersAtom);
return {
refetchInterval: enablePolling ? 1000 : false,
@@ -163,7 +167,8 @@ export const shieldedBalanceAtom = atomWithQuery<
const viewingKeys = viewingKeysQuery.data;
const chainTokens = chainTokensQuery.data;
const syncEmitter = shieldedSync.data;
- if (!viewingKeys || !chainTokens || !syncEmitter) {
+ const chain = chainParametersQuery.data;
+ if (!viewingKeys || !chainTokens || !syncEmitter || !chain) {
return [];
}
const [viewingKey] = viewingKeys;
@@ -174,14 +179,20 @@ export const shieldedBalanceAtom = atomWithQuery<
const response = await fetchShieldedBalance(
viewingKey,
- chainTokens.map((t) => t.address)
+ chainTokens.map((t) => t.address),
+ chain.chainId
);
const shieldedBalance = response.map(([address, amount]) => ({
address,
minDenomAmount: BigNumber(amount),
}));
return shieldedBalance;
- }, [viewingKeysQuery, chainTokensQuery, namTokenAddressQuery]),
+ }, [
+ viewingKeysQuery,
+ chainTokensQuery,
+ namTokenAddressQuery,
+ chainParametersQuery,
+ ]),
};
});
diff --git a/apps/namadillo/src/atoms/balance/services.ts b/apps/namadillo/src/atoms/balance/services.ts
index 0dd37c1a21..2e33c6e109 100644
--- a/apps/namadillo/src/atoms/balance/services.ts
+++ b/apps/namadillo/src/atoms/balance/services.ts
@@ -29,7 +29,8 @@ export function shieldedSync(
rpcUrl: string,
maspIndexerUrl: string,
token: string,
- viewingKeys: DatedViewingKey[]
+ viewingKeys: DatedViewingKey[],
+ chainId: string
): EventEmitter {
// Only one sync process at a time
if (shieldedSyncEmitter) {
@@ -63,7 +64,7 @@ export function shieldedSync(
});
await shieldedSyncWorker.sync({
type: "sync",
- payload: { vks: viewingKeys },
+ payload: { vks: viewingKeys, chainId },
});
} finally {
worker.terminate();
@@ -76,13 +77,14 @@ export function shieldedSync(
export const fetchShieldedBalance = async (
viewingKey: DatedViewingKey,
- addresses: string[]
+ addresses: string[],
+ chainId: string
): Promise => {
// TODO mock shielded balance
// return await mockShieldedBalance(viewingKey);
const sdk = await getSdkInstance();
- return await sdk.rpc.queryBalance(viewingKey.key, addresses);
+ return await sdk.rpc.queryBalance(viewingKey.key, addresses, chainId);
};
export const fetchBlockHeightByTimestamp = async (
@@ -93,16 +95,3 @@ export const fetchBlockHeightByTimestamp = async (
return Number(response.data.height);
};
-
-// eslint-disable-next-line @typescript-eslint/no-unused-vars
-const mockShieldedBalance = async (
- viewingKey: DatedViewingKey
-): Promise => {
- await new Promise((r) => setTimeout(() => r(0), 500));
- getSdkInstance().then((sdk) => sdk.rpc.shieldedSync([viewingKey]));
- return [
- ["tnam1qy440ynh9fwrx8aewjvvmu38zxqgukgc259fzp6h", "37"], // nam
- ["tnam1p5nnjnasjtfwen2kzg78fumwfs0eycqpecuc2jwz", "1"], // uatom
- ["tnam1p4rm6gy30xzeehj29qr8v0t33xmwdlsn5ye0ezf0", "2"], // uosmo
- ];
-};
diff --git a/apps/namadillo/src/atoms/chain/services.ts b/apps/namadillo/src/atoms/chain/services.ts
index 34d1e406a9..c49a15115e 100644
--- a/apps/namadillo/src/atoms/chain/services.ts
+++ b/apps/namadillo/src/atoms/chain/services.ts
@@ -4,6 +4,7 @@ import {
NativeToken,
Parameters,
} from "@namada/indexer-client";
+import { getSdkInstance } from "utils/sdk";
export const fetchRpcUrlFromIndexer = async (
api: DefaultApi
@@ -24,3 +25,8 @@ export const fetchChainTokens = async (
): Promise<(NativeToken | IbcToken)[]> => {
return (await api.apiV1ChainTokenGet()).data;
};
+
+export const clearShieldedContext = async (chainId: string): Promise => {
+ const sdk = await getSdkInstance();
+ await sdk.getMasp().clearShieldedContext(chainId);
+};
diff --git a/apps/namadillo/src/atoms/settings/atoms.ts b/apps/namadillo/src/atoms/settings/atoms.ts
index a93d165a85..41ed8294f8 100644
--- a/apps/namadillo/src/atoms/settings/atoms.ts
+++ b/apps/namadillo/src/atoms/settings/atoms.ts
@@ -1,10 +1,11 @@
import { isUrlValid, sanitizeUrl } from "@namada/utils";
-import { indexerRpcUrlAtom } from "atoms/chain";
+import { chainParametersAtom, indexerRpcUrlAtom } from "atoms/chain";
import { Getter, Setter, atom, getDefaultStore } from "jotai";
import { atomWithMutation, atomWithQuery } from "jotai-tanstack-query";
import { atomWithStorage } from "jotai/utils";
import { SettingsStorage } from "types";
import {
+ clearShieldedContext,
fetchDefaultTomlConfig,
isIndexerAlive,
isMaspIndexerAlive,
@@ -206,3 +207,15 @@ export const indexerHeartbeatAtom = atomWithQuery((get) => {
},
};
});
+
+export const clearShieldedContextAtom = atomWithMutation((get) => {
+ const parameters = get(chainParametersAtom);
+ if (!parameters.data) {
+ throw new Error("Chain parameters not loaded");
+ }
+
+ return {
+ mutationKey: ["clear-shielded-context"],
+ mutationFn: () => clearShieldedContext(parameters.data.chainId),
+ };
+});
diff --git a/apps/namadillo/src/atoms/settings/services.ts b/apps/namadillo/src/atoms/settings/services.ts
index 5230ba0922..094a19b232 100644
--- a/apps/namadillo/src/atoms/settings/services.ts
+++ b/apps/namadillo/src/atoms/settings/services.ts
@@ -2,6 +2,7 @@ import { Configuration, DefaultApi } from "@namada/indexer-client";
import { isUrlValid } from "@namada/utils";
import toml from "toml";
import { SettingsTomlOptions } from "types";
+import { getSdkInstance } from "utils/sdk";
export const isIndexerAlive = async (url: string): Promise => {
if (!isUrlValid(url)) {
@@ -46,3 +47,8 @@ export const fetchDefaultTomlConfig =
const response = await fetch("/config.toml");
return toml.parse(await response.text()) as SettingsTomlOptions;
};
+
+export const clearShieldedContext = async (chainId: string): Promise => {
+ const sdk = await getSdkInstance();
+ await sdk.getMasp().clearShieldedContext(chainId);
+};
diff --git a/apps/namadillo/src/hooks/useSdk.tsx b/apps/namadillo/src/hooks/useSdk.tsx
index 0beeabc0e8..ffaba51f5e 100644
--- a/apps/namadillo/src/hooks/useSdk.tsx
+++ b/apps/namadillo/src/hooks/useSdk.tsx
@@ -1,6 +1,6 @@
import { Sdk } from "@namada/sdk/web";
import { QueryStatus, useQuery } from "@tanstack/react-query";
-import { nativeTokenAddressAtom } from "atoms/chain";
+import { chainParametersAtom, nativeTokenAddressAtom } from "atoms/chain";
import { useAtomValue } from "jotai";
import {
createContext,
@@ -29,20 +29,21 @@ export const SdkProvider: FunctionComponent = ({
}) => {
const [sdk, setSdk] = useState();
const nativeToken = useAtomValue(nativeTokenAddressAtom);
+ const parameters = useAtomValue(chainParametersAtom);
// fetchAndStoreMaspParams() returns nothing,
// so we return boolean on success for the query to succeed:
- const fetchMaspParams = async (): Promise => {
+ const fetchMaspParams = async (chainId: string): Promise => {
const { masp } = sdk!;
return masp.hasMaspParams().then(async (hasMaspParams) => {
if (hasMaspParams) {
- await masp.loadMaspParams("").catch((e) => Promise.reject(e));
+ await masp.loadMaspParams("", chainId).catch((e) => Promise.reject(e));
return true;
}
return masp
.fetchAndStoreMaspParams(paramsUrl)
- .then(() => masp.loadMaspParams("").then(() => true))
+ .then(() => masp.loadMaspParams("", chainId).then(() => true))
.catch((e) => {
throw new Error(e);
});
@@ -51,7 +52,8 @@ export const SdkProvider: FunctionComponent = ({
const { status: maspParamsStatus } = useQuery({
queryKey: ["sdk"],
- queryFn: fetchMaspParams,
+ enabled: Boolean(parameters.data),
+ queryFn: async () => await fetchMaspParams(parameters.data!.chainId),
retry: 3,
retryDelay: 3000,
});
diff --git a/apps/namadillo/src/workers/MaspTxWorker.ts b/apps/namadillo/src/workers/MaspTxWorker.ts
index e2e280d369..ac2423a87b 100644
--- a/apps/namadillo/src/workers/MaspTxWorker.ts
+++ b/apps/namadillo/src/workers/MaspTxWorker.ts
@@ -85,7 +85,7 @@ async function shield(
await api.apiV1RevealedPublicKeyAddressGet(account.address)
).data.publicKey;
- await sdk.masp.loadMaspParams("");
+ await sdk.masp.loadMaspParams("", chain.chainId);
const encodedTxData = await buildTx(
sdk,
account,
@@ -105,8 +105,8 @@ async function unshield(
): Promise> {
const { account, gasConfig, chain, unshieldingProps, vks } = payload;
- await sdk.rpc.shieldedSync(vks);
- await sdk.masp.loadMaspParams("");
+ await sdk.rpc.shieldedSync(vks, chain.chainId);
+ await sdk.masp.loadMaspParams("", chain.chainId);
const encodedTxData = await buildTx(
sdk,
@@ -127,8 +127,8 @@ async function shieldedTransfer(
): Promise> {
const { account, gasConfig, chain, shieldingProps, vks } = payload;
- await sdk.rpc.shieldedSync(vks);
- await sdk.masp.loadMaspParams("");
+ await sdk.rpc.shieldedSync(vks, chain.chainId);
+ await sdk.masp.loadMaspParams("", chain.chainId);
const encodedTxData = await buildTx(
sdk,
diff --git a/apps/namadillo/src/workers/ShieldedSyncMessages.ts b/apps/namadillo/src/workers/ShieldedSyncMessages.ts
index 73cdc9232f..eed30683a0 100644
--- a/apps/namadillo/src/workers/ShieldedSyncMessages.ts
+++ b/apps/namadillo/src/workers/ShieldedSyncMessages.ts
@@ -11,6 +11,7 @@ export type InitDone = WebWorkerMessage<"init-done", null>;
type ShiededSyncPayload = {
vks: DatedViewingKey[];
+ chainId: string;
};
export type Sync = WebWorkerMessage<"sync", ShiededSyncPayload>;
export type SyncDone = WebWorkerMessage<"sync-done", null>;
diff --git a/apps/namadillo/src/workers/ShieldedSyncWorker.ts b/apps/namadillo/src/workers/ShieldedSyncWorker.ts
index 476e481b80..1a367db4d2 100644
--- a/apps/namadillo/src/workers/ShieldedSyncWorker.ts
+++ b/apps/namadillo/src/workers/ShieldedSyncWorker.ts
@@ -71,7 +71,7 @@ function newSdk(
}
async function shieldedSync(sdk: Sdk, payload: Sync["payload"]): Promise {
- await sdk.rpc.shieldedSync(payload.vks);
+ await sdk.rpc.shieldedSync(payload.vks, payload.chainId);
}
Comlink.expose(new Worker());
diff --git a/packages/sdk/src/masp.ts b/packages/sdk/src/masp.ts
index 6e68b3db33..4c0685d78b 100644
--- a/packages/sdk/src/masp.ts
+++ b/packages/sdk/src/masp.ts
@@ -31,11 +31,12 @@ export class Masp {
/**
* Load stored MASP params
* @param pathOrDbName - Path to stored MASP params(nodejs) or name of the database(browser)
+ * @param chainId - Chain ID to read the MASP params for
* @async
* @returns void
*/
- async loadMaspParams(pathOrDbName: string): Promise {
- return await this.sdk.load_masp_params(pathOrDbName);
+ async loadMaspParams(pathOrDbName: string, chainId: string): Promise {
+ return await this.sdk.load_masp_params(pathOrDbName, chainId);
}
/**
@@ -79,4 +80,13 @@ export class Masp {
maspAddress(): string {
return this.sdk.masp_address();
}
+
+ /**
+ * Clear shilded context
+ * @param chainId - Chain ID to clear the shielded context for
+ * @returns void
+ */
+ clearShieldedContext(chainId: string): Promise {
+ return SdkWasm.clear_shielded_context(chainId);
+ }
}
diff --git a/packages/sdk/src/rpc/rpc.ts b/packages/sdk/src/rpc/rpc.ts
index 5134f64175..3b539b6937 100644
--- a/packages/sdk/src/rpc/rpc.ts
+++ b/packages/sdk/src/rpc/rpc.ts
@@ -45,10 +45,15 @@ export class Rpc {
* @async
* @param owner - Owner address
* @param tokens - Array of token addresses
+ * @param chainId - Chain id needed to load specific context
* @returns [[tokenAddress, amount]]
*/
- async queryBalance(owner: string, tokens: string[]): Promise {
- return await this.query.query_balance(owner, tokens);
+ async queryBalance(
+ owner: string,
+ tokens: string[],
+ chainId: string
+ ): Promise {
+ return await this.query.query_balance(owner, tokens, chainId);
}
/**
@@ -238,14 +243,14 @@ export class Rpc {
* Sync the shielded context
* @async
* @param vks - Array of dated viewing keys
+ * @param chainId - Chain ID to sync the shielded context for
* @returns
*/
- async shieldedSync(vks: DatedViewingKey[]): Promise {
+ async shieldedSync(vks: DatedViewingKey[], chainId: string): Promise {
const datedViewingKeys = vks.map(
(vk) => new DatedViewingKeyWasm(vk.key, String(vk.birthday))
);
- // TODO: shieled_sync expects an array for strings atm
- await this.query.shielded_sync(datedViewingKeys);
+ await this.query.shielded_sync(datedViewingKeys, chainId);
}
}
diff --git a/packages/shared/lib/src/query.rs b/packages/shared/lib/src/query.rs
index 8c51af77f9..dfb29637c0 100644
--- a/packages/shared/lib/src/query.rs
+++ b/packages/shared/lib/src/query.rs
@@ -324,17 +324,21 @@ impl Query {
Ok(result)
}
- pub async fn shielded_sync(&self, vks: Box<[DatedViewingKey]>) -> Result<(), JsError> {
+ pub async fn shielded_sync(
+ &self,
+ vks: Box<[DatedViewingKey]>,
+ chain_id: String,
+ ) -> Result<(), JsError> {
let dated_keypairs = vks.iter().map(|vk| vk.0).collect::>();
match &self.masp_client {
MaspClient::Indexer(client) => {
web_sys::console::info_1(&"Syncing using IndexerMaspClient".into());
- self.sync(client.clone(), dated_keypairs).await?
+ self.sync(client.clone(), dated_keypairs, chain_id).await?
}
MaspClient::Ledger(client) => {
web_sys::console::info_1(&"Syncing using LedgerMaspClient".into());
- self.sync(client.clone(), dated_keypairs).await?
+ self.sync(client.clone(), dated_keypairs, chain_id).await?
}
};
@@ -345,6 +349,7 @@ impl Query {
&self,
client: C,
dated_keypairs: Vec>,
+ chain_id: String,
) -> Result<(), JsError>
where
C: NamadaMaspClient + Send + Sync + Unpin + 'static,
@@ -374,6 +379,7 @@ impl Query {
let env = sync::TaskEnvWeb::new();
let mut shielded_context: ShieldedContext = ShieldedContext::default();
+ shielded_context.utils.chain_id = chain_id.clone();
shielded_context
.sync(env, config, None, &[], dated_keypairs.as_slice())
@@ -392,11 +398,13 @@ impl Query {
&self,
xvk: ExtendedViewingKey,
tokens: Vec,
+ chain_id: String,
) -> Result, JsError> {
let viewing_key = ExtendedFullViewingKey::from(xvk).fvk.vk;
// We are recreating shielded context to avoid multiple mutable borrows
let mut shielded: ShieldedContext = ShieldedContext::default();
+ shielded.utils.chain_id = chain_id.clone();
shielded.load().await?;
shielded
.precompute_asset_types(&self.client, tokens.iter().collect())
@@ -427,6 +435,8 @@ impl Query {
&self,
owner: String,
tokens: Box<[JsValue]>,
+ // We need to pass chain id to load correct context
+ chain_id: String,
) -> Result {
let tokens: Vec = tokens
.iter()
@@ -439,7 +449,7 @@ impl Query {
let result = match Address::from_str(&owner) {
Ok(addr) => self.query_transparent_balance(addr, tokens).await,
Err(e1) => match ExtendedViewingKey::from_str(&owner) {
- Ok(xvk) => self.query_shielded_balance(xvk, tokens).await,
+ Ok(xvk) => self.query_shielded_balance(xvk, tokens, chain_id).await,
Err(e2) => return Err(JsError::new(&format!("{} {}", e1, e2))),
},
}?;
diff --git a/packages/shared/lib/src/sdk/masp/masp_node.rs b/packages/shared/lib/src/sdk/masp/masp_node.rs
index 821f72dc62..915fa292a0 100644
--- a/packages/shared/lib/src/sdk/masp/masp_node.rs
+++ b/packages/shared/lib/src/sdk/masp/masp_node.rs
@@ -32,6 +32,7 @@ const CACHE_FILE_TMP_PREFIX: &str = "shielded_sync.cache.tmp";
pub struct NodeShieldedUtils {
#[borsh(skip)]
context_dir: PathBuf,
+ pub chain_id: String,
}
impl NodeShieldedUtils {
@@ -57,7 +58,10 @@ impl NodeShieldedUtils {
ContextSyncStatus::Confirmed
};
- let utils = Self { context_dir };
+ let utils = Self {
+ context_dir,
+ chain_id: String::from("node"),
+ };
ShieldedWallet {
utils,
@@ -66,6 +70,11 @@ impl NodeShieldedUtils {
}
}
+ //TODO: This should not be rexie:Error - it's added only to make the code compile
+ pub async fn clear(_chain_id: &str) -> Result<(), rexie::Error> {
+ todo!("Clear not implemented for NodeShieldedUtils");
+ }
+
async fn fetch_params(path: PathBuf, name: &str) {
let path = path.to_str().unwrap();
let response = reqwest::get(format!(
diff --git a/packages/shared/lib/src/sdk/masp/masp_web.rs b/packages/shared/lib/src/sdk/masp/masp_web.rs
index 1c9a060891..cc8082d7f2 100644
--- a/packages/shared/lib/src/sdk/masp/masp_web.rs
+++ b/packages/shared/lib/src/sdk/masp/masp_web.rs
@@ -9,8 +9,7 @@ use wasm_bindgen::{JsError, JsValue};
use crate::utils::to_bytes;
-const DB_PREFIX: &str = "namada_sdk::MASP";
-const SHIELDED_CONTEXT_TABLE: &str = "ShieldedContext";
+const SHIELDED_CONTEXT_PREFIX: &str = "shielded-context";
const SHIELDED_CONTEXT_KEY_CONFIRMED: &str = "shielded-context-confirmed";
const SHIELDED_CONTEXT_KEY_SPECULATIVE: &str = "shielded-context-speculative";
const SHIELDED_CONTEXT_KEY_TEMP: &str = "shielded-context-temp";
@@ -21,6 +20,7 @@ pub struct WebShieldedUtils {
spend_param_bytes: Vec,
output_param_bytes: Vec,
convert_param_bytes: Vec,
+ pub chain_id: String,
}
impl WebShieldedUtils {
@@ -28,16 +28,21 @@ impl WebShieldedUtils {
spend_param_bytes: Vec,
output_param_bytes: Vec,
convert_param_bytes: Vec,
+ chain_id: String,
) -> Result, JsError> {
let utils = Self {
spend_param_bytes,
output_param_bytes,
convert_param_bytes,
+ chain_id: chain_id.clone(),
};
- let db = Self::build_database().await?;
+ let db = Self::build_database(&chain_id).await?;
- let sync_status = if Self::get_context(&db, false, false).await.is_ok() {
+ let sync_status = if Self::get_context(&db, false, false, &chain_id)
+ .await
+ .is_ok()
+ {
ContextSyncStatus::Speculative
} else {
ContextSyncStatus::Confirmed
@@ -50,14 +55,36 @@ impl WebShieldedUtils {
})
}
+ /// Clear all shielded context data from the database.
+ pub async fn clear(chain_id: &str) -> Result<(), Error> {
+ let db = Self::build_database(&chain_id).await?;
+ let entry = format!("{}-{}", SHIELDED_CONTEXT_PREFIX, chain_id);
+
+ db.transaction(&[entry.clone()], TransactionMode::ReadWrite)?
+ .store(&entry)?
+ .delete(&JsValue::from_str(SHIELDED_CONTEXT_KEY_SPECULATIVE))
+ .await?;
+ db.transaction(&[entry.clone()], TransactionMode::ReadWrite)?
+ .store(&entry)?
+ .delete(&JsValue::from_str(SHIELDED_CONTEXT_KEY_CONFIRMED))
+ .await?;
+ db.transaction(&[entry.clone()], TransactionMode::ReadWrite)?
+ .store(&entry)?
+ .delete(&JsValue::from_str(SHIELDED_CONTEXT_KEY_TEMP))
+ .await?;
+
+ Ok(())
+ }
+
fn to_io_err(e: Error) -> std::io::Error {
std::io::Error::new(std::io::ErrorKind::Other, e.to_string())
}
- pub async fn build_database() -> Result {
- let rexie = Rexie::builder(DB_PREFIX)
+ pub async fn build_database(chain_id: &str) -> Result {
+ let entry = format!("{}-{}", SHIELDED_CONTEXT_PREFIX, chain_id);
+ let rexie = Rexie::builder(&entry)
.version(1)
- .add_object_store(ObjectStore::new(SHIELDED_CONTEXT_TABLE))
+ .add_object_store(ObjectStore::new(&entry))
.build()
.await?;
@@ -69,12 +96,13 @@ impl WebShieldedUtils {
context: JsValue,
confirmed: bool,
cache: bool,
+ chain_id: &str,
) -> Result<(), Error> {
+ let entry = format!("{}-{}", SHIELDED_CONTEXT_PREFIX, chain_id);
//TODO: add readwriteflush
- let transaction =
- rexie.transaction(&[SHIELDED_CONTEXT_TABLE], TransactionMode::ReadWrite)?;
+ let transaction = rexie.transaction(&[entry.clone()], TransactionMode::ReadWrite)?;
- let context_store = transaction.store(SHIELDED_CONTEXT_TABLE)?;
+ let context_store = transaction.store(&entry)?;
let key = Self::get_key(confirmed, cache);
@@ -85,11 +113,16 @@ impl WebShieldedUtils {
Ok(())
}
- async fn get_context(rexie: &Rexie, confirmed: bool, cache: bool) -> Result {
- let transaction =
- rexie.transaction(&[SHIELDED_CONTEXT_TABLE], TransactionMode::ReadOnly)?;
+ async fn get_context(
+ rexie: &Rexie,
+ confirmed: bool,
+ cache: bool,
+ chain_id: &str,
+ ) -> Result {
+ let entry = format!("{}-{}", SHIELDED_CONTEXT_PREFIX, chain_id);
+ let transaction = rexie.transaction(&[entry.clone()], TransactionMode::ReadOnly)?;
- let context_store = transaction.store(SHIELDED_CONTEXT_TABLE)?;
+ let context_store = transaction.store(&entry)?;
let key = Self::get_key(confirmed, cache);
@@ -98,11 +131,11 @@ impl WebShieldedUtils {
Ok(context)
}
- async fn remove_speculative_context(rexie: &Rexie) -> Result<(), Error> {
- let transaction =
- rexie.transaction(&[SHIELDED_CONTEXT_TABLE], TransactionMode::ReadWrite)?;
+ async fn remove_speculative_context(rexie: &Rexie, chain_id: &str) -> Result<(), Error> {
+ let entry = format!("{}-{}", SHIELDED_CONTEXT_PREFIX, chain_id);
+ let transaction = rexie.transaction(&[entry.clone()], TransactionMode::ReadWrite)?;
- let context_store = transaction.store(SHIELDED_CONTEXT_TABLE)?;
+ let context_store = transaction.store(&entry)?;
context_store
.delete(&JsValue::from_str(SHIELDED_CONTEXT_KEY_SPECULATIVE))
@@ -144,10 +177,12 @@ impl ShieldedUtils for WebShieldedUtils {
ctx: &mut ShieldedWallet,
force_confirmed: bool,
) -> std::io::Result<()> {
- let db = Self::build_database().await.map_err(Self::to_io_err)?;
+ let db = Self::build_database(&self.chain_id)
+ .await
+ .map_err(Self::to_io_err)?;
let confirmed = force_confirmed || get_confirmed(&ctx.sync_status);
- let stored_ctx = Self::get_context(&db, confirmed, false)
+ let stored_ctx = Self::get_context(&db, confirmed, false, &self.chain_id)
.await
.map_err(Self::to_io_err)?;
let stored_ctx_bytes = to_bytes(stored_ctx);
@@ -170,15 +205,24 @@ impl ShieldedUtils for WebShieldedUtils {
let mut bytes = Vec::new();
ctx.serialize(&mut bytes)
.expect("cannot serialize shielded context");
- let db = Self::build_database().await.map_err(Self::to_io_err)?;
- let confirmed = get_confirmed(&ctx.sync_status);
- Self::set_context(&db, JsValue::from_serde(&bytes).unwrap(), confirmed, false)
+ let db = Self::build_database(&self.chain_id)
.await
.map_err(Self::to_io_err)?;
+ let confirmed = get_confirmed(&ctx.sync_status);
+
+ Self::set_context(
+ &db,
+ JsValue::from_serde(&bytes).unwrap(),
+ confirmed,
+ false,
+ &self.chain_id,
+ )
+ .await
+ .map_err(Self::to_io_err)?;
if let ContextSyncStatus::Confirmed = ctx.sync_status {
- Self::remove_speculative_context(&db)
+ Self::remove_speculative_context(&db, &self.chain_id)
.await
.map_err(Self::to_io_err)?;
}
@@ -192,18 +236,28 @@ impl ShieldedUtils for WebShieldedUtils {
let mut bytes = Vec::new();
cache.serialize(&mut bytes).expect("cannot serialize cache");
- let db = Self::build_database().await.map_err(Self::to_io_err)?;
- Self::set_context(&db, JsValue::from_serde(&bytes).unwrap(), false, true)
+ let db = Self::build_database(&self.chain_id)
.await
- .map_err(Self::to_io_err)
+ .map_err(Self::to_io_err)?;
+ Self::set_context(
+ &db,
+ JsValue::from_serde(&bytes).unwrap(),
+ false,
+ true,
+ &self.chain_id,
+ )
+ .await
+ .map_err(Self::to_io_err)
}
/// Load a cache of data as part of shielded sync if that
/// process gets interrupted.
async fn cache_load(&self) -> std::io::Result {
- let db = Self::build_database().await.map_err(Self::to_io_err)?;
+ let db = Self::build_database(&self.chain_id)
+ .await
+ .map_err(Self::to_io_err)?;
- let stored_cache = Self::get_context(&db, false, true)
+ let stored_cache = Self::get_context(&db, false, true, &self.chain_id)
.await
.map_err(Self::to_io_err)?;
let stored_cache_bytes = to_bytes(stored_cache);
diff --git a/packages/shared/lib/src/sdk/mod.rs b/packages/shared/lib/src/sdk/mod.rs
index 69493b1ed5..81c44c54de 100644
--- a/packages/shared/lib/src/sdk/mod.rs
+++ b/packages/shared/lib/src/sdk/mod.rs
@@ -99,6 +99,12 @@ impl Sdk {
}
}
+ pub async fn clear_shielded_context(chain_id: String) -> Result<(), JsValue> {
+ masp::JSShieldedUtils::clear(&chain_id).await?;
+
+ Ok(())
+ }
+
pub async fn has_masp_params() -> Result {
let has = has_masp_params().await?;
@@ -111,7 +117,11 @@ impl Sdk {
}
#[cfg(feature = "web")]
- pub async fn load_masp_params(&self, _db_name: JsValue) -> Result<(), JsValue> {
+ pub async fn load_masp_params(
+ &self,
+ _db_name: JsValue,
+ chain_id: String,
+ ) -> Result<(), JsValue> {
// _dn_name is not used in the web version for a time being
let params = get_masp_params().await?;
let params_iter = js_sys::try_iter(¶ms)?.ok_or("Can't iterate over JsValue")?;
@@ -125,7 +135,9 @@ impl Sdk {
assert_eq!(params_bytes.next(), None);
let mut shielded = self.namada.shielded_mut().await;
- *shielded = ShieldedContext::new(masp::JSShieldedUtils::new(spend, output, convert).await?);
+ *shielded = ShieldedContext::new(
+ masp::JSShieldedUtils::new(spend, output, convert, chain_id).await?,
+ );
Ok(())
}
diff --git a/packages/shared/package.json b/packages/shared/package.json
index cf648fda01..97ae090758 100644
--- a/packages/shared/package.json
+++ b/packages/shared/package.json
@@ -22,7 +22,7 @@
"test-wasm:ci": "yarn wasm:ts:node && cd ./lib && wasm-pack test --node -- --features nodejs",
"wasm:build:node:multicore": "yarn wasm:ts:node && node ./scripts/build.js --target nodejs --release --multicore",
"wasm:build:node:dev": "yarn wasm:ts:node && node ./scripts/build.js --target nodejs",
- "wasm:build:node:dev:multicore": "yarn wasm:ts:node && node ./scripts/build.js --target node --multicore"
+ "wasm:build:node:dev:multicore": "yarn wasm:ts:node && node ./scripts/build.js --target nodejs --multicore"
},
"dependencies": {
"@dao-xyz/borsh": "^5.1.5",