@aztec/txe 0.0.1-commit.1bea0213 → 0.0.1-commit.217f559981

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 (52) hide show
  1. package/dest/index.d.ts +1 -1
  2. package/dest/index.d.ts.map +1 -1
  3. package/dest/index.js +82 -50
  4. package/dest/oracle/interfaces.d.ts +3 -3
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +2 -2
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +3 -4
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +5 -6
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +92 -31
  12. package/dest/rpc_translator.d.ts +9 -9
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +42 -31
  15. package/dest/state_machine/archiver.d.ts +1 -1
  16. package/dest/state_machine/archiver.d.ts.map +1 -1
  17. package/dest/state_machine/archiver.js +2 -0
  18. package/dest/state_machine/dummy_p2p_client.d.ts +15 -11
  19. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  20. package/dest/state_machine/dummy_p2p_client.js +27 -15
  21. package/dest/state_machine/index.d.ts +5 -5
  22. package/dest/state_machine/index.d.ts.map +1 -1
  23. package/dest/state_machine/index.js +15 -10
  24. package/dest/state_machine/mock_epoch_cache.d.ts +3 -1
  25. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  26. package/dest/state_machine/mock_epoch_cache.js +4 -0
  27. package/dest/txe_session.d.ts +4 -6
  28. package/dest/txe_session.d.ts.map +1 -1
  29. package/dest/txe_session.js +69 -17
  30. package/dest/util/txe_public_contract_data_source.d.ts +2 -3
  31. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  32. package/dest/util/txe_public_contract_data_source.js +5 -22
  33. package/dest/utils/block_creation.d.ts +1 -1
  34. package/dest/utils/block_creation.d.ts.map +1 -1
  35. package/dest/utils/block_creation.js +3 -1
  36. package/package.json +15 -15
  37. package/src/index.ts +83 -49
  38. package/src/oracle/interfaces.ts +2 -2
  39. package/src/oracle/txe_oracle_public_context.ts +3 -5
  40. package/src/oracle/txe_oracle_top_level_context.ts +113 -85
  41. package/src/rpc_translator.ts +44 -26
  42. package/src/state_machine/archiver.ts +2 -0
  43. package/src/state_machine/dummy_p2p_client.ts +39 -21
  44. package/src/state_machine/index.ts +25 -9
  45. package/src/state_machine/mock_epoch_cache.ts +5 -0
  46. package/src/txe_session.ts +73 -77
  47. package/src/util/txe_public_contract_data_source.ts +10 -36
  48. package/src/utils/block_creation.ts +3 -1
  49. package/dest/util/txe_contract_store.d.ts +0 -12
  50. package/dest/util/txe_contract_store.d.ts.map +0 -1
  51. package/dest/util/txe_contract_store.js +0 -22
  52. package/src/util/txe_contract_store.ts +0 -36
@@ -328,7 +328,7 @@ export class RPCTranslator {
328
328
 
329
329
  // When the argument is a slice, noir automatically adds a length field to oracle call.
330
330
  // When the argument is an array, we add the field length manually to the signature.
331
- utilityDebugLog(
331
+ async utilityLog(
332
332
  foreignLevel: ForeignCallSingle,
333
333
  foreignMessage: ForeignCallArray,
334
334
  _foreignLength: ForeignCallSingle,
@@ -340,7 +340,7 @@ export class RPCTranslator {
340
340
  .join('');
341
341
  const fields = fromArray(foreignFields);
342
342
 
343
- this.handlerAsMisc().utilityDebugLog(level, message, fields);
343
+ await this.handlerAsMisc().utilityLog(level, message, fields);
344
344
 
345
345
  return toForeignCallResult([]);
346
346
  }
@@ -351,7 +351,7 @@ export class RPCTranslator {
351
351
  foreignStartStorageSlot: ForeignCallSingle,
352
352
  foreignNumberOfElements: ForeignCallSingle,
353
353
  ) {
354
- const blockHash = BlockHash.fromString(foreignBlockHash);
354
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
355
355
  const contractAddress = addressFromSingle(foreignContractAddress);
356
356
  const startStorageSlot = fromSingle(foreignStartStorageSlot);
357
357
  const numberOfElements = fromSingle(foreignNumberOfElements).toNumber();
@@ -367,7 +367,7 @@ export class RPCTranslator {
367
367
  }
368
368
 
369
369
  async utilityGetPublicDataWitness(foreignBlockHash: ForeignCallSingle, foreignLeafSlot: ForeignCallSingle) {
370
- const blockHash = BlockHash.fromString(foreignBlockHash);
370
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
371
371
  const leafSlot = fromSingle(foreignLeafSlot);
372
372
 
373
373
  const witness = await this.handlerAsUtility().utilityGetPublicDataWitness(blockHash, leafSlot);
@@ -545,12 +545,23 @@ export class RPCTranslator {
545
545
  );
546
546
  }
547
547
 
548
- async utilityGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
548
+ async utilityTryGetPublicKeysAndPartialAddress(foreignAddress: ForeignCallSingle) {
549
549
  const address = addressFromSingle(foreignAddress);
550
550
 
551
- const { publicKeys, partialAddress } = await this.handlerAsUtility().utilityGetPublicKeysAndPartialAddress(address);
551
+ const result = await this.handlerAsUtility().utilityTryGetPublicKeysAndPartialAddress(address);
552
552
 
553
- 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
+ }
554
565
  }
555
566
 
556
567
  async utilityGetKeyValidationRequest(foreignPkMHash: ForeignCallSingle) {
@@ -574,7 +585,7 @@ export class RPCTranslator {
574
585
  }
575
586
 
576
587
  async utilityGetNullifierMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignNullifier: ForeignCallSingle) {
577
- const blockHash = BlockHash.fromString(foreignBlockHash);
588
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
578
589
  const nullifier = fromSingle(foreignNullifier);
579
590
 
580
591
  const witness = await this.handlerAsUtility().utilityGetNullifierMembershipWitness(blockHash, nullifier);
@@ -641,26 +652,34 @@ export class RPCTranslator {
641
652
  return toForeignCallResult(header.toFields().map(toSingle));
642
653
  }
643
654
 
644
- async utilityGetNoteHashMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
645
- const blockHash = BlockHash.fromString(foreignBlockHash);
646
- const leafValue = fromSingle(foreignLeafValue);
655
+ async utilityGetNoteHashMembershipWitness(
656
+ foreignAnchorBlockHash: ForeignCallSingle,
657
+ foreignNoteHash: ForeignCallSingle,
658
+ ) {
659
+ const blockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
660
+ const noteHash = fromSingle(foreignNoteHash);
647
661
 
648
- const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, leafValue);
662
+ const witness = await this.handlerAsUtility().utilityGetNoteHashMembershipWitness(blockHash, noteHash);
649
663
 
650
664
  if (!witness) {
651
- throw new Error(`Note hash ${leafValue} not found in the note hash tree at block ${blockHash.toString()}.`);
665
+ throw new Error(`Note hash ${noteHash} not found in the note hash tree at block ${blockHash.toString()}.`);
652
666
  }
653
667
  return toForeignCallResult(witness.toNoirRepresentation());
654
668
  }
655
669
 
656
- async utilityGetArchiveMembershipWitness(foreignBlockHash: ForeignCallSingle, foreignLeafValue: ForeignCallSingle) {
657
- const blockHash = BlockHash.fromString(foreignBlockHash);
658
- const leafValue = fromSingle(foreignLeafValue);
670
+ async utilityGetBlockHashMembershipWitness(
671
+ foreignAnchorBlockHash: ForeignCallSingle,
672
+ foreignBlockHash: ForeignCallSingle,
673
+ ) {
674
+ const anchorBlockHash = new BlockHash(fromSingle(foreignAnchorBlockHash));
675
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
659
676
 
660
- const witness = await this.handlerAsUtility().utilityGetArchiveMembershipWitness(blockHash, leafValue);
677
+ const witness = await this.handlerAsUtility().utilityGetBlockHashMembershipWitness(anchorBlockHash, blockHash);
661
678
 
662
679
  if (!witness) {
663
- throw new Error(`Block hash ${leafValue} not found in the archive tree at block ${blockHash.toString()}.`);
680
+ throw new Error(
681
+ `Block hash ${blockHash.toString()} not found in the archive tree at anchor block ${anchorBlockHash.toString()}.`,
682
+ );
664
683
  }
665
684
  return toForeignCallResult(witness.toNoirRepresentation());
666
685
  }
@@ -669,7 +688,7 @@ export class RPCTranslator {
669
688
  foreignBlockHash: ForeignCallSingle,
670
689
  foreignNullifier: ForeignCallSingle,
671
690
  ) {
672
- const blockHash = BlockHash.fromString(foreignBlockHash);
691
+ const blockHash = new BlockHash(fromSingle(foreignBlockHash));
673
692
  const nullifier = fromSingle(foreignNullifier);
674
693
 
675
694
  const witness = await this.handlerAsUtility().utilityGetLowNullifierMembershipWitness(blockHash, nullifier);
@@ -830,7 +849,7 @@ export class RPCTranslator {
830
849
 
831
850
  // AVM opcodes
832
851
 
833
- avmOpcodeEmitUnencryptedLog(_foreignMessage: ForeignCallArray) {
852
+ avmOpcodeEmitPublicLog(_foreignMessage: ForeignCallArray) {
834
853
  // TODO(#8811): Implement
835
854
  return toForeignCallResult([]);
836
855
  }
@@ -911,11 +930,10 @@ export class RPCTranslator {
911
930
  return toForeignCallResult([]);
912
931
  }
913
932
 
914
- async avmOpcodeNullifierExists(foreignInnerNullifier: ForeignCallSingle, foreignTargetAddress: ForeignCallSingle) {
915
- const innerNullifier = fromSingle(foreignInnerNullifier);
916
- const targetAddress = AztecAddress.fromField(fromSingle(foreignTargetAddress));
933
+ async avmOpcodeNullifierExists(foreignSiloedNullifier: ForeignCallSingle) {
934
+ const siloedNullifier = fromSingle(foreignSiloedNullifier);
917
935
 
918
- const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(innerNullifier, targetAddress);
936
+ const exists = await this.handlerAsAvm().avmOpcodeNullifierExists(siloedNullifier);
919
937
 
920
938
  return toForeignCallResult([toSingle(new Fr(exists))]);
921
939
  }
@@ -1025,7 +1043,7 @@ export class RPCTranslator {
1025
1043
  return toForeignCallResult([toArray(returnValues)]);
1026
1044
  }
1027
1045
 
1028
- async txeSimulateUtilityFunction(
1046
+ async txeExecuteUtilityFunction(
1029
1047
  foreignTargetContractAddress: ForeignCallSingle,
1030
1048
  foreignFunctionSelector: ForeignCallSingle,
1031
1049
  foreignArgs: ForeignCallArray,
@@ -1034,7 +1052,7 @@ export class RPCTranslator {
1034
1052
  const functionSelector = FunctionSelector.fromField(fromSingle(foreignFunctionSelector));
1035
1053
  const args = fromArray(foreignArgs);
1036
1054
 
1037
- const returnValues = await this.handlerAsTxe().txeSimulateUtilityFunction(
1055
+ const returnValues = await this.handlerAsTxe().txeExecuteUtilityFunction(
1038
1056
  targetContractAddress,
1039
1057
  functionSelector,
1040
1058
  args,
@@ -59,6 +59,8 @@ export class TXEArchiver extends ArchiverDataSourceBase {
59
59
  if (!checkpointedBlock) {
60
60
  throw new Error(`L2Tips requested from TXE Archiver but no checkpointed block found for block number ${number}`);
61
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.
62
64
  const checkpoint = await this.store.getRangeOfCheckpoints(CheckpointNumber.fromBlockNumber(number), 1);
63
65
  if (checkpoint.length === 0) {
64
66
  throw new Error(`L2Tips requested from TXE Archiver but no checkpoint found for block number ${number}`);
@@ -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,
@@ -14,9 +16,9 @@ import type {
14
16
  StatusMessage,
15
17
  } from '@aztec/p2p';
16
18
  import type { EthAddress, L2BlockStreamEvent, L2Tips } from '@aztec/stdlib/block';
17
- import type { PeerInfo } from '@aztec/stdlib/interfaces/server';
18
- import type { BlockProposal, CheckpointAttestation, CheckpointProposal } from '@aztec/stdlib/p2p';
19
- import type { Tx, TxHash } from '@aztec/stdlib/tx';
19
+ import type { ITxProvider, PeerInfo } from '@aztec/stdlib/interfaces/server';
20
+ import type { BlockProposal, CheckpointAttestation, CheckpointProposal, TopicType } from '@aztec/stdlib/p2p';
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> {
@@ -39,6 +41,10 @@ export class DummyP2P implements P2P {
39
41
  throw new Error('DummyP2P does not implement "getPeers"');
40
42
  }
41
43
 
44
+ public getGossipMeshPeerCount(_topicType: TopicType): Promise<number> {
45
+ return Promise.resolve(0);
46
+ }
47
+
42
48
  public broadcastProposal(_proposal: BlockProposal): Promise<void> {
43
49
  throw new Error('DummyP2P does not implement "broadcastProposal"');
44
50
  }
@@ -71,8 +77,8 @@ export class DummyP2P implements P2P {
71
77
  throw new Error('DummyP2P does not implement "sendTx"');
72
78
  }
73
79
 
74
- public deleteTxs(_txHashes: TxHash[]): Promise<void> {
75
- throw new Error('DummyP2P does not implement "deleteTxs"');
80
+ public handleFailedExecution(_txHashes: TxHash[]): Promise<void> {
81
+ throw new Error('DummyP2P does not implement "handleFailedExecution"');
76
82
  }
77
83
 
78
84
  public getTxByHashFromPool(_txHash: TxHash): Promise<Tx | undefined> {
@@ -97,6 +103,10 @@ export class DummyP2P implements P2P {
97
103
  throw new Error('DummyP2P does not implement "iteratePendingTxs"');
98
104
  }
99
105
 
106
+ public iterateEligiblePendingTxs(): AsyncIterableIterator<Tx> {
107
+ throw new Error('DummyP2P does not implement "iterateEligiblePendingTxs"');
108
+ }
109
+
100
110
  public getPendingTxCount(): Promise<number> {
101
111
  throw new Error('DummyP2P does not implement "getPendingTxCount"');
102
112
  }
@@ -125,6 +135,10 @@ export class DummyP2P implements P2P {
125
135
  throw new Error('DummyP2P does not implement "isP2PClient"');
126
136
  }
127
137
 
138
+ public getTxProvider(): ITxProvider {
139
+ throw new Error('DummyP2P does not implement "getTxProvider"');
140
+ }
141
+
128
142
  public getTxsByHash(_txHashes: TxHash[]): Promise<Tx[]> {
129
143
  throw new Error('DummyP2P does not implement "getTxsByHash"');
130
144
  }
@@ -133,8 +147,8 @@ export class DummyP2P implements P2P {
133
147
  throw new Error('DummyP2P does not implement "getCheckpointAttestationsForSlot"');
134
148
  }
135
149
 
136
- public addCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
137
- throw new Error('DummyP2P does not implement "addCheckpointAttestations"');
150
+ public addOwnCheckpointAttestations(_attestations: CheckpointAttestation[]): Promise<void> {
151
+ throw new Error('DummyP2P does not implement "addOwnCheckpointAttestations"');
138
152
  }
139
153
 
140
154
  public getL2BlockHash(_number: number): Promise<string | undefined> {
@@ -157,14 +171,6 @@ export class DummyP2P implements P2P {
157
171
  throw new Error('DummyP2P does not implement "sync"');
158
172
  }
159
173
 
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
174
  public getTxsByHashFromPool(_txHashes: TxHash[]): Promise<(Tx | undefined)[]> {
169
175
  throw new Error('DummyP2P does not implement "getTxsByHashFromPool"');
170
176
  }
@@ -173,10 +179,6 @@ export class DummyP2P implements P2P {
173
179
  throw new Error('DummyP2P does not implement "hasTxsInPool"');
174
180
  }
175
181
 
176
- public addTxsToPool(_txs: Tx[]): Promise<number> {
177
- throw new Error('DummyP2P does not implement "addTxs"');
178
- }
179
-
180
182
  public getSyncedLatestBlockNum(): Promise<number> {
181
183
  throw new Error('DummyP2P does not implement "getSyncedLatestBlockNum"');
182
184
  }
@@ -189,8 +191,12 @@ export class DummyP2P implements P2P {
189
191
  throw new Error('DummyP2P does not implement "getSyncedLatestSlot"');
190
192
  }
191
193
 
192
- markTxsAsNonEvictable(_: TxHash[]): Promise<void> {
193
- throw new Error('DummyP2P does not implement "markTxsAsNonEvictable".');
194
+ protectTxs(_txHashes: TxHash[], _blockHeader: BlockHeader): Promise<TxHash[]> {
195
+ throw new Error('DummyP2P does not implement "protectTxs".');
196
+ }
197
+
198
+ prepareForSlot(_slotNumber: SlotNumber): Promise<void> {
199
+ return Promise.resolve();
194
200
  }
195
201
 
196
202
  addReqRespSubProtocol(
@@ -206,4 +212,16 @@ export class DummyP2P implements P2P {
206
212
 
207
213
  //This is no-op
208
214
  public registerThisValidatorAddresses(_address: EthAddress[]): void {}
215
+
216
+ public registerDuplicateProposalCallback(_callback: P2PDuplicateProposalCallback): void {
217
+ throw new Error('DummyP2P does not implement "registerDuplicateProposalCallback"');
218
+ }
219
+
220
+ public registerDuplicateAttestationCallback(_callback: P2PDuplicateAttestationCallback): void {
221
+ throw new Error('DummyP2P does not implement "registerDuplicateAttestationCallback"');
222
+ }
223
+
224
+ public hasBlockProposalsForSlot(_slot: SlotNumber): Promise<boolean> {
225
+ throw new Error('DummyP2P does not implement "hasBlockProposalsForSlot"');
226
+ }
209
227
  }
@@ -3,8 +3,7 @@ import { TestCircuitVerifier } from '@aztec/bb-prover/test';
3
3
  import { CheckpointNumber } from '@aztec/foundation/branded-types';
4
4
  import { Fr } from '@aztec/foundation/curves/bn254';
5
5
  import { createLogger } from '@aztec/foundation/log';
6
- import type { AztecAsyncKVStore } from '@aztec/kv-store';
7
- import { AnchorBlockStore } from '@aztec/pxe/server';
6
+ import { type AnchorBlockStore, type ContractStore, ContractSyncService, type NoteStore } from '@aztec/pxe/server';
8
7
  import { L2Block } from '@aztec/stdlib/block';
9
8
  import { Checkpoint, L1PublishedData, PublishedCheckpoint } from '@aztec/stdlib/checkpoint';
10
9
  import type { AztecNode } from '@aztec/stdlib/interfaces/client';
@@ -26,13 +25,16 @@ export class TXEStateMachine {
26
25
  public synchronizer: TXESynchronizer,
27
26
  public archiver: TXEArchiver,
28
27
  public anchorBlockStore: AnchorBlockStore,
28
+ public contractSyncService: ContractSyncService,
29
29
  ) {}
30
30
 
31
- public static async create(db: AztecAsyncKVStore) {
32
- const archiver = new TXEArchiver(db);
31
+ public static async create(
32
+ archiver: TXEArchiver,
33
+ anchorBlockStore: AnchorBlockStore,
34
+ contractStore: ContractStore,
35
+ noteStore: NoteStore,
36
+ ) {
33
37
  const synchronizer = await TXESynchronizer.create();
34
- const anchorBlockStore = new AnchorBlockStore(db);
35
-
36
38
  const aztecNodeConfig = {} as AztecNodeConfig;
37
39
 
38
40
  const log = createLogger('txe_node');
@@ -48,6 +50,7 @@ export class TXEStateMachine {
48
50
  undefined,
49
51
  undefined,
50
52
  undefined,
53
+ undefined,
51
54
  VERSION,
52
55
  CHAIN_ID,
53
56
  new TXEGlobalVariablesBuilder(),
@@ -58,11 +61,21 @@ export class TXEStateMachine {
58
61
  log,
59
62
  );
60
63
 
61
- return new this(node, synchronizer, archiver, anchorBlockStore);
64
+ const contractSyncService = new ContractSyncService(
65
+ node,
66
+ contractStore,
67
+ noteStore,
68
+ createLogger('txe:contract_sync'),
69
+ );
70
+
71
+ return new this(node, synchronizer, archiver, anchorBlockStore, contractSyncService);
62
72
  }
63
73
 
64
74
  public async handleL2Block(block: L2Block) {
65
- // Create a checkpoint from the block manually
75
+ // Create a checkpoint from the block manually.
76
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
77
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
78
+ const checkpointNumber = CheckpointNumber.fromBlockNumber(block.number);
66
79
  const checkpoint = new Checkpoint(
67
80
  block.archive,
68
81
  CheckpointHeader.from({
@@ -79,7 +92,7 @@ export class TXEStateMachine {
79
92
  totalManaUsed: block.header.totalManaUsed,
80
93
  }),
81
94
  [block],
82
- CheckpointNumber.fromBlockNumber(block.number),
95
+ checkpointNumber,
83
96
  );
84
97
 
85
98
  const publishedCheckpoint = new PublishedCheckpoint(
@@ -91,6 +104,9 @@ export class TXEStateMachine {
91
104
  ),
92
105
  [],
93
106
  );
107
+ // Wipe contract sync cache when anchor block changes (mirrors BlockSynchronizer behavior)
108
+ this.contractSyncService.wipe();
109
+
94
110
  await Promise.all([
95
111
  this.synchronizer.handleL2Block(block),
96
112
  this.archiver.addCheckpoints([publishedCheckpoint], undefined),
@@ -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.
@@ -64,4 +65,8 @@ export class MockEpochCache implements EpochCacheInterface {
64
65
  filterInCommittee(_slot: SlotTag, _validators: EthAddress[]): Promise<EthAddress[]> {
65
66
  return Promise.resolve([]);
66
67
  }
68
+
69
+ getL1Constants(): L1RollupConstants {
70
+ return EmptyL1RollupConstants;
71
+ }
67
72
  }
@@ -3,10 +3,12 @@ import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { type Logger, createLogger } from '@aztec/foundation/log';
4
4
  import { KeyStore } from '@aztec/key-store';
5
5
  import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
6
- import type { ProtocolContract } from '@aztec/protocol-contracts';
6
+ import type { AccessScopes } from '@aztec/pxe/client/lazy';
7
7
  import {
8
8
  AddressStore,
9
+ AnchorBlockStore,
9
10
  CapsuleStore,
11
+ ContractStore,
10
12
  JobCoordinator,
11
13
  NoteService,
12
14
  NoteStore,
@@ -49,10 +51,10 @@ import type { IAvmExecutionOracle, ITxeExecutionOracle } from './oracle/interfac
49
51
  import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
50
52
  import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
51
53
  import { RPCTranslator } from './rpc_translator.js';
54
+ import { TXEArchiver } from './state_machine/archiver.js';
52
55
  import { TXEStateMachine } from './state_machine/index.js';
53
56
  import type { ForeignCallArgs, ForeignCallResult } from './util/encoding.js';
54
57
  import { TXEAccountStore } from './util/txe_account_store.js';
55
- import { TXEContractStore } from './util/txe_contract_store.js';
56
58
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
57
59
  import { makeTxEffect } from './utils/tx_effect_creation.js';
58
60
 
@@ -129,7 +131,7 @@ export class TXESession implements TXESessionStateHandler {
129
131
  | IPrivateExecutionOracle
130
132
  | IAvmExecutionOracle
131
133
  | ITxeExecutionOracle,
132
- private contractStore: TXEContractStore,
134
+ private contractStore: ContractStore,
133
135
  private noteStore: NoteStore,
134
136
  private keyStore: KeyStore,
135
137
  private addressStore: AddressStore,
@@ -146,12 +148,11 @@ export class TXESession implements TXESessionStateHandler {
146
148
  private nextBlockTimestamp: bigint,
147
149
  ) {}
148
150
 
149
- static async init(protocolContracts: ProtocolContract[]) {
151
+ static async init(contractStore: ContractStore) {
150
152
  const store = await openTmpStore('txe-session');
151
153
 
152
154
  const addressStore = new AddressStore(store);
153
155
  const privateEventStore = new PrivateEventStore(store);
154
- const contractStore = new TXEContractStore(store);
155
156
  const noteStore = new NoteStore(store);
156
157
  const senderTaggingStore = new SenderTaggingStore(store);
157
158
  const recipientTaggingStore = new RecipientTaggingStore(store);
@@ -170,13 +171,9 @@ export class TXESession implements TXESessionStateHandler {
170
171
  noteStore,
171
172
  ]);
172
173
 
173
- // Register protocol contracts.
174
- for (const { contractClass, instance, artifact } of protocolContracts) {
175
- await contractStore.addContractArtifact(contractClass.id, artifact);
176
- await contractStore.addContractInstance(instance);
177
- }
178
-
179
- const stateMachine = await TXEStateMachine.create(store);
174
+ const archiver = new TXEArchiver(store);
175
+ const anchorBlockStore = new AnchorBlockStore(store);
176
+ const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
180
177
 
181
178
  const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
182
179
  const version = new Fr(await stateMachine.node.getVersion());
@@ -312,17 +309,15 @@ export class TXESession implements TXESessionStateHandler {
312
309
  ): Promise<PrivateContextInputs> {
313
310
  this.exitTopLevelState();
314
311
 
315
- await new NoteService(
316
- this.noteStore,
317
- this.stateMachine.node,
318
- this.stateMachine.anchorBlockStore,
319
- this.currentJobId,
320
- ).syncNoteNullifiers(contractAddress);
321
-
322
312
  // Private execution has two associated block numbers: the anchor block (i.e. the historical block that is used to
323
313
  // build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
324
314
  // a single transaction with the effects of what was done in the test.
325
315
  const anchorBlock = await this.stateMachine.node.getBlockHeader(anchorBlockNumber ?? 'latest');
316
+
317
+ await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock!, this.currentJobId).syncNoteNullifiers(
318
+ contractAddress,
319
+ 'ALL_SCOPES',
320
+ );
326
321
  const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
327
322
 
328
323
  const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
@@ -338,30 +333,31 @@ export class TXESession implements TXESessionStateHandler {
338
333
  const taggingIndexCache = new ExecutionTaggingIndexCache();
339
334
 
340
335
  const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
341
- this.oracleHandler = new PrivateExecutionOracle(
342
- Fr.ZERO,
343
- new TxContext(this.chainId, this.version, GasSettings.empty()),
344
- new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
345
- anchorBlock!,
336
+ this.oracleHandler = new PrivateExecutionOracle({
337
+ argsHash: Fr.ZERO,
338
+ txContext: new TxContext(this.chainId, this.version, GasSettings.empty()),
339
+ callContext: new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
340
+ anchorBlockHeader: anchorBlock!,
346
341
  utilityExecutor,
347
- [],
348
- [],
349
- new HashedValuesCache(),
342
+ authWitnesses: [],
343
+ capsules: [],
344
+ executionCache: new HashedValuesCache(),
350
345
  noteCache,
351
346
  taggingIndexCache,
352
- this.contractStore,
353
- this.noteStore,
354
- this.keyStore,
355
- this.addressStore,
356
- this.stateMachine.node,
357
- this.stateMachine.anchorBlockStore,
358
- this.senderTaggingStore,
359
- this.recipientTaggingStore,
360
- this.senderAddressBookStore,
361
- this.capsuleStore,
362
- this.privateEventStore,
363
- this.currentJobId,
364
- );
347
+ contractStore: this.contractStore,
348
+ noteStore: this.noteStore,
349
+ keyStore: this.keyStore,
350
+ addressStore: this.addressStore,
351
+ aztecNode: this.stateMachine.node,
352
+ senderTaggingStore: this.senderTaggingStore,
353
+ recipientTaggingStore: this.recipientTaggingStore,
354
+ senderAddressBookStore: this.senderAddressBookStore,
355
+ capsuleStore: this.capsuleStore,
356
+ privateEventStore: this.privateEventStore,
357
+ contractSyncService: this.stateMachine.contractSyncService,
358
+ jobId: this.currentJobId,
359
+ scopes: 'ALL_SCOPES',
360
+ });
365
361
 
366
362
  // We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
367
363
  // data) in order to refer to it later, mimicking the way this object is used by the ContractFunctionSimulator. The
@@ -401,6 +397,8 @@ export class TXESession implements TXESessionStateHandler {
401
397
  async enterUtilityState(contractAddress: AztecAddress = DEFAULT_ADDRESS) {
402
398
  this.exitTopLevelState();
403
399
 
400
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
401
+
404
402
  // There is no automatic message discovery and contract-driven syncing process in inlined private or utility
405
403
  // contexts, which means that known nullifiers are also not searched for, since it is during the tagging sync that
406
404
  // we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
@@ -409,29 +407,27 @@ export class TXESession implements TXESessionStateHandler {
409
407
  await new NoteService(
410
408
  this.noteStore,
411
409
  this.stateMachine.node,
412
- this.stateMachine.anchorBlockStore,
410
+ anchorBlockHeader,
413
411
  this.currentJobId,
414
- ).syncNoteNullifiers(contractAddress);
412
+ ).syncNoteNullifiers(contractAddress, 'ALL_SCOPES');
415
413
 
416
- const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
417
-
418
- this.oracleHandler = new UtilityExecutionOracle(
414
+ this.oracleHandler = new UtilityExecutionOracle({
419
415
  contractAddress,
420
- [],
421
- [],
416
+ authWitnesses: [],
417
+ capsules: [],
422
418
  anchorBlockHeader,
423
- this.contractStore,
424
- this.noteStore,
425
- this.keyStore,
426
- this.addressStore,
427
- this.stateMachine.node,
428
- this.stateMachine.anchorBlockStore,
429
- this.recipientTaggingStore,
430
- this.senderAddressBookStore,
431
- this.capsuleStore,
432
- this.privateEventStore,
433
- this.currentJobId,
434
- );
419
+ contractStore: this.contractStore,
420
+ noteStore: this.noteStore,
421
+ keyStore: this.keyStore,
422
+ addressStore: this.addressStore,
423
+ aztecNode: this.stateMachine.node,
424
+ recipientTaggingStore: this.recipientTaggingStore,
425
+ senderAddressBookStore: this.senderAddressBookStore,
426
+ capsuleStore: this.capsuleStore,
427
+ privateEventStore: this.privateEventStore,
428
+ jobId: this.currentJobId,
429
+ scopes: 'ALL_SCOPES',
430
+ });
435
431
 
436
432
  this.state = { name: 'UTILITY' };
437
433
  this.logger.debug(`Entered state ${this.state.name}`);
@@ -499,30 +495,30 @@ export class TXESession implements TXESessionStateHandler {
499
495
  }
500
496
 
501
497
  private utilityExecutorForContractSync(anchorBlock: any) {
502
- return async (call: FunctionCall) => {
498
+ return async (call: FunctionCall, scopes: AccessScopes) => {
503
499
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
504
500
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
505
501
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
506
502
  }
507
503
 
508
504
  try {
509
- const oracle = new UtilityExecutionOracle(
510
- call.to,
511
- [],
512
- [],
513
- anchorBlock!,
514
- this.contractStore,
515
- this.noteStore,
516
- this.keyStore,
517
- this.addressStore,
518
- this.stateMachine.node,
519
- this.stateMachine.anchorBlockStore,
520
- this.recipientTaggingStore,
521
- this.senderAddressBookStore,
522
- this.capsuleStore,
523
- this.privateEventStore,
524
- this.currentJobId,
525
- );
505
+ const oracle = new UtilityExecutionOracle({
506
+ contractAddress: call.to,
507
+ authWitnesses: [],
508
+ capsules: [],
509
+ anchorBlockHeader: anchorBlock!,
510
+ contractStore: this.contractStore,
511
+ noteStore: this.noteStore,
512
+ keyStore: this.keyStore,
513
+ addressStore: this.addressStore,
514
+ aztecNode: this.stateMachine.node,
515
+ recipientTaggingStore: this.recipientTaggingStore,
516
+ senderAddressBookStore: this.senderAddressBookStore,
517
+ capsuleStore: this.capsuleStore,
518
+ privateEventStore: this.privateEventStore,
519
+ jobId: this.currentJobId,
520
+ scopes,
521
+ });
526
522
  await new WASMSimulator()
527
523
  .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
528
524
  .catch((err: Error) => {