@aztec/txe 0.0.1-commit.b655e406 → 0.0.1-commit.b6e433891

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 +91 -56
  8. package/dest/oracle/interfaces.d.ts +33 -29
  9. package/dest/oracle/interfaces.d.ts.map +1 -1
  10. package/dest/oracle/txe_oracle_public_context.d.ts +16 -16
  11. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  12. package/dest/oracle/txe_oracle_public_context.js +20 -22
  13. package/dest/oracle/txe_oracle_top_level_context.d.ts +37 -27
  14. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  15. package/dest/oracle/txe_oracle_top_level_context.js +228 -106
  16. package/dest/rpc_translator.d.ts +98 -78
  17. package/dest/rpc_translator.d.ts.map +1 -1
  18. package/dest/rpc_translator.js +367 -171
  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 +66 -99
  22. package/dest/state_machine/dummy_p2p_client.d.ts +21 -14
  23. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  24. package/dest/state_machine/dummy_p2p_client.js +42 -22
  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 +9 -7
  29. package/dest/state_machine/index.d.ts.map +1 -1
  30. package/dest/state_machine/index.js +44 -23
  31. package/dest/state_machine/mock_epoch_cache.d.ts +30 -12
  32. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  33. package/dest/state_machine/mock_epoch_cache.js +53 -15
  34. package/dest/state_machine/synchronizer.d.ts +6 -5
  35. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  36. package/dest/state_machine/synchronizer.js +8 -7
  37. package/dest/txe_session.d.ts +27 -15
  38. package/dest/txe_session.d.ts.map +1 -1
  39. package/dest/txe_session.js +173 -56
  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 +103 -63
  60. package/src/oracle/interfaces.ts +36 -32
  61. package/src/oracle/txe_oracle_public_context.ts +21 -28
  62. package/src/oracle/txe_oracle_top_level_context.ts +272 -145
  63. package/src/rpc_translator.ts +422 -194
  64. package/src/state_machine/archiver.ts +63 -117
  65. package/src/state_machine/dummy_p2p_client.ts +59 -29
  66. package/src/state_machine/global_variable_builder.ts +22 -4
  67. package/src/state_machine/index.ts +64 -21
  68. package/src/state_machine/mock_epoch_cache.ts +67 -23
  69. package/src/state_machine/synchronizer.ts +9 -8
  70. package/src/txe_session.ts +239 -105
  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,88 +1,107 @@
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;
32
39
  nextBlockTimestamp;
33
40
  version;
34
41
  chainId;
35
42
  authwits;
43
+ contractSyncService;
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, nextBlockTimestamp, version, chainId, authwits, contractSyncService){
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;
46
59
  this.nextBlockTimestamp = nextBlockTimestamp;
47
60
  this.version = version;
48
61
  this.chainId = chainId;
49
62
  this.authwits = authwits;
63
+ this.contractSyncService = contractSyncService;
50
64
  this.isMisc = true;
51
65
  this.isTxe = true;
52
66
  this.logger = createLogger('txe:top_level_context');
53
67
  this.logger.debug('Entering Top Level Context');
54
68
  }
55
- utilityAssertCompatibleOracleVersion(version) {
69
+ assertCompatibleOracleVersion(version) {
56
70
  if (version !== ORACLE_VERSION) {
57
71
  throw new Error(`Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`);
58
72
  }
59
73
  }
60
74
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
61
75
  // setup.
62
- utilityGetRandomField() {
76
+ getRandomField() {
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
+ log(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();
74
89
  }
75
- async txeGetNextBlockNumber() {
76
- return await this.getLastBlockNumber() + 1;
90
+ getDefaultAddress() {
91
+ return DEFAULT_ADDRESS;
77
92
  }
78
- txeGetNextBlockTimestamp() {
93
+ async getNextBlockNumber() {
94
+ return BlockNumber(await this.getLastBlockNumber() + 1);
95
+ }
96
+ getNextBlockTimestamp() {
79
97
  return Promise.resolve(this.nextBlockTimestamp);
80
98
  }
81
- async txeGetLastBlockTimestamp() {
99
+ async getLastBlockTimestamp() {
82
100
  return (await this.stateMachine.node.getBlockHeader('latest')).globalVariables.timestamp;
83
101
  }
84
- async txeGetLastTxEffects() {
85
- const block = await this.stateMachine.archiver.getBlock('latest');
102
+ async getLastTxEffects() {
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,17 +113,39 @@ export class TXEOracleTopLevelContext {
94
113
  nullifiers: txEffects.nullifiers
95
114
  };
96
115
  }
97
- async txeAdvanceBlocksBy(blocks) {
116
+ async syncContractNonOracleMethod(contractAddress, scope, jobId) {
117
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
118
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
119
+ return;
120
+ }
121
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
122
+ await this.stateMachine.contractSyncService.ensureContractSynced(contractAddress, null, async (call, execScopes)=>{
123
+ await this.executeUtilityCall(call, execScopes, jobId);
124
+ }, blockHeader, jobId, [
125
+ scope
126
+ ]);
127
+ }
128
+ async getPrivateEvents(selector, contractAddress, scope) {
129
+ return (await this.privateEventStore.getPrivateEvents(selector, {
130
+ contractAddress,
131
+ scopes: [
132
+ scope
133
+ ],
134
+ fromBlock: 0,
135
+ toBlock: await this.getLastBlockNumber() + 1
136
+ })).map((e)=>e.packedEvent);
137
+ }
138
+ async advanceBlocksBy(blocks) {
98
139
  this.logger.debug(`time traveling ${blocks} blocks`);
99
140
  for(let i = 0; i < blocks; i++){
100
141
  await this.mineBlock();
101
142
  }
102
143
  }
103
- txeAdvanceTimestampBy(duration) {
144
+ advanceTimestampBy(duration) {
104
145
  this.logger.debug(`time traveling ${duration} seconds`);
105
146
  this.nextBlockTimestamp += duration;
106
147
  }
107
- async txeDeploy(artifact, instance, secret) {
148
+ async deploy(artifact, instance, secret) {
108
149
  // Emit deployment nullifier
109
150
  await this.mineBlock({
110
151
  nullifiers: [
@@ -112,34 +153,34 @@ export class TXEOracleTopLevelContext {
112
153
  ]
113
154
  });
114
155
  if (!secret.equals(Fr.ZERO)) {
115
- await this.txeAddAccount(artifact, instance, secret);
156
+ await this.addAccount(artifact, instance, secret);
116
157
  } else {
117
- await this.contractDataProvider.addContractInstance(instance);
118
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
158
+ await this.contractStore.addContractInstance(instance);
159
+ await this.contractStore.addContractArtifact(artifact);
119
160
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
120
161
  }
121
162
  }
122
- async txeAddAccount(artifact, instance, secret) {
163
+ async addAccount(artifact, instance, secret) {
123
164
  const partialAddress = await computePartialAddress(instance);
124
165
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
125
- await this.contractDataProvider.addContractInstance(instance);
126
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
166
+ await this.contractStore.addContractInstance(instance);
167
+ await this.contractStore.addContractArtifact(artifact);
127
168
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
128
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
129
- await this.addressDataProvider.addCompleteAddress(completeAddress);
169
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
170
+ await this.addressStore.addCompleteAddress(completeAddress);
130
171
  this.logger.debug(`Created account ${completeAddress.address}`);
131
172
  return completeAddress;
132
173
  }
133
- async txeCreateAccount(secret) {
134
- // This is a footgun !
174
+ async createAccount(secret) {
175
+ // This is a foot gun !
135
176
  const completeAddress = await this.keyStore.addAccount(secret, secret);
136
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
137
- await this.addressDataProvider.addCompleteAddress(completeAddress);
177
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
178
+ await this.addressStore.addCompleteAddress(completeAddress);
138
179
  this.logger.debug(`Created account ${completeAddress.address}`);
139
180
  return completeAddress;
140
181
  }
141
- async txeAddAuthWitness(address, messageHash) {
142
- const account = await this.accountDataProvider.getAccount(address);
182
+ async addAuthWitness(address, messageHash) {
183
+ const account = await this.accountStore.getAccount(address);
143
184
  const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
144
185
  const schnorr = new Schnorr();
145
186
  const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
@@ -149,7 +190,7 @@ export class TXEOracleTopLevelContext {
149
190
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
150
191
  }
151
192
  async mineBlock(options = {}) {
152
- const blockNumber = await this.txeGetNextBlockNumber();
193
+ const blockNumber = await this.getNextBlockNumber();
153
194
  const txEffect = TxEffect.empty();
154
195
  txEffect.nullifiers = [
155
196
  getSingleTxBlockRequestHash(blockNumber),
@@ -158,42 +199,86 @@ export class TXEOracleTopLevelContext {
158
199
  txEffect.txHash = new TxHash(new Fr(blockNumber));
159
200
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
160
201
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
161
- const block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, makeGlobalVariables(undefined, {
202
+ const globals = makeGlobalVariables(undefined, {
162
203
  blockNumber,
163
204
  timestamp: this.nextBlockTimestamp,
164
205
  version: this.version,
165
206
  chainId: this.chainId
166
- })), new Body([
207
+ });
208
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [
167
209
  txEffect
168
- ]));
210
+ ]);
169
211
  await forkedWorldTrees.close();
170
212
  this.logger.info(`Created block ${blockNumber} with timestamp ${block.header.globalVariables.timestamp}`);
171
213
  await this.stateMachine.handleL2Block(block);
172
214
  }
173
- 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);
215
+ async privateCallNewFlow(from, targetContractAddress = AztecAddress.zero(), functionSelector = FunctionSelector.empty(), args, argsHash = Fr.zero(), isStaticCall = false, jobId) {
216
+ this.logger.verbose(`Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`);
217
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
176
218
  if (!artifact) {
177
219
  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
220
  throw new Error(message);
179
221
  }
180
- const blockNumber = await this.txeGetNextBlockNumber();
222
+ // When `from` is the zero address (e.g. when deploying a new account contract), we return an
223
+ // empty scope list which acts as deny-all: no notes are visible and no keys are accessible.
224
+ const effectiveScopes = from.isZero() ? [] : [
225
+ from
226
+ ];
227
+ // Sync notes before executing private function to discover notes from previous transactions
228
+ const utilityExecutor = async (call, execScopes)=>{
229
+ await this.executeUtilityCall(call, execScopes, jobId);
230
+ };
231
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
232
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, utilityExecutor, blockHeader, jobId, effectiveScopes);
233
+ const blockNumber = await this.getNextBlockNumber();
181
234
  const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
182
235
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
183
236
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
184
237
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
185
238
  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);
239
+ const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
240
+ const noteCache = new ExecutionNoteCache(protocolNullifier);
241
+ // In production, the account contract sets the min revertible counter before calling the app function.
242
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
243
+ // marking all side effects as revertible.
244
+ const minRevertibleSideEffectCounter = 1;
245
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
189
246
  const taggingIndexCache = new ExecutionTaggingIndexCache();
190
247
  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);
248
+ const privateExecutionOracle = new PrivateExecutionOracle({
249
+ argsHash,
250
+ txContext,
251
+ callContext,
252
+ anchorBlockHeader: blockHeader,
253
+ utilityExecutor,
254
+ authWitnesses: Array.from(this.authwits.values()),
255
+ capsules: [],
256
+ executionCache: HashedValuesCache.create([
257
+ new HashedValues(args, argsHash)
258
+ ]),
259
+ noteCache,
260
+ taggingIndexCache,
261
+ contractStore: this.contractStore,
262
+ noteStore: this.noteStore,
263
+ keyStore: this.keyStore,
264
+ addressStore: this.addressStore,
265
+ aztecNode: this.stateMachine.node,
266
+ senderTaggingStore: this.senderTaggingStore,
267
+ recipientTaggingStore: this.recipientTaggingStore,
268
+ senderAddressBookStore: this.senderAddressBookStore,
269
+ capsuleStore: this.capsuleStore,
270
+ privateEventStore: this.privateEventStore,
271
+ contractSyncService: this.stateMachine.contractSyncService,
272
+ jobId,
273
+ totalPublicCalldataCount: 0,
274
+ sideEffectCounter: minRevertibleSideEffectCounter,
275
+ scopes: effectiveScopes,
276
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
277
+ // contract would perform, including setting senderForTags.
278
+ senderForTags: from,
279
+ simulator,
280
+ messageContextService: this.stateMachine.messageContextService
281
+ });
197
282
  // 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
283
  let result;
199
284
  let executionResult;
@@ -205,21 +290,19 @@ export class TXEOracleTopLevelContext {
205
290
  r.publicInputs.publicTeardownCallRequest
206
291
  ]));
207
292
  const publicFunctionsCalldata = await Promise.all(publicCallRequests.map(async (r)=>{
208
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
293
+ const calldata = await privateExecutionOracle.loadFromExecutionCache(r.calldataHash);
209
294
  return new HashedValues(calldata, r.calldataHash);
210
295
  }));
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);
296
+ noteCache.finish();
297
+ const nonceGenerator = noteCache.getNonceGenerator();
298
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
215
299
  } catch (err) {
216
300
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
217
301
  }
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);
302
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
303
+ // the nonce generator for the note hashes.
304
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
305
+ const { publicInputs } = await generateSimulatedProvingResult(result, (addr, sel)=>this.contractStore.getDebugFunctionName(addr, sel), this.stateMachine.node, minRevertibleSideEffectCounter);
223
306
  const globals = makeGlobalVariables();
224
307
  globals.blockNumber = blockNumber;
225
308
  globals.timestamp = this.nextBlockTimestamp;
@@ -227,12 +310,17 @@ export class TXEOracleTopLevelContext {
227
310
  globals.version = this.version;
228
311
  globals.gasFees = GasFees.empty();
229
312
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
230
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
313
+ const bindings = this.logger.getBindings();
314
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings);
231
315
  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());
316
+ const config = PublicSimulatorConfig.from({
317
+ skipFeeEnforcement: true,
318
+ collectDebugLogs: true,
319
+ collectHints: false,
320
+ collectStatistics: false,
321
+ collectCallMetadata: true
322
+ });
323
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings), new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings));
236
324
  const tx = await Tx.create({
237
325
  data: publicInputs,
238
326
  chonkProof: ChonkProof.empty(),
@@ -253,7 +341,7 @@ export class TXEOracleTopLevelContext {
253
341
  } else if (!processedTx.revertCode.isOK()) {
254
342
  if (processedTx.revertReason) {
255
343
  try {
256
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
344
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
257
345
  // eslint-disable-next-line no-empty
258
346
  } catch {}
259
347
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -275,22 +363,21 @@ export class TXEOracleTopLevelContext {
275
363
  txEffect.txHash = new TxHash(new Fr(blockNumber));
276
364
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
277
365
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
278
- const body = new Body([
366
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
279
367
  txEffect
280
368
  ]);
281
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
282
369
  await this.stateMachine.handleL2Block(l2Block);
283
370
  await forkedWorldTrees.close();
284
371
  return executionResult.returnValues ?? [];
285
372
  }
286
- 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}`);
288
- const blockNumber = await this.txeGetNextBlockNumber();
373
+ async publicCallNewFlow(from, targetContractAddress, calldata, isStaticCall) {
374
+ this.logger.verbose(`Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`);
375
+ const blockNumber = await this.getNextBlockNumber();
289
376
  const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
290
377
  const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
291
378
  const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
292
379
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
293
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
380
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
294
381
  const calldataHash = await computeCalldataHash(calldata);
295
382
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
296
383
  const globals = makeGlobalVariables();
@@ -300,28 +387,31 @@ export class TXEOracleTopLevelContext {
300
387
  globals.version = this.version;
301
388
  globals.gasFees = GasFees.empty();
302
389
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
303
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
390
+ const bindings2 = this.logger.getBindings();
391
+ const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractStore), bindings2);
304
392
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
305
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
306
- doMerkleOperations: true,
307
- skipFeeEnforcement: true
393
+ const config = PublicSimulatorConfig.from({
394
+ skipFeeEnforcement: true,
395
+ collectDebugLogs: true,
396
+ collectHints: false,
397
+ collectStatistics: false,
398
+ collectCallMetadata: true
308
399
  });
309
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
400
+ const simulator = new CppPublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
401
+ const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider(), undefined, createLogger('simulator:public-processor', bindings2));
310
402
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
311
403
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
312
404
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
313
405
  // unique.
314
406
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
315
- if (!isStaticCall) {
316
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
317
- }
407
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
318
408
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
319
409
  // may require producing reverts.
320
410
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
321
411
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(from, targetContractAddress, isStaticCall, calldataHash);
322
412
  const inputsForPublic = new PartialPrivateTailPublicInputsForPublic(nonRevertibleAccumulatedData, revertibleAccumulatedData, PublicCallRequest.empty());
323
413
  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);
414
+ const txData = new PrivateKernelTailCircuitPublicInputs(constantData, /*gasUsed=*/ new Gas(0, 0), /*feePayer=*/ AztecAddress.zero(), /*expirationTimestamp=*/ 0n, inputsForPublic, undefined);
325
415
  const tx = await Tx.create({
326
416
  data: txData,
327
417
  chonkProof: ChonkProof.empty(),
@@ -344,7 +434,7 @@ export class TXEOracleTopLevelContext {
344
434
  } else if (!processedTx.revertCode.isOK()) {
345
435
  if (processedTx.revertReason) {
346
436
  try {
347
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
437
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
348
438
  // eslint-disable-next-line no-empty
349
439
  } catch {}
350
440
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -367,25 +457,37 @@ export class TXEOracleTopLevelContext {
367
457
  txEffect.txHash = new TxHash(new Fr(blockNumber));
368
458
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
369
459
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
370
- const body = new Body([
460
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [
371
461
  txEffect
372
462
  ]);
373
- const l2Block = new L2Block(makeAppendOnlyTreeSnapshot(), await makeTXEBlockHeader(forkedWorldTrees, globals), body);
374
463
  await this.stateMachine.handleL2Block(l2Block);
375
464
  await forkedWorldTrees.close();
376
465
  return returnValues ?? [];
377
466
  }
378
- async txeSimulateUtilityFunction(targetContractAddress, functionSelector, args) {
379
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
467
+ async executeUtilityFunction(targetContractAddress, functionSelector, args, jobId) {
468
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
380
469
  if (!artifact) {
381
470
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
382
471
  }
383
- const call = {
472
+ // Sync notes before executing utility function to discover notes from previous transactions
473
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
474
+ await this.stateMachine.contractSyncService.ensureContractSynced(targetContractAddress, functionSelector, async (call, execScopes)=>{
475
+ await this.executeUtilityCall(call, execScopes, jobId);
476
+ }, blockHeader, jobId, 'ALL_SCOPES');
477
+ const call = FunctionCall.from({
384
478
  name: artifact.name,
479
+ to: targetContractAddress,
385
480
  selector: functionSelector,
386
- to: targetContractAddress
387
- };
388
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
481
+ type: FunctionType.UTILITY,
482
+ hideMsgSender: false,
483
+ isStatic: false,
484
+ args,
485
+ returnTypes: []
486
+ });
487
+ return this.executeUtilityCall(call, 'ALL_SCOPES', jobId);
488
+ }
489
+ async executeUtilityCall(call, scopes, jobId) {
490
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
389
491
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
390
492
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
391
493
  }
@@ -394,8 +496,27 @@ export class TXEOracleTopLevelContext {
394
496
  selector: call.selector
395
497
  });
396
498
  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)=>{
499
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
500
+ const oracle = new UtilityExecutionOracle({
501
+ contractAddress: call.to,
502
+ authWitnesses: [],
503
+ capsules: [],
504
+ anchorBlockHeader,
505
+ contractStore: this.contractStore,
506
+ noteStore: this.noteStore,
507
+ keyStore: this.keyStore,
508
+ addressStore: this.addressStore,
509
+ aztecNode: this.stateMachine.node,
510
+ recipientTaggingStore: this.recipientTaggingStore,
511
+ senderAddressBookStore: this.senderAddressBookStore,
512
+ capsuleStore: this.capsuleStore,
513
+ privateEventStore: this.privateEventStore,
514
+ messageContextService: this.stateMachine.messageContextService,
515
+ contractSyncService: this.contractSyncService,
516
+ jobId,
517
+ scopes
518
+ });
519
+ const acirExecutionResult = await new WASMSimulator().executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback()).catch((err)=>{
399
520
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
400
521
  throw new ExecutionError(err.message, {
401
522
  contractAddress: call.to,
@@ -404,10 +525,10 @@ export class TXEOracleTopLevelContext {
404
525
  cause: err
405
526
  });
406
527
  });
407
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
528
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
408
529
  return witnessMapToFields(acirExecutionResult.returnWitness);
409
530
  } catch (err) {
410
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
531
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
411
532
  }
412
533
  }
413
534
  close() {
@@ -418,6 +539,7 @@ export class TXEOracleTopLevelContext {
418
539
  ];
419
540
  }
420
541
  async getLastBlockNumber() {
421
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
542
+ const header = await this.stateMachine.node.getBlockHeader('latest');
543
+ return header ? header.globalVariables.blockNumber : BlockNumber.ZERO;
422
544
  }
423
545
  }