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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dest/oracle/interfaces.d.ts +3 -3
  2. package/dest/oracle/interfaces.d.ts.map +1 -1
  3. package/dest/oracle/txe_oracle_public_context.d.ts +5 -5
  4. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  5. package/dest/oracle/txe_oracle_public_context.js +6 -6
  6. package/dest/oracle/txe_oracle_top_level_context.d.ts +2 -2
  7. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_top_level_context.js +33 -14
  9. package/dest/rpc_translator.d.ts +14 -8
  10. package/dest/rpc_translator.d.ts.map +1 -1
  11. package/dest/rpc_translator.js +58 -34
  12. package/dest/state_machine/archiver.d.ts +2 -2
  13. package/dest/state_machine/archiver.d.ts.map +1 -1
  14. package/dest/state_machine/archiver.js +7 -6
  15. package/dest/state_machine/dummy_p2p_client.d.ts +9 -8
  16. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  17. package/dest/state_machine/dummy_p2p_client.js +15 -12
  18. package/dest/state_machine/index.d.ts +7 -7
  19. package/dest/state_machine/index.d.ts.map +1 -1
  20. package/dest/state_machine/index.js +30 -16
  21. package/dest/state_machine/mock_epoch_cache.d.ts +6 -2
  22. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  23. package/dest/state_machine/mock_epoch_cache.js +6 -1
  24. package/dest/state_machine/synchronizer.d.ts +3 -3
  25. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  26. package/dest/txe_session.d.ts +1 -1
  27. package/dest/txe_session.d.ts.map +1 -1
  28. package/dest/txe_session.js +14 -10
  29. package/dest/utils/block_creation.d.ts +5 -5
  30. package/dest/utils/block_creation.d.ts.map +1 -1
  31. package/dest/utils/block_creation.js +7 -5
  32. package/package.json +15 -15
  33. package/src/oracle/interfaces.ts +2 -2
  34. package/src/oracle/txe_oracle_public_context.ts +8 -10
  35. package/src/oracle/txe_oracle_top_level_context.ts +63 -26
  36. package/src/rpc_translator.ts +60 -28
  37. package/src/state_machine/archiver.ts +6 -8
  38. package/src/state_machine/dummy_p2p_client.ts +21 -15
  39. package/src/state_machine/index.ts +48 -19
  40. package/src/state_machine/mock_epoch_cache.ts +7 -1
  41. package/src/state_machine/synchronizer.ts +2 -2
  42. package/src/txe_session.ts +22 -15
  43. package/src/utils/block_creation.ts +8 -6
@@ -10,8 +10,7 @@ import {
10
10
  } from '@aztec/pxe/simulator';
11
11
  import { type ContractArtifact, EventSelector, FunctionSelector, NoteSelector } from '@aztec/stdlib/abi';
12
12
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { L2BlockHash } from '@aztec/stdlib/block';
14
- import { MerkleTreeId } from '@aztec/stdlib/trees';
13
+ import { BlockHash } from '@aztec/stdlib/block';
15
14
 
16
15
  import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfaces.js';
17
16
  import type { TXESessionStateHandler } from './txe_session.js';
@@ -329,7 +328,7 @@ export class RPCTranslator {
329
328
 
330
329
  // When the argument is a slice, noir automatically adds a length field to oracle call.
331
330
  // When the argument is an array, we add the field length manually to the signature.
332
- utilityDebugLog(
331
+ async utilityDebugLog(
333
332
  foreignLevel: ForeignCallSingle,
334
333
  foreignMessage: ForeignCallArray,
335
334
  _foreignLength: ForeignCallSingle,
@@ -341,7 +340,7 @@ export class RPCTranslator {
341
340
  .join('');
342
341
  const fields = fromArray(foreignFields);
343
342
 
344
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
343
+ await this.handlerAsMisc().utilityDebugLog(level, message, fields);
345
344
 
346
345
  return toForeignCallResult([]);
347
346
  }
@@ -352,7 +351,7 @@ export class RPCTranslator {
352
351
  foreignStartStorageSlot: ForeignCallSingle,
353
352
  foreignNumberOfElements: ForeignCallSingle,
354
353
  ) {
355
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
354
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
356
355
  const contractAddress = addressFromSingle(foreignContractAddress);
357
356
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
358
357
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
@@ -368,7 +367,7 @@ export class RPCTranslator {
368
367
  }
369
368
 
370
369
  async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
371
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
370
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
372
371
  const leafSlot = fromSingle(foreignLeafSlot);
373
372
 
374
373
  const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
@@ -513,6 +512,15 @@ export class RPCTranslator {
513
512
  return toForeignCallResult([]);
514
513
  }
515
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
+
516
524
  async utilityCheckNullifierExists(foreignInnerNullifier: ForeignCallSingle) {
517
525
  const innerNullifier = fromSingle(foreignInnerNullifier);
518
526
 
@@ -537,12 +545,23 @@ export class RPCTranslator {
537
545
  );
538
546
  }
539
547
 
540
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
548
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
541
549
  const address = addressFromSingle(foreignAddress);
542
550
 
543
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
551
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
544
552
 
545
- 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
+ }
546
565
  }
547
566
 
548
567
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -566,7 +585,7 @@ export class RPCTranslator {
566
585
  }
567
586
 
568
587
  async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
569
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
588
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
570
589
  const nullifier = fromSingle(foreignNullifier);
571
590
 
572
591
  const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
@@ -633,30 +652,43 @@ export class RPCTranslator {
633
652
  return toForeignCallResult(header.toFields().map(toSingle));
634
653
  }
635
654
 
636
- async utilityGetMembershipWitness(
655
+ async utilityGetNoteHashMembershipWitness(
656
+ foreignAnchorBlockHash: ForeignCallSingle,
657
+ foreignNoteHash: ForeignCallSingle,
658
+ ) {
659
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
660
+ const noteHash = fromSingle(foreignNoteHash);
661
+
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,
637
672
  foreignBlockHash: ForeignCallSingle,
638
- foreignTreeId: ForeignCallSingle,
639
- foreignLeafValue: ForeignCallSingle,
640
673
  ) {
641
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
642
- const treeId = fromSingle(foreignTreeId).toNumber();
643
- const leafValue = fromSingle(foreignLeafValue);
674
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
675
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
644
676
 
645
- const witness = await this.handlerAsUtility().utilityGetMembershipWitness(blockHash, treeId, leafValue);
677
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
646
678
 
647
679
  if (!witness) {
648
680
  throw new Error(
649
- `Membership witness in tree ${MerkleTreeId[treeId]} not found for value ${leafValue} at block ${blockHash}.`,
681
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
650
682
  );
651
683
  }
652
- return toForeignCallResult([toSingle(witness[0]), toArray(witness.slice(1))]);
684
+ return toForeignCallResult(witness.toNoirRepresentation());
653
685
  }
654
686
 
655
687
  async utilityGetLowNullifierMembershipWitness(
656
688
  foreignBlockHash: ForeignCallSingle,
657
689
  foreignNullifier: ForeignCallSingle,
658
690
  ) {
659
- const blockHash = L2BlockHash.fromString(foreignBlockHash);
691
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
660
692
  const nullifier = fromSingle(foreignNullifier);
661
693
 
662
694
  const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
@@ -675,7 +707,7 @@ export class RPCTranslator {
675
707
  return toForeignCallResult([]);
676
708
  }
677
709
 
678
- public async utilityValidateEnqueuedNotesAndEvents(
710
+ public async utilityValidateAndStoreEnqueuedNotesAndEvents(
679
711
  foreignContractAddress: ForeignCallSingle,
680
712
  foreignNoteValidationRequestsArrayBaseSlot: ForeignCallSingle,
681
713
  foreignEventValidationRequestsArrayBaseSlot: ForeignCallSingle,
@@ -684,7 +716,7 @@ export class RPCTranslator {
684
716
  const noteValidationRequestsArrayBaseSlot = fromSingle(foreignNoteValidationRequestsArrayBaseSlot);
685
717
  const eventValidationRequestsArrayBaseSlot = fromSingle(foreignEventValidationRequestsArrayBaseSlot);
686
718
 
687
- await this.handlerAsUtility().utilityValidateEnqueuedNotesAndEvents(
719
+ await this.handlerAsUtility().utilityValidateAndStoreEnqueuedNotesAndEvents(
688
720
  contractAddress,
689
721
  noteValidationRequestsArrayBaseSlot,
690
722
  eventValidationRequestsArrayBaseSlot,
@@ -822,10 +854,11 @@ export class RPCTranslator {
822
854
  return toForeignCallResult([]);
823
855
  }
824
856
 
825
- async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle) {
857
+ async avmOpcodeStorageRead(foreignSlot: ForeignCallSingle, foreignContractAddress: ForeignCallSingle) {
826
858
  const slot = fromSingle(foreignSlot);
859
+ const contractAddress = AztecAddress.fromField(fromSingle(foreignContractAddress));
827
860
 
828
- const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot)).value;
861
+ const value = (await this.handlerAsAvm().avmOpcodeStorageRead(slot, contractAddress)).value;
829
862
 
830
863
  return toForeignCallResult([toSingle(new Fr(value))]);
831
864
  }
@@ -897,11 +930,10 @@ export class RPCTranslator {
897
930
  return toForeignCallResult([]);
898
931
  }
899
932
 
900
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
901
- const innerNullifier = fromSingle(foreignInnerNullifier);
902
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
933
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
934
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
903
935
 
904
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
936
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
905
937
 
906
938
  return toForeignCallResult([toSingle(new Fr(exists))]);
907
939
  }
@@ -17,18 +17,14 @@ export class TXEArchiver extends ArchiverDataSourceBase {
17
17
  private readonly updater = new ArchiverDataStoreUpdater(this.store);
18
18
 
19
19
  constructor(db: AztecAsyncKVStore) {
20
- const store = new KVArchiverDataStore(db, 9999);
20
+ const store = new KVArchiverDataStore(db, 9999, { epochDuration: 32 });
21
21
  super(store);
22
22
  }
23
23
 
24
- // TXE-specific method for adding checkpoints
25
- public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<boolean> {
26
- await this.updater.setNewCheckpointData(checkpoints, result);
27
- return true;
24
+ public async addCheckpoints(checkpoints: PublishedCheckpoint[], result?: ValidateCheckpointResult): Promise<void> {
25
+ await this.updater.addCheckpoints(checkpoints, result);
28
26
  }
29
27
 
30
- // Abstract method implementations
31
-
32
28
  public getRollupAddress(): Promise<EthAddress> {
33
29
  throw new Error('TXE Archiver does not implement "getRollupAddress"');
34
30
  }
@@ -63,7 +59,9 @@ export class TXEArchiver extends ArchiverDataSourceBase {
63
59
  if (!checkpointedBlock) {
64
60
  throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
65
61
  }
66
- const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber(number), 1);
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);
67
65
  if (checkpoint.length === 0) {
68
66
  throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
69
67
  }
@@ -6,6 +6,8 @@ import type {
6
6
  P2PBlockReceivedCallback,
7
7
  P2PCheckpointReceivedCallback,
8
8
  P2PConfig,
9
+ P2PDuplicateAttestationCallback,
10
+ P2PDuplicateProposalCallback,
9
11
  P2PSyncState,
10
12
  PeerId,
11
13
  ReqRespSubProtocol,
@@ -16,7 +18,7 @@ import type {
16
18
  import type { EthAddress, L2BlockStreamEvent, L2Tips } from '@aztec/stdlib/block';
17
19
  import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
18
20
  import type { BlockProposal, CheckpointAttestation, CheckpointProposal } from '@aztec/stdlib/p2p';
19
- import type { Tx, TxHash } from '@aztec/stdlib/tx';
21
+ import type { BlockHeader, Tx, TxHash } from '@aztec/stdlib/tx';
20
22
 
21
23
  export class DummyP2P implements P2P {
22
24
  public validate(_txs: Tx[]): Promise<void> {
@@ -71,8 +73,8 @@ export class DummyP2P implements P2P {
71
73
  throw new Error('DummyP2P does not implement "sendTx"');
72
74
  }
73
75
 
74
- public deleteTxs(_txHashes: TxHash[]): Promise<void> {
75
- throw new Error('DummyP2P does not implement "deleteTxs"');
76
+ public handleFailedExecution(_txHashes: TxHash[]): Promise<void> {
77
+ throw new Error('DummyP2P does not implement "handleFailedExecution"');
76
78
  }
77
79
 
78
80
  public getTxByHashFromPool(_txHash: TxHash): Promise<Tx | undefined> {
@@ -133,8 +135,8 @@ export class DummyP2P implements P2P {
133
135
  throw new Error('DummyP2P does not implement "getCheckpointAttestationsForSlot"');
134
136
  }
135
137
 
136
- public addCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
137
- throw new Error('DummyP2P does not implement "addCheckpointAttestations"');
138
+ public addOwnCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
139
+ throw new Error('DummyP2P does not implement "addOwnCheckpointAttestations"');
138
140
  }
139
141
 
140
142
  public getL2BlockHash(_number: number): Promise<string | undefined> {
@@ -157,14 +159,6 @@ export class DummyP2P implements P2P {
157
159
  throw new Error('DummyP2P does not implement "sync"');
158
160
  }
159
161
 
160
- public requestTxsByHash(_txHashes: TxHash[]): Promise<Tx[]> {
161
- throw new Error('DummyP2P does not implement "requestTxsByHash"');
162
- }
163
-
164
- public getTxs(_filter: 'all' | 'pending' | 'mined'): Promise<Tx[]> {
165
- throw new Error('DummyP2P does not implement "getTxs"');
166
- }
167
-
168
162
  public getTxsByHashFromPool(_txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
169
163
  throw new Error('DummyP2P does not implement "getTxsByHashFromPool"');
170
164
  }
@@ -189,8 +183,12 @@ export class DummyP2P implements P2P {
189
183
  throw new Error('DummyP2P does not implement "getSyncedLatestSlot"');
190
184
  }
191
185
 
192
- markTxsAsNonEvictable(_: TxHash[]): Promise<void> {
193
- throw new Error('DummyP2P does not implement "markTxsAsNonEvictable".');
186
+ protectTxs(_txHashes: TxHash[], _blockHeader: BlockHeader): Promise<TxHash[]> {
187
+ throw new Error('DummyP2P does not implement "protectTxs".');
188
+ }
189
+
190
+ prepareForSlot(_slotNumber: SlotNumber): Promise<void> {
191
+ return Promise.resolve();
194
192
  }
195
193
 
196
194
  addReqRespSubProtocol(
@@ -206,4 +204,12 @@ export class DummyP2P implements P2P {
206
204
 
207
205
  //This is no-op
208
206
  public registerThisValidatorAddresses(_address: EthAddress[]): void {}
207
+
208
+ public registerDuplicateProposalCallback(_callback: P2PDuplicateProposalCallback): void {
209
+ throw new Error('DummyP2P does not implement "registerDuplicateProposalCallback"');
210
+ }
211
+
212
+ public registerDuplicateAttestationCallback(_callback: P2PDuplicateAttestationCallback): void {
213
+ throw new Error('DummyP2P does not implement "registerDuplicateAttestationCallback"');
214
+ }
209
215
  }
@@ -1,11 +1,13 @@
1
1
  import { type AztecNodeConfig, AztecNodeService } from '@aztec/aztec-node';
2
2
  import { TestCircuitVerifier } from '@aztec/bb-prover/test';
3
+ import { CheckpointNumber } from '@aztec/foundation/branded-types';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
3
5
  import { createLogger } from '@aztec/foundation/log';
4
- import type { AztecAsyncKVStore } from '@aztec/kv-store';
5
- import { AnchorBlockStore } from '@aztec/pxe/server';
6
- import { L2BlockNew } from '@aztec/stdlib/block';
6
+ import { type AnchorBlockStore, type ContractStore, ContractSyncService, type NoteStore } from '@aztec/pxe/server';
7
+ import { L2Block } from '@aztec/stdlib/block';
7
8
  import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
8
9
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
10
+ import { CheckpointHeader } from '@aztec/stdlib/rollup';
9
11
  import { getPackageVersion } from '@aztec/stdlib/update-checker';
10
12
 
11
13
  import { TXEArchiver } from './archiver.js';
@@ -23,13 +25,16 @@ export class TXEStateMachine {
23
25
  public synchronizer: TXESynchronizer,
24
26
  public archiver: TXEArchiver,
25
27
  public anchorBlockStore: AnchorBlockStore,
28
+ public contractSyncService: ContractSyncService,
26
29
  ) {}
27
30
 
28
- public static async create(db: AztecAsyncKVStore) {
29
- const archiver = new TXEArchiver(db);
31
+ public static async create(
32
+ archiver: TXEArchiver,
33
+ anchorBlockStore: AnchorBlockStore,
34
+ contractStore: ContractStore,
35
+ noteStore: NoteStore,
36
+ ) {
30
37
  const synchronizer = await TXESynchronizer.create();
31
- const anchorBlockStore = new AnchorBlockStore(db);
32
-
33
38
  const aztecNodeConfig = {} as AztecNodeConfig;
34
39
 
35
40
  const log = createLogger('txe_node');
@@ -55,18 +60,39 @@ export class TXEStateMachine {
55
60
  log,
56
61
  );
57
62
 
58
- return new this(node, synchronizer, archiver, anchorBlockStore);
63
+ const contractSyncService = new ContractSyncService(
64
+ node,
65
+ contractStore,
66
+ noteStore,
67
+ createLogger('txe:contract_sync'),
68
+ );
69
+
70
+ return new this(node, synchronizer, archiver, anchorBlockStore, contractSyncService);
59
71
  }
60
72
 
61
- public async handleL2Block(block: L2BlockNew) {
62
- // Create a checkpoint from the block - L2BlockNew doesn't have toCheckpoint() method
63
- // We need to construct the Checkpoint manually
64
- const checkpoint = await Checkpoint.random(block.checkpointNumber, {
65
- numBlocks: 1,
66
- startBlockNumber: Number(block.number),
67
- });
68
- // Replace the random block with our actual block
69
- checkpoint.blocks = [block];
73
+ public async handleL2Block(block: L2Block) {
74
+ // Create a checkpoint from the block manually.
75
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
76
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
77
+ const checkpointNumber = CheckpointNumber.fromBlockNumber(block.number);
78
+ const checkpoint = new Checkpoint(
79
+ block.archive,
80
+ CheckpointHeader.from({
81
+ lastArchiveRoot: block.header.lastArchive.root,
82
+ inHash: Fr.ZERO,
83
+ blobsHash: Fr.ZERO,
84
+ blockHeadersHash: Fr.ZERO,
85
+ epochOutHash: Fr.ZERO,
86
+ slotNumber: block.header.globalVariables.slotNumber,
87
+ timestamp: block.header.globalVariables.timestamp,
88
+ coinbase: block.header.globalVariables.coinbase,
89
+ feeRecipient: block.header.globalVariables.feeRecipient,
90
+ gasFees: block.header.globalVariables.gasFees,
91
+ totalManaUsed: block.header.totalManaUsed,
92
+ }),
93
+ [block],
94
+ checkpointNumber,
95
+ );
70
96
 
71
97
  const publishedCheckpoint = new PublishedCheckpoint(
72
98
  checkpoint,
@@ -77,10 +103,13 @@ export class TXEStateMachine {
77
103
  ),
78
104
  [],
79
105
  );
106
+ // Wipe contract sync cache when anchor block changes (mirrors BlockSynchronizer behavior)
107
+ this.contractSyncService.wipe();
108
+
80
109
  await Promise.all([
81
- this.synchronizer.handleL2Block(block), // L2BlockNew doesn't need toL2Block() conversion
110
+ this.synchronizer.handleL2Block(block),
82
111
  this.archiver.addCheckpoints([publishedCheckpoint], undefined),
83
- this.anchorBlockStore.setHeader(block.header), // Use .header property directly
112
+ this.anchorBlockStore.setHeader(block.header),
84
113
  ]);
85
114
  }
86
115
  }
@@ -1,6 +1,7 @@
1
1
  import type { EpochAndSlot, EpochCacheInterface, EpochCommitteeInfo, SlotTag } from '@aztec/epoch-cache';
2
2
  import { EpochNumber, SlotNumber } from '@aztec/foundation/branded-types';
3
3
  import { EthAddress } from '@aztec/foundation/eth-address';
4
+ import { EmptyL1RollupConstants, type L1RollupConstants } from '@aztec/stdlib/epoch-helpers';
4
5
 
5
6
  /**
6
7
  * Mock implementation of the EpochCacheInterface used to satisfy dependencies of AztecNodeService.
@@ -16,11 +17,12 @@ export class MockEpochCache implements EpochCacheInterface {
16
17
  });
17
18
  }
18
19
 
19
- getEpochAndSlotNow(): EpochAndSlot {
20
+ getEpochAndSlotNow(): EpochAndSlot & { nowMs: bigint } {
20
21
  return {
21
22
  epoch: EpochNumber.ZERO,
22
23
  slot: SlotNumber(0),
23
24
  ts: 0n,
25
+ nowMs: 0n,
24
26
  };
25
27
  }
26
28
 
@@ -63,4 +65,8 @@ export class MockEpochCache implements EpochCacheInterface {
63
65
  filterInCommittee(_slot: SlotTag, _validators: EthAddress[]): Promise<EthAddress[]> {
64
66
  return Promise.resolve([]);
65
67
  }
68
+
69
+ getL1Constants(): L1RollupConstants {
70
+ return EmptyL1RollupConstants;
71
+ }
66
72
  }
@@ -1,7 +1,7 @@
1
1
  import { NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
2
  import { BlockNumber } from '@aztec/foundation/branded-types';
3
3
  import { Fr } from '@aztec/foundation/curves/bn254';
4
- import type { L2BlockNew } from '@aztec/stdlib/block';
4
+ import type { L2Block } from '@aztec/stdlib/block';
5
5
  import type {
6
6
  MerkleTreeReadOperations,
7
7
  MerkleTreeWriteOperations,
@@ -23,7 +23,7 @@ export class TXESynchronizer implements WorldStateSynchronizer {
23
23
  return new this(nativeWorldStateService);
24
24
  }
25
25
 
26
- public async handleL2Block(block: L2BlockNew) {
26
+ public async handleL2Block(block: L2Block) {
27
27
  await this.nativeWorldStateService.handleL2BlockAndMessages(
28
28
  block,
29
29
  Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero),
@@ -6,6 +6,7 @@ import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
6
6
  import type { ProtocolContract } from '@aztec/protocol-contracts';
7
7
  import {
8
8
  AddressStore,
9
+ AnchorBlockStore,
9
10
  CapsuleStore,
10
11
  JobCoordinator,
11
12
  NoteService,
@@ -49,6 +50,7 @@ import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfac
49
50
  import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
50
51
  import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
51
52
  import { RPCTranslator } from './rpc_translator.js';
53
+ import { TXEArchiver } from './state_machine/archiver.js';
52
54
  import { TXEStateMachine } from './state_machine/index.js';
53
55
  import type { ForeignCallArgs, ForeignCallResult } from './util/encoding.js';
54
56
  import { TXEAccountStore } from './util/txe_account_store.js';
@@ -152,7 +154,7 @@ export class TXESession implements TXESessionStateHandler {
152
154
  const addressStore = new AddressStore(store);
153
155
  const privateEventStore = new PrivateEventStore(store);
154
156
  const contractStore = new TXEContractStore(store);
155
- const noteStore = await NoteStore.create(store);
157
+ const noteStore = new NoteStore(store);
156
158
  const senderTaggingStore = new SenderTaggingStore(store);
157
159
  const recipientTaggingStore = new RecipientTaggingStore(store);
158
160
  const senderAddressBookStore = new SenderAddressBookStore(store);
@@ -162,7 +164,13 @@ export class TXESession implements TXESessionStateHandler {
162
164
 
163
165
  // Create job coordinator and register staged stores
164
166
  const jobCoordinator = new JobCoordinator(store);
165
- jobCoordinator.registerStores([capsuleStore, senderTaggingStore, recipientTaggingStore, privateEventStore]);
167
+ jobCoordinator.registerStores([
168
+ capsuleStore,
169
+ senderTaggingStore,
170
+ recipientTaggingStore,
171
+ privateEventStore,
172
+ noteStore,
173
+ ]);
166
174
 
167
175
  // Register protocol contracts.
168
176
  for (const { contractClass, instance, artifact } of protocolContracts) {
@@ -170,7 +178,9 @@ export class TXESession implements TXESessionStateHandler {
170
178
  await contractStore.addContractInstance(instance);
171
179
  }
172
180
 
173
- const stateMachine = await TXEStateMachine.create(store);
181
+ const archiver = new TXEArchiver(store);
182
+ const anchorBlockStore = new AnchorBlockStore(store);
183
+ const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
174
184
 
175
185
  const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
176
186
  const version = new Fr(await stateMachine.node.getVersion());
@@ -306,16 +316,14 @@ export class TXESession implements TXESessionStateHandler {
306
316
  ): Promise<PrivateContextInputs> {
307
317
  this.exitTopLevelState();
308
318
 
309
- await new NoteService(
310
- this.noteStore,
311
- this.stateMachine.node,
312
- this.stateMachine.anchorBlockStore,
313
- ).syncNoteNullifiers(contractAddress);
314
-
315
319
  // Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
316
320
  // build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
317
321
  // a single transaction with the effects of what was done in the test.
318
322
  const anchorBlock = await this.stateMachine.node.getBlockHeader(anchorBlockNumber ?? 'latest');
323
+
324
+ await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
325
+ contractAddress,
326
+ );
319
327
  const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
320
328
 
321
329
  const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
@@ -347,12 +355,12 @@ export class TXESession implements TXESessionStateHandler {
347
355
  this.keyStore,
348
356
  this.addressStore,
349
357
  this.stateMachine.node,
350
- this.stateMachine.anchorBlockStore,
351
358
  this.senderTaggingStore,
352
359
  this.recipientTaggingStore,
353
360
  this.senderAddressBookStore,
354
361
  this.capsuleStore,
355
362
  this.privateEventStore,
363
+ this.stateMachine.contractSyncService,
356
364
  this.currentJobId,
357
365
  );
358
366
 
@@ -394,6 +402,8 @@ export class TXESession implements TXESessionStateHandler {
394
402
  async enterUtilityState(contractAddress: AztecAddress = DEFAULT_ADDRESS) {
395
403
  this.exitTopLevelState();
396
404
 
405
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
406
+
397
407
  // There is no automatic message discovery and contract-driven syncing process in inlined private or utility
398
408
  // contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
399
409
  // we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
@@ -402,11 +412,10 @@ export class TXESession implements TXESessionStateHandler {
402
412
  await new NoteService(
403
413
  this.noteStore,
404
414
  this.stateMachine.node,
405
- this.stateMachine.anchorBlockStore,
415
+ anchorBlockHeader,
416
+ this.currentJobId,
406
417
  ).syncNoteNullifiers(contractAddress);
407
418
 
408
- const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
409
-
410
419
  this.oracleHandler = new UtilityExecutionOracle(
411
420
  contractAddress,
412
421
  [],
@@ -417,7 +426,6 @@ export class TXESession implements TXESessionStateHandler {
417
426
  this.keyStore,
418
427
  this.addressStore,
419
428
  this.stateMachine.node,
420
- this.stateMachine.anchorBlockStore,
421
429
  this.recipientTaggingStore,
422
430
  this.senderAddressBookStore,
423
431
  this.capsuleStore,
@@ -508,7 +516,6 @@ export class TXESession implements TXESessionStateHandler {
508
516
  this.keyStore,
509
517
  this.addressStore,
510
518
  this.stateMachine.node,
511
- this.stateMachine.anchorBlockStore,
512
519
  this.recipientTaggingStore,
513
520
  this.senderAddressBookStore,
514
521
  this.capsuleStore,
@@ -7,7 +7,7 @@ import {
7
7
  import { BlockNumber, CheckpointNumber, IndexWithinCheckpoint } from '@aztec/foundation/branded-types';
8
8
  import { padArrayEnd } from '@aztec/foundation/collection';
9
9
  import { Fr } from '@aztec/foundation/curves/bn254';
10
- import { Body, L2BlockNew } from '@aztec/stdlib/block';
10
+ import { Body, L2Block } from '@aztec/stdlib/block';
11
11
  import { AppendOnlyTreeSnapshot, MerkleTreeId, type MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
12
12
  import { BlockHeader, GlobalVariables, TxEffect } from '@aztec/stdlib/tx';
13
13
 
@@ -61,7 +61,7 @@ export async function makeTXEBlockHeader(
61
61
  }
62
62
 
63
63
  /**
64
- * Creates an L2BlockNew with proper archive chaining.
64
+ * Creates an L2Block with proper archive chaining.
65
65
  * This function:
66
66
  * 1. Gets the current archive state as lastArchive for the header
67
67
  * 2. Creates the block header
@@ -71,13 +71,13 @@ export async function makeTXEBlockHeader(
71
71
  * @param worldTrees - The world trees to read/write from
72
72
  * @param globalVariables - Global variables for the block
73
73
  * @param txEffects - Transaction effects to include in the block
74
- * @returns The created L2BlockNew with proper archive chaining
74
+ * @returns The created L2Block with proper archive chaining
75
75
  */
76
76
  export async function makeTXEBlock(
77
77
  worldTrees: MerkleTreeWriteOperations,
78
78
  globalVariables: GlobalVariables,
79
79
  txEffects: TxEffect[],
80
- ): Promise<L2BlockNew> {
80
+ ): Promise<L2Block> {
81
81
  const header = await makeTXEBlockHeader(worldTrees, globalVariables);
82
82
 
83
83
  // Update the archive tree with this block's header hash
@@ -87,9 +87,11 @@ export async function makeTXEBlock(
87
87
  const newArchiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
88
88
  const newArchive = new AppendOnlyTreeSnapshot(new Fr(newArchiveInfo.root), Number(newArchiveInfo.size));
89
89
 
90
- // L2BlockNew requires checkpointNumber and indexWithinCheckpoint
90
+ // L2Block requires checkpointNumber and indexWithinCheckpoint.
91
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
92
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
91
93
  const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber);
92
94
  const indexWithinCheckpoint = IndexWithinCheckpoint(0);
93
95
 
94
- return new L2BlockNew(newArchive, header, new Body(txEffects), checkpointNumber, indexWithinCheckpoint);
96
+ return new L2Block(newArchive, header, new Body(txEffects), checkpointNumber, indexWithinCheckpoint);
95
97
  }