@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.
- package/dest/acvm/acvm.js +2 -2
- package/dest/acvm/serialize.d.ts.map +1 -1
- package/dest/acvm/serialize.js +8 -3
- package/dest/avm/avm_context.d.ts +3 -3
- package/dest/avm/avm_context.d.ts.map +1 -1
- package/dest/avm/avm_context.js +6 -5
- package/dest/avm/avm_execution_environment.d.ts +3 -3
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +16 -17
- package/dest/avm/avm_memory_types.d.ts +10 -0
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +39 -4
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +3 -3
- package/dest/avm/opcodes/addressing_mode.d.ts.map +1 -1
- package/dest/avm/opcodes/addressing_mode.js +3 -3
- package/dest/avm/opcodes/arithmetic.d.ts.map +1 -1
- package/dest/avm/opcodes/arithmetic.js +2 -1
- package/dest/avm/opcodes/comparators.d.ts.map +1 -1
- package/dest/avm/opcodes/comparators.js +5 -7
- package/dest/avm/opcodes/control_flow.d.ts +0 -20
- package/dest/avm/opcodes/control_flow.d.ts.map +1 -1
- package/dest/avm/opcodes/control_flow.js +2 -46
- package/dest/avm/opcodes/external_calls.d.ts +24 -2
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +74 -17
- package/dest/avm/opcodes/storage.d.ts +4 -3
- package/dest/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/avm/opcodes/storage.js +23 -12
- package/dest/avm/serialization/instruction_serialization.d.ts +1 -2
- package/dest/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/avm/serialization/instruction_serialization.js +9 -3
- package/dest/avm/temporary_executor_migration.d.ts.map +1 -1
- package/dest/avm/temporary_executor_migration.js +6 -1
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +4 -6
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +3 -3
- package/dest/index.d.ts +2 -1
- package/dest/index.d.ts.map +1 -1
- package/dest/index.js +3 -2
- package/dest/public/execution.d.ts +13 -12
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +2 -2
- package/dest/public/executor.d.ts +22 -1
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +137 -13
- package/dest/public/public_execution_context.d.ts.map +1 -1
- package/dest/public/public_execution_context.js +2 -3
- package/package.json +5 -5
- package/src/acvm/acvm.ts +1 -1
- package/src/acvm/serialize.ts +9 -3
- package/src/avm/avm_context.ts +21 -5
- package/src/avm/avm_execution_environment.ts +27 -12
- package/src/avm/avm_memory_types.ts +42 -3
- package/src/avm/avm_simulator.ts +10 -3
- package/src/avm/opcodes/addressing_mode.ts +3 -2
- package/src/avm/opcodes/arithmetic.ts +2 -0
- package/src/avm/opcodes/comparators.ts +4 -6
- package/src/avm/opcodes/control_flow.ts +1 -47
- package/src/avm/opcodes/external_calls.ts +88 -14
- package/src/avm/opcodes/storage.ts +37 -18
- package/src/avm/serialization/instruction_serialization.ts +8 -2
- package/src/avm/temporary_executor_migration.ts +6 -0
- package/src/client/client_execution_context.ts +1 -13
- package/src/client/simulator.ts +1 -2
- package/src/index.ts +2 -1
- package/src/public/execution.ts +15 -14
- package/src/public/executor.ts +157 -13
- package/src/public/public_execution_context.ts +1 -2
package/src/public/executor.ts
CHANGED
|
@@ -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(
|
|
38
|
-
(
|
|
39
|
-
|
|
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
|
-
|
|
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(
|