@aztec/txe 3.0.3 → 4.0.0-devnet.1-patch.0

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 (77) 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 +6 -4
  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 +20 -11
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +117 -61
  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 +108 -53
  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 +62 -103
  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/txe_session.d.ts +17 -9
  36. package/dest/txe_session.d.ts.map +1 -1
  37. package/dest/txe_session.js +94 -45
  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_contract_store.d.ts +12 -0
  44. package/dest/util/txe_contract_store.d.ts.map +1 -0
  45. package/dest/util/{txe_contract_data_provider.js → txe_contract_store.js} +3 -3
  46. package/dest/util/txe_public_contract_data_source.d.ts +4 -4
  47. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  48. package/dest/util/txe_public_contract_data_source.js +10 -10
  49. package/dest/utils/block_creation.d.ts +18 -4
  50. package/dest/utils/block_creation.d.ts.map +1 -1
  51. package/dest/utils/block_creation.js +37 -3
  52. package/dest/utils/tx_effect_creation.d.ts +2 -3
  53. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  54. package/dest/utils/tx_effect_creation.js +3 -6
  55. package/package.json +16 -16
  56. package/src/constants.ts +3 -0
  57. package/src/index.ts +15 -12
  58. package/src/oracle/interfaces.ts +5 -3
  59. package/src/oracle/txe_oracle_public_context.ts +9 -16
  60. package/src/oracle/txe_oracle_top_level_context.ts +187 -90
  61. package/src/rpc_translator.ts +123 -55
  62. package/src/state_machine/archiver.ts +58 -126
  63. package/src/state_machine/dummy_p2p_client.ts +40 -27
  64. package/src/state_machine/global_variable_builder.ts +19 -2
  65. package/src/state_machine/index.ts +60 -22
  66. package/src/state_machine/mock_epoch_cache.ts +15 -11
  67. package/src/state_machine/synchronizer.ts +2 -2
  68. package/src/txe_session.ts +188 -78
  69. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  70. package/src/util/{txe_contract_data_provider.ts → txe_contract_store.ts} +3 -3
  71. package/src/util/txe_public_contract_data_source.ts +9 -9
  72. package/src/utils/block_creation.ts +47 -14
  73. package/src/utils/tx_effect_creation.ts +3 -11
  74. package/dest/util/txe_account_data_provider.d.ts +0 -10
  75. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  76. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  77. 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,40 +340,40 @@ 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
  }
@@ -354,7 +396,7 @@ export class RPCTranslator {
354
396
  foreignOffset: ForeignCallSingle,
355
397
  foreignStatus: ForeignCallSingle,
356
398
  foreignMaxNotes: ForeignCallSingle,
357
- foreignPackedRetrievedNoteLength: ForeignCallSingle,
399
+ foreignPackedHintedNoteLength: ForeignCallSingle,
358
400
  ) {
359
401
  // Parse Option<AztecAddress>: ownerIsSome is 0 for None, 1 for Some
360
402
  const owner = fromSingle(foreignOwnerIsSome).toBool()
@@ -375,7 +417,7 @@ export class RPCTranslator {
375
417
  const offset = fromSingle(foreignOffset).toNumber();
376
418
  const status = fromSingle(foreignStatus).toNumber();
377
419
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
378
- const packedRetrievedNoteLength = fromSingle(foreignPackedRetrievedNoteLength).toNumber();
420
+ const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
379
421
 
380
422
  const noteDatas = await this.handlerAsUtility().utilityGetNotes(
381
423
  owner,
@@ -396,13 +438,13 @@ export class RPCTranslator {
396
438
  );
397
439
 
398
440
  const returnDataAsArrayOfArrays = noteDatas.map(noteData =>
399
- packAsRetrievedNote({
441
+ packAsHintedNote({
400
442
  contractAddress: noteData.contractAddress,
401
443
  owner: noteData.owner,
402
444
  randomness: noteData.randomness,
403
445
  storageSlot: noteData.storageSlot,
404
446
  noteNonce: noteData.noteNonce,
405
- index: noteData.index,
447
+ isPending: noteData.isPending,
406
448
  note: noteData.note,
407
449
  }),
408
450
  );
@@ -414,11 +456,7 @@ export class RPCTranslator {
414
456
 
415
457
  // At last we convert the array of arrays to a bounded vec of arrays
416
458
  return toForeignCallResult(
417
- arrayOfArraysToBoundedVecOfArrays(
418
- returnDataAsArrayOfForeignCallSingleArrays,
419
- maxNotes,
420
- packedRetrievedNoteLength,
421
- ),
459
+ arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
422
460
  );
423
461
  }
424
462
 
@@ -474,6 +512,15 @@ export class RPCTranslator {
474
512
  return toForeignCallResult([]);
475
513
  }
476
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
+
477
524
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
478
525
  const innerNullifier = fromSingle(foreignInnerNullifier);
479
526
 
@@ -498,12 +545,23 @@ export class RPCTranslator {
498
545
  );
499
546
  }
500
547
 
501
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
548
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
502
549
  const address = addressFromSingle(foreignAddress);
503
550
 
504
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
551
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
505
552
 
506
- 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
+ }
507
565
  }
508
566
 
509
567
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -526,17 +584,14 @@ export class RPCTranslator {
526
584
  );
527
585
  }
528
586
 
529
- async utilityGetNullifierMembershipWitness(
530
- foreignBlockNumber: ForeignCallSingle,
531
- foreignNullifier: ForeignCallSingle,
532
- ) {
533
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
587
+ async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
588
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
534
589
  const nullifier = fromSingle(foreignNullifier);
535
590
 
536
- const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockNumber, nullifier);
591
+ const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
537
592
 
538
593
  if (!witness) {
539
- throw new Error(`Nullifier membership witness not found at block ${blockNumber}.`);
594
+ throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
540
595
  }
541
596
  return toForeignCallResult(witness.toNoirRepresentation());
542
597
  }
@@ -580,8 +635,8 @@ export class RPCTranslator {
580
635
  return toForeignCallResult([toSingle(new Fr(isRevertible))]);
581
636
  }
582
637
 
583
- async utilityGetUtilityContext() {
584
- const context = await this.handlerAsUtility().utilityGetUtilityContext();
638
+ utilityGetUtilityContext() {
639
+ const context = this.handlerAsUtility().utilityGetUtilityContext();
585
640
 
586
641
  return toForeignCallResult(context.toNoirRepresentation());
587
642
  }
@@ -597,36 +652,49 @@ export class RPCTranslator {
597
652
  return toForeignCallResult(header.toFields().map(toSingle));
598
653
  }
599
654
 
600
- async utilityGetMembershipWitness(
601
- foreignBlockNumber: ForeignCallSingle,
602
- foreignTreeId: ForeignCallSingle,
603
- foreignLeafValue: ForeignCallSingle,
655
+ async utilityGetNoteHashMembershipWitness(
656
+ foreignAnchorBlockHash: ForeignCallSingle,
657
+ foreignNoteHash: ForeignCallSingle,
604
658
  ) {
605
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
606
- const treeId = fromSingle(foreignTreeId).toNumber();
607
- const leafValue = fromSingle(foreignLeafValue);
659
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
660
+ const noteHash = fromSingle(foreignNoteHash);
608
661
 
609
- 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);
610
678
 
611
679
  if (!witness) {
612
680
  throw new Error(
613
- `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()}.`,
614
682
  );
615
683
  }
616
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
684
+ return toForeignCallResult(witness.toNoirRepresentation());
617
685
  }
618
686
 
619
687
  async utilityGetLowNullifierMembershipWitness(
620
- foreignBlockNumber: ForeignCallSingle,
688
+ foreignBlockHash: ForeignCallSingle,
621
689
  foreignNullifier: ForeignCallSingle,
622
690
  ) {
623
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
691
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
624
692
  const nullifier = fromSingle(foreignNullifier);
625
693
 
626
- const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockNumber, nullifier);
694
+ const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
627
695
 
628
696
  if (!witness) {
629
- 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}.`);
630
698
  }
631
699
  return toForeignCallResult(witness.toNoirRepresentation());
632
700
  }
@@ -639,7 +707,7 @@ export class RPCTranslator {
639
707
  return toForeignCallResult([]);
640
708
  }
641
709
 
642
- public async utilityValidateEnqueuedNotesAndEvents(
710
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
643
711
  foreignContractAddress: ForeignCallSingle,
644
712
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
645
713
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -648,7 +716,7 @@ export class RPCTranslator {
648
716
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
649
717
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
650
718
 
651
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
719
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
652
720
  contractAddress,
653
721
  noteValidationRequestsArrayBaseSlot,
654
722
  eventValidationRequestsArrayBaseSlot,
@@ -786,10 +854,11 @@ export class RPCTranslator {
786
854
  return toForeignCallResult([]);
787
855
  }
788
856
 
789
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
857
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
790
858
  const slot = fromSingle(foreignSlot);
859
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
791
860
 
792
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
861
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
793
862
 
794
863
  return toForeignCallResult([toSingle(new Fr(value))]);
795
864
  }
@@ -861,11 +930,10 @@ export class RPCTranslator {
861
930
  return toForeignCallResult([]);
862
931
  }
863
932
 
864
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
865
- const innerNullifier = fromSingle(foreignInnerNullifier);
866
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
933
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
934
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
867
935
 
868
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
936
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
869
937
 
870
938
  return toForeignCallResult([toSingle(new Fr(exists))]);
871
939
  }
@@ -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
- }
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
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
  }