@aztec/simulator 0.26.5 → 0.27.0

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 (70) hide show
  1. package/dest/acvm/acvm.js +2 -2
  2. package/dest/acvm/serialize.d.ts.map +1 -1
  3. package/dest/acvm/serialize.js +8 -3
  4. package/dest/avm/avm_context.d.ts +3 -3
  5. package/dest/avm/avm_context.d.ts.map +1 -1
  6. package/dest/avm/avm_context.js +6 -5
  7. package/dest/avm/avm_execution_environment.d.ts +3 -3
  8. package/dest/avm/avm_execution_environment.d.ts.map +1 -1
  9. package/dest/avm/avm_execution_environment.js +16 -17
  10. package/dest/avm/avm_memory_types.d.ts +10 -0
  11. package/dest/avm/avm_memory_types.d.ts.map +1 -1
  12. package/dest/avm/avm_memory_types.js +39 -4
  13. package/dest/avm/avm_simulator.d.ts.map +1 -1
  14. package/dest/avm/avm_simulator.js +3 -3
  15. package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -1
  16. package/dest/avm/opcodes/addressing_mode.js +3 -3
  17. package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
  18. package/dest/avm/opcodes/arithmetic.js +2 -1
  19. package/dest/avm/opcodes/comparators.d.ts.map +1 -1
  20. package/dest/avm/opcodes/comparators.js +5 -7
  21. package/dest/avm/opcodes/control_flow.d.ts +0 -20
  22. package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
  23. package/dest/avm/opcodes/control_flow.js +2 -46
  24. package/dest/avm/opcodes/external_calls.d.ts +24 -2
  25. package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
  26. package/dest/avm/opcodes/external_calls.js +74 -17
  27. package/dest/avm/opcodes/storage.d.ts +4 -3
  28. package/dest/avm/opcodes/storage.d.ts.map +1 -1
  29. package/dest/avm/opcodes/storage.js +23 -12
  30. package/dest/avm/serialization/instruction_serialization.d.ts +1 -2
  31. package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
  32. package/dest/avm/serialization/instruction_serialization.js +9 -3
  33. package/dest/avm/temporary_executor_migration.d.ts.map +1 -1
  34. package/dest/avm/temporary_executor_migration.js +6 -1
  35. package/dest/client/client_execution_context.d.ts.map +1 -1
  36. package/dest/client/client_execution_context.js +4 -6
  37. package/dest/client/simulator.d.ts.map +1 -1
  38. package/dest/client/simulator.js +3 -3
  39. package/dest/index.d.ts +2 -1
  40. package/dest/index.d.ts.map +1 -1
  41. package/dest/index.js +3 -2
  42. package/dest/public/execution.d.ts +13 -12
  43. package/dest/public/execution.d.ts.map +1 -1
  44. package/dest/public/execution.js +2 -2
  45. package/dest/public/executor.d.ts +22 -1
  46. package/dest/public/executor.d.ts.map +1 -1
  47. package/dest/public/executor.js +137 -13
  48. package/dest/public/public_execution_context.d.ts.map +1 -1
  49. package/dest/public/public_execution_context.js +2 -3
  50. package/package.json +5 -5
  51. package/src/acvm/acvm.ts +1 -1
  52. package/src/acvm/serialize.ts +9 -3
  53. package/src/avm/avm_context.ts +21 -5
  54. package/src/avm/avm_execution_environment.ts +27 -12
  55. package/src/avm/avm_memory_types.ts +42 -3
  56. package/src/avm/avm_simulator.ts +10 -3
  57. package/src/avm/opcodes/addressing_mode.ts +3 -2
  58. package/src/avm/opcodes/arithmetic.ts +2 -0
  59. package/src/avm/opcodes/comparators.ts +4 -6
  60. package/src/avm/opcodes/control_flow.ts +1 -47
  61. package/src/avm/opcodes/external_calls.ts +88 -14
  62. package/src/avm/opcodes/storage.ts +37 -18
  63. package/src/avm/serialization/instruction_serialization.ts +8 -2
  64. package/src/avm/temporary_executor_migration.ts +6 -0
  65. package/src/client/client_execution_context.ts +1 -13
  66. package/src/client/simulator.ts +1 -2
  67. package/src/index.ts +2 -1
  68. package/src/public/execution.ts +15 -14
  69. package/src/public/executor.ts +157 -13
  70. package/src/public/public_execution_context.ts +1 -2
@@ -1,6 +1,11 @@
1
+ import { FunctionL2Logs } from '@aztec/circuit-types';
1
2
  import { GlobalVariables, Header, PublicCircuitPublicInputs } from '@aztec/circuits.js';
2
3
  import { createDebugLogger } from '@aztec/foundation/log';
3
4
 
5
+ import { spawn } from 'child_process';
6
+ import fs from 'fs/promises';
7
+ import path from 'path';
8
+
4
9
  import { Oracle, acvm, extractCallStack, extractReturnWitness } from '../acvm/index.js';
5
10
  import { AvmContext } from '../avm/avm_context.js';
6
11
  import { AvmMachineState } from '../avm/avm_machine_state.js';
@@ -11,10 +16,10 @@ import {
11
16
  temporaryConvertAvmResults,
12
17
  temporaryCreateAvmExecutionEnvironment,
13
18
  } from '../avm/temporary_executor_migration.js';
19
+ import { AcirSimulator } from '../client/simulator.js';
14
20
  import { ExecutionError, createSimulationError } from '../common/errors.js';
15
21
  import { SideEffectCounter } from '../common/index.js';
16
22
  import { PackedArgsCache } from '../common/packed_args_cache.js';
17
- import { AcirSimulator } from '../index.js';
18
23
  import { CommitmentsDB, PublicContractsDB, PublicStateDB } from './db.js';
19
24
  import { PublicExecution, PublicExecutionResult, checkValidStaticCall } from './execution.js';
20
25
  import { PublicExecutionContext } from './public_execution_context.js';
@@ -25,6 +30,7 @@ import { PublicExecutionContext } from './public_execution_context.js';
25
30
  export async function executePublicFunction(
26
31
  context: PublicExecutionContext,
27
32
  acir: Buffer,
33
+ nested: boolean,
28
34
  log = createDebugLogger('aztec:simulator:public_execution'),
29
35
  ): Promise<PublicExecutionResult> {
30
36
  const execution = context.execution;
@@ -34,9 +40,19 @@ export async function executePublicFunction(
34
40
 
35
41
  const initialWitness = context.getInitialWitness();
36
42
  const acvmCallback = new Oracle(context);
37
- const { partialWitness } = await acvm(await AcirSimulator.getSolver(), acir, initialWitness, acvmCallback).catch(
38
- (err: Error) => {
39
- throw new ExecutionError(
43
+ const { partialWitness, reverted, revertReason } = await acvm(
44
+ await AcirSimulator.getSolver(),
45
+ acir,
46
+ initialWitness,
47
+ acvmCallback,
48
+ )
49
+ .then(result => ({
50
+ partialWitness: result.partialWitness,
51
+ reverted: false,
52
+ revertReason: undefined,
53
+ }))
54
+ .catch((err: Error) => {
55
+ const ee = new ExecutionError(
40
56
  err.message,
41
57
  {
42
58
  contractAddress,
@@ -45,17 +61,53 @@ export async function executePublicFunction(
45
61
  extractCallStack(err),
46
62
  { cause: err },
47
63
  );
48
- },
49
- );
64
+
65
+ if (nested) {
66
+ // If we're nested, throw the error so the parent can handle it
67
+ throw ee;
68
+ } else {
69
+ return {
70
+ partialWitness: undefined,
71
+ reverted: true,
72
+ revertReason: createSimulationError(ee),
73
+ };
74
+ }
75
+ });
76
+ if (reverted) {
77
+ if (!revertReason) {
78
+ throw new Error('Reverted but no revert reason');
79
+ }
80
+
81
+ return {
82
+ execution,
83
+ returnValues: [],
84
+ newNoteHashes: [],
85
+ newL2ToL1Messages: [],
86
+ newNullifiers: [],
87
+ nullifierReadRequests: [],
88
+ contractStorageReads: [],
89
+ contractStorageUpdateRequests: [],
90
+ nestedExecutions: [],
91
+ unencryptedLogs: FunctionL2Logs.empty(),
92
+ reverted,
93
+ revertReason,
94
+ };
95
+ }
96
+
97
+ if (!partialWitness) {
98
+ throw new Error('No partial witness returned from ACVM');
99
+ }
50
100
 
51
101
  const returnWitness = extractReturnWitness(acir, partialWitness);
52
102
  const {
53
103
  returnValues,
104
+ nullifierReadRequests: nullifierReadRequestsPadded,
54
105
  newL2ToL1Msgs,
55
106
  newNoteHashes: newNoteHashesPadded,
56
107
  newNullifiers: newNullifiersPadded,
57
108
  } = PublicCircuitPublicInputs.fromFields(returnWitness);
58
109
 
110
+ const nullifierReadRequests = nullifierReadRequestsPadded.filter(v => !v.isEmpty());
59
111
  const newL2ToL1Messages = newL2ToL1Msgs.filter(v => !v.isEmpty());
60
112
  const newNoteHashes = newNoteHashesPadded.filter(v => !v.isEmpty());
61
113
  const newNullifiers = newNullifiersPadded.filter(v => !v.isEmpty());
@@ -81,11 +133,14 @@ export async function executePublicFunction(
81
133
  newNoteHashes,
82
134
  newL2ToL1Messages,
83
135
  newNullifiers,
136
+ nullifierReadRequests,
84
137
  contractStorageReads,
85
138
  contractStorageUpdateRequests,
86
139
  returnValues,
87
140
  nestedExecutions,
88
141
  unencryptedLogs,
142
+ reverted: false,
143
+ revertReason: undefined,
89
144
  };
90
145
  }
91
146
 
@@ -130,13 +185,7 @@ export class PublicExecutor {
130
185
  this.commitmentsDb,
131
186
  );
132
187
 
133
- let executionResult;
134
-
135
- try {
136
- executionResult = await executePublicFunction(context, acir);
137
- } catch (err) {
138
- throw createSimulationError(err instanceof Error ? err : new Error('Unknown error during public execution'));
139
- }
188
+ const executionResult = await executePublicFunction(context, acir, false /** nested */);
140
189
 
141
190
  if (executionResult.execution.callContext.isStaticCall) {
142
191
  checkValidStaticCall(
@@ -175,4 +224,99 @@ export class PublicExecutor {
175
224
  const newWorldState = context.persistableState.flush();
176
225
  return temporaryConvertAvmResults(execution, newWorldState, result);
177
226
  }
227
+
228
+ /**
229
+ * These functions are currently housed in the temporary executor as it relies on access to
230
+ * oracles like the contractsDB and this is the least intrusive way to achieve this.
231
+ * When we remove this executor(tracking issue #4792) and have an interface that is compatible with the kernel circuits,
232
+ * this will be moved to sequencer-client/prover.
233
+ */
234
+
235
+ /**
236
+ * Generates a proof for an associated avm execution. This is currently only used for testing purposes,
237
+ * as proof generation is not fully complete in the AVM yet.
238
+ * @param execution - The execution to run.
239
+ * @returns An AVM proof and the verification key.
240
+ */
241
+ public async getAvmProof(avmExecution: PublicExecution): Promise<Buffer[]> {
242
+ // The paths for the barretenberg binary and the write path are hardcoded for now.
243
+ // We additionally need the path to a valid crs for proof generation.
244
+ // const bbPath = '../../barretenberg/cpp';
245
+ const bbPath = path.resolve('../../barretenberg/cpp');
246
+ const artifactsPath = path.resolve('target');
247
+
248
+ // Create the directory if it does not exist
249
+ await fs.mkdir(artifactsPath, { recursive: true });
250
+
251
+ const calldataPath = path.join(artifactsPath, 'calldata.bin');
252
+ const bytecodePath = path.join(artifactsPath, 'avm_bytecode.bin');
253
+ const proofPath = path.join(artifactsPath, 'proof');
254
+
255
+ const { args, functionData, contractAddress } = avmExecution;
256
+ const bytecode = await this.contractsDb.getBytecode(contractAddress, functionData.selector);
257
+ // Write call data and bytecode to files.
258
+ await Promise.all([
259
+ fs.writeFile(
260
+ calldataPath,
261
+ args.map(c => c.toBuffer()),
262
+ ),
263
+ fs.writeFile(bytecodePath, bytecode!),
264
+ ]);
265
+
266
+ const bbBinary = spawn(path.join(bbPath, 'build', 'bin', 'bb'), [
267
+ 'avm_prove',
268
+ '-b',
269
+ bytecodePath,
270
+ '-d',
271
+ calldataPath,
272
+ '-c',
273
+ path.join(bbPath, 'srs_db', 'ignition'),
274
+ '-o',
275
+ proofPath,
276
+ ]);
277
+ // The binary writes the proof and the verification key to the write path.
278
+ return new Promise((resolve, reject) => {
279
+ bbBinary.on('close', () => {
280
+ resolve(Promise.all([fs.readFile(proofPath), fs.readFile(path.join(artifactsPath, 'vk'))]));
281
+ });
282
+ // Catch and propagate errors from spawning
283
+ bbBinary.on('error', err => {
284
+ reject(err);
285
+ });
286
+ });
287
+ }
288
+ /**
289
+ * Verifies an AVM proof. This function is currently only used for testing purposes, as verification
290
+ * is not fully complete in the AVM yet.
291
+ * @param vk - The verification key to use.
292
+ * @param proof - The proof to verify.
293
+ * @returns True if the proof is valid, false otherwise.
294
+ */
295
+ async verifyAvmProof(vk: Buffer, proof: Buffer): Promise<boolean> {
296
+ // The relative paths for the barretenberg binary and the write path are hardcoded for now.
297
+ const bbPath = path.resolve('../../barretenberg/cpp');
298
+ const artifactsPath = path.resolve('./target');
299
+
300
+ const vkPath = path.join(artifactsPath, 'vk');
301
+ const proofPath = path.join(artifactsPath, 'proof');
302
+
303
+ // Write the verification key and the proof to files.
304
+ await Promise.all([fs.writeFile(vkPath, vk), fs.writeFile(proofPath, proof)]);
305
+
306
+ const bbBinary = spawn(path.join(bbPath, 'build', 'bin', 'bb'), ['avm_verify', '-p', proofPath]);
307
+ // The binary prints to stdout 1 if the proof is valid and 0 if it is not.
308
+ return new Promise((resolve, reject) => {
309
+ let result = Buffer.alloc(0);
310
+ bbBinary.stdout.on('data', data => {
311
+ result += data;
312
+ });
313
+ bbBinary.on('close', () => {
314
+ resolve(result.toString() === '1');
315
+ });
316
+ // Catch and propagate errors from spawning
317
+ bbBinary.on('error', err => {
318
+ reject(err);
319
+ });
320
+ });
321
+ }
178
322
  }
@@ -186,7 +186,6 @@ export class PublicExecutionContext extends TypedOracle {
186
186
  storageContractAddress: isDelegateCall ? this.execution.contractAddress : targetContractAddress,
187
187
  portalContractAddress: portalAddress,
188
188
  functionSelector,
189
- isContractDeployment: false,
190
189
  isDelegateCall,
191
190
  isStaticCall,
192
191
  startSideEffectCounter: 0, // TODO use counters in public execution
@@ -211,7 +210,7 @@ export class PublicExecutionContext extends TypedOracle {
211
210
  this.log,
212
211
  );
213
212
 
214
- const childExecutionResult = await executePublicFunction(context, acir);
213
+ const childExecutionResult = await executePublicFunction(context, acir, true /** nested */);
215
214
 
216
215
  if (isStaticCall) {
217
216
  checkValidStaticCall(