@aztec/txe 0.0.1-commit.ee80a48 → 0.0.1-commit.ef17749e1

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 +88 -54
  4. package/dest/oracle/interfaces.d.ts +29 -28
  5. package/dest/oracle/interfaces.d.ts.map +1 -1
  6. package/dest/oracle/txe_oracle_public_context.d.ts +13 -13
  7. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  8. package/dest/oracle/txe_oracle_public_context.js +12 -12
  9. package/dest/oracle/txe_oracle_top_level_context.d.ts +22 -23
  10. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_top_level_context.js +118 -50
  12. package/dest/rpc_translator.d.ts +83 -83
  13. package/dest/rpc_translator.d.ts.map +1 -1
  14. package/dest/rpc_translator.js +259 -154
  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 +16 -12
  19. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  20. package/dest/state_machine/dummy_p2p_client.js +28 -16
  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 +9 -6
  28. package/dest/txe_session.d.ts.map +1 -1
  29. package/dest/txe_session.js +82 -23
  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 +89 -52
  38. package/src/oracle/interfaces.ts +32 -31
  39. package/src/oracle/txe_oracle_public_context.ts +12 -12
  40. package/src/oracle/txe_oracle_top_level_context.ts +121 -103
  41. package/src/rpc_translator.ts +266 -157
  42. package/src/state_machine/archiver.ts +2 -0
  43. package/src/state_machine/dummy_p2p_client.ts +40 -22
  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 +85 -71
  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
@@ -3,7 +3,7 @@ import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import { 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 { AddressStore, CapsuleStore, JobCoordinator, NoteService, NoteStore, PrivateEventStore, RecipientTaggingStore, SenderAddressBookStore, SenderTaggingStore } from '@aztec/pxe/server';
6
+ import { AddressStore, AnchorBlockStore, CapsuleStore, JobCoordinator, NoteService, NoteStore, PrivateEventStore, RecipientTaggingStore, SenderAddressBookStore, SenderTaggingStore } from '@aztec/pxe/server';
7
7
  import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle } from '@aztec/pxe/simulator';
8
8
  import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness } from '@aztec/simulator/client';
9
9
  import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
@@ -17,9 +17,9 @@ import { DEFAULT_ADDRESS } from './constants.js';
17
17
  import { TXEOraclePublicContext } from './oracle/txe_oracle_public_context.js';
18
18
  import { TXEOracleTopLevelContext } from './oracle/txe_oracle_top_level_context.js';
19
19
  import { RPCTranslator } from './rpc_translator.js';
20
+ import { TXEArchiver } from './state_machine/archiver.js';
20
21
  import { TXEStateMachine } from './state_machine/index.js';
21
22
  import { TXEAccountStore } from './util/txe_account_store.js';
22
- import { TXEContractStore } from './util/txe_contract_store.js';
23
23
  import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from './utils/block_creation.js';
24
24
  import { makeTxEffect } from './utils/tx_effect_creation.js';
25
25
  /**
@@ -70,11 +70,10 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
70
70
  };
71
71
  this.authwits = new Map();
72
72
  }
73
- static async init(protocolContracts) {
73
+ static async init(contractStore) {
74
74
  const store = await openTmpStore('txe-session');
75
75
  const addressStore = new AddressStore(store);
76
76
  const privateEventStore = new PrivateEventStore(store);
77
- const contractStore = new TXEContractStore(store);
78
77
  const noteStore = new NoteStore(store);
79
78
  const senderTaggingStore = new SenderTaggingStore(store);
80
79
  const recipientTaggingStore = new RecipientTaggingStore(store);
@@ -91,18 +90,15 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
91
90
  privateEventStore,
92
91
  noteStore
93
92
  ]);
94
- // Register protocol contracts.
95
- for (const { contractClass, instance, artifact } of protocolContracts){
96
- await contractStore.addContractArtifact(contractClass.id, artifact);
97
- await contractStore.addContractInstance(instance);
98
- }
99
- const stateMachine = await TXEStateMachine.create(store);
93
+ const archiver = new TXEArchiver(store);
94
+ const anchorBlockStore = new AnchorBlockStore(store);
95
+ const stateMachine = await TXEStateMachine.create(archiver, anchorBlockStore, contractStore, noteStore);
100
96
  const nextBlockTimestamp = BigInt(Math.floor(new Date().getTime() / 1000));
101
97
  const version = new Fr(await stateMachine.node.getVersion());
102
98
  const chainId = new Fr(await stateMachine.node.getChainId());
103
99
  const initialJobId = jobCoordinator.beginJob();
104
- const topLevelOracleHandler = new TXEOracleTopLevelContext(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, initialJobId, nextBlockTimestamp, version, chainId, new Map());
105
- await topLevelOracleHandler.txeAdvanceBlocksBy(1);
100
+ const topLevelOracleHandler = new TXEOracleTopLevelContext(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, nextBlockTimestamp, version, chainId, new Map());
101
+ await topLevelOracleHandler.advanceBlocksBy(1);
106
102
  return new TXESession(createLogger('txe:session'), stateMachine, topLevelOracleHandler, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, jobCoordinator, initialJobId, version, chainId, nextBlockTimestamp);
107
103
  }
108
104
  /**
@@ -126,6 +122,14 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
126
122
  }
127
123
  }
128
124
  }
125
+ getCurrentJob() {
126
+ return this.currentJobId;
127
+ }
128
+ /** Commits the current job and begins a new one. Returns the new job ID. */ async cycleJob() {
129
+ await this.jobCoordinator.commitJob(this.currentJobId);
130
+ this.currentJobId = this.jobCoordinator.beginJob();
131
+ return this.currentJobId;
132
+ }
129
133
  async enterTopLevelState() {
130
134
  switch(this.state.name){
131
135
  case 'PRIVATE':
@@ -153,9 +157,8 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
153
157
  }
154
158
  }
155
159
  // Commit all staged stores from the job that was just completed, then begin a new job
156
- await this.jobCoordinator.commitJob(this.currentJobId);
157
- this.currentJobId = this.jobCoordinator.beginJob();
158
- this.oracleHandler = new TXEOracleTopLevelContext(this.stateMachine, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.accountStore, this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.currentJobId, this.nextBlockTimestamp, this.version, this.chainId, this.authwits);
160
+ await this.cycleJob();
161
+ this.oracleHandler = new TXEOracleTopLevelContext(this.stateMachine, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.accountStore, this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.nextBlockTimestamp, this.version, this.chainId, this.authwits);
159
162
  this.state = {
160
163
  name: 'TOP_LEVEL'
161
164
  };
@@ -167,7 +170,7 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
167
170
  // build the proof), and the *next* block, i.e. the one we'll create once the execution ends, and which will contain
168
171
  // a single transaction with the effects of what was done in the test.
169
172
  const anchorBlock = await this.stateMachine.node.getBlockHeader(anchorBlockNumber ?? 'latest');
170
- await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock, this.currentJobId).syncNoteNullifiers(contractAddress);
173
+ await new NoteService(this.noteStore, this.stateMachine.node, anchorBlock, this.currentJobId).syncNoteNullifiers(contractAddress, 'ALL_SCOPES');
171
174
  const latestBlock = await this.stateMachine.node.getBlockHeader('latest');
172
175
  const nextBlockGlobalVariables = makeGlobalVariables(undefined, {
173
176
  blockNumber: BlockNumber(latestBlock.globalVariables.blockNumber + 1),
@@ -180,7 +183,31 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
180
183
  const noteCache = new ExecutionNoteCache(protocolNullifier);
181
184
  const taggingIndexCache = new ExecutionTaggingIndexCache();
182
185
  const utilityExecutor = this.utilityExecutorForContractSync(anchorBlock);
183
- this.oracleHandler = new PrivateExecutionOracle(Fr.ZERO, new TxContext(this.chainId, this.version, GasSettings.empty()), new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false), anchorBlock, utilityExecutor, [], [], new HashedValuesCache(), noteCache, taggingIndexCache, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.senderTaggingStore, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.currentJobId);
186
+ this.oracleHandler = new PrivateExecutionOracle({
187
+ argsHash: Fr.ZERO,
188
+ txContext: new TxContext(this.chainId, this.version, GasSettings.empty()),
189
+ callContext: new CallContext(AztecAddress.ZERO, contractAddress, FunctionSelector.empty(), false),
190
+ anchorBlockHeader: anchorBlock,
191
+ utilityExecutor,
192
+ authWitnesses: [],
193
+ capsules: [],
194
+ executionCache: new HashedValuesCache(),
195
+ noteCache,
196
+ taggingIndexCache,
197
+ contractStore: this.contractStore,
198
+ noteStore: this.noteStore,
199
+ keyStore: this.keyStore,
200
+ addressStore: this.addressStore,
201
+ aztecNode: this.stateMachine.node,
202
+ senderTaggingStore: this.senderTaggingStore,
203
+ recipientTaggingStore: this.recipientTaggingStore,
204
+ senderAddressBookStore: this.senderAddressBookStore,
205
+ capsuleStore: this.capsuleStore,
206
+ privateEventStore: this.privateEventStore,
207
+ contractSyncService: this.stateMachine.contractSyncService,
208
+ jobId: this.currentJobId,
209
+ scopes: 'ALL_SCOPES'
210
+ });
184
211
  // We store the note and tagging index caches fed into the PrivateExecutionOracle (along with some other auxiliary
185
212
  // data) in order to refer to it later, mimicking the way this object is used by the ContractFunctionSimulator. The
186
213
  // difference resides in that the simulator has all information needed in order to run the simulation, while ours
@@ -220,8 +247,24 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
220
247
  // we perform this. We therefore search for known nullifiers now, as otherwise notes that were nullified would not
221
248
  // be removed from the database.
222
249
  // TODO(#12553): make the synchronizer sync here instead and remove this
223
- await new NoteService(this.noteStore, this.stateMachine.node, anchorBlockHeader, this.currentJobId).syncNoteNullifiers(contractAddress);
224
- this.oracleHandler = new UtilityExecutionOracle(contractAddress, [], [], anchorBlockHeader, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.currentJobId);
250
+ await new NoteService(this.noteStore, this.stateMachine.node, anchorBlockHeader, this.currentJobId).syncNoteNullifiers(contractAddress, 'ALL_SCOPES');
251
+ this.oracleHandler = new UtilityExecutionOracle({
252
+ contractAddress,
253
+ authWitnesses: [],
254
+ capsules: [],
255
+ anchorBlockHeader,
256
+ contractStore: this.contractStore,
257
+ noteStore: this.noteStore,
258
+ keyStore: this.keyStore,
259
+ addressStore: this.addressStore,
260
+ aztecNode: this.stateMachine.node,
261
+ recipientTaggingStore: this.recipientTaggingStore,
262
+ senderAddressBookStore: this.senderAddressBookStore,
263
+ capsuleStore: this.capsuleStore,
264
+ privateEventStore: this.privateEventStore,
265
+ jobId: this.currentJobId,
266
+ scopes: 'ALL_SCOPES'
267
+ });
225
268
  this.state = {
226
269
  name: 'UTILITY'
227
270
  };
@@ -233,8 +276,8 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
233
276
  }
234
277
  // Note that while all public and private contexts do is build a single block that we then process when exiting
235
278
  // those, the top level context performs a large number of actions not captured in the following 'close' call. Among
236
- // others, it will create empty blocks (via `txeAdvanceBlocksBy` and `deploy`), create blocks with transactions via
237
- // `txePrivateCallNewFlow` and `txePublicCallNewFlow`, add accounts to PXE via `txeAddAccount`, etc. This is a
279
+ // others, it will create empty blocks (via `advanceBlocksBy` and `deploy`), create blocks with transactions via
280
+ // `privateCallNewFlow` and `publicCallNewFlow`, add accounts to PXE via `addAccount`, etc. This is a
238
281
  // slight inconsistency in the working model of this class, but is not too bad.
239
282
  // TODO: it's quite unfortunate that we need to capture the authwits created to later pass them again when the top
240
283
  // level context is re-created. This is because authwits create a temporary utility context that'd otherwise reset
@@ -278,13 +321,29 @@ import { makeTxEffect } from './utils/tx_effect_creation.js';
278
321
  }
279
322
  }
280
323
  utilityExecutorForContractSync(anchorBlock) {
281
- return async (call)=>{
324
+ return async (call, scopes)=>{
282
325
  const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
283
326
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
284
327
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
285
328
  }
286
329
  try {
287
- const oracle = new UtilityExecutionOracle(call.to, [], [], anchorBlock, this.contractStore, this.noteStore, this.keyStore, this.addressStore, this.stateMachine.node, this.recipientTaggingStore, this.senderAddressBookStore, this.capsuleStore, this.privateEventStore, this.currentJobId);
330
+ const oracle = new UtilityExecutionOracle({
331
+ contractAddress: call.to,
332
+ authWitnesses: [],
333
+ capsules: [],
334
+ anchorBlockHeader: anchorBlock,
335
+ contractStore: this.contractStore,
336
+ noteStore: this.noteStore,
337
+ keyStore: this.keyStore,
338
+ addressStore: this.addressStore,
339
+ aztecNode: this.stateMachine.node,
340
+ recipientTaggingStore: this.recipientTaggingStore,
341
+ senderAddressBookStore: this.senderAddressBookStore,
342
+ capsuleStore: this.capsuleStore,
343
+ privateEventStore: this.privateEventStore,
344
+ jobId: this.currentJobId,
345
+ scopes
346
+ });
288
347
  await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
289
348
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
290
349
  throw new ExecutionError(err.message, {
@@ -3,9 +3,8 @@ import { Fr } from '@aztec/foundation/curves/bn254';
3
3
  import type { ContractStore } from '@aztec/pxe/server';
4
4
  import { type ContractArtifact, FunctionSelector } from '@aztec/stdlib/abi';
5
5
  import type { AztecAddress } from '@aztec/stdlib/aztec-address';
6
- import { type ContractClassPublic, type ContractDataSource, type ContractInstanceWithAddress } from '@aztec/stdlib/contract';
6
+ import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
7
7
  export declare class TXEPublicContractDataSource implements ContractDataSource {
8
- #private;
9
8
  private blockNumber;
10
9
  private contractStore;
11
10
  constructor(blockNumber: BlockNumber, contractStore: ContractStore);
@@ -18,4 +17,4 @@ export declare class TXEPublicContractDataSource implements ContractDataSource {
18
17
  getDebugFunctionName(address: AztecAddress, selector: FunctionSelector): Promise<string | undefined>;
19
18
  registerContractFunctionSignatures(_signatures: []): Promise<void>;
20
19
  }
21
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhlX3B1YmxpY19jb250cmFjdF9kYXRhX3NvdXJjZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWwvdHhlX3B1YmxpY19jb250cmFjdF9kYXRhX3NvdXJjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDOUQsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3BELE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxLQUFLLGdCQUFnQixFQUFFLGdCQUFnQixFQUFnQixNQUFNLG1CQUFtQixDQUFDO0FBQzFGLE9BQU8sS0FBSyxFQUFFLFlBQVksRUFBRSxNQUFNLDZCQUE2QixDQUFDO0FBQ2hFLE9BQU8sRUFDTCxLQUFLLG1CQUFtQixFQUN4QixLQUFLLGtCQUFrQixFQUN2QixLQUFLLDJCQUEyQixFQUlqQyxNQUFNLHdCQUF3QixDQUFDO0FBRWhDLHFCQUFhLDJCQUE0QixZQUFXLGtCQUFrQjs7SUFHbEUsT0FBTyxDQUFDLFdBQVc7SUFDbkIsT0FBTyxDQUFDLGFBQWE7SUFGdkIsWUFDVSxXQUFXLEVBQUUsV0FBVyxFQUN4QixhQUFhLEVBQUUsYUFBYSxFQUNsQztJQUVKLGNBQWMsSUFBSSxPQUFPLENBQUMsV0FBVyxDQUFDLENBRXJDO0lBRUssZ0JBQWdCLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDLENBZ0N2RTtJQUVLLHFCQUFxQixDQUFDLEVBQUUsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLEVBQUUsR0FBRyxTQUFTLENBQUMsQ0FHM0Q7SUFFSyxXQUFXLENBQUMsT0FBTyxFQUFFLFlBQVksR0FBRyxPQUFPLENBQUMsMkJBQTJCLEdBQUcsU0FBUyxDQUFDLENBR3pGO0lBRUQsbUJBQW1CLElBQUksT0FBTyxDQUFDLEVBQUUsRUFBRSxDQUFDLENBRW5DO0lBRUssbUJBQW1CLENBQUMsT0FBTyxFQUFFLFlBQVksR0FBRyxPQUFPLENBQUMsZ0JBQWdCLEdBQUcsU0FBUyxDQUFDLENBR3RGO0lBRUssb0JBQW9CLENBQUMsT0FBTyxFQUFFLFlBQVksRUFBRSxRQUFRLEVBQUUsZ0JBQWdCLEdBQUcsT0FBTyxDQUFDLE1BQU0sR0FBRyxTQUFTLENBQUMsQ0FFekc7SUFFRCxrQ0FBa0MsQ0FBQyxXQUFXLEVBQUUsRUFBRSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FFakU7Q0FDRiJ9
20
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhlX3B1YmxpY19jb250cmFjdF9kYXRhX3NvdXJjZS5kLnRzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3V0aWwvdHhlX3B1YmxpY19jb250cmFjdF9kYXRhX3NvdXJjZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsV0FBVyxFQUFFLE1BQU0saUNBQWlDLENBQUM7QUFDOUQsT0FBTyxFQUFFLEVBQUUsRUFBRSxNQUFNLGdDQUFnQyxDQUFDO0FBQ3BELE9BQU8sS0FBSyxFQUFFLGFBQWEsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBQ3ZELE9BQU8sRUFBRSxLQUFLLGdCQUFnQixFQUFFLGdCQUFnQixFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFDNUUsT0FBTyxLQUFLLEVBQUUsWUFBWSxFQUFFLE1BQU0sNkJBQTZCLENBQUM7QUFDaEUsT0FBTyxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsa0JBQWtCLEVBQUUsMkJBQTJCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQztBQUVuSCxxQkFBYSwyQkFBNEIsWUFBVyxrQkFBa0I7SUFFbEUsT0FBTyxDQUFDLFdBQVc7SUFDbkIsT0FBTyxDQUFDLGFBQWE7SUFGdkIsWUFDVSxXQUFXLEVBQUUsV0FBVyxFQUN4QixhQUFhLEVBQUUsYUFBYSxFQUNsQztJQUVKLGNBQWMsSUFBSSxPQUFPLENBQUMsV0FBVyxDQUFDLENBRXJDO0lBRUssZ0JBQWdCLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsbUJBQW1CLEdBQUcsU0FBUyxDQUFDLENBY3ZFO0lBRUsscUJBQXFCLENBQUMsRUFBRSxFQUFFLEVBQUUsR0FBRyxPQUFPLENBQUMsRUFBRSxHQUFHLFNBQVMsQ0FBQyxDQUczRDtJQUVLLFdBQVcsQ0FBQyxPQUFPLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQywyQkFBMkIsR0FBRyxTQUFTLENBQUMsQ0FHekY7SUFFRCxtQkFBbUIsSUFBSSxPQUFPLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FFbkM7SUFFSyxtQkFBbUIsQ0FBQyxPQUFPLEVBQUUsWUFBWSxHQUFHLE9BQU8sQ0FBQyxnQkFBZ0IsR0FBRyxTQUFTLENBQUMsQ0FHdEY7SUFFSyxvQkFBb0IsQ0FBQyxPQUFPLEVBQUUsWUFBWSxFQUFFLFFBQVEsRUFBRSxnQkFBZ0IsR0FBRyxPQUFPLENBQUMsTUFBTSxHQUFHLFNBQVMsQ0FBQyxDQUV6RztJQUVELGtDQUFrQyxDQUFDLFdBQVcsRUFBRSxFQUFFLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUVqRTtDQUNGIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"txe_public_contract_data_source.d.ts","sourceRoot":"","sources":["../../src/util/txe_public_contract_data_source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,KAAK,gBAAgB,EAAE,gBAAgB,EAAgB,MAAM,mBAAmB,CAAC;AAC1F,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,EACL,KAAK,mBAAmB,EACxB,KAAK,kBAAkB,EACvB,KAAK,2BAA2B,EAIjC,MAAM,wBAAwB,CAAC;AAEhC,qBAAa,2BAA4B,YAAW,kBAAkB;;IAGlE,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,aAAa;IAFvB,YACU,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAClC;IAEJ,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAErC;IAEK,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAgCvE;IAEK,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAG3D;IAEK,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC,CAGzF;IAED,mBAAmB,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAEnC;IAEK,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAGtF;IAEK,oBAAoB,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAEzG;IAED,kCAAkC,CAAC,WAAW,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjE;CACF"}
1
+ {"version":3,"file":"txe_public_contract_data_source.d.ts","sourceRoot":"","sources":["../../src/util/txe_public_contract_data_source.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,MAAM,iCAAiC,CAAC;AAC9D,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,mBAAmB,CAAC;AACvD,OAAO,EAAE,KAAK,gBAAgB,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAC5E,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAChE,OAAO,KAAK,EAAE,mBAAmB,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,wBAAwB,CAAC;AAEnH,qBAAa,2BAA4B,YAAW,kBAAkB;IAElE,OAAO,CAAC,WAAW;IACnB,OAAO,CAAC,aAAa;IAFvB,YACU,WAAW,EAAE,WAAW,EACxB,aAAa,EAAE,aAAa,EAClC;IAEJ,cAAc,IAAI,OAAO,CAAC,WAAW,CAAC,CAErC;IAEK,gBAAgB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,mBAAmB,GAAG,SAAS,CAAC,CAcvE;IAEK,qBAAqB,CAAC,EAAE,EAAE,EAAE,GAAG,OAAO,CAAC,EAAE,GAAG,SAAS,CAAC,CAG3D;IAEK,WAAW,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,2BAA2B,GAAG,SAAS,CAAC,CAGzF;IAED,mBAAmB,IAAI,OAAO,CAAC,EAAE,EAAE,CAAC,CAEnC;IAEK,mBAAmB,CAAC,OAAO,EAAE,YAAY,GAAG,OAAO,CAAC,gBAAgB,GAAG,SAAS,CAAC,CAGtF;IAEK,oBAAoB,CAAC,OAAO,EAAE,YAAY,EAAE,QAAQ,EAAE,gBAAgB,GAAG,OAAO,CAAC,MAAM,GAAG,SAAS,CAAC,CAEzG;IAED,kCAAkC,CAAC,WAAW,EAAE,EAAE,GAAG,OAAO,CAAC,IAAI,CAAC,CAEjE;CACF"}
@@ -1,48 +1,31 @@
1
- import { Fr } from '@aztec/foundation/curves/bn254';
2
- import { FunctionType } from '@aztec/stdlib/abi';
3
- import { computePrivateFunctionsRoot, computePublicBytecodeCommitment, getContractClassPrivateFunctionFromArtifact } from '@aztec/stdlib/contract';
4
1
  export class TXEPublicContractDataSource {
5
2
  blockNumber;
6
3
  contractStore;
7
- #privateFunctionsRoot;
8
4
  constructor(blockNumber, contractStore){
9
5
  this.blockNumber = blockNumber;
10
6
  this.contractStore = contractStore;
11
- this.#privateFunctionsRoot = new Map();
12
7
  }
13
8
  getBlockNumber() {
14
9
  return Promise.resolve(this.blockNumber);
15
10
  }
16
11
  async getContractClass(id) {
17
- const contractClass = await this.contractStore.getContractClass(id);
12
+ const contractClass = await this.contractStore.getContractClassWithPreimage(id);
18
13
  if (!contractClass) {
19
14
  return;
20
15
  }
21
- const artifact = await this.contractStore.getContractArtifact(id);
22
- if (!artifact) {
23
- return;
24
- }
25
- let privateFunctionsRoot;
26
- if (!this.#privateFunctionsRoot.has(id.toString())) {
27
- const privateFunctions = await Promise.all(artifact.functions.filter((fn)=>fn.functionType === FunctionType.PRIVATE).map((fn)=>getContractClassPrivateFunctionFromArtifact(fn)));
28
- privateFunctionsRoot = await computePrivateFunctionsRoot(privateFunctions);
29
- this.#privateFunctionsRoot.set(id.toString(), privateFunctionsRoot.toBuffer());
30
- } else {
31
- privateFunctionsRoot = Fr.fromBuffer(this.#privateFunctionsRoot.get(id.toString()));
32
- }
33
16
  return {
34
- id,
17
+ id: contractClass.id,
35
18
  artifactHash: contractClass.artifactHash,
36
19
  packedBytecode: contractClass.packedBytecode,
37
- privateFunctionsRoot,
20
+ privateFunctionsRoot: contractClass.privateFunctionsRoot,
38
21
  version: contractClass.version,
39
22
  privateFunctions: [],
40
23
  utilityFunctions: []
41
24
  };
42
25
  }
43
26
  async getBytecodeCommitment(id) {
44
- const contractClass = await this.contractStore.getContractClass(id);
45
- return contractClass && computePublicBytecodeCommitment(contractClass.packedBytecode);
27
+ const contractClass = await this.contractStore.getContractClassWithPreimage(id);
28
+ return contractClass?.publicBytecodeCommitment;
46
29
  }
47
30
  async getContract(address) {
48
31
  const instance = await this.contractStore.getContractInstance(address);
@@ -25,4 +25,4 @@ export declare function makeTXEBlockHeader(worldTrees: MerkleTreeWriteOperations
25
25
  * @returns The created L2Block with proper archive chaining
26
26
  */
27
27
  export declare function makeTXEBlock(worldTrees: MerkleTreeWriteOperations, globalVariables: GlobalVariables, txEffects: TxEffect[]): Promise<L2Block>;
28
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfY3JlYXRpb24uZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9ibG9ja19jcmVhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFNQSxPQUFPLEVBQUUsV0FBVyxFQUEyQyxNQUFNLGlDQUFpQyxDQUFDO0FBRXZHLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQVEsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUF3QyxLQUFLLHlCQUF5QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0csT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFMUU7Ozs7R0FJRztBQUNILHdCQUFnQiwyQkFBMkIsQ0FBQyxXQUFXLEVBQUUsV0FBVyxHQUFHLEVBQUUsQ0FFeEU7QUFFRCx3QkFBc0IsNEJBQTRCLENBQ2hELFFBQVEsRUFBRSxRQUFRLEVBQ2xCLFVBQVUsRUFBRSx5QkFBeUIsR0FDcEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWtCZjtBQUVELHdCQUFzQixrQkFBa0IsQ0FDdEMsVUFBVSxFQUFFLHlCQUF5QixFQUNyQyxlQUFlLEVBQUUsZUFBZSxHQUMvQixPQUFPLENBQUMsV0FBVyxDQUFDLENBWXRCO0FBRUQ7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsd0JBQXNCLFlBQVksQ0FDaEMsVUFBVSxFQUFFLHlCQUF5QixFQUNyQyxlQUFlLEVBQUUsZUFBZSxFQUNoQyxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQ3BCLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FlbEIifQ==
28
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmxvY2tfY3JlYXRpb24uZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy91dGlscy9ibG9ja19jcmVhdGlvbi50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFNQSxPQUFPLEVBQUUsV0FBVyxFQUEyQyxNQUFNLGlDQUFpQyxDQUFDO0FBRXZHLE9BQU8sRUFBRSxFQUFFLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQztBQUNwRCxPQUFPLEVBQVEsT0FBTyxFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDcEQsT0FBTyxFQUF3QyxLQUFLLHlCQUF5QixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFDM0csT0FBTyxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsUUFBUSxFQUFFLE1BQU0sa0JBQWtCLENBQUM7QUFFMUU7Ozs7R0FJRztBQUNILHdCQUFnQiwyQkFBMkIsQ0FBQyxXQUFXLEVBQUUsV0FBVyxHQUFHLEVBQUUsQ0FFeEU7QUFFRCx3QkFBc0IsNEJBQTRCLENBQ2hELFFBQVEsRUFBRSxRQUFRLEVBQ2xCLFVBQVUsRUFBRSx5QkFBeUIsR0FDcEMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQWtCZjtBQUVELHdCQUFzQixrQkFBa0IsQ0FDdEMsVUFBVSxFQUFFLHlCQUF5QixFQUNyQyxlQUFlLEVBQUUsZUFBZSxHQUMvQixPQUFPLENBQUMsV0FBVyxDQUFDLENBWXRCO0FBRUQ7Ozs7Ozs7Ozs7OztHQVlHO0FBQ0gsd0JBQXNCLFlBQVksQ0FDaEMsVUFBVSxFQUFFLHlCQUF5QixFQUNyQyxlQUFlLEVBQUUsZUFBZSxFQUNoQyxTQUFTLEVBQUUsUUFBUSxFQUFFLEdBQ3BCLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FpQmxCIn0=
@@ -1 +1 @@
1
- {"version":3,"file":"block_creation.d.ts","sourceRoot":"","sources":["../../src/utils/block_creation.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAA2C,MAAM,iCAAiC,CAAC;AAEvG,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAQ,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAwC,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,WAAW,GAAG,EAAE,CAExE;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,yBAAyB,GACpC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,yBAAyB,EACrC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,WAAW,CAAC,CAYtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,yBAAyB,EACrC,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,QAAQ,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CAelB"}
1
+ {"version":3,"file":"block_creation.d.ts","sourceRoot":"","sources":["../../src/utils/block_creation.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,WAAW,EAA2C,MAAM,iCAAiC,CAAC;AAEvG,OAAO,EAAE,EAAE,EAAE,MAAM,gCAAgC,CAAC;AACpD,OAAO,EAAQ,OAAO,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAwC,KAAK,yBAAyB,EAAE,MAAM,qBAAqB,CAAC;AAC3G,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAE1E;;;;GAIG;AACH,wBAAgB,2BAA2B,CAAC,WAAW,EAAE,WAAW,GAAG,EAAE,CAExE;AAED,wBAAsB,4BAA4B,CAChD,QAAQ,EAAE,QAAQ,EAClB,UAAU,EAAE,yBAAyB,GACpC,OAAO,CAAC,IAAI,CAAC,CAkBf;AAED,wBAAsB,kBAAkB,CACtC,UAAU,EAAE,yBAAyB,EACrC,eAAe,EAAE,eAAe,GAC/B,OAAO,CAAC,WAAW,CAAC,CAYtB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAsB,YAAY,CAChC,UAAU,EAAE,yBAAyB,EACrC,eAAe,EAAE,eAAe,EAChC,SAAS,EAAE,QAAQ,EAAE,GACpB,OAAO,CAAC,OAAO,CAAC,CAiBlB"}
@@ -49,7 +49,9 @@ export async function makeTXEBlockHeader(worldTrees, globalVariables) {
49
49
  // Get the new archive state after updating
50
50
  const newArchiveInfo = await worldTrees.getTreeInfo(MerkleTreeId.ARCHIVE);
51
51
  const newArchive = new AppendOnlyTreeSnapshot(new Fr(newArchiveInfo.root), Number(newArchiveInfo.size));
52
- // L2Block requires checkpointNumber and indexWithinCheckpoint
52
+ // L2Block requires checkpointNumber and indexWithinCheckpoint.
53
+ // TXE uses 1-block-per-checkpoint for testing simplicity, so we can use block number as checkpoint number.
54
+ // This uses the deprecated fromBlockNumber method intentionally for the TXE testing environment.
53
55
  const checkpointNumber = CheckpointNumber.fromBlockNumber(globalVariables.blockNumber);
54
56
  const indexWithinCheckpoint = IndexWithinCheckpoint(0);
55
57
  return new L2Block(newArchive, header, new Body(txEffects), checkpointNumber, indexWithinCheckpoint);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aztec/txe",
3
- "version": "0.0.1-commit.ee80a48",
3
+ "version": "0.0.1-commit.ef17749e1",
4
4
  "type": "module",
5
5
  "exports": "./dest/index.js",
6
6
  "bin": "./dest/bin/index.js",
@@ -61,20 +61,20 @@
61
61
  ]
62
62
  },
63
63
  "dependencies": {
64
- "@aztec/accounts": "0.0.1-commit.ee80a48",
65
- "@aztec/archiver": "0.0.1-commit.ee80a48",
66
- "@aztec/aztec-node": "0.0.1-commit.ee80a48",
67
- "@aztec/aztec.js": "0.0.1-commit.ee80a48",
68
- "@aztec/bb-prover": "0.0.1-commit.ee80a48",
69
- "@aztec/constants": "0.0.1-commit.ee80a48",
70
- "@aztec/foundation": "0.0.1-commit.ee80a48",
71
- "@aztec/key-store": "0.0.1-commit.ee80a48",
72
- "@aztec/kv-store": "0.0.1-commit.ee80a48",
73
- "@aztec/protocol-contracts": "0.0.1-commit.ee80a48",
74
- "@aztec/pxe": "0.0.1-commit.ee80a48",
75
- "@aztec/simulator": "0.0.1-commit.ee80a48",
76
- "@aztec/stdlib": "0.0.1-commit.ee80a48",
77
- "@aztec/world-state": "0.0.1-commit.ee80a48",
64
+ "@aztec/accounts": "0.0.1-commit.ef17749e1",
65
+ "@aztec/archiver": "0.0.1-commit.ef17749e1",
66
+ "@aztec/aztec-node": "0.0.1-commit.ef17749e1",
67
+ "@aztec/aztec.js": "0.0.1-commit.ef17749e1",
68
+ "@aztec/bb-prover": "0.0.1-commit.ef17749e1",
69
+ "@aztec/constants": "0.0.1-commit.ef17749e1",
70
+ "@aztec/foundation": "0.0.1-commit.ef17749e1",
71
+ "@aztec/key-store": "0.0.1-commit.ef17749e1",
72
+ "@aztec/kv-store": "0.0.1-commit.ef17749e1",
73
+ "@aztec/protocol-contracts": "0.0.1-commit.ef17749e1",
74
+ "@aztec/pxe": "0.0.1-commit.ef17749e1",
75
+ "@aztec/simulator": "0.0.1-commit.ef17749e1",
76
+ "@aztec/stdlib": "0.0.1-commit.ef17749e1",
77
+ "@aztec/world-state": "0.0.1-commit.ef17749e1",
78
78
  "zod": "^3.23.8"
79
79
  },
80
80
  "devDependencies": {
package/src/index.ts CHANGED
@@ -9,9 +9,12 @@ import { Fr } from '@aztec/aztec.js/fields';
9
9
  import { PublicKeys, deriveKeys } from '@aztec/aztec.js/keys';
10
10
  import { createSafeJsonRpcServer } from '@aztec/foundation/json-rpc/server';
11
11
  import type { Logger } from '@aztec/foundation/log';
12
- import { type ProtocolContract, protocolContractNames } from '@aztec/protocol-contracts';
12
+ import { openTmpStore } from '@aztec/kv-store/lmdb-v2';
13
+ import { protocolContractNames } from '@aztec/protocol-contracts';
13
14
  import { BundledProtocolContractsProvider } from '@aztec/protocol-contracts/providers/bundle';
15
+ import { ContractStore } from '@aztec/pxe/server';
14
16
  import { computeArtifactHash } from '@aztec/stdlib/contract';
17
+ import type { ContractArtifactWithHash } from '@aztec/stdlib/contract';
15
18
  import type { ApiSchemaFor } from '@aztec/stdlib/schemas';
16
19
  import { zodFor } from '@aztec/stdlib/schemas';
17
20
 
@@ -29,22 +32,29 @@ import {
29
32
  type ForeignCallResult,
30
33
  ForeignCallResultSchema,
31
34
  type ForeignCallSingle,
35
+ addressFromSingle,
32
36
  fromArray,
33
37
  fromSingle,
34
38
  toSingle,
35
39
  } from './util/encoding.js';
36
- import type { ContractArtifactWithHash } from './util/txe_contract_store.js';
37
40
 
38
41
  const sessions = new Map<number, TXESession>();
39
42
 
40
43
  /*
41
44
  * TXE typically has to load the same contract artifacts over and over again for multiple tests,
42
- * so we cache them here to avoid both loading them from disk repeatedly and computing their artifact hashes
45
+ * so we cache them here to avoid loading from disk repeatedly.
46
+ *
47
+ * The in-flight map coalesces concurrent requests for the same cache key so that
48
+ * computeArtifactHash (very expensive) is only run once even under parallelism.
43
49
  */
44
50
  const TXEArtifactsCache = new Map<
45
51
  string,
46
52
  { artifact: ContractArtifactWithHash; instance: ContractInstanceWithAddress }
47
53
  >();
54
+ const TXEArtifactsCacheInFlight = new Map<
55
+ string,
56
+ Promise<{ artifact: ContractArtifactWithHash; instance: ContractInstanceWithAddress }>
57
+ >();
48
58
 
49
59
  type TXEForeignCallInput = {
50
60
  session_id: number;
@@ -68,7 +78,7 @@ const TXEForeignCallInputSchema = zodFor<TXEForeignCallInput>()(
68
78
  );
69
79
 
70
80
  class TXEDispatcher {
71
- private protocolContracts!: ProtocolContract[];
81
+ private contractStore!: ContractStore;
72
82
 
73
83
  constructor(private logger: Logger) {}
74
84
 
@@ -96,6 +106,8 @@ class TXEDispatcher {
96
106
 
97
107
  const decodedArgs = fromArray(inputs[3] as ForeignCallArray);
98
108
  const secret = fromSingle(inputs[4] as ForeignCallSingle);
109
+ const salt = fromSingle(inputs[5] as ForeignCallSingle);
110
+ const deployer = addressFromSingle(inputs[6] as ForeignCallSingle);
99
111
  const publicKeys = secret.equals(Fr.ZERO) ? PublicKeys.default() : (await deriveKeys(secret)).publicKeys;
100
112
  const publicKeysHash = await publicKeys.hash();
101
113
 
@@ -126,7 +138,7 @@ class TXEDispatcher {
126
138
 
127
139
  const cacheKey = `${contractDirectory ?? ''}-${contractFilename}-${initializer}-${decodedArgs
128
140
  .map(arg => arg.toString())
129
- .join('-')}-${publicKeysHash}-${fileHash}`;
141
+ .join('-')}-${publicKeysHash}-${salt}-${deployer}-${fileHash}`;
130
142
 
131
143
  let instance;
132
144
  let artifact: ContractArtifactWithHash;
@@ -135,29 +147,36 @@ class TXEDispatcher {
135
147
  this.logger.debug(`Using cached artifact for ${cacheKey}`);
136
148
  ({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
137
149
  } else {
138
- this.logger.debug(`Loading compiled artifact ${artifactPath}`);
139
- const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8')) as NoirCompiledContract;
140
- const artifactWithoutHash = loadContractArtifact(artifactJSON);
141
- artifact = {
142
- ...artifactWithoutHash,
143
- // Artifact hash is *very* expensive to compute, so we do it here once
144
- // and the TXE contract data provider can cache it
145
- artifactHash: await computeArtifactHash(artifactWithoutHash),
146
- };
147
- this.logger.debug(
148
- `Deploy ${
149
- artifact.name
150
- } with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`,
151
- );
152
- instance = await getContractInstanceFromInstantiationParams(artifact, {
153
- constructorArgs: decodedArgs,
154
- skipArgsDecoding: true,
155
- salt: Fr.ONE,
156
- publicKeys,
157
- constructorArtifact: initializer ? initializer : undefined,
158
- deployer: AztecAddress.ZERO,
159
- });
160
- TXEArtifactsCache.set(cacheKey, { artifact, instance });
150
+ if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
151
+ this.logger.debug(`Loading compiled artifact ${artifactPath}`);
152
+ const compute = async () => {
153
+ const artifactJSON = JSON.parse(await readFile(artifactPath, 'utf-8')) as NoirCompiledContract;
154
+ const artifactWithoutHash = loadContractArtifact(artifactJSON);
155
+ const computedArtifact: ContractArtifactWithHash = {
156
+ ...artifactWithoutHash,
157
+ // Artifact hash is *very* expensive to compute, so we do it here once
158
+ // and the TXE contract data provider can cache it
159
+ artifactHash: await computeArtifactHash(artifactWithoutHash),
160
+ };
161
+ this.logger.debug(
162
+ `Deploy ${computedArtifact.name} with initializer ${initializer}(${decodedArgs}) and public keys hash ${publicKeysHash.toString()}`,
163
+ );
164
+ const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
165
+ constructorArgs: decodedArgs,
166
+ skipArgsDecoding: true,
167
+ salt,
168
+ publicKeys,
169
+ constructorArtifact: initializer ? initializer : undefined,
170
+ deployer,
171
+ });
172
+ const result = { artifact: computedArtifact, instance: computedInstance };
173
+ TXEArtifactsCache.set(cacheKey, result);
174
+ TXEArtifactsCacheInFlight.delete(cacheKey);
175
+ return result;
176
+ };
177
+ TXEArtifactsCacheInFlight.set(cacheKey, compute());
178
+ }
179
+ ({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey)!);
161
180
  }
162
181
 
163
182
  inputs.splice(0, 1, artifact, instance, toSingle(secret));
@@ -175,23 +194,35 @@ class TXEDispatcher {
175
194
  this.logger.debug(`Using cached artifact for ${cacheKey}`);
176
195
  ({ artifact, instance } = TXEArtifactsCache.get(cacheKey)!);
177
196
  } else {
178
- const keys = await deriveKeys(secret);
179
- const args = [keys.publicKeys.masterIncomingViewingPublicKey.x, keys.publicKeys.masterIncomingViewingPublicKey.y];
180
- artifact = {
181
- ...SchnorrAccountContractArtifact,
182
- // Artifact hash is *very* expensive to compute, so we do it here once
183
- // and the TXE contract data provider can cache it
184
- artifactHash: await computeArtifactHash(SchnorrAccountContractArtifact),
185
- };
186
- instance = await getContractInstanceFromInstantiationParams(artifact, {
187
- constructorArgs: args,
188
- skipArgsDecoding: true,
189
- salt: Fr.ONE,
190
- publicKeys: keys.publicKeys,
191
- constructorArtifact: 'constructor',
192
- deployer: AztecAddress.ZERO,
193
- });
194
- TXEArtifactsCache.set(cacheKey, { artifact, instance });
197
+ if (!TXEArtifactsCacheInFlight.has(cacheKey)) {
198
+ const compute = async () => {
199
+ const keys = await deriveKeys(secret);
200
+ const args = [
201
+ keys.publicKeys.masterIncomingViewingPublicKey.x,
202
+ keys.publicKeys.masterIncomingViewingPublicKey.y,
203
+ ];
204
+ const computedArtifact: ContractArtifactWithHash = {
205
+ ...SchnorrAccountContractArtifact,
206
+ // Artifact hash is *very* expensive to compute, so we do it here once
207
+ // and the TXE contract data provider can cache it
208
+ artifactHash: await computeArtifactHash(SchnorrAccountContractArtifact),
209
+ };
210
+ const computedInstance = await getContractInstanceFromInstantiationParams(computedArtifact, {
211
+ constructorArgs: args,
212
+ skipArgsDecoding: true,
213
+ salt: Fr.ONE,
214
+ publicKeys: keys.publicKeys,
215
+ constructorArtifact: 'constructor',
216
+ deployer: AztecAddress.ZERO,
217
+ });
218
+ const result = { artifact: computedArtifact, instance: computedInstance };
219
+ TXEArtifactsCache.set(cacheKey, result);
220
+ TXEArtifactsCacheInFlight.delete(cacheKey);
221
+ return result;
222
+ };
223
+ TXEArtifactsCacheInFlight.set(cacheKey, compute());
224
+ }
225
+ ({ artifact, instance } = await TXEArtifactsCacheInFlight.get(cacheKey)!);
195
226
  }
196
227
 
197
228
  inputs.splice(0, 0, artifact, instance);
@@ -204,20 +235,26 @@ class TXEDispatcher {
204
235
 
205
236
  if (!sessions.has(sessionId)) {
206
237
  this.logger.debug(`Creating new session ${sessionId}`);
207
- if (!this.protocolContracts) {
208
- this.protocolContracts = await Promise.all(
209
- protocolContractNames.map(name => new BundledProtocolContractsProvider().getProtocolContractArtifact(name)),
210
- );
238
+ if (!this.contractStore) {
239
+ const kvStore = await openTmpStore('txe-contracts');
240
+ this.contractStore = new ContractStore(kvStore);
241
+ const provider = new BundledProtocolContractsProvider();
242
+ for (const name of protocolContractNames) {
243
+ const { instance, artifact } = await provider.getProtocolContractArtifact(name);
244
+ await this.contractStore.addContractArtifact(artifact);
245
+ await this.contractStore.addContractInstance(instance);
246
+ }
247
+ this.logger.debug('Registered protocol contracts in shared contract store');
211
248
  }
212
- sessions.set(sessionId, await TXESession.init(this.protocolContracts));
249
+ sessions.set(sessionId, await TXESession.init(this.contractStore));
213
250
  }
214
251
 
215
252
  switch (functionName) {
216
- case 'txeDeploy': {
253
+ case 'aztec_txe_deploy': {
217
254
  await this.#processDeployInputs(callData);
218
255
  break;
219
256
  }
220
- case 'txeAddAccount': {
257
+ case 'aztec_txe_addAccount': {
221
258
  await this.#processAddAccountInputs(callData);
222
259
  break;
223
260
  }