@aztec/txe 0.0.1-commit.04852196a → 0.0.1-commit.04d373f

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 (126) hide show
  1. package/dest/ContractClassRegistry-KKNT527R.js +3 -0
  2. package/dest/ContractClassRegistry-KKNT527R.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-GSKBNL3Q.js +3 -0
  4. package/dest/ContractInstanceRegistry-GSKBNL3Q.js.map +7 -0
  5. package/dest/FeeJuice-GUJ5O6GB.js +3 -0
  6. package/dest/FeeJuice-GUJ5O6GB.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-ZQPCKVKL.js +3 -0
  8. package/dest/MultiCallEntrypoint-ZQPCKVKL.js.map +7 -0
  9. package/dest/SchnorrAccount-QIXE5DXA.js +3 -0
  10. package/dest/SchnorrAccount-QIXE5DXA.js.map +7 -0
  11. package/dest/bin/check_txe_oracle_version.d.ts +2 -0
  12. package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
  13. package/dest/bin/check_txe_oracle_version.js +32 -0
  14. package/dest/bin/index.js +3 -30
  15. package/dest/bin/index.js.map +7 -0
  16. package/dest/chunk-BJVAAXNA.js +3 -0
  17. package/dest/chunk-BJVAAXNA.js.map +7 -0
  18. package/dest/chunk-DF6RMOC6.js +304 -0
  19. package/dest/chunk-DF6RMOC6.js.map +7 -0
  20. package/dest/chunk-PPJTNNUG.js +265 -0
  21. package/dest/chunk-PPJTNNUG.js.map +7 -0
  22. package/dest/constants.d.ts +3 -1
  23. package/dest/constants.d.ts.map +1 -1
  24. package/dest/constants.js +5 -0
  25. package/dest/dispatcher_pool.d.ts +67 -0
  26. package/dest/dispatcher_pool.d.ts.map +1 -0
  27. package/dest/dispatcher_pool.js +284 -0
  28. package/dest/index.d.ts +188 -7
  29. package/dest/index.d.ts.map +1 -1
  30. package/dest/index.js +155 -116
  31. package/dest/metafile.json +38147 -0
  32. package/dest/msgpackr_fr_extension.d.ts +2 -0
  33. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  34. package/dest/msgpackr_fr_extension.js +21 -0
  35. package/dest/oracle/interfaces.d.ts +15 -4
  36. package/dest/oracle/interfaces.d.ts.map +1 -1
  37. package/dest/oracle/txe_oracle_public_context.d.ts +6 -1
  38. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  39. package/dest/oracle/txe_oracle_public_context.js +15 -0
  40. package/dest/oracle/txe_oracle_top_level_context.d.ts +22 -6
  41. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  42. package/dest/oracle/txe_oracle_top_level_context.js +106 -47
  43. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  44. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  45. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  46. package/dest/rpc_server.d.ts +14 -0
  47. package/dest/rpc_server.d.ts.map +1 -0
  48. package/dest/rpc_server.js +78 -0
  49. package/dest/rpc_translator.d.ts +90 -34
  50. package/dest/rpc_translator.d.ts.map +1 -1
  51. package/dest/rpc_translator.js +396 -153
  52. package/dest/server.bundle.js +3 -0
  53. package/dest/server.bundle.js.map +7 -0
  54. package/dest/state_machine/archiver.d.ts +4 -4
  55. package/dest/state_machine/archiver.d.ts.map +1 -1
  56. package/dest/state_machine/archiver.js +22 -20
  57. package/dest/state_machine/dummy_p2p_client.d.ts +13 -7
  58. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  59. package/dest/state_machine/dummy_p2p_client.js +16 -4
  60. package/dest/state_machine/global_variable_builder.d.ts +9 -4
  61. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  62. package/dest/state_machine/global_variable_builder.js +9 -3
  63. package/dest/state_machine/index.d.ts +7 -3
  64. package/dest/state_machine/index.d.ts.map +1 -1
  65. package/dest/state_machine/index.js +23 -5
  66. package/dest/state_machine/mock_epoch_cache.d.ts +18 -3
  67. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  68. package/dest/state_machine/mock_epoch_cache.js +35 -2
  69. package/dest/state_machine/synchronizer.d.ts +5 -5
  70. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  71. package/dest/state_machine/synchronizer.js +4 -4
  72. package/dest/txe_oracle_version.d.ts +17 -0
  73. package/dest/txe_oracle_version.d.ts.map +1 -0
  74. package/dest/txe_oracle_version.js +14 -0
  75. package/dest/txe_session.d.ts +64 -6
  76. package/dest/txe_session.d.ts.map +1 -1
  77. package/dest/txe_session.js +157 -29
  78. package/dest/utils/encoding.d.ts +191 -0
  79. package/dest/utils/encoding.d.ts.map +1 -0
  80. package/dest/{util → utils}/encoding.js +7 -2
  81. package/dest/{util → utils}/expected_failure_error.d.ts +1 -1
  82. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  83. package/dest/{util → utils}/txe_account_store.d.ts +1 -1
  84. package/dest/utils/txe_account_store.d.ts.map +1 -0
  85. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  86. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  87. package/dest/{util → utils}/txe_public_contract_data_source.js +1 -3
  88. package/dest/worker.bundle.js +3 -0
  89. package/dest/worker.bundle.js.map +7 -0
  90. package/dest/worker.d.ts +2 -0
  91. package/dest/worker.d.ts.map +1 -0
  92. package/dest/worker.js +92 -0
  93. package/package.json +37 -21
  94. package/src/bin/check_txe_oracle_version.ts +37 -0
  95. package/src/bin/index.ts +11 -2
  96. package/src/constants.ts +6 -0
  97. package/src/dispatcher_pool.ts +316 -0
  98. package/src/index.ts +172 -123
  99. package/src/msgpackr_fr_extension.ts +23 -0
  100. package/src/oracle/interfaces.ts +16 -3
  101. package/src/oracle/txe_oracle_public_context.ts +30 -0
  102. package/src/oracle/txe_oracle_top_level_context.ts +124 -55
  103. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  104. package/src/rpc_server.ts +87 -0
  105. package/src/rpc_translator.ts +459 -222
  106. package/src/state_machine/archiver.ts +33 -18
  107. package/src/state_machine/dummy_p2p_client.ts +31 -11
  108. package/src/state_machine/global_variable_builder.ts +18 -3
  109. package/src/state_machine/index.ts +25 -6
  110. package/src/state_machine/mock_epoch_cache.ts +46 -3
  111. package/src/state_machine/synchronizer.ts +5 -5
  112. package/src/txe_oracle_version.ts +17 -0
  113. package/src/txe_session.ts +251 -31
  114. package/src/{util → utils}/encoding.ts +8 -2
  115. package/src/{util → utils}/txe_public_contract_data_source.ts +0 -2
  116. package/src/worker.ts +98 -0
  117. package/dest/util/encoding.d.ts +0 -720
  118. package/dest/util/encoding.d.ts.map +0 -1
  119. package/dest/util/expected_failure_error.d.ts.map +0 -1
  120. package/dest/util/txe_account_store.d.ts.map +0 -1
  121. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  122. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  123. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  124. /package/dest/{util → utils}/txe_account_store.js +0 -0
  125. /package/src/{util → utils}/expected_failure_error.ts +0 -0
  126. /package/src/{util → utils}/txe_account_store.ts +0 -0
@@ -1,17 +1,27 @@
1
1
  import type { ContractInstanceWithAddress } from '@aztec/aztec.js/contracts';
2
- import { Fr, Point } from '@aztec/aztec.js/fields';
3
- import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX } from '@aztec/constants';
2
+ import { Fr } from '@aztec/aztec.js/fields';
3
+ import {
4
+ ARCHIVE_HEIGHT,
5
+ MAX_NOTE_HASHES_PER_TX,
6
+ MAX_NULLIFIERS_PER_TX,
7
+ MAX_PRIVATE_LOGS_PER_TX,
8
+ PRIVATE_LOG_SIZE_IN_FIELDS,
9
+ } from '@aztec/constants';
4
10
  import { BlockNumber } from '@aztec/foundation/branded-types';
11
+ import { MembershipWitness } from '@aztec/foundation/trees';
5
12
  import {
13
+ BoundedVec,
6
14
  type IMiscOracle,
7
15
  type IPrivateExecutionOracle,
8
16
  type IUtilityExecutionOracle,
17
+ Option,
9
18
  packAsHintedNote,
10
19
  } from '@aztec/pxe/simulator';
11
20
  import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
12
21
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { BlockHash } from '@aztec/stdlib/block';
22
+ import { GasSettings } from '@aztec/stdlib/gas';
14
23
 
24
+ import { MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY, MAX_OFFCHAIN_EFFECT_LEN } from './constants.js';
15
25
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
16
26
  import type { TXESessionStateHandler } from './txe_session.js';
17
27
  import {
@@ -20,6 +30,7 @@ import {
20
30
  addressFromSingle,
21
31
  arrayOfArraysToBoundedVecOfArrays,
22
32
  arrayToBoundedVec,
33
+ blockHashFromSingle,
23
34
  bufferToU8Array,
24
35
  fromArray,
25
36
  fromSingle,
@@ -28,7 +39,7 @@ import {
28
39
  toArray,
29
40
  toForeignCallResult,
30
41
  toSingle,
31
- } from './util/encoding.js';
42
+ } from './utils/encoding.js';
32
43
 
33
44
  const MAX_EVENT_LEN = 10; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN
34
45
  const MAX_PRIVATE_EVENTS_PER_TXE_QUERY = 5;
@@ -102,6 +113,16 @@ export class RPCTranslator {
102
113
  return this.oracleHandler;
103
114
  }
104
115
 
116
+ // eslint-disable-next-line camelcase
117
+ aztec_txe_assertCompatibleOracleVersion(foreignMajor: ForeignCallSingle, foreignMinor: ForeignCallSingle) {
118
+ const major = fromSingle(foreignMajor).toNumber();
119
+ const minor = fromSingle(foreignMinor).toNumber();
120
+
121
+ this.stateHandler.setTxeOracleVersion(major, minor);
122
+
123
+ return toForeignCallResult([]);
124
+ }
125
+
105
126
  // TXE session state transition functions - these get handled by the state handler
106
127
 
107
128
  // eslint-disable-next-line camelcase
@@ -117,6 +138,7 @@ export class RPCTranslator {
117
138
  foreignContractAddressValue: ForeignCallSingle,
118
139
  foreignAnchorBlockNumberIsSome: ForeignCallSingle,
119
140
  foreignAnchorBlockNumberValue: ForeignCallSingle,
141
+ foreignGasSettings: ForeignCallArray,
120
142
  ) {
121
143
  const contractAddress = fromSingle(foreignContractAddressIsSome).toBool()
122
144
  ? AztecAddress.fromField(fromSingle(foreignContractAddressValue))
@@ -126,7 +148,13 @@ export class RPCTranslator {
126
148
  ? BlockNumber(fromSingle(foreignAnchorBlockNumberValue).toNumber())
127
149
  : undefined;
128
150
 
129
- const privateContextInputs = await this.stateHandler.enterPrivateState(contractAddress, anchorBlockNumber);
151
+ const gasSettings = GasSettings.fromFields(fromArray(foreignGasSettings));
152
+
153
+ const privateContextInputs = await this.stateHandler.enterPrivateState(
154
+ contractAddress,
155
+ anchorBlockNumber,
156
+ gasSettings,
157
+ );
130
158
 
131
159
  return toForeignCallResult(privateContextInputs.toFields().map(toSingle));
132
160
  }
@@ -218,6 +246,7 @@ export class RPCTranslator {
218
246
  instance.deployer.toField(),
219
247
  instance.currentContractClassId,
220
248
  instance.initializationHash,
249
+ instance.immutablesHash,
221
250
  ...instance.publicKeys.toFields(),
222
251
  ]),
223
252
  ]);
@@ -264,10 +293,11 @@ export class RPCTranslator {
264
293
  // PXE oracles
265
294
 
266
295
  // eslint-disable-next-line camelcase
267
- aztec_utl_assertCompatibleOracleVersion(foreignVersion: ForeignCallSingle) {
268
- const version = fromSingle(foreignVersion).toNumber();
296
+ aztec_utl_assertCompatibleOracleVersion(foreignMajor: ForeignCallSingle, foreignMinor: ForeignCallSingle) {
297
+ const major = fromSingle(foreignMajor).toNumber();
298
+ const minor = fromSingle(foreignMinor).toNumber();
269
299
 
270
- this.handlerAsMisc().assertCompatibleOracleVersion(version);
300
+ this.handlerAsMisc().assertCompatibleOracleVersion(major, minor);
271
301
 
272
302
  return toForeignCallResult([]);
273
303
  }
@@ -288,15 +318,64 @@ export class RPCTranslator {
288
318
 
289
319
  // eslint-disable-next-line camelcase
290
320
  async aztec_txe_getLastTxEffects() {
291
- const { txHash, noteHashes, nullifiers } = await this.handlerAsTxe().getLastTxEffects();
321
+ const { txHash, noteHashes, nullifiers, privateLogs } = await this.handlerAsTxe().getLastTxEffects();
322
+
323
+ // Same workaround as `aztec_txe_getPrivateEvents`: Noir cannot yet return nested structs with arrays, so we return
324
+ // a flat multidimensional array plus per-log lengths and the total count, and reassemble into a
325
+ // `BoundedVec<BoundedVec<T>>` on the Noir side. Each log contributes only its emitted fields. The rest
326
+ // is zero-padded to `PRIVATE_LOG_SIZE_IN_FIELDS`.
327
+ const emittedLogs = privateLogs.map(log => log.getEmittedFields());
328
+
329
+ const rawLogStorage = emittedLogs
330
+ .map(fields => fields.concat(Array(PRIVATE_LOG_SIZE_IN_FIELDS - fields.length).fill(new Fr(0))))
331
+ .concat(
332
+ Array(MAX_PRIVATE_LOGS_PER_TX - emittedLogs.length).fill(Array(PRIVATE_LOG_SIZE_IN_FIELDS).fill(new Fr(0))),
333
+ )
334
+ .flat();
335
+
336
+ const logLengths = emittedLogs
337
+ .map(fields => new Fr(fields.length))
338
+ .concat(Array(MAX_PRIVATE_LOGS_PER_TX - emittedLogs.length).fill(new Fr(0)));
339
+
340
+ const logCount = new Fr(emittedLogs.length);
292
341
 
293
342
  return toForeignCallResult([
294
343
  toSingle(txHash.hash),
295
344
  ...arrayToBoundedVec(toArray(noteHashes), MAX_NOTE_HASHES_PER_TX),
296
345
  ...arrayToBoundedVec(toArray(nullifiers), MAX_NULLIFIERS_PER_TX),
346
+ toArray(rawLogStorage),
347
+ toArray(logLengths),
348
+ toSingle(logCount),
297
349
  ]);
298
350
  }
299
351
 
352
+ // eslint-disable-next-line camelcase
353
+ aztec_txe_getLastCallOffchainEffects() {
354
+ const { effects } = this.stateHandler.getLastCallOffchainEffects();
355
+
356
+ const rawArrayStorage = effects
357
+ .map(e => e.concat(Array(MAX_OFFCHAIN_EFFECT_LEN - e.length).fill(new Fr(0))))
358
+ .concat(
359
+ Array(MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY - effects.length).fill(Array(MAX_OFFCHAIN_EFFECT_LEN).fill(new Fr(0))),
360
+ )
361
+ .flat();
362
+
363
+ const effectLengths = effects
364
+ .map(e => new Fr(e.length))
365
+ .concat(Array(MAX_OFFCHAIN_EFFECTS_PER_TXE_QUERY - effects.length).fill(new Fr(0)));
366
+
367
+ const count = new Fr(effects.length);
368
+
369
+ return toForeignCallResult([toArray(rawArrayStorage), toArray(effectLengths), toSingle(count)]);
370
+ }
371
+
372
+ // eslint-disable-next-line camelcase
373
+ aztec_txe_getLastCallContext() {
374
+ const { txHash, anchorBlockTimestamp } = this.stateHandler.getLastCallContext();
375
+ const isSome = txHash.isZero() ? 0 : 1;
376
+ return toForeignCallResult([toSingle(isSome), toSingle(txHash), toSingle(new Fr(anchorBlockTimestamp))]);
377
+ }
378
+
300
379
  // eslint-disable-next-line camelcase
301
380
  async aztec_txe_getPrivateEvents(
302
381
  foreignSelector: ForeignCallSingle,
@@ -339,20 +418,20 @@ export class RPCTranslator {
339
418
  }
340
419
 
341
420
  // eslint-disable-next-line camelcase
342
- aztec_prv_storeInExecutionCache(foreignValues: ForeignCallArray, foreignHash: ForeignCallSingle) {
421
+ aztec_prv_setHashPreimage(foreignValues: ForeignCallArray, foreignHash: ForeignCallSingle) {
343
422
  const values = fromArray(foreignValues);
344
423
  const hash = fromSingle(foreignHash);
345
424
 
346
- this.handlerAsPrivate().storeInExecutionCache(values, hash);
425
+ this.handlerAsPrivate().setHashPreimage(values, hash);
347
426
 
348
427
  return toForeignCallResult([]);
349
428
  }
350
429
 
351
430
  // eslint-disable-next-line camelcase
352
- async aztec_prv_loadFromExecutionCache(foreignHash: ForeignCallSingle) {
431
+ async aztec_prv_getHashPreimage(foreignHash: ForeignCallSingle) {
353
432
  const hash = fromSingle(foreignHash);
354
433
 
355
- const returns = await this.handlerAsPrivate().loadFromExecutionCache(hash);
434
+ const returns = await this.handlerAsPrivate().getHashPreimage(hash);
356
435
 
357
436
  return toForeignCallResult([toArray(returns)]);
358
437
  }
@@ -378,18 +457,18 @@ export class RPCTranslator {
378
457
  }
379
458
 
380
459
  // eslint-disable-next-line camelcase
381
- async aztec_utl_storageRead(
460
+ async aztec_utl_getFromPublicStorage(
382
461
  foreignBlockHash: ForeignCallSingle,
383
462
  foreignContractAddress: ForeignCallSingle,
384
463
  foreignStartStorageSlot: ForeignCallSingle,
385
464
  foreignNumberOfElements: ForeignCallSingle,
386
465
  ) {
387
- const blockHash = new BlockHash(fromSingle(foreignBlockHash));
466
+ const blockHash = blockHashFromSingle(foreignBlockHash);
388
467
  const contractAddress = addressFromSingle(foreignContractAddress);
389
468
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
390
469
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
391
470
 
392
- const values = await this.handlerAsUtility().storageRead(
471
+ const values = await this.handlerAsUtility().getFromPublicStorage(
393
472
  blockHash,
394
473
  contractAddress,
395
474
  startStorageSlot,
@@ -401,14 +480,10 @@ export class RPCTranslator {
401
480
 
402
481
  // eslint-disable-next-line camelcase
403
482
  async aztec_utl_getPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
404
- const blockHash = new BlockHash(fromSingle(foreignBlockHash));
483
+ const blockHash = blockHashFromSingle(foreignBlockHash);
405
484
  const leafSlot = fromSingle(foreignLeafSlot);
406
485
 
407
486
  const witness = await this.handlerAsUtility().getPublicDataWitness(blockHash, leafSlot);
408
-
409
- if (!witness) {
410
- throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockHash.toString()}.`);
411
- }
412
487
  return toForeignCallResult(witness.toNoirRepresentation());
413
488
  }
414
489
 
@@ -435,8 +510,8 @@ export class RPCTranslator {
435
510
  ) {
436
511
  // Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
437
512
  const owner = fromSingle(foreignOwnerIsSome).toBool()
438
- ? AztecAddress.fromField(fromSingle(foreignOwnerValue))
439
- : undefined;
513
+ ? Option.some(AztecAddress.fromField(fromSingle(foreignOwnerValue)))
514
+ : Option.none(AztecAddress.ZERO);
440
515
  const storageSlot = fromSingle(foreignStorageSlot);
441
516
  const numSelects = fromSingle(foreignNumSelects).toNumber();
442
517
  const selectByIndexes = fromArray(foreignSelectByIndexes).map(fr => fr.toNumber());
@@ -454,7 +529,7 @@ export class RPCTranslator {
454
529
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
455
530
  const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
456
531
 
457
- const noteDatas = await this.handlerAsUtility().getNotes(
532
+ const noteVec = await this.handlerAsUtility().getNotes(
458
533
  owner,
459
534
  storageSlot,
460
535
  numSelects,
@@ -470,9 +545,11 @@ export class RPCTranslator {
470
545
  limit,
471
546
  offset,
472
547
  status,
548
+ maxNotes,
549
+ packedHintedNoteLength,
473
550
  );
474
551
 
475
- const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
552
+ const returnDataAsArrayOfArrays = Array.from(noteVec.data).map(noteData =>
476
553
  packAsHintedNote({
477
554
  contractAddress: noteData.contractAddress,
478
555
  owner: noteData.owner,
@@ -484,12 +561,10 @@ export class RPCTranslator {
484
561
  }),
485
562
  );
486
563
 
487
- // Now we convert each sub-array to an array of ForeignCallSingles
488
564
  const returnDataAsArrayOfForeignCallSingleArrays = returnDataAsArrayOfArrays.map(subArray =>
489
565
  subArray.map(toSingle),
490
566
  );
491
567
 
492
- // At last we convert the array of arrays to a bounded vec of arrays
493
568
  return toForeignCallResult(
494
569
  arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
495
570
  );
@@ -556,10 +631,10 @@ export class RPCTranslator {
556
631
  }
557
632
 
558
633
  // eslint-disable-next-line camelcase
559
- async aztec_utl_checkNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
634
+ async aztec_utl_doesNullifierExist(foreignInnerNullifier: ForeignCallSingle) {
560
635
  const innerNullifier = fromSingle(foreignInnerNullifier);
561
636
 
562
- const exists = await this.handlerAsUtility().checkNullifierExists(innerNullifier);
637
+ const exists = await this.handlerAsUtility().doesNullifierExist(innerNullifier);
563
638
 
564
639
  return toForeignCallResult([toSingle(new Fr(exists))]);
565
640
  }
@@ -576,27 +651,42 @@ export class RPCTranslator {
576
651
  instance.deployer.toField(),
577
652
  instance.currentContractClassId,
578
653
  instance.initializationHash,
654
+ instance.immutablesHash,
579
655
  ...instance.publicKeys.toFields(),
580
656
  ].map(toSingle),
581
657
  );
582
658
  }
583
659
 
584
660
  // eslint-disable-next-line camelcase
585
- async aztec_utl_tryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
661
+ async aztec_utl_getPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
586
662
  const address = addressFromSingle(foreignAddress);
587
663
 
588
- const result = await this.handlerAsUtility().tryGetPublicKeysAndPartialAddress(address);
664
+ const result = await this.handlerAsUtility().getPublicKeysAndPartialAddress(address);
589
665
 
590
666
  // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
591
667
  // with two fields: `some` (a boolean) and `value` (a field array in this case).
592
- if (result === undefined) {
668
+ if (!result.isSome()) {
593
669
  // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
594
- return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
670
+ // Wire shape: [npk_m_hash, ivpk_m.x, ivpk_m.y, ovpk_m_hash, tpk_m_hash, mspk_m_hash, fbpk_m_hash, partial_address] = 8 fields.
671
+ return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(8).fill(new Fr(0)))]);
595
672
  } else {
596
- // Data was found so we set `some` to 1 and return it along with `value`.
673
+ // The Noir side hand-decodes a `[Field; 8]` here (see aztec-nr/aztec/src/oracle/keys.nr), so we
674
+ // emit the 7-field PublicKeys shape + partial_address explicitly
675
+ // rather than going through `publicKeys.toFields()` (which is the struct-flattened 8-field
676
+ // wire for oracle returns that decode via struct shape).
677
+ const { publicKeys, partialAddress } = result.value;
597
678
  return toForeignCallResult([
598
679
  toSingle(new Fr(1)),
599
- toArray([...result.publicKeys.toFields(), result.partialAddress]),
680
+ toArray([
681
+ publicKeys.npkMHash,
682
+ publicKeys.ivpkM.x,
683
+ publicKeys.ivpkM.y,
684
+ publicKeys.ovpkMHash,
685
+ publicKeys.tpkMHash,
686
+ publicKeys.mspkMHash,
687
+ publicKeys.fbpkMHash,
688
+ partialAddress,
689
+ ]),
600
690
  ]);
601
691
  }
602
692
  }
@@ -611,16 +701,27 @@ export class RPCTranslator {
611
701
  }
612
702
 
613
703
  // eslint-disable-next-line camelcase
614
- aztec_prv_callPrivateFunction(
615
- _foreignTargetContractAddress: ForeignCallSingle,
616
- _foreignFunctionSelector: ForeignCallSingle,
617
- _foreignArgsHash: ForeignCallSingle,
618
- _foreignSideEffectCounter: ForeignCallSingle,
619
- _foreignIsStaticCall: ForeignCallSingle,
704
+ async aztec_prv_callPrivateFunction(
705
+ foreignTargetContractAddress: ForeignCallSingle,
706
+ foreignFunctionSelector: ForeignCallSingle,
707
+ foreignArgsHash: ForeignCallSingle,
708
+ foreignSideEffectCounter: ForeignCallSingle,
709
+ foreignIsStaticCall: ForeignCallSingle,
620
710
  ) {
621
- throw new Error(
622
- 'Contract calls are forbidden inside a `TestEnvironment::private_context`, use `private_call` instead',
711
+ const targetContractAddress = addressFromSingle(foreignTargetContractAddress);
712
+ const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
713
+ const argsHash = fromSingle(foreignArgsHash);
714
+ const sideEffectCounter = fromSingle(foreignSideEffectCounter).toNumber();
715
+ const isStaticCall = fromSingle(foreignIsStaticCall).toBool();
716
+
717
+ const { endSideEffectCounter, returnsHash } = await this.handlerAsPrivate().callPrivateFunction(
718
+ targetContractAddress,
719
+ functionSelector,
720
+ argsHash,
721
+ sideEffectCounter,
722
+ isStaticCall,
623
723
  );
724
+ return toForeignCallResult([[endSideEffectCounter, returnsHash].map(toSingle)]);
624
725
  }
625
726
 
626
727
  // eslint-disable-next-line camelcase
@@ -628,14 +729,10 @@ export class RPCTranslator {
628
729
  foreignBlockHash: ForeignCallSingle,
629
730
  foreignNullifier: ForeignCallSingle,
630
731
  ) {
631
- const blockHash = new BlockHash(fromSingle(foreignBlockHash));
732
+ const blockHash = blockHashFromSingle(foreignBlockHash);
632
733
  const nullifier = fromSingle(foreignNullifier);
633
734
 
634
735
  const witness = await this.handlerAsUtility().getNullifierMembershipWitness(blockHash, nullifier);
635
-
636
- if (!witness) {
637
- throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
638
- }
639
736
  return toForeignCallResult(witness.toNoirRepresentation());
640
737
  }
641
738
 
@@ -644,42 +741,27 @@ export class RPCTranslator {
644
741
  const messageHash = fromSingle(foreignMessageHash);
645
742
 
646
743
  const authWitness = await this.handlerAsUtility().getAuthWitness(messageHash);
647
-
648
- if (!authWitness) {
649
- throw new Error(`Auth witness not found for message hash ${messageHash}.`);
650
- }
651
744
  return toForeignCallResult([toArray(authWitness)]);
652
745
  }
653
746
 
654
747
  // eslint-disable-next-line camelcase
655
- public aztec_prv_notifyEnqueuedPublicFunctionCall(
656
- _foreignTargetContractAddress: ForeignCallSingle,
657
- _foreignCalldataHash: ForeignCallSingle,
658
- _foreignSideEffectCounter: ForeignCallSingle,
659
- _foreignIsStaticCall: ForeignCallSingle,
660
- ) {
661
- throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
662
- }
663
-
664
- // eslint-disable-next-line camelcase
665
- public aztec_prv_notifySetPublicTeardownFunctionCall(
666
- _foreignTargetContractAddress: ForeignCallSingle,
667
- _foreignCalldataHash: ForeignCallSingle,
668
- _foreignSideEffectCounter: ForeignCallSingle,
669
- _foreignIsStaticCall: ForeignCallSingle,
670
- ) {
671
- throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
748
+ public async aztec_prv_assertValidPublicCalldata(foreignCalldataHash: ForeignCallSingle) {
749
+ const calldataHash = fromSingle(foreignCalldataHash);
750
+ await this.handlerAsPrivate().assertValidPublicCalldata(calldataHash);
751
+ return toForeignCallResult([]);
672
752
  }
673
753
 
674
754
  // eslint-disable-next-line camelcase
675
- public aztec_prv_notifySetMinRevertibleSideEffectCounter(_foreignMinRevertibleSideEffectCounter: ForeignCallSingle) {
676
- throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
755
+ public async aztec_prv_notifyRevertiblePhaseStart(foreignMinRevertibleSideEffectCounter: ForeignCallSingle) {
756
+ const minRevertibleSideEffectCounter = fromSingle(foreignMinRevertibleSideEffectCounter).toNumber();
757
+ await this.handlerAsPrivate().notifyRevertiblePhaseStart(minRevertibleSideEffectCounter);
758
+ return toForeignCallResult([]);
677
759
  }
678
760
 
679
761
  // eslint-disable-next-line camelcase
680
- public async aztec_prv_isSideEffectCounterRevertible(foreignSideEffectCounter: ForeignCallSingle) {
762
+ public async aztec_prv_isExecutionInRevertiblePhase(foreignSideEffectCounter: ForeignCallSingle) {
681
763
  const sideEffectCounter = fromSingle(foreignSideEffectCounter).toNumber();
682
- const isRevertible = await this.handlerAsPrivate().isSideEffectCounterRevertible(sideEffectCounter);
764
+ const isRevertible = await this.handlerAsPrivate().isExecutionInRevertiblePhase(sideEffectCounter);
683
765
  return toForeignCallResult([toSingle(new Fr(isRevertible))]);
684
766
  }
685
767
 
@@ -695,10 +777,6 @@ export class RPCTranslator {
695
777
  const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
696
778
 
697
779
  const header = await this.handlerAsUtility().getBlockHeader(blockNumber);
698
-
699
- if (!header) {
700
- throw new Error(`Block header not found for block ${blockNumber}.`);
701
- }
702
780
  return toForeignCallResult(header.toFields().map(toSingle));
703
781
  }
704
782
 
@@ -707,14 +785,10 @@ export class RPCTranslator {
707
785
  foreignAnchorBlockHash: ForeignCallSingle,
708
786
  foreignNoteHash: ForeignCallSingle,
709
787
  ) {
710
- const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
788
+ const blockHash = blockHashFromSingle(foreignAnchorBlockHash);
711
789
  const noteHash = fromSingle(foreignNoteHash);
712
790
 
713
791
  const witness = await this.handlerAsUtility().getNoteHashMembershipWitness(blockHash, noteHash);
714
-
715
- if (!witness) {
716
- throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
717
- }
718
792
  return toForeignCallResult(witness.toNoirRepresentation());
719
793
  }
720
794
 
@@ -723,17 +797,12 @@ export class RPCTranslator {
723
797
  foreignAnchorBlockHash: ForeignCallSingle,
724
798
  foreignBlockHash: ForeignCallSingle,
725
799
  ) {
726
- const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
727
- const blockHash = new BlockHash(fromSingle(foreignBlockHash));
800
+ const anchorBlockHash = blockHashFromSingle(foreignAnchorBlockHash);
801
+ const blockHash = blockHashFromSingle(foreignBlockHash);
728
802
 
729
- const witness = await this.handlerAsUtility().getBlockHashMembershipWitness(anchorBlockHash, blockHash);
730
-
731
- if (!witness) {
732
- throw new Error(
733
- `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
734
- );
735
- }
736
- return toForeignCallResult(witness.toNoirRepresentation());
803
+ const witnessOpt = await this.handlerAsUtility().getBlockHashMembershipWitness(anchorBlockHash, blockHash);
804
+ const effective = witnessOpt.value ?? MembershipWitness.empty(ARCHIVE_HEIGHT);
805
+ return toForeignCallResult([toSingle(new Fr(witnessOpt.isSome() ? 1 : 0)), ...effective.toNoirRepresentation()]);
737
806
  }
738
807
 
739
808
  // eslint-disable-next-line camelcase
@@ -741,108 +810,106 @@ export class RPCTranslator {
741
810
  foreignBlockHash: ForeignCallSingle,
742
811
  foreignNullifier: ForeignCallSingle,
743
812
  ) {
744
- const blockHash = new BlockHash(fromSingle(foreignBlockHash));
813
+ const blockHash = blockHashFromSingle(foreignBlockHash);
745
814
  const nullifier = fromSingle(foreignNullifier);
746
815
 
747
816
  const witness = await this.handlerAsUtility().getLowNullifierMembershipWitness(blockHash, nullifier);
748
-
749
- if (!witness) {
750
- throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockHash}.`);
751
- }
752
817
  return toForeignCallResult(witness.toNoirRepresentation());
753
818
  }
754
819
 
755
820
  // eslint-disable-next-line camelcase
756
- async aztec_utl_fetchTaggedLogs(foreignPendingTaggedLogArrayBaseSlot: ForeignCallSingle) {
757
- const pendingTaggedLogArrayBaseSlot = fromSingle(foreignPendingTaggedLogArrayBaseSlot);
758
-
759
- await this.handlerAsUtility().fetchTaggedLogs(pendingTaggedLogArrayBaseSlot);
760
-
761
- return toForeignCallResult([]);
821
+ async aztec_utl_getPendingTaggedLogs(foreignScope: ForeignCallSingle) {
822
+ const scope = AztecAddress.fromField(fromSingle(foreignScope));
823
+ const slot = await this.handlerAsUtility().getPendingTaggedLogs(scope);
824
+ return toForeignCallResult([toSingle(slot)]);
762
825
  }
763
826
 
764
827
  // eslint-disable-next-line camelcase
765
828
  public async aztec_utl_validateAndStoreEnqueuedNotesAndEvents(
766
- foreignContractAddress: ForeignCallSingle,
767
829
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
768
830
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
831
+ foreignScope: ForeignCallSingle,
769
832
  ) {
770
- const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
771
833
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
772
834
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
835
+ const scope = AztecAddress.fromField(fromSingle(foreignScope));
773
836
 
774
837
  await this.handlerAsUtility().validateAndStoreEnqueuedNotesAndEvents(
775
- contractAddress,
776
838
  noteValidationRequestsArrayBaseSlot,
777
839
  eventValidationRequestsArrayBaseSlot,
840
+ scope,
778
841
  );
779
842
 
780
843
  return toForeignCallResult([]);
781
844
  }
782
845
 
783
846
  // eslint-disable-next-line camelcase
784
- public async aztec_utl_bulkRetrieveLogs(
785
- foreignContractAddress: ForeignCallSingle,
786
- foreignLogRetrievalRequestsArrayBaseSlot: ForeignCallSingle,
787
- foreignLogRetrievalResponsesArrayBaseSlot: ForeignCallSingle,
788
- ) {
789
- const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
790
- const logRetrievalRequestsArrayBaseSlot = fromSingle(foreignLogRetrievalRequestsArrayBaseSlot);
791
- const logRetrievalResponsesArrayBaseSlot = fromSingle(foreignLogRetrievalResponsesArrayBaseSlot);
792
-
793
- await this.handlerAsUtility().bulkRetrieveLogs(
794
- contractAddress,
795
- logRetrievalRequestsArrayBaseSlot,
796
- logRetrievalResponsesArrayBaseSlot,
797
- );
847
+ async aztec_utl_getLogsByTag(foreignRequestArrayBaseSlot: ForeignCallSingle) {
848
+ const requestArrayBaseSlot = fromSingle(foreignRequestArrayBaseSlot);
849
+ const responseSlot = await this.handlerAsUtility().getLogsByTag(requestArrayBaseSlot);
850
+ return toForeignCallResult([toSingle(responseSlot)]);
851
+ }
798
852
 
799
- return toForeignCallResult([]);
853
+ // eslint-disable-next-line camelcase
854
+ async aztec_utl_getMessageContextsByTxHash(foreignRequestArrayBaseSlot: ForeignCallSingle) {
855
+ const requestArrayBaseSlot = fromSingle(foreignRequestArrayBaseSlot);
856
+ const responseSlot = await this.handlerAsUtility().getMessageContextsByTxHash(requestArrayBaseSlot);
857
+ return toForeignCallResult([toSingle(responseSlot)]);
800
858
  }
801
859
 
802
860
  // eslint-disable-next-line camelcase
803
- async aztec_utl_storeCapsule(
861
+ aztec_utl_setCapsule(
804
862
  foreignContractAddress: ForeignCallSingle,
805
863
  foreignSlot: ForeignCallSingle,
806
864
  foreignCapsule: ForeignCallArray,
865
+ foreignScope: ForeignCallSingle,
807
866
  ) {
808
867
  const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
809
868
  const slot = fromSingle(foreignSlot);
810
869
  const capsule = fromArray(foreignCapsule);
870
+ const scope = AztecAddress.fromField(fromSingle(foreignScope));
811
871
 
812
- await this.handlerAsUtility().storeCapsule(contractAddress, slot, capsule);
872
+ this.handlerAsUtility().setCapsule(contractAddress, slot, capsule, scope);
813
873
 
814
874
  return toForeignCallResult([]);
815
875
  }
816
876
 
817
877
  // eslint-disable-next-line camelcase
818
- async aztec_utl_loadCapsule(
878
+ async aztec_utl_getCapsule(
819
879
  foreignContractAddress: ForeignCallSingle,
820
880
  foreignSlot: ForeignCallSingle,
821
881
  foreignTSize: ForeignCallSingle,
882
+ foreignScope: ForeignCallSingle,
822
883
  ) {
823
884
  const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
824
885
  const slot = fromSingle(foreignSlot);
825
886
  const tSize = fromSingle(foreignTSize).toNumber();
887
+ const scope = AztecAddress.fromField(fromSingle(foreignScope));
826
888
 
827
- const values = await this.handlerAsUtility().loadCapsule(contractAddress, slot);
889
+ const opt = await this.handlerAsUtility().getCapsule(contractAddress, slot, tSize, scope);
828
890
 
829
891
  // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
830
892
  // with two fields: `some` (a boolean) and `value` (a field array in this case).
831
- if (values === null) {
893
+ if (opt.isSome()) {
894
+ // Data was found so we set `some` to 1 and return it along with `value`.
895
+ return toForeignCallResult([toSingle(new Fr(1)), toArray(Array.from(opt.value))]);
896
+ } else {
832
897
  // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
833
898
  return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(tSize).fill(new Fr(0)))]);
834
- } else {
835
- // Data was found so we set `some` to 1 and return it along with `value`.
836
- return toForeignCallResult([toSingle(new Fr(1)), toArray(values)]);
837
899
  }
838
900
  }
839
901
 
840
902
  // eslint-disable-next-line camelcase
841
- async aztec_utl_deleteCapsule(foreignContractAddress: ForeignCallSingle, foreignSlot: ForeignCallSingle) {
903
+ aztec_utl_deleteCapsule(
904
+ foreignContractAddress: ForeignCallSingle,
905
+ foreignSlot: ForeignCallSingle,
906
+ foreignScope: ForeignCallSingle,
907
+ ) {
842
908
  const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
843
909
  const slot = fromSingle(foreignSlot);
910
+ const scope = AztecAddress.fromField(fromSingle(foreignScope));
844
911
 
845
- await this.handlerAsUtility().deleteCapsule(contractAddress, slot);
912
+ this.handlerAsUtility().deleteCapsule(contractAddress, slot, scope);
846
913
 
847
914
  return toForeignCallResult([]);
848
915
  }
@@ -853,14 +920,74 @@ export class RPCTranslator {
853
920
  foreignSrcSlot: ForeignCallSingle,
854
921
  foreignDstSlot: ForeignCallSingle,
855
922
  foreignNumEntries: ForeignCallSingle,
923
+ foreignScope: ForeignCallSingle,
856
924
  ) {
857
925
  const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
858
926
  const srcSlot = fromSingle(foreignSrcSlot);
859
927
  const dstSlot = fromSingle(foreignDstSlot);
860
928
  const numEntries = fromSingle(foreignNumEntries).toNumber();
929
+ const scope = AztecAddress.fromField(fromSingle(foreignScope));
930
+
931
+ await this.handlerAsUtility().copyCapsule(contractAddress, srcSlot, dstSlot, numEntries, scope);
932
+
933
+ return toForeignCallResult([]);
934
+ }
935
+
936
+ // eslint-disable-next-line camelcase
937
+ aztec_utl_pushEphemeral(foreignSlot: ForeignCallSingle, foreignElements: ForeignCallArray) {
938
+ const slot = fromSingle(foreignSlot);
939
+ const elements = fromArray(foreignElements);
940
+ const newLen = this.handlerAsUtility().pushEphemeral(slot, elements);
941
+ return toForeignCallResult([toSingle(new Fr(newLen))]);
942
+ }
943
+
944
+ // eslint-disable-next-line camelcase
945
+ aztec_utl_popEphemeral(foreignSlot: ForeignCallSingle) {
946
+ const slot = fromSingle(foreignSlot);
947
+ const element = this.handlerAsUtility().popEphemeral(slot);
948
+ return toForeignCallResult([toArray(element)]);
949
+ }
950
+
951
+ // eslint-disable-next-line camelcase
952
+ aztec_utl_getEphemeral(foreignSlot: ForeignCallSingle, foreignIndex: ForeignCallSingle) {
953
+ const slot = fromSingle(foreignSlot);
954
+ const index = fromSingle(foreignIndex).toNumber();
955
+ const element = this.handlerAsUtility().getEphemeral(slot, index);
956
+ return toForeignCallResult([toArray(element)]);
957
+ }
958
+
959
+ // eslint-disable-next-line camelcase
960
+ aztec_utl_setEphemeral(
961
+ foreignSlot: ForeignCallSingle,
962
+ foreignIndex: ForeignCallSingle,
963
+ foreignElements: ForeignCallArray,
964
+ ) {
965
+ const slot = fromSingle(foreignSlot);
966
+ const index = fromSingle(foreignIndex).toNumber();
967
+ const elements = fromArray(foreignElements);
968
+ this.handlerAsUtility().setEphemeral(slot, index, elements);
969
+ return toForeignCallResult([]);
970
+ }
861
971
 
862
- await this.handlerAsUtility().copyCapsule(contractAddress, srcSlot, dstSlot, numEntries);
972
+ // eslint-disable-next-line camelcase
973
+ aztec_utl_getEphemeralLen(foreignSlot: ForeignCallSingle) {
974
+ const slot = fromSingle(foreignSlot);
975
+ const len = this.handlerAsUtility().getEphemeralLen(slot);
976
+ return toForeignCallResult([toSingle(new Fr(len))]);
977
+ }
863
978
 
979
+ // eslint-disable-next-line camelcase
980
+ aztec_utl_removeEphemeral(foreignSlot: ForeignCallSingle, foreignIndex: ForeignCallSingle) {
981
+ const slot = fromSingle(foreignSlot);
982
+ const index = fromSingle(foreignIndex).toNumber();
983
+ this.handlerAsUtility().removeEphemeral(slot, index);
984
+ return toForeignCallResult([]);
985
+ }
986
+
987
+ // eslint-disable-next-line camelcase
988
+ aztec_utl_clearEphemeral(foreignSlot: ForeignCallSingle) {
989
+ const slot = fromSingle(foreignSlot);
990
+ this.handlerAsUtility().clearEphemeral(slot);
864
991
  return toForeignCallResult([]);
865
992
  }
866
993
 
@@ -869,45 +996,71 @@ export class RPCTranslator {
869
996
  // to implement this function here. Isn't there a way to programmatically identify that this is missing, given the
870
997
  // existence of a txe_oracle method?
871
998
  // eslint-disable-next-line camelcase
872
- async aztec_utl_aes128Decrypt(
999
+ async aztec_utl_decryptAes128(
873
1000
  foreignCiphertextBVecStorage: ForeignCallArray,
874
1001
  foreignCiphertextLength: ForeignCallSingle,
875
1002
  foreignIv: ForeignCallArray,
876
1003
  foreignSymKey: ForeignCallArray,
877
1004
  ) {
878
- const ciphertext = fromUintBoundedVec(foreignCiphertextBVecStorage, foreignCiphertextLength, 8);
1005
+ const capacity = foreignCiphertextBVecStorage.length;
1006
+ const ciphertextBuf = fromUintBoundedVec(foreignCiphertextBVecStorage, foreignCiphertextLength, 8);
1007
+ const ciphertext = BoundedVec.from<number>({ data: [...ciphertextBuf], maxLength: capacity });
879
1008
  const iv = fromUintArray(foreignIv, 8);
880
1009
  const symKey = fromUintArray(foreignSymKey, 8);
881
1010
 
882
- const plaintextBuffer = await this.handlerAsUtility().aes128Decrypt(ciphertext, iv, symKey);
883
-
884
- return toForeignCallResult(
885
- arrayToBoundedVec(bufferToU8Array(plaintextBuffer), foreignCiphertextBVecStorage.length),
886
- );
1011
+ // Noir Option<BoundedVec> is encoded as [is_some: Field, storage: Field[], length: Field].
1012
+ const plaintextOpt = await this.handlerAsUtility().decryptAes128(ciphertext, iv, symKey);
1013
+ if (plaintextOpt.isSome()) {
1014
+ const [storage, length] = arrayToBoundedVec(bufferToU8Array(Buffer.from(plaintextOpt.value.data)), capacity);
1015
+ return toForeignCallResult([toSingle(new Fr(1)), storage, length]);
1016
+ } else {
1017
+ const zeroStorage = toArray(Array(capacity).fill(new Fr(0)));
1018
+ return toForeignCallResult([toSingle(new Fr(0)), zeroStorage, toSingle(new Fr(0))]);
1019
+ }
887
1020
  }
888
1021
 
889
1022
  // eslint-disable-next-line camelcase
890
- async aztec_utl_getSharedSecret(
1023
+ async aztec_utl_getSharedSecrets(
891
1024
  foreignAddress: ForeignCallSingle,
892
- foreignEphPKField0: ForeignCallSingle,
893
- foreignEphPKField1: ForeignCallSingle,
894
- foreignEphPKField2: ForeignCallSingle,
1025
+ foreignEphPksSlot: ForeignCallSingle,
1026
+ foreignContractAddress: ForeignCallSingle,
895
1027
  ) {
896
1028
  const address = AztecAddress.fromField(fromSingle(foreignAddress));
897
- const ephPK = Point.fromFields([
898
- fromSingle(foreignEphPKField0),
899
- fromSingle(foreignEphPKField1),
900
- fromSingle(foreignEphPKField2),
901
- ]);
1029
+ const ephPksSlot = fromSingle(foreignEphPksSlot);
1030
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
1031
+
1032
+ const responseSlot = await this.handlerAsUtility().getSharedSecrets(address, ephPksSlot, contractAddress);
1033
+
1034
+ return toForeignCallResult([toSingle(responseSlot)]);
1035
+ }
1036
+
1037
+ // eslint-disable-next-line camelcase
1038
+ aztec_utl_setContractSyncCacheInvalid(
1039
+ foreignContractAddress: ForeignCallSingle,
1040
+ foreignScopes: ForeignCallArray,
1041
+ foreignScopeCount: ForeignCallSingle,
1042
+ ) {
1043
+ const contractAddress = addressFromSingle(foreignContractAddress);
1044
+ const allFields = fromArray(foreignScopes);
1045
+ const count = fromSingle(foreignScopeCount).toNumber();
1046
+ const scopes = BoundedVec.from({
1047
+ data: allFields.slice(0, count).map(f => new AztecAddress(f)),
1048
+ maxLength: allFields.length,
1049
+ });
902
1050
 
903
- const secret = await this.handlerAsUtility().getSharedSecret(address, ephPK);
1051
+ this.handlerAsUtility().setContractSyncCacheInvalid(contractAddress, scopes);
904
1052
 
905
- return toForeignCallResult(secret.toFields().map(toSingle));
1053
+ return Promise.resolve(toForeignCallResult([]));
906
1054
  }
907
1055
 
908
1056
  // eslint-disable-next-line camelcase
909
- aztec_utl_emitOffchainEffect(_foreignData: ForeignCallArray) {
910
- throw new Error('Offchain effects are not yet supported in the TestEnvironment');
1057
+ aztec_utl_emitOffchainEffect(foreignData: ForeignCallArray) {
1058
+ // Record the raw payload against the currently-executing top-level call. The Noir side
1059
+ // (via `env.offchain_messages()`) is responsible for decoding the protocol-reserved prefix
1060
+ // (`OFFCHAIN_MESSAGE_IDENTIFIER`, recipient) and turning each payload into an `OffchainMessage` struct suitable
1061
+ // for `offchain_receive`.
1062
+ this.stateHandler.recordOffchainEffect(fromArray(foreignData));
1063
+ return Promise.resolve(toForeignCallResult([]));
911
1064
  }
912
1065
 
913
1066
  // AVM opcodes
@@ -977,6 +1130,19 @@ export class RPCTranslator {
977
1130
  ]);
978
1131
  }
979
1132
 
1133
+ // eslint-disable-next-line camelcase
1134
+ async aztec_avm_getContractInstanceImmutablesHash(foreignAddress: ForeignCallSingle) {
1135
+ const address = addressFromSingle(foreignAddress);
1136
+
1137
+ const instance = await this.handlerAsUtility().getContractInstance(address);
1138
+
1139
+ return toForeignCallResult([
1140
+ toSingle(instance.immutablesHash),
1141
+ // AVM requires an extra boolean indicating the instance was found
1142
+ toSingle(new Fr(1)),
1143
+ ]);
1144
+ }
1145
+
980
1146
  // eslint-disable-next-line camelcase
981
1147
  async aztec_avm_sender() {
982
1148
  const sender = await this.handlerAsAvm().sender();
@@ -1054,147 +1220,209 @@ export class RPCTranslator {
1054
1220
  }
1055
1221
 
1056
1222
  // eslint-disable-next-line camelcase
1057
- aztec_avm_returndataSize() {
1058
- throw new Error(
1059
- 'Contract calls are forbidden inside a `TestEnvironment::public_context`, use `public_call` instead',
1060
- );
1223
+ async aztec_avm_returndataSize() {
1224
+ const result = await this.handlerAsAvm().returndataSize();
1225
+ return toForeignCallResult([toSingle(result)]);
1061
1226
  }
1062
1227
 
1063
1228
  // eslint-disable-next-line camelcase
1064
- aztec_avm_returndataCopy(_foreignRdOffset: ForeignCallSingle, _foreignCopySize: ForeignCallSingle) {
1065
- throw new Error(
1066
- 'Contract calls are forbidden inside a `TestEnvironment::public_context`, use `public_call` instead',
1067
- );
1229
+ async aztec_avm_returndataCopy(foreignRdOffset: ForeignCallSingle, foreignCopySize: ForeignCallSingle) {
1230
+ const rdOffset = fromSingle(foreignRdOffset).toNumber();
1231
+ const copySize = fromSingle(foreignCopySize).toNumber();
1232
+ const result = await this.handlerAsAvm().returndataCopy(rdOffset, copySize);
1233
+ return toForeignCallResult([toArray(result)]);
1068
1234
  }
1069
1235
 
1070
1236
  // eslint-disable-next-line camelcase
1071
- aztec_avm_call(
1072
- _foreignL2Gas: ForeignCallSingle,
1073
- _foreignDaGas: ForeignCallSingle,
1074
- _foreignAddress: ForeignCallSingle,
1075
- _foreignLength: ForeignCallSingle,
1076
- _foreignArgs: ForeignCallArray,
1237
+ async aztec_avm_call(
1238
+ foreignL2Gas: ForeignCallSingle,
1239
+ foreignDaGas: ForeignCallSingle,
1240
+ foreignAddress: ForeignCallSingle,
1241
+ foreignLength: ForeignCallSingle,
1242
+ foreignArgs: ForeignCallArray,
1077
1243
  ) {
1078
- throw new Error(
1079
- 'Contract calls are forbidden inside a `TestEnvironment::public_context`, use `public_call` instead',
1080
- );
1244
+ const l2Gas = fromSingle(foreignL2Gas).toNumber();
1245
+ const daGas = fromSingle(foreignDaGas).toNumber();
1246
+ const address = addressFromSingle(foreignAddress);
1247
+ const argsLength = fromSingle(foreignLength).toNumber();
1248
+ const args = fromArray(foreignArgs);
1249
+ const result = await this.handlerAsAvm().call(l2Gas, daGas, address, argsLength, args);
1250
+ return toForeignCallResult([toArray(result)]);
1081
1251
  }
1082
1252
 
1083
1253
  // eslint-disable-next-line camelcase
1084
- aztec_avm_staticCall(
1085
- _foreignL2Gas: ForeignCallSingle,
1086
- _foreignDaGas: ForeignCallSingle,
1087
- _foreignAddress: ForeignCallSingle,
1088
- _foreignLength: ForeignCallSingle,
1089
- _foreignArgs: ForeignCallArray,
1254
+ async aztec_avm_staticCall(
1255
+ foreignL2Gas: ForeignCallSingle,
1256
+ foreignDaGas: ForeignCallSingle,
1257
+ foreignAddress: ForeignCallSingle,
1258
+ foreignLength: ForeignCallSingle,
1259
+ foreignArgs: ForeignCallArray,
1090
1260
  ) {
1091
- throw new Error(
1092
- 'Contract calls are forbidden inside a `TestEnvironment::public_context`, use `public_call` instead',
1093
- );
1261
+ const l2Gas = fromSingle(foreignL2Gas).toNumber();
1262
+ const daGas = fromSingle(foreignDaGas).toNumber();
1263
+ const address = addressFromSingle(foreignAddress);
1264
+ const argsLength = fromSingle(foreignLength).toNumber();
1265
+ const args = fromArray(foreignArgs);
1266
+ const result = await this.handlerAsAvm().staticCall(l2Gas, daGas, address, argsLength, args);
1267
+ return toForeignCallResult([toArray(result)]);
1094
1268
  }
1095
1269
 
1096
1270
  // eslint-disable-next-line camelcase
1097
- aztec_avm_successCopy() {
1098
- throw new Error(
1099
- 'Contract calls are forbidden inside a `TestEnvironment::public_context`, use `public_call` instead',
1100
- );
1271
+ async aztec_avm_successCopy() {
1272
+ const result = await this.handlerAsAvm().successCopy();
1273
+ return toForeignCallResult([toSingle(result)]);
1101
1274
  }
1102
1275
 
1276
+ // TODO(F-674): Move orchestration logic into the handler so the transport layer is pure serialize→delegate→deserialize.
1103
1277
  // eslint-disable-next-line camelcase
1104
1278
  async aztec_txe_privateCallNewFlow(
1105
- foreignFrom: ForeignCallSingle,
1279
+ foreignFromIsSome: ForeignCallSingle,
1280
+ foreignFromValue: ForeignCallSingle,
1106
1281
  foreignTargetContractAddress: ForeignCallSingle,
1107
1282
  foreignFunctionSelector: ForeignCallSingle,
1108
1283
  foreignArgs: ForeignCallArray,
1109
1284
  foreignArgsHash: ForeignCallSingle,
1110
1285
  foreignIsStaticCall: ForeignCallSingle,
1286
+ foreignAdditionalScopes: ForeignCallArray,
1287
+ foreignAuthorizedUtilityCallTargets: ForeignCallArray,
1288
+ foreignGasSettings: ForeignCallArray,
1111
1289
  ) {
1112
- const from = addressFromSingle(foreignFrom);
1290
+ const from = fromSingle(foreignFromIsSome).toBool() ? addressFromSingle(foreignFromValue) : undefined;
1113
1291
  const targetContractAddress = addressFromSingle(foreignTargetContractAddress);
1114
1292
  const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
1115
1293
  const args = fromArray(foreignArgs);
1116
1294
  const argsHash = fromSingle(foreignArgsHash);
1117
1295
  const isStaticCall = fromSingle(foreignIsStaticCall).toBool();
1118
-
1119
- const returnValues = await this.handlerAsTxe().privateCallNewFlow(
1120
- from,
1121
- targetContractAddress,
1122
- functionSelector,
1123
- args,
1124
- argsHash,
1125
- isStaticCall,
1126
- this.stateHandler.getCurrentJob(),
1296
+ const additionalScopes = fromArray(foreignAdditionalScopes).map(field => AztecAddress.fromField(field));
1297
+ const authorizedUtilityCallTargets = fromArray(foreignAuthorizedUtilityCallTargets).map(field =>
1298
+ AztecAddress.fromField(field),
1127
1299
  );
1300
+ const gasSettings = GasSettings.fromFields(fromArray(foreignGasSettings));
1301
+
1302
+ const returnValues = await this.stateHandler.withTopLevelCallTracking(async () => {
1303
+ const { returnValues, offchainEffects } = await this.handlerAsTxe().privateCallNewFlow(
1304
+ from,
1305
+ targetContractAddress,
1306
+ functionSelector,
1307
+ args,
1308
+ argsHash,
1309
+ isStaticCall,
1310
+ additionalScopes,
1311
+ this.stateHandler.getCurrentJob(),
1312
+ authorizedUtilityCallTargets,
1313
+ gasSettings,
1314
+ );
1315
+
1316
+ // Private execution collects offchain effects inside PXE's PrivateExecutionOracle rather than
1317
+ // round-tripping them through `aztec_utl_emitOffchainEffect`, so the session buffer is empty
1318
+ // at this point. Drain the effects from the execution tree into the session buffer so the
1319
+ // next `env.offchain_messages()` call in the test sees them.
1320
+ for (const data of offchainEffects) {
1321
+ this.stateHandler.recordOffchainEffect(data);
1322
+ }
1323
+
1324
+ // TODO(F-335): Avoid doing the following call here.
1325
+ await this.stateHandler.cycleJob();
1326
+
1327
+ if (isStaticCall) {
1328
+ // Static calls revert their checkpoint and mine no block, so there is no tx hash to tag
1329
+ // offchain effects with. Querying `getLastTxEffects()` here would return an unrelated
1330
+ // predecessor tx.
1331
+ return { result: returnValues };
1332
+ }
1333
+ const { txHash } = await this.handlerAsTxe().getLastTxEffects();
1334
+ return { result: returnValues, txHash: txHash.hash };
1335
+ });
1128
1336
 
1129
- // TODO(F-335): Avoid doing the following call here.
1130
- await this.stateHandler.cycleJob();
1131
1337
  return toForeignCallResult([toArray(returnValues)]);
1132
1338
  }
1133
1339
 
1340
+ // TODO(F-674): Move orchestration logic into the handler so the transport layer is pure serialize→delegate→deserialize.
1134
1341
  // eslint-disable-next-line camelcase
1135
1342
  async aztec_txe_executeUtilityFunction(
1136
1343
  foreignTargetContractAddress: ForeignCallSingle,
1137
1344
  foreignFunctionSelector: ForeignCallSingle,
1138
1345
  foreignArgs: ForeignCallArray,
1346
+ foreignAuthorizedUtilityCallTargets: ForeignCallArray,
1139
1347
  ) {
1140
1348
  const targetContractAddress = addressFromSingle(foreignTargetContractAddress);
1141
1349
  const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
1142
1350
  const args = fromArray(foreignArgs);
1143
-
1144
- const returnValues = await this.handlerAsTxe().executeUtilityFunction(
1145
- targetContractAddress,
1146
- functionSelector,
1147
- args,
1148
- this.stateHandler.getCurrentJob(),
1351
+ const authorizedUtilityCallTargets = fromArray(foreignAuthorizedUtilityCallTargets).map(field =>
1352
+ AztecAddress.fromField(field),
1149
1353
  );
1150
1354
 
1151
- // TODO(F-335): Avoid doing the following call here.
1152
- await this.stateHandler.cycleJob();
1355
+ const returnValues = await this.stateHandler.withTopLevelCallTracking(async () => {
1356
+ const returnValues = await this.handlerAsTxe().executeUtilityFunction(
1357
+ targetContractAddress,
1358
+ functionSelector,
1359
+ args,
1360
+ this.stateHandler.getCurrentJob(),
1361
+ authorizedUtilityCallTargets,
1362
+ );
1363
+
1364
+ // TODO(F-335): Avoid doing the following call here.
1365
+ await this.stateHandler.cycleJob();
1366
+
1367
+ return { result: returnValues };
1368
+ });
1369
+
1153
1370
  return toForeignCallResult([toArray(returnValues)]);
1154
1371
  }
1155
1372
 
1373
+ // TODO(F-674): Move orchestration logic into the handler so the transport layer is pure serialize→delegate→deserialize.
1156
1374
  // eslint-disable-next-line camelcase
1157
1375
  async aztec_txe_publicCallNewFlow(
1158
- foreignFrom: ForeignCallSingle,
1376
+ foreignFromIsSome: ForeignCallSingle,
1377
+ foreignFromValue: ForeignCallSingle,
1159
1378
  foreignAddress: ForeignCallSingle,
1160
1379
  foreignCalldata: ForeignCallArray,
1161
1380
  foreignIsStaticCall: ForeignCallSingle,
1381
+ foreignGasSettings: ForeignCallArray,
1162
1382
  ) {
1163
- const from = addressFromSingle(foreignFrom);
1383
+ const from = fromSingle(foreignFromIsSome).toBool() ? addressFromSingle(foreignFromValue) : undefined;
1164
1384
  const address = addressFromSingle(foreignAddress);
1165
1385
  const calldata = fromArray(foreignCalldata);
1166
1386
  const isStaticCall = fromSingle(foreignIsStaticCall).toBool();
1387
+ const gasSettings = GasSettings.fromFields(fromArray(foreignGasSettings));
1388
+
1389
+ const returnValues = await this.stateHandler.withTopLevelCallTracking(async () => {
1390
+ const returnValues = await this.handlerAsTxe().publicCallNewFlow(
1391
+ from,
1392
+ address,
1393
+ calldata,
1394
+ isStaticCall,
1395
+ gasSettings,
1396
+ );
1397
+
1398
+ // TODO(F-335): Avoid doing the following call here.
1399
+ await this.stateHandler.cycleJob();
1167
1400
 
1168
- const returnValues = await this.handlerAsTxe().publicCallNewFlow(from, address, calldata, isStaticCall);
1401
+ if (isStaticCall) {
1402
+ // See equivalent branch in `aztec_txe_privateCallNewFlow`.
1403
+ return { result: returnValues };
1404
+ }
1405
+ const { txHash } = await this.handlerAsTxe().getLastTxEffects();
1406
+ return { result: returnValues, txHash: txHash.hash };
1407
+ });
1169
1408
 
1170
- // TODO(F-335): Avoid doing the following call here.
1171
- await this.stateHandler.cycleJob();
1172
1409
  return toForeignCallResult([toArray(returnValues)]);
1173
1410
  }
1174
1411
 
1175
1412
  // eslint-disable-next-line camelcase
1176
1413
  async aztec_prv_getSenderForTags() {
1177
- const sender = await this.handlerAsPrivate().getSenderForTags();
1414
+ const senderOpt = await this.handlerAsPrivate().getSenderForTags();
1178
1415
 
1179
1416
  // Return a Noir Option struct with `some` and `value` fields
1180
- if (sender === undefined) {
1417
+ if (senderOpt.isSome()) {
1418
+ // Sender found, return Option with some=1 and value=sender address
1419
+ return toForeignCallResult([toSingle(1), toSingle(senderOpt.value)]);
1420
+ } else {
1181
1421
  // No sender found, return Option with some=0 and value=0
1182
1422
  return toForeignCallResult([toSingle(0), toSingle(0)]);
1183
- } else {
1184
- // Sender found, return Option with some=1 and value=sender address
1185
- return toForeignCallResult([toSingle(1), toSingle(sender)]);
1186
1423
  }
1187
1424
  }
1188
1425
 
1189
- // eslint-disable-next-line camelcase
1190
- async aztec_prv_setSenderForTags(foreignSenderForTags: ForeignCallSingle) {
1191
- const senderForTags = AztecAddress.fromField(fromSingle(foreignSenderForTags));
1192
-
1193
- await this.handlerAsPrivate().setSenderForTags(senderForTags);
1194
-
1195
- return toForeignCallResult([]);
1196
- }
1197
-
1198
1426
  // eslint-disable-next-line camelcase
1199
1427
  async aztec_prv_getNextAppTagAsSender(foreignSender: ForeignCallSingle, foreignRecipient: ForeignCallSingle) {
1200
1428
  const sender = AztecAddress.fromField(fromSingle(foreignSender));
@@ -1204,4 +1432,13 @@ export class RPCTranslator {
1204
1432
 
1205
1433
  return toForeignCallResult([toSingle(nextAppTag.value)]);
1206
1434
  }
1435
+
1436
+ // eslint-disable-next-line camelcase
1437
+ async aztec_prv_getNextConstrainedTaggingIndex(foreignAppSiloedSecret: ForeignCallSingle) {
1438
+ const appSiloedSecret = fromSingle(foreignAppSiloedSecret);
1439
+
1440
+ const index = await this.handlerAsPrivate().getNextConstrainedTaggingIndex(appSiloedSecret);
1441
+
1442
+ return toForeignCallResult([toSingle(new Fr(index))]);
1443
+ }
1207
1444
  }