@aztec/txe 0.0.1-commit.d3ec352c → 0.0.1-commit.d6f2b3f94

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 (80) 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 +3 -2
  7. package/dest/oracle/interfaces.d.ts +7 -5
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +5 -5
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +10 -12
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +21 -12
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +119 -63
  15. package/dest/rpc_translator.d.ts +27 -15
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +117 -53
  18. package/dest/state_machine/archiver.d.ts +21 -57
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +63 -107
  21. package/dest/state_machine/dummy_p2p_client.d.ts +14 -12
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +29 -21
  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 +40 -23
  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/state_machine/synchronizer.js +2 -2
  36. package/dest/txe_session.d.ts +18 -10
  37. package/dest/txe_session.d.ts.map +1 -1
  38. package/dest/txe_session.js +95 -46
  39. package/dest/util/encoding.d.ts +618 -19
  40. package/dest/util/encoding.d.ts.map +1 -1
  41. package/dest/util/encoding.js +1 -1
  42. package/dest/util/txe_account_store.d.ts +10 -0
  43. package/dest/util/txe_account_store.d.ts.map +1 -0
  44. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  45. package/dest/util/txe_contract_store.d.ts +12 -0
  46. package/dest/util/txe_contract_store.d.ts.map +1 -0
  47. package/dest/util/{txe_contract_data_provider.js → txe_contract_store.js} +3 -3
  48. package/dest/util/txe_public_contract_data_source.d.ts +5 -5
  49. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  50. package/dest/util/txe_public_contract_data_source.js +11 -11
  51. package/dest/utils/block_creation.d.ts +19 -5
  52. package/dest/utils/block_creation.d.ts.map +1 -1
  53. package/dest/utils/block_creation.js +38 -4
  54. package/dest/utils/tx_effect_creation.d.ts +2 -3
  55. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  56. package/dest/utils/tx_effect_creation.js +4 -7
  57. package/package.json +16 -16
  58. package/src/constants.ts +3 -0
  59. package/src/index.ts +15 -12
  60. package/src/oracle/interfaces.ts +6 -4
  61. package/src/oracle/txe_oracle_public_context.ts +10 -17
  62. package/src/oracle/txe_oracle_top_level_context.ts +189 -92
  63. package/src/rpc_translator.ts +138 -56
  64. package/src/state_machine/archiver.ts +59 -131
  65. package/src/state_machine/dummy_p2p_client.ts +40 -27
  66. package/src/state_machine/global_variable_builder.ts +19 -2
  67. package/src/state_machine/index.ts +60 -22
  68. package/src/state_machine/mock_epoch_cache.ts +15 -11
  69. package/src/state_machine/synchronizer.ts +3 -4
  70. package/src/txe_session.ts +189 -79
  71. package/src/util/encoding.ts +1 -1
  72. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  73. package/src/util/{txe_contract_data_provider.ts → txe_contract_store.ts} +3 -3
  74. package/src/util/txe_public_contract_data_source.ts +10 -10
  75. package/src/utils/block_creation.ts +48 -15
  76. package/src/utils/tx_effect_creation.ts +4 -12
  77. package/dest/util/txe_account_data_provider.d.ts +0 -10
  78. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  79. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  80. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
@@ -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 = 12; // This is MAX_MESSAGE_CONTENT_LEN - PRIVATE_EVENT_RESERVED_FIELDS
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,39 @@ 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
+ const events = await this.handlerAsTxe().txeGetPrivateEvents(selector, contractAddress, scope);
289
+
290
+ if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
291
+ throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
292
+ }
293
+
294
+ if (events.some(e => e.length > MAX_EVENT_LEN)) {
295
+ throw new Error(`Some private event has length larger than maxLen ${MAX_EVENT_LEN}`);
296
+ }
297
+
298
+ // This is a workaround as Noir does not currently let us return nested structs with arrays. We instead return a raw
299
+ // multidimensional array in get_private_events_oracle and create the BoundedVecs here.
300
+ const rawArrayStorage = events
301
+ .map(e => e.concat(Array(MAX_EVENT_LEN - e.length).fill(new Fr(0))))
302
+ .concat(Array(MAX_PRIVATE_EVENTS_PER_TXE_QUERY - events.length).fill(Array(MAX_EVENT_LEN).fill(new Fr(0))))
303
+ .flat();
304
+ const eventLengths = events
305
+ .map(e => new Fr(e.length))
306
+ .concat(Array(MAX_PRIVATE_EVENTS_PER_TXE_QUERY - events.length).fill(new Fr(0)));
307
+ const queryLength = new Fr(events.length);
308
+
309
+ return toForeignCallResult([toArray(rawArrayStorage), toArray(eventLengths), toSingle(queryLength)]);
310
+ }
311
+
270
312
  privateStoreInExecutionCache(foreignValues: ForeignCallArray, foreignHash: ForeignCallSingle) {
271
313
  const values = fromArray(foreignValues);
272
314
  const hash = fromSingle(foreignHash);
@@ -286,7 +328,7 @@ export class RPCTranslator {
286
328
 
287
329
  // When the argument is a slice, noir automatically adds a length field to oracle call.
288
330
  // When the argument is an array, we add the field length manually to the signature.
289
- utilityDebugLog(
331
+ async utilityDebugLog(
290
332
  foreignLevel: ForeignCallSingle,
291
333
  foreignMessage: ForeignCallArray,
292
334
  _foreignLength: ForeignCallSingle,
@@ -298,46 +340,47 @@ export class RPCTranslator {
298
340
  .join('');
299
341
  const fields = fromArray(foreignFields);
300
342
 
301
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
343
+ await this.handlerAsMisc().utilityDebugLog(level, message, fields);
302
344
 
303
345
  return toForeignCallResult([]);
304
346
  }
305
347
 
306
348
  async utilityStorageRead(
349
+ foreignBlockHash: ForeignCallSingle,
307
350
  foreignContractAddress: ForeignCallSingle,
308
351
  foreignStartStorageSlot: ForeignCallSingle,
309
- foreignBlockNumber: ForeignCallSingle,
310
352
  foreignNumberOfElements: ForeignCallSingle,
311
353
  ) {
354
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
312
355
  const contractAddress = addressFromSingle(foreignContractAddress);
313
356
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
314
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
315
357
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
316
358
 
317
359
  const values = await this.handlerAsUtility().utilityStorageRead(
360
+ blockHash,
318
361
  contractAddress,
319
362
  startStorageSlot,
320
- blockNumber,
321
363
  numberOfElements,
322
364
  );
323
365
 
324
366
  return toForeignCallResult([toArray(values)]);
325
367
  }
326
368
 
327
- async utilityGetPublicDataWitness(foreignBlockNumber: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
328
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
369
+ async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
370
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
329
371
  const leafSlot = fromSingle(foreignLeafSlot);
330
372
 
331
- const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockNumber, leafSlot);
373
+ const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
332
374
 
333
375
  if (!witness) {
334
- throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockNumber}.`);
376
+ throw new Error(`Public data witness not found for slot ${leafSlot} at block ${blockHash.toString()}.`);
335
377
  }
336
378
  return toForeignCallResult(witness.toNoirRepresentation());
337
379
  }
338
380
 
339
381
  async utilityGetNotes(
340
- foreignOwner: ForeignCallSingle,
382
+ foreignOwnerIsSome: ForeignCallSingle,
383
+ foreignOwnerValue: ForeignCallSingle,
341
384
  foreignStorageSlot: ForeignCallSingle,
342
385
  foreignNumSelects: ForeignCallSingle,
343
386
  foreignSelectByIndexes: ForeignCallArray,
@@ -353,9 +396,12 @@ export class RPCTranslator {
353
396
  foreignOffset: ForeignCallSingle,
354
397
  foreignStatus: ForeignCallSingle,
355
398
  foreignMaxNotes: ForeignCallSingle,
356
- foreignPackedRetrievedNoteLength: ForeignCallSingle,
399
+ foreignPackedHintedNoteLength: ForeignCallSingle,
357
400
  ) {
358
- const owner = addressFromSingle(foreignOwner);
401
+ // Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
402
+ const owner = fromSingle(foreignOwnerIsSome).toBool()
403
+ ? AztecAddress.fromField(fromSingle(foreignOwnerValue))
404
+ : undefined;
359
405
  const storageSlot = fromSingle(foreignStorageSlot);
360
406
  const numSelects = fromSingle(foreignNumSelects).toNumber();
361
407
  const selectByIndexes = fromArray(foreignSelectByIndexes).map(fr => fr.toNumber());
@@ -371,7 +417,7 @@ export class RPCTranslator {
371
417
  const offset = fromSingle(foreignOffset).toNumber();
372
418
  const status = fromSingle(foreignStatus).toNumber();
373
419
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
374
- const packedRetrievedNoteLength = fromSingle(foreignPackedRetrievedNoteLength).toNumber();
420
+ const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
375
421
 
376
422
  const noteDatas = await this.handlerAsUtility().utilityGetNotes(
377
423
  owner,
@@ -391,7 +437,17 @@ export class RPCTranslator {
391
437
  status,
392
438
  );
393
439
 
394
- const returnDataAsArrayOfArrays = noteDatas.map(packAsRetrievedNote);
440
+ const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
441
+ packAsHintedNote({
442
+ contractAddress: noteData.contractAddress,
443
+ owner: noteData.owner,
444
+ randomness: noteData.randomness,
445
+ storageSlot: noteData.storageSlot,
446
+ noteNonce: noteData.noteNonce,
447
+ isPending: noteData.isPending,
448
+ note: noteData.note,
449
+ }),
450
+ );
395
451
 
396
452
  // Now we convert each sub-array to an array of ForeignCallSingles
397
453
  const returnDataAsArrayOfForeignCallSingleArrays = returnDataAsArrayOfArrays.map(subArray =>
@@ -400,11 +456,7 @@ export class RPCTranslator {
400
456
 
401
457
  // At last we convert the array of arrays to a bounded vec of arrays
402
458
  return toForeignCallResult(
403
- arrayOfArraysToBoundedVecOfArrays(
404
- returnDataAsArrayOfForeignCallSingleArrays,
405
- maxNotes,
406
- packedRetrievedNoteLength,
407
- ),
459
+ arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
408
460
  );
409
461
  }
410
462
 
@@ -460,6 +512,15 @@ export class RPCTranslator {
460
512
  return toForeignCallResult([]);
461
513
  }
462
514
 
515
+ async privateIsNullifierPending(foreignInnerNullifier: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
516
+ const innerNullifier = fromSingle(foreignInnerNullifier);
517
+ const contractAddress = addressFromSingle(foreignContractAddress);
518
+
519
+ const isPending = await this.handlerAsPrivate().privateIsNullifierPending(innerNullifier, contractAddress);
520
+
521
+ return toForeignCallResult([toSingle(new Fr(isPending))]);
522
+ }
523
+
463
524
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
464
525
  const innerNullifier = fromSingle(foreignInnerNullifier);
465
526
 
@@ -484,12 +545,23 @@ export class RPCTranslator {
484
545
  );
485
546
  }
486
547
 
487
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
548
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
488
549
  const address = addressFromSingle(foreignAddress);
489
550
 
490
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
551
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
491
552
 
492
- return toForeignCallResult([toArray([...publicKeys.toFields(), partialAddress])]);
553
+ // We are going to return a Noir Option struct to represent the possibility of null values. Options are a struct
554
+ // with two fields: `some` (a boolean) and `value` (a field array in this case).
555
+ if (result === undefined) {
556
+ // No data was found so we set `some` to 0 and pad `value` with zeros get the correct return size.
557
+ return toForeignCallResult([toSingle(new Fr(0)), toArray(Array(13).fill(new Fr(0)))]);
558
+ } else {
559
+ // Data was found so we set `some` to 1 and return it along with `value`.
560
+ return toForeignCallResult([
561
+ toSingle(new Fr(1)),
562
+ toArray([...result.publicKeys.toFields(), result.partialAddress]),
563
+ ]);
564
+ }
493
565
  }
494
566
 
495
567
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -512,17 +584,14 @@ export class RPCTranslator {
512
584
  );
513
585
  }
514
586
 
515
- async utilityGetNullifierMembershipWitness(
516
- foreignBlockNumber: ForeignCallSingle,
517
- foreignNullifier: ForeignCallSingle,
518
- ) {
519
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
587
+ async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
588
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
520
589
  const nullifier = fromSingle(foreignNullifier);
521
590
 
522
- const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockNumber, nullifier);
591
+ const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
523
592
 
524
593
  if (!witness) {
525
- throw new Error(`Nullifier membership witness not found at block ${blockNumber}.`);
594
+ throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
526
595
  }
527
596
  return toForeignCallResult(witness.toNoirRepresentation());
528
597
  }
@@ -566,8 +635,8 @@ export class RPCTranslator {
566
635
  return toForeignCallResult([toSingle(new Fr(isRevertible))]);
567
636
  }
568
637
 
569
- async utilityGetUtilityContext() {
570
- const context = await this.handlerAsUtility().utilityGetUtilityContext();
638
+ utilityGetUtilityContext() {
639
+ const context = this.handlerAsUtility().utilityGetUtilityContext();
571
640
 
572
641
  return toForeignCallResult(context.toNoirRepresentation());
573
642
  }
@@ -583,36 +652,49 @@ export class RPCTranslator {
583
652
  return toForeignCallResult(header.toFields().map(toSingle));
584
653
  }
585
654
 
586
- async utilityGetMembershipWitness(
587
- foreignBlockNumber: ForeignCallSingle,
588
- foreignTreeId: ForeignCallSingle,
589
- foreignLeafValue: ForeignCallSingle,
655
+ async utilityGetNoteHashMembershipWitness(
656
+ foreignAnchorBlockHash: ForeignCallSingle,
657
+ foreignNoteHash: ForeignCallSingle,
590
658
  ) {
591
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
592
- const treeId = fromSingle(foreignTreeId).toNumber();
593
- const leafValue = fromSingle(foreignLeafValue);
659
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
660
+ const noteHash = fromSingle(foreignNoteHash);
594
661
 
595
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockNumber, treeId, leafValue);
662
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
663
+
664
+ if (!witness) {
665
+ throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
666
+ }
667
+ return toForeignCallResult(witness.toNoirRepresentation());
668
+ }
669
+
670
+ async utilityGetBlockHashMembershipWitness(
671
+ foreignAnchorBlockHash: ForeignCallSingle,
672
+ foreignBlockHash: ForeignCallSingle,
673
+ ) {
674
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
675
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
676
+
677
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
596
678
 
597
679
  if (!witness) {
598
680
  throw new Error(
599
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockNumber}.`,
681
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
600
682
  );
601
683
  }
602
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
684
+ return toForeignCallResult(witness.toNoirRepresentation());
603
685
  }
604
686
 
605
687
  async utilityGetLowNullifierMembershipWitness(
606
- foreignBlockNumber: ForeignCallSingle,
688
+ foreignBlockHash: ForeignCallSingle,
607
689
  foreignNullifier: ForeignCallSingle,
608
690
  ) {
609
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
691
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
610
692
  const nullifier = fromSingle(foreignNullifier);
611
693
 
612
- const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockNumber, nullifier);
694
+ const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
613
695
 
614
696
  if (!witness) {
615
- throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockNumber}.`);
697
+ throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockHash}.`);
616
698
  }
617
699
  return toForeignCallResult(witness.toNoirRepresentation());
618
700
  }
@@ -625,7 +707,7 @@ export class RPCTranslator {
625
707
  return toForeignCallResult([]);
626
708
  }
627
709
 
628
- public async utilityValidateEnqueuedNotesAndEvents(
710
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
629
711
  foreignContractAddress: ForeignCallSingle,
630
712
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
631
713
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -634,7 +716,7 @@ export class RPCTranslator {
634
716
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
635
717
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
636
718
 
637
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
719
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
638
720
  contractAddress,
639
721
  noteValidationRequestsArrayBaseSlot,
640
722
  eventValidationRequestsArrayBaseSlot,
@@ -772,10 +854,11 @@ export class RPCTranslator {
772
854
  return toForeignCallResult([]);
773
855
  }
774
856
 
775
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
857
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
776
858
  const slot = fromSingle(foreignSlot);
859
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
777
860
 
778
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
861
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
779
862
 
780
863
  return toForeignCallResult([toSingle(new Fr(value))]);
781
864
  }
@@ -847,11 +930,10 @@ export class RPCTranslator {
847
930
  return toForeignCallResult([]);
848
931
  }
849
932
 
850
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
851
- const innerNullifier = fromSingle(foreignInnerNullifier);
852
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
933
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
934
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
853
935
 
854
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
936
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
855
937
 
856
938
  return toForeignCallResult([toSingle(new Fr(exists))]);
857
939
  }
@@ -1,169 +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
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import type { EthAddress } from '@aztec/foundation/eth-address';
5
- import { Fr } from '@aztec/foundation/fields';
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
- }
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);
22
18
 
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);
19
+ constructor(db: AztecAsyncKVStore) {
20
+ const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
21
+ super(store);
30
22
  }
31
23
 
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();
24
+ public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
25
+ await this.updater.addCheckpoints(checkpoints, result);
38
26
  }
39
27
 
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();
28
+ public getRollupAddress(): Promise<EthAddress> {
29
+ throw new Error('TXE Archiver does not implement "getRollupAddress"');
46
30
  }
47
31
 
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];
32
+ public getRegistryAddress(): Promise<EthAddress> {
33
+ throw new Error('TXE Archiver does not implement "getRegistryAddress"');
63
34
  }
64
35
 
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);
36
+ public getL1Constants(): Promise<L1RollupConstants> {
37
+ throw new Error('TXE Archiver does not implement "getL1Constants"');
72
38
  }
73
39
 
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];
40
+ public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
41
+ return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
88
42
  }
89
43
 
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));
44
+ public getL1Timestamp(): Promise<bigint | undefined> {
45
+ throw new Error('TXE Archiver does not implement "getL1Timestamp"');
92
46
  }
93
47
 
94
- public getPublishedCheckpoints(_from: CheckpointNumber, _limit: number): Promise<PublishedCheckpoint[]> {
95
- throw new Error('TXE Archiver does not implement "getPublishedCheckpoints"');
96
- }
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
+ }
97
55
 
98
- public getCheckpointByArchive(_archive: Fr): Promise<Checkpoint | undefined> {
99
- throw new Error('TXE Archiver does not implement "getCheckpointByArchive"');
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
+ };
100
80
  }
101
81
 
102
82
  public getL2SlotNumber(): Promise<SlotNumber | undefined> {
103
83
  throw new Error('TXE Archiver does not implement "getL2SlotNumber"');
104
84
  }
105
85
 
106
- public getL2EpochNumber(): Promise<EpochNumber> {
86
+ public getL2EpochNumber(): Promise<EpochNumber | undefined> {
107
87
  throw new Error('TXE Archiver does not implement "getL2EpochNumber"');
108
88
  }
109
89
 
110
- public getCheckpointsForEpoch(_epochNumber: EpochNumber): Promise<Checkpoint[]> {
111
- throw new Error('TXE Archiver does not implement "getCheckpointsForEpoch"');
112
- }
113
-
114
- public getBlocksForEpoch(_epochNumber: EpochNumber): Promise<L2Block[]> {
115
- throw new Error('TXE Archiver does not implement "getBlocksForEpoch"');
116
- }
117
-
118
- public getBlockHeadersForEpoch(_epochNumber: EpochNumber): Promise<BlockHeader[]> {
119
- throw new Error('TXE Archiver does not implement "getBlockHeadersForEpoch"');
120
- }
121
-
122
- public getL1ToL2MessagesForCheckpoint(_checkpointNumber: CheckpointNumber): Promise<Fr[]> {
123
- throw new Error('TXE Archiver does not implement "getL1ToL2MessagesForCheckpoint"');
124
- }
125
-
126
90
  public isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
127
91
  throw new Error('TXE Archiver does not implement "isEpochComplete"');
128
92
  }
129
93
 
130
- public getL2Tips(): Promise<L2Tips> {
131
- throw new Error('TXE Archiver does not implement "getL2Tips"');
132
- }
133
-
134
- public getL1Constants(): Promise<L1RollupConstants> {
135
- throw new Error('TXE Archiver does not implement "getL2Constants"');
136
- }
137
-
138
- public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
139
- return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
140
- }
141
-
142
94
  public syncImmediate(): Promise<void> {
143
95
  throw new Error('TXE Archiver does not implement "syncImmediate"');
144
96
  }
145
-
146
- public getContract(_address: AztecAddress, _timestamp?: UInt64): Promise<ContractInstanceWithAddress | undefined> {
147
- throw new Error('TXE Archiver does not implement "getContract"');
148
- }
149
-
150
- public getRollupAddress(): Promise<EthAddress> {
151
- throw new Error('TXE Archiver does not implement "getRollupAddress"');
152
- }
153
-
154
- public getRegistryAddress(): Promise<EthAddress> {
155
- throw new Error('TXE Archiver does not implement "getRegistryAddress"');
156
- }
157
-
158
- public getL1Timestamp(): Promise<bigint> {
159
- throw new Error('TXE Archiver does not implement "getL1Timestamp"');
160
- }
161
-
162
- public isPendingChainInvalid(): Promise<boolean> {
163
- return Promise.resolve(false);
164
- }
165
-
166
- public override getPendingChainValidationStatus(): Promise<ValidateBlockResult> {
167
- return Promise.resolve({ valid: true });
168
- }
169
97
  }