@aztec/txe 0.0.1-fake-c83136db25 → 0.0.2-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 (81) hide show
  1. package/dest/bin/index.d.ts +1 -1
  2. package/dest/constants.d.ts +3 -0
  3. package/dest/constants.d.ts.map +1 -0
  4. package/dest/constants.js +2 -0
  5. package/dest/index.d.ts +1 -1
  6. package/dest/index.d.ts.map +1 -1
  7. package/dest/index.js +85 -52
  8. package/dest/oracle/interfaces.d.ts +12 -9
  9. package/dest/oracle/interfaces.d.ts.map +1 -1
  10. package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
  11. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  12. package/dest/oracle/txe_oracle_public_context.js +10 -12
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts +23 -14
  14. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  15. package/dest/oracle/txe_oracle_top_level_context.js +194 -87
  16. package/dest/rpc_translator.d.ts +35 -20
  17. package/dest/rpc_translator.d.ts.map +1 -1
  18. package/dest/rpc_translator.js +138 -64
  19. package/dest/state_machine/archiver.d.ts +21 -51
  20. package/dest/state_machine/archiver.d.ts.map +1 -1
  21. package/dest/state_machine/archiver.js +63 -94
  22. package/dest/state_machine/dummy_p2p_client.d.ts +20 -13
  23. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  24. package/dest/state_machine/dummy_p2p_client.js +41 -21
  25. package/dest/state_machine/global_variable_builder.d.ts +6 -4
  26. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  27. package/dest/state_machine/global_variable_builder.js +13 -1
  28. package/dest/state_machine/index.d.ts +7 -7
  29. package/dest/state_machine/index.d.ts.map +1 -1
  30. package/dest/state_machine/index.js +40 -23
  31. package/dest/state_machine/mock_epoch_cache.d.ts +14 -10
  32. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  33. package/dest/state_machine/mock_epoch_cache.js +21 -13
  34. package/dest/state_machine/synchronizer.d.ts +3 -2
  35. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  36. package/dest/state_machine/synchronizer.js +5 -4
  37. package/dest/txe_session.d.ts +21 -15
  38. package/dest/txe_session.d.ts.map +1 -1
  39. package/dest/txe_session.js +154 -53
  40. package/dest/util/encoding.d.ts +615 -16
  41. package/dest/util/encoding.d.ts.map +1 -1
  42. package/dest/util/encoding.js +1 -1
  43. package/dest/util/expected_failure_error.d.ts +1 -1
  44. package/dest/util/expected_failure_error.d.ts.map +1 -1
  45. package/dest/util/txe_account_store.d.ts +10 -0
  46. package/dest/util/txe_account_store.d.ts.map +1 -0
  47. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  48. package/dest/util/txe_public_contract_data_source.d.ts +8 -8
  49. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  50. package/dest/util/txe_public_contract_data_source.js +12 -29
  51. package/dest/utils/block_creation.d.ts +21 -6
  52. package/dest/utils/block_creation.d.ts.map +1 -1
  53. package/dest/utils/block_creation.js +38 -4
  54. package/dest/utils/tx_effect_creation.d.ts +3 -3
  55. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  56. package/dest/utils/tx_effect_creation.js +4 -7
  57. package/package.json +18 -17
  58. package/src/constants.ts +3 -0
  59. package/src/index.ts +97 -60
  60. package/src/oracle/interfaces.ts +11 -8
  61. package/src/oracle/txe_oracle_public_context.ts +12 -19
  62. package/src/oracle/txe_oracle_top_level_context.ts +229 -131
  63. package/src/rpc_translator.ts +164 -68
  64. package/src/state_machine/archiver.ts +63 -117
  65. package/src/state_machine/dummy_p2p_client.ts +58 -28
  66. package/src/state_machine/global_variable_builder.ts +22 -4
  67. package/src/state_machine/index.ts +60 -21
  68. package/src/state_machine/mock_epoch_cache.ts +25 -20
  69. package/src/state_machine/synchronizer.ts +6 -5
  70. package/src/txe_session.ts +210 -101
  71. package/src/util/encoding.ts +1 -1
  72. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  73. package/src/util/txe_public_contract_data_source.ts +20 -45
  74. package/src/utils/block_creation.ts +49 -14
  75. package/src/utils/tx_effect_creation.ts +5 -12
  76. package/dest/util/txe_account_data_provider.d.ts +0 -10
  77. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  78. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  79. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  80. package/dest/util/txe_contract_data_provider.js +0 -22
  81. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -1,34 +1,42 @@
1
1
  import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS, DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT, DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT, NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP } from '@aztec/constants';
2
- import { Schnorr } from '@aztec/foundation/crypto';
3
- import { Fr } from '@aztec/foundation/fields';
2
+ import { BlockNumber } from '@aztec/foundation/branded-types';
3
+ import { Schnorr } from '@aztec/foundation/crypto/schnorr';
4
+ import { Fr } from '@aztec/foundation/curves/bn254';
4
5
  import { LogLevels, applyStringFormatting, createLogger } from '@aztec/foundation/log';
5
6
  import { TestDateProvider } from '@aztec/foundation/timer';
6
7
  import { ORACLE_VERSION, enrichPublicSimulationError } from '@aztec/pxe/server';
7
8
  import { ExecutionNoteCache, ExecutionTaggingIndexCache, HashedValuesCache, Oracle, PrivateExecutionOracle, UtilityExecutionOracle, executePrivateFunction, generateSimulatedProvingResult } from '@aztec/pxe/simulator';
8
9
  import { ExecutionError, WASMSimulator, createSimulationError, extractCallStack, resolveAssertionMessageFromError, toACVMWitness, witnessMapToFields } from '@aztec/simulator/client';
9
- import { GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor, PublicTxSimulator } from '@aztec/simulator/server';
10
- import { FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
10
+ import { CppPublicTxSimulator, GuardedMerkleTreeOperations, PublicContractsDB, PublicProcessor } from '@aztec/simulator/server';
11
+ import { FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
11
12
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
13
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
12
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
13
- import { Body, L2Block } from '@aztec/stdlib/block';
14
15
  import { computePartialAddress } from '@aztec/stdlib/contract';
15
16
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
16
- import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
17
+ import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
17
18
  import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
18
19
  import { ChonkProof } from '@aztec/stdlib/proofs';
19
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
20
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
20
21
  import { MerkleTreeId } from '@aztec/stdlib/trees';
21
22
  import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
22
23
  import { ForkCheckpoint } from '@aztec/world-state';
24
+ import { DEFAULT_ADDRESS } from '../constants.js';
23
25
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
24
- import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlockHeader } from '../utils/block_creation.js';
26
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
25
27
  export class TXEOracleTopLevelContext {
26
28
  stateMachine;
27
- contractDataProvider;
29
+ contractStore;
30
+ noteStore;
28
31
  keyStore;
29
- addressDataProvider;
30
- accountDataProvider;
31
- pxeOracleInterface;
32
+ addressStore;
33
+ accountStore;
34
+ senderTaggingStore;
35
+ recipientTaggingStore;
36
+ senderAddressBookStore;
37
+ capsuleStore;
38
+ privateEventStore;
39
+ jobId;
32
40
  nextBlockTimestamp;
33
41
  version;
34
42
  chainId;
@@ -36,13 +44,19 @@ export class TXEOracleTopLevelContext {
36
44
  isMisc;
37
45
  isTxe;
38
46
  logger;
39
- constructor(stateMachine, contractDataProvider, keyStore, addressDataProvider, accountDataProvider, pxeOracleInterface, nextBlockTimestamp, version, chainId, authwits){
47
+ constructor(stateMachine, contractStore, noteStore, keyStore, addressStore, accountStore, senderTaggingStore, recipientTaggingStore, senderAddressBookStore, capsuleStore, privateEventStore, jobId, nextBlockTimestamp, version, chainId, authwits){
40
48
  this.stateMachine = stateMachine;
41
- this.contractDataProvider = contractDataProvider;
49
+ this.contractStore = contractStore;
50
+ this.noteStore = noteStore;
42
51
  this.keyStore = keyStore;
43
- this.addressDataProvider = addressDataProvider;
44
- this.accountDataProvider = accountDataProvider;
45
- this.pxeOracleInterface = pxeOracleInterface;
52
+ this.addressStore = addressStore;
53
+ this.accountStore = accountStore;
54
+ this.senderTaggingStore = senderTaggingStore;
55
+ this.recipientTaggingStore = recipientTaggingStore;
56
+ this.senderAddressBookStore = senderAddressBookStore;
57
+ this.capsuleStore = capsuleStore;
58
+ this.privateEventStore = privateEventStore;
59
+ this.jobId = jobId;
46
60
  this.nextBlockTimestamp = nextBlockTimestamp;
47
61
  this.version = version;
48
62
  this.chainId = chainId;
@@ -63,17 +77,21 @@ export class TXEOracleTopLevelContext {
63
77
  return Fr.random();
64
78
  }
65
79
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
66
- utilityDebugLog(level, message, fields) {
80
+ utilityLog(level, message, fields) {
67
81
  if (!LogLevels[level]) {
68
- throw new Error(`Invalid debug log level: ${level}`);
82
+ throw new Error(`Invalid log level: ${level}`);
69
83
  }
70
84
  const levelName = LogLevels[level];
71
85
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
72
86
  module: `${this.logger.module}:debug_log`
73
87
  });
88
+ return Promise.resolve();
89
+ }
90
+ txeGetDefaultAddress() {
91
+ return DEFAULT_ADDRESS;
74
92
  }
75
93
  async txeGetNextBlockNumber() {
76
- return await this.getLastBlockNumber() + 1;
94
+ return BlockNumber(await this.getLastBlockNumber() + 1);
77
95
  }
78
96
  txeGetNextBlockTimestamp() {
79
97
  return Promise.resolve(this.nextBlockTimestamp);
@@ -82,7 +100,8 @@ export class TXEOracleTopLevelContext {
82
100
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
83
101
  }
84
102
  async txeGetLastTxEffects() {
85
- const block = await this.stateMachine.archiver.getBlock('latest');
103
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
104
+ const block = await this.stateMachine.archiver.getBlock(latestBlockNumber);
86
105
  if (block.body.txEffects.length != 1) {
87
106
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
88
107
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
@@ -94,6 +113,16 @@ export class TXEOracleTopLevelContext {
94
113
  nullifiers: txEffects.nullifiers
95
114
  };
96
115
  }
116
+ async txeGetPrivateEvents(selector, contractAddress, scope) {
117
+ return (await this.privateEventStore.getPrivateEvents(selector, {
118
+ contractAddress,
119
+ scopes: [
120
+ scope
121
+ ],
122
+ fromBlock: 0,
123
+ toBlock: await this.getLastBlockNumber() + 1
124
+ })).map((e)=>e.packedEvent);
125
+ }
97
126
  async txeAdvanceBlocksBy(blocks) {
98
127
  this.logger.debug(`time traveling ${blocks} blocks`);
99
128
  for(let i = 0; i < blocks; i++){
@@ -114,32 +143,32 @@ export class TXEOracleTopLevelContext {
114
143
  if (!secret.equals(Fr.ZERO)) {
115
144
  await this.txeAddAccount(artifact, instance, secret);
116
145
  } else {
117
- await this.contractDataProvider.addContractInstance(instance);
118
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
146
+ await this.contractStore.addContractInstance(instance);
147
+ await this.contractStore.addContractArtifact(artifact);
119
148
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
120
149
  }
121
150
  }
122
151
  async txeAddAccount(artifact, instance, secret) {
123
152
  const partialAddress = await computePartialAddress(instance);
124
153
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
125
- await this.contractDataProvider.addContractInstance(instance);
126
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
154
+ await this.contractStore.addContractInstance(instance);
155
+ await this.contractStore.addContractArtifact(artifact);
127
156
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
128
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
129
- await this.addressDataProvider.addCompleteAddress(completeAddress);
157
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
158
+ await this.addressStore.addCompleteAddress(completeAddress);
130
159
  this.logger.debug(`Created account ${completeAddress.address}`);
131
160
  return completeAddress;
132
161
  }
133
162
  async txeCreateAccount(secret) {
134
- // This is a footgun !
163
+ // This is a foot gun !
135
164
  const completeAddress = await this.keyStore.addAccount(secret, secret);
136
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
137
- await this.addressDataProvider.addCompleteAddress(completeAddress);
165
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
166
+ await this.addressStore.addCompleteAddress(completeAddress);
138
167
  this.logger.debug(`Created account ${completeAddress.address}`);
139
168
  return completeAddress;
140
169
  }
141
170
  async txeAddAuthWitness(address, messageHash) {
142
- const account = await this.accountDataProvider.getAccount(address);
171
+ const account = await this.accountStore.getAccount(address);
143
172
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
144
173
  const schnorr = new Schnorr();
145
174
  const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
@@ -158,42 +187,85 @@ export class TXEOracleTopLevelContext {
158
187
  txEffect.txHash = new TxHash(new Fr(blockNumber));
159
188
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
160
189
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
161
- const block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, makeGlobalVariables(undefined, {
190
+ const globals = makeGlobalVariables(undefined, {
162
191
  blockNumber,
163
192
  timestamp: this.nextBlockTimestamp,
164
193
  version: this.version,
165
194
  chainId: this.chainId
166
- })), new Body([
195
+ });
196
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [
167
197
  txEffect
168
- ]));
198
+ ]);
169
199
  await forkedWorldTrees.close();
170
200
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
171
201
  await this.stateMachine.handleL2Block(block);
172
202
  }
173
203
  async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
174
- this.logger.verbose(`Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
175
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
204
+ this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
205
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
176
206
  if (!artifact) {
177
207
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)')) ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.' : 'Function Artifact does not exist';
178
208
  throw new Error(message);
179
209
  }
210
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
211
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
212
+ const effectiveScopes = from.isZero() ? [] : [
213
+ from
214
+ ];
215
+ // Sync notes before executing private function to discover notes from previous transactions
216
+ const utilityExecutor = async (call, execScopes)=>{
217
+ await this.executeUtilityCall(call, execScopes);
218
+ };
219
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
220
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, this.jobId, effectiveScopes);
180
221
  const blockNumber = await this.txeGetNextBlockNumber();
181
222
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
182
223
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
183
224
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
184
225
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
185
226
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
186
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
187
- const txRequestHash = getSingleTxBlockRequestHash(blockNumber);
188
- const noteCache = new ExecutionNoteCache(txRequestHash);
227
+ const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
228
+ const noteCache = new ExecutionNoteCache(protocolNullifier);
229
+ // In production, the account contract sets the min revertible counter before calling the app function.
230
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
231
+ // marking all side effects as revertible.
232
+ const minRevertibleSideEffectCounter = 1;
233
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
189
234
  const taggingIndexCache = new ExecutionTaggingIndexCache();
190
235
  const simulator = new WASMSimulator();
191
- const privateExecutionOracle = new PrivateExecutionOracle(argsHash, txContext, callContext, /** Header of a block whose state is used during private execution (not the block the transaction is included in). */ blockHeader, /** List of transient auth witnesses to be used during this simulation */ Array.from(this.authwits.values()), /** List of transient auth witnesses to be used during this simulation */ [], HashedValuesCache.create([
192
- new HashedValues(args, argsHash)
193
- ]), noteCache, taggingIndexCache, this.pxeOracleInterface, 0, 1, undefined, undefined, /**
194
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
195
- * contract would perform, including setting senderForTags.
196
- */ from, simulator);
236
+ const privateExecutionOracle = new PrivateExecutionOracle({
237
+ argsHash,
238
+ txContext,
239
+ callContext,
240
+ anchorBlockHeader: blockHeader,
241
+ utilityExecutor,
242
+ authWitnesses: Array.from(this.authwits.values()),
243
+ capsules: [],
244
+ executionCache: HashedValuesCache.create([
245
+ new HashedValues(args, argsHash)
246
+ ]),
247
+ noteCache,
248
+ taggingIndexCache,
249
+ contractStore: this.contractStore,
250
+ noteStore: this.noteStore,
251
+ keyStore: this.keyStore,
252
+ addressStore: this.addressStore,
253
+ aztecNode: this.stateMachine.node,
254
+ senderTaggingStore: this.senderTaggingStore,
255
+ recipientTaggingStore: this.recipientTaggingStore,
256
+ senderAddressBookStore: this.senderAddressBookStore,
257
+ capsuleStore: this.capsuleStore,
258
+ privateEventStore: this.privateEventStore,
259
+ contractSyncService: this.stateMachine.contractSyncService,
260
+ jobId: this.jobId,
261
+ totalPublicCalldataCount: 0,
262
+ sideEffectCounter: minRevertibleSideEffectCounter,
263
+ scopes: effectiveScopes,
264
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
265
+ // contract would perform, including setting senderForTags.
266
+ senderForTags: from,
267
+ simulator
268
+ });
197
269
  // Note: This is a slight modification of simulator.run without any of the checks. Maybe we should modify simulator.run with a boolean value to skip checks.
198
270
  let result;
199
271
  let executionResult;
@@ -208,18 +280,16 @@ export class TXEOracleTopLevelContext {
208
280
  const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
209
281
  return new HashedValues(calldata, r.calldataHash);
210
282
  }));
211
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
212
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
213
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
214
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
283
+ noteCache.finish();
284
+ const nonceGenerator = noteCache.getNonceGenerator();
285
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
215
286
  } catch (err) {
216
287
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
217
288
  }
218
- // According to the protocol rules, the nonce generator for the note hashes
219
- // can either be the first nullifier in the tx or the hash of the initial tx request
220
- // if there are none.
221
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? txRequestHash : result.firstNullifier;
222
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
289
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
290
+ // the nonce generator for the note hashes.
291
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
292
+ const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
223
293
  const globals = makeGlobalVariables();
224
294
  globals.blockNumber = blockNumber;
225
295
  globals.timestamp = this.nextBlockTimestamp;
@@ -227,12 +297,17 @@ export class TXEOracleTopLevelContext {
227
297
  globals.version = this.version;
228
298
  globals.gasFees = GasFees.empty();
229
299
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
230
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
300
+ const bindings = this.logger.getBindings();
301
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
231
302
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
232
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
233
- doMerkleOperations: true,
234
- skipFeeEnforcement: true
235
- }), new TestDateProvider());
303
+ const config = PublicSimulatorConfig.from({
304
+ skipFeeEnforcement: true,
305
+ collectDebugLogs: true,
306
+ collectHints: false,
307
+ collectStatistics: false,
308
+ collectCallMetadata: true
309
+ });
310
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
236
311
  const tx = await Tx.create({
237
312
  data: publicInputs,
238
313
  chonkProof: ChonkProof.empty(),
@@ -253,7 +328,7 @@ export class TXEOracleTopLevelContext {
253
328
  } else if (!processedTx.revertCode.isOK()) {
254
329
  if (processedTx.revertReason) {
255
330
  try {
256
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
331
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
257
332
  // eslint-disable-next-line no-empty
258
333
  } catch {}
259
334
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -275,22 +350,21 @@ export class TXEOracleTopLevelContext {
275
350
  txEffect.txHash = new TxHash(new Fr(blockNumber));
276
351
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
277
352
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
278
- const body = new Body([
353
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
279
354
  txEffect
280
355
  ]);
281
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
282
356
  await this.stateMachine.handleL2Block(l2Block);
283
357
  await forkedWorldTrees.close();
284
358
  return executionResult.returnValues ?? [];
285
359
  }
286
360
  async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
287
- this.logger.verbose(`Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
361
+ this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
288
362
  const blockNumber = await this.txeGetNextBlockNumber();
289
363
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
290
364
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
291
365
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
292
366
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
293
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
367
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
294
368
  const calldataHash = await computeCalldataHash(calldata);
295
369
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
296
370
  const globals = makeGlobalVariables();
@@ -300,28 +374,31 @@ export class TXEOracleTopLevelContext {
300
374
  globals.version = this.version;
301
375
  globals.gasFees = GasFees.empty();
302
376
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
303
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
377
+ const bindings2 = this.logger.getBindings();
378
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
304
379
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
305
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
306
- doMerkleOperations: true,
307
- skipFeeEnforcement: true
380
+ const config = PublicSimulatorConfig.from({
381
+ skipFeeEnforcement: true,
382
+ collectDebugLogs: true,
383
+ collectHints: false,
384
+ collectStatistics: false,
385
+ collectCallMetadata: true
308
386
  });
309
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
387
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
388
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
310
389
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
311
390
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
312
391
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
313
392
  // unique.
314
393
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
315
- if (!isStaticCall) {
316
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
317
- }
394
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
318
395
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
319
396
  // may require producing reverts.
320
397
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
321
398
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
322
399
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
323
400
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
324
- const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*includeByTimestamp=*/ 0n, inputsForPublic, undefined);
401
+ const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
325
402
  const tx = await Tx.create({
326
403
  data: txData,
327
404
  chonkProof: ChonkProof.empty(),
@@ -344,7 +421,7 @@ export class TXEOracleTopLevelContext {
344
421
  } else if (!processedTx.revertCode.isOK()) {
345
422
  if (processedTx.revertReason) {
346
423
  try {
347
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
424
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
348
425
  // eslint-disable-next-line no-empty
349
426
  } catch {}
350
427
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -367,25 +444,37 @@ export class TXEOracleTopLevelContext {
367
444
  txEffect.txHash = new TxHash(new Fr(blockNumber));
368
445
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
369
446
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
370
- const body = new Body([
447
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
371
448
  txEffect
372
449
  ]);
373
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
374
450
  await this.stateMachine.handleL2Block(l2Block);
375
451
  await forkedWorldTrees.close();
376
452
  return returnValues ?? [];
377
453
  }
378
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
379
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
454
+ async txeExecuteUtilityFunction(targetContractAddress, functionSelector, args) {
455
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
380
456
  if (!artifact) {
381
457
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
382
458
  }
383
- const call = {
459
+ // Sync notes before executing utility function to discover notes from previous transactions
460
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
461
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
462
+ await this.executeUtilityCall(call, execScopes);
463
+ }, blockHeader, this.jobId, 'ALL_SCOPES');
464
+ const call = FunctionCall.from({
384
465
  name: artifact.name,
466
+ to: targetContractAddress,
385
467
  selector: functionSelector,
386
- to: targetContractAddress
387
- };
388
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
468
+ type: FunctionType.UTILITY,
469
+ hideMsgSender: false,
470
+ isStatic: false,
471
+ args,
472
+ returnTypes: []
473
+ });
474
+ return this.executeUtilityCall(call, 'ALL_SCOPES');
475
+ }
476
+ async executeUtilityCall(call, scopes) {
477
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
389
478
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
390
479
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
391
480
  }
@@ -394,8 +483,25 @@ export class TXEOracleTopLevelContext {
394
483
  selector: call.selector
395
484
  });
396
485
  try {
397
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
398
- const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
486
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
487
+ const oracle = new UtilityExecutionOracle({
488
+ contractAddress: call.to,
489
+ authWitnesses: [],
490
+ capsules: [],
491
+ anchorBlockHeader,
492
+ contractStore: this.contractStore,
493
+ noteStore: this.noteStore,
494
+ keyStore: this.keyStore,
495
+ addressStore: this.addressStore,
496
+ aztecNode: this.stateMachine.node,
497
+ recipientTaggingStore: this.recipientTaggingStore,
498
+ senderAddressBookStore: this.senderAddressBookStore,
499
+ capsuleStore: this.capsuleStore,
500
+ privateEventStore: this.privateEventStore,
501
+ jobId: this.jobId,
502
+ scopes
503
+ });
504
+ const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
399
505
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
400
506
  throw new ExecutionError(err.message, {
401
507
  contractAddress: call.to,
@@ -404,10 +510,10 @@ export class TXEOracleTopLevelContext {
404
510
  cause: err
405
511
  });
406
512
  });
407
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
513
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
408
514
  return witnessMapToFields(acirExecutionResult.returnWitness);
409
515
  } catch (err) {
410
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
516
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
411
517
  }
412
518
  }
413
519
  close() {
@@ -418,6 +524,7 @@ export class TXEOracleTopLevelContext {
418
524
  ];
419
525
  }
420
526
  async getLastBlockNumber() {
421
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
527
+ const header = await this.stateMachine.node.getBlockHeader('latest');
528
+ return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
422
529
  }
423
530
  }