@aztec/txe 0.0.1-commit.3469e52 → 0.0.1-commit.381b1a9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (55) hide show
  1. package/dest/index.d.ts +1 -1
  2. package/dest/index.d.ts.map +1 -1
  3. package/dest/index.js +82 -50
  4. package/dest/oracle/interfaces.d.ts +6 -5
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +5 -5
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +6 -6
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +7 -8
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +105 -34
  12. package/dest/rpc_translator.d.ts +16 -10
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +75 -39
  15. package/dest/state_machine/archiver.d.ts +4 -4
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +8 -9
  18. package/dest/state_machine/dummy_p2p_client.d.ts +16 -12
  19. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  20. package/dest/state_machine/dummy_p2p_client.js +28 -16
  21. package/dest/state_machine/index.d.ts +7 -7
  22. package/dest/state_machine/index.d.ts.map +1 -1
  23. package/dest/state_machine/index.js +31 -17
  24. package/dest/state_machine/mock_epoch_cache.d.ts +6 -2
  25. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  26. package/dest/state_machine/mock_epoch_cache.js +6 -1
  27. package/dest/state_machine/synchronizer.d.ts +3 -3
  28. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  29. package/dest/txe_session.d.ts +9 -6
  30. package/dest/txe_session.d.ts.map +1 -1
  31. package/dest/txe_session.js +83 -23
  32. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  33. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  34. package/dest/util/txe_public_contract_data_source.js +5 -22
  35. package/dest/utils/block_creation.d.ts +5 -5
  36. package/dest/utils/block_creation.d.ts.map +1 -1
  37. package/dest/utils/block_creation.js +7 -5
  38. package/package.json +15 -15
  39. package/src/index.ts +83 -49
  40. package/src/oracle/interfaces.ts +8 -3
  41. package/src/oracle/txe_oracle_public_context.ts +8 -10
  42. package/src/oracle/txe_oracle_top_level_context.ts +134 -81
  43. package/src/rpc_translator.ts +79 -32
  44. package/src/state_machine/archiver.ts +9 -11
  45. package/src/state_machine/dummy_p2p_client.ts +40 -22
  46. package/src/state_machine/index.ts +49 -19
  47. package/src/state_machine/mock_epoch_cache.ts +7 -1
  48. package/src/state_machine/synchronizer.ts +2 -2
  49. package/src/txe_session.ts +98 -82
  50. package/src/util/txe_public_contract_data_source.ts +10 -36
  51. package/src/utils/block_creation.ts +8 -6
  52. package/dest/util/txe_contract_store.d.ts +0 -12
  53. package/dest/util/txe_contract_store.d.ts.map +0 -1
  54. package/dest/util/txe_contract_store.js +0 -22
  55. package/src/util/txe_contract_store.ts +0 -36
@@ -12,9 +12,11 @@ import { Fr } from '@aztec/foundation/curves/bn254';
12
12
  import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
13
13
  import { TestDateProvider } from '@aztec/foundation/timer';
14
14
  import type { KeyStore } from '@aztec/key-store';
15
+ import type { AccessScopes } from '@aztec/pxe/client/lazy';
15
16
  import {
16
17
  AddressStore,
17
18
  CapsuleStore,
19
+ type ContractStore,
18
20
  NoteStore,
19
21
  ORACLE_VERSION,
20
22
  PrivateEventStore,
@@ -83,7 +85,6 @@ import { ForkCheckpoint } from '@aztec/world-state';
83
85
  import { DEFAULT_ADDRESS } from '../constants.js';
84
86
  import type { TXEStateMachine } from '../state_machine/index.js';
85
87
  import type { TXEAccountStore } from '../util/txe_account_store.js';
86
- import type { TXEContractStore } from '../util/txe_contract_store.js';
87
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
88
89
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
89
90
  import type { ITxeExecutionOracle } from './interfaces.js';
@@ -96,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
96
97
 
97
98
  constructor(
98
99
  private stateMachine: TXEStateMachine,
99
- private contractStore: TXEContractStore,
100
+ private contractStore: ContractStore,
100
101
  private noteStore: NoteStore,
101
102
  private keyStore: KeyStore,
102
103
  private addressStore: AddressStore,
@@ -106,7 +107,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
106
107
  private senderAddressBookStore: SenderAddressBookStore,
107
108
  private capsuleStore: CapsuleStore,
108
109
  private privateEventStore: PrivateEventStore,
109
- private jobId: string,
110
110
  private nextBlockTimestamp: bigint,
111
111
  private version: Fr,
112
112
  private chainId: Fr,
@@ -131,13 +131,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
131
131
  }
132
132
 
133
133
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
134
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
134
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
135
135
  if (!LogLevels[level]) {
136
- throw new Error(`Invalid debug log level: ${level}`);
136
+ throw new Error(`Invalid log level: ${level}`);
137
137
  }
138
138
  const levelName = LogLevels[level];
139
139
 
140
140
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
141
+ return Promise.resolve();
141
142
  }
142
143
 
143
144
  txeGetDefaultAddress(): AztecAddress {
@@ -170,6 +171,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
170
171
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
171
172
  }
172
173
 
174
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
175
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
176
+ this.logger.debug(`Skipping sync in txeGetPrivateEvents because the events correspond to the default address.`);
177
+ return;
178
+ }
179
+
180
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
181
+ await this.stateMachine.contractSyncService.ensureContractSynced(
182
+ contractAddress,
183
+ null,
184
+ async (call, execScopes) => {
185
+ await this.executeUtilityCall(call, execScopes, jobId);
186
+ },
187
+ blockHeader,
188
+ jobId,
189
+ [scope],
190
+ );
191
+ }
192
+
173
193
  async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
174
194
  return (
175
195
  await this.privateEventStore.getPrivateEvents(selector, {
@@ -209,7 +229,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
209
229
  await this.txeAddAccount(artifact, instance, secret);
210
230
  } else {
211
231
  await this.contractStore.addContractInstance(instance);
212
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
232
+ await this.contractStore.addContractArtifact(artifact);
213
233
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
214
234
  }
215
235
  }
@@ -219,7 +239,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
219
239
 
220
240
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
221
241
  await this.contractStore.addContractInstance(instance);
222
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
242
+ await this.contractStore.addContractArtifact(artifact);
223
243
 
224
244
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
225
245
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -283,6 +303,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
283
303
  args: Fr[],
284
304
  argsHash: Fr = Fr.zero(),
285
305
  isStaticCall: boolean = false,
306
+ jobId: string,
286
307
  ) {
287
308
  this.logger.verbose(
288
309
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -296,12 +317,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
296
317
  throw new Error(message);
297
318
  }
298
319
 
320
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
321
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
322
+ const effectiveScopes = from.isZero() ? [] : [from];
323
+
299
324
  // Sync notes before executing private function to discover notes from previous transactions
300
- const utilityExecutor = async (call: FunctionCall) => {
301
- await this.executeUtilityCall(call);
325
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
326
+ await this.executeUtilityCall(call, execScopes, jobId);
302
327
  };
303
328
 
304
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, utilityExecutor);
329
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
330
+ await this.stateMachine.contractSyncService.ensureContractSynced(
331
+ targetContractAddress,
332
+ functionSelector,
333
+ utilityExecutor,
334
+ blockHeader,
335
+ jobId,
336
+ effectiveScopes,
337
+ );
305
338
 
306
339
  const blockNumber = await this.txeGetNextBlockNumber();
307
340
 
@@ -313,8 +346,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
313
346
 
314
347
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
315
348
 
316
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
317
-
318
349
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
319
350
  const noteCache = new ExecutionNoteCache(protocolNullifier);
320
351
  // In production, the account contract sets the min revertible counter before calling the app function.
@@ -326,43 +357,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
326
357
 
327
358
  const simulator = new WASMSimulator();
328
359
 
329
- const privateExecutionOracle = new PrivateExecutionOracle(
360
+ const privateExecutionOracle = new PrivateExecutionOracle({
330
361
  argsHash,
331
362
  txContext,
332
363
  callContext,
333
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
334
- blockHeader,
364
+ anchorBlockHeader: blockHeader,
335
365
  utilityExecutor,
336
- /** List of transient auth witnesses to be used during this simulation */
337
- Array.from(this.authwits.values()),
338
- /** List of transient auth witnesses to be used during this simulation */
339
- [],
340
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
366
+ authWitnesses: Array.from(this.authwits.values()),
367
+ capsules: [],
368
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
341
369
  noteCache,
342
370
  taggingIndexCache,
343
- this.contractStore,
344
- this.noteStore,
345
- this.keyStore,
346
- this.addressStore,
347
- this.stateMachine.node,
348
- this.stateMachine.anchorBlockStore,
349
- this.senderTaggingStore,
350
- this.recipientTaggingStore,
351
- this.senderAddressBookStore,
352
- this.capsuleStore,
353
- this.privateEventStore,
354
- this.jobId,
355
- 0, // totalPublicArgsCount
356
- minRevertibleSideEffectCounter, // (start) sideEffectCounter
357
- undefined, // log
358
- undefined, // scopes
359
- /**
360
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
361
- * contract would perform, including setting senderForTags.
362
- */
363
- from,
371
+ contractStore: this.contractStore,
372
+ noteStore: this.noteStore,
373
+ keyStore: this.keyStore,
374
+ addressStore: this.addressStore,
375
+ aztecNode: this.stateMachine.node,
376
+ senderTaggingStore: this.senderTaggingStore,
377
+ recipientTaggingStore: this.recipientTaggingStore,
378
+ senderAddressBookStore: this.senderAddressBookStore,
379
+ capsuleStore: this.capsuleStore,
380
+ privateEventStore: this.privateEventStore,
381
+ contractSyncService: this.stateMachine.contractSyncService,
382
+ jobId,
383
+ totalPublicCalldataCount: 0,
384
+ sideEffectCounter: minRevertibleSideEffectCounter,
385
+ scopes: effectiveScopes,
386
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
387
+ // contract would perform, including setting senderForTags.
388
+ senderForTags: from,
364
389
  simulator,
365
- );
390
+ });
366
391
 
367
392
  // Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
368
393
  let result: PrivateExecutionResult;
@@ -401,7 +426,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
401
426
  // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
402
427
  const { publicInputs } = await generateSimulatedProvingResult(
403
428
  result,
404
- this.contractStore,
429
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
430
+ this.stateMachine.node,
405
431
  minRevertibleSideEffectCounter,
406
432
  );
407
433
 
@@ -414,7 +440,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
414
440
 
415
441
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
416
442
 
417
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
443
+ const bindings = this.logger.getBindings();
444
+ const contractsDB = new PublicContractsDB(
445
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
446
+ bindings,
447
+ );
418
448
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
419
449
  const config = PublicSimulatorConfig.from({
420
450
  skipFeeEnforcement: true,
@@ -427,8 +457,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
427
457
  globals,
428
458
  guardedMerkleTrees,
429
459
  contractsDB,
430
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
460
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
431
461
  new TestDateProvider(),
462
+ undefined,
463
+ createLogger('simulator:public-processor', bindings),
432
464
  );
433
465
 
434
466
  const tx = await Tx.create({
@@ -525,7 +557,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
525
557
 
526
558
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
527
559
 
528
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore));
560
+ const bindings2 = this.logger.getBindings();
561
+ const contractsDB = new PublicContractsDB(
562
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
563
+ bindings2,
564
+ );
529
565
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
530
566
  const config = PublicSimulatorConfig.from({
531
567
  skipFeeEnforcement: true,
@@ -534,8 +570,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
534
570
  collectStatistics: false,
535
571
  collectCallMetadata: true,
536
572
  });
537
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
538
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
573
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
574
+ const processor = new PublicProcessor(
575
+ globals,
576
+ guardedMerkleTrees,
577
+ contractsDB,
578
+ simulator,
579
+ new TestDateProvider(),
580
+ undefined,
581
+ createLogger('simulator:public-processor', bindings2),
582
+ );
539
583
 
540
584
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
541
585
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -566,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
566
610
  constantData,
567
611
  /*gasUsed=*/ new Gas(0, 0),
568
612
  /*feePayer=*/ AztecAddress.zero(),
569
- /*includeByTimestamp=*/ 0n,
613
+ /*expirationTimestamp=*/ 0n,
570
614
  inputsForPublic,
571
615
  undefined,
572
616
  );
@@ -634,10 +678,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
634
678
  return returnValues ?? [];
635
679
  }
636
680
 
637
- async txeSimulateUtilityFunction(
681
+ async txeExecuteUtilityFunction(
638
682
  targetContractAddress: AztecAddress,
639
683
  functionSelector: FunctionSelector,
640
684
  args: Fr[],
685
+ jobId: string,
641
686
  ) {
642
687
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
643
688
  if (!artifact) {
@@ -645,25 +690,33 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
645
690
  }
646
691
 
647
692
  // Sync notes before executing utility function to discover notes from previous transactions
648
- await this.contractStore.syncPrivateState(targetContractAddress, functionSelector, async call => {
649
- await this.executeUtilityCall(call);
650
- });
651
-
652
- const call = new FunctionCall(
653
- artifact.name,
693
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
694
+ await this.stateMachine.contractSyncService.ensureContractSynced(
654
695
  targetContractAddress,
655
696
  functionSelector,
656
- FunctionType.UTILITY,
657
- false,
658
- false,
659
- args,
660
- [],
697
+ async (call, execScopes) => {
698
+ await this.executeUtilityCall(call, execScopes, jobId);
699
+ },
700
+ blockHeader,
701
+ jobId,
702
+ 'ALL_SCOPES',
661
703
  );
662
704
 
663
- return this.executeUtilityCall(call);
705
+ const call = FunctionCall.from({
706
+ name: artifact.name,
707
+ to: targetContractAddress,
708
+ selector: functionSelector,
709
+ type: FunctionType.UTILITY,
710
+ hideMsgSender: false,
711
+ isStatic: false,
712
+ args,
713
+ returnTypes: [],
714
+ });
715
+
716
+ return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
664
717
  }
665
718
 
666
- private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
719
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
667
720
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
668
721
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
669
722
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -676,23 +729,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
676
729
 
677
730
  try {
678
731
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
679
- const oracle = new UtilityExecutionOracle(
680
- call.to,
681
- [],
682
- [],
732
+ const oracle = new UtilityExecutionOracle({
733
+ contractAddress: call.to,
734
+ authWitnesses: [],
735
+ capsules: [],
683
736
  anchorBlockHeader,
684
- this.contractStore,
685
- this.noteStore,
686
- this.keyStore,
687
- this.addressStore,
688
- this.stateMachine.node,
689
- this.stateMachine.anchorBlockStore,
690
- this.recipientTaggingStore,
691
- this.senderAddressBookStore,
692
- this.capsuleStore,
693
- this.privateEventStore,
694
- this.jobId,
695
- );
737
+ contractStore: this.contractStore,
738
+ noteStore: this.noteStore,
739
+ keyStore: this.keyStore,
740
+ addressStore: this.addressStore,
741
+ aztecNode: this.stateMachine.node,
742
+ recipientTaggingStore: this.recipientTaggingStore,
743
+ senderAddressBookStore: this.senderAddressBookStore,
744
+ capsuleStore: this.capsuleStore,
745
+ privateEventStore: this.privateEventStore,
746
+ jobId,
747
+ scopes,
748
+ });
696
749
  const acirExecutionResult = await new WASMSimulator()
697
750
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
698
751
  .catch((err: Error) => {
@@ -708,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
708
761
  );
709
762
  });
710
763
 
711
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
764
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
712
765
  return witnessMapToFields(acirExecutionResult.returnWitness);
713
766
  } catch (err) {
714
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
767
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
715
768
  }
716
769
  }
717
770
 
@@ -10,8 +10,7 @@ import {
10
10
  } from '@aztec/pxe/simulator';
11
11
  import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
12
12
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { L2BlockHash } from '@aztec/stdlib/block';
14
- import { MerkleTreeId } from '@aztec/stdlib/trees';
13
+ import { BlockHash } from '@aztec/stdlib/block';
15
14
 
16
15
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
17
16
  import type { TXESessionStateHandler } from './txe_session.js';
@@ -31,7 +30,7 @@ import {
31
30
  toSingle,
32
31
  } from './util/encoding.js';
33
32
 
34
- const MAX_EVENT_LEN = 12; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_RESERVED_FIELDS
33
+ const MAX_EVENT_LEN = 10; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN
35
34
  const MAX_PRIVATE_EVENTS_PER_TXE_QUERY = 5;
36
35
 
37
36
  export class UnavailableOracleError extends Error {
@@ -286,6 +285,13 @@ export class RPCTranslator {
286
285
  const contractAddress = addressFromSingle(foreignContractAddress);
287
286
  const scope = addressFromSingle(foreignScope);
288
287
 
288
+ // TODO(F-335): Avoid doing the following 2 calls here.
289
+ {
290
+ await this.handlerAsTxe().syncContractNonOracleMethod(contractAddress, scope, this.stateHandler.getCurrentJob());
291
+ // We cycle job to commit the stores after the contract sync.
292
+ await this.stateHandler.cycleJob();
293
+ }
294
+
289
295
  const events = await this.handlerAsTxe().txeGetPrivateEvents(selector, contractAddress, scope);
290
296
 
291
297
  if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
@@ -329,7 +335,7 @@ export class RPCTranslator {
329
335
 
330
336
  // When the argument is a slice, noir automatically adds a length field to oracle call.
331
337
  // When the argument is an array, we add the field length manually to the signature.
332
- utilityDebugLog(
338
+ async utilityLog(
333
339
  foreignLevel: ForeignCallSingle,
334
340
  foreignMessage: ForeignCallArray,
335
341
  _foreignLength: ForeignCallSingle,
@@ -341,7 +347,7 @@ export class RPCTranslator {
341
347
  .join('');
342
348
  const fields = fromArray(foreignFields);
343
349
 
344
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
350
+ await this.handlerAsMisc().utilityLog(level, message, fields);
345
351
 
346
352
  return toForeignCallResult([]);
347
353
  }
@@ -352,7 +358,7 @@ export class RPCTranslator {
352
358
  foreignStartStorageSlot: ForeignCallSingle,
353
359
  foreignNumberOfElements: ForeignCallSingle,
354
360
  ) {
355
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
361
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
356
362
  const contractAddress = addressFromSingle(foreignContractAddress);
357
363
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
358
364
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
@@ -368,7 +374,7 @@ export class RPCTranslator {
368
374
  }
369
375
 
370
376
  async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
371
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
377
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
372
378
  const leafSlot = fromSingle(foreignLeafSlot);
373
379
 
374
380
  const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
@@ -513,6 +519,15 @@ export class RPCTranslator {
513
519
  return toForeignCallResult([]);
514
520
  }
515
521
 
522
+ async privateIsNullifierPending(foreignInnerNullifier: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
523
+ const innerNullifier = fromSingle(foreignInnerNullifier);
524
+ const contractAddress = addressFromSingle(foreignContractAddress);
525
+
526
+ const isPending = await this.handlerAsPrivate().privateIsNullifierPending(innerNullifier, contractAddress);
527
+
528
+ return toForeignCallResult([toSingle(new Fr(isPending))]);
529
+ }
530
+
516
531
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
517
532
  const innerNullifier = fromSingle(foreignInnerNullifier);
518
533
 
@@ -537,12 +552,23 @@ export class RPCTranslator {
537
552
  );
538
553
  }
539
554
 
540
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
555
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
541
556
  const address = addressFromSingle(foreignAddress);
542
557
 
543
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
558
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
544
559
 
545
- return toForeignCallResult([toArray([...publicKeys.toFields(), partialAddress])]);
560
+ // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
561
+ // with two fields: `some` (a boolean) and `value` (a field array in this case).
562
+ if (result === undefined) {
563
+ // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
564
+ return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
565
+ } else {
566
+ // Data was found so we set `some` to 1 and return it along with `value`.
567
+ return toForeignCallResult([
568
+ toSingle(new Fr(1)),
569
+ toArray([...result.publicKeys.toFields(), result.partialAddress]),
570
+ ]);
571
+ }
546
572
  }
547
573
 
548
574
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -566,7 +592,7 @@ export class RPCTranslator {
566
592
  }
567
593
 
568
594
  async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
569
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
595
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
570
596
  const nullifier = fromSingle(foreignNullifier);
571
597
 
572
598
  const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
@@ -633,30 +659,43 @@ export class RPCTranslator {
633
659
  return toForeignCallResult(header.toFields().map(toSingle));
634
660
  }
635
661
 
636
- async utilityGetMembershipWitness(
662
+ async utilityGetNoteHashMembershipWitness(
663
+ foreignAnchorBlockHash: ForeignCallSingle,
664
+ foreignNoteHash: ForeignCallSingle,
665
+ ) {
666
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
667
+ const noteHash = fromSingle(foreignNoteHash);
668
+
669
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
670
+
671
+ if (!witness) {
672
+ throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
673
+ }
674
+ return toForeignCallResult(witness.toNoirRepresentation());
675
+ }
676
+
677
+ async utilityGetBlockHashMembershipWitness(
678
+ foreignAnchorBlockHash: ForeignCallSingle,
637
679
  foreignBlockHash: ForeignCallSingle,
638
- foreignTreeId: ForeignCallSingle,
639
- foreignLeafValue: ForeignCallSingle,
640
680
  ) {
641
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
642
- const treeId = fromSingle(foreignTreeId).toNumber();
643
- const leafValue = fromSingle(foreignLeafValue);
681
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
682
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
644
683
 
645
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockHash, treeId, leafValue);
684
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
646
685
 
647
686
  if (!witness) {
648
687
  throw new Error(
649
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockHash}.`,
688
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
650
689
  );
651
690
  }
652
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
691
+ return toForeignCallResult(witness.toNoirRepresentation());
653
692
  }
654
693
 
655
694
  async utilityGetLowNullifierMembershipWitness(
656
695
  foreignBlockHash: ForeignCallSingle,
657
696
  foreignNullifier: ForeignCallSingle,
658
697
  ) {
659
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
698
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
660
699
  const nullifier = fromSingle(foreignNullifier);
661
700
 
662
701
  const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
@@ -675,7 +714,7 @@ export class RPCTranslator {
675
714
  return toForeignCallResult([]);
676
715
  }
677
716
 
678
- public async utilityValidateEnqueuedNotesAndEvents(
717
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
679
718
  foreignContractAddress: ForeignCallSingle,
680
719
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
681
720
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -684,7 +723,7 @@ export class RPCTranslator {
684
723
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
685
724
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
686
725
 
687
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
726
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
688
727
  contractAddress,
689
728
  noteValidationRequestsArrayBaseSlot,
690
729
  eventValidationRequestsArrayBaseSlot,
@@ -817,15 +856,16 @@ export class RPCTranslator {
817
856
 
818
857
  // AVM opcodes
819
858
 
820
- avmOpcodeEmitUnencryptedLog(_foreignMessage: ForeignCallArray) {
859
+ avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
821
860
  // TODO(#8811): Implement
822
861
  return toForeignCallResult([]);
823
862
  }
824
863
 
825
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
864
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
826
865
  const slot = fromSingle(foreignSlot);
866
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
827
867
 
828
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
868
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
829
869
 
830
870
  return toForeignCallResult([toSingle(new Fr(value))]);
831
871
  }
@@ -897,11 +937,10 @@ export class RPCTranslator {
897
937
  return toForeignCallResult([]);
898
938
  }
899
939
 
900
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
901
- const innerNullifier = fromSingle(foreignInnerNullifier);
902
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
940
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
941
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
903
942
 
904
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
943
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
905
944
 
906
945
  return toForeignCallResult([toSingle(new Fr(exists))]);
907
946
  }
@@ -1006,12 +1045,15 @@ export class RPCTranslator {
1006
1045
  args,
1007
1046
  argsHash,
1008
1047
  isStaticCall,
1048
+ this.stateHandler.getCurrentJob(),
1009
1049
  );
1010
1050
 
1051
+ // TODO(F-335): Avoid doing the following call here.
1052
+ await this.stateHandler.cycleJob();
1011
1053
  return toForeignCallResult([toArray(returnValues)]);
1012
1054
  }
1013
1055
 
1014
- async txeSimulateUtilityFunction(
1056
+ async txeExecuteUtilityFunction(
1015
1057
  foreignTargetContractAddress: ForeignCallSingle,
1016
1058
  foreignFunctionSelector: ForeignCallSingle,
1017
1059
  foreignArgs: ForeignCallArray,
@@ -1020,12 +1062,15 @@ export class RPCTranslator {
1020
1062
  const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
1021
1063
  const args = fromArray(foreignArgs);
1022
1064
 
1023
- const returnValues = await this.handlerAsTxe().txeSimulateUtilityFunction(
1065
+ const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
1024
1066
  targetContractAddress,
1025
1067
  functionSelector,
1026
1068
  args,
1069
+ this.stateHandler.getCurrentJob(),
1027
1070
  );
1028
1071
 
1072
+ // TODO(F-335): Avoid doing the following call here.
1073
+ await this.stateHandler.cycleJob();
1029
1074
  return toForeignCallResult([toArray(returnValues)]);
1030
1075
  }
1031
1076
 
@@ -1042,6 +1087,8 @@ export class RPCTranslator {
1042
1087
 
1043
1088
  const returnValues = await this.handlerAsTxe().txePublicCallNewFlow(from, address, calldata, isStaticCall);
1044
1089
 
1090
+ // TODO(F-335): Avoid doing the following call here.
1091
+ await this.stateHandler.cycleJob();
1045
1092
  return toForeignCallResult([toArray(returnValues)]);
1046
1093
  }
1047
1094