Skip to content

Commit e73027d

Browse files
committed
refactor: drop artifact field from SimulationOverrides
`SimulationOverrides.contracts` entries no longer carry a `ContractArtifact`. Simulation resolves the override-instance's `currentContractClassId` through PXE's locally registered classes, so callers register the target artifact via `pxe.registerContractClass(...)` once, then construct an instance with the desired `currentContractClassId` to drive dispatch. Migrates the in-tree account-stub flows (`cli-wallet`, `embedded_wallet`, `test_wallet`) to pre-register the stub class and bump `currentContractClassId` on the override instance. `proxied_contract_data_source` drops its `getFunctionArtifact*` overrides — function lookup falls through to the regular `ContractStore`.
1 parent cba6e28 commit e73027d

5 files changed

Lines changed: 41 additions & 113 deletions

File tree

yarn-project/cli-wallet/src/utils/wallet.ts

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,7 @@ import { StubEcdsaAccountContractArtifact, createStubEcdsaAccount } from '@aztec
44
import { StubSchnorrAccountContractArtifact, createStubSchnorrAccount } from '@aztec/accounts/stub/schnorr';
55
import { getIdentities } from '@aztec/accounts/utils';
66
import { type Account, type AccountContract, NO_FROM } from '@aztec/aztec.js/account';
7-
import {
8-
type InteractionFeeOptions,
9-
getContractInstanceFromInstantiationParams,
10-
getGasLimits,
11-
} from '@aztec/aztec.js/contracts';
7+
import { type InteractionFeeOptions, getContractClassFromArtifact, getGasLimits } from '@aztec/aztec.js/contracts';
128
import type { AztecNode } from '@aztec/aztec.js/node';
139
import { AccountManager, type Aliased, type SimulateOptions } from '@aztec/aztec.js/wallet';
1410
import { TxSimulationResultWithAppOffset } from '@aztec/aztec.js/wallet';
@@ -205,8 +201,12 @@ export class CLIWallet extends BaseWallet {
205201
const isSchnorr = type === 'schnorr';
206202
const artifact = isSchnorr ? StubSchnorrAccountContractArtifact : StubEcdsaAccountContractArtifact;
207203
const stubAccount = isSchnorr ? createStubSchnorrAccount(originalAddress) : createStubEcdsaAccount(originalAddress);
208-
const instance = await getContractInstanceFromInstantiationParams(artifact, { salt: Fr.random() });
209-
return { account: stubAccount, instance, artifact };
204+
// Pre-register the stub class so PXE's ACIR simulator resolves the override-instance's
205+
// currentContractClassId to the stub artifact during simulation.
206+
await this.pxe.registerContractClass(artifact);
207+
const stubClassId = (await getContractClassFromArtifact(artifact)).id;
208+
const instance = { ...contractInstance, currentContractClassId: stubClassId };
209+
return { account: stubAccount, instance };
210210
}
211211

212212
override async simulateTx(
@@ -249,9 +249,9 @@ export class CLIWallet extends BaseWallet {
249249
const entrypoint = new DefaultEntrypoint();
250250
txRequest = await entrypoint.createTxExecutionRequest(finalExecutionPayload, feeOptions.gasSettings, chainInfo);
251251
} else {
252-
const { account, instance, artifact } = await this.getFakeAccountDataFor(from);
252+
const { account, instance } = await this.getFakeAccountDataFor(from);
253253
overrides = {
254-
contracts: { [from.toString()]: { instance, artifact } },
254+
contracts: { [from.toString()]: { instance } },
255255
};
256256
const executionOptions: DefaultAccountEntrypointOptions = {
257257
txNonce: Fr.random(),

yarn-project/end-to-end/src/test-wallet/test_wallet.ts

Lines changed: 6 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import { type PXEConfig, getPXEConfig } from '@aztec/pxe/config';
2525
import { PXE, type PXECreationOptions, createPXE } from '@aztec/pxe/server';
2626
import { AuthWitness } from '@aztec/stdlib/auth-witness';
2727
import { AztecAddress } from '@aztec/stdlib/aztec-address';
28-
import { getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
28+
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
2929
import { deriveSigningKey } from '@aztec/stdlib/keys';
3030
import type { NoteDao } from '@aztec/stdlib/note';
3131
import {
@@ -133,16 +133,13 @@ export class TestWallet extends BaseWallet {
133133
}
134134

135135
const stubArtifact = this.getStubArtifactFor(address);
136-
const stubConstructorArgs =
137-
this.getTypeFor(address) === 'schnorr' ? [Fr.ZERO, Fr.ZERO] : [Buffer.alloc(32), Buffer.alloc(32)];
138-
const stubInstance = await getContractInstanceFromInstantiationParams(stubArtifact, {
139-
salt: Fr.random(),
140-
constructorArgs: stubConstructorArgs,
141-
});
136+
// Pre-register the stub class so PXE's ACIR simulator resolves the override-instance's
137+
// currentContractClassId to the stub artifact during simulation.
138+
await this.pxe.registerContractClass(stubArtifact);
139+
const stubClassId = (await getContractClassFromArtifact(stubArtifact)).id;
142140

143141
contracts[address.toString()] = {
144-
instance: stubInstance,
145-
artifact: stubArtifact,
142+
instance: { ...contractInstance, currentContractClassId: stubClassId },
146143
};
147144
}
148145

yarn-project/pxe/src/contract_function_simulator/proxied_contract_data_source.ts

Lines changed: 12 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,13 @@
1-
import { FunctionSelector } from '@aztec/stdlib/abi';
2-
import { AztecAddress } from '@aztec/stdlib/aztec-address';
1+
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
32
import type { ContractOverrides } from '@aztec/stdlib/tx';
43

54
import type { ContractStore } from '../storage/contract_store/contract_store.js';
65

76
/*
8-
* Proxy generator for a ContractStore that allows overriding contract instances and artifacts, so
9-
* the contract function simulator can execute different bytecode on certain addresses. An example use case
10-
* would be overriding your own account contract so that valid signatures don't have to be provided while simulating.
7+
* Proxy generator for a ContractStore that allows overriding contract instances at given addresses,
8+
* so the contract function simulator can execute different bytecode on certain addresses. The
9+
* override instance's `currentContractClassId` resolves to the artifact via the underlying
10+
* ContractStore — pre-register the target class via `pxe.registerContractClass(...)`.
1111
*/
1212
export class ProxiedContractStoreFactory {
1313
static create(contractStore: ContractStore, overrides?: ContractOverrides) {
@@ -17,73 +17,14 @@ export class ProxiedContractStoreFactory {
1717

1818
return new Proxy(contractStore, {
1919
get(target, prop: keyof ContractStore) {
20-
switch (prop) {
21-
case 'getContractInstance': {
22-
return async (address: AztecAddress) => {
23-
if (overrides[address.toString()]) {
24-
const { instance } = overrides[address.toString()]!;
25-
instance.address = address;
26-
const realInstance = await target.getContractInstance(address);
27-
if (!realInstance) {
28-
throw new Error(`Contract instance not found for address: ${address}`);
29-
}
30-
instance.currentContractClassId = realInstance.currentContractClassId;
31-
instance.originalContractClassId = realInstance.originalContractClassId;
32-
instance.initializationHash = realInstance.initializationHash;
33-
return instance;
34-
} else {
35-
return target.getContractInstance(address);
36-
}
37-
};
38-
}
39-
case 'getFunctionArtifact': {
40-
return async (contractAddress: AztecAddress, selector: FunctionSelector) => {
41-
if (overrides[contractAddress.toString()]) {
42-
const { artifact } = overrides[contractAddress.toString()]!;
43-
const functions = artifact.functions;
44-
for (let i = 0; i < functions.length; i++) {
45-
const fn = functions[i];
46-
const fnSelector = await FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
47-
if (fnSelector.equals(selector)) {
48-
return fn;
49-
}
50-
}
51-
throw new Error(
52-
`Function with selector ${selector} not found in stub artifact for overridden contract at ${contractAddress}. The stub does not implement this function.`,
53-
);
54-
} else {
55-
return target.getFunctionArtifact(contractAddress, selector);
56-
}
57-
};
58-
}
59-
case 'getFunctionArtifactWithDebugMetadata': {
60-
return async (contractAddress: AztecAddress, selector: FunctionSelector) => {
61-
if (overrides[contractAddress.toString()]) {
62-
const { artifact } = overrides[contractAddress.toString()]!;
63-
const functions = artifact.functions;
64-
for (let i = 0; i < functions.length; i++) {
65-
const fn = functions[i];
66-
const fnSelector = await FunctionSelector.fromNameAndParameters(fn.name, fn.parameters);
67-
if (fnSelector.equals(selector)) {
68-
return fn;
69-
}
70-
}
71-
throw new Error(
72-
`Function with selector ${selector} not found in stub artifact for overridden contract at ${contractAddress}. The stub does not implement this function.`,
73-
);
74-
} else {
75-
return target.getFunctionArtifactWithDebugMetadata(contractAddress, selector);
76-
}
77-
};
78-
}
79-
default: {
80-
const value = Reflect.get(target, prop);
81-
if (typeof value === 'function') {
82-
return value.bind(target);
83-
}
84-
return value;
85-
}
20+
if (prop === 'getContractInstance') {
21+
return async (address: AztecAddress) => {
22+
const override = overrides[address.toString()];
23+
return override ? override.instance : target.getContractInstance(address);
24+
};
8625
}
26+
const value = Reflect.get(target, prop);
27+
return typeof value === 'function' ? value.bind(target) : value;
8728
},
8829
}) satisfies ContractStore;
8930
}

yarn-project/stdlib/src/tx/simulated_tx.ts

Lines changed: 8 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import type { FieldsOf } from '@aztec/foundation/types';
33

44
import { z } from 'zod';
55

6-
import { type ContractArtifact, ContractArtifactSchema } from '../abi/abi.js';
76
import {
87
type ContractInstanceWithAddress,
98
ContractInstanceWithAddressSchema,
@@ -24,18 +23,16 @@ import { NestedProcessReturnValues, PublicSimulationOutput } from './public_simu
2423
import { Tx } from './tx.js';
2524

2625
/*
27-
* If passed during the execution of a user circuit, the contract function simulator will replace the instance and class
28-
* of the contract with the one provided in the overrides for that address. An example use case
29-
* would be overriding your own account contract so that valid signatures don't have to be provided while simulating.
26+
* Per-address contract instance overrides applied during simulation. The simulator uses each provided
27+
* instance in place of the chain-registered one at its address, driving both AVM-side public dispatch
28+
* and PXE-side ACIR private dispatch through the override's `currentContractClassId`. Pre-register the
29+
* target class artifact in PXE (`pxe.registerContractClass(...)`) so artifact lookups resolve.
3030
*/
31-
export type ContractOverrides = Record<
32-
string /* AztecAddress as string */,
33-
{ instance: ContractInstanceWithAddress; artifact: ContractArtifact }
34-
>;
31+
export type ContractOverrides = Record<string /* AztecAddress as string */, { instance: ContractInstanceWithAddress }>;
3532

3633
/*
37-
* Optional values that can be overridden during simulation. In order to simulate a transaction with these
38-
* set, it *must* be run without the kernel circuits, or validations will fail
34+
* Pre-simulation overrides applied to the contract DB before running the tx. Setting `contracts`
35+
* requires `skipKernels: true` (kernel validations would fail against shadowed instances).
3936
*/
4037
export class SimulationOverrides {
4138
public contracts?: ContractOverrides;
@@ -47,12 +44,7 @@ export class SimulationOverrides {
4744
static get schema() {
4845
return z
4946
.object({
50-
contracts: optional(
51-
z.record(
52-
z.string(),
53-
z.object({ instance: ContractInstanceWithAddressSchema, artifact: ContractArtifactSchema }),
54-
),
55-
),
47+
contracts: optional(z.record(z.string(), z.object({ instance: ContractInstanceWithAddressSchema }))),
5648
})
5749
.transform(({ contracts }) => {
5850
return new SimulationOverrides(contracts);

yarn-project/wallets/src/embedded/embedded_wallet.ts

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import type { AztecAsyncKVStore } from '@aztec/kv-store';
1111
import type { PXEConfig, PXECreationOptions } from '@aztec/pxe/client/lazy';
1212
import type { PXE } from '@aztec/pxe/server';
1313
import { AztecAddress } from '@aztec/stdlib/aztec-address';
14-
import { getContractInstanceFromInstantiationParams } from '@aztec/stdlib/contract';
14+
import { getContractClassFromArtifact } from '@aztec/stdlib/contract';
1515
import { GasSettings } from '@aztec/stdlib/gas';
1616
import type { AztecNode } from '@aztec/stdlib/interfaces/client';
1717
import { deriveSigningKey } from '@aztec/stdlib/keys';
@@ -216,15 +216,13 @@ export class EmbeddedWallet extends BaseWallet {
216216
);
217217
}
218218

219-
const stubConstructorArgs = type === 'schnorr' ? [Fr.ZERO, Fr.ZERO] : [Buffer.alloc(32), Buffer.alloc(32)];
220-
const stubInstance = await getContractInstanceFromInstantiationParams(stubArtifact, {
221-
salt: Fr.random(),
222-
constructorArgs: stubConstructorArgs,
223-
});
219+
// Pre-register the stub class so PXE's ACIR simulator resolves the override-instance's
220+
// currentContractClassId to the stub artifact during simulation.
221+
await this.pxe.registerContractClass(stubArtifact);
222+
const stubClassId = (await getContractClassFromArtifact(stubArtifact)).id;
224223

225224
contracts[address.toString()] = {
226-
instance: stubInstance,
227-
artifact: stubArtifact,
225+
instance: { ...contractInstance, currentContractClassId: stubClassId },
228226
};
229227
}
230228

0 commit comments

Comments
 (0)