@aztec/txe 0.0.1-commit.24de95ac → 0.0.1-commit.2e2504e2

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 (83) hide show
  1. package/dest/bin/index.d.ts +1 -1
  2. package/dest/constants.d.ts +3 -0
  3. package/dest/constants.d.ts.map +1 -0
  4. package/dest/constants.js +2 -0
  5. package/dest/index.d.ts +1 -1
  6. package/dest/index.d.ts.map +1 -1
  7. package/dest/index.js +3 -2
  8. package/dest/oracle/interfaces.d.ts +11 -8
  9. package/dest/oracle/interfaces.d.ts.map +1 -1
  10. package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
  11. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  12. package/dest/oracle/txe_oracle_public_context.js +10 -12
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts +22 -12
  14. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  15. package/dest/oracle/txe_oracle_top_level_context.js +128 -79
  16. package/dest/rpc_translator.d.ts +32 -17
  17. package/dest/rpc_translator.d.ts.map +1 -1
  18. package/dest/rpc_translator.js +134 -60
  19. package/dest/state_machine/archiver.d.ts +21 -51
  20. package/dest/state_machine/archiver.d.ts.map +1 -1
  21. package/dest/state_machine/archiver.js +63 -94
  22. package/dest/state_machine/dummy_p2p_client.d.ts +9 -6
  23. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  24. package/dest/state_machine/dummy_p2p_client.js +16 -8
  25. package/dest/state_machine/global_variable_builder.d.ts +6 -4
  26. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  27. package/dest/state_machine/global_variable_builder.js +13 -1
  28. package/dest/state_machine/index.d.ts +7 -7
  29. package/dest/state_machine/index.d.ts.map +1 -1
  30. package/dest/state_machine/index.js +39 -22
  31. package/dest/state_machine/mock_epoch_cache.d.ts +12 -10
  32. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  33. package/dest/state_machine/mock_epoch_cache.js +17 -13
  34. package/dest/state_machine/synchronizer.d.ts +3 -2
  35. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  36. package/dest/state_machine/synchronizer.js +5 -4
  37. package/dest/txe_session.d.ts +21 -13
  38. package/dest/txe_session.d.ts.map +1 -1
  39. package/dest/txe_session.js +101 -49
  40. package/dest/util/encoding.d.ts +615 -16
  41. package/dest/util/encoding.d.ts.map +1 -1
  42. package/dest/util/encoding.js +1 -1
  43. package/dest/util/expected_failure_error.d.ts +1 -1
  44. package/dest/util/expected_failure_error.d.ts.map +1 -1
  45. package/dest/util/txe_account_store.d.ts +10 -0
  46. package/dest/util/txe_account_store.d.ts.map +1 -0
  47. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  48. package/dest/util/txe_contract_store.d.ts +12 -0
  49. package/dest/util/txe_contract_store.d.ts.map +1 -0
  50. package/dest/util/{txe_contract_data_provider.js → txe_contract_store.js} +3 -3
  51. package/dest/util/txe_public_contract_data_source.d.ts +7 -6
  52. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  53. package/dest/util/txe_public_contract_data_source.js +11 -11
  54. package/dest/utils/block_creation.d.ts +21 -6
  55. package/dest/utils/block_creation.d.ts.map +1 -1
  56. package/dest/utils/block_creation.js +38 -4
  57. package/dest/utils/tx_effect_creation.d.ts +3 -3
  58. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  59. package/dest/utils/tx_effect_creation.js +4 -7
  60. package/package.json +18 -17
  61. package/src/constants.ts +3 -0
  62. package/src/index.ts +15 -12
  63. package/src/oracle/interfaces.ts +10 -7
  64. package/src/oracle/txe_oracle_public_context.ts +12 -19
  65. package/src/oracle/txe_oracle_top_level_context.ts +205 -107
  66. package/src/rpc_translator.ts +159 -63
  67. package/src/state_machine/archiver.ts +63 -117
  68. package/src/state_machine/dummy_p2p_client.ts +22 -10
  69. package/src/state_machine/global_variable_builder.ts +22 -4
  70. package/src/state_machine/index.ts +59 -21
  71. package/src/state_machine/mock_epoch_cache.ts +20 -20
  72. package/src/state_machine/synchronizer.ts +6 -5
  73. package/src/txe_session.ts +197 -85
  74. package/src/util/encoding.ts +1 -1
  75. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  76. package/src/util/{txe_contract_data_provider.ts → txe_contract_store.ts} +3 -3
  77. package/src/util/txe_public_contract_data_source.ts +13 -12
  78. package/src/utils/block_creation.ts +49 -14
  79. package/src/utils/tx_effect_creation.ts +5 -12
  80. package/dest/util/txe_account_data_provider.d.ts +0 -10
  81. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  82. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  83. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
@@ -1,15 +1,16 @@
1
1
  import type { ContractInstanceWithAddress } from '@aztec/aztec.js/contracts';
2
2
  import { Fr, Point } from '@aztec/aztec.js/fields';
3
3
  import { MAX_NOTE_HASHES_PER_TX, MAX_NULLIFIERS_PER_TX } from '@aztec/constants';
4
+ import { BlockNumber } from '@aztec/foundation/branded-types';
4
5
  import {
5
6
  type IMiscOracle,
6
7
  type IPrivateExecutionOracle,
7
8
  type IUtilityExecutionOracle,
8
- packAsRetrievedNote,
9
+ packAsHintedNote,
9
10
  } from '@aztec/pxe/simulator';
10
- import { type ContractArtifact, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
11
+ import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
11
12
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
12
- import { MerkleTreeId } from '@aztec/stdlib/trees';
13
+ import { BlockHash } from '@aztec/stdlib/block';
13
14
 
14
15
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
15
16
  import type { TXESessionStateHandler } from './txe_session.js';
@@ -29,6 +30,9 @@ import {
29
30
  toSingle,
30
31
  } from './util/encoding.js';
31
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
+
32
36
  export class UnavailableOracleError extends Error {
33
37
  constructor(oracleName: string) {
34
38
  super(`${oracleName} oracles not available with the current handler`);
@@ -117,7 +121,7 @@ export class RPCTranslator {
117
121
  : undefined;
118
122
 
119
123
  const anchorBlockNumber = fromSingle(foreignAnchorBlockNumberIsSome).toBool()
120
- ? fromSingle(foreignAnchorBlockNumberValue).toNumber()
124
+ ? BlockNumber(fromSingle(foreignAnchorBlockNumberValue).toNumber())
121
125
  : undefined;
122
126
 
123
127
  const privateContextInputs = await this.stateHandler.enterPrivateState(contractAddress, anchorBlockNumber);
@@ -155,6 +159,12 @@ export class RPCTranslator {
155
159
 
156
160
  // TXE-specific oracles
157
161
 
162
+ txeGetDefaultAddress() {
163
+ const defaultAddress = this.handlerAsTxe().txeGetDefaultAddress();
164
+
165
+ return toForeignCallResult([toSingle(defaultAddress)]);
166
+ }
167
+
158
168
  async txeGetNextBlockNumber() {
159
169
  const nextBlockNumber = await this.handlerAsTxe().txeGetNextBlockNumber();
160
170
 
@@ -266,12 +276,40 @@ export class RPCTranslator {
266
276
  ]);
267
277
  }
268
278
 
269
- // Since the argument is a slice, noir automatically adds a length field to oracle call.
270
- privateStoreInExecutionCache(
271
- _foreignLength: ForeignCallSingle,
272
- foreignValues: ForeignCallArray,
273
- foreignHash: ForeignCallSingle,
279
+ async txeGetPrivateEvents(
280
+ foreignSelector: ForeignCallSingle,
281
+ foreignContractAddress: ForeignCallSingle,
282
+ foreignScope: ForeignCallSingle,
274
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
+
312
+ privateStoreInExecutionCache(foreignValues: ForeignCallArray, foreignHash: ForeignCallSingle) {
275
313
  const values = fromArray(foreignValues);
276
314
  const hash = fromSingle(foreignHash);
277
315
 
@@ -308,39 +346,41 @@ export class RPCTranslator {
308
346
  }
309
347
 
310
348
  async utilityStorageRead(
349
+ foreignBlockHash: ForeignCallSingle,
311
350
  foreignContractAddress: ForeignCallSingle,
312
351
  foreignStartStorageSlot: ForeignCallSingle,
313
- foreignBlockNumber: ForeignCallSingle,
314
352
  foreignNumberOfElements: ForeignCallSingle,
315
353
  ) {
354
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
316
355
  const contractAddress = addressFromSingle(foreignContractAddress);
317
356
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
318
- const blockNumber = fromSingle(foreignBlockNumber).toNumber();
319
357
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
320
358
 
321
359
  const values = await this.handlerAsUtility().utilityStorageRead(
360
+ blockHash,
322
361
  contractAddress,
323
362
  startStorageSlot,
324
- blockNumber,
325
363
  numberOfElements,
326
364
  );
327
365
 
328
366
  return toForeignCallResult([toArray(values)]);
329
367
  }
330
368
 
331
- async utilityGetPublicDataWitness(foreignBlockNumber: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
332
- const blockNumber = fromSingle(foreignBlockNumber).toNumber();
369
+ async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
370
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
333
371
  const leafSlot = fromSingle(foreignLeafSlot);
334
372
 
335
- const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockNumber, leafSlot);
373
+ const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
336
374
 
337
375
  if (!witness) {
338
- 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()}.`);
339
377
  }
340
378
  return toForeignCallResult(witness.toNoirRepresentation());
341
379
  }
342
380
 
343
381
  async utilityGetNotes(
382
+ foreignOwnerIsSome: ForeignCallSingle,
383
+ foreignOwnerValue: ForeignCallSingle,
344
384
  foreignStorageSlot: ForeignCallSingle,
345
385
  foreignNumSelects: ForeignCallSingle,
346
386
  foreignSelectByIndexes: ForeignCallArray,
@@ -356,8 +396,12 @@ export class RPCTranslator {
356
396
  foreignOffset: ForeignCallSingle,
357
397
  foreignStatus: ForeignCallSingle,
358
398
  foreignMaxNotes: ForeignCallSingle,
359
- foreignPackedRetrievedNoteLength: ForeignCallSingle,
399
+ foreignPackedHintedNoteLength: ForeignCallSingle,
360
400
  ) {
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;
361
405
  const storageSlot = fromSingle(foreignStorageSlot);
362
406
  const numSelects = fromSingle(foreignNumSelects).toNumber();
363
407
  const selectByIndexes = fromArray(foreignSelectByIndexes).map(fr => fr.toNumber());
@@ -373,9 +417,10 @@ export class RPCTranslator {
373
417
  const offset = fromSingle(foreignOffset).toNumber();
374
418
  const status = fromSingle(foreignStatus).toNumber();
375
419
  const maxNotes = fromSingle(foreignMaxNotes).toNumber();
376
- const packedRetrievedNoteLength = fromSingle(foreignPackedRetrievedNoteLength).toNumber();
420
+ const packedHintedNoteLength = fromSingle(foreignPackedHintedNoteLength).toNumber();
377
421
 
378
422
  const noteDatas = await this.handlerAsUtility().utilityGetNotes(
423
+ owner,
379
424
  storageSlot,
380
425
  numSelects,
381
426
  selectByIndexes,
@@ -392,7 +437,17 @@ export class RPCTranslator {
392
437
  status,
393
438
  );
394
439
 
395
- 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
+ );
396
451
 
397
452
  // Now we convert each sub-array to an array of ForeignCallSingles
398
453
  const returnDataAsArrayOfForeignCallSingleArrays = returnDataAsArrayOfArrays.map(subArray =>
@@ -401,28 +456,36 @@ export class RPCTranslator {
401
456
 
402
457
  // At last we convert the array of arrays to a bounded vec of arrays
403
458
  return toForeignCallResult(
404
- arrayOfArraysToBoundedVecOfArrays(
405
- returnDataAsArrayOfForeignCallSingleArrays,
406
- maxNotes,
407
- packedRetrievedNoteLength,
408
- ),
459
+ arrayOfArraysToBoundedVecOfArrays(returnDataAsArrayOfForeignCallSingleArrays, maxNotes, packedHintedNoteLength),
409
460
  );
410
461
  }
411
462
 
412
463
  privateNotifyCreatedNote(
464
+ foreignOwner: ForeignCallSingle,
413
465
  foreignStorageSlot: ForeignCallSingle,
466
+ foreignRandomness: ForeignCallSingle,
414
467
  foreignNoteTypeId: ForeignCallSingle,
415
468
  foreignNote: ForeignCallArray,
416
469
  foreignNoteHash: ForeignCallSingle,
417
470
  foreignCounter: ForeignCallSingle,
418
471
  ) {
472
+ const owner = addressFromSingle(foreignOwner);
419
473
  const storageSlot = fromSingle(foreignStorageSlot);
474
+ const randomness = fromSingle(foreignRandomness);
420
475
  const noteTypeId = NoteSelector.fromField(fromSingle(foreignNoteTypeId));
421
476
  const note = fromArray(foreignNote);
422
477
  const noteHash = fromSingle(foreignNoteHash);
423
478
  const counter = fromSingle(foreignCounter).toNumber();
424
479
 
425
- this.handlerAsPrivate().privateNotifyCreatedNote(storageSlot, noteTypeId, note, noteHash, counter);
480
+ this.handlerAsPrivate().privateNotifyCreatedNote(
481
+ owner,
482
+ storageSlot,
483
+ randomness,
484
+ noteTypeId,
485
+ note,
486
+ noteHash,
487
+ counter,
488
+ );
426
489
 
427
490
  return toForeignCallResult([]);
428
491
  }
@@ -449,6 +512,15 @@ export class RPCTranslator {
449
512
  return toForeignCallResult([]);
450
513
  }
451
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
+
452
524
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
453
525
  const innerNullifier = fromSingle(foreignInnerNullifier);
454
526
 
@@ -473,12 +545,23 @@ export class RPCTranslator {
473
545
  );
474
546
  }
475
547
 
476
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
548
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
477
549
  const address = addressFromSingle(foreignAddress);
478
550
 
479
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
551
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
480
552
 
481
- 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
+ }
482
565
  }
483
566
 
484
567
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -501,17 +584,14 @@ export class RPCTranslator {
501
584
  );
502
585
  }
503
586
 
504
- async utilityGetNullifierMembershipWitness(
505
- foreignBlockNumber: ForeignCallSingle,
506
- foreignNullifier: ForeignCallSingle,
507
- ) {
508
- const blockNumber = fromSingle(foreignBlockNumber).toNumber();
587
+ async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
588
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
509
589
  const nullifier = fromSingle(foreignNullifier);
510
590
 
511
- const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockNumber, nullifier);
591
+ const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
512
592
 
513
593
  if (!witness) {
514
- throw new Error(`Nullifier membership witness not found at block ${blockNumber}.`);
594
+ throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
515
595
  }
516
596
  return toForeignCallResult(witness.toNoirRepresentation());
517
597
  }
@@ -549,14 +629,20 @@ export class RPCTranslator {
549
629
  throw new Error('Enqueueing public calls is not supported in TestEnvironment::private_context');
550
630
  }
551
631
 
552
- async utilityGetUtilityContext() {
553
- const context = await this.handlerAsUtility().utilityGetUtilityContext();
632
+ public async privateIsSideEffectCounterRevertible(foreignSideEffectCounter: ForeignCallSingle) {
633
+ const sideEffectCounter = fromSingle(foreignSideEffectCounter).toNumber();
634
+ const isRevertible = await this.handlerAsPrivate().privateIsSideEffectCounterRevertible(sideEffectCounter);
635
+ return toForeignCallResult([toSingle(new Fr(isRevertible))]);
636
+ }
637
+
638
+ utilityGetUtilityContext() {
639
+ const context = this.handlerAsUtility().utilityGetUtilityContext();
554
640
 
555
641
  return toForeignCallResult(context.toNoirRepresentation());
556
642
  }
557
643
 
558
644
  async utilityGetBlockHeader(foreignBlockNumber: ForeignCallSingle) {
559
- const blockNumber = fromSingle(foreignBlockNumber).toNumber();
645
+ const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
560
646
 
561
647
  const header = await this.handlerAsUtility().utilityGetBlockHeader(blockNumber);
562
648
 
@@ -566,36 +652,49 @@ export class RPCTranslator {
566
652
  return toForeignCallResult(header.toFields().map(toSingle));
567
653
  }
568
654
 
569
- async utilityGetMembershipWitness(
570
- foreignBlockNumber: ForeignCallSingle,
571
- foreignTreeId: ForeignCallSingle,
572
- foreignLeafValue: ForeignCallSingle,
655
+ async utilityGetNoteHashMembershipWitness(
656
+ foreignAnchorBlockHash: ForeignCallSingle,
657
+ foreignNoteHash: ForeignCallSingle,
573
658
  ) {
574
- const blockNumber = fromSingle(foreignBlockNumber).toNumber();
575
- const treeId = fromSingle(foreignTreeId).toNumber();
576
- const leafValue = fromSingle(foreignLeafValue);
659
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
660
+ const noteHash = fromSingle(foreignNoteHash);
577
661
 
578
- 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);
579
678
 
580
679
  if (!witness) {
581
680
  throw new Error(
582
- `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()}.`,
583
682
  );
584
683
  }
585
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
684
+ return toForeignCallResult(witness.toNoirRepresentation());
586
685
  }
587
686
 
588
687
  async utilityGetLowNullifierMembershipWitness(
589
- foreignBlockNumber: ForeignCallSingle,
688
+ foreignBlockHash: ForeignCallSingle,
590
689
  foreignNullifier: ForeignCallSingle,
591
690
  ) {
592
- const blockNumber = fromSingle(foreignBlockNumber).toNumber();
691
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
593
692
  const nullifier = fromSingle(foreignNullifier);
594
693
 
595
- const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockNumber, nullifier);
694
+ const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
596
695
 
597
696
  if (!witness) {
598
- 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}.`);
599
698
  }
600
699
  return toForeignCallResult(witness.toNoirRepresentation());
601
700
  }
@@ -608,7 +707,7 @@ export class RPCTranslator {
608
707
  return toForeignCallResult([]);
609
708
  }
610
709
 
611
- public async utilityValidateEnqueuedNotesAndEvents(
710
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
612
711
  foreignContractAddress: ForeignCallSingle,
613
712
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
614
713
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -617,7 +716,7 @@ export class RPCTranslator {
617
716
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
618
717
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
619
718
 
620
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
719
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
621
720
  contractAddress,
622
721
  noteValidationRequestsArrayBaseSlot,
623
722
  eventValidationRequestsArrayBaseSlot,
@@ -755,10 +854,11 @@ export class RPCTranslator {
755
854
  return toForeignCallResult([]);
756
855
  }
757
856
 
758
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
857
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
759
858
  const slot = fromSingle(foreignSlot);
859
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
760
860
 
761
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
861
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
762
862
 
763
863
  return toForeignCallResult([toSingle(new Fr(value))]);
764
864
  }
@@ -830,11 +930,10 @@ export class RPCTranslator {
830
930
  return toForeignCallResult([]);
831
931
  }
832
932
 
833
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
834
- const innerNullifier = fromSingle(foreignInnerNullifier);
835
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
933
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
934
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
836
935
 
837
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
936
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
838
937
 
839
938
  return toForeignCallResult([toSingle(new Fr(exists))]);
840
939
  }
@@ -921,7 +1020,6 @@ export class RPCTranslator {
921
1020
  foreignFrom: ForeignCallSingle,
922
1021
  foreignTargetContractAddress: ForeignCallSingle,
923
1022
  foreignFunctionSelector: ForeignCallSingle,
924
- _foreignArgsLength: ForeignCallSingle,
925
1023
  foreignArgs: ForeignCallArray,
926
1024
  foreignArgsHash: ForeignCallSingle,
927
1025
  foreignIsStaticCall: ForeignCallSingle,
@@ -948,7 +1046,6 @@ export class RPCTranslator {
948
1046
  async txeSimulateUtilityFunction(
949
1047
  foreignTargetContractAddress: ForeignCallSingle,
950
1048
  foreignFunctionSelector: ForeignCallSingle,
951
- _foreignArgsLength: ForeignCallSingle,
952
1049
  foreignArgs: ForeignCallArray,
953
1050
  ) {
954
1051
  const targetContractAddress = addressFromSingle(foreignTargetContractAddress);
@@ -967,7 +1064,6 @@ export class RPCTranslator {
967
1064
  async txePublicCallNewFlow(
968
1065
  foreignFrom: ForeignCallSingle,
969
1066
  foreignAddress: ForeignCallSingle,
970
- _foreignLength: ForeignCallSingle,
971
1067
  foreignCalldata: ForeignCallArray,
972
1068
  foreignIsStaticCall: ForeignCallSingle,
973
1069
  ) {
@@ -1,151 +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 { CheckpointNumber, type EpochNumber, type SlotNumber } from '@aztec/foundation/branded-types';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
5
  import type { EthAddress } from '@aztec/foundation/eth-address';
4
- import { Fr } from '@aztec/foundation/fields';
5
6
  import type { AztecAsyncKVStore } from '@aztec/kv-store';
6
- import type { AztecAddress } from '@aztec/stdlib/aztec-address';
7
- import type { L2Block, L2BlockSource, L2Tips, ValidateBlockResult } from '@aztec/stdlib/block';
8
- 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';
9
9
  import type { L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
10
- import type { BlockHeader } from '@aztec/stdlib/tx';
11
- import type { UInt64 } from '@aztec/stdlib/types';
12
10
 
13
- // We are extending the ArchiverDataStoreHelper here because it provides most of the endpoints needed by the
14
- // node for reading from and writing to state, without needing any of the extra overhead that the Archiver itself
15
- // requires (i.e. an L1 client)
16
- export class TXEArchiver extends ArchiverStoreHelper implements L2BlockSource {
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);
18
+
17
19
  constructor(db: AztecAsyncKVStore) {
18
- super(new KVArchiverDataStore(db, 9999));
20
+ const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
21
+ super(store);
19
22
  }
20
23
 
21
- public override async addBlocks(blocks: PublishedL2Block[]): Promise<boolean> {
22
- const opResults = await Promise.all([
23
- this.store.addLogs(blocks.map(block => block.block)),
24
- this.store.addBlocks(blocks),
25
- ]);
26
-
27
- return opResults.every(Boolean);
24
+ public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
25
+ await this.updater.addCheckpoints(checkpoints, result);
28
26
  }
29
27
 
30
- /**
31
- * Gets the number of the latest L2 block processed by the block source implementation.
32
- * @returns The number of the latest L2 block processed by the block source implementation.
33
- */
34
- public getBlockNumber(): Promise<number> {
35
- return this.store.getSynchedL2BlockNumber();
28
+ public getRollupAddress(): Promise<EthAddress> {
29
+ throw new Error('TXE Archiver does not implement "getRollupAddress"');
36
30
  }
37
31
 
38
- /**
39
- * Gets the number of the latest L2 block proven seen by the block source implementation.
40
- * @returns The number of the latest L2 block proven seen by the block source implementation.
41
- */
42
- public getProvenBlockNumber(): Promise<number> {
43
- return this.store.getSynchedL2BlockNumber();
32
+ public getRegistryAddress(): Promise<EthAddress> {
33
+ throw new Error('TXE Archiver does not implement "getRegistryAddress"');
44
34
  }
45
35
 
46
- /**
47
- * Gets a published l2 block. If a negative number is passed, the block returned is the most recent.
48
- * @param number - The block number to return (inclusive).
49
- * @returns The requested L2 block.
50
- */
51
- public override async getPublishedBlock(number: number): Promise<PublishedL2Block | undefined> {
52
- // If the number provided is -ve, then return the latest block.
53
- if (number < 0) {
54
- number = await this.store.getSynchedL2BlockNumber();
55
- }
56
- if (number == 0) {
57
- return undefined;
58
- }
59
- const blocks = await this.store.getPublishedBlocks(number, 1);
60
- return blocks.length === 0 ? undefined : blocks[0];
36
+ public getL1Constants(): Promise<L1RollupConstants> {
37
+ throw new Error('TXE Archiver does not implement "getL1Constants"');
61
38
  }
62
39
 
63
- /**
64
- * Gets an l2 block. If a negative number is passed, the block returned is the most recent.
65
- * @param number - The block number to return (inclusive).
66
- * @returns The requested L2 block.
67
- */
68
- public getBlock(number: number | 'latest'): Promise<L2Block | undefined> {
69
- return this.getPublishedBlock(number != 'latest' ? number : -1).then(block => block?.block);
40
+ public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
41
+ return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
70
42
  }
71
43
 
72
- /**
73
- * Gets an l2 block header.
74
- * @param number - The block number to return or 'latest' for the most recent one.
75
- * @returns The requested L2 block header.
76
- */
77
- public async getBlockHeader(number: number | 'latest'): Promise<BlockHeader | undefined> {
78
- if (number === 'latest') {
79
- number = await this.store.getSynchedL2BlockNumber();
80
- }
81
- if (number === 0) {
82
- return undefined;
83
- }
84
- const headers = await this.store.getBlockHeaders(number, 1);
85
- return headers.length === 0 ? undefined : headers[0];
44
+ public getL1Timestamp(): Promise<bigint | undefined> {
45
+ throw new Error('TXE Archiver does not implement "getL1Timestamp"');
86
46
  }
87
47
 
88
- public getBlocks(from: number, limit: number, _proven?: boolean): Promise<L2Block[]> {
89
- return this.getPublishedBlocks(from, limit).then(blocks => blocks.map(b => b.block));
90
- }
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
+ }
91
55
 
92
- public getL2SlotNumber(): Promise<bigint> {
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
+ };
80
+ }
81
+
82
+ public getL2SlotNumber(): Promise<SlotNumber | undefined> {
93
83
  throw new Error('TXE Archiver does not implement "getL2SlotNumber"');
94
84
  }
95
85
 
96
- public getL2EpochNumber(): Promise<bigint> {
86
+ public getL2EpochNumber(): Promise<EpochNumber | undefined> {
97
87
  throw new Error('TXE Archiver does not implement "getL2EpochNumber"');
98
88
  }
99
89
 
100
- public getBlocksForEpoch(_epochNumber: bigint): Promise<L2Block[]> {
101
- throw new Error('TXE Archiver does not implement "getBlocksForEpoch"');
102
- }
103
-
104
- public getBlockHeadersForEpoch(_epochNumber: bigint): Promise<BlockHeader[]> {
105
- throw new Error('TXE Archiver does not implement "getBlockHeadersForEpoch"');
106
- }
107
-
108
- public isEpochComplete(_epochNumber: bigint): Promise<boolean> {
90
+ public isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
109
91
  throw new Error('TXE Archiver does not implement "isEpochComplete"');
110
92
  }
111
93
 
112
- public getL2Tips(): Promise<L2Tips> {
113
- throw new Error('TXE Archiver does not implement "getL2Tips"');
114
- }
115
-
116
- public getL1Constants(): Promise<L1RollupConstants> {
117
- throw new Error('TXE Archiver does not implement "getL2Constants"');
118
- }
119
-
120
- public getGenesisValues(): Promise<{ genesisArchiveRoot: Fr }> {
121
- return Promise.resolve({ genesisArchiveRoot: new Fr(GENESIS_ARCHIVE_ROOT) });
122
- }
123
-
124
94
  public syncImmediate(): Promise<void> {
125
95
  throw new Error('TXE Archiver does not implement "syncImmediate"');
126
96
  }
127
-
128
- public getContract(_address: AztecAddress, _timestamp?: UInt64): Promise<ContractInstanceWithAddress | undefined> {
129
- throw new Error('TXE Archiver does not implement "getContract"');
130
- }
131
-
132
- public getRollupAddress(): Promise<EthAddress> {
133
- throw new Error('TXE Archiver does not implement "getRollupAddress"');
134
- }
135
-
136
- public getRegistryAddress(): Promise<EthAddress> {
137
- throw new Error('TXE Archiver does not implement "getRegistryAddress"');
138
- }
139
-
140
- public getL1Timestamp(): Promise<bigint> {
141
- throw new Error('TXE Archiver does not implement "getL1Timestamp"');
142
- }
143
-
144
- public isPendingChainInvalid(): Promise<boolean> {
145
- return Promise.resolve(false);
146
- }
147
-
148
- public override getPendingChainValidationStatus(): Promise<ValidateBlockResult> {
149
- return Promise.resolve({ valid: true });
150
- }
151
97
  }