Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions docs/docs-developers/docs/resources/migration_notes.md
Original file line number Diff line number Diff line change
Expand Up @@ -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:
Expand Down
5 changes: 3 additions & 2 deletions yarn-project/cli-wallet/src/cmds/check_tx.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -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()];
Expand Down
7 changes: 6 additions & 1 deletion yarn-project/cli-wallet/src/utils/wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,12 @@ export class CLIWallet extends BaseWallet {

override async getAccounts(): Promise<Aliased<AztecAddress>[]> {
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(
Expand Down
9 changes: 0 additions & 9 deletions yarn-project/pxe/src/access_scopes.ts

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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;
};
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -149,7 +149,7 @@ describe('Oracle Version Check test suite', () => {
anchorBlockHeader,
senderForTags,
jobId: 'test',
scopes: 'ALL_SCOPES',
scopes: [],
});

expect(assertCompatibleOracleVersionSpy).toHaveBeenCalledTimes(1);
Expand Down Expand Up @@ -206,7 +206,7 @@ describe('Oracle Version Check test suite', () => {
messageContextService,
contractSyncService,
jobId: 'test',
scopes: 'ALL_SCOPES',
scopes: [],
});
});

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -206,7 +206,7 @@ describe('Private Execution test suite', () => {
anchorBlockHeader,
senderForTags,
jobId: TEST_JOB_ID,
scopes: 'ALL_SCOPES',
scopes: [owner],
});
};

Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand All @@ -43,7 +42,7 @@ export type PrivateExecutionOracleArgs = Omit<UtilityExecutionOracleArgs, 'contr
txContext: TxContext;
callContext: CallContext;
/** Needed to trigger contract synchronization before nested calls */
utilityExecutor: (call: FunctionCall, scopes: AccessScopes) => Promise<void>;
utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise<void>;
executionCache: HashedValuesCache;
noteCache: ExecutionNoteCache;
taggingIndexCache: ExecutionTaggingIndexCache;
Expand Down Expand Up @@ -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<void>;
private readonly utilityExecutor: (call: FunctionCall, scopes: AztecAddress[]) => Promise<void>;
private readonly executionCache: HashedValuesCache;
private readonly noteCache: ExecutionNoteCache;
private readonly taggingIndexCache: ExecutionTaggingIndexCache;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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: [],
Expand All @@ -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],
});
});

Expand All @@ -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();
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -65,7 +64,7 @@ export type UtilityExecutionOracleArgs = {
contractSyncService: ContractSyncService;
jobId: string;
log?: ReturnType<typeof createLogger>;
scopes: AccessScopes;
scopes: AztecAddress[];
};

/**
Expand Down Expand Up @@ -96,7 +95,7 @@ export class UtilityExecutionOracle implements IMiscOracle, IUtilityExecutionOra
protected readonly contractSyncService: ContractSyncService;
protected readonly jobId: string;
protected logger: ReturnType<typeof createLogger>;
protected readonly scopes: AccessScopes;
protected readonly scopes: AztecAddress[];

constructor(args: UtilityExecutionOracleArgs) {
this.contractAddress = args.contractAddress;
Expand Down Expand Up @@ -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<KeyValidationRequest> {
// 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);
}

Expand Down
Loading
Loading