Skip to content

Commit

Permalink
init
Browse files Browse the repository at this point in the history
  • Loading branch information
sklppy88 committed Aug 2, 2024
1 parent fd4ec01 commit 63e1197
Show file tree
Hide file tree
Showing 7 changed files with 48 additions and 19 deletions.
9 changes: 6 additions & 3 deletions yarn-project/circuit-types/src/interfaces/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -159,11 +159,12 @@ export interface PXE {
*
* @param txRequest - An authenticated tx request ready for simulation
* @param simulatePublic - Whether to simulate the public part of the transaction.
* @param scopes - (Optional) The accounts whose notes we can access in this call. Currently optional and will default to all.
* @returns A transaction ready to be sent to the network for execution.
* @throws If the code for the functions executed in this transaction has not been made available via `addContracts`.
* Also throws if simulatePublic is true and public simulation reverts.
*/
proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean): Promise<Tx>;
proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean, scopes?: AztecAddress[]): Promise<Tx>;

/**
* Simulates a transaction based on the provided preauthenticated execution request.
Expand All @@ -179,12 +180,13 @@ export interface PXE {
* @param txRequest - An authenticated tx request ready for simulation
* @param simulatePublic - Whether to simulate the public part of the transaction.
* @param msgSender - (Optional) The message sender to use for the simulation.
* @param scopes - (Optional) The accounts whose notes we can access in this call. Currently optional and will default to all.
* @returns A simulated transaction object that includes a transaction that is potentially ready
* to be sent to the network for execution, along with public and private return values.
* @throws If the code for the functions executed in this transaction has not been made available via `addContracts`.
* Also throws if simulatePublic is true and public simulation reverts.
*/
simulateTx(txRequest: TxExecutionRequest, simulatePublic: boolean, msgSender?: AztecAddress): Promise<SimulatedTx>;
simulateTx(txRequest: TxExecutionRequest, simulatePublic: boolean, msgSender?: AztecAddress, scopes?: AztecAddress[]): Promise<SimulatedTx>;

/**
* Sends a transaction to an Aztec node to be broadcasted to the network and mined.
Expand Down Expand Up @@ -280,9 +282,10 @@ export interface PXE {
* @param args - The arguments to be provided to the function.
* @param to - The address of the contract to be called.
* @param from - (Optional) The msg sender to set for the call.
* @param scopes - (Optional) The accounts whose notes we can access in this call. Currently optional and will default to all.
* @returns The result of the view function call, structured based on the function ABI.
*/
simulateUnconstrained(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress): Promise<any>;
simulateUnconstrained(functionName: string, args: any[], to: AztecAddress, from?: AztecAddress, scopes?: AztecAddress[]): Promise<any>;

/**
* Gets unencrypted logs based on the provided filter.
Expand Down
27 changes: 18 additions & 9 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -502,9 +502,9 @@ export class PXEService implements PXE {
return await this.node.getBlock(blockNumber);
}

public proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean): Promise<Tx> {
public proveTx(txRequest: TxExecutionRequest, simulatePublic: boolean, scopes?: AztecAddress[]): Promise<Tx> {
return this.jobQueue.put(async () => {
const simulatedTx = await this.#simulateAndProve(txRequest, this.proofCreator, undefined);
const simulatedTx = await this.#simulateAndProve(txRequest, this.proofCreator, undefined, scopes);
if (simulatePublic) {
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
}
Expand All @@ -517,9 +517,10 @@ export class PXEService implements PXE {
txRequest: TxExecutionRequest,
simulatePublic: boolean,
msgSender: AztecAddress | undefined = undefined,
scopes?: AztecAddress[],
): Promise<SimulatedTx> {
return await this.jobQueue.put(async () => {
const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender);
const simulatedTx = await this.#simulateAndProve(txRequest, this.fakeProofCreator, msgSender, scopes);
if (simulatePublic) {
simulatedTx.publicOutput = await this.#simulatePublicCalls(simulatedTx.tx);
}
Expand Down Expand Up @@ -550,12 +551,13 @@ export class PXEService implements PXE {
args: any[],
to: AztecAddress,
_from?: AztecAddress,
scopes?: AztecAddress[],
): Promise<DecodedReturn> {
// all simulations must be serialized w.r.t. the synchronizer
return await this.jobQueue.put(async () => {
// TODO - Should check if `from` has the permission to call the view function.
const functionCall = await this.#getFunctionCall(functionName, args, to);
const executionResult = await this.#simulateUnconstrained(functionCall);
const executionResult = await this.#simulateUnconstrained(functionCall, scopes);

// TODO - Return typed result based on the function artifact.
return executionResult;
Expand Down Expand Up @@ -667,14 +669,18 @@ export class PXEService implements PXE {
};
}

async #simulate(txRequest: TxExecutionRequest, msgSender?: AztecAddress): Promise<ExecutionResult> {
async #simulate(
txRequest: TxExecutionRequest,
msgSender?: AztecAddress,
scopes?: AztecAddress[],
): Promise<ExecutionResult> {
// TODO - Pause syncing while simulating.

const { contractAddress, functionArtifact } = await this.#getSimulationParameters(txRequest);

this.log.debug('Executing simulator...');
try {
const result = await this.simulator.run(txRequest, functionArtifact, contractAddress, msgSender);
const result = await this.simulator.run(txRequest, functionArtifact, contractAddress, msgSender, scopes);
this.log.verbose(`Simulation completed for ${contractAddress.toString()}:${functionArtifact.name}`);
return result;
} catch (err) {
Expand All @@ -691,14 +697,15 @@ export class PXEService implements PXE {
* 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.
* @returns The simulation result containing the outputs of the unconstrained function.
*/
async #simulateUnconstrained(execRequest: FunctionCall) {
async #simulateUnconstrained(execRequest: FunctionCall, scopes?: AztecAddress[]) {
const { contractAddress, functionArtifact } = await this.#getSimulationParameters(execRequest);

this.log.debug('Executing unconstrained simulator...');
try {
const result = await this.simulator.runUnconstrained(execRequest, functionArtifact, contractAddress);
const result = await this.simulator.runUnconstrained(execRequest, functionArtifact, contractAddress, scopes);
this.log.verbose(`Unconstrained simulation for ${contractAddress}.${functionArtifact.name} completed`);

return result;
Expand Down Expand Up @@ -756,6 +763,7 @@ export class PXEService implements PXE {
* @param txExecutionRequest - The transaction request to be simulated and proved.
* @param proofCreator - The proof creator to use for proving the execution.
* @param msgSender - (Optional) The message sender to use for the simulation.
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
* @returns An object that contains:
* A private transaction object containing the proof, public inputs, and encrypted logs.
* The return values of the private execution
Expand All @@ -764,9 +772,10 @@ export class PXEService implements PXE {
txExecutionRequest: TxExecutionRequest,
proofCreator: PrivateKernelProver,
msgSender?: AztecAddress,
scopes?: AztecAddress[],
): Promise<SimulatedTx> {
// Get values that allow us to reconstruct the block hash
const executionResult = await this.#simulate(txExecutionRequest, msgSender);
const executionResult = await this.#simulate(txExecutionRequest, msgSender, scopes);

const kernelOracle = new KernelOracle(this.contractDataOracle, this.keyStore, this.node);
const kernelProver = new KernelProver(kernelOracle, proofCreator);
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/pxe/src/simulator_oracle/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,11 +77,12 @@ export class SimulatorOracle implements DBOracle {
return capsule;
}

async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus) {
async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus, scopes?: AztecAddress[]) {
const noteDaos = await this.db.getIncomingNotes({
contractAddress,
storageSlot,
status,
scopes,
});
return noteDaos.map(({ contractAddress, storageSlot, nonce, note, slottedNoteHash, siloedNullifier, index }) => ({
contractAddress,
Expand Down
7 changes: 5 additions & 2 deletions yarn-project/simulator/src/client/client_execution_context.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,8 +94,9 @@ export class ClientExecutionContext extends ViewDataOracle {
private node: AztecNode,
protected sideEffectCounter: number = 0,
log = createDebugLogger('aztec:simulator:client_execution_context'),
scopes?: AztecAddress[],
) {
super(contractAddress, authWitnesses, db, node, log);
super(contractAddress, authWitnesses, db, node, log, scopes);
}

// We still need this function until we can get user-defined ordering of structs for fn arguments
Expand Down Expand Up @@ -251,7 +252,7 @@ export class ClientExecutionContext extends ViewDataOracle {
const pendingNotes = this.noteCache.getNotes(this.callContext.storageContractAddress, storageSlot);

const pendingNullifiers = this.noteCache.getNullifiers(this.callContext.storageContractAddress);
const dbNotes = await this.db.getNotes(this.callContext.storageContractAddress, storageSlot, status);
const dbNotes = await this.db.getNotes(this.callContext.storageContractAddress, storageSlot, status, this.scopes);
const dbNotesFiltered = dbNotes.filter(n => !pendingNullifiers.has((n.siloedNullifier as Fr).value));

const notes = pickNotes<NoteData>([...dbNotesFiltered, ...pendingNotes], {
Expand Down Expand Up @@ -519,6 +520,8 @@ export class ClientExecutionContext extends ViewDataOracle {
this.db,
this.node,
sideEffectCounter,
this.log,
this.scopes,
);

const childExecutionResult = await executePrivateFunction(
Expand Down
8 changes: 7 additions & 1 deletion yarn-project/simulator/src/client/db_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,15 @@ export interface DBOracle extends CommitmentsDB {
* @param contractAddress - The contract address of the notes.
* @param storageSlot - The storage slot of the notes.
* @param status - The status of notes to fetch.
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
* @returns A Promise that resolves to an array of note data.
*/
getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus): Promise<NoteData[]>;
getNotes(
contractAddress: AztecAddress,
storageSlot: Fr,
status: NoteStatus,
scopes?: AztecAddress[],
): Promise<NoteData[]>;

/**
* Retrieve the artifact information of a specific function within a contract.
Expand Down
10 changes: 8 additions & 2 deletions yarn-project/simulator/src/client/simulator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,15 @@ export class AcirSimulator {
* @param entryPointArtifact - The artifact of the entry point function.
* @param contractAddress - The address of the contract (should match request.origin)
* @param msgSender - The address calling the function. This can be replaced to simulate a call from another contract or a specific account.
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
* @returns The result of the execution.
*/
public async run(
request: TxExecutionRequest,
entryPointArtifact: FunctionArtifact,
contractAddress: AztecAddress,
msgSender = AztecAddress.fromField(Fr.MAX_FIELD_VALUE),
scopes?: AztecAddress[],
): Promise<ExecutionResult> {
if (entryPointArtifact.functionType !== FunctionType.PRIVATE) {
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as private`);
Expand Down Expand Up @@ -83,6 +85,8 @@ export class AcirSimulator {
this.db,
this.node,
startSideEffectCounter,
undefined,
scopes,
);

try {
Expand All @@ -103,18 +107,19 @@ export class AcirSimulator {
* @param request - The transaction request.
* @param entryPointArtifact - The artifact of the entry point function.
* @param contractAddress - The address of the contract.
* @param aztecNode - The AztecNode instance.
* @param scopes - The accounts whose notes we can access in this call. Currently optional and will default to all.
*/
public async runUnconstrained(
request: FunctionCall,
entryPointArtifact: FunctionArtifact,
contractAddress: AztecAddress,
scopes?: AztecAddress[],
) {
if (entryPointArtifact.functionType !== FunctionType.UNCONSTRAINED) {
throw new Error(`Cannot run ${entryPointArtifact.functionType} function as unconstrained`);
}

const context = new ViewDataOracle(contractAddress, [], this.db, this.node);
const context = new ViewDataOracle(contractAddress, [], this.db, this.node, undefined, scopes);

try {
return await executeUnconstrainedFunction(
Expand Down Expand Up @@ -195,6 +200,7 @@ export class AcirSimulator {
execRequest,
artifact,
contractAddress,
// We can omit scopes here, because "compute_note_hash_and_optionally_a_nullifier" does not need access to any notes.
)) as bigint[];

return {
Expand Down
3 changes: 2 additions & 1 deletion yarn-project/simulator/src/client/view_data_oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ export class ViewDataOracle extends TypedOracle {
protected readonly db: DBOracle,
protected readonly aztecNode: AztecNode,
protected log = createDebugLogger('aztec:simulator:client_view_context'),
protected readonly scopes?: AztecAddress[],
) {
super();
}
Expand Down Expand Up @@ -219,7 +220,7 @@ export class ViewDataOracle extends TypedOracle {
offset: number,
status: NoteStatus,
): Promise<NoteData[]> {
const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status);
const dbNotes = await this.db.getNotes(this.contractAddress, storageSlot, status, this.scopes);
return pickNotes<NoteData>(dbNotes, {
selects: selectByIndexes.slice(0, numSelects).map((index, i) => ({
selector: { index, offset: selectByOffsets[i], length: selectByLengths[i] },
Expand Down

0 comments on commit 63e1197

Please sign in to comment.