@aztec/txe 0.0.1-commit.e61ad554 → 0.0.1-commit.ec5f612

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 (52) 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 +5 -4
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +2 -2
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +3 -4
  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 +106 -35
  12. package/dest/rpc_translator.d.ts +9 -9
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +57 -34
  15. package/dest/state_machine/archiver.d.ts +1 -1
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +2 -0
  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 +5 -5
  22. package/dest/state_machine/index.d.ts.map +1 -1
  23. package/dest/state_machine/index.js +15 -10
  24. package/dest/state_machine/mock_epoch_cache.d.ts +3 -1
  25. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  26. package/dest/state_machine/mock_epoch_cache.js +4 -0
  27. package/dest/txe_session.d.ts +9 -6
  28. package/dest/txe_session.d.ts.map +1 -1
  29. package/dest/txe_session.js +80 -21
  30. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  31. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  32. package/dest/util/txe_public_contract_data_source.js +5 -22
  33. package/dest/utils/block_creation.d.ts +1 -1
  34. package/dest/utils/block_creation.d.ts.map +1 -1
  35. package/dest/utils/block_creation.js +3 -1
  36. package/package.json +15 -15
  37. package/src/index.ts +83 -49
  38. package/src/oracle/interfaces.ts +7 -2
  39. package/src/oracle/txe_oracle_public_context.ts +3 -5
  40. package/src/oracle/txe_oracle_top_level_context.ts +134 -82
  41. package/src/rpc_translator.ts +61 -28
  42. package/src/state_machine/archiver.ts +2 -0
  43. package/src/state_machine/dummy_p2p_client.ts +40 -22
  44. package/src/state_machine/index.ts +25 -9
  45. package/src/state_machine/mock_epoch_cache.ts +5 -0
  46. package/src/txe_session.ts +89 -81
  47. package/src/util/txe_public_contract_data_source.ts +10 -36
  48. package/src/utils/block_creation.ts +3 -1
  49. package/dest/util/txe_contract_store.d.ts +0 -12
  50. package/dest/util/txe_contract_store.d.ts.map +0 -1
  51. package/dest/util/txe_contract_store.js +0 -22
  52. 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,
@@ -22,7 +24,6 @@ import {
22
24
  SenderAddressBookStore,
23
25
  SenderTaggingStore,
24
26
  enrichPublicSimulationError,
25
- syncState,
26
27
  } from '@aztec/pxe/server';
27
28
  import {
28
29
  ExecutionNoteCache,
@@ -84,7 +85,6 @@ import { ForkCheckpoint } from '@aztec/world-state';
84
85
  import { DEFAULT_ADDRESS } from '../constants.js';
85
86
  import type { TXEStateMachine } from '../state_machine/index.js';
86
87
  import type { TXEAccountStore } from '../util/txe_account_store.js';
87
- import type { TXEContractStore } from '../util/txe_contract_store.js';
88
88
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
89
89
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
90
90
  import type { ITxeExecutionOracle } from './interfaces.js';
@@ -97,7 +97,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
97
97
 
98
98
  constructor(
99
99
  private stateMachine: TXEStateMachine,
100
- private contractStore: TXEContractStore,
100
+ private contractStore: ContractStore,
101
101
  private noteStore: NoteStore,
102
102
  private keyStore: KeyStore,
103
103
  private addressStore: AddressStore,
@@ -107,7 +107,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
107
107
  private senderAddressBookStore: SenderAddressBookStore,
108
108
  private capsuleStore: CapsuleStore,
109
109
  private privateEventStore: PrivateEventStore,
110
- private jobId: string,
111
110
  private nextBlockTimestamp: bigint,
112
111
  private version: Fr,
113
112
  private chainId: Fr,
@@ -132,13 +131,14 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
132
131
  }
133
132
 
134
133
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
135
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
134
+ utilityLog(level: number, message: string, fields: Fr[]): Promise<void> {
136
135
  if (!LogLevels[level]) {
137
- throw new Error(`Invalid debug log level: ${level}`);
136
+ throw new Error(`Invalid log level: ${level}`);
138
137
  }
139
138
  const levelName = LogLevels[level];
140
139
 
141
140
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
141
+ return Promise.resolve();
142
142
  }
143
143
 
144
144
  txeGetDefaultAddress(): AztecAddress {
@@ -171,6 +171,25 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
171
171
  return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
172
172
  }
173
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
+
174
193
  async txeGetPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
175
194
  return (
176
195
  await this.privateEventStore.getPrivateEvents(selector, {
@@ -210,7 +229,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
210
229
  await this.txeAddAccount(artifact, instance, secret);
211
230
  } else {
212
231
  await this.contractStore.addContractInstance(instance);
213
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
232
+ await this.contractStore.addContractArtifact(artifact);
214
233
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
215
234
  }
216
235
  }
@@ -220,7 +239,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
220
239
 
221
240
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
222
241
  await this.contractStore.addContractInstance(instance);
223
- await this.contractStore.addContractArtifact(instance.currentContractClassId, artifact);
242
+ await this.contractStore.addContractArtifact(artifact);
224
243
 
225
244
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
226
245
  await this.accountStore.setAccount(completeAddress.address, completeAddress);
@@ -284,6 +303,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
284
303
  args: Fr[],
285
304
  argsHash: Fr = Fr.zero(),
286
305
  isStaticCall: boolean = false,
306
+ jobId: string,
287
307
  ) {
288
308
  this.logger.verbose(
289
309
  `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
@@ -297,12 +317,24 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
297
317
  throw new Error(message);
298
318
  }
299
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
+
300
324
  // Sync notes before executing private function to discover notes from previous transactions
301
- const utilityExecutor = async (call: FunctionCall) => {
302
- await this.executeUtilityCall(call);
325
+ const utilityExecutor = async (call: FunctionCall, execScopes: AccessScopes) => {
326
+ await this.executeUtilityCall(call, execScopes, jobId);
303
327
  };
304
328
 
305
- await syncState(targetContractAddress, this.contractStore, 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
+ );
306
338
 
307
339
  const blockNumber = await this.txeGetNextBlockNumber();
308
340
 
@@ -314,8 +346,6 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
314
346
 
315
347
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
316
348
 
317
- const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
318
-
319
349
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
320
350
  const noteCache = new ExecutionNoteCache(protocolNullifier);
321
351
  // In production, the account contract sets the min revertible counter before calling the app function.
@@ -327,43 +357,37 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
327
357
 
328
358
  const simulator = new WASMSimulator();
329
359
 
330
- const privateExecutionOracle = new PrivateExecutionOracle(
360
+ const privateExecutionOracle = new PrivateExecutionOracle({
331
361
  argsHash,
332
362
  txContext,
333
363
  callContext,
334
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
335
- blockHeader,
364
+ anchorBlockHeader: blockHeader,
336
365
  utilityExecutor,
337
- /** List of transient auth witnesses to be used during this simulation */
338
- Array.from(this.authwits.values()),
339
- /** List of transient auth witnesses to be used during this simulation */
340
- [],
341
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
366
+ authWitnesses: Array.from(this.authwits.values()),
367
+ capsules: [],
368
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
342
369
  noteCache,
343
370
  taggingIndexCache,
344
- this.contractStore,
345
- this.noteStore,
346
- this.keyStore,
347
- this.addressStore,
348
- this.stateMachine.node,
349
- this.stateMachine.anchorBlockStore,
350
- this.senderTaggingStore,
351
- this.recipientTaggingStore,
352
- this.senderAddressBookStore,
353
- this.capsuleStore,
354
- this.privateEventStore,
355
- this.jobId,
356
- 0, // totalPublicArgsCount
357
- minRevertibleSideEffectCounter, // (start) sideEffectCounter
358
- undefined, // log
359
- undefined, // scopes
360
- /**
361
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
362
- * contract would perform, including setting senderForTags.
363
- */
364
- 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,
365
389
  simulator,
366
- );
390
+ });
367
391
 
368
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.
369
393
  let result: PrivateExecutionResult;
@@ -402,7 +426,8 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
402
426
  // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
403
427
  const { publicInputs } = await generateSimulatedProvingResult(
404
428
  result,
405
- this.contractStore,
429
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
430
+ this.stateMachine.node,
406
431
  minRevertibleSideEffectCounter,
407
432
  );
408
433
 
@@ -415,7 +440,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
415
440
 
416
441
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
417
442
 
418
- 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
+ );
419
448
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
420
449
  const config = PublicSimulatorConfig.from({
421
450
  skipFeeEnforcement: true,
@@ -428,8 +457,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
428
457
  globals,
429
458
  guardedMerkleTrees,
430
459
  contractsDB,
431
- new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config),
460
+ new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
432
461
  new TestDateProvider(),
462
+ undefined,
463
+ createLogger('simulator:public-processor', bindings),
433
464
  );
434
465
 
435
466
  const tx = await Tx.create({
@@ -526,7 +557,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
526
557
 
527
558
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
528
559
 
529
- 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
+ );
530
565
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
531
566
  const config = PublicSimulatorConfig.from({
532
567
  skipFeeEnforcement: true,
@@ -535,8 +570,16 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
535
570
  collectStatistics: false,
536
571
  collectCallMetadata: true,
537
572
  });
538
- const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
539
- 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
+ );
540
583
 
541
584
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
542
585
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
@@ -567,7 +610,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
567
610
  constantData,
568
611
  /*gasUsed=*/ new Gas(0, 0),
569
612
  /*feePayer=*/ AztecAddress.zero(),
570
- /*includeByTimestamp=*/ 0n,
613
+ /*expirationTimestamp=*/ 0n,
571
614
  inputsForPublic,
572
615
  undefined,
573
616
  );
@@ -635,10 +678,11 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
635
678
  return returnValues ?? [];
636
679
  }
637
680
 
638
- async txeSimulateUtilityFunction(
681
+ async txeExecuteUtilityFunction(
639
682
  targetContractAddress: AztecAddress,
640
683
  functionSelector: FunctionSelector,
641
684
  args: Fr[],
685
+ jobId: string,
642
686
  ) {
643
687
  const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
644
688
  if (!artifact) {
@@ -646,25 +690,33 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
646
690
  }
647
691
 
648
692
  // Sync notes before executing utility function to discover notes from previous transactions
649
- await syncState(targetContractAddress, this.contractStore, functionSelector, async call => {
650
- await this.executeUtilityCall(call);
651
- });
652
-
653
- const call = new FunctionCall(
654
- artifact.name,
693
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
694
+ await this.stateMachine.contractSyncService.ensureContractSynced(
655
695
  targetContractAddress,
656
696
  functionSelector,
657
- FunctionType.UTILITY,
658
- false,
659
- false,
660
- args,
661
- [],
697
+ async (call, execScopes) => {
698
+ await this.executeUtilityCall(call, execScopes, jobId);
699
+ },
700
+ blockHeader,
701
+ jobId,
702
+ 'ALL_SCOPES',
662
703
  );
663
704
 
664
- 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);
665
717
  }
666
718
 
667
- private async executeUtilityCall(call: FunctionCall): Promise<Fr[]> {
719
+ private async executeUtilityCall(call: FunctionCall, scopes: AccessScopes, jobId: string): Promise<Fr[]> {
668
720
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
669
721
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
670
722
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
@@ -677,23 +729,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
677
729
 
678
730
  try {
679
731
  const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
680
- const oracle = new UtilityExecutionOracle(
681
- call.to,
682
- [],
683
- [],
732
+ const oracle = new UtilityExecutionOracle({
733
+ contractAddress: call.to,
734
+ authWitnesses: [],
735
+ capsules: [],
684
736
  anchorBlockHeader,
685
- this.contractStore,
686
- this.noteStore,
687
- this.keyStore,
688
- this.addressStore,
689
- this.stateMachine.node,
690
- this.stateMachine.anchorBlockStore,
691
- this.recipientTaggingStore,
692
- this.senderAddressBookStore,
693
- this.capsuleStore,
694
- this.privateEventStore,
695
- this.jobId,
696
- );
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
+ });
697
749
  const acirExecutionResult = await new WASMSimulator()
698
750
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
699
751
  .catch((err: Error) => {
@@ -709,10 +761,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
709
761
  );
710
762
  });
711
763
 
712
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
764
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
713
765
  return witnessMapToFields(acirExecutionResult.returnWitness);
714
766
  } catch (err) {
715
- 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'));
716
768
  }
717
769
  }
718
770
 
@@ -10,7 +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';
13
+ import { BlockHash } from '@aztec/stdlib/block';
14
14
 
15
15
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
16
16
  import type { TXESessionStateHandler } from './txe_session.js';
@@ -30,7 +30,7 @@ import {
30
30
  toSingle,
31
31
  } from './util/encoding.js';
32
32
 
33
- 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
34
34
  const MAX_PRIVATE_EVENTS_PER_TXE_QUERY = 5;
35
35
 
36
36
  export class UnavailableOracleError extends Error {
@@ -285,6 +285,13 @@ export class RPCTranslator {
285
285
  const contractAddress = addressFromSingle(foreignContractAddress);
286
286
  const scope = addressFromSingle(foreignScope);
287
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
+
288
295
  const events = await this.handlerAsTxe().txeGetPrivateEvents(selector, contractAddress, scope);
289
296
 
290
297
  if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
@@ -328,7 +335,7 @@ export class RPCTranslator {
328
335
 
329
336
  // When the argument is a slice, noir automatically adds a length field to oracle call.
330
337
  // When the argument is an array, we add the field length manually to the signature.
331
- utilityDebugLog(
338
+ async utilityLog(
332
339
  foreignLevel: ForeignCallSingle,
333
340
  foreignMessage: ForeignCallArray,
334
341
  _foreignLength: ForeignCallSingle,
@@ -340,7 +347,7 @@ export class RPCTranslator {
340
347
  .join('');
341
348
  const fields = fromArray(foreignFields);
342
349
 
343
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
350
+ await this.handlerAsMisc().utilityLog(level, message, fields);
344
351
 
345
352
  return toForeignCallResult([]);
346
353
  }
@@ -351,7 +358,7 @@ export class RPCTranslator {
351
358
  foreignStartStorageSlot: ForeignCallSingle,
352
359
  foreignNumberOfElements: ForeignCallSingle,
353
360
  ) {
354
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
361
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
355
362
  const contractAddress = addressFromSingle(foreignContractAddress);
356
363
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
357
364
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
@@ -367,7 +374,7 @@ export class RPCTranslator {
367
374
  }
368
375
 
369
376
  async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
370
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
377
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
371
378
  const leafSlot = fromSingle(foreignLeafSlot);
372
379
 
373
380
  const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
@@ -545,12 +552,23 @@ export class RPCTranslator {
545
552
  );
546
553
  }
547
554
 
548
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
555
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
549
556
  const address = addressFromSingle(foreignAddress);
550
557
 
551
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
558
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
552
559
 
553
- 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
+ }
554
572
  }
555
573
 
556
574
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -574,7 +592,7 @@ export class RPCTranslator {
574
592
  }
575
593
 
576
594
  async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
577
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
595
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
578
596
  const nullifier = fromSingle(foreignNullifier);
579
597
 
580
598
  const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
@@ -641,26 +659,34 @@ export class RPCTranslator {
641
659
  return toForeignCallResult(header.toFields().map(toSingle));
642
660
  }
643
661
 
644
- async utilityGetNoteHashMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
645
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
646
- const leafValue = fromSingle(foreignLeafValue);
662
+ async utilityGetNoteHashMembershipWitness(
663
+ foreignAnchorBlockHash: ForeignCallSingle,
664
+ foreignNoteHash: ForeignCallSingle,
665
+ ) {
666
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
667
+ const noteHash = fromSingle(foreignNoteHash);
647
668
 
648
- const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, leafValue);
669
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
649
670
 
650
671
  if (!witness) {
651
- throw new Error(`Note hash ${leafValue} not found in the note hash tree at block ${blockHash.toString()}.`);
672
+ throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
652
673
  }
653
674
  return toForeignCallResult(witness.toNoirRepresentation());
654
675
  }
655
676
 
656
- async utilityGetArchiveMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
657
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
658
- const leafValue = fromSingle(foreignLeafValue);
677
+ async utilityGetBlockHashMembershipWitness(
678
+ foreignAnchorBlockHash: ForeignCallSingle,
679
+ foreignBlockHash: ForeignCallSingle,
680
+ ) {
681
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
682
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
659
683
 
660
- const witness = await this.handlerAsUtility().utilityGetArchiveMembershipWitness(blockHash, leafValue);
684
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
661
685
 
662
686
  if (!witness) {
663
- throw new Error(`Block hash ${leafValue} not found in the archive tree at block ${blockHash.toString()}.`);
687
+ throw new Error(
688
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
689
+ );
664
690
  }
665
691
  return toForeignCallResult(witness.toNoirRepresentation());
666
692
  }
@@ -669,7 +695,7 @@ export class RPCTranslator {
669
695
  foreignBlockHash: ForeignCallSingle,
670
696
  foreignNullifier: ForeignCallSingle,
671
697
  ) {
672
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
698
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
673
699
  const nullifier = fromSingle(foreignNullifier);
674
700
 
675
701
  const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
@@ -830,7 +856,7 @@ export class RPCTranslator {
830
856
 
831
857
  // AVM opcodes
832
858
 
833
- avmOpcodeEmitUnencryptedLog(_foreignMessage: ForeignCallArray) {
859
+ avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
834
860
  // TODO(#8811): Implement
835
861
  return toForeignCallResult([]);
836
862
  }
@@ -911,11 +937,10 @@ export class RPCTranslator {
911
937
  return toForeignCallResult([]);
912
938
  }
913
939
 
914
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
915
- const innerNullifier = fromSingle(foreignInnerNullifier);
916
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
940
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
941
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
917
942
 
918
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
943
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
919
944
 
920
945
  return toForeignCallResult([toSingle(new Fr(exists))]);
921
946
  }
@@ -1020,12 +1045,15 @@ export class RPCTranslator {
1020
1045
  args,
1021
1046
  argsHash,
1022
1047
  isStaticCall,
1048
+ this.stateHandler.getCurrentJob(),
1023
1049
  );
1024
1050
 
1051
+ // TODO(F-335): Avoid doing the following call here.
1052
+ await this.stateHandler.cycleJob();
1025
1053
  return toForeignCallResult([toArray(returnValues)]);
1026
1054
  }
1027
1055
 
1028
- async txeSimulateUtilityFunction(
1056
+ async txeExecuteUtilityFunction(
1029
1057
  foreignTargetContractAddress: ForeignCallSingle,
1030
1058
  foreignFunctionSelector: ForeignCallSingle,
1031
1059
  foreignArgs: ForeignCallArray,
@@ -1034,12 +1062,15 @@ export class RPCTranslator {
1034
1062
  const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
1035
1063
  const args = fromArray(foreignArgs);
1036
1064
 
1037
- const returnValues = await this.handlerAsTxe().txeSimulateUtilityFunction(
1065
+ const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
1038
1066
  targetContractAddress,
1039
1067
  functionSelector,
1040
1068
  args,
1069
+ this.stateHandler.getCurrentJob(),
1041
1070
  );
1042
1071
 
1072
+ // TODO(F-335): Avoid doing the following call here.
1073
+ await this.stateHandler.cycleJob();
1043
1074
  return toForeignCallResult([toArray(returnValues)]);
1044
1075
  }
1045
1076
 
@@ -1056,6 +1087,8 @@ export class RPCTranslator {
1056
1087
 
1057
1088
  const returnValues = await this.handlerAsTxe().txePublicCallNewFlow(from, address, calldata, isStaticCall);
1058
1089
 
1090
+ // TODO(F-335): Avoid doing the following call here.
1091
+ await this.stateHandler.cycleJob();
1059
1092
  return toForeignCallResult([toArray(returnValues)]);
1060
1093
  }
1061
1094
 
@@ -59,6 +59,8 @@ export class TXEArchiver extends ArchiverDataSourceBase {
59
59
  if (!checkpointedBlock) {
60
60
  throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
61
61
  }
62
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
63
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
62
64
  const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
63
65
  if (checkpoint.length === 0) {
64
66
  throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);