Skip to content

Commit

Permalink
web-wallet: Fix creation of a new wallet causing the sync to start fr…
Browse files Browse the repository at this point in the history
…om genesis

Resolves #3362
  • Loading branch information
ascartabelli committed Jan 17, 2025
1 parent 2765f71 commit 68d4a98
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 37 deletions.
3 changes: 3 additions & 0 deletions web-wallet/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Fixed

- Fix creation of a new wallet causing the sync to start from genesis [#3362]

## [1.2.0] - 2025-01-16

### Added
Expand Down Expand Up @@ -537,6 +539,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
[#3339]: https://github.com/dusk-network/rusk/issues/3339
[#3354]: https://github.com/dusk-network/rusk/issues/3354
[#3356]: https://github.com/dusk-network/rusk/issues/3356
[#3362]: https://github.com/dusk-network/rusk/issues/3362

<!-- VERSIONS -->

Expand Down
15 changes: 15 additions & 0 deletions web-wallet/src/routes/(welcome)/setup/create/+page.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { error } from "@sveltejs/kit";

import { networkStore } from "$lib/stores";

/** @type {import("./$types").PageLoad} */
export async function load() {
return {
currentBlockHeight: await networkStore.getCurrentBlockHeight().catch(() => {
error(
500,
"Unable to retrieve current block height: the network may be down."
);
}),
};
}
8 changes: 6 additions & 2 deletions web-wallet/src/routes/(welcome)/setup/create/+page.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
import PasswordSetup from "../PasswordSetup.svelte";
import { goto } from "$lib/navigation";
/** @type {import("./$types").PageData} */
export let data;
/** @type {boolean} */
let notice = false;
Expand Down Expand Up @@ -47,6 +50,7 @@
let enteredMnemonicPhrase = [];
const { userId } = $settingsStore;
const { currentBlockHeight } = data;
$: if (showPasswordSetup) {
password = showPasswordSetup ? password : "";
Expand Down Expand Up @@ -141,7 +145,7 @@
}}
nextButton={{
action: async () => {
await initializeWallet(mnemonicPhrase.join(" "));
await initializeWallet(mnemonicPhrase.join(" "), currentBlockHeight);
mnemonicPhrase = [];
},
disabled: false,
Expand All @@ -151,7 +155,7 @@
Network<br />
<mark>Syncing</mark>
</h2>
<NetworkSync />
<NetworkSync {currentBlockHeight} />
</WizardStep>
<WizardStep
step={5}
Expand Down
13 changes: 4 additions & 9 deletions web-wallet/src/routes/(welcome)/setup/create/NetworkSync.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -5,16 +5,12 @@
import { DOCUMENTATION_LINKS } from "$lib/constants";
import { IconHeadingCard } from "$lib/containers/Cards";
import { createNumberFormatter } from "$lib/dusk/number";
import { networkStore, settingsStore } from "$lib/stores";
import { settingsStore } from "$lib/stores";
import { mdiCubeOutline } from "@mdi/js";
$: ({ language } = $settingsStore);
/** @type {bigint} */
let currentBlock;
networkStore.getCurrentBlockHeight().then((block) => {
currentBlock = block;
});
export let currentBlockHeight;
const numberFormatter = createNumberFormatter(language);
</script>
Expand All @@ -27,9 +23,8 @@

<CopyField
name="Block Height"
displayValue={currentBlock ? numberFormatter(currentBlock) : "Loading..."}
rawValue={String(currentBlock)}
disabled={!currentBlock}
displayValue={numberFormatter(currentBlockHeight)}
rawValue={String(currentBlockHeight)}
/>

<small>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1787,7 +1787,6 @@ exports[`Create > ensures the Network Syncing step renders as expected 1`] = `
<button
aria-label="Copy Address"
class="dusk-button dusk-button--type--button dusk-button--variant--primary dusk-button--size--default dusk-icon-button copy-field__button"
disabled=""
type="button"
>
<svg
Expand Down
90 changes: 65 additions & 25 deletions web-wallet/src/routes/(welcome)/setup/create/__tests__/page.spec.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { afterAll, afterEach, describe, expect, it, vi } from "vitest";
import { cleanup, fireEvent, render } from "@testing-library/svelte";
import { tick } from "svelte";
import * as SvelteKit from "@sveltejs/kit";
import { getKey, setKey } from "lamb";
import * as bip39 from "bip39";
import { ProfileGenerator } from "$lib/vendor/w3sper.js/src/mod";
Expand All @@ -12,6 +13,7 @@ import loginInfoStorage from "$lib/services/loginInfoStorage";
import * as shuffleArray from "$lib/dusk/array";

import Create from "../+page.svelte";
import { load } from "../+page.js";

/**
* @param {HTMLElement} input
Expand Down Expand Up @@ -53,9 +55,14 @@ describe("Create", async () => {
.then(getKey("address"))
.then(String);

const blockHeightSpy = vi
.spyOn(networkStore, "getCurrentBlockHeight")
.mockResolvedValue(currentBlockHeight);
const baseProps = {
data: { currentBlockHeight },
};
const baseOptions = {
props: baseProps,
target: document.body,
};

const generateMnemonicSpy = vi
.spyOn(bip39, "generateMnemonic")
.mockReturnValue(mnemonic);
Expand All @@ -72,7 +79,7 @@ describe("Create", async () => {
afterEach(() => {
cleanup();
settingsStore.reset();
blockHeightSpy.mockClear();

generateMnemonicSpy.mockClear();
shuffleArraySpy.mockClear();
clearAndInitSpy.mockClear();
Expand All @@ -82,7 +89,6 @@ describe("Create", async () => {
});

afterAll(() => {
blockHeightSpy.mockRestore();
generateMnemonicSpy.mockRestore();
shuffleArraySpy.mockRestore();
clearAndInitSpy.mockRestore();
Expand All @@ -91,22 +97,55 @@ describe("Create", async () => {
initWalletSpy.mockRestore();
});

describe("Create page load", () => {
const blockHeightSpy = vi
.spyOn(networkStore, "getCurrentBlockHeight")
.mockResolvedValue(currentBlockHeight);

afterEach(() => {
blockHeightSpy.mockClear();
});

afterAll(() => {
blockHeightSpy.mockRestore();
});

it('should retrieve the current block height and pass it to the page as "page data"', async () => {
// @ts-ignore we don't care for load parameters here
await expect(load()).resolves.toStrictEqual({ currentBlockHeight });
});

it("should call the svelte kit error if the current block height can't be retrieved", async () => {
const svelteKitErrorSpy = vi.spyOn(SvelteKit, "error");

blockHeightSpy.mockRejectedValueOnce(new Error("some error"));

// @ts-ignore we don't care for load parameters here
await expect(load()).rejects.toThrow();

expect(svelteKitErrorSpy).toHaveBeenCalledTimes(1);
expect(svelteKitErrorSpy).toHaveBeenCalledWith(500, expect.any(String));

svelteKitErrorSpy.mockRestore();
});
});

it("should render the Existing Wallet notice step of the Create flow if there is a userId saved in localStorage", () => {
settingsStore.update(setKey("userId", userId));

const { container } = render(Create);
const { container } = render(Create, baseOptions);

expect(container.firstChild).toMatchSnapshot();
});

it("should render the Terms of Service step of the Create flow if there is no userId saved in localStorage", () => {
const { container } = render(Create);
const { container } = render(Create, baseOptions);

expect(container.firstChild).toMatchSnapshot();
});

it("should render the `Securely store your mnemonic phrase!` agreement step after the ToS", async () => {
const { container, getByRole } = render(Create);
const { container, getByRole } = render(Create, baseOptions);

const mathRandomSpy = vi.spyOn(Math, "random").mockReturnValue(42);

Expand All @@ -118,7 +157,7 @@ describe("Create", async () => {
});

it("should not allow the user proceed unless both agreement checks are selected on the `Securely store your mnemonic phrase!` step", async () => {
const { getByRole, getAllByRole } = render(Create);
const { getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand Down Expand Up @@ -149,7 +188,7 @@ describe("Create", async () => {
});

it("correctly renders the Mnemonic Preview page", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand All @@ -162,7 +201,7 @@ describe("Create", async () => {
});

it("correctly renders the Mnemonic Verification page", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand All @@ -176,7 +215,7 @@ describe("Create", async () => {
});

it("doesn't let the user proceed if they have entered mismatching Mnemonic", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand Down Expand Up @@ -204,7 +243,7 @@ describe("Create", async () => {
});

it("lets the user proceed if they have entered a matching Mnemonic", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand All @@ -228,7 +267,7 @@ describe("Create", async () => {
});

it("ensures that the Undo button on the Mnemonic Validate step works as expected", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand All @@ -254,7 +293,7 @@ describe("Create", async () => {
});

it("ensures the Password step renders as expected", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand Down Expand Up @@ -284,7 +323,7 @@ describe("Create", async () => {
});

it("ensures the Network Syncing step renders as expected", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand All @@ -303,13 +342,11 @@ describe("Create", async () => {
await fireEvent.click(getByRole("button", { name: "Next" }));
await fireEvent.click(getByRole("button", { name: "Next" }));

expect(blockHeightSpy).toHaveBeenCalledTimes(1);

expect(container.firstChild).toMatchSnapshot();
});

it("ensures the All Done step renders as expected", async () => {
const { container, getByRole, getAllByRole } = render(Create);
const { container, getByRole, getAllByRole } = render(Create, baseOptions);

await fireEvent.click(getByRole("button", { name: "Accept" }));

Expand Down Expand Up @@ -340,7 +377,7 @@ describe("Create", async () => {
});

it("should initialize the wallet without setting a password", async () => {
const { getByRole, getAllByRole } = render(Create);
const { getByRole, getAllByRole } = render(Create, baseOptions);

// ToS step
await fireEvent.click(getByRole("button", { name: "Accept" }));
Expand Down Expand Up @@ -375,14 +412,14 @@ describe("Create", async () => {

expect(settingsResetSpy).toHaveBeenCalledTimes(1);
expect(initWalletSpy).toHaveBeenCalledTimes(1);
expect(initWalletSpy).toHaveBeenCalledWith(mnemonic);
expect(initWalletSpy).toHaveBeenCalledWith(mnemonic, currentBlockHeight);

await vi.waitUntil(() => clearAndInitSpy.mock.calls.length === 1);

expect(clearAndInitSpy).toHaveBeenCalledTimes(1);
expect(clearAndInitSpy).toHaveBeenCalledWith(
expect.any(ProfileGenerator),
undefined
currentBlockHeight
);

// All Done step
Expand All @@ -395,7 +432,10 @@ describe("Create", async () => {
});

it("should initialize the wallet encrypted mnemonic saved in localStorage", async () => {
const { getByPlaceholderText, getByRole, getAllByRole } = render(Create);
const { getByPlaceholderText, getByRole, getAllByRole } = render(
Create,
baseOptions
);

// ToS step
await fireEvent.click(getByRole("button", { name: "Accept" }));
Expand Down Expand Up @@ -436,14 +476,14 @@ describe("Create", async () => {

expect(settingsResetSpy).toHaveBeenCalledTimes(1);
expect(initWalletSpy).toHaveBeenCalledTimes(1);
expect(initWalletSpy).toHaveBeenCalledWith(mnemonic);
expect(initWalletSpy).toHaveBeenCalledWith(mnemonic, currentBlockHeight);

await vi.waitUntil(() => clearAndInitSpy.mock.calls.length === 1);

expect(clearAndInitSpy).toHaveBeenCalledTimes(1);
expect(clearAndInitSpy).toHaveBeenCalledWith(
expect.any(ProfileGenerator),
undefined
currentBlockHeight
);

// All Done step
Expand Down

0 comments on commit 68d4a98

Please sign in to comment.