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
2 changes: 1 addition & 1 deletion docs/docs/aztec/smart_contracts/functions/attributes.md
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ To generate the environment, the simulator gets the blockheader from the [PXE da

Once the execution environment is created, `execute_unconstrained_function` is invoked:

#include_code execute_unconstrained_function yarn-project/simulator/src/private/unconstrained_execution.ts typescript
#include_code execute_unconstrained_function yarn-project/simulator/src/private/simulator.ts typescript

This:

Expand Down
22 changes: 8 additions & 14 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -343,27 +343,21 @@ export class PXEService implements PXE {
}

/**
* Simulate an unconstrained transaction on the given contract, without considering constraints set by ACIR.
* Simulate an unconstrained function call on the given contract, without considering constraints set by ACIR.
* The simulation parameters are fetched using ContractDataProvider and executed using AcirSimulator.
* Returns the simulation result containing the outputs of the unconstrained function.
*
* @param execRequest - The transaction request object containing the target contract and function data.
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
* @param call - The function call to execute.
* @param authWitnesses - Authentication witnesses required for the function call.
* @param scopes - Optional array of account addresses whose notes can be accessed in this call. Defaults to all
* accounts if not specified.
* @returns The simulation result containing the outputs of the unconstrained function.
*/
async #simulateUnconstrained(execRequest: FunctionCall, authWitnesses?: AuthWitness[], scopes?: AztecAddress[]) {
const { to: contractAddress, selector: functionSelector } = execRequest;

async #simulateUnconstrained(call: FunctionCall, authWitnesses?: AuthWitness[], scopes?: AztecAddress[]) {
this.log.debug('Executing unconstrained simulator...');
try {
const result = await this.simulator.runUnconstrained(
execRequest,
contractAddress,
functionSelector,
authWitnesses ?? [],
scopes,
);
this.log.verbose(`Unconstrained simulation for ${contractAddress}.${functionSelector} completed`);
const result = await this.simulator.runUnconstrained(call, authWitnesses ?? [], scopes);
this.log.verbose(`Unconstrained simulation for ${call.to}.${call.selector} completed`);

return result;
} catch (err) {
Expand Down
60 changes: 38 additions & 22 deletions yarn-project/simulator/src/private/simulator.ts
Original file line number Diff line number Diff line change
@@ -1,19 +1,19 @@
import { Fr } from '@aztec/foundation/fields';
import { type Logger, createLogger } from '@aztec/foundation/log';
import type { AbiDecoded, FunctionCall } from '@aztec/stdlib/abi';
import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
import { FunctionSelector, FunctionType, decodeFromAbi } from '@aztec/stdlib/abi';
import type { AuthWitness } from '@aztec/stdlib/auth-witness';
import { AztecAddress } from '@aztec/stdlib/aztec-address';
import { CallContext, HashedValues, PrivateExecutionResult, TxExecutionRequest, collectNested } from '@aztec/stdlib/tx';

import { createSimulationError } from '../common/errors.js';
import { ExecutionError, createSimulationError, resolveAssertionMessageFromError } from '../common/errors.js';
import { Oracle, extractCallStack, toACVMWitness, witnessMapToFields } from './acvm/index.js';
import type { ExecutionDataProvider } from './execution_data_provider.js';
import { ExecutionNoteCache } from './execution_note_cache.js';
import { HashedValuesCache } from './hashed_values_cache.js';
import { executePrivateFunction, verifyCurrentClassId } from './private_execution.js';
import { PrivateExecutionOracle } from './private_execution_oracle.js';
import type { SimulationProvider } from './providers/simulation_provider.js';
import { executeUnconstrainedFunction } from './unconstrained_execution.js';
import { UnconstrainedExecutionOracle } from './unconstrained_execution_oracle.js';

/**
Expand Down Expand Up @@ -115,29 +115,29 @@ export class AcirSimulator {
}
}

// docs:start:execute_unconstrained_function
/**
* Runs an unconstrained function.
* @param request - The transaction request.
* @param entryPointArtifact - The artifact of the entry point function.
* @param contractAddress - The address of the contract.
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
* @param call - The function call to execute.
* @param authwits - Authentication witnesses required for the function call.
* @param scopes - Optional array of account addresses whose notes can be accessed in this call. Defaults to all
* accounts if not specified.
* @returns A decoded ABI value containing the function's return data.
*/
public async runUnconstrained(
request: FunctionCall,
contractAddress: AztecAddress,
selector: FunctionSelector,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These 2 params here made no sense as they were also in the FunctionCall.

call: FunctionCall,
authwits: AuthWitness[],
scopes?: AztecAddress[],
): Promise<AbiDecoded> {
await verifyCurrentClassId(contractAddress, this.executionDataProvider);
const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(contractAddress, selector);
await verifyCurrentClassId(call.to, this.executionDataProvider);
const entryPointArtifact = await this.executionDataProvider.getFunctionArtifact(call.to, call.selector);

if (entryPointArtifact.functionType !== FunctionType.UNCONSTRAINED) {
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as unconstrained`);
}

const context = new UnconstrainedExecutionOracle(
contractAddress,
const oracle = new UnconstrainedExecutionOracle(
call.to,
authwits,
[],
this.executionDataProvider,
Expand All @@ -146,16 +146,32 @@ export class AcirSimulator {
);

try {
return await executeUnconstrainedFunction(
this.simulationProvider,
context,
entryPointArtifact,
contractAddress,
request.selector,
request.args,
);
this.log.verbose(`Executing unconstrained function ${entryPointArtifact.name}`, {
contract: call.to,
selector: call.selector,
});

const initialWitness = toACVMWitness(0, call.args);
const acirExecutionResult = await this.simulationProvider
.executeUserCircuit(initialWitness, entryPointArtifact, new Oracle(oracle))
.catch((err: Error) => {
err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
throw new ExecutionError(
err.message,
{
contractAddress: call.to,
functionSelector: call.selector,
},
extractCallStack(err, entryPointArtifact.debug),
{ cause: err },
);
});

const returnWitness = witnessMapToFields(acirExecutionResult.returnWitness);
return decodeFromAbi(entryPointArtifact.returnTypes, returnWitness);
} catch (err) {
throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
}
}
// docs:end:execute_unconstrained_function
}
Original file line number Diff line number Diff line change
Expand Up @@ -93,7 +93,7 @@ describe('Unconstrained Execution test suite', () => {
returnTypes: artifact.returnTypes,
};

const result = await acirSimulator.runUnconstrained(execRequest, contractAddress, FunctionSelector.empty(), []);
const result = await acirSimulator.runUnconstrained(execRequest, [], []);

expect(result).toEqual(9n);
}, 30_000);
Expand Down
54 changes: 0 additions & 54 deletions yarn-project/simulator/src/private/unconstrained_execution.ts

This file was deleted.

Loading