diff --git a/docs/docs-developers/docs/resources/migration_notes.md b/docs/docs-developers/docs/resources/migration_notes.md index 18312c283918..79486a4ce294 100644 --- a/docs/docs-developers/docs/resources/migration_notes.md +++ b/docs/docs-developers/docs/resources/migration_notes.md @@ -9,6 +9,37 @@ Aztec is in active development. Each version may introduce breaking changes that ## TBD +### [PXE] `simulateTx`, `executeUtility`, `profileTx`, and `proveTx` no longer accept `scopes: 'ALL_SCOPES'` + +The `AccessScopes` type (`'ALL_SCOPES' | AztecAddress[]`) has been removed. The `scopes` field in `SimulateTxOpts`, +`ExecuteUtilityOpts`, and `ProfileTxOpts` now requires an explicit `AztecAddress[]`. Callers that previously passed +`'ALL_SCOPES'` must now specify which addresses will be in scope for the call. + +**Migration:** + +```diff ++ const accounts = await pxe.getRegisteredAccounts(); ++ const scopes = accounts.map(a => a.address); + + // simulateTx +- await pxe.simulateTx(txRequest, { simulatePublic: true, scopes: 'ALL_SCOPES' }); ++ await pxe.simulateTx(txRequest, { simulatePublic: true, scopes }); + + // executeUtility +- await pxe.executeUtility(call, { scopes: 'ALL_SCOPES' }); ++ await pxe.executeUtility(call, { scopes }); + + // profileTx +- await pxe.profileTx(txRequest, { profileMode: 'full', scopes: 'ALL_SCOPES' }); ++ await pxe.profileTx(txRequest, { profileMode: 'full', scopes }); + + // proveTx +- await pxe.proveTx(txRequest, 'ALL_SCOPES'); ++ await pxe.proveTx(txRequest, scopes); +``` + +**Impact**: Any code passing `'ALL_SCOPES'` to `simulateTx`, `executeUtility`, `profileTx`, or `proveTx` will fail to compile. Replace with an explicit array of account addresses. + ### [PXE] Capsule operations are now scope-enforced at the PXE level The PXE now enforces that capsule operations can only access scopes that were authorized for the current execution. If a contract attempts to access a capsule scope that is not in its allowed scopes list, the PXE will throw an error: diff --git a/yarn-project/cli-wallet/src/cmds/check_tx.ts b/yarn-project/cli-wallet/src/cmds/check_tx.ts index 1ff5ef54dbfe..749633c9422b 100644 --- a/yarn-project/cli-wallet/src/cmds/check_tx.ts +++ b/yarn-project/cli-wallet/src/cmds/check_tx.ts @@ -1,5 +1,5 @@ import type { ContractArtifact } from '@aztec/aztec.js/abi'; -import type { AztecAddress } from '@aztec/aztec.js/addresses'; +import { AztecAddress } from '@aztec/aztec.js/addresses'; import { Fr } from '@aztec/aztec.js/fields'; import type { AztecNode } from '@aztec/aztec.js/node'; import { ProtocolContractAddress } from '@aztec/aztec.js/protocol'; @@ -87,12 +87,13 @@ async function inspectTx(wallet: CLIWallet, aztecNode: AztecNode, txHash: TxHash // Nullifiers const nullifierCount = effects.nullifiers.length; const { deployNullifiers, initNullifiers, classNullifiers } = await getKnownNullifiers(wallet, artifactMap); + const accounts = (await wallet.getAccounts()).map(a => a.item); if (nullifierCount > 0) { log(' Nullifiers:'); for (const nullifier of effects.nullifiers) { const deployed = deployNullifiers[nullifier.toString()]; const note = deployed - ? (await wallet.getNotes({ siloedNullifier: nullifier, contractAddress: deployed, scopes: 'ALL_SCOPES' }))[0] + ? (await wallet.getNotes({ siloedNullifier: nullifier, contractAddress: deployed, scopes: accounts }))[0] : undefined; const initialized = initNullifiers[nullifier.toString()]; const registered = classNullifiers[nullifier.toString()]; diff --git a/yarn-project/cli-wallet/src/utils/wallet.ts b/yarn-project/cli-wallet/src/utils/wallet.ts index 3768dc272267..d339a4d82026 100644 --- a/yarn-project/cli-wallet/src/utils/wallet.ts +++ b/yarn-project/cli-wallet/src/utils/wallet.ts @@ -56,7 +56,12 @@ export class CLIWallet extends BaseWallet { override async getAccounts(): Promise[]> { const accounts = (await this.db?.listAliases('accounts')) ?? []; - return Promise.resolve(accounts.map(({ key, value }) => ({ alias: value, item: AztecAddress.fromString(key) }))); + return Promise.resolve( + accounts.map(({ key, value }) => { + const alias = key.includes(':') ? key.slice(key.indexOf(':') + 1) : key; + return { alias, item: AztecAddress.fromString(value) }; + }), + ); } private async createCancellationTxExecutionRequest( diff --git a/yarn-project/pxe/src/access_scopes.ts b/yarn-project/pxe/src/access_scopes.ts deleted file mode 100644 index 9ea570de8e13..000000000000 --- a/yarn-project/pxe/src/access_scopes.ts +++ /dev/null @@ -1,9 +0,0 @@ -import type { AztecAddress } from '@aztec/stdlib/aztec-address'; - -/** - * Controls which accounts' private state and keys are accessible during execution. - * - `'ALL_SCOPES'`: All registered accounts' private state and keys are accessible. - * - `AztecAddress[]` with entries: Only the specified accounts' private state and keys are accessible. - * - `[]` (empty array): Deny-all. No private state is visible and no keys are accessible. - */ -export type AccessScopes = 'ALL_SCOPES' | AztecAddress[]; diff --git a/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts b/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts index 9dfa5b3c58a1..aab99e813410 100644 --- a/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts +++ b/yarn-project/pxe/src/contract_function_simulator/contract_function_simulator.ts @@ -89,7 +89,6 @@ import { getFinalMinRevertibleSideEffectCounter, } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../access_scopes.js'; import type { ContractSyncService } from '../contract_sync/contract_sync_service.js'; import type { MessageContextService } from '../messages/message_context_service.js'; import type { AddressStore } from '../storage/address_store/address_store.js'; @@ -123,7 +122,7 @@ export type ContractSimulatorRunOpts = { /** The address used as a tagging sender when emitting private logs. */ senderForTags?: AztecAddress; /** The accounts whose notes we can access in this call. */ - scopes: AccessScopes; + scopes: AztecAddress[]; /** The job ID for staged writes. */ jobId: string; }; @@ -320,7 +319,7 @@ export class ContractFunctionSimulator { call: FunctionCall, authwits: AuthWitness[], anchorBlockHeader: BlockHeader, - scopes: AccessScopes, + scopes: AztecAddress[], jobId: string, ): Promise<{ result: Fr[]; offchainEffects: OffchainEffect[] }> { const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector); diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/oracle_version_is_checked.test.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/oracle_version_is_checked.test.ts index 7815f5ae9663..983ad39a26cf 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/oracle_version_is_checked.test.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/oracle_version_is_checked.test.ts @@ -149,7 +149,7 @@ describe('Oracle Version Check test suite', () => { anchorBlockHeader, senderForTags, jobId: 'test', - scopes: 'ALL_SCOPES', + scopes: [], }); expect(assertCompatibleOracleVersionSpy).toHaveBeenCalledTimes(1); @@ -206,7 +206,7 @@ describe('Oracle Version Check test suite', () => { messageContextService, contractSyncService, jobId: 'test', - scopes: 'ALL_SCOPES', + scopes: [], }); }); diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution.test.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution.test.ts index 7589d26233ca..e8a41155c9cb 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution.test.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution.test.ts @@ -206,7 +206,7 @@ describe('Private Execution test suite', () => { anchorBlockHeader, senderForTags, jobId: TEST_JOB_ID, - scopes: 'ALL_SCOPES', + scopes: [owner], }); }; @@ -290,8 +290,7 @@ describe('Private Execution test suite', () => { // Configure mock to actually perform sync_state calls (needed for nested call tests) contractSyncService.ensureContractSynced.mockImplementation( async (contractAddress, functionToInvokeAfterSync, utilityExecutor, anchorBlockHeader, jobId, scopes) => { - const scopeAddresses = scopes === 'ALL_SCOPES' ? [owner] : scopes; - for (const scope of scopeAddresses) { + for (const scope of scopes) { await syncState( contractAddress, contractStore, @@ -350,6 +349,19 @@ describe('Private Execution test suite', () => { keyStore.getAccounts.mockResolvedValue([owner, recipient, senderForTags]); + keyStore.accountHasKey.mockImplementation(async (account: AztecAddress, pkMHash: Fr) => { + if (account.equals(owner)) { + return pkMHash.equals(await ownerCompleteAddress.publicKeys.masterNullifierPublicKey.hash()); + } + if (account.equals(recipient)) { + return pkMHash.equals(await recipientCompleteAddress.publicKeys.masterNullifierPublicKey.hash()); + } + if (account.equals(senderForTags)) { + return pkMHash.equals(await senderForTagsCompleteAddress.publicKeys.masterNullifierPublicKey.hash()); + } + return false; + }); + keyStore.getKeyValidationRequest.mockImplementation(async (pkMHash: Fr, contractAddress: AztecAddress) => { if (pkMHash.equals(await ownerCompleteAddress.publicKeys.masterNullifierPublicKey.hash())) { return Promise.resolve( diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution_oracle.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution_oracle.ts index 0d7c309d9fae..beb60ab64971 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution_oracle.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/private_execution_oracle.ts @@ -25,7 +25,6 @@ import { type TxContext, } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../../access_scopes.js'; import { NoteService } from '../../notes/note_service.js'; import type { SenderTaggingStore } from '../../storage/tagging_store/sender_tagging_store.js'; import { syncSenderTaggingIndexes } from '../../tagging/index.js'; @@ -43,7 +42,7 @@ export type PrivateExecutionOracleArgs = Omit Promise; + utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise; executionCache: HashedValuesCache; noteCache: ExecutionNoteCache; taggingIndexCache: ExecutionTaggingIndexCache; @@ -76,7 +75,7 @@ export class PrivateExecutionOracle extends UtilityExecutionOracle implements IP private readonly argsHash: Fr; private readonly txContext: TxContext; private readonly callContext: CallContext; - private readonly utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise; + private readonly utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise; private readonly executionCache: HashedValuesCache; private readonly noteCache: ExecutionNoteCache; private readonly taggingIndexCache: ExecutionTaggingIndexCache; diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution.test.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution.test.ts index 4ebf9ccb3ce2..24d1f3418097 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution.test.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution.test.ts @@ -232,12 +232,16 @@ describe('Utility Execution test suite', () => { let utilityExecutionOracle: UtilityExecutionOracle; const syncedBlockNumber = 100; + let scope: AztecAddress; + beforeEach(async () => { contractAddress = await AztecAddress.random(); anchorBlockHeader = BlockHeader.empty({ globalVariables: GlobalVariables.empty({ blockNumber: BlockNumber(syncedBlockNumber) }), }); + scope = await AztecAddress.random(); + utilityExecutionOracle = new UtilityExecutionOracle({ contractAddress, authWitnesses: [], @@ -250,12 +254,12 @@ describe('Utility Execution test suite', () => { aztecNode, recipientTaggingStore, senderAddressBookStore, - capsuleService: new CapsuleService(capsuleStore, 'ALL_SCOPES'), + capsuleService: new CapsuleService(capsuleStore, [scope]), privateEventStore, messageContextService, contractSyncService, jobId: 'test-job-id', - scopes: 'ALL_SCOPES', + scopes: [scope], }); }); @@ -268,8 +272,7 @@ describe('Utility Execution test suite', () => { }); describe('capsules', () => { - it('forwards scope to the capsule store', async () => { - const scope = await AztecAddress.random(); + it('forwards scope to the capsule service', async () => { const slot = Fr.random(); const srcSlot = Fr.random(); const dstSlot = Fr.random(); @@ -317,12 +320,12 @@ describe('Utility Execution test suite', () => { aztecNode, recipientTaggingStore, senderAddressBookStore, - capsuleService: new CapsuleService(capsuleStore, 'ALL_SCOPES'), + capsuleService: new CapsuleService(capsuleStore, [scope]), privateEventStore, messageContextService, contractSyncService, jobId: 'test-job-id', - scopes: 'ALL_SCOPES', + scopes: [scope], }); capsuleStore.getCapsule.mockResolvedValueOnce(persisted); @@ -358,7 +361,6 @@ describe('Utility Execution test suite', () => { describe('utilityResolveMessageContexts', () => { const requestSlot = Fr.random(); const responseSlot = Fr.random(); - const scope = AztecAddress.fromBigInt(42n); it('throws when contractAddress does not match', async () => { const wrongAddress = await AztecAddress.random(); @@ -498,12 +500,12 @@ describe('Utility Execution test suite', () => { aztecNode, recipientTaggingStore, senderAddressBookStore, - capsuleService: new CapsuleService(capsuleStore, 'ALL_SCOPES'), + capsuleService: new CapsuleService(capsuleStore, []), privateEventStore, messageContextService, contractSyncService, jobId: 'test-job-id', - scopes: 'ALL_SCOPES', + scopes: [], }); const oracleA = makeOracle(contractAddressA); diff --git a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts index 6b7370186f54..512ca45ab9ec 100644 --- a/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts +++ b/yarn-project/pxe/src/contract_function_simulator/oracle/utility_execution_oracle.ts @@ -21,7 +21,6 @@ import type { NoteStatus } from '@aztec/stdlib/note'; import { MerkleTreeId, type NullifierMembershipWitness, PublicDataWitness } from '@aztec/stdlib/trees'; import type { BlockHeader, Capsule, OffchainEffect } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../../access_scopes.js'; import { createContractLogger, logContractMessage, stripAztecnrLogPrefix } from '../../contract_logging.js'; import type { ContractSyncService } from '../../contract_sync/contract_sync_service.js'; import { EventService } from '../../events/event_service.js'; @@ -65,7 +64,7 @@ export type UtilityExecutionOracleArgs = { contractSyncService: ContractSyncService; jobId: string; log?: ReturnType; - scopes: AccessScopes; + scopes: AztecAddress[]; }; /** @@ -96,7 +95,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra protected readonly contractSyncService: ContractSyncService; protected readonly jobId: string; protected logger: ReturnType; - protected readonly scopes: AccessScopes; + protected readonly scopes: AztecAddress[]; constructor(args: UtilityExecutionOracleArgs) { this.contractAddress = args.contractAddress; @@ -166,18 +165,15 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra * @throws If scopes are defined and the account is not in the scopes. */ public async getKeyValidationRequest(pkMHash: Fr): Promise { - // If scopes are defined, check that the key belongs to an account in the scopes. - if (this.scopes !== 'ALL_SCOPES' && this.scopes.length > 0) { - let hasAccess = false; - for (let i = 0; i < this.scopes.length && !hasAccess; i++) { - if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) { - hasAccess = true; - } - } - if (!hasAccess) { - throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`); + let hasAccess = false; + for (let i = 0; i < this.scopes.length && !hasAccess; i++) { + if (await this.keyStore.accountHasKey(this.scopes[i], pkMHash)) { + hasAccess = true; } } + if (!hasAccess) { + throw new Error(`Key validation request denied: no scoped account has a key with hash ${pkMHash.toString()}.`); + } return this.keyStore.getKeyValidationRequest(pkMHash, this.contractAddress); } diff --git a/yarn-project/pxe/src/contract_sync/contract_sync_service.test.ts b/yarn-project/pxe/src/contract_sync/contract_sync_service.test.ts index 0ed395978b75..6e70a2b12896 100644 --- a/yarn-project/pxe/src/contract_sync/contract_sync_service.test.ts +++ b/yarn-project/pxe/src/contract_sync/contract_sync_service.test.ts @@ -9,7 +9,6 @@ import { makeBlockHeader } from '@aztec/stdlib/testing'; import { jest } from '@jest/globals'; import { mock } from 'jest-mock-extended'; -import type { AccessScopes } from '../access_scopes.js'; import type { ContractStore } from '../storage/contract_store/contract_store.js'; import type { NoteStore } from '../storage/note_store/note_store.js'; import { ContractSyncService } from './contract_sync_service.js'; @@ -19,7 +18,7 @@ describe('ContractSyncService', () => { let contractStore: ReturnType>; let noteStore: ReturnType>; let service: ContractSyncService; - let utilityExecutor: jest.Mock<(call: FunctionCall, scopes: AccessScopes) => Promise>; + let utilityExecutor: jest.Mock<(call: FunctionCall, scopes: AztecAddress[]) => Promise>; const contractAddress = AztecAddress.fromBigInt(100n); const scopeA = AztecAddress.fromBigInt(200n); @@ -30,7 +29,7 @@ describe('ContractSyncService', () => { beforeEach(() => { utilityExecutor = jest - .fn<(call: FunctionCall, scopes: AccessScopes) => Promise>() + .fn<(call: FunctionCall, scopes: AztecAddress[]) => Promise>() .mockResolvedValue(undefined); contractStore = mock(); @@ -62,13 +61,7 @@ describe('ContractSyncService', () => { // syncNoteNullifiers returns early when no notes noteStore.getNotes.mockResolvedValue([]); - service = new ContractSyncService( - aztecNode, - contractStore, - noteStore, - () => Promise.resolve([scopeA, scopeB]), - createLogger('test:contract-sync'), - ); + service = new ContractSyncService(aztecNode, contractStore, noteStore, createLogger('test:contract-sync')); }); describe('ensureContractSynced', () => { @@ -85,15 +78,11 @@ describe('ContractSyncService', () => { }); it('skips scope-specific syncs after syncing with all scopes', async () => { - await service.ensureContractSynced( - contractAddress, - null, - utilityExecutor, - anchorBlockHeader, - jobId, - 'ALL_SCOPES', - ); - // ALL_SCOPES resolves to [scopeA, scopeB] via getRegisteredAccounts, so syncState is called once per account + await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [ + scopeA, + scopeB, + ]); + // [scopeA, scopeB] syncs each scope individually expectSyncedScopes([scopeA], [scopeB]); // After syncing all scopes, scope-specific calls should be skipped @@ -102,18 +91,14 @@ describe('ContractSyncService', () => { expectSyncedScopes([scopeA], [scopeB]); }); - it('still syncs all scopes even after scope-specific sync', async () => { + it('only syncs unsynced scopes when requesting multiple', async () => { await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [scopeA]); - await service.ensureContractSynced( - contractAddress, - null, - utilityExecutor, - anchorBlockHeader, - jobId, - 'ALL_SCOPES', - ); - // ALL_SCOPES resolves to [scopeA, scopeB]; both are re-synced since ALL_SCOPES bypasses per-scope cache - expectSyncedScopes([scopeA], [scopeA], [scopeB]); + await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [ + scopeA, + scopeB, + ]); + // scopeA is already cached, so only scopeB is synced + expectSyncedScopes([scopeA], [scopeB]); }); it('empty scopes array skips sync entirely', async () => { @@ -277,63 +262,46 @@ describe('ContractSyncService', () => { expectSyncedScopes([scopeA], [scopeB], [scopeA], [scopeB]); }); - it('also invalidates the ALL_SCOPES entry', async () => { - // Sync ALL_SCOPES -- covers every account. Resolves to [scopeA, scopeB] via getRegisteredAccounts. - await service.ensureContractSynced( - contractAddress, - null, - utilityExecutor, - anchorBlockHeader, - jobId, - 'ALL_SCOPES', - ); + it('invalidating one scope does not affect the other', async () => { + await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [ + scopeA, + scopeB, + ]); expectSyncedScopes([scopeA], [scopeB]); - // Syncing scopeA is a no-op because ALL_SCOPES already covers it. + // Syncing scopeA is a no-op because it's already cached. await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [scopeA]); expectSyncedScopes([scopeA], [scopeB]); - // Invalidate scopeA -- this should also clear the ALL_SCOPES entry. + // Invalidate scopeA only. service.invalidateContractForScopes(contractAddress, [scopeA]); // Now syncing scopeA triggers a re-sync. await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [scopeA]); expectSyncedScopes([scopeA], [scopeB], [scopeA]); - // And syncing ALL_SCOPES also triggers a re-sync since it was invalidated too. - await service.ensureContractSynced( - contractAddress, - null, - utilityExecutor, - anchorBlockHeader, - jobId, - 'ALL_SCOPES', - ); - expectSyncedScopes([scopeA], [scopeB], [scopeA], [scopeA], [scopeB]); + // Syncing both scopes only re-syncs scopeA (already re-synced above is cached), scopeB is still cached. + await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [ + scopeA, + scopeB, + ]); + expectSyncedScopes([scopeA], [scopeB], [scopeA]); }); it('empty scopes is a no-op', async () => { - await service.ensureContractSynced( - contractAddress, - null, - utilityExecutor, - anchorBlockHeader, - jobId, - 'ALL_SCOPES', - ); + await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [ + scopeA, + scopeB, + ]); expectSyncedScopes([scopeA], [scopeB]); service.invalidateContractForScopes(contractAddress, []); - // ALL_SCOPES should still be cached since no scopes were invalidated. - await service.ensureContractSynced( - contractAddress, - null, - utilityExecutor, - anchorBlockHeader, - jobId, - 'ALL_SCOPES', - ); + // Both scopes should still be cached since no scopes were invalidated. + await service.ensureContractSynced(contractAddress, null, utilityExecutor, anchorBlockHeader, jobId, [ + scopeA, + scopeB, + ]); expectSyncedScopes([scopeA], [scopeB]); }); @@ -351,7 +319,7 @@ describe('ContractSyncService', () => { }); /** Asserts the utility executor was called exactly with the given sequence of scope arrays. */ - const expectSyncedScopes = (...expectedScopes: AccessScopes[]) => { + const expectSyncedScopes = (...expectedScopes: AztecAddress[][]) => { expect(utilityExecutor).toHaveBeenCalledTimes(expectedScopes.length); for (let i = 0; i < expectedScopes.length; i++) { const [, actualScopes] = utilityExecutor.mock.calls[i]; @@ -360,7 +328,7 @@ describe('ContractSyncService', () => { }; /** Asserts the utility executor was called exactly with the given sequence of [contractAddress, scopes] pairs. */ - const expectSyncedContracts = (...expected: [AztecAddress, AccessScopes][]) => { + const expectSyncedContracts = (...expected: [AztecAddress, AztecAddress[]][]) => { expect(utilityExecutor).toHaveBeenCalledTimes(expected.length); for (let i = 0; i < expected.length; i++) { const [call, actualScopes] = utilityExecutor.mock.calls[i]; diff --git a/yarn-project/pxe/src/contract_sync/contract_sync_service.ts b/yarn-project/pxe/src/contract_sync/contract_sync_service.ts index 8708010c62e2..147bd1eb65df 100644 --- a/yarn-project/pxe/src/contract_sync/contract_sync_service.ts +++ b/yarn-project/pxe/src/contract_sync/contract_sync_service.ts @@ -4,7 +4,6 @@ import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { BlockHeader } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../access_scopes.js'; import type { StagedStore } from '../job_coordinator/job_coordinator.js'; import type { ContractStore } from '../storage/contract_store/contract_store.js'; import type { NoteStore } from '../storage/note_store/note_store.js'; @@ -31,7 +30,6 @@ export class ContractSyncService implements StagedStore { private aztecNode: AztecNode, private contractStore: ContractStore, private noteStore: NoteStore, - private getRegisteredAccounts: () => Promise, private log: Logger, ) {} @@ -52,10 +50,10 @@ export class ContractSyncService implements StagedStore { async ensureContractSynced( contractAddress: AztecAddress, functionToInvokeAfterSync: FunctionSelector | null, - utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise, + utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise, anchorBlockHeader: BlockHeader, jobId: string, - scopes: AccessScopes, + scopes: AztecAddress[], ): Promise { if (this.#shouldSkipSync(jobId, contractAddress)) { return; @@ -75,33 +73,29 @@ export class ContractSyncService implements StagedStore { await this.#awaitSync(contractAddress, scopes); } - /** Clears sync cache entries for the given scopes of a contract. Also clears the ALL_SCOPES entry. */ + /** Clears sync cache entries for the given scopes of a contract. */ invalidateContractForScopes(contractAddress: AztecAddress, scopes: AztecAddress[]): void { if (scopes.length === 0) { return; } scopes.forEach(scope => this.syncedContracts.delete(toKey(contractAddress, scope))); - this.syncedContracts.delete(toKey(contractAddress, 'ALL_SCOPES')); } async #syncContract( contractAddress: AztecAddress, functionToInvokeAfterSync: FunctionSelector | null, - utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise, + utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise, anchorBlockHeader: BlockHeader, jobId: string, - scopes: AccessScopes, + scopes: AztecAddress[], ): Promise { this.log.debug(`Syncing contract ${contractAddress}`); - // Resolve ALL_SCOPES to actual registered accounts, since sync_state must be called once per account. - const scopeAddresses = scopes === 'ALL_SCOPES' ? await this.getRegisteredAccounts() : scopes; - await Promise.all([ // Call sync_state sequentially for each scope address — each invocation synchronizes one account's private // state using scoped capsule arrays. (async () => { - for (const scope of scopeAddresses) { + for (const scope of scopes) { await syncState( contractAddress, this.contractStore, @@ -147,11 +141,11 @@ export class ContractSyncService implements StagedStore { /** If there are unsynced scopes, starts sync and stores the promise in cache with error cleanup. */ #startSyncIfNeeded( contractAddress: AztecAddress, - scopes: AccessScopes, - syncFn: (scopesToSync: AccessScopes) => Promise, + scopes: AztecAddress[], + syncFn: (scopesToSync: AztecAddress[]) => Promise, ): void { - const scopesToSync = this.#getScopesToSync(contractAddress, scopes); - const keys = toKeys(contractAddress, scopesToSync); + const scopesToSync = scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope))); + const keys = scopesToSync.map(scope => toKey(contractAddress, scope)); if (keys.length === 0) { return; } @@ -162,31 +156,15 @@ export class ContractSyncService implements StagedStore { keys.forEach(key => this.syncedContracts.set(key, promise)); } - /** Filters out scopes that are already cached, returning only those that still need syncing. */ - #getScopesToSync(contractAddress: AztecAddress, scopes: AccessScopes): AccessScopes { - if (this.syncedContracts.has(toKey(contractAddress, 'ALL_SCOPES'))) { - // If we are already syncing all scopes, then return an empty list - return []; - } - if (scopes === 'ALL_SCOPES') { - return 'ALL_SCOPES'; - } - return scopes.filter(scope => !this.syncedContracts.has(toKey(contractAddress, scope))); - } - /** Collects all relevant scope promises (including in-flight ones from concurrent calls) and awaits them. */ - async #awaitSync(contractAddress: AztecAddress, scopes: AccessScopes): Promise { - const promises = toKeys(contractAddress, scopes) - .map(key => this.syncedContracts.get(key)) + async #awaitSync(contractAddress: AztecAddress, scopes: AztecAddress[]): Promise { + const promises = scopes + .map(scope => this.syncedContracts.get(toKey(contractAddress, scope))) .filter(p => p !== undefined); await Promise.all(promises); } } -function toKeys(contract: AztecAddress, scopes: AccessScopes) { - return scopes === 'ALL_SCOPES' ? [toKey(contract, scopes)] : scopes.map(scope => toKey(contract, scope)); -} - -function toKey(contract: AztecAddress, scope: AztecAddress | 'ALL_SCOPES') { - return scope === 'ALL_SCOPES' ? `${contract.toString()}:*` : `${contract.toString()}:${scope.toString()}`; +function toKey(contract: AztecAddress, scope: AztecAddress) { + return `${contract.toString()}:${scope.toString()}`; } diff --git a/yarn-project/pxe/src/contract_sync/helpers.ts b/yarn-project/pxe/src/contract_sync/helpers.ts index 8f437d10dd7f..f794527a32f9 100644 --- a/yarn-project/pxe/src/contract_sync/helpers.ts +++ b/yarn-project/pxe/src/contract_sync/helpers.ts @@ -6,7 +6,6 @@ import { DelayedPublicMutableValues, DelayedPublicMutableValuesWithHash } from ' import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { BlockHeader } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../access_scopes.js'; import { NoteService } from '../notes/note_service.js'; import type { ContractStore } from '../storage/contract_store/contract_store.js'; import type { NoteStore } from '../storage/note_store/note_store.js'; @@ -43,7 +42,7 @@ export async function syncState( contractAddress: AztecAddress, contractStore: ContractStore, functionToInvokeAfterSync: FunctionSelector | null, - utilityExecutor: (privateSyncCall: FunctionCall, scopes: AccessScopes) => Promise, + utilityExecutor: (privateSyncCall: FunctionCall, scopes: AztecAddress[]) => Promise, noteStore: NoteStore, aztecNode: AztecNode, anchorBlockHeader: BlockHeader, @@ -60,7 +59,7 @@ export async function syncState( } const noteService = new NoteService(noteStore, aztecNode, anchorBlockHeader, jobId); - const scopes: AccessScopes = [scope]; + const scopes: AztecAddress[] = [scope]; // Both sync_state and syncNoteNullifiers interact with the note store, but running them in parallel is safe // because note store is designed to handle concurrent operations. diff --git a/yarn-project/pxe/src/debug/pxe_debug_utils.ts b/yarn-project/pxe/src/debug/pxe_debug_utils.ts index e5504328a611..592074cd37fe 100644 --- a/yarn-project/pxe/src/debug/pxe_debug_utils.ts +++ b/yarn-project/pxe/src/debug/pxe_debug_utils.ts @@ -1,9 +1,9 @@ import type { FunctionCall } from '@aztec/stdlib/abi'; import type { AuthWitness } from '@aztec/stdlib/auth-witness'; +import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { NoteDao } from '@aztec/stdlib/note'; import type { ContractOverrides } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../access_scopes.js'; import type { BlockSynchronizer } from '../block_synchronizer/block_synchronizer.js'; import type { ContractFunctionSimulator } from '../contract_function_simulator/contract_function_simulator.js'; import type { ContractSyncService } from '../contract_sync/contract_sync_service.js'; @@ -22,7 +22,7 @@ export class PXEDebugUtils { contractFunctionSimulator: ContractFunctionSimulator, call: FunctionCall, authWitnesses: AuthWitness[] | undefined, - scopes: AccessScopes, + scopes: AztecAddress[], jobId: string, ) => Promise; @@ -41,7 +41,7 @@ export class PXEDebugUtils { contractFunctionSimulator: ContractFunctionSimulator, call: FunctionCall, authWitnesses: AuthWitness[] | undefined, - scopes: AccessScopes, + scopes: AztecAddress[], jobId: string, ) => Promise, ) { diff --git a/yarn-project/pxe/src/entrypoints/client/bundle/index.ts b/yarn-project/pxe/src/entrypoints/client/bundle/index.ts index d854f0abf873..437bf2a74da3 100644 --- a/yarn-project/pxe/src/entrypoints/client/bundle/index.ts +++ b/yarn-project/pxe/src/entrypoints/client/bundle/index.ts @@ -1,4 +1,3 @@ -export * from '../../../access_scopes.js'; export * from '../../../notes_filter.js'; export * from '../../../pxe.js'; export * from '../../../config/index.js'; diff --git a/yarn-project/pxe/src/entrypoints/client/lazy/index.ts b/yarn-project/pxe/src/entrypoints/client/lazy/index.ts index 17b4025cbf74..3f417a8b5209 100644 --- a/yarn-project/pxe/src/entrypoints/client/lazy/index.ts +++ b/yarn-project/pxe/src/entrypoints/client/lazy/index.ts @@ -1,4 +1,3 @@ -export * from '../../../access_scopes.js'; export * from '../../../notes_filter.js'; export * from '../../../pxe.js'; export * from '../../../config/index.js'; diff --git a/yarn-project/pxe/src/entrypoints/server/index.ts b/yarn-project/pxe/src/entrypoints/server/index.ts index ffc0a3248e21..49a02ca88a4d 100644 --- a/yarn-project/pxe/src/entrypoints/server/index.ts +++ b/yarn-project/pxe/src/entrypoints/server/index.ts @@ -1,4 +1,3 @@ -export * from '../../access_scopes.js'; export * from '../../notes_filter.js'; export * from '../../pxe.js'; export * from '../../config/index.js'; diff --git a/yarn-project/pxe/src/logs/log_service.test.ts b/yarn-project/pxe/src/logs/log_service.test.ts index a801f48c948a..68678dc94cfc 100644 --- a/yarn-project/pxe/src/logs/log_service.test.ts +++ b/yarn-project/pxe/src/logs/log_service.test.ts @@ -54,7 +54,7 @@ describe('LogService', () => { aztecNode, anchorBlockHeader, keyStore, - new CapsuleService(capsuleStore, 'ALL_SCOPES'), + new CapsuleService(capsuleStore, []), recipientTaggingStore, senderAddressBookStore, addressStore, diff --git a/yarn-project/pxe/src/notes/note_service.test.ts b/yarn-project/pxe/src/notes/note_service.test.ts index d29529735c65..667fc26f2cea 100644 --- a/yarn-project/pxe/src/notes/note_service.test.ts +++ b/yarn-project/pxe/src/notes/note_service.test.ts @@ -41,13 +41,13 @@ describe('NoteService', () => { contractAddress = await AztecAddress.random(); - const notes = await noteStore.getNotes({ contractAddress, scopes: 'ALL_SCOPES' }, 'test'); + recipient = await keyStore.addAccount(new Fr(69), Fr.random()); + + const notes = await noteStore.getNotes({ contractAddress, scopes: [recipient.address] }, 'test'); expect(notes).toHaveLength(0); const accounts = await keyStore.getAccounts(); - expect(accounts).toHaveLength(0); - - recipient = await keyStore.addAccount(new Fr(69), Fr.random()); + expect(accounts).toHaveLength(1); setSyncedBlockNumber(BlockNumber(syncedBlockNumber)); }); @@ -65,7 +65,7 @@ describe('NoteService', () => { const nullifierIndex = randomDataInBlock(123n); aztecNode.findLeavesIndexes.mockResolvedValue([nullifierIndex]); - await noteService.syncNoteNullifiers(contractAddress, 'ALL_SCOPES'); + await noteService.syncNoteNullifiers(contractAddress, [recipient.address]); const remainingNotes = await noteStore.getNotes( { @@ -103,7 +103,7 @@ describe('NoteService', () => { // No nullifier found in merkle tree aztecNode.findLeavesIndexes.mockResolvedValue([undefined]); - await noteService.syncNoteNullifiers(contractAddress, 'ALL_SCOPES'); + await noteService.syncNoteNullifiers(contractAddress, [recipient.address]); const remainingNotes = await noteStore.getNotes( { @@ -148,7 +148,7 @@ describe('NoteService', () => { return Promise.resolve([undefined]); }); - await noteService.syncNoteNullifiers(contractAddress, 'ALL_SCOPES'); + await noteService.syncNoteNullifiers(contractAddress, [recipient.address]); // Verify note still exists const remainingNotes = await noteStore.getNotes( @@ -186,7 +186,7 @@ describe('NoteService', () => { const getNotesSpy = jest.spyOn(noteStore, 'getNotes'); - await noteService.syncNoteNullifiers(contractAddress, 'ALL_SCOPES'); + await noteService.syncNoteNullifiers(contractAddress, [recipient.address]); // Verify applyNullifiers was called once for all accounts expect(getNotesSpy).toHaveBeenCalledTimes(1); diff --git a/yarn-project/pxe/src/notes/note_service.ts b/yarn-project/pxe/src/notes/note_service.ts index dd50499c3ffd..bf839db370b8 100644 --- a/yarn-project/pxe/src/notes/note_service.ts +++ b/yarn-project/pxe/src/notes/note_service.ts @@ -7,7 +7,6 @@ import { Note, NoteDao, NoteStatus } from '@aztec/stdlib/note'; import { MerkleTreeId } from '@aztec/stdlib/trees'; import type { BlockHeader, TxHash } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../access_scopes.js'; import type { NoteStore } from '../storage/note_store/note_store.js'; export class NoteService { @@ -32,7 +31,7 @@ export class NoteService { owner: AztecAddress | undefined, storageSlot: Fr, status: NoteStatus, - scopes: AccessScopes, + scopes: AztecAddress[], ) { const noteDaos = await this.noteStore.getNotes( { @@ -71,7 +70,7 @@ export class NoteService { * * @param contractAddress - The contract whose notes should be checked and nullified. */ - public async syncNoteNullifiers(contractAddress: AztecAddress, scopes: AccessScopes): Promise { + public async syncNoteNullifiers(contractAddress: AztecAddress, scopes: AztecAddress[]): Promise { const anchorBlockHash = await this.anchorBlockHeader.hash(); const contractNotes = await this.noteStore.getNotes({ contractAddress, scopes }, this.jobId); diff --git a/yarn-project/pxe/src/notes_filter.ts b/yarn-project/pxe/src/notes_filter.ts index cdf6c3dc2bc1..18e2ab2ab9f5 100644 --- a/yarn-project/pxe/src/notes_filter.ts +++ b/yarn-project/pxe/src/notes_filter.ts @@ -2,8 +2,6 @@ import type { Fr } from '@aztec/foundation/curves/bn254'; import type { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { NoteStatus } from '@aztec/stdlib/note'; -import type { AccessScopes } from './access_scopes.js'; - /** * A filter used to fetch notes. * @remarks This filter is applied as an intersection of all its params. @@ -22,5 +20,5 @@ export type NotesFilter = { status?: NoteStatus; /** The siloed nullifier for the note. */ siloedNullifier?: Fr; - scopes: AccessScopes; + scopes: AztecAddress[]; }; diff --git a/yarn-project/pxe/src/pxe.ts b/yarn-project/pxe/src/pxe.ts index dd27286ceb0d..262eb3224be3 100644 --- a/yarn-project/pxe/src/pxe.ts +++ b/yarn-project/pxe/src/pxe.ts @@ -52,7 +52,6 @@ import { import { inspect } from 'util'; -import type { AccessScopes } from './access_scopes.js'; import { BlockSynchronizer } from './block_synchronizer/index.js'; import type { PXEConfig } from './config/index.js'; import { BenchmarkedNodeFactory } from './contract_function_simulator/benchmarked_node.js'; @@ -96,7 +95,7 @@ export type ProfileTxOpts = { /** If true, proof generation is skipped during profiling. Defaults to true. */ skipProofGeneration?: boolean; /** Addresses whose private state and keys are accessible during private execution. */ - scopes: AccessScopes; + scopes: AztecAddress[]; }; /** Options for PXE.simulateTx. */ @@ -112,7 +111,7 @@ export type SimulateTxOpts = { /** State overrides for the simulation, such as contract instances and artifacts. Requires skipKernels: true */ overrides?: SimulationOverrides; /** Addresses whose private state and keys are accessible during private execution */ - scopes: AccessScopes; + scopes: AztecAddress[]; }; /** Options for PXE.executeUtility. */ @@ -120,7 +119,7 @@ export type ExecuteUtilityOpts = { /** The authentication witnesses required for the function call. */ authwits?: AuthWitness[]; /** The accounts whose notes we can access in this call */ - scopes: AccessScopes; + scopes: AztecAddress[]; }; /** Args for PXE.create. */ @@ -215,7 +214,6 @@ export class PXE { node, contractStore, noteStore, - () => keyStore.getAccounts(), createLogger('pxe:contract_sync', bindings), ); const messageContextService = new MessageContextService(node); @@ -369,7 +367,7 @@ export class PXE { async #executePrivate( contractFunctionSimulator: ContractFunctionSimulator, txRequest: TxExecutionRequest, - scopes: AccessScopes, + scopes: AztecAddress[], jobId: string, ): Promise { const { origin: contractAddress, functionSelector } = txRequest; @@ -418,7 +416,7 @@ export class PXE { contractFunctionSimulator: ContractFunctionSimulator, call: FunctionCall, authWitnesses: AuthWitness[] | undefined, - scopes: AccessScopes, + scopes: AztecAddress[], jobId: string, ) { try { @@ -1043,7 +1041,7 @@ export class PXE { inspect(txRequest), `simulatePublic=${simulatePublic}`, `skipTxValidation=${skipTxValidation}`, - `scopes=${scopes === 'ALL_SCOPES' ? scopes : scopes.map(s => s.toString()).join(', ')}`, + `scopes=${scopes.map(s => s.toString()).join(', ')}`, ); } }); @@ -1055,7 +1053,7 @@ export class PXE { */ public executeUtility( call: FunctionCall, - { authwits, scopes }: ExecuteUtilityOpts = { scopes: 'ALL_SCOPES' }, + { authwits, scopes }: ExecuteUtilityOpts = { scopes: [] }, ): Promise { // We disable concurrent executions since those might execute oracles which read and write to the PXE stores (e.g. // to the capsules), and we need to prevent concurrent runs from interfering with one another (e.g. attempting to @@ -1113,7 +1111,7 @@ export class PXE { throw this.#contextualizeError( err, `executeUtility ${to}:${name}(${stringifiedArgs})`, - `scopes=${scopes === 'ALL_SCOPES' ? scopes : scopes.map(s => s.toString()).join(', ')}`, + `scopes=${scopes.map(s => s.toString()).join(', ')}`, ); } }); diff --git a/yarn-project/pxe/src/storage/capsule_store/capsule_service.test.ts b/yarn-project/pxe/src/storage/capsule_store/capsule_service.test.ts index 6cbe7a68b46c..616c907de454 100644 --- a/yarn-project/pxe/src/storage/capsule_store/capsule_service.test.ts +++ b/yarn-project/pxe/src/storage/capsule_store/capsule_service.test.ts @@ -95,15 +95,6 @@ describe('CapsuleService', () => { expect(await capsuleService.readCapsuleArray(contract, baseSlot, jobId, scope)).toEqual(newArray); }); - it('ALL_SCOPES allows any scope', async () => { - const allScopesService = new CapsuleService(capsuleStore, 'ALL_SCOPES'); - const randomScope = await AztecAddress.random(); - - allScopesService.setCapsule(contract, slot, capsule, jobId, randomScope); - const result = await allScopesService.getCapsule(contract, slot, jobId, randomScope); - expect(result).toEqual(capsule); - }); - it('address zero is always allowed even if not in the scopes list', async () => { const scope = AztecAddress.ZERO; diff --git a/yarn-project/pxe/src/storage/capsule_store/capsule_service.ts b/yarn-project/pxe/src/storage/capsule_store/capsule_service.ts index 4ba3c2084b95..cdb61859cb13 100644 --- a/yarn-project/pxe/src/storage/capsule_store/capsule_service.ts +++ b/yarn-project/pxe/src/storage/capsule_store/capsule_service.ts @@ -2,7 +2,6 @@ import type { Fr } from '@aztec/foundation/curves/bn254'; import { AztecAddress } from '@aztec/stdlib/aztec-address'; import type { Capsule } from '@aztec/stdlib/tx'; -import type { AccessScopes } from '../../access_scopes.js'; import type { CapsuleStore } from './capsule_store.js'; /** @@ -12,7 +11,7 @@ import type { CapsuleStore } from './capsule_store.js'; export class CapsuleService { constructor( private readonly capsuleStore: CapsuleStore, - private readonly allowedScopes: AccessScopes, + private readonly allowedScopes: AztecAddress[], ) {} setCapsule(contractAddress: AztecAddress, slot: Fr, capsule: Fr[], jobId: string, scope: AztecAddress) { @@ -79,13 +78,13 @@ export class CapsuleService { } } -function assertAllowedScope(scope: AztecAddress, allowedScopes: AccessScopes) { - if (allowedScopes === 'ALL_SCOPES' || scope.equals(AztecAddress.ZERO)) { +function assertAllowedScope(scope: AztecAddress, allowedScopes: AztecAddress[]) { + if (scope.equals(AztecAddress.ZERO)) { return; } - if (!allowedScopes.some(allowed => allowed.equals(scope))) { + if (!allowedScopes.some((allowed: AztecAddress) => allowed.equals(scope))) { throw new Error( - `Scope ${scope.toString()} is not in the allowed scopes list: [${allowedScopes.map(s => s.toString()).join(', ')}]. See https://docs.aztec.network/errors/10`, + `Scope ${scope.toString()} is not in the allowed scopes list: [${allowedScopes.map((s: AztecAddress) => s.toString()).join(', ')}]. See https://docs.aztec.network/errors/10`, ); } } diff --git a/yarn-project/pxe/src/storage/note_store/note_store.test.ts b/yarn-project/pxe/src/storage/note_store/note_store.test.ts index 8fc1a287e518..01e38dee0a71 100644 --- a/yarn-project/pxe/src/storage/note_store/note_store.test.ts +++ b/yarn-project/pxe/src/storage/note_store/note_store.test.ts @@ -99,7 +99,7 @@ describe('NoteStore', () => { const noteStore = new NoteStore(store); await verifyAndCommitForEachJob(['pre-commit', 'post-commit'], noteStore, async (jobId: string) => { - const notes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); + const notes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, jobId); expect(Array.isArray(notes)).toBe(true); expect(notes).toHaveLength(0); }); @@ -123,8 +123,8 @@ describe('NoteStore', () => { const noteStore2 = new NoteStore(store); await verifyAndCommitForEachJob(['second-store', 'fresh-job'], noteStore2, async (jobId: string) => { - const notesA = await noteStore2.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); - const notesB = await noteStore2.getNotes({ contractAddress: CONTRACT_B, scopes: 'ALL_SCOPES' }, jobId); + const notesA = await noteStore2.getNotes({ contractAddress: CONTRACT_A, scopes: [FAKE_ADDRESS] }, jobId); + const notesB = await noteStore2.getNotes({ contractAddress: CONTRACT_B, scopes: [FAKE_ADDRESS] }, jobId); expect(nullifierSet(notesA)).toEqual(nullifierSet([SILOED_NULLIFIER_1])); expect(nullifierSet(notesB)).toEqual(nullifierSet([SILOED_NULLIFIER_2])); @@ -150,14 +150,14 @@ describe('NoteStore', () => { }); it('filters notes matching only the contractAddress', async () => { - const notes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const notes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, 'test'); // note1 and note2 match CONTRACT_A expect(nullifierSet(notes)).toEqual(nullifierSet([note1, note2])); }); it('filters notes matching contractAddress and storageSlot', async () => { const notes = await noteStore.getNotes( - { contractAddress: CONTRACT_A, storageSlot: SLOT_Y, scopes: 'ALL_SCOPES' }, + { contractAddress: CONTRACT_A, storageSlot: SLOT_Y, scopes: [SCOPE_1, SCOPE_2] }, 'test', ); expect(nullifierSet(notes)).toEqual(nullifierSet([note2])); @@ -210,14 +210,14 @@ describe('NoteStore', () => { const nullifiers = [mkNullifier(note2)]; await expect(noteStore.applyNullifiers(nullifiers, 'test')).resolves.toEqual([note2]); - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, 'test'); expect(nullifierSet(activeNotes)).toEqual(nullifierSet([note1])); const allNotes = await noteStore.getNotes( { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -270,7 +270,7 @@ describe('NoteStore', () => { const filter = { contractAddress: CONTRACT_A, siloedNullifier: note1.siloedNullifier, - scopes: 'ALL_SCOPES' as const, + scopes: [SCOPE_1, SCOPE_2], }; const notes = await noteStore.getNotes(filter, 'test'); @@ -281,7 +281,7 @@ describe('NoteStore', () => { { contractAddress: CONTRACT_A, siloedNullifier: note2.siloedNullifier, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -303,13 +303,13 @@ describe('NoteStore', () => { }); it('returns no notes when filtering by non-existing contractAddress', async () => { - const notes = await noteStore.getNotes({ contractAddress: FAKE_ADDRESS, scopes: 'ALL_SCOPES' }, 'test'); + const notes = await noteStore.getNotes({ contractAddress: FAKE_ADDRESS, scopes: [SCOPE_1, SCOPE_2] }, 'test'); expect(notes).toHaveLength(0); }); it('returns no notes when filtering by non-existing storageSlot', async () => { const notes = await noteStore.getNotes( - { contractAddress: CONTRACT_A, storageSlot: NON_EXISTING_SLOT, scopes: 'ALL_SCOPES' }, + { contractAddress: CONTRACT_A, storageSlot: NON_EXISTING_SLOT, scopes: [SCOPE_1, SCOPE_2] }, 'test', ); expect(notes).toHaveLength(0); @@ -329,7 +329,7 @@ describe('NoteStore', () => { const filter = { contractAddress: CONTRACT_A, siloedNullifier: NON_EXISTING_SLOT, - scopes: 'ALL_SCOPES' as const, + scopes: [SCOPE_1, SCOPE_2], }; const notes = await noteStore.getNotes(filter, 'test'); @@ -340,7 +340,7 @@ describe('NoteStore', () => { const filter = { contractAddress: CONTRACT_B, siloedNullifier: note2.siloedNullifier, - scopes: 'ALL_SCOPES' as const, + scopes: [SCOPE_1, SCOPE_2], }; const notes = await noteStore.getNotes(filter, 'test'); @@ -372,12 +372,12 @@ describe('NoteStore', () => { const result = await noteStore.applyNullifiers([mkNullifier(note1)], 'test'); expect(result).toEqual([note1]); - const active = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const active = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, 'test'); const all = await noteStore.getNotes( { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -390,8 +390,8 @@ describe('NoteStore', () => { const nullifiers = [mkNullifier(note1), mkNullifier(note3)]; const result = await noteStore.applyNullifiers(nullifiers, 'test'); - const activeA = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); - const activeB = await noteStore.getNotes({ contractAddress: CONTRACT_B, scopes: 'ALL_SCOPES' }, 'test'); + const activeA = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, 'test'); + const activeB = await noteStore.getNotes({ contractAddress: CONTRACT_B, scopes: [SCOPE_1, SCOPE_2] }, 'test'); expect(result).toEqual([note1, note3]); // returned nullified notes expect(nullifierSet(activeA)).toEqual(nullifierSet([note2])); // note2 remains active @@ -405,7 +405,7 @@ describe('NoteStore', () => { contractAddress: CONTRACT_A, siloedNullifier: note2.siloedNullifier, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES' as const, + scopes: [SCOPE_1, SCOPE_2], }; const notes = await noteStore.getNotes(filter, 'test'); @@ -479,7 +479,10 @@ describe('NoteStore', () => { // Verify notes are still active (transaction rolled back) await verifyAndCommitForEachJob(['test', 'after-job-commit'], noteStore, async (jobId: string) => { - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + jobId, + ); expect(nullifierSet(activeNotes)).toEqual(nullifierSet([note1, note2])); }); }); @@ -495,7 +498,10 @@ describe('NoteStore', () => { expect(result).toEqual([]); await verifyAndCommitForEachJob(['test', 'after-job-commit'], noteStore, async (jobId: string) => { - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + jobId, + ); expect(nullifierSet(activeNotes)).toEqual(nullifierSet([note2])); }); }); @@ -519,11 +525,14 @@ describe('NoteStore', () => { // Verify note is now in nullified state await verifyAndCommitForEachJob(['fresh-job', 'after-job-commit'], noteStore, async (jobId: string) => { - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + jobId, + ); expect(nullifierSet(activeNotes)).not.toContain(freshNullifier.toBigInt()); const allNotes = await noteStore.getNotes( - { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: 'ALL_SCOPES' }, + { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: [SCOPE_1, SCOPE_2] }, jobId, ); expect(nullifierSet(allNotes)).toContain(freshNullifier.toBigInt()); @@ -553,14 +562,17 @@ describe('NoteStore', () => { // Verify all notes are nullified await verifyAndCommitForEachJob(['concurrent-job', 'after-job-commit'], noteStore, async (jobId: string) => { - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + jobId, + ); const activeNullifiers = nullifierSet(activeNotes); for (const nullifier of noteNullifiers) { expect(activeNullifiers).not.toContain(nullifier.toBigInt()); } const allNotes = await noteStore.getNotes( - { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: 'ALL_SCOPES' }, + { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: [SCOPE_1, SCOPE_2] }, jobId, ); expect(nullifierSet(allNotes)).toEqual(nullifierSet([note1, note2, ...noteNullifiers])); @@ -578,11 +590,14 @@ describe('NoteStore', () => { // Verify the note is in nullified state await verifyAndCommitForEachJob(['new-job', 'after-job-commit'], noteStore, async (jobId: string) => { - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, jobId); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + jobId, + ); expect(nullifierSet(activeNotes)).not.toContain(note1.siloedNullifier.toBigInt()); const allNotes = await noteStore.getNotes( - { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: 'ALL_SCOPES' }, + { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: [SCOPE_1, SCOPE_2] }, jobId, ); expect(nullifierSet(allNotes)).toContain(note1.siloedNullifier.toBigInt()); @@ -622,7 +637,7 @@ describe('NoteStore', () => { // Verify the note is nullified and has both scopes await verifyAndCommitForEachJob(['duplicate-job', 'after-job-commit'], noteStore, async (jobId: string) => { const allNotes = await noteStore.getNotes( - { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: 'ALL_SCOPES' }, + { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, scopes: [SCOPE_1, SCOPE_2] }, jobId, ); expect(nullifierSet(allNotes)).toContain(duplicateNullifier.toBigInt()); @@ -678,7 +693,10 @@ describe('NoteStore', () => { it('restores notes that were nullified after the rollback block', async () => { // noteBlock2 remains active, noteBlock3 was nullified at block 4 should be restored - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + 'test', + ); expect(nullifierSet(activeNotes)).toEqual(nullifierSet([noteBlock2, noteBlock3])); }); @@ -687,7 +705,7 @@ describe('NoteStore', () => { { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -696,13 +714,19 @@ describe('NoteStore', () => { expect(nullifierSet(allNotes)).toEqual(nullifierSet([noteBlock1, noteBlock2, noteBlock3])); // Verify noteBlock1 is not in active notes - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + 'test', + ); expect(nullifierSet(activeNotes)).not.toContain(noteBlock1.siloedNullifier.toBigInt()); }); it('preserves active notes created before the rollback block that were never nullified', async () => { // noteBlock2 was created at block 2 (before rollback block 3) and never nullified - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + 'test', + ); expect(nullifierSet(activeNotes)).toEqual(nullifierSet([noteBlock2, noteBlock3])); }); @@ -711,7 +735,7 @@ describe('NoteStore', () => { { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -742,14 +766,17 @@ describe('NoteStore', () => { await noteStore.commit('test'); await noteStore.rollback(5, 5); - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + 'test', + ); expect(activeNotes).toHaveLength(0); const allNotes = await noteStore.getNotes( { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -774,14 +801,17 @@ describe('NoteStore', () => { await noteStore.commit('test'); await noteStore.rollback(6, 4); - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + 'test', + ); expect(activeNotes).toHaveLength(0); const allNotes = await noteStore.getNotes( { contractAddress: CONTRACT_A, status: NoteStatus.ACTIVE_OR_NULLIFIED, - scopes: 'ALL_SCOPES', + scopes: [SCOPE_1, SCOPE_2], }, 'test', ); @@ -808,13 +838,16 @@ describe('NoteStore', () => { // note1 should be restored (nullified at block 7 > rollback block 5) // note2 should be deleted (created at block 10 > rollback block 5) - const activeNotes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const activeNotes = await noteStore.getNotes( + { contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, + 'test', + ); expect(nullifierSet(activeNotes)).toEqual(nullifierSet([note1Nullifier])); }); it('handles rollback on empty PXE database gracefully', async () => { await expect(noteStore.rollback(10, 20)).resolves.not.toThrow(); - const notes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: 'ALL_SCOPES' }, 'test'); + const notes = await noteStore.getNotes({ contractAddress: CONTRACT_A, scopes: [SCOPE_1, SCOPE_2] }, 'test'); expect(notes).toHaveLength(0); }); diff --git a/yarn-project/pxe/src/storage/note_store/note_store.ts b/yarn-project/pxe/src/storage/note_store/note_store.ts index 7d93c1e24a40..ae43b85e5b09 100644 --- a/yarn-project/pxe/src/storage/note_store/note_store.ts +++ b/yarn-project/pxe/src/storage/note_store/note_store.ts @@ -106,7 +106,7 @@ export class NoteStore implements StagedStore { * returned once if this is the case) */ getNotes(filter: NotesFilter, jobId: string): Promise { - if (filter.scopes !== 'ALL_SCOPES' && filter.scopes.length === 0) { + if (filter.scopes.length === 0) { return Promise.resolve([]); } @@ -180,10 +180,7 @@ export class NoteStore implements StagedStore { continue; } - if ( - filter.scopes !== 'ALL_SCOPES' && - note.scopes.intersection(new Set(filter.scopes.map(s => s.toString()))).size === 0 - ) { + if (note.scopes.intersection(new Set(filter.scopes.map(s => s.toString()))).size === 0) { continue; } diff --git a/yarn-project/txe/src/oracle/txe_oracle_top_level_context.ts b/yarn-project/txe/src/oracle/txe_oracle_top_level_context.ts index fb40853bb609..d5b01754c8ec 100644 --- a/yarn-project/txe/src/oracle/txe_oracle_top_level_context.ts +++ b/yarn-project/txe/src/oracle/txe_oracle_top_level_context.ts @@ -12,7 +12,6 @@ import { Fr } from '@aztec/foundation/curves/bn254'; import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log'; import { TestDateProvider } from '@aztec/foundation/timer'; import type { KeyStore } from '@aztec/key-store'; -import type { AccessScopes } from '@aztec/pxe/client/lazy'; import { AddressStore, CapsuleService, @@ -329,7 +328,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl const effectiveScopes = from.isZero() ? [] : [from]; // Sync notes before executing private function to discover notes from previous transactions - const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => { + const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => { await this.executeUtilityCall(call, execScopes, jobId); }; @@ -707,7 +706,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl }, blockHeader, jobId, - 'ALL_SCOPES', + await this.keyStore.getAccounts(), ); const call = FunctionCall.from({ @@ -721,10 +720,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl returnTypes: [], }); - return this.executeUtilityCall(call, 'ALL_SCOPES', jobId); + return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId); } - private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise { + private async executeUtilityCall(call: FunctionCall, scopes: AztecAddress[], jobId: string): Promise { const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector); if (entryPointArtifact.functionType !== FunctionType.UTILITY) { throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`); diff --git a/yarn-project/txe/src/state_machine/index.ts b/yarn-project/txe/src/state_machine/index.ts index 32ff8348b4f0..ca44362beee2 100644 --- a/yarn-project/txe/src/state_machine/index.ts +++ b/yarn-project/txe/src/state_machine/index.ts @@ -3,7 +3,6 @@ import { TestCircuitVerifier } from '@aztec/bb-prover/test'; import { CheckpointNumber } from '@aztec/foundation/branded-types'; import { Fr } from '@aztec/foundation/curves/bn254'; import { createLogger } from '@aztec/foundation/log'; -import type { KeyStore } from '@aztec/key-store'; import { type AnchorBlockStore, type ContractStore, ContractSyncService, type NoteStore } from '@aztec/pxe/server'; import { MessageContextService } from '@aztec/pxe/simulator'; import { L2Block } from '@aztec/stdlib/block'; @@ -36,7 +35,6 @@ export class TXEStateMachine { anchorBlockStore: AnchorBlockStore, contractStore: ContractStore, noteStore: NoteStore, - keyStore: KeyStore, ) { const synchronizer = await TXESynchronizer.create(); const aztecNodeConfig = {} as AztecNodeConfig; @@ -70,7 +68,6 @@ export class TXEStateMachine { node, contractStore, noteStore, - () => keyStore.getAccounts(), createLogger('txe:contract_sync'), ); diff --git a/yarn-project/txe/src/txe_session.ts b/yarn-project/txe/src/txe_session.ts index 6da13ce61304..ffb8574597a4 100644 --- a/yarn-project/txe/src/txe_session.ts +++ b/yarn-project/txe/src/txe_session.ts @@ -3,7 +3,6 @@ import { Fr } from '@aztec/foundation/curves/bn254'; import { type Logger, createLogger } from '@aztec/foundation/log'; import { KeyStore } from '@aztec/key-store'; import { openTmpStore } from '@aztec/kv-store/lmdb-v2'; -import type { AccessScopes } from '@aztec/pxe/client/lazy'; import { AddressStore, AnchorBlockStore, @@ -180,7 +179,7 @@ export class TXESession implements TXESessionStateHandler { const archiver = new TXEArchiver(store); const anchorBlockStore = new AnchorBlockStore(store); - const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore, keyStore); + const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore); const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000)); const version = new Fr(await stateMachine.node.getVersion()); @@ -189,13 +188,7 @@ export class TXESession implements TXESessionStateHandler { const initialJobId = jobCoordinator.beginJob(); const logger = createLogger('txe:session'); - const contractSyncService = new ContractSyncService( - stateMachine.node, - contractStore, - noteStore, - () => keyStore.getAccounts(), - logger, - ); + const contractSyncService = new ContractSyncService(stateMachine.node, contractStore, noteStore, logger); const topLevelOracleHandler = new TXEOracleTopLevelContext( stateMachine, @@ -343,7 +336,7 @@ export class TXESession implements TXESessionStateHandler { await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers( contractAddress, - 'ALL_SCOPES', + await this.keyStore.getAccounts(), ); const latestBlock = await this.stateMachine.node.getBlockHeader('latest'); @@ -379,11 +372,11 @@ export class TXESession implements TXESessionStateHandler { senderTaggingStore: this.senderTaggingStore, recipientTaggingStore: this.recipientTaggingStore, senderAddressBookStore: this.senderAddressBookStore, - capsuleService: new CapsuleService(this.capsuleStore, 'ALL_SCOPES'), + capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()), privateEventStore: this.privateEventStore, contractSyncService: this.stateMachine.contractSyncService, jobId: this.currentJobId, - scopes: 'ALL_SCOPES', + scopes: await this.keyStore.getAccounts(), messageContextService: this.stateMachine.messageContextService, }); @@ -437,7 +430,7 @@ export class TXESession implements TXESessionStateHandler { this.stateMachine.node, anchorBlockHeader, this.currentJobId, - ).syncNoteNullifiers(contractAddress, 'ALL_SCOPES'); + ).syncNoteNullifiers(contractAddress, await this.keyStore.getAccounts()); this.oracleHandler = new UtilityExecutionOracle({ contractAddress, @@ -451,12 +444,12 @@ export class TXESession implements TXESessionStateHandler { aztecNode: this.stateMachine.node, recipientTaggingStore: this.recipientTaggingStore, senderAddressBookStore: this.senderAddressBookStore, - capsuleService: new CapsuleService(this.capsuleStore, 'ALL_SCOPES'), + capsuleService: new CapsuleService(this.capsuleStore, await this.keyStore.getAccounts()), privateEventStore: this.privateEventStore, messageContextService: this.stateMachine.messageContextService, contractSyncService: this.contractSyncService, jobId: this.currentJobId, - scopes: 'ALL_SCOPES', + scopes: await this.keyStore.getAccounts(), }); this.state = { name: 'UTILITY' }; @@ -525,7 +518,7 @@ export class TXESession implements TXESessionStateHandler { } private utilityExecutorForContractSync(anchorBlock: any) { - return async (call: FunctionCall, scopes: AccessScopes) => { + return async (call: FunctionCall, scopes: AztecAddress[]) => { const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector); if (entryPointArtifact.functionType !== FunctionType.UTILITY) { throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`); diff --git a/yarn-project/wallet-sdk/src/base-wallet/base_wallet.ts b/yarn-project/wallet-sdk/src/base-wallet/base_wallet.ts index dc21fe15ac84..9b11ae2e88a4 100644 --- a/yarn-project/wallet-sdk/src/base-wallet/base_wallet.ts +++ b/yarn-project/wallet-sdk/src/base-wallet/base_wallet.ts @@ -36,7 +36,7 @@ import type { ChainInfo } from '@aztec/entrypoints/interfaces'; import { Fr } from '@aztec/foundation/curves/bn254'; import { createLogger } from '@aztec/foundation/log'; import type { FieldsOf } from '@aztec/foundation/types'; -import { type AccessScopes, displayDebugLogs } from '@aztec/pxe/client/lazy'; +import { displayDebugLogs } from '@aztec/pxe/client/lazy'; import type { PXE, PackedPrivateEvent } from '@aztec/pxe/server'; import { type ContractArtifact, @@ -94,7 +94,7 @@ export type SimulateViaEntrypointOptions = Pick< /** Fee options for the entrypoint */ feeOptions: FeeOptions; /** Scopes to use for the simulation */ - scopes: AccessScopes; + scopes: AztecAddress[]; }; /** * A base class for Wallet implementations