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

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 (167) hide show
  1. package/dest/ContractClassRegistry-PII7Q556.js +3 -0
  2. package/dest/ContractClassRegistry-PII7Q556.js.map +7 -0
  3. package/dest/ContractInstanceRegistry-3MHLGFNZ.js +3 -0
  4. package/dest/ContractInstanceRegistry-3MHLGFNZ.js.map +7 -0
  5. package/dest/FeeJuice-TQV5AQK7.js +3 -0
  6. package/dest/FeeJuice-TQV5AQK7.js.map +7 -0
  7. package/dest/MultiCallEntrypoint-SBJUIJY7.js +3 -0
  8. package/dest/MultiCallEntrypoint-SBJUIJY7.js.map +7 -0
  9. package/dest/SchnorrAccount-MQXPIZ44.js +3 -0
  10. package/dest/SchnorrAccount-MQXPIZ44.js.map +7 -0
  11. package/dest/bin/check_txe_oracle_version.d.ts +2 -0
  12. package/dest/bin/check_txe_oracle_version.d.ts.map +1 -0
  13. package/dest/bin/check_txe_oracle_version.js +61 -0
  14. package/dest/bin/index.d.ts +1 -1
  15. package/dest/bin/index.js +3 -30
  16. package/dest/bin/index.js.map +7 -0
  17. package/dest/bin/oracle_test_server.d.ts +3 -0
  18. package/dest/bin/oracle_test_server.d.ts.map +1 -0
  19. package/dest/bin/oracle_test_server.js +41 -0
  20. package/dest/chunk-BJVAAXNA.js +3 -0
  21. package/dest/chunk-BJVAAXNA.js.map +7 -0
  22. package/dest/chunk-CUSVOJA4.js +304 -0
  23. package/dest/chunk-CUSVOJA4.js.map +7 -0
  24. package/dest/chunk-OYLIPWI6.js +260 -0
  25. package/dest/chunk-OYLIPWI6.js.map +7 -0
  26. package/dest/constants.d.ts +7 -0
  27. package/dest/constants.d.ts.map +1 -0
  28. package/dest/constants.js +10 -0
  29. package/dest/dispatcher_pool.d.ts +67 -0
  30. package/dest/dispatcher_pool.d.ts.map +1 -0
  31. package/dest/dispatcher_pool.js +284 -0
  32. package/dest/index.d.ts +185 -7
  33. package/dest/index.d.ts.map +1 -1
  34. package/dest/index.js +73 -158
  35. package/dest/metafile.json +36863 -0
  36. package/dest/msgpackr_fr_extension.d.ts +2 -0
  37. package/dest/msgpackr_fr_extension.d.ts.map +1 -0
  38. package/dest/msgpackr_fr_extension.js +21 -0
  39. package/dest/oracle/interfaces.d.ts +60 -31
  40. package/dest/oracle/interfaces.d.ts.map +1 -1
  41. package/dest/oracle/test-resolver/fixtures.d.ts +43 -0
  42. package/dest/oracle/test-resolver/fixtures.d.ts.map +1 -0
  43. package/dest/oracle/test-resolver/fixtures.js +39 -0
  44. package/dest/oracle/test-resolver/index.d.ts +9 -0
  45. package/dest/oracle/test-resolver/index.d.ts.map +1 -0
  46. package/dest/oracle/test-resolver/index.js +33 -0
  47. package/dest/oracle/test-resolver/resolver.d.ts +34 -0
  48. package/dest/oracle/test-resolver/resolver.d.ts.map +1 -0
  49. package/dest/oracle/test-resolver/resolver.js +114 -0
  50. package/dest/oracle/txe_oracle_public_context.d.ts +41 -17
  51. package/dest/oracle/txe_oracle_public_context.d.ts.map +1 -1
  52. package/dest/oracle/txe_oracle_public_context.js +63 -23
  53. package/dest/oracle/txe_oracle_registry.d.ts +147 -0
  54. package/dest/oracle/txe_oracle_registry.d.ts.map +1 -0
  55. package/dest/oracle/txe_oracle_registry.js +562 -0
  56. package/dest/oracle/txe_oracle_top_level_context.d.ts +57 -28
  57. package/dest/oracle/txe_oracle_top_level_context.d.ts.map +1 -1
  58. package/dest/oracle/txe_oracle_top_level_context.js +341 -130
  59. package/dest/oracle/txe_oracle_version.d.ts +17 -0
  60. package/dest/oracle/txe_oracle_version.d.ts.map +1 -0
  61. package/dest/oracle/txe_oracle_version.js +14 -0
  62. package/dest/oracle/txe_private_execution_oracle.d.ts +17 -0
  63. package/dest/oracle/txe_private_execution_oracle.d.ts.map +1 -0
  64. package/dest/oracle/txe_private_execution_oracle.js +15 -0
  65. package/dest/rpc_server.d.ts +14 -0
  66. package/dest/rpc_server.d.ts.map +1 -0
  67. package/dest/rpc_server.js +78 -0
  68. package/dest/rpc_translator.d.ts +96 -213
  69. package/dest/rpc_translator.d.ts.map +1 -1
  70. package/dest/rpc_translator.js +815 -550
  71. package/dest/server.bundle.js +3 -0
  72. package/dest/server.bundle.js.map +7 -0
  73. package/dest/state_machine/archiver.d.ts +23 -52
  74. package/dest/state_machine/archiver.d.ts.map +1 -1
  75. package/dest/state_machine/archiver.js +77 -99
  76. package/dest/state_machine/dummy_p2p_client.d.ts +28 -15
  77. package/dest/state_machine/dummy_p2p_client.d.ts.map +1 -1
  78. package/dest/state_machine/dummy_p2p_client.js +54 -22
  79. package/dest/state_machine/global_variable_builder.d.ts +11 -4
  80. package/dest/state_machine/global_variable_builder.d.ts.map +1 -1
  81. package/dest/state_machine/global_variable_builder.js +21 -3
  82. package/dest/state_machine/index.d.ts +11 -7
  83. package/dest/state_machine/index.d.ts.map +1 -1
  84. package/dest/state_machine/index.js +60 -25
  85. package/dest/state_machine/mock_epoch_cache.d.ts +29 -12
  86. package/dest/state_machine/mock_epoch_cache.d.ts.map +1 -1
  87. package/dest/state_machine/mock_epoch_cache.js +50 -15
  88. package/dest/state_machine/synchronizer.d.ts +6 -5
  89. package/dest/state_machine/synchronizer.d.ts.map +1 -1
  90. package/dest/state_machine/synchronizer.js +9 -8
  91. package/dest/txe_session.d.ts +94 -21
  92. package/dest/txe_session.d.ts.map +1 -1
  93. package/dest/txe_session.js +314 -68
  94. package/dest/utils/block_creation.d.ts +21 -6
  95. package/dest/utils/block_creation.d.ts.map +1 -1
  96. package/dest/utils/block_creation.js +38 -4
  97. package/dest/utils/encoding.d.ts +191 -0
  98. package/dest/utils/encoding.d.ts.map +1 -0
  99. package/dest/{util → utils}/encoding.js +8 -3
  100. package/dest/utils/expected_failure_error.d.ts +4 -0
  101. package/dest/utils/expected_failure_error.d.ts.map +1 -0
  102. package/dest/utils/tx_effect_creation.d.ts +3 -3
  103. package/dest/utils/tx_effect_creation.d.ts.map +1 -1
  104. package/dest/utils/tx_effect_creation.js +4 -7
  105. package/dest/utils/txe_account_store.d.ts +10 -0
  106. package/dest/utils/txe_account_store.d.ts.map +1 -0
  107. package/dest/{util/txe_account_data_provider.js → utils/txe_account_store.js} +1 -1
  108. package/dest/utils/txe_artifact_resolver.d.ts +37 -0
  109. package/dest/utils/txe_artifact_resolver.d.ts.map +1 -0
  110. package/dest/utils/txe_artifact_resolver.js +161 -0
  111. package/dest/utils/txe_public_contract_data_source.d.ts +20 -0
  112. package/dest/utils/txe_public_contract_data_source.d.ts.map +1 -0
  113. package/dest/utils/txe_public_contract_data_source.js +48 -0
  114. package/dest/worker.bundle.js +3 -0
  115. package/dest/worker.bundle.js.map +7 -0
  116. package/dest/worker.d.ts +2 -0
  117. package/dest/worker.d.ts.map +1 -0
  118. package/dest/worker.js +92 -0
  119. package/package.json +40 -22
  120. package/src/bin/check_txe_oracle_version.ts +70 -0
  121. package/src/bin/index.ts +11 -2
  122. package/src/bin/oracle_test_server.ts +51 -0
  123. package/src/constants.ts +13 -0
  124. package/src/dispatcher_pool.ts +316 -0
  125. package/src/index.ts +111 -201
  126. package/src/msgpackr_fr_extension.ts +23 -0
  127. package/src/oracle/interfaces.ts +62 -36
  128. package/src/oracle/test-resolver/fixtures.ts +84 -0
  129. package/src/oracle/test-resolver/index.ts +45 -0
  130. package/src/oracle/test-resolver/resolver.ts +165 -0
  131. package/src/oracle/txe_oracle_public_context.ts +81 -28
  132. package/src/oracle/txe_oracle_registry.ts +401 -0
  133. package/src/oracle/txe_oracle_top_level_context.ts +418 -178
  134. package/src/oracle/txe_oracle_version.ts +17 -0
  135. package/src/oracle/txe_private_execution_oracle.ts +30 -0
  136. package/src/rpc_server.ts +87 -0
  137. package/src/rpc_translator.ts +999 -909
  138. package/src/state_machine/archiver.ts +83 -115
  139. package/src/state_machine/dummy_p2p_client.ts +83 -33
  140. package/src/state_machine/global_variable_builder.ts +39 -6
  141. package/src/state_machine/index.ts +82 -24
  142. package/src/state_machine/mock_epoch_cache.ts +63 -23
  143. package/src/state_machine/synchronizer.ts +10 -9
  144. package/src/txe_session.ts +486 -119
  145. package/src/utils/block_creation.ts +49 -14
  146. package/src/{util → utils}/encoding.ts +9 -3
  147. package/src/utils/tx_effect_creation.ts +5 -12
  148. package/src/{util/txe_account_data_provider.ts → utils/txe_account_store.ts} +1 -1
  149. package/src/utils/txe_artifact_resolver.ts +217 -0
  150. package/src/utils/txe_public_contract_data_source.ts +58 -0
  151. package/src/worker.ts +98 -0
  152. package/dest/util/encoding.d.ts +0 -121
  153. package/dest/util/encoding.d.ts.map +0 -1
  154. package/dest/util/expected_failure_error.d.ts +0 -4
  155. package/dest/util/expected_failure_error.d.ts.map +0 -1
  156. package/dest/util/txe_account_data_provider.d.ts +0 -10
  157. package/dest/util/txe_account_data_provider.d.ts.map +0 -1
  158. package/dest/util/txe_contract_data_provider.d.ts +0 -12
  159. package/dest/util/txe_contract_data_provider.d.ts.map +0 -1
  160. package/dest/util/txe_contract_data_provider.js +0 -22
  161. package/dest/util/txe_public_contract_data_source.d.ts +0 -20
  162. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  163. package/dest/util/txe_public_contract_data_source.js +0 -67
  164. package/src/util/txe_contract_data_provider.ts +0 -36
  165. package/src/util/txe_public_contract_data_source.ts +0 -85
  166. /package/dest/{util → utils}/expected_failure_error.js +0 -0
  167. /package/src/{util → utils}/expected_failure_error.ts +0 -0
@@ -1,20 +1,27 @@
1
1
  import {
2
2
  CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
3
- DEFAULT_DA_GAS_LIMIT,
4
- DEFAULT_L2_GAS_LIMIT,
5
- DEFAULT_TEARDOWN_DA_GAS_LIMIT,
6
- DEFAULT_TEARDOWN_L2_GAS_LIMIT,
3
+ MAX_PRIVATE_LOGS_PER_TX,
7
4
  NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP,
8
5
  } from '@aztec/constants';
9
- import { Schnorr } from '@aztec/foundation/crypto';
10
- import { Fr } from '@aztec/foundation/fields';
6
+ import { BlockNumber } from '@aztec/foundation/branded-types';
7
+ import { Schnorr } from '@aztec/foundation/crypto/schnorr';
8
+ import { Fr } from '@aztec/foundation/curves/bn254';
11
9
  import { LogLevels, type Logger, applyStringFormatting, createLogger } from '@aztec/foundation/log';
12
10
  import { TestDateProvider } from '@aztec/foundation/timer';
13
11
  import type { KeyStore } from '@aztec/key-store';
14
12
  import {
15
- AddressDataProvider,
16
- ORACLE_VERSION,
17
- PXEOracleInterface,
13
+ AddressStore,
14
+ CapsuleService,
15
+ CapsuleStore,
16
+ type ContractStore,
17
+ type ExecutionHooks,
18
+ NoteStore,
19
+ ORACLE_VERSION_MAJOR,
20
+ PrivateEventStore,
21
+ RecipientTaggingStore,
22
+ SenderAddressBookStore,
23
+ SenderTaggingStore,
24
+ composeHooks,
18
25
  enrichPublicSimulationError,
19
26
  } from '@aztec/pxe/server';
20
27
  import {
@@ -43,21 +50,22 @@ import {
43
50
  PublicProcessor,
44
51
  PublicTxSimulator,
45
52
  } from '@aztec/simulator/server';
46
- import { type ContractArtifact, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
53
+ import { type ContractArtifact, EventSelector, FunctionCall, FunctionSelector, FunctionType } from '@aztec/stdlib/abi';
47
54
  import { AuthWitness } from '@aztec/stdlib/auth-witness';
55
+ import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
48
56
  import { AztecAddress } from '@aztec/stdlib/aztec-address';
49
- import { Body, L2Block } from '@aztec/stdlib/block';
50
57
  import { type ContractInstanceWithAddress, computePartialAddress } from '@aztec/stdlib/contract';
51
58
  import { Gas, GasFees, GasSettings } from '@aztec/stdlib/gas';
52
- import { computeCalldataHash, siloNullifier } from '@aztec/stdlib/hash';
59
+ import { computeCalldataHash, computeProtocolNullifier, siloNullifier } from '@aztec/stdlib/hash';
53
60
  import {
54
61
  PartialPrivateTailPublicInputsForPublic,
55
62
  PrivateKernelTailCircuitPublicInputs,
56
63
  PrivateToPublicAccumulatedData,
57
64
  PublicCallRequest,
58
65
  } from '@aztec/stdlib/kernel';
66
+ import { hashPublicKey } from '@aztec/stdlib/keys';
59
67
  import { ChonkProof } from '@aztec/stdlib/proofs';
60
- import { makeAppendOnlyTreeSnapshot, makeGlobalVariables } from '@aztec/stdlib/testing';
68
+ import { makeGlobalVariables } from '@aztec/stdlib/testing';
61
69
  import { MerkleTreeId } from '@aztec/stdlib/trees';
62
70
  import {
63
71
  CallContext,
@@ -72,17 +80,14 @@ import {
72
80
  collectNested,
73
81
  } from '@aztec/stdlib/tx';
74
82
  import type { UInt64 } from '@aztec/stdlib/types';
75
- import { ForkCheckpoint } from '@aztec/world-state';
83
+ import { ForkCheckpoint } from '@aztec/world-state/native';
76
84
 
85
+ import { DEFAULT_ADDRESS, MAX_PRIVATE_EVENTS_PER_TXE_QUERY, MAX_PRIVATE_EVENT_LEN } from '../constants.js';
77
86
  import type { TXEStateMachine } from '../state_machine/index.js';
78
- import type { TXEAccountDataProvider } from '../util/txe_account_data_provider.js';
79
- import type { TXEContractDataProvider } from '../util/txe_contract_data_provider.js';
80
- import { TXEPublicContractDataSource } from '../util/txe_public_contract_data_source.js';
81
- import {
82
- getSingleTxBlockRequestHash,
83
- insertTxEffectIntoWorldTrees,
84
- makeTXEBlockHeader,
85
- } from '../utils/block_creation.js';
87
+ import { getSingleTxBlockRequestHash, insertTxEffectIntoWorldTrees, makeTXEBlock } from '../utils/block_creation.js';
88
+ import type { TXEAccountStore } from '../utils/txe_account_store.js';
89
+ import type { TXEArtifactResolver } from '../utils/txe_artifact_resolver.js';
90
+ import { TXEPublicContractDataSource } from '../utils/txe_public_contract_data_source.js';
86
91
  import type { ITxeExecutionOracle } from './interfaces.js';
87
92
 
88
93
  export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracle {
@@ -93,58 +98,84 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
93
98
 
94
99
  constructor(
95
100
  private stateMachine: TXEStateMachine,
96
- private contractDataProvider: TXEContractDataProvider,
101
+ private contractStore: ContractStore,
102
+ private noteStore: NoteStore,
97
103
  private keyStore: KeyStore,
98
- private addressDataProvider: AddressDataProvider,
99
- private accountDataProvider: TXEAccountDataProvider,
100
- private pxeOracleInterface: PXEOracleInterface,
104
+ private addressStore: AddressStore,
105
+ private accountStore: TXEAccountStore,
106
+ private senderTaggingStore: SenderTaggingStore,
107
+ private recipientTaggingStore: RecipientTaggingStore,
108
+ private senderAddressBookStore: SenderAddressBookStore,
109
+ private capsuleStore: CapsuleStore,
110
+ private privateEventStore: PrivateEventStore,
101
111
  private nextBlockTimestamp: bigint,
102
112
  private version: Fr,
103
113
  private chainId: Fr,
104
114
  private authwits: Map<string, AuthWitness>,
115
+ private readonly artifactResolver: TXEArtifactResolver,
116
+ private readonly rootPath: string,
117
+ private readonly packageName: string,
105
118
  ) {
106
119
  this.logger = createLogger('txe:top_level_context');
107
120
  this.logger.debug('Entering Top Level Context');
108
121
  }
109
122
 
110
- utilityAssertCompatibleOracleVersion(version: number): void {
111
- if (version !== ORACLE_VERSION) {
123
+ private contractOracleVersion: { major: number; minor: number } | undefined;
124
+
125
+ assertCompatibleOracleVersion(major: number, minor: number): void {
126
+ if (major !== ORACLE_VERSION_MAJOR) {
127
+ const hint =
128
+ major > ORACLE_VERSION_MAJOR
129
+ ? 'The contract was compiled with a newer version of Aztec.nr than this aztec cli version supports. Upgrade your aztec cli version to a compatible version.'
130
+ : 'The contract was compiled with an older version of Aztec.nr than this aztec cli version supports. Recompile the contract with a compatible version of Aztec.nr.';
112
131
  throw new Error(
113
- `Incompatible oracle version. TXE is using version '${ORACLE_VERSION}', but got a request for '${version}'.`,
132
+ `Incompatible aztec cli version: ${hint} See https://docs.aztec.network/errors/8 (expected oracle major version ${ORACLE_VERSION_MAJOR}, got ${major})`,
114
133
  );
115
134
  }
135
+ this.contractOracleVersion = { major, minor };
136
+ }
137
+
138
+ // Prefixed with "nonOracleFunction" as it is not used as an oracle handler.
139
+ nonOracleFunctionGetContractOracleVersion(): { major: number; minor: number } | undefined {
140
+ return this.contractOracleVersion;
116
141
  }
117
142
 
118
143
  // This is typically only invoked in private contexts, but it is convenient to also have it in top-level for testing
119
144
  // setup.
120
- utilityGetRandomField(): Fr {
145
+ getRandomField(): Fr {
121
146
  return Fr.random();
122
147
  }
123
148
 
124
149
  // We instruct users to debug contracts via this oracle, so it makes sense that they'd expect it to also work in tests
125
- utilityDebugLog(level: number, message: string, fields: Fr[]): void {
150
+ log(level: number, message: string, _fieldsSize: number, fields: Fr[]): Promise<void> {
126
151
  if (!LogLevels[level]) {
127
- throw new Error(`Invalid debug log level: ${level}`);
152
+ throw new Error(`Invalid log level: ${level}`);
128
153
  }
129
154
  const levelName = LogLevels[level];
130
155
 
131
156
  this.logger[levelName](`${applyStringFormatting(message, fields)}`, { module: `${this.logger.module}:debug_log` });
157
+ return Promise.resolve();
158
+ }
159
+
160
+ getDefaultAddress(): AztecAddress {
161
+ return DEFAULT_ADDRESS;
132
162
  }
133
163
 
134
- async txeGetNextBlockNumber(): Promise<number> {
135
- return (await this.getLastBlockNumber()) + 1;
164
+ async getNextBlockNumber(): Promise<BlockNumber> {
165
+ return BlockNumber((await this.getLastBlockNumber()) + 1);
136
166
  }
137
167
 
138
- txeGetNextBlockTimestamp(): Promise<bigint> {
168
+ getNextBlockTimestamp(): Promise<bigint> {
139
169
  return Promise.resolve(this.nextBlockTimestamp);
140
170
  }
141
171
 
142
- async txeGetLastBlockTimestamp() {
143
- return (await this.stateMachine.node.getBlockHeader('latest'))!.globalVariables.timestamp;
172
+ async getLastBlockTimestamp() {
173
+ return (await this.stateMachine.node.getBlockData('latest'))!.header.globalVariables.timestamp;
144
174
  }
145
175
 
146
- async txeGetLastTxEffects() {
147
- const block = await this.stateMachine.archiver.getBlock('latest');
176
+ async getLastTxEffects() {
177
+ const latestBlockNumber = await this.stateMachine.archiver.getBlockNumber();
178
+ const block = await this.stateMachine.archiver.getBlock({ number: latestBlockNumber });
148
179
 
149
180
  if (block!.body.txEffects.length != 1) {
150
181
  // Note that calls like env.mine() will result in blocks with no transactions, hitting this
@@ -153,10 +184,59 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
153
184
 
154
185
  const txEffects = block!.body.txEffects[0];
155
186
 
156
- return { txHash: txEffects.txHash, noteHashes: txEffects.noteHashes, nullifiers: txEffects.nullifiers };
187
+ const privateLogs = txEffects.privateLogs;
188
+ if (privateLogs.length > MAX_PRIVATE_LOGS_PER_TX) {
189
+ throw new Error(`${privateLogs.length} private logs exceed max ${MAX_PRIVATE_LOGS_PER_TX}`);
190
+ }
191
+
192
+ return {
193
+ txHash: txEffects.txHash,
194
+ noteHashes: txEffects.noteHashes,
195
+ nullifiers: txEffects.nullifiers,
196
+ privateLogs,
197
+ };
198
+ }
199
+
200
+ async syncContractNonOracleMethod(contractAddress: AztecAddress, scope: AztecAddress, jobId: string) {
201
+ if (contractAddress.equals(DEFAULT_ADDRESS)) {
202
+ this.logger.debug(`Skipping sync in getPrivateEvents because the events correspond to the default address.`);
203
+ return;
204
+ }
205
+
206
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
207
+ await this.stateMachine.contractSyncService.ensureContractSynced(
208
+ contractAddress,
209
+ null,
210
+ async (call, execScopes) => {
211
+ await this.executeUtilityCall(call, execScopes, jobId);
212
+ },
213
+ blockHeader,
214
+ jobId,
215
+ [scope],
216
+ );
157
217
  }
158
218
 
159
- async txeAdvanceBlocksBy(blocks: number) {
219
+ async getPrivateEvents(selector: EventSelector, contractAddress: AztecAddress, scope: AztecAddress) {
220
+ const events = (
221
+ await this.privateEventStore.getPrivateEvents(selector, {
222
+ contractAddress,
223
+ scopes: [scope],
224
+ fromBlock: 0,
225
+ toBlock: (await this.getLastBlockNumber()) + 1,
226
+ })
227
+ ).map(e => e.packedEvent);
228
+
229
+ if (events.length > MAX_PRIVATE_EVENTS_PER_TXE_QUERY) {
230
+ throw new Error(`Array of length ${events.length} larger than maxLen ${MAX_PRIVATE_EVENTS_PER_TXE_QUERY}`);
231
+ }
232
+ if (events.some(e => e.length > MAX_PRIVATE_EVENT_LEN)) {
233
+ throw new Error(`Some private event has length larger than maxLen ${MAX_PRIVATE_EVENT_LEN}`);
234
+ }
235
+
236
+ return events;
237
+ }
238
+
239
+ async advanceBlocksBy(blocks: number) {
160
240
  this.logger.debug(`time traveling ${blocks} blocks`);
161
241
 
162
242
  for (let i = 0; i < blocks; i++) {
@@ -164,70 +244,115 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
164
244
  }
165
245
  }
166
246
 
167
- txeAdvanceTimestampBy(duration: UInt64) {
247
+ advanceTimestampBy(duration: UInt64) {
168
248
  this.logger.debug(`time traveling ${duration} seconds`);
169
249
  this.nextBlockTimestamp += duration;
170
250
  }
171
251
 
172
- async txeDeploy(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
252
+ private deploymentNullifier(address: AztecAddress): Promise<Fr> {
253
+ return siloNullifier(AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS), address.toField());
254
+ }
255
+
256
+ async deploy(
257
+ contractPath: string,
258
+ initializer: string,
259
+ args: Fr[],
260
+ secret: Fr,
261
+ salt: Fr,
262
+ deployer: AztecAddress,
263
+ ): Promise<Fr[]> {
264
+ const { artifact, instance } = await this.artifactResolver.resolveDeployArtifact({
265
+ rootPath: this.rootPath,
266
+ packageName: this.packageName,
267
+ contractPath,
268
+ initializer,
269
+ args,
270
+ secret,
271
+ salt,
272
+ deployer,
273
+ });
274
+
173
275
  // Emit deployment nullifier
174
276
  await this.mineBlock({
175
- nullifiers: [
176
- await siloNullifier(
177
- AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
178
- instance.address.toField(),
179
- ),
180
- ],
277
+ nullifiers: [await this.deploymentNullifier(instance.address)],
181
278
  });
182
279
 
183
280
  if (!secret.equals(Fr.ZERO)) {
184
- await this.txeAddAccount(artifact, instance, secret);
281
+ await this.registerContractAndAddAccount(artifact, instance, secret);
185
282
  } else {
186
- await this.contractDataProvider.addContractInstance(instance);
187
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
283
+ await this.contractStore.addContractInstance(instance);
284
+ await this.contractStore.addContractArtifact(artifact);
188
285
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
189
286
  }
287
+
288
+ return [
289
+ instance.salt,
290
+ instance.deployer.toField(),
291
+ instance.currentContractClassId,
292
+ instance.initializationHash,
293
+ instance.immutablesHash,
294
+ ...instance.publicKeys.toFields(),
295
+ ];
296
+ }
297
+
298
+ /**
299
+ * Mines a single block containing only the deployment nullifiers for the contracts at the given addresses.
300
+ */
301
+ async mineDeploymentNullifiers(addresses: AztecAddress[]) {
302
+ await this.mineBlock({
303
+ nullifiers: await Promise.all(addresses.map(address => this.deploymentNullifier(address))),
304
+ });
305
+ }
306
+
307
+ async addAccount(secret: Fr) {
308
+ const { artifact, instance } = await this.artifactResolver.resolveAccountArtifact(secret);
309
+ return this.registerContractAndAddAccount(artifact, instance, secret);
190
310
  }
191
311
 
192
- async txeAddAccount(artifact: ContractArtifact, instance: ContractInstanceWithAddress, secret: Fr) {
312
+ private async registerContractAndAddAccount(
313
+ artifact: ContractArtifact,
314
+ instance: ContractInstanceWithAddress,
315
+ secret: Fr,
316
+ ) {
193
317
  const partialAddress = await computePartialAddress(instance);
194
318
 
195
319
  this.logger.debug(`Deployed ${artifact.name} at ${instance.address}`);
196
- await this.contractDataProvider.addContractInstance(instance);
197
- await this.contractDataProvider.addContractArtifact(instance.currentContractClassId, artifact);
320
+ await this.contractStore.addContractInstance(instance);
321
+ await this.contractStore.addContractArtifact(artifact);
198
322
 
199
323
  const completeAddress = await this.keyStore.addAccount(secret, partialAddress);
200
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
201
- await this.addressDataProvider.addCompleteAddress(completeAddress);
324
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
325
+ await this.addressStore.addCompleteAddress(completeAddress);
202
326
  this.logger.debug(`Created account ${completeAddress.address}`);
203
327
 
204
328
  return completeAddress;
205
329
  }
206
330
 
207
- async txeCreateAccount(secret: Fr) {
208
- // This is a footgun !
331
+ async createAccount(secret: Fr) {
332
+ // This is a foot gun !
209
333
  const completeAddress = await this.keyStore.addAccount(secret, secret);
210
- await this.accountDataProvider.setAccount(completeAddress.address, completeAddress);
211
- await this.addressDataProvider.addCompleteAddress(completeAddress);
334
+ await this.accountStore.setAccount(completeAddress.address, completeAddress);
335
+ await this.addressStore.addCompleteAddress(completeAddress);
212
336
  this.logger.debug(`Created account ${completeAddress.address}`);
213
337
 
214
338
  return completeAddress;
215
339
  }
216
340
 
217
- async txeAddAuthWitness(address: AztecAddress, messageHash: Fr) {
218
- const account = await this.accountDataProvider.getAccount(address);
219
- const privateKey = await this.keyStore.getMasterSecretKey(account.publicKeys.masterIncomingViewingPublicKey);
341
+ async addAuthWitness(address: AztecAddress, messageHash: Fr) {
342
+ const account = await this.accountStore.getAccount(address);
343
+ const ivpkMHash = await hashPublicKey(account.publicKeys.ivpkM);
344
+ const privateKey = await this.keyStore.getMasterSecretKey(ivpkMHash);
220
345
 
221
346
  const schnorr = new Schnorr();
222
- const signature = await schnorr.constructSignature(messageHash.toBuffer(), privateKey);
347
+ const signature = await schnorr.constructSignature(messageHash, privateKey);
223
348
 
224
- const authWitness = new AuthWitness(messageHash, [...signature.toBuffer()]);
349
+ const authWitness = new AuthWitness(messageHash, signature.toLimbFields());
225
350
 
226
351
  this.authwits.set(authWitness.requestHash.toString(), authWitness);
227
352
  }
228
353
 
229
354
  async mineBlock(options: { nullifiers?: Fr[] } = {}) {
230
- const blockNumber = await this.txeGetNextBlockNumber();
355
+ const blockNumber = await this.getNextBlockNumber();
231
356
 
232
357
  const txEffect = TxEffect.empty();
233
358
  txEffect.nullifiers = [getSingleTxBlockRequestHash(blockNumber), ...(options.nullifiers ?? [])];
@@ -236,19 +361,13 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
236
361
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
237
362
  await insertTxEffectIntoWorldTrees(txEffect, forkedWorldTrees);
238
363
 
239
- const block = new L2Block(
240
- makeAppendOnlyTreeSnapshot(),
241
- await makeTXEBlockHeader(
242
- forkedWorldTrees,
243
- makeGlobalVariables(undefined, {
244
- blockNumber,
245
- timestamp: this.nextBlockTimestamp,
246
- version: this.version,
247
- chainId: this.chainId,
248
- }),
249
- ),
250
- new Body([txEffect]),
251
- );
364
+ const globals = makeGlobalVariables(undefined, {
365
+ blockNumber,
366
+ timestamp: this.nextBlockTimestamp,
367
+ version: this.version,
368
+ chainId: this.chainId,
369
+ });
370
+ const block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
252
371
 
253
372
  await forkedWorldTrees.close();
254
373
 
@@ -257,19 +376,23 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
257
376
  await this.stateMachine.handleL2Block(block);
258
377
  }
259
378
 
260
- async txePrivateCallNewFlow(
261
- from: AztecAddress,
379
+ async privateCallNewFlow(
380
+ from: AztecAddress | undefined,
262
381
  targetContractAddress: AztecAddress = AztecAddress.zero(),
263
382
  functionSelector: FunctionSelector = FunctionSelector.empty(),
264
383
  args: Fr[],
265
384
  argsHash: Fr = Fr.zero(),
266
385
  isStaticCall: boolean = false,
386
+ additionalScopes: AztecAddress[] = [],
387
+ jobId: string,
388
+ authorizedUtilityCallTargets: AztecAddress[],
389
+ gasSettings: GasSettings,
267
390
  ) {
268
391
  this.logger.verbose(
269
- `Executing external function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
392
+ `Executing external function ${await this.contractStore.getDebugFunctionName(targetContractAddress, functionSelector)}@${targetContractAddress} isStaticCall=${isStaticCall}`,
270
393
  );
271
394
 
272
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
395
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
273
396
  if (!artifact) {
274
397
  const message = functionSelector.equals(await FunctionSelector.fromSignature('verify_private_authwit(Field)'))
275
398
  ? 'Found no account contract artifact for a private authwit check - use `create_contract_account` instead of `create_light_account` for authwit support.'
@@ -277,51 +400,80 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
277
400
  throw new Error(message);
278
401
  }
279
402
 
280
- const blockNumber = await this.txeGetNextBlockNumber();
403
+ const scopes = from === undefined ? additionalScopes : [from, ...additionalScopes];
281
404
 
282
- const callContext = new CallContext(from, targetContractAddress, functionSelector, isStaticCall);
405
+ // Sync notes before executing private function to discover notes from previous transactions
406
+ const utilityExecutor = async (call: FunctionCall, execScopes: AztecAddress[]) => {
407
+ await this.executeUtilityCall(call, execScopes, jobId);
408
+ };
283
409
 
284
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
410
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
411
+ await this.stateMachine.contractSyncService.ensureContractSynced(
412
+ targetContractAddress,
413
+ functionSelector,
414
+ utilityExecutor,
415
+ blockHeader,
416
+ jobId,
417
+ scopes,
418
+ );
285
419
 
286
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
420
+ const blockNumber = await this.getNextBlockNumber();
287
421
 
288
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
422
+ const msgSender = from ?? AztecAddress.NULL_MSG_SENDER;
423
+ const callContext = new CallContext(msgSender, targetContractAddress, functionSelector, isStaticCall);
289
424
 
290
425
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
291
426
 
292
- const blockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
293
-
294
- const txRequestHash = getSingleTxBlockRequestHash(blockNumber);
295
- const noteCache = new ExecutionNoteCache(txRequestHash);
427
+ const protocolNullifier = await computeProtocolNullifier(getSingleTxBlockRequestHash(blockNumber));
428
+ const noteCache = new ExecutionNoteCache(protocolNullifier);
429
+ // In production, the account contract sets the min revertible counter before calling the app function.
430
+ // Since TXE bypasses the account contract, we simulate this by setting minRevertibleSideEffectCounter to 1,
431
+ // marking all side effects as revertible.
432
+ const minRevertibleSideEffectCounter = 1;
433
+ await noteCache.setMinRevertibleSideEffectCounter(minRevertibleSideEffectCounter);
296
434
  const taggingIndexCache = new ExecutionTaggingIndexCache();
297
435
 
298
436
  const simulator = new WASMSimulator();
299
437
 
300
- const privateExecutionOracle = new PrivateExecutionOracle(
438
+ const privateExecutionOracle = new PrivateExecutionOracle({
301
439
  argsHash,
302
440
  txContext,
303
441
  callContext,
304
- /** Header of a block whose state is used during private execution (not the block the transaction is included in). */
305
- blockHeader,
306
- /** List of transient auth witnesses to be used during this simulation */
307
- Array.from(this.authwits.values()),
308
- /** List of transient auth witnesses to be used during this simulation */
309
- [],
310
- HashedValuesCache.create([new HashedValues(args, argsHash)]),
442
+ anchorBlockHeader: blockHeader,
443
+ utilityExecutor,
444
+ authWitnesses: Array.from(this.authwits.values()),
445
+ capsules: [],
446
+ executionCache: HashedValuesCache.create([new HashedValues(args, argsHash)]),
311
447
  noteCache,
312
448
  taggingIndexCache,
313
- this.pxeOracleInterface,
314
- 0,
315
- 1,
316
- undefined, // log
317
- undefined, // scopes
318
- /**
319
- * In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
320
- * contract would perform, including setting senderForTags.
321
- */
322
- from,
449
+ contractStore: this.contractStore,
450
+ noteStore: this.noteStore,
451
+ keyStore: this.keyStore,
452
+ addressStore: this.addressStore,
453
+ aztecNode: this.stateMachine.node,
454
+ senderTaggingStore: this.senderTaggingStore,
455
+ recipientTaggingStore: this.recipientTaggingStore,
456
+ senderAddressBookStore: this.senderAddressBookStore,
457
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
458
+ privateEventStore: this.privateEventStore,
459
+ contractSyncService: this.stateMachine.contractSyncService,
460
+ jobId,
461
+ totalPublicCalldataCount: 0,
462
+ sideEffectCounter: minRevertibleSideEffectCounter,
463
+ scopes,
464
+ // In TXE, the typical transaction entrypoint is skipped, so we need to simulate the actions that such a
465
+ // contract would perform, including setting senderForTags.
466
+ senderForTags: from,
323
467
  simulator,
324
- );
468
+ messageContextService: this.stateMachine.messageContextService,
469
+ l2TipsStore: this.stateMachine.l2TipsProvider,
470
+ hooks: composeHooks({
471
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook(
472
+ isStaticCall ? 'private view' : 'private',
473
+ authorizedUtilityCallTargets,
474
+ ),
475
+ }),
476
+ });
325
477
 
326
478
  // 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.
327
479
  let result: PrivateExecutionResult;
@@ -343,24 +495,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
343
495
  );
344
496
  const publicFunctionsCalldata = await Promise.all(
345
497
  publicCallRequests.map(async r => {
346
- const calldata = await privateExecutionOracle.privateLoadFromExecutionCache(r.calldataHash);
498
+ const calldata = await privateExecutionOracle.getHashPreimage(r.calldataHash);
347
499
  return new HashedValues(calldata, r.calldataHash);
348
500
  }),
349
501
  );
350
502
 
351
- // TXE's top level context does not track side effect counters, and as such, minRevertibleSideEffectCounter is always 0.
352
- // This has the unfortunate consequence of always producing revertible nullifiers, which means we
353
- // must set the firstNullifierHint to Fr.ZERO so the txRequestHash is always used as nonce generator
354
- result = new PrivateExecutionResult(executionResult, Fr.ZERO, publicFunctionsCalldata);
503
+ noteCache.finish();
504
+ const nonceGenerator = noteCache.getNonceGenerator();
505
+ result = new PrivateExecutionResult(executionResult, nonceGenerator, publicFunctionsCalldata);
355
506
  } catch (err) {
356
507
  throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during private execution'));
357
508
  }
358
509
 
359
- // According to the protocol rules, the nonce generator for the note hashes
360
- // can either be the first nullifier in the tx or the hash of the initial tx request
361
- // if there are none.
362
- const nonceGenerator = result.firstNullifier.equals(Fr.ZERO) ? txRequestHash : result.firstNullifier;
363
- const { publicInputs } = await generateSimulatedProvingResult(result, nonceGenerator, this.contractDataProvider);
510
+ // According to the protocol rules, there must be at least one nullifier in the tx. The first nullifier is used as
511
+ // the nonce generator for the note hashes.
512
+ // We pass the non-zero minRevertibleSideEffectCounter to make sure the side effects are split correctly.
513
+ const { publicInputs } = await generateSimulatedProvingResult(
514
+ result,
515
+ (addr, sel) => this.contractStore.getDebugFunctionName(addr, sel),
516
+ this.stateMachine.node,
517
+ minRevertibleSideEffectCounter,
518
+ );
364
519
 
365
520
  const globals = makeGlobalVariables();
366
521
  globals.blockNumber = blockNumber;
@@ -371,17 +526,27 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
371
526
 
372
527
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
373
528
 
374
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
529
+ const bindings = this.logger.getBindings();
530
+ const contractsDB = new PublicContractsDB(
531
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
532
+ bindings,
533
+ );
375
534
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
535
+ const config = PublicSimulatorConfig.from({
536
+ skipFeeEnforcement: true,
537
+ collectDebugLogs: true,
538
+ collectHints: false,
539
+ collectStatistics: false,
540
+ collectCallMetadata: true,
541
+ });
376
542
  const processor = new PublicProcessor(
377
543
  globals,
378
544
  guardedMerkleTrees,
379
545
  contractsDB,
380
- new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
381
- doMerkleOperations: true,
382
- skipFeeEnforcement: true,
383
- }),
546
+ new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings),
384
547
  new TestDateProvider(),
548
+ undefined,
549
+ createLogger('simulator:public-processor', bindings),
385
550
  );
386
551
 
387
552
  const tx = await Tx.create({
@@ -406,7 +571,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
406
571
  } else if (!processedTx.revertCode.isOK()) {
407
572
  if (processedTx.revertReason) {
408
573
  try {
409
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
574
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
410
575
  // eslint-disable-next-line no-empty
411
576
  } catch {}
412
577
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -415,11 +580,17 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
415
580
  }
416
581
  }
417
582
 
583
+ // Walk the nested private-call tree and collect every offchain effect the transaction emitted.
584
+ // PXE stores these on each `PrivateCallExecutionResult` and they never reach TXE via the
585
+ // `aztec_utl_emitOffchainEffect` foreign-call path (that path only fires at the top-level), so
586
+ // we pull them out here and the RPC wrapper will hand them to `TXESession` for buffering.
587
+ const offchainEffects = collectNested([executionResult], r => r.offchainEffects.map(e => e.data));
588
+
418
589
  if (isStaticCall) {
419
590
  await checkpoint!.revert();
420
591
 
421
592
  await forkedWorldTrees.close();
422
- return executionResult.returnValues ?? [];
593
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
423
594
  }
424
595
 
425
596
  const txEffect = TxEffect.empty();
@@ -435,42 +606,31 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
435
606
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
436
607
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
437
608
 
438
- const body = new Body([txEffect]);
439
-
440
- const l2Block = new L2Block(
441
- makeAppendOnlyTreeSnapshot(),
442
- await makeTXEBlockHeader(forkedWorldTrees, globals),
443
- body,
444
- );
609
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
445
610
 
446
611
  await this.stateMachine.handleL2Block(l2Block);
447
612
 
448
613
  await forkedWorldTrees.close();
449
614
 
450
- return executionResult.returnValues ?? [];
615
+ return { returnValues: executionResult.returnValues ?? [], offchainEffects };
451
616
  }
452
617
 
453
- async txePublicCallNewFlow(
454
- from: AztecAddress,
618
+ async publicCallNewFlow(
619
+ from: AztecAddress | undefined,
455
620
  targetContractAddress: AztecAddress,
456
621
  calldata: Fr[],
457
622
  isStaticCall: boolean,
623
+ gasSettings: GasSettings,
458
624
  ) {
459
625
  this.logger.verbose(
460
- `Executing public function ${await this.contractDataProvider.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
626
+ `Executing public function ${await this.contractStore.getDebugFunctionName(targetContractAddress, FunctionSelector.fromField(calldata[0]))}@${targetContractAddress} isStaticCall=${isStaticCall}`,
461
627
  );
462
628
 
463
- const blockNumber = await this.txeGetNextBlockNumber();
464
-
465
- const gasLimits = new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
466
-
467
- const teardownGasLimits = new Gas(DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT);
468
-
469
- const gasSettings = new GasSettings(gasLimits, teardownGasLimits, GasFees.empty(), GasFees.empty());
629
+ const blockNumber = await this.getNextBlockNumber();
470
630
 
471
631
  const txContext = new TxContext(this.chainId, this.version, gasSettings);
472
632
 
473
- const anchorBlockHeader = await this.pxeOracleInterface.getAnchorBlockHeader();
633
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
474
634
 
475
635
  const calldataHash = await computeCalldataHash(calldata);
476
636
  const calldataHashedValues = new HashedValues(calldata, calldataHash);
@@ -484,28 +644,42 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
484
644
 
485
645
  const forkedWorldTrees = await this.stateMachine.synchronizer.nativeWorldStateService.fork();
486
646
 
487
- const contractsDB = new PublicContractsDB(new TXEPublicContractDataSource(blockNumber, this.contractDataProvider));
647
+ const bindings2 = this.logger.getBindings();
648
+ const contractsDB = new PublicContractsDB(
649
+ new TXEPublicContractDataSource(blockNumber, this.contractStore),
650
+ bindings2,
651
+ );
488
652
  const guardedMerkleTrees = new GuardedMerkleTreeOperations(forkedWorldTrees);
489
- const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, {
490
- doMerkleOperations: true,
653
+ const config = PublicSimulatorConfig.from({
491
654
  skipFeeEnforcement: true,
655
+ collectDebugLogs: true,
656
+ collectHints: false,
657
+ collectStatistics: false,
658
+ collectCallMetadata: true,
492
659
  });
493
- const processor = new PublicProcessor(globals, guardedMerkleTrees, contractsDB, simulator, new TestDateProvider());
660
+ const simulator = new PublicTxSimulator(guardedMerkleTrees, contractsDB, globals, config, bindings2);
661
+ const processor = new PublicProcessor(
662
+ globals,
663
+ guardedMerkleTrees,
664
+ contractsDB,
665
+ simulator,
666
+ new TestDateProvider(),
667
+ undefined,
668
+ createLogger('simulator:public-processor', bindings2),
669
+ );
494
670
 
495
671
  // We're simulating a scenario in which private execution immediately enqueues a public call and halts. The private
496
672
  // kernel init would in this case inject a nullifier with the transaction request hash as a non-revertible
497
673
  // side-effect, which the AVM then expects to exist in order to use it as the nonce generator when siloing notes as
498
674
  // unique.
499
675
  const nonRevertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
500
- if (!isStaticCall) {
501
- nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
502
- }
676
+ nonRevertibleAccumulatedData.nullifiers[0] = getSingleTxBlockRequestHash(blockNumber);
503
677
 
504
678
  // The enqueued public call itself we make be revertible so that the public execution is itself revertible, as tests
505
679
  // may require producing reverts.
506
680
  const revertibleAccumulatedData = PrivateToPublicAccumulatedData.empty();
507
681
  revertibleAccumulatedData.publicCallRequests[0] = new PublicCallRequest(
508
- from,
682
+ from ?? AztecAddress.NULL_MSG_SENDER,
509
683
  targetContractAddress,
510
684
  isStaticCall,
511
685
  calldataHash,
@@ -523,7 +697,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
523
697
  constantData,
524
698
  /*gasUsed=*/ new Gas(0, 0),
525
699
  /*feePayer=*/ AztecAddress.zero(),
526
- /*includeByTimestamp=*/ 0n,
700
+ /*expirationTimestamp=*/ 0n,
527
701
  inputsForPublic,
528
702
  undefined,
529
703
  );
@@ -550,7 +724,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
550
724
  } else if (!processedTx.revertCode.isOK()) {
551
725
  if (processedTx.revertReason) {
552
726
  try {
553
- await enrichPublicSimulationError(processedTx.revertReason, this.contractDataProvider, this.logger);
727
+ await enrichPublicSimulationError(processedTx.revertReason, this.contractStore, this.logger);
554
728
  // eslint-disable-next-line no-empty
555
729
  } catch {}
556
730
  throw new Error(`Contract execution has reverted: ${processedTx.revertReason.getMessage()}`);
@@ -582,13 +756,7 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
582
756
  const l1ToL2Messages = Array(NUMBER_OF_L1_L2_MESSAGES_PER_ROLLUP).fill(0).map(Fr.zero);
583
757
  await forkedWorldTrees.appendLeaves(MerkleTreeId.L1_TO_L2_MESSAGE_TREE, l1ToL2Messages);
584
758
 
585
- const body = new Body([txEffect]);
586
-
587
- const l2Block = new L2Block(
588
- makeAppendOnlyTreeSnapshot(),
589
- await makeTXEBlockHeader(forkedWorldTrees, globals),
590
- body,
591
- );
759
+ const l2Block = await makeTXEBlock(forkedWorldTrees, globals, [txEffect]);
592
760
 
593
761
  await this.stateMachine.handleL2Block(l2Block);
594
762
 
@@ -597,23 +765,52 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
597
765
  return returnValues ?? [];
598
766
  }
599
767
 
600
- async txeSimulateUtilityFunction(
768
+ async executeUtilityFunction(
601
769
  targetContractAddress: AztecAddress,
602
770
  functionSelector: FunctionSelector,
603
771
  args: Fr[],
772
+ jobId: string,
773
+ authorizedUtilityCallTargets: AztecAddress[],
604
774
  ) {
605
- const artifact = await this.contractDataProvider.getFunctionArtifact(targetContractAddress, functionSelector);
775
+ const artifact = await this.contractStore.getFunctionArtifact(targetContractAddress, functionSelector);
606
776
  if (!artifact) {
607
777
  throw new Error(`Cannot call ${functionSelector} as there is no artifact found at ${targetContractAddress}.`);
608
778
  }
609
779
 
610
- const call = {
780
+ // Sync notes before executing utility function to discover notes from previous transactions
781
+ const blockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
782
+ await this.stateMachine.contractSyncService.ensureContractSynced(
783
+ targetContractAddress,
784
+ functionSelector,
785
+ async (call, execScopes) => {
786
+ await this.executeUtilityCall(call, execScopes, jobId);
787
+ },
788
+ blockHeader,
789
+ jobId,
790
+ await this.keyStore.getAccounts(),
791
+ );
792
+
793
+ const call = FunctionCall.from({
611
794
  name: artifact.name,
612
- selector: functionSelector,
613
795
  to: targetContractAddress,
614
- };
796
+ selector: functionSelector,
797
+ type: FunctionType.UTILITY,
798
+ hideMsgSender: false,
799
+ isStatic: false,
800
+ args,
801
+ returnTypes: [],
802
+ });
803
+
804
+ return this.executeUtilityCall(call, await this.keyStore.getAccounts(), jobId, authorizedUtilityCallTargets);
805
+ }
615
806
 
616
- const entryPointArtifact = await this.pxeOracleInterface.getFunctionArtifact(call.to, call.selector);
807
+ private async executeUtilityCall(
808
+ call: FunctionCall,
809
+ scopes: AztecAddress[],
810
+ jobId: string,
811
+ authorizedUtilityCallTargets: AztecAddress[] = [],
812
+ ): Promise<Fr[]> {
813
+ const entryPointArtifact = await this.contractStore.getFunctionArtifactWithDebugMetadata(call.to, call.selector);
617
814
  if (entryPointArtifact.functionType !== FunctionType.UTILITY) {
618
815
  throw new Error(`Cannot run ${entryPointArtifact.functionType} function as utility`);
619
816
  }
@@ -624,9 +821,38 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
624
821
  });
625
822
 
626
823
  try {
627
- const oracle = new UtilityExecutionOracle(call.to, [], [], this.pxeOracleInterface);
628
- const acirExecutionResult = await new WASMSimulator()
629
- .executeUserCircuit(toACVMWitness(0, args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
824
+ const anchorBlockHeader = await this.stateMachine.anchorBlockStore.getBlockHeader();
825
+ const simulator = new WASMSimulator();
826
+ const utilityExecutor = async (syncCall: FunctionCall, execScopes: AztecAddress[]) => {
827
+ await this.executeUtilityCall(syncCall, execScopes, jobId);
828
+ };
829
+ const oracle = new UtilityExecutionOracle({
830
+ contractAddress: call.to,
831
+ authWitnesses: [],
832
+ capsules: [],
833
+ anchorBlockHeader,
834
+ contractStore: this.contractStore,
835
+ noteStore: this.noteStore,
836
+ keyStore: this.keyStore,
837
+ addressStore: this.addressStore,
838
+ aztecNode: this.stateMachine.node,
839
+ recipientTaggingStore: this.recipientTaggingStore,
840
+ senderAddressBookStore: this.senderAddressBookStore,
841
+ capsuleService: new CapsuleService(this.capsuleStore, scopes),
842
+ privateEventStore: this.privateEventStore,
843
+ messageContextService: this.stateMachine.messageContextService,
844
+ contractSyncService: this.stateMachine.contractSyncService,
845
+ l2TipsStore: this.stateMachine.l2TipsProvider,
846
+ jobId,
847
+ scopes,
848
+ simulator,
849
+ hooks: composeHooks({
850
+ authorizeUtilityCall: this.buildAuthorizeUtilityCallHook('utility', authorizedUtilityCallTargets),
851
+ }),
852
+ utilityExecutor,
853
+ });
854
+ const acirExecutionResult = await simulator
855
+ .executeUserCircuit(toACVMWitness(0, call.args), entryPointArtifact, new Oracle(oracle).toACIRCallback())
630
856
  .catch((err: Error) => {
631
857
  err.message = resolveAssertionMessageFromError(err, entryPointArtifact);
632
858
  throw new ExecutionError(
@@ -640,10 +866,10 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
640
866
  );
641
867
  });
642
868
 
643
- this.logger.verbose(`Utility simulation for ${call.to}.${call.selector} completed`);
869
+ this.logger.verbose(`Utility execution for ${call.to}.${call.selector} completed`);
644
870
  return witnessMapToFields(acirExecutionResult.returnWitness);
645
871
  } catch (err) {
646
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility simulation'));
872
+ throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during utility execution'));
647
873
  }
648
874
  }
649
875
 
@@ -652,7 +878,21 @@ export class TXEOracleTopLevelContext implements IMiscOracle, ITxeExecutionOracl
652
878
  return [this.nextBlockTimestamp, this.authwits];
653
879
  }
654
880
 
655
- private async getLastBlockNumber(): Promise<number> {
656
- return (await this.stateMachine.node.getBlockHeader('latest'))?.globalVariables.blockNumber ?? 0;
881
+ private async getLastBlockNumber(): Promise<BlockNumber> {
882
+ const block = await this.stateMachine.node.getBlock('latest');
883
+ return block ? block.header.globalVariables.blockNumber : BlockNumber.ZERO;
884
+ }
885
+
886
+ private buildAuthorizeUtilityCallHook(
887
+ callerContext: 'private' | 'private view' | 'utility',
888
+ authorizedTargets: AztecAddress[],
889
+ ): ExecutionHooks['authorizeUtilityCall'] | undefined {
890
+ if (authorizedTargets.length === 0) {
891
+ return undefined;
892
+ }
893
+ return req =>
894
+ Promise.resolve({
895
+ authorized: req.callerContext === callerContext && authorizedTargets.some(t => t.equals(req.target)),
896
+ });
657
897
  }
658
898
  }