@aztec/txe 3.0.3 → 3.9.9-nightly.20260312

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 (75) hide show
  1. package/dest/constants.d.ts +3 -0
  2. package/dest/constants.d.ts.map +1 -0
  3. package/dest/constants.js +2 -0
  4. package/dest/index.d.ts +1 -1
  5. package/dest/index.d.ts.map +1 -1
  6. package/dest/index.js +85 -52
  7. package/dest/oracle/interfaces.d.ts +9 -6
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +4 -4
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +9 -11
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +21 -13
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +180 -72
  15. package/dest/rpc_translator.d.ts +29 -17
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +124 -57
  18. package/dest/state_machine/archiver.d.ts +20 -55
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +67 -108
  21. package/dest/state_machine/dummy_p2p_client.d.ts +20 -15
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +42 -25
  24. package/dest/state_machine/global_variable_builder.d.ts +4 -3
  25. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  26. package/dest/state_machine/global_variable_builder.js +13 -1
  27. package/dest/state_machine/index.d.ts +7 -7
  28. package/dest/state_machine/index.d.ts.map +1 -1
  29. package/dest/state_machine/index.js +41 -24
  30. package/dest/state_machine/mock_epoch_cache.d.ts +9 -6
  31. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  32. package/dest/state_machine/mock_epoch_cache.js +14 -7
  33. package/dest/state_machine/synchronizer.d.ts +3 -3
  34. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  35. package/dest/txe_session.d.ts +22 -11
  36. package/dest/txe_session.d.ts.map +1 -1
  37. package/dest/txe_session.js +154 -49
  38. package/dest/util/encoding.d.ts +617 -18
  39. package/dest/util/encoding.d.ts.map +1 -1
  40. package/dest/util/txe_account_store.d.ts +10 -0
  41. package/dest/util/txe_account_store.d.ts.map +1 -0
  42. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  43. package/dest/util/txe_public_contract_data_source.d.ts +5 -6
  44. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  45. package/dest/util/txe_public_contract_data_source.js +12 -29
  46. package/dest/utils/block_creation.d.ts +18 -4
  47. package/dest/utils/block_creation.d.ts.map +1 -1
  48. package/dest/utils/block_creation.js +37 -3
  49. package/dest/utils/tx_effect_creation.d.ts +2 -3
  50. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  51. package/dest/utils/tx_effect_creation.js +3 -6
  52. package/package.json +16 -16
  53. package/src/constants.ts +3 -0
  54. package/src/index.ts +97 -60
  55. package/src/oracle/interfaces.ts +11 -4
  56. package/src/oracle/txe_oracle_public_context.ts +9 -16
  57. package/src/oracle/txe_oracle_top_level_context.ts +223 -110
  58. package/src/rpc_translator.ts +141 -58
  59. package/src/state_machine/archiver.ts +61 -129
  60. package/src/state_machine/dummy_p2p_client.ts +58 -33
  61. package/src/state_machine/global_variable_builder.ts +19 -2
  62. package/src/state_machine/index.ts +61 -22
  63. package/src/state_machine/mock_epoch_cache.ts +15 -11
  64. package/src/state_machine/synchronizer.ts +2 -2
  65. package/src/txe_session.ts +213 -94
  66. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  67. package/src/util/txe_public_contract_data_source.ts +16 -42
  68. package/src/utils/block_creation.ts +47 -14
  69. package/src/utils/tx_effect_creation.ts +3 -11
  70. package/dest/util/txe_account_data_provider.d.ts +0 -10
  71. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  72. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  73. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  74. package/dest/util/txe_contract_data_provider.js +0 -22
  75. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -6,11 +6,11 @@ import {
6
6
  type IMiscOracle,
7
7
  type IPrivateExecutionOracle,
8
8
  type IUtilityExecutionOracle,
9
- packAsRetrievedNote,
9
+ packAsHintedNote,
10
10
  } from '@aztec/pxe/simulator';
11
- import { type ContractArtifact, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
11
+ import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
12
12
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { MerkleTreeId } from '@aztec/stdlib/trees';
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,6 +30,9 @@ import {
30
30
  toSingle,
31
31
  } from './util/encoding.js';
32
32
 
33
+ const MAX_EVENT_LEN = 10; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_MSG_PLAINTEXT_RESERVED_FIELDS_LEN
34
+ const MAX_PRIVATE_EVENTS_PER_TXE_QUERY = 5;
35
+
33
36
  export class UnavailableOracleError extends Error {
34
37
  constructor(oracleName: string) {
35
38
  super(`${oracleName} oracles not available with the current handler`);
@@ -156,6 +159,12 @@ export class RPCTranslator {
156
159
 
157
160
  // TXE-specific oracles
158
161
 
162
+ txeGetDefaultAddress() {
163
+ const defaultAddress = this.handlerAsTxe().txeGetDefaultAddress();
164
+
165
+ return toForeignCallResult([toSingle(defaultAddress)]);
166
+ }
167
+
159
168
  async txeGetNextBlockNumber() {
160
169
  const nextBlockNumber = await this.handlerAsTxe().txeGetNextBlockNumber();
161
170
 
@@ -267,6 +276,46 @@ export class RPCTranslator {
267
276
  ]);
268
277
  }
269
278
 
279
+ async txeGetPrivateEvents(
280
+ foreignSelector: ForeignCallSingle,
281
+ foreignContractAddress: ForeignCallSingle,
282
+ foreignScope: ForeignCallSingle,
283
+ ) {
284
+ const selector = EventSelector.fromField(fromSingle(foreignSelector));
285
+ const contractAddress = addressFromSingle(foreignContractAddress);
286
+ const scope = addressFromSingle(foreignScope);
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
+
295
+ const events = await this.handlerAsTxe().txeGetPrivateEvents(selector, contractAddress, scope);
296
+
297
+ if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
298
+ throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
299
+ }
300
+
301
+ if (events.some(e => e.length > MAX_EVENT_LEN)) {
302
+ throw new Error(`Some private event has length larger than maxLen ${MAX_EVENT_LEN}`);
303
+ }
304
+
305
+ // This is a workaround as Noir does not currently let us return nested structs with arrays. We instead return a raw
306
+ // multidimensional array in get_private_events_oracle and create the BoundedVecs here.
307
+ const rawArrayStorage = events
308
+ .map(e => e.concat(Array(MAX_EVENT_LEN - e.length).fill(new Fr(0))))
309
+ .concat(Array(MAX_PRIVATE_EVENTS_PER_TXE_QUERY - events.length).fill(Array(MAX_EVENT_LEN).fill(new Fr(0))))
310
+ .flat();
311
+ const eventLengths = events
312
+ .map(e => new Fr(e.length))
313
+ .concat(Array(MAX_PRIVATE_EVENTS_PER_TXE_QUERY - events.length).fill(new Fr(0)));
314
+ const queryLength = new Fr(events.length);
315
+
316
+ return toForeignCallResult([toArray(rawArrayStorage), toArray(eventLengths), toSingle(queryLength)]);
317
+ }
318
+
270
319
  privateStoreInExecutionCache(foreignValues: ForeignCallArray, foreignHash: ForeignCallSingle) {
271
320
  const values = fromArray(foreignValues);
272
321
  const hash = fromSingle(foreignHash);
@@ -286,7 +335,7 @@ export class RPCTranslator {
286
335
 
287
336
  // When the argument is a slice, noir automatically adds a length field to oracle call.
288
337
  // When the argument is an array, we add the field length manually to the signature.
289
- utilityDebugLog(
338
+ async utilityLog(
290
339
  foreignLevel: ForeignCallSingle,
291
340
  foreignMessage: ForeignCallArray,
292
341
  _foreignLength: ForeignCallSingle,
@@ -298,40 +347,40 @@ export class RPCTranslator {
298
347
  .join('');
299
348
  const fields = fromArray(foreignFields);
300
349
 
301
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
350
+ await this.handlerAsMisc().utilityLog(level, message, fields);
302
351
 
303
352
  return toForeignCallResult([]);
304
353
  }
305
354
 
306
355
  async utilityStorageRead(
356
+ foreignBlockHash: ForeignCallSingle,
307
357
  foreignContractAddress: ForeignCallSingle,
308
358
  foreignStartStorageSlot: ForeignCallSingle,
309
- foreignBlockNumber: ForeignCallSingle,
310
359
  foreignNumberOfElements: ForeignCallSingle,
311
360
  ) {
361
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
312
362
  const contractAddress = addressFromSingle(foreignContractAddress);
313
363
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
314
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
315
364
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
316
365
 
317
366
  const values = await this.handlerAsUtility().utilityStorageRead(
367
+ blockHash,
318
368
  contractAddress,
319
369
  startStorageSlot,
320
- blockNumber,
321
370
  numberOfElements,
322
371
  );
323
372
 
324
373
  return toForeignCallResult([toArray(values)]);
325
374
  }
326
375
 
327
- async utilityGetPublicDataWitness(foreignBlockNumber: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
328
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
376
+ async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
377
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
329
378
  const leafSlot = fromSingle(foreignLeafSlot);
330
379
 
331
- const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockNumber, leafSlot);
380
+ const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
332
381
 
333
382
  if (!witness) {
334
- throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockNumber}.`);
383
+ throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockHash.toString()}.`);
335
384
  }
336
385
  return toForeignCallResult(witness.toNoirRepresentation());
337
386
  }
@@ -354,7 +403,7 @@ export class RPCTranslator {
354
403
  foreignOffset: ForeignCallSingle,
355
404
  foreignStatus: ForeignCallSingle,
356
405
  foreignMaxNotes: ForeignCallSingle,
357
- foreignPackedRetrievedNoteLength: ForeignCallSingle,
406
+ foreignPackedHintedNoteLength: ForeignCallSingle,
358
407
  ) {
359
408
  // Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
360
409
  const owner = fromSingle(foreignOwnerIsSome).toBool()
@@ -375,7 +424,7 @@ export class RPCTranslator {
375
424
  const offset = fromSingle(foreignOffset).toNumber();
376
425
  const status = fromSingle(foreignStatus).toNumber();
377
426
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
378
- const packedRetrievedNoteLength = fromSingle(foreignPackedRetrievedNoteLength).toNumber();
427
+ const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
379
428
 
380
429
  const noteDatas = await this.handlerAsUtility().utilityGetNotes(
381
430
  owner,
@@ -396,13 +445,13 @@ export class RPCTranslator {
396
445
  );
397
446
 
398
447
  const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
399
- packAsRetrievedNote({
448
+ packAsHintedNote({
400
449
  contractAddress: noteData.contractAddress,
401
450
  owner: noteData.owner,
402
451
  randomness: noteData.randomness,
403
452
  storageSlot: noteData.storageSlot,
404
453
  noteNonce: noteData.noteNonce,
405
- index: noteData.index,
454
+ isPending: noteData.isPending,
406
455
  note: noteData.note,
407
456
  }),
408
457
  );
@@ -414,11 +463,7 @@ export class RPCTranslator {
414
463
 
415
464
  // At last we convert the array of arrays to a bounded vec of arrays
416
465
  return toForeignCallResult(
417
- arrayOfArraysToBoundedVecOfArrays(
418
- returnDataAsArrayOfForeignCallSingleArrays,
419
- maxNotes,
420
- packedRetrievedNoteLength,
421
- ),
466
+ arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
422
467
  );
423
468
  }
424
469
 
@@ -474,6 +519,15 @@ export class RPCTranslator {
474
519
  return toForeignCallResult([]);
475
520
  }
476
521
 
522
+ async privateIsNullifierPending(foreignInnerNullifier: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
523
+ const innerNullifier = fromSingle(foreignInnerNullifier);
524
+ const contractAddress = addressFromSingle(foreignContractAddress);
525
+
526
+ const isPending = await this.handlerAsPrivate().privateIsNullifierPending(innerNullifier, contractAddress);
527
+
528
+ return toForeignCallResult([toSingle(new Fr(isPending))]);
529
+ }
530
+
477
531
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
478
532
  const innerNullifier = fromSingle(foreignInnerNullifier);
479
533
 
@@ -498,12 +552,23 @@ export class RPCTranslator {
498
552
  );
499
553
  }
500
554
 
501
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
555
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
502
556
  const address = addressFromSingle(foreignAddress);
503
557
 
504
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
558
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
505
559
 
506
- 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
+ }
507
572
  }
508
573
 
509
574
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -526,17 +591,14 @@ export class RPCTranslator {
526
591
  );
527
592
  }
528
593
 
529
- async utilityGetNullifierMembershipWitness(
530
- foreignBlockNumber: ForeignCallSingle,
531
- foreignNullifier: ForeignCallSingle,
532
- ) {
533
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
594
+ async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
595
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
534
596
  const nullifier = fromSingle(foreignNullifier);
535
597
 
536
- const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockNumber, nullifier);
598
+ const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
537
599
 
538
600
  if (!witness) {
539
- throw new Error(`Nullifier membership witness not found at block ${blockNumber}.`);
601
+ throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
540
602
  }
541
603
  return toForeignCallResult(witness.toNoirRepresentation());
542
604
  }
@@ -580,8 +642,8 @@ export class RPCTranslator {
580
642
  return toForeignCallResult([toSingle(new Fr(isRevertible))]);
581
643
  }
582
644
 
583
- async utilityGetUtilityContext() {
584
- const context = await this.handlerAsUtility().utilityGetUtilityContext();
645
+ utilityGetUtilityContext() {
646
+ const context = this.handlerAsUtility().utilityGetUtilityContext();
585
647
 
586
648
  return toForeignCallResult(context.toNoirRepresentation());
587
649
  }
@@ -597,36 +659,49 @@ export class RPCTranslator {
597
659
  return toForeignCallResult(header.toFields().map(toSingle));
598
660
  }
599
661
 
600
- async utilityGetMembershipWitness(
601
- foreignBlockNumber: ForeignCallSingle,
602
- foreignTreeId: ForeignCallSingle,
603
- foreignLeafValue: ForeignCallSingle,
662
+ async utilityGetNoteHashMembershipWitness(
663
+ foreignAnchorBlockHash: ForeignCallSingle,
664
+ foreignNoteHash: ForeignCallSingle,
604
665
  ) {
605
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
606
- const treeId = fromSingle(foreignTreeId).toNumber();
607
- const leafValue = fromSingle(foreignLeafValue);
666
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
667
+ const noteHash = fromSingle(foreignNoteHash);
608
668
 
609
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockNumber, treeId, leafValue);
669
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
670
+
671
+ if (!witness) {
672
+ throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
673
+ }
674
+ return toForeignCallResult(witness.toNoirRepresentation());
675
+ }
676
+
677
+ async utilityGetBlockHashMembershipWitness(
678
+ foreignAnchorBlockHash: ForeignCallSingle,
679
+ foreignBlockHash: ForeignCallSingle,
680
+ ) {
681
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
682
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
683
+
684
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
610
685
 
611
686
  if (!witness) {
612
687
  throw new Error(
613
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockNumber}.`,
688
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
614
689
  );
615
690
  }
616
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
691
+ return toForeignCallResult(witness.toNoirRepresentation());
617
692
  }
618
693
 
619
694
  async utilityGetLowNullifierMembershipWitness(
620
- foreignBlockNumber: ForeignCallSingle,
695
+ foreignBlockHash: ForeignCallSingle,
621
696
  foreignNullifier: ForeignCallSingle,
622
697
  ) {
623
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
698
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
624
699
  const nullifier = fromSingle(foreignNullifier);
625
700
 
626
- const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockNumber, nullifier);
701
+ const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
627
702
 
628
703
  if (!witness) {
629
- throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockNumber}.`);
704
+ throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockHash}.`);
630
705
  }
631
706
  return toForeignCallResult(witness.toNoirRepresentation());
632
707
  }
@@ -639,7 +714,7 @@ export class RPCTranslator {
639
714
  return toForeignCallResult([]);
640
715
  }
641
716
 
642
- public async utilityValidateEnqueuedNotesAndEvents(
717
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
643
718
  foreignContractAddress: ForeignCallSingle,
644
719
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
645
720
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -648,7 +723,7 @@ export class RPCTranslator {
648
723
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
649
724
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
650
725
 
651
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
726
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
652
727
  contractAddress,
653
728
  noteValidationRequestsArrayBaseSlot,
654
729
  eventValidationRequestsArrayBaseSlot,
@@ -781,15 +856,16 @@ export class RPCTranslator {
781
856
 
782
857
  // AVM opcodes
783
858
 
784
- avmOpcodeEmitUnencryptedLog(_foreignMessage: ForeignCallArray) {
859
+ avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
785
860
  // TODO(#8811): Implement
786
861
  return toForeignCallResult([]);
787
862
  }
788
863
 
789
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
864
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
790
865
  const slot = fromSingle(foreignSlot);
866
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
791
867
 
792
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
868
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
793
869
 
794
870
  return toForeignCallResult([toSingle(new Fr(value))]);
795
871
  }
@@ -861,11 +937,10 @@ export class RPCTranslator {
861
937
  return toForeignCallResult([]);
862
938
  }
863
939
 
864
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
865
- const innerNullifier = fromSingle(foreignInnerNullifier);
866
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
940
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
941
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
867
942
 
868
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
943
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
869
944
 
870
945
  return toForeignCallResult([toSingle(new Fr(exists))]);
871
946
  }
@@ -970,12 +1045,15 @@ export class RPCTranslator {
970
1045
  args,
971
1046
  argsHash,
972
1047
  isStaticCall,
1048
+ this.stateHandler.getCurrentJob(),
973
1049
  );
974
1050
 
1051
+ // TODO(F-335): Avoid doing the following call here.
1052
+ await this.stateHandler.cycleJob();
975
1053
  return toForeignCallResult([toArray(returnValues)]);
976
1054
  }
977
1055
 
978
- async txeSimulateUtilityFunction(
1056
+ async txeExecuteUtilityFunction(
979
1057
  foreignTargetContractAddress: ForeignCallSingle,
980
1058
  foreignFunctionSelector: ForeignCallSingle,
981
1059
  foreignArgs: ForeignCallArray,
@@ -984,12 +1062,15 @@ export class RPCTranslator {
984
1062
  const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
985
1063
  const args = fromArray(foreignArgs);
986
1064
 
987
- const returnValues = await this.handlerAsTxe().txeSimulateUtilityFunction(
1065
+ const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
988
1066
  targetContractAddress,
989
1067
  functionSelector,
990
1068
  args,
1069
+ this.stateHandler.getCurrentJob(),
991
1070
  );
992
1071
 
1072
+ // TODO(F-335): Avoid doing the following call here.
1073
+ await this.stateHandler.cycleJob();
993
1074
  return toForeignCallResult([toArray(returnValues)]);
994
1075
  }
995
1076
 
@@ -1006,6 +1087,8 @@ export class RPCTranslator {
1006
1087
 
1007
1088
  const returnValues = await this.handlerAsTxe().txePublicCallNewFlow(from, address, calldata, isStaticCall);
1008
1089
 
1090
+ // TODO(F-335): Avoid doing the following call here.
1091
+ await this.stateHandler.cycleJob();
1009
1092
  return toForeignCallResult([toArray(returnValues)]);
1010
1093
  }
1011
1094
 
@@ -1,165 +1,97 @@
1
- import { ArchiverStoreHelper, KVArchiverDataStore, type PublishedL2Block } from '@aztec/archiver';
1
+ import { ArchiverDataSourceBase, ArchiverDataStoreUpdater, KVArchiverDataStore } from '@aztec/archiver';
2
2
  import { GENESIS_ARCHIVE_ROOT } from '@aztec/constants';
3
- import { BlockNumber, CheckpointNumber, EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
+ import { CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import type { EthAddress } from '@aztec/foundation/eth-address';
6
6
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
7
- import type { AztecAddress } from '@aztec/stdlib/aztec-address';
8
- import type { L2Block, L2BlockSource, L2Tips, ValidateBlockResult } from '@aztec/stdlib/block';
9
- import type { Checkpoint, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
10
- import type { ContractInstanceWithAddress } from '@aztec/stdlib/contract';
7
+ import type { CheckpointId, L2BlockId, L2TipId, L2Tips, ValidateCheckpointResult } from '@aztec/stdlib/block';
8
+ import type { PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
11
9
  import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
12
- import type { BlockHeader } from '@aztec/stdlib/tx';
13
- import type { UInt64 } from '@aztec/stdlib/types';
14
10
 
15
- // We are extending the ArchiverDataStoreHelper here because it provides most of the endpoints needed by the
16
- // node for reading from and writing to state, without needing any of the extra overhead that the Archiver itself
17
- // requires (i.e. an L1 client)
18
- export class TXEArchiver extends ArchiverStoreHelper implements L2BlockSource {
19
- constructor(db: AztecAsyncKVStore) {
20
- super(new KVArchiverDataStore(db, 9999));
21
- }
22
-
23
- public override async addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
24
- const opResults = await Promise.all([
25
- this.store.addLogs(blocks.map(block => block.block)),
26
- this.store.addBlocks(blocks),
27
- ]);
28
-
29
- return opResults.every(Boolean);
30
- }
31
-
32
- /**
33
- * Gets the number of the latest L2 block processed by the block source implementation.
34
- * @returns The number of the latest L2 block processed by the block source implementation.
35
- */
36
- public getBlockNumber(): Promise<BlockNumber> {
37
- return this.store.getSynchedL2BlockNumber();
38
- }
11
+ /**
12
+ * TXE Archiver implementation.
13
+ * Provides most of the endpoints needed by the node for reading from and writing to state,
14
+ * without needing any of the extra overhead that the Archiver itself requires (i.e. an L1 client).
15
+ */
16
+ export class TXEArchiver extends ArchiverDataSourceBase {
17
+ private readonly updater = new ArchiverDataStoreUpdater(this.store);
39
18
 
40
- /**
41
- * Gets the number of the latest L2 block proven seen by the block source implementation.
42
- * @returns The number of the latest L2 block proven seen by the block source implementation.
43
- */
44
- public getProvenBlockNumber(): Promise<BlockNumber> {
45
- return this.store.getSynchedL2BlockNumber();
46
- }
47
-
48
- /**
49
- * Gets a published l2 block. If a negative number is passed, the block returned is the most recent.
50
- * @param number - The block number to return (inclusive).
51
- * @returns The requested L2 block.
52
- */
53
- public override async getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
54
- // If the number provided is -ve, then return the latest block.
55
- if (number < 0) {
56
- number = await this.store.getSynchedL2BlockNumber();
57
- }
58
- if (number == 0) {
59
- return undefined;
60
- }
61
- const blocks = await this.store.getPublishedBlocks(BlockNumber(number), 1);
62
- return blocks.length === 0 ? undefined : blocks[0];
19
+ constructor(db: AztecAsyncKVStore) {
20
+ const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
21
+ super(store);
63
22
  }
64
23
 
65
- /**
66
- * Gets an l2 block. If a negative number is passed, the block returned is the most recent.
67
- * @param number - The block number to return (inclusive).
68
- * @returns The requested L2 block.
69
- */
70
- public getBlock(number: number | 'latest'): Promise<L2Block | undefined> {
71
- return this.getPublishedBlock(number != 'latest' ? number : -1).then(block => block?.block);
24
+ public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
25
+ await this.updater.addCheckpoints(checkpoints, result);
72
26
  }
73
27
 
74
- /**
75
- * Gets an l2 block header.
76
- * @param number - The block number to return or 'latest' for the most recent one.
77
- * @returns The requested L2 block header.
78
- */
79
- public async getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
80
- if (number === 'latest') {
81
- number = await this.store.getSynchedL2BlockNumber();
82
- }
83
- if (number === 0) {
84
- return undefined;
85
- }
86
- const headers = await this.store.getBlockHeaders(BlockNumber(number), 1);
87
- return headers.length === 0 ? undefined : headers[0];
28
+ public getRollupAddress(): Promise<EthAddress> {
29
+ throw new Error('TXE Archiver does not implement "getRollupAddress"');
88
30
  }
89
31
 
90
- public getBlocks(from: number, limit: number, _proven?: boolean): Promise<L2Block[]> {
91
- return this.getPublishedBlocks(BlockNumber(from), limit).then(blocks => blocks.map(b => b.block));
32
+ public getRegistryAddress(): Promise<EthAddress> {
33
+ throw new Error('TXE Archiver does not implement "getRegistryAddress"');
92
34
  }
93
35
 
94
- public getPublishedCheckpoints(_from: CheckpointNumber, _limit: number): Promise<PublishedCheckpoint[]> {
95
- throw new Error('TXE Archiver does not implement "getPublishedCheckpoints"');
36
+ public getL1Constants(): Promise<L1RollupConstants> {
37
+ throw new Error('TXE Archiver does not implement "getL1Constants"');
96
38
  }
97
39
 
98
- public getCheckpointByArchive(_archive: Fr): Promise<Checkpoint | undefined> {
99
- throw new Error('TXE Archiver does not implement "getCheckpointByArchive"');
40
+ public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
41
+ return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
100
42
  }
101
43
 
102
- public getL2SlotNumber(): Promise<SlotNumber | undefined> {
103
- throw new Error('TXE Archiver does not implement "getL2SlotNumber"');
44
+ public getL1Timestamp(): Promise<bigint | undefined> {
45
+ throw new Error('TXE Archiver does not implement "getL1Timestamp"');
104
46
  }
105
47
 
106
- public getL2EpochNumber(): Promise<EpochNumber> {
107
- throw new Error('TXE Archiver does not implement "getL2EpochNumber"');
108
- }
48
+ public async getL2Tips(): Promise<L2Tips> {
49
+ // In TXE there is no possibility of reorgs and no blocks are ever getting proven so we just set 'latest', 'proven'
50
+ // and 'finalized' to the latest block.
51
+ const blockHeader = await this.getBlockHeader('latest');
52
+ if (!blockHeader) {
53
+ throw new Error('L2Tips requested from TXE Archiver but no block header found');
54
+ }
109
55
 
110
- public getCheckpointsForEpoch(_epochNumber: EpochNumber): Promise<Checkpoint[]> {
111
- throw new Error('TXE Archiver does not implement "getCheckpointsForEpoch"');
56
+ const number = blockHeader.globalVariables.blockNumber;
57
+ const hash = (await blockHeader.hash()).toString();
58
+ const checkpointedBlock = await this.getCheckpointedBlock(number);
59
+ if (!checkpointedBlock) {
60
+ throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
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.
64
+ const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
65
+ if (checkpoint.length === 0) {
66
+ throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
67
+ }
68
+ const blockId: L2BlockId = { number, hash };
69
+ const checkpointId: CheckpointId = {
70
+ number: checkpoint[0].checkpointNumber,
71
+ hash: checkpoint[0].header.hash().toString(),
72
+ };
73
+ const tipId: L2TipId = { block: blockId, checkpoint: checkpointId };
74
+ return {
75
+ proposed: blockId,
76
+ proven: tipId,
77
+ finalized: tipId,
78
+ checkpointed: tipId,
79
+ };
112
80
  }
113
81
 
114
- public getBlocksForEpoch(_epochNumber: EpochNumber): Promise<L2Block[]> {
115
- throw new Error('TXE Archiver does not implement "getBlocksForEpoch"');
82
+ public getSyncedL2SlotNumber(): Promise<SlotNumber | undefined> {
83
+ throw new Error('TXE Archiver does not implement "getSyncedL2SlotNumber"');
116
84
  }
117
85
 
118
- public getBlockHeadersForEpoch(_epochNumber: EpochNumber): Promise<BlockHeader[]> {
119
- throw new Error('TXE Archiver does not implement "getBlockHeadersForEpoch"');
86
+ public getSyncedL2EpochNumber(): Promise<EpochNumber | undefined> {
87
+ throw new Error('TXE Archiver does not implement "getSyncedL2EpochNumber"');
120
88
  }
121
89
 
122
90
  public isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
123
91
  throw new Error('TXE Archiver does not implement "isEpochComplete"');
124
92
  }
125
93
 
126
- public getL2Tips(): Promise<L2Tips> {
127
- throw new Error('TXE Archiver does not implement "getL2Tips"');
128
- }
129
-
130
- public getL1Constants(): Promise<L1RollupConstants> {
131
- throw new Error('TXE Archiver does not implement "getL2Constants"');
132
- }
133
-
134
- public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
135
- return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
136
- }
137
-
138
94
  public syncImmediate(): Promise<void> {
139
95
  throw new Error('TXE Archiver does not implement "syncImmediate"');
140
96
  }
141
-
142
- public getContract(_address: AztecAddress, _timestamp?: UInt64): Promise<ContractInstanceWithAddress | undefined> {
143
- throw new Error('TXE Archiver does not implement "getContract"');
144
- }
145
-
146
- public getRollupAddress(): Promise<EthAddress> {
147
- throw new Error('TXE Archiver does not implement "getRollupAddress"');
148
- }
149
-
150
- public getRegistryAddress(): Promise<EthAddress> {
151
- throw new Error('TXE Archiver does not implement "getRegistryAddress"');
152
- }
153
-
154
- public getL1Timestamp(): Promise<bigint> {
155
- throw new Error('TXE Archiver does not implement "getL1Timestamp"');
156
- }
157
-
158
- public isPendingChainInvalid(): Promise<boolean> {
159
- return Promise.resolve(false);
160
- }
161
-
162
- public override getPendingChainValidationStatus(): Promise<ValidateBlockResult> {
163
- return Promise.resolve({ valid: true });
164
- }
165
97
  }