From ba4299890ea3fa7576cfbe8deb42aebdb33b6c0d Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Fri, 13 Oct 2023 11:33:36 +0000 Subject: [PATCH 1/7] fix: account sync state for processors catching up --- yarn-project/pxe/src/synchronizer/synchronizer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index 56a42dc377f..485d4defac8 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -259,7 +259,8 @@ export class Synchronizer { if (!completeAddress) { throw new Error(`Checking if account is synched is not possible for ${account} because it is not registered.`); } - const processor = this.noteProcessors.find(x => x.publicKey.equals(completeAddress.publicKey)); + const findByPublicKey = (x: NoteProcessor) => x.publicKey.equals(completeAddress.publicKey); + const processor = this.noteProcessors.find(findByPublicKey) ?? this.noteProcessorsToCatchUp.find(findByPublicKey); if (!processor) { throw new Error( `Checking if account is synched is not possible for ${account} because it is only registered as a recipient.`, From 4d031d5d2aa42e6d1012da1537d99bc7b15a499c Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Fri, 13 Oct 2023 11:42:27 +0000 Subject: [PATCH 2/7] fix: multiple processors catching up same address --- yarn-project/pxe/src/synchronizer/synchronizer.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index 485d4defac8..bc3ad8c03d6 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -240,7 +240,8 @@ export class Synchronizer { * @returns A promise that resolves once the account is added to the Synchronizer. */ public addAccount(publicKey: PublicKey, keyStore: KeyStore, startingBlock: number) { - const processor = this.noteProcessors.find(x => x.publicKey.equals(publicKey)); + const predicate = (x: NoteProcessor) => x.publicKey.equals(publicKey); + const processor = this.noteProcessors.find(predicate) ?? this.noteProcessorsToCatchUp.find(predicate); if (processor) return; this.noteProcessorsToCatchUp.push(new NoteProcessor(publicKey, keyStore, this.db, this.node, startingBlock)); From 676c083080f53723228205f13d64993976ec7386 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Mon, 16 Oct 2023 08:41:42 +0000 Subject: [PATCH 3/7] fix: report status of note processor catching up --- .../pxe/src/synchronizer/synchronizer.test.ts | 20 ++++++++++++++++--- .../pxe/src/synchronizer/synchronizer.ts | 7 ++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index 29833507e2b..4e5505ffa78 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -1,7 +1,7 @@ import { CompleteAddress, Fr, GrumpkinScalar, HistoricBlockData } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { TestKeyStore } from '@aztec/key-store'; -import { AztecNode, INITIAL_L2_BLOCK_NUM, L2Block, MerkleTreeId } from '@aztec/types'; +import { AztecNode, L2Block, MerkleTreeId } from '@aztec/types'; import { MockProxy, mock } from 'jest-mock-extended'; import omit from 'lodash.omit'; @@ -99,7 +99,7 @@ describe('Synchronizer', () => { await synchronizer.work(); // Used in synchronizer.isAccountStateSynchronized - aztecNode.getBlockNumber.mockResolvedValueOnce(1); + aztecNode.getBlockNumber.mockResolvedValue(1); // Manually adding account to database so that we can call synchronizer.isAccountStateSynchronized const keyStore = new TestKeyStore(await Grumpkin.new()); @@ -109,11 +109,25 @@ describe('Synchronizer', () => { await database.addCompleteAddress(completeAddress); // Add the account which will add the note processor to the synchronizer - synchronizer.addAccount(completeAddress.publicKey, keyStore, INITIAL_L2_BLOCK_NUM); + synchronizer.addAccount(completeAddress.publicKey, keyStore, 1); + + expect(await synchronizer.isAccountStateSynchronized(completeAddress.address)).toBe(false); + expect(synchronizer.getSyncStatus()).toEqual({ + blocks: 1, + notes: { + [completeAddress.publicKey.toString()]: 0, + }, + }); await synchronizer.workNoteProcessorCatchUp(); expect(await synchronizer.isAccountStateSynchronized(completeAddress.address)).toBe(true); + expect(synchronizer.getSyncStatus()).toEqual({ + blocks: 1, + notes: { + [completeAddress.publicKey.toString()]: 1, + }, + }); }); }); diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index bc3ad8c03d6..e600d6628f3 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -288,7 +288,12 @@ export class Synchronizer { public getSyncStatus() { return { blocks: this.synchedToBlock, - notes: Object.fromEntries(this.noteProcessors.map(n => [n.publicKey.toString(), n.status.syncedToBlock])), + notes: Object.fromEntries( + [...this.noteProcessors, ...this.noteProcessorsToCatchUp].map(n => [ + n.publicKey.toString(), + n.status.syncedToBlock, + ]), + ), }; } } From 0026b7e8f0d741f3f22132cf33ba16cccfe6ab8d Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Mon, 6 Nov 2023 11:29:39 +0000 Subject: [PATCH 4/7] Revert "fix: report status of note processor catching up" This reverts commit 676c083080f53723228205f13d64993976ec7386. --- .../pxe/src/synchronizer/synchronizer.test.ts | 20 +++---------------- .../pxe/src/synchronizer/synchronizer.ts | 7 +------ 2 files changed, 4 insertions(+), 23 deletions(-) diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index 4e5505ffa78..29833507e2b 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -1,7 +1,7 @@ import { CompleteAddress, Fr, GrumpkinScalar, HistoricBlockData } from '@aztec/circuits.js'; import { Grumpkin } from '@aztec/circuits.js/barretenberg'; import { TestKeyStore } from '@aztec/key-store'; -import { AztecNode, L2Block, MerkleTreeId } from '@aztec/types'; +import { AztecNode, INITIAL_L2_BLOCK_NUM, L2Block, MerkleTreeId } from '@aztec/types'; import { MockProxy, mock } from 'jest-mock-extended'; import omit from 'lodash.omit'; @@ -99,7 +99,7 @@ describe('Synchronizer', () => { await synchronizer.work(); // Used in synchronizer.isAccountStateSynchronized - aztecNode.getBlockNumber.mockResolvedValue(1); + aztecNode.getBlockNumber.mockResolvedValueOnce(1); // Manually adding account to database so that we can call synchronizer.isAccountStateSynchronized const keyStore = new TestKeyStore(await Grumpkin.new()); @@ -109,25 +109,11 @@ describe('Synchronizer', () => { await database.addCompleteAddress(completeAddress); // Add the account which will add the note processor to the synchronizer - synchronizer.addAccount(completeAddress.publicKey, keyStore, 1); - - expect(await synchronizer.isAccountStateSynchronized(completeAddress.address)).toBe(false); - expect(synchronizer.getSyncStatus()).toEqual({ - blocks: 1, - notes: { - [completeAddress.publicKey.toString()]: 0, - }, - }); + synchronizer.addAccount(completeAddress.publicKey, keyStore, INITIAL_L2_BLOCK_NUM); await synchronizer.workNoteProcessorCatchUp(); expect(await synchronizer.isAccountStateSynchronized(completeAddress.address)).toBe(true); - expect(synchronizer.getSyncStatus()).toEqual({ - blocks: 1, - notes: { - [completeAddress.publicKey.toString()]: 1, - }, - }); }); }); diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index e600d6628f3..bc3ad8c03d6 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -288,12 +288,7 @@ export class Synchronizer { public getSyncStatus() { return { blocks: this.synchedToBlock, - notes: Object.fromEntries( - [...this.noteProcessors, ...this.noteProcessorsToCatchUp].map(n => [ - n.publicKey.toString(), - n.status.syncedToBlock, - ]), - ), + notes: Object.fromEntries(this.noteProcessors.map(n => [n.publicKey.toString(), n.status.syncedToBlock])), }; } } From cc38e4555a799f549e2e5d428f2e967210db064f Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Mon, 6 Nov 2023 12:47:30 +0000 Subject: [PATCH 5/7] fix: register account waits for it to be synched --- .../aztec.js/src/account/manager/index.ts | 30 ++++++++++++++++++- 1 file changed, 29 insertions(+), 1 deletion(-) diff --git a/yarn-project/aztec.js/src/account/manager/index.ts b/yarn-project/aztec.js/src/account/manager/index.ts index 69f73ebea8d..0e3a53c65c9 100644 --- a/yarn-project/aztec.js/src/account/manager/index.ts +++ b/yarn-project/aztec.js/src/account/manager/index.ts @@ -8,6 +8,7 @@ import { DeployMethod, WaitOpts, generatePublicKey, + retryUntil, } from '../../index.js'; import { AccountContract, Salt } from '../index.js'; import { AccountInterface } from '../interface.js'; @@ -88,11 +89,13 @@ export class AccountManager { * Registers this account in the PXE Service and returns the associated wallet. Registering * the account on the PXE Service is required for managing private state associated with it. * Use the returned wallet to create Contract instances to be interacted with from this account. + * @param opts - Options to wait for the account to be registered. * @returns A Wallet instance. */ - public async register(): Promise { + public async register(opts: WaitOpts = {}): Promise { const completeAddress = await this.getCompleteAddress(); await this.pxe.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); + await this.waitSynch(opts); return this.getWallet(); } @@ -142,4 +145,29 @@ export class AccountManager { await this.deploy().then(tx => tx.wait(opts)); return this.getWallet(); } + + /** + * Waits for the account to finish synchronizing with the PXE Service. + * @param opts - Options to wait for account to finish synchronizing + * @returns A wallet instance + */ + public async waitSynch({ interval, timeout }: WaitOpts): Promise { + const address = (await this.getCompleteAddress()).address; + await retryUntil( + async () => { + const status = await this.pxe.getSyncStatus(); + const accountSynchedToBlock = status.notes[address.toString()]; + if (!accountSynchedToBlock) { + return false; + } else { + return accountSynchedToBlock >= status.blocks; + } + }, + 'waitSynch', + interval, + timeout, + ); + + return this.getWallet(); + } } From d56a6a1cf2812b14a10a39be5764026a6a549282 Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Mon, 6 Nov 2023 15:54:05 +0000 Subject: [PATCH 6/7] refactor: wait for account synch in DeployAccountSentTx --- .../account/manager/deploy_account_sent_tx.ts | 30 +++++++++++++++++-- .../aztec.js/src/account/manager/index.ts | 30 +------------------ yarn-project/aztec.js/src/contract/index.ts | 2 +- yarn-project/aztec.js/src/contract/sent_tx.ts | 2 +- 4 files changed, 31 insertions(+), 33 deletions(-) diff --git a/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts b/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts index c34051e894a..b3735b848fa 100644 --- a/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts +++ b/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts @@ -1,7 +1,9 @@ import { FieldsOf } from '@aztec/circuits.js'; +import { retryUntil } from '@aztec/foundation/retry'; import { TxHash, TxReceipt } from '@aztec/types'; -import { SentTx, WaitOpts, Wallet } from '../../index.js'; +import { DefaultWaitOpts, SentTx, WaitOpts } from '../../contract/sent_tx.js'; +import { Wallet } from '../../wallet/index.js'; /** Extends a transaction receipt with a wallet instance for the newly deployed contract. */ export type DeployAccountTxReceipt = FieldsOf & { @@ -32,8 +34,32 @@ export class DeployAccountSentTx extends SentTx { * @param opts - Options for configuring the waiting for the tx to be mined. * @returns The transaction receipt with the wallet for the deployed account contract. */ - public async wait(opts?: WaitOpts): Promise { + public async wait(opts: WaitOpts = DefaultWaitOpts): Promise { const receipt = await super.wait(opts); + await this.waitForAccountSynch(opts); return { ...receipt, wallet: this.wallet }; } + + /** + * Waits for the account to finish synchronizing with the PXE Service. + * @param opts - Options to wait for account to finish synchronizing + * @returns A wallet instance + */ + private async waitForAccountSynch({ interval, timeout }: WaitOpts): Promise { + const address = this.wallet.getCompleteAddress().publicKey; + await retryUntil( + async () => { + const status = await this.pxe.getSyncStatus(); + const accountSynchedToBlock = status.notes[address.toString()]; + if (!accountSynchedToBlock) { + return false; + } else { + return accountSynchedToBlock >= status.blocks; + } + }, + 'waitForAccountSynch', + interval, + timeout, + ); + } } diff --git a/yarn-project/aztec.js/src/account/manager/index.ts b/yarn-project/aztec.js/src/account/manager/index.ts index 0e3a53c65c9..69f73ebea8d 100644 --- a/yarn-project/aztec.js/src/account/manager/index.ts +++ b/yarn-project/aztec.js/src/account/manager/index.ts @@ -8,7 +8,6 @@ import { DeployMethod, WaitOpts, generatePublicKey, - retryUntil, } from '../../index.js'; import { AccountContract, Salt } from '../index.js'; import { AccountInterface } from '../interface.js'; @@ -89,13 +88,11 @@ export class AccountManager { * Registers this account in the PXE Service and returns the associated wallet. Registering * the account on the PXE Service is required for managing private state associated with it. * Use the returned wallet to create Contract instances to be interacted with from this account. - * @param opts - Options to wait for the account to be registered. * @returns A Wallet instance. */ - public async register(opts: WaitOpts = {}): Promise { + public async register(): Promise { const completeAddress = await this.getCompleteAddress(); await this.pxe.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); - await this.waitSynch(opts); return this.getWallet(); } @@ -145,29 +142,4 @@ export class AccountManager { await this.deploy().then(tx => tx.wait(opts)); return this.getWallet(); } - - /** - * Waits for the account to finish synchronizing with the PXE Service. - * @param opts - Options to wait for account to finish synchronizing - * @returns A wallet instance - */ - public async waitSynch({ interval, timeout }: WaitOpts): Promise { - const address = (await this.getCompleteAddress()).address; - await retryUntil( - async () => { - const status = await this.pxe.getSyncStatus(); - const accountSynchedToBlock = status.notes[address.toString()]; - if (!accountSynchedToBlock) { - return false; - } else { - return accountSynchedToBlock >= status.blocks; - } - }, - 'waitSynch', - interval, - timeout, - ); - - return this.getWallet(); - } } diff --git a/yarn-project/aztec.js/src/contract/index.ts b/yarn-project/aztec.js/src/contract/index.ts index a2a3bf8db63..0a2d9ea8994 100644 --- a/yarn-project/aztec.js/src/contract/index.ts +++ b/yarn-project/aztec.js/src/contract/index.ts @@ -37,6 +37,6 @@ */ export * from './contract.js'; export * from './contract_function_interaction.js'; -export * from './sent_tx.js'; +export { SentTx, WaitOpts } from './sent_tx.js'; export * from './contract_base.js'; export * from './batch_call.js'; diff --git a/yarn-project/aztec.js/src/contract/sent_tx.ts b/yarn-project/aztec.js/src/contract/sent_tx.ts index 9c52a6418a7..92f96a96967 100644 --- a/yarn-project/aztec.js/src/contract/sent_tx.ts +++ b/yarn-project/aztec.js/src/contract/sent_tx.ts @@ -19,7 +19,7 @@ export type WaitOpts = { debug?: boolean; }; -const DefaultWaitOpts: WaitOpts = { +export const DefaultWaitOpts: WaitOpts = { timeout: 60, interval: 1, waitForNotesSync: true, From dc973e4db07e2fe14903d264ebe23c5bfac31e5b Mon Sep 17 00:00:00 2001 From: Alex Gherghisan Date: Mon, 6 Nov 2023 17:08:43 +0000 Subject: [PATCH 7/7] fix: wait for synch when registering known account --- .../account/manager/deploy_account_sent_tx.ts | 27 ++--------------- .../aztec.js/src/account/manager/index.ts | 19 ++++++++---- .../aztec.js/src/account/manager/util.ts | 29 +++++++++++++++++++ .../end-to-end/src/e2e_2_pxes.test.ts | 20 +++++++++++++ 4 files changed, 65 insertions(+), 30 deletions(-) create mode 100644 yarn-project/aztec.js/src/account/manager/util.ts diff --git a/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts b/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts index b3735b848fa..321d8632ae5 100644 --- a/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts +++ b/yarn-project/aztec.js/src/account/manager/deploy_account_sent_tx.ts @@ -1,9 +1,9 @@ import { FieldsOf } from '@aztec/circuits.js'; -import { retryUntil } from '@aztec/foundation/retry'; import { TxHash, TxReceipt } from '@aztec/types'; import { DefaultWaitOpts, SentTx, WaitOpts } from '../../contract/sent_tx.js'; import { Wallet } from '../../wallet/index.js'; +import { waitForAccountSynch } from './util.js'; /** Extends a transaction receipt with a wallet instance for the newly deployed contract. */ export type DeployAccountTxReceipt = FieldsOf & { @@ -36,30 +36,7 @@ export class DeployAccountSentTx extends SentTx { */ public async wait(opts: WaitOpts = DefaultWaitOpts): Promise { const receipt = await super.wait(opts); - await this.waitForAccountSynch(opts); + await waitForAccountSynch(this.pxe, this.wallet.getCompleteAddress(), opts); return { ...receipt, wallet: this.wallet }; } - - /** - * Waits for the account to finish synchronizing with the PXE Service. - * @param opts - Options to wait for account to finish synchronizing - * @returns A wallet instance - */ - private async waitForAccountSynch({ interval, timeout }: WaitOpts): Promise { - const address = this.wallet.getCompleteAddress().publicKey; - await retryUntil( - async () => { - const status = await this.pxe.getSyncStatus(); - const accountSynchedToBlock = status.notes[address.toString()]; - if (!accountSynchedToBlock) { - return false; - } else { - return accountSynchedToBlock >= status.blocks; - } - }, - 'waitForAccountSynch', - interval, - timeout, - ); - } } diff --git a/yarn-project/aztec.js/src/account/manager/index.ts b/yarn-project/aztec.js/src/account/manager/index.ts index 69f73ebea8d..ace65bf7999 100644 --- a/yarn-project/aztec.js/src/account/manager/index.ts +++ b/yarn-project/aztec.js/src/account/manager/index.ts @@ -2,6 +2,7 @@ import { PublicKey, getContractDeploymentInfo } from '@aztec/circuits.js'; import { Fr } from '@aztec/foundation/fields'; import { CompleteAddress, GrumpkinPrivateKey, PXE } from '@aztec/types'; +import { DefaultWaitOpts } from '../../contract/sent_tx.js'; import { AccountWalletWithPrivateKey, ContractDeployer, @@ -12,6 +13,7 @@ import { import { AccountContract, Salt } from '../index.js'; import { AccountInterface } from '../interface.js'; import { DeployAccountSentTx } from './deploy_account_sent_tx.js'; +import { waitForAccountSynch } from './util.js'; /** * Manages a user account. Provides methods for calculating the account's address, deploying the account contract, @@ -88,11 +90,12 @@ export class AccountManager { * Registers this account in the PXE Service and returns the associated wallet. Registering * the account on the PXE Service is required for managing private state associated with it. * Use the returned wallet to create Contract instances to be interacted with from this account. + * @param opts - Options to wait for the account to be synched. * @returns A Wallet instance. */ - public async register(): Promise { - const completeAddress = await this.getCompleteAddress(); - await this.pxe.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); + public async register(opts: WaitOpts = DefaultWaitOpts): Promise { + const address = await this.#register(); + await waitForAccountSynch(this.pxe, address, opts); return this.getWallet(); } @@ -105,7 +108,7 @@ export class AccountManager { public async getDeployMethod() { if (!this.deployMethod) { if (!this.salt) throw new Error(`Cannot deploy account contract without known salt.`); - await this.register(); + await this.#register(); const encryptionPublicKey = await this.getEncryptionPublicKey(); const deployer = new ContractDeployer(this.accountContract.getContractArtifact(), this.pxe, encryptionPublicKey); const args = await this.accountContract.getDeploymentArgs(); @@ -138,8 +141,14 @@ export class AccountManager { * @param opts - Options to wait for the tx to be mined. * @returns A Wallet instance. */ - public async waitDeploy(opts: WaitOpts = {}): Promise { + public async waitDeploy(opts: WaitOpts = DefaultWaitOpts): Promise { await this.deploy().then(tx => tx.wait(opts)); return this.getWallet(); } + + async #register(): Promise { + const completeAddress = await this.getCompleteAddress(); + await this.pxe.registerAccount(this.encryptionPrivateKey, completeAddress.partialAddress); + return completeAddress; + } } diff --git a/yarn-project/aztec.js/src/account/manager/util.ts b/yarn-project/aztec.js/src/account/manager/util.ts new file mode 100644 index 00000000000..2c111eca4fe --- /dev/null +++ b/yarn-project/aztec.js/src/account/manager/util.ts @@ -0,0 +1,29 @@ +import { CompleteAddress, PXE, WaitOpts, retryUntil } from '../../index.js'; + +/** + * Waits for the account to finish synchronizing with the PXE Service. + * @param pxe - PXE instance + * @param address - Address to wait for synch + * @param opts - Wait options + */ +export async function waitForAccountSynch( + pxe: PXE, + address: CompleteAddress, + { interval, timeout }: WaitOpts, +): Promise { + const publicKey = address.publicKey.toString(); + await retryUntil( + async () => { + const status = await pxe.getSyncStatus(); + const accountSynchedToBlock = status.notes[publicKey]; + if (typeof accountSynchedToBlock === 'undefined') { + return false; + } else { + return accountSynchedToBlock >= status.blocks; + } + }, + 'waitForAccountSynch', + timeout, + interval, + ); +} diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index cd3e221a237..660d89292b6 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -6,11 +6,13 @@ import { EthAddress, ExtendedNote, Fr, + GrumpkinScalar, Note, PXE, TxStatus, Wallet, computeMessageSecretHash, + getUnsafeSchnorrAccount, retryUntil, } from '@aztec/aztec.js'; import { ChildContract, TokenContract } from '@aztec/noir-contracts/types'; @@ -248,4 +250,22 @@ describe('e2e_2_pxes', () => { // Check that user B balance is 0 on server A await expectTokenBalance(walletA, completeTokenAddress.address, userB.address, 0n, checkIfSynchronized); }); + + it('permits migrating an account from one PXE to another', async () => { + const privateKey = GrumpkinScalar.random(); + const account = getUnsafeSchnorrAccount(pxeA, privateKey, Fr.random()); + const completeAddress = await account.getCompleteAddress(); + const wallet = await account.waitDeploy(); + + await expect(wallet.isAccountStateSynchronized(completeAddress.address)).resolves.toBe(true); + const accountOnB = getUnsafeSchnorrAccount(pxeB, privateKey, completeAddress); + const walletOnB = await accountOnB.getWallet(); + + // need to register first otherwise the new PXE won't know about the account + await expect(walletOnB.isAccountStateSynchronized(completeAddress.address)).rejects.toThrow(); + + await accountOnB.register(); + // registering should wait for the account to be synchronized + await expect(walletOnB.isAccountStateSynchronized(completeAddress.address)).resolves.toBe(true); + }); });