@@ -38,7 +38,7 @@ import {
3838 toACVMWitness ,
3939} from '@aztec/simulator/client' ;
4040import { STANDARD_AUTH_REGISTRY_ADDRESS } from '@aztec/standard-contracts/auth-registry/constants' ;
41- import { FunctionCall , FunctionSelector , FunctionType } from '@aztec/stdlib/abi' ;
41+ import { EventSelector , FunctionCall , FunctionSelector , FunctionType } from '@aztec/stdlib/abi' ;
4242import type { AuthWitness } from '@aztec/stdlib/auth-witness' ;
4343import { AztecAddress } from '@aztec/stdlib/aztec-address' ;
4444import type { GasSettings } from '@aztec/stdlib/gas' ;
@@ -55,7 +55,7 @@ import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
5555import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js' ;
5656import { TXE_ORACLE_VERSION_MAJOR , TXE_ORACLE_VERSION_MINOR } from './oracle/txe_oracle_version.js' ;
5757import { TXEPrivateExecutionOracle } from './oracle/txe_private_execution_oracle.js' ;
58- import { RPCTranslator } from './rpc_translator.js' ;
58+ import { RPCTranslator , UnavailableOracleError } from './rpc_translator.js' ;
5959import { TXEArchiver } from './state_machine/archiver.js' ;
6060import { TXEStateMachine } from './state_machine/index.js' ;
6161import { getSingleTxBlockRequestHash , insertTxEffectIntoWorldTrees , makeTXEBlock } from './utils/block_creation.js' ;
@@ -127,14 +127,44 @@ export interface TXESessionStateHandler {
127127 ) : Promise < PrivateContextInputs > ;
128128 enterUtilityState ( contractAddress : Option < AztecAddress > ) : Promise < void > ;
129129
130- // TODO(F-335): Exposing the job info is abstraction breakage - drop the following 2 functions.
131- cycleJob ( ) : Promise < string > ;
132- getCurrentJob ( ) : string ;
130+ /**
131+ * Executes a top-level private call: runs the private function, drains its offchain effects into the session buffer,
132+ * commits the job, and (for non-static calls) tags the result with the mined tx hash.
133+ */
134+ executePrivateCall (
135+ from : Option < AztecAddress > ,
136+ targetContractAddress : AztecAddress ,
137+ functionSelector : FunctionSelector ,
138+ args : Fr [ ] ,
139+ argsHash : Fr ,
140+ isStaticCall : boolean ,
141+ additionalScopes : AztecAddress [ ] ,
142+ authorizedUtilityCallTargets : AztecAddress [ ] ,
143+ gasSettings : GasSettings ,
144+ ) : Promise < Fr [ ] > ;
145+
146+ /** Executes a top-level utility function and commits the job. */
147+ executeUtilityFunction (
148+ targetContractAddress : AztecAddress ,
149+ functionSelector : FunctionSelector ,
150+ args : Fr [ ] ,
151+ authorizedUtilityCallTargets : AztecAddress [ ] ,
152+ ) : Promise < Fr [ ] > ;
133153
134154 /**
135- * Runs an executor-style top-level call (private/public call, utility execution) with last-call tracking.
155+ * Executes a top-level public call, commits the job, and (for non-static calls) tags the result with the mined tx
156+ * hash.
136157 */
137- withTopLevelCallTracking < T > ( work : ( ) => Promise < { result : T ; txHash ?: Fr } > ) : Promise < T > ;
158+ executePublicCall (
159+ from : Option < AztecAddress > ,
160+ targetContractAddress : AztecAddress ,
161+ calldata : Fr [ ] ,
162+ isStaticCall : boolean ,
163+ gasSettings : GasSettings ,
164+ ) : Promise < Fr [ ] > ;
165+
166+ /** Syncs the target contract and returns the private events it emitted matching the given selector and scope. */
167+ getPrivateEvents ( selector : EventSelector , contractAddress : AztecAddress , scope : AztecAddress ) : Promise < Fr [ ] [ ] > ;
138168
139169 /**
140170 * Captures a raw offchain effect payload for consumption from test environment. Called by the `emit_offchain_effect`
@@ -398,12 +428,8 @@ export class TXESession implements TXESessionStateHandler {
398428 }
399429 }
400430
401- getCurrentJob ( ) : string {
402- return this . currentJobId ;
403- }
404-
405431 /** Commits the current job and begins a new one. Returns the new job ID. */
406- async cycleJob ( ) : Promise < string > {
432+ private async cycleJob ( ) : Promise < string > {
407433 await this . jobCoordinator . commitJob ( this . currentJobId ) ;
408434 this . currentJobId = this . jobCoordinator . beginJob ( ) ;
409435 return this . currentJobId ;
@@ -433,7 +459,7 @@ export class TXESession implements TXESessionStateHandler {
433459 this . lastCallInfo . anchorBlockTimestamp = anchorBlockTimestamp ;
434460 }
435461
436- async withTopLevelCallTracking < T > ( work : ( ) => Promise < { result : T ; txHash ?: Fr } > ) : Promise < T > {
462+ private async withTopLevelCallTracking < T > ( work : ( ) => Promise < { result : T ; txHash ?: Fr } > ) : Promise < T > {
437463 this . resetLastCall ( ) ;
438464 // Capture the anchor *before* `work` runs: private/public executor calls mine a new block as a
439465 // side effect, and that block's timestamp should not be attributed to this call's anchor.
@@ -463,6 +489,117 @@ export class TXESession implements TXESessionStateHandler {
463489 return { txHash, anchorBlockTimestamp } ;
464490 }
465491
492+ async executePrivateCall (
493+ from : Option < AztecAddress > ,
494+ targetContractAddress : AztecAddress ,
495+ functionSelector : FunctionSelector ,
496+ args : Fr [ ] ,
497+ argsHash : Fr ,
498+ isStaticCall : boolean ,
499+ additionalScopes : AztecAddress [ ] ,
500+ authorizedUtilityCallTargets : AztecAddress [ ] ,
501+ gasSettings : GasSettings ,
502+ ) : Promise < Fr [ ] > {
503+ const handler = this . handlerAsTxe ( ) ;
504+ return await this . withTopLevelCallTracking ( async ( ) => {
505+ const { returnValues, offchainEffects } = await handler . privateCallNewFlow (
506+ from ?. value ,
507+ targetContractAddress ,
508+ functionSelector ,
509+ args ,
510+ argsHash ,
511+ isStaticCall ,
512+ additionalScopes ,
513+ this . currentJobId ,
514+ authorizedUtilityCallTargets ,
515+ gasSettings ,
516+ ) ;
517+
518+ // Private execution collects offchain effects inside PXE's PrivateExecutionOracle rather than round-tripping
519+ // them through `aztec_utl_emitOffchainEffect`, so the session buffer is empty at this point. Drain the effects
520+ // from the execution tree into the session buffer so the next `env.offchain_messages()` call in the test sees
521+ // them.
522+ for ( const data of offchainEffects ) {
523+ this . recordOffchainEffect ( data ) ;
524+ }
525+
526+ await this . cycleJob ( ) ;
527+
528+ if ( isStaticCall ) {
529+ // Static calls revert their checkpoint and mine no block, so there is no tx hash to tag offchain effects
530+ // with. Querying `getLastTxEffects()` here would return an unrelated predecessor tx.
531+ return { result : returnValues } ;
532+ }
533+ const { txHash } = await handler . getLastTxEffects ( ) ;
534+ return { result : returnValues , txHash : txHash . hash } ;
535+ } ) ;
536+ }
537+
538+ async executeUtilityFunction (
539+ targetContractAddress : AztecAddress ,
540+ functionSelector : FunctionSelector ,
541+ args : Fr [ ] ,
542+ authorizedUtilityCallTargets : AztecAddress [ ] ,
543+ ) : Promise < Fr [ ] > {
544+ const handler = this . handlerAsTxe ( ) ;
545+ return await this . withTopLevelCallTracking ( async ( ) => {
546+ const returnValues = await handler . executeUtilityFunction (
547+ targetContractAddress ,
548+ functionSelector ,
549+ args ,
550+ this . currentJobId ,
551+ authorizedUtilityCallTargets ,
552+ ) ;
553+
554+ await this . cycleJob ( ) ;
555+
556+ return { result : returnValues } ;
557+ } ) ;
558+ }
559+
560+ async executePublicCall (
561+ from : Option < AztecAddress > ,
562+ targetContractAddress : AztecAddress ,
563+ calldata : Fr [ ] ,
564+ isStaticCall : boolean ,
565+ gasSettings : GasSettings ,
566+ ) : Promise < Fr [ ] > {
567+ const handler = this . handlerAsTxe ( ) ;
568+ return await this . withTopLevelCallTracking ( async ( ) => {
569+ const returnValues = await handler . publicCallNewFlow (
570+ from ?. value ,
571+ targetContractAddress ,
572+ calldata ,
573+ isStaticCall ,
574+ gasSettings ,
575+ ) ;
576+
577+ await this . cycleJob ( ) ;
578+
579+ if ( isStaticCall ) {
580+ // See the equivalent branch in `executePrivateCall`.
581+ return { result : returnValues } ;
582+ }
583+ const { txHash } = await handler . getLastTxEffects ( ) ;
584+ return { result : returnValues , txHash : txHash . hash } ;
585+ } ) ;
586+ }
587+
588+ async getPrivateEvents ( selector : EventSelector , contractAddress : AztecAddress , scope : AztecAddress ) : Promise < Fr [ ] [ ] > {
589+ const handler = this . handlerAsTxe ( ) ;
590+ await handler . syncContractNonOracleMethod ( contractAddress , scope , this . currentJobId ) ;
591+ // Cycle the job to commit the stores after the contract sync.
592+ await this . cycleJob ( ) ;
593+ return handler . getPrivateEvents ( selector , contractAddress , scope ) ;
594+ }
595+
596+ private handlerAsTxe ( ) : ITxeExecutionOracle {
597+ if ( ! ( 'isTxe' in this . oracleHandler ) ) {
598+ throw new UnavailableOracleError ( 'Txe' ) ;
599+ }
600+ return this . oracleHandler ;
601+ }
602+
466603 setTxeOracleVersion ( major : number , minor : number ) : void {
467604 if ( major !== TXE_ORACLE_VERSION_MAJOR ) {
468605 const hint =
0 commit comments