@aztec/txe 0.0.1-commit.fce3e4f → 0.0.1-commit.ff7989d6c

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 (78) hide show
  1. package/dest/constants.d.ts +3 -0
  2. package/dest/constants.d.ts.map +1 -0
  3. package/dest/constants.js +2 -0
  4. package/dest/index.d.ts +1 -1
  5. package/dest/index.d.ts.map +1 -1
  6. package/dest/index.js +85 -52
  7. package/dest/oracle/interfaces.d.ts +12 -9
  8. package/dest/oracle/interfaces.d.ts.map +1 -1
  9. package/dest/oracle/txe_oracle_public_context.d.ts +7 -7
  10. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  11. package/dest/oracle/txe_oracle_public_context.js +10 -12
  12. package/dest/oracle/txe_oracle_top_level_context.d.ts +23 -14
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  14. package/dest/oracle/txe_oracle_top_level_context.js +177 -79
  15. package/dest/rpc_translator.d.ts +30 -18
  16. package/dest/rpc_translator.d.ts.map +1 -1
  17. package/dest/rpc_translator.js +127 -60
  18. package/dest/state_machine/archiver.d.ts +21 -52
  19. package/dest/state_machine/archiver.d.ts.map +1 -1
  20. package/dest/state_machine/archiver.js +63 -94
  21. package/dest/state_machine/dummy_p2p_client.d.ts +19 -14
  22. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  23. package/dest/state_machine/dummy_p2p_client.js +41 -24
  24. package/dest/state_machine/global_variable_builder.d.ts +6 -5
  25. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  26. package/dest/state_machine/global_variable_builder.js +13 -1
  27. package/dest/state_machine/index.d.ts +7 -7
  28. package/dest/state_machine/index.d.ts.map +1 -1
  29. package/dest/state_machine/index.js +40 -23
  30. package/dest/state_machine/mock_epoch_cache.d.ts +9 -6
  31. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  32. package/dest/state_machine/mock_epoch_cache.js +14 -7
  33. package/dest/state_machine/synchronizer.d.ts +3 -2
  34. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  35. package/dest/state_machine/synchronizer.js +5 -4
  36. package/dest/txe_session.d.ts +21 -15
  37. package/dest/txe_session.d.ts.map +1 -1
  38. package/dest/txe_session.js +151 -52
  39. package/dest/util/encoding.d.ts +618 -19
  40. package/dest/util/encoding.d.ts.map +1 -1
  41. package/dest/util/encoding.js +1 -1
  42. package/dest/util/txe_account_store.d.ts +10 -0
  43. package/dest/util/txe_account_store.d.ts.map +1 -0
  44. package/dest/util/{txe_account_data_provider.js → txe_account_store.js} +1 -1
  45. package/dest/util/txe_public_contract_data_source.d.ts +8 -8
  46. package/dest/util/txe_public_contract_data_source.d.ts.map +1 -1
  47. package/dest/util/txe_public_contract_data_source.js +12 -29
  48. package/dest/utils/block_creation.d.ts +21 -6
  49. package/dest/utils/block_creation.d.ts.map +1 -1
  50. package/dest/utils/block_creation.js +38 -4
  51. package/dest/utils/tx_effect_creation.d.ts +3 -3
  52. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  53. package/dest/utils/tx_effect_creation.js +4 -7
  54. package/package.json +18 -18
  55. package/src/constants.ts +3 -0
  56. package/src/index.ts +97 -60
  57. package/src/oracle/interfaces.ts +11 -8
  58. package/src/oracle/txe_oracle_public_context.ts +12 -19
  59. package/src/oracle/txe_oracle_top_level_context.ts +213 -124
  60. package/src/rpc_translator.ts +156 -60
  61. package/src/state_machine/archiver.ts +59 -114
  62. package/src/state_machine/dummy_p2p_client.ts +57 -32
  63. package/src/state_machine/global_variable_builder.ts +21 -4
  64. package/src/state_machine/index.ts +60 -21
  65. package/src/state_machine/mock_epoch_cache.ts +15 -11
  66. package/src/state_machine/synchronizer.ts +6 -5
  67. package/src/txe_session.ts +207 -100
  68. package/src/util/encoding.ts +1 -1
  69. package/src/util/{txe_account_data_provider.ts → txe_account_store.ts} +1 -1
  70. package/src/util/txe_public_contract_data_source.ts +20 -45
  71. package/src/utils/block_creation.ts +49 -15
  72. package/src/utils/tx_effect_creation.ts +5 -12
  73. package/dest/util/txe_account_data_provider.d.ts +0 -10
  74. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  75. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  76. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  77. package/dest/util/txe_contract_data_provider.js +0 -22
  78. package/src/util/txe_contract_data_provider.ts +0 -36
@@ -1,35 +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';
12
13
  import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
13
14
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
14
- import { Body, L2Block } from '@aztec/stdlib/block';
15
15
  import { computePartialAddress } from '@aztec/stdlib/contract';
16
16
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
17
17
  import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
18
18
  import { PartialPrivateTailPublicInputsForPublic, PrivateKernelTailCircuitPublicInputs, PrivateToPublicAccumulatedData, PublicCallRequest } from '@aztec/stdlib/kernel';
19
19
  import { ChonkProof } from '@aztec/stdlib/proofs';
20
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
20
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
21
21
  import { MerkleTreeId } from '@aztec/stdlib/trees';
22
22
  import { CallContext, HashedValues, PrivateExecutionResult, Tx, TxConstantData, TxContext, TxEffect, TxHash, collectNested } from '@aztec/stdlib/tx';
23
23
  import { ForkCheckpoint } from '@aztec/world-state';
24
+ import { DEFAULT_ADDRESS } from '../constants.js';
24
25
  import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
25
- import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlockHeader } from '../utils/block_creation.js';
26
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
26
27
  export class TXEOracleTopLevelContext {
27
28
  stateMachine;
28
- contractDataProvider;
29
+ contractStore;
30
+ noteStore;
29
31
  keyStore;
30
- addressDataProvider;
31
- accountDataProvider;
32
- pxeOracleInterface;
32
+ addressStore;
33
+ accountStore;
34
+ senderTaggingStore;
35
+ recipientTaggingStore;
36
+ senderAddressBookStore;
37
+ capsuleStore;
38
+ privateEventStore;
39
+ jobId;
33
40
  nextBlockTimestamp;
34
41
  version;
35
42
  chainId;
@@ -37,13 +44,19 @@ export class TXEOracleTopLevelContext {
37
44
  isMisc;
38
45
  isTxe;
39
46
  logger;
40
- 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){
41
48
  this.stateMachine = stateMachine;
42
- this.contractDataProvider = contractDataProvider;
49
+ this.contractStore = contractStore;
50
+ this.noteStore = noteStore;
43
51
  this.keyStore = keyStore;
44
- this.addressDataProvider = addressDataProvider;
45
- this.accountDataProvider = accountDataProvider;
46
- 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;
47
60
  this.nextBlockTimestamp = nextBlockTimestamp;
48
61
  this.version = version;
49
62
  this.chainId = chainId;
@@ -64,17 +77,21 @@ export class TXEOracleTopLevelContext {
64
77
  return Fr.random();
65
78
  }
66
79
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
67
- utilityDebugLog(level, message, fields) {
80
+ utilityLog(level, message, fields) {
68
81
  if (!LogLevels[level]) {
69
- throw new Error(`Invalid debug log level: ${level}`);
82
+ throw new Error(`Invalid log level: ${level}`);
70
83
  }
71
84
  const levelName = LogLevels[level];
72
85
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, {
73
86
  module: `${this.logger.module}:debug_log`
74
87
  });
88
+ return Promise.resolve();
89
+ }
90
+ txeGetDefaultAddress() {
91
+ return DEFAULT_ADDRESS;
75
92
  }
76
93
  async txeGetNextBlockNumber() {
77
- return await this.getLastBlockNumber() + 1;
94
+ return BlockNumber(await this.getLastBlockNumber() + 1);
78
95
  }
79
96
  txeGetNextBlockTimestamp() {
80
97
  return Promise.resolve(this.nextBlockTimestamp);
@@ -83,7 +100,8 @@ export class TXEOracleTopLevelContext {
83
100
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
84
101
  }
85
102
  async txeGetLastTxEffects() {
86
- 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);
87
105
  if (block.body.txEffects.length != 1) {
88
106
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
89
107
  throw new Error(`Expected a single transaction in the last block, found ${block.body.txEffects.length}`);
@@ -95,6 +113,16 @@ export class TXEOracleTopLevelContext {
95
113
  nullifiers: txEffects.nullifiers
96
114
  };
97
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
+ }
98
126
  async txeAdvanceBlocksBy(blocks) {
99
127
  this.logger.debug(`time traveling ${blocks} blocks`);
100
128
  for(let i = 0; i < blocks; i++){
@@ -115,32 +143,32 @@ export class TXEOracleTopLevelContext {
115
143
  if (!secret.equals(Fr.ZERO)) {
116
144
  await this.txeAddAccount(artifact, instance, secret);
117
145
  } else {
118
- await this.contractDataProvider.addContractInstance(instance);
119
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
146
+ await this.contractStore.addContractInstance(instance);
147
+ await this.contractStore.addContractArtifact(artifact);
120
148
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
121
149
  }
122
150
  }
123
151
  async txeAddAccount(artifact, instance, secret) {
124
152
  const partialAddress = await computePartialAddress(instance);
125
153
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
126
- await this.contractDataProvider.addContractInstance(instance);
127
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
154
+ await this.contractStore.addContractInstance(instance);
155
+ await this.contractStore.addContractArtifact(artifact);
128
156
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
129
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
130
- await this.addressDataProvider.addCompleteAddress(completeAddress);
157
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
158
+ await this.addressStore.addCompleteAddress(completeAddress);
131
159
  this.logger.debug(`Created account ${completeAddress.address}`);
132
160
  return completeAddress;
133
161
  }
134
162
  async txeCreateAccount(secret) {
135
- // This is a footgun !
163
+ // This is a foot gun !
136
164
  const completeAddress = await this.keyStore.addAccount(secret, secret);
137
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
138
- await this.addressDataProvider.addCompleteAddress(completeAddress);
165
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
166
+ await this.addressStore.addCompleteAddress(completeAddress);
139
167
  this.logger.debug(`Created account ${completeAddress.address}`);
140
168
  return completeAddress;
141
169
  }
142
170
  async txeAddAuthWitness(address, messageHash) {
143
- const account = await this.accountDataProvider.getAccount(address);
171
+ const account = await this.accountStore.getAccount(address);
144
172
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
145
173
  const schnorr = new Schnorr();
146
174
  const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
@@ -159,42 +187,85 @@ export class TXEOracleTopLevelContext {
159
187
  txEffect.txHash = new TxHash(new Fr(blockNumber));
160
188
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
161
189
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
162
- const block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, makeGlobalVariables(undefined, {
190
+ const globals = makeGlobalVariables(undefined, {
163
191
  blockNumber,
164
192
  timestamp: this.nextBlockTimestamp,
165
193
  version: this.version,
166
194
  chainId: this.chainId
167
- })), new Body([
195
+ });
196
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [
168
197
  txEffect
169
- ]));
198
+ ]);
170
199
  await forkedWorldTrees.close();
171
200
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
172
201
  await this.stateMachine.handleL2Block(block);
173
202
  }
174
203
  async txePrivateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false) {
175
- this.logger.verbose(`Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
176
- 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);
177
206
  if (!artifact) {
178
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';
179
208
  throw new Error(message);
180
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);
181
221
  const blockNumber = await this.txeGetNextBlockNumber();
182
222
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
183
223
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
184
224
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
185
225
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
186
226
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
187
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
188
227
  const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
189
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);
190
234
  const taggingIndexCache = new ExecutionTaggingIndexCache();
191
235
  const simulator = new WASMSimulator();
192
- 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([
193
- new HashedValues(args, argsHash)
194
- ]), noteCache, taggingIndexCache, this.pxeOracleInterface, 0, 1, undefined, undefined, /**
195
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
196
- * contract would perform, including setting senderForTags.
197
- */ 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
+ });
198
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.
199
270
  let result;
200
271
  let executionResult;
@@ -209,18 +280,16 @@ export class TXEOracleTopLevelContext {
209
280
  const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
210
281
  return new HashedValues(calldata, r.calldataHash);
211
282
  }));
212
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
213
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
214
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
215
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
283
+ noteCache.finish();
284
+ const nonceGenerator = noteCache.getNonceGenerator();
285
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
216
286
  } catch (err) {
217
287
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
218
288
  }
219
- // According to the protocol rules, the nonce generator for the note hashes
220
- // can either be the first nullifier in the tx or the hash of the initial tx request
221
- // if there are none.
222
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? protocolNullifier : result.firstNullifier;
223
- 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);
224
293
  const globals = makeGlobalVariables();
225
294
  globals.blockNumber = blockNumber;
226
295
  globals.timestamp = this.nextBlockTimestamp;
@@ -228,7 +297,8 @@ export class TXEOracleTopLevelContext {
228
297
  globals.version = this.version;
229
298
  globals.gasFees = GasFees.empty();
230
299
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
231
- 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);
232
302
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
233
303
  const config = PublicSimulatorConfig.from({
234
304
  skipFeeEnforcement: true,
@@ -237,7 +307,7 @@ export class TXEOracleTopLevelContext {
237
307
  collectStatistics: false,
238
308
  collectCallMetadata: true
239
309
  });
240
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config), new TestDateProvider());
310
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
241
311
  const tx = await Tx.create({
242
312
  data: publicInputs,
243
313
  chonkProof: ChonkProof.empty(),
@@ -258,7 +328,7 @@ export class TXEOracleTopLevelContext {
258
328
  } else if (!processedTx.revertCode.isOK()) {
259
329
  if (processedTx.revertReason) {
260
330
  try {
261
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
331
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
262
332
  // eslint-disable-next-line no-empty
263
333
  } catch {}
264
334
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -280,22 +350,21 @@ export class TXEOracleTopLevelContext {
280
350
  txEffect.txHash = new TxHash(new Fr(blockNumber));
281
351
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
282
352
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
283
- const body = new Body([
353
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
284
354
  txEffect
285
355
  ]);
286
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
287
356
  await this.stateMachine.handleL2Block(l2Block);
288
357
  await forkedWorldTrees.close();
289
358
  return executionResult.returnValues ?? [];
290
359
  }
291
360
  async txePublicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
292
- 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}`);
293
362
  const blockNumber = await this.txeGetNextBlockNumber();
294
363
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
295
364
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
296
365
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
297
366
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
298
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
367
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
299
368
  const calldataHash = await computeCalldataHash(calldata);
300
369
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
301
370
  const globals = makeGlobalVariables();
@@ -305,7 +374,8 @@ export class TXEOracleTopLevelContext {
305
374
  globals.version = this.version;
306
375
  globals.gasFees = GasFees.empty();
307
376
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
308
- 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);
309
379
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
310
380
  const config = PublicSimulatorConfig.from({
311
381
  skipFeeEnforcement: true,
@@ -314,23 +384,21 @@ export class TXEOracleTopLevelContext {
314
384
  collectStatistics: false,
315
385
  collectCallMetadata: true
316
386
  });
317
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config);
318
- 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));
319
389
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
320
390
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
321
391
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
322
392
  // unique.
323
393
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
324
- if (!isStaticCall) {
325
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
326
- }
394
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
327
395
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
328
396
  // may require producing reverts.
329
397
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
330
398
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
331
399
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
332
400
  const constantData = new TxConstantData(anchorBlockHeader, txContext, Fr.zero(), Fr.zero());
333
- 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);
334
402
  const tx = await Tx.create({
335
403
  data: txData,
336
404
  chonkProof: ChonkProof.empty(),
@@ -353,7 +421,7 @@ export class TXEOracleTopLevelContext {
353
421
  } else if (!processedTx.revertCode.isOK()) {
354
422
  if (processedTx.revertReason) {
355
423
  try {
356
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
424
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
357
425
  // eslint-disable-next-line no-empty
358
426
  } catch {}
359
427
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -376,25 +444,37 @@ export class TXEOracleTopLevelContext {
376
444
  txEffect.txHash = new TxHash(new Fr(blockNumber));
377
445
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
378
446
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
379
- const body = new Body([
447
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
380
448
  txEffect
381
449
  ]);
382
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
383
450
  await this.stateMachine.handleL2Block(l2Block);
384
451
  await forkedWorldTrees.close();
385
452
  return returnValues ?? [];
386
453
  }
387
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
388
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
454
+ async txeExecuteUtilityFunction(targetContractAddress, functionSelector, args) {
455
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
389
456
  if (!artifact) {
390
457
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
391
458
  }
392
- 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({
393
465
  name: artifact.name,
466
+ to: targetContractAddress,
394
467
  selector: functionSelector,
395
- to: targetContractAddress
396
- };
397
- 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);
398
478
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
399
479
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
400
480
  }
@@ -403,8 +483,25 @@ export class TXEOracleTopLevelContext {
403
483
  selector: call.selector
404
484
  });
405
485
  try {
406
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
407
- 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)=>{
408
505
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
409
506
  throw new ExecutionError(err.message, {
410
507
  contractAddress: call.to,
@@ -413,10 +510,10 @@ export class TXEOracleTopLevelContext {
413
510
  cause: err
414
511
  });
415
512
  });
416
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
513
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
417
514
  return witnessMapToFields(acirExecutionResult.returnWitness);
418
515
  } catch (err) {
419
- 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'));
420
517
  }
421
518
  }
422
519
  close() {
@@ -427,6 +524,7 @@ export class TXEOracleTopLevelContext {
427
524
  ];
428
525
  }
429
526
  async getLastBlockNumber() {
430
- 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;
431
529
  }
432
530
  }