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

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 +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 +7 -8
  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 +100 -63
  15. package/dest/rpc_translator.d.ts +23 -11
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +91 -38
  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 +61 -107
  21. package/dest/state_machine/dummy_p2p_client.d.ts +8 -7
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +16 -11
  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 +5 -5
  28. package/dest/state_machine/index.d.ts.map +1 -1
  29. package/dest/state_machine/index.js +32 -20
  30. package/dest/state_machine/mock_epoch_cache.d.ts +7 -6
  31. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  32. package/dest/state_machine/mock_epoch_cache.js +10 -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 +91 -45
  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 +36 -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 +5 -3
  61. package/src/oracle/txe_oracle_public_context.ts +7 -12
  62. package/src/oracle/txe_oracle_top_level_context.ts +149 -88
  63. package/src/rpc_translator.ts +113 -49
  64. package/src/state_machine/archiver.ts +57 -131
  65. package/src/state_machine/dummy_p2p_client.ts +21 -14
  66. package/src/state_machine/global_variable_builder.ts +19 -2
  67. package/src/state_machine/index.ts +41 -18
  68. package/src/state_machine/mock_epoch_cache.ts +10 -11
  69. package/src/state_machine/synchronizer.ts +3 -4
  70. package/src/txe_session.ts +187 -76
  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 +46 -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 { L2BlockHash } 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);
@@ -304,40 +346,41 @@ export class RPCTranslator {
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 = L2BlockHash.fromString(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 = L2BlockHash.fromString(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
 
@@ -512,17 +573,14 @@ export class RPCTranslator {
512
573
  );
513
574
  }
514
575
 
515
- async utilityGetNullifierMembershipWitness(
516
- foreignBlockNumber: ForeignCallSingle,
517
- foreignNullifier: ForeignCallSingle,
518
- ) {
519
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
576
+ async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
577
+ const blockHash = L2BlockHash.fromString(foreignBlockHash);
520
578
  const nullifier = fromSingle(foreignNullifier);
521
579
 
522
- const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockNumber, nullifier);
580
+ const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
523
581
 
524
582
  if (!witness) {
525
- throw new Error(`Nullifier membership witness not found at block ${blockNumber}.`);
583
+ throw new Error(`Nullifier membership witness not found at block ${blockHash}.`);
526
584
  }
527
585
  return toForeignCallResult(witness.toNoirRepresentation());
528
586
  }
@@ -566,8 +624,8 @@ export class RPCTranslator {
566
624
  return toForeignCallResult([toSingle(new Fr(isRevertible))]);
567
625
  }
568
626
 
569
- async utilityGetUtilityContext() {
570
- const context = await this.handlerAsUtility().utilityGetUtilityContext();
627
+ utilityGetUtilityContext() {
628
+ const context = this.handlerAsUtility().utilityGetUtilityContext();
571
629
 
572
630
  return toForeignCallResult(context.toNoirRepresentation());
573
631
  }
@@ -583,36 +641,41 @@ export class RPCTranslator {
583
641
  return toForeignCallResult(header.toFields().map(toSingle));
584
642
  }
585
643
 
586
- async utilityGetMembershipWitness(
587
- foreignBlockNumber: ForeignCallSingle,
588
- foreignTreeId: ForeignCallSingle,
589
- foreignLeafValue: ForeignCallSingle,
590
- ) {
591
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
592
- const treeId = fromSingle(foreignTreeId).toNumber();
644
+ async utilityGetNoteHashMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
645
+ const blockHash = L2BlockHash.fromString(foreignBlockHash);
593
646
  const leafValue = fromSingle(foreignLeafValue);
594
647
 
595
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockNumber, treeId, leafValue);
648
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, leafValue);
596
649
 
597
650
  if (!witness) {
598
- throw new Error(
599
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockNumber}.`,
600
- );
651
+ throw new Error(`Note hash ${leafValue} not found in the note hash tree at block ${blockHash.toString()}.`);
601
652
  }
602
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
653
+ return toForeignCallResult(witness.toNoirRepresentation());
654
+ }
655
+
656
+ async utilityGetArchiveMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
657
+ const blockHash = L2BlockHash.fromString(foreignBlockHash);
658
+ const leafValue = fromSingle(foreignLeafValue);
659
+
660
+ const witness = await this.handlerAsUtility().utilityGetArchiveMembershipWitness(blockHash, leafValue);
661
+
662
+ if (!witness) {
663
+ throw new Error(`Block hash ${leafValue} not found in the archive tree at block ${blockHash.toString()}.`);
664
+ }
665
+ return toForeignCallResult(witness.toNoirRepresentation());
603
666
  }
604
667
 
605
668
  async utilityGetLowNullifierMembershipWitness(
606
- foreignBlockNumber: ForeignCallSingle,
669
+ foreignBlockHash: ForeignCallSingle,
607
670
  foreignNullifier: ForeignCallSingle,
608
671
  ) {
609
- const blockNumber = BlockNumber(fromSingle(foreignBlockNumber).toNumber());
672
+ const blockHash = L2BlockHash.fromString(foreignBlockHash);
610
673
  const nullifier = fromSingle(foreignNullifier);
611
674
 
612
- const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockNumber, nullifier);
675
+ const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
613
676
 
614
677
  if (!witness) {
615
- throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockNumber}.`);
678
+ throw new Error(`Low nullifier witness not found for nullifier ${nullifier} at block ${blockHash}.`);
616
679
  }
617
680
  return toForeignCallResult(witness.toNoirRepresentation());
618
681
  }
@@ -625,7 +688,7 @@ export class RPCTranslator {
625
688
  return toForeignCallResult([]);
626
689
  }
627
690
 
628
- public async utilityValidateEnqueuedNotesAndEvents(
691
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
629
692
  foreignContractAddress: ForeignCallSingle,
630
693
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
631
694
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -634,7 +697,7 @@ export class RPCTranslator {
634
697
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
635
698
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
636
699
 
637
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
700
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
638
701
  contractAddress,
639
702
  noteValidationRequestsArrayBaseSlot,
640
703
  eventValidationRequestsArrayBaseSlot,
@@ -772,10 +835,11 @@ export class RPCTranslator {
772
835
  return toForeignCallResult([]);
773
836
  }
774
837
 
775
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
838
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
776
839
  const slot = fromSingle(foreignSlot);
840
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
777
841
 
778
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
842
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
779
843
 
780
844
  return toForeignCallResult([toSingle(new Fr(value))]);
781
845
  }
@@ -1,169 +1,95 @@
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
+ const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
63
+ if (checkpoint.length === 0) {
64
+ throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
65
+ }
66
+ const blockId: L2BlockId = { number, hash };
67
+ const checkpointId: CheckpointId = {
68
+ number: checkpoint[0].checkpointNumber,
69
+ hash: checkpoint[0].header.hash().toString(),
70
+ };
71
+ const tipId: L2TipId = { block: blockId, checkpoint: checkpointId };
72
+ return {
73
+ proposed: blockId,
74
+ proven: tipId,
75
+ finalized: tipId,
76
+ checkpointed: tipId,
77
+ };
100
78
  }
101
79
 
102
80
  public getL2SlotNumber(): Promise<SlotNumber | undefined> {
103
81
  throw new Error('TXE Archiver does not implement "getL2SlotNumber"');
104
82
  }
105
83
 
106
- public getL2EpochNumber(): Promise<EpochNumber> {
84
+ public getL2EpochNumber(): Promise<EpochNumber | undefined> {
107
85
  throw new Error('TXE Archiver does not implement "getL2EpochNumber"');
108
86
  }
109
87
 
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
88
  public isEpochComplete(_epochNumber: EpochNumber): Promise<boolean> {
127
89
  throw new Error('TXE Archiver does not implement "isEpochComplete"');
128
90
  }
129
91
 
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
92
  public syncImmediate(): Promise<void> {
143
93
  throw new Error('TXE Archiver does not implement "syncImmediate"');
144
94
  }
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
95
  }
@@ -4,6 +4,7 @@ import type {
4
4
  ENR,
5
5
  P2P,
6
6
  P2PBlockReceivedCallback,
7
+ P2PCheckpointReceivedCallback,
7
8
  P2PConfig,
8
9
  P2PSyncState,
9
10
  PeerId,
@@ -14,14 +15,10 @@ import type {
14
15
  } from '@aztec/p2p';
15
16
  import type { EthAddress, L2BlockStreamEvent, L2Tips } from '@aztec/stdlib/block';
16
17
  import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
17
- import type { BlockAttestation, BlockProposal } from '@aztec/stdlib/p2p';
18
+ import type { BlockProposal, CheckpointAttestation, CheckpointProposal } from '@aztec/stdlib/p2p';
18
19
  import type { Tx, TxHash } from '@aztec/stdlib/tx';
19
20
 
20
21
  export class DummyP2P implements P2P {
21
- public broadcastAttestations(_attestations: BlockAttestation[]): Promise<void> {
22
- return Promise.resolve();
23
- }
24
-
25
22
  public validate(_txs: Tx[]): Promise<void> {
26
23
  return Promise.resolve();
27
24
  }
@@ -46,10 +43,22 @@ export class DummyP2P implements P2P {
46
43
  throw new Error('DummyP2P does not implement "broadcastProposal"');
47
44
  }
48
45
 
46
+ public broadcastCheckpointProposal(_proposal: CheckpointProposal): Promise<void> {
47
+ throw new Error('DummyP2P does not implement "broadcastCheckpointProposal"');
48
+ }
49
+
50
+ public broadcastCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
51
+ throw new Error('DummyP2P does not implement "broadcastCheckpointAttestations"');
52
+ }
53
+
49
54
  public registerBlockProposalHandler(_handler: P2PBlockReceivedCallback): void {
50
55
  throw new Error('DummyP2P does not implement "registerBlockProposalHandler"');
51
56
  }
52
57
 
58
+ public registerCheckpointProposalHandler(_handler: P2PCheckpointReceivedCallback): void {
59
+ throw new Error('DummyP2P does not implement "registerCheckpointProposalHandler"');
60
+ }
61
+
53
62
  public requestTxs(_txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
54
63
  throw new Error('DummyP2P does not implement "requestTxs"');
55
64
  }
@@ -79,7 +88,9 @@ export class DummyP2P implements P2P {
79
88
  }
80
89
 
81
90
  public getTxStatus(_txHash: TxHash): Promise<'pending' | 'mined' | undefined> {
82
- throw new Error('DummyP2P does not implement "getTxStatus"');
91
+ // In TXE there is no concept of transactions but we need to implement this because of tagging. We return 'mined'
92
+ // tx status for any tx hash.
93
+ return Promise.resolve('mined');
83
94
  }
84
95
 
85
96
  public iteratePendingTxs(): AsyncIterableIterator<Tx> {
@@ -118,16 +129,12 @@ export class DummyP2P implements P2P {
118
129
  throw new Error('DummyP2P does not implement "getTxsByHash"');
119
130
  }
120
131
 
121
- public getAttestationsForSlot(_slot: SlotNumber, _proposalId?: string): Promise<BlockAttestation[]> {
122
- throw new Error('DummyP2P does not implement "getAttestationForSlot"');
123
- }
124
-
125
- public deleteAttestation(_attestation: BlockAttestation): Promise<void> {
126
- return Promise.resolve();
132
+ public getCheckpointAttestationsForSlot(_slot: SlotNumber, _proposalId?: string): Promise<CheckpointAttestation[]> {
133
+ throw new Error('DummyP2P does not implement "getCheckpointAttestationsForSlot"');
127
134
  }
128
135
 
129
- public addAttestations(_attestations: BlockAttestation[]): Promise<void> {
130
- throw new Error('DummyP2P does not implement "addAttestations"');
136
+ public addCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
137
+ throw new Error('DummyP2P does not implement "addCheckpointAttestations"');
131
138
  }
132
139
 
133
140
  public getL2BlockHash(_number: number): Promise<string | undefined> {
@@ -3,10 +3,10 @@ import type { EthAddress } from '@aztec/foundation/eth-address';
3
3
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
4
4
  import { GasFees } from '@aztec/stdlib/gas';
5
5
  import { makeGlobalVariables } from '@aztec/stdlib/testing';
6
- import { type GlobalVariableBuilder, GlobalVariables } from '@aztec/stdlib/tx';
6
+ import { type CheckpointGlobalVariables, type GlobalVariableBuilder, GlobalVariables } from '@aztec/stdlib/tx';
7
7
 
8
8
  export class TXEGlobalVariablesBuilder implements GlobalVariableBuilder {
9
- public getCurrentBaseFees(): Promise<GasFees> {
9
+ public getCurrentMinFees(): Promise<GasFees> {
10
10
  return Promise.resolve(new GasFees(0, 0));
11
11
  }
12
12
 
@@ -18,4 +18,21 @@ export class TXEGlobalVariablesBuilder implements GlobalVariableBuilder {
18
18
  ): Promise<GlobalVariables> {
19
19
  return Promise.resolve(makeGlobalVariables());
20
20
  }
21
+
22
+ public buildCheckpointGlobalVariables(
23
+ _coinbase: EthAddress,
24
+ _feeRecipient: AztecAddress,
25
+ _slotNumber: SlotNumber,
26
+ ): Promise<CheckpointGlobalVariables> {
27
+ const vars = makeGlobalVariables();
28
+ return Promise.resolve({
29
+ chainId: vars.chainId,
30
+ version: vars.version,
31
+ slotNumber: vars.slotNumber,
32
+ timestamp: vars.timestamp,
33
+ coinbase: vars.coinbase,
34
+ feeRecipient: vars.feeRecipient,
35
+ gasFees: vars.gasFees,
36
+ });
37
+ }
21
38
  }