@aztec/simulator 0.57.0 → 0.59.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/oracle/oracle.js +2 -2
- package/dest/acvm/oracle/typed_oracle.d.ts +1 -2
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +1 -1
- package/dest/avm/avm_gas.js +2 -2
- package/dest/avm/avm_memory_types.d.ts +7 -3
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +29 -14
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +5 -2
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +3 -3
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +2 -3
- package/dest/avm/opcodes/accrued_substate.js +17 -17
- package/dest/avm/opcodes/arithmetic.js +2 -2
- package/dest/avm/opcodes/bitwise.d.ts +3 -3
- package/dest/avm/opcodes/bitwise.d.ts.map +1 -1
- package/dest/avm/opcodes/bitwise.js +9 -8
- package/dest/avm/opcodes/comparators.js +2 -2
- package/dest/avm/opcodes/contract.d.ts.map +1 -1
- package/dest/avm/opcodes/contract.js +4 -3
- package/dest/avm/opcodes/control_flow.js +1 -1
- package/dest/avm/opcodes/conversion.js +4 -4
- package/dest/avm/opcodes/ec_add.d.ts.map +1 -1
- package/dest/avm/opcodes/ec_add.js +18 -9
- package/dest/avm/opcodes/external_calls.js +10 -10
- package/dest/avm/opcodes/hashing.js +8 -8
- package/dest/avm/opcodes/instruction_impl.d.ts +1 -2
- package/dest/avm/opcodes/instruction_impl.d.ts.map +1 -1
- package/dest/avm/opcodes/instruction_impl.js +2 -5
- package/dest/avm/opcodes/memory.js +3 -3
- package/dest/avm/opcodes/misc.js +4 -4
- package/dest/avm/opcodes/multi_scalar_mul.d.ts.map +1 -1
- package/dest/avm/opcodes/multi_scalar_mul.js +24 -9
- package/dest/avm/opcodes/storage.js +2 -2
- package/dest/avm/serialization/instruction_serialization.js +2 -2
- package/dest/avm/test_utils.d.ts +1 -2
- package/dest/avm/test_utils.d.ts.map +1 -1
- package/dest/avm/test_utils.js +1 -1
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +7 -3
- package/dest/client/db_oracle.d.ts +1 -2
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/db_oracle.js +1 -1
- package/dest/client/index.d.ts +1 -0
- package/dest/client/index.d.ts.map +1 -1
- package/dest/client/index.js +2 -1
- package/dest/client/private_execution.d.ts +10 -1
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +25 -5
- package/dest/client/view_data_oracle.d.ts +1 -2
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +1 -1
- package/dest/public/db_interfaces.d.ts +1 -2
- package/dest/public/db_interfaces.d.ts.map +1 -1
- package/dest/public/dual_side_effect_trace.d.ts +76 -0
- package/dest/public/dual_side_effect_trace.d.ts.map +1 -0
- package/dest/public/dual_side_effect_trace.js +109 -0
- package/dest/public/enqueued_call_side_effect_trace.d.ts +114 -0
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -0
- package/dest/public/enqueued_call_side_effect_trace.js +314 -0
- package/dest/public/enqueued_call_simulator.d.ts +2 -2
- package/dest/public/enqueued_call_simulator.d.ts.map +1 -1
- package/dest/public/enqueued_call_simulator.js +18 -7
- package/dest/public/enqueued_calls_processor.d.ts +2 -2
- package/dest/public/enqueued_calls_processor.d.ts.map +1 -1
- package/dest/public/enqueued_calls_processor.js +3 -5
- package/dest/public/execution.d.ts +3 -4
- package/dest/public/execution.d.ts.map +1 -1
- package/dest/public/execution.js +1 -1
- package/dest/public/executor.d.ts +6 -4
- package/dest/public/executor.d.ts.map +1 -1
- package/dest/public/executor.js +18 -9
- package/dest/public/fee_payment.d.ts +1 -1
- package/dest/public/fee_payment.d.ts.map +1 -1
- package/dest/public/fee_payment.js +4 -7
- package/dest/public/hints_builder.d.ts +2 -2
- package/dest/public/hints_builder.d.ts.map +1 -1
- package/dest/public/hints_builder.js +1 -1
- package/dest/public/public_db_sources.d.ts +4 -5
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +15 -11
- package/dest/public/public_kernel_tail_simulator.d.ts +3 -3
- package/dest/public/public_kernel_tail_simulator.d.ts.map +1 -1
- package/dest/public/public_kernel_tail_simulator.js +1 -1
- package/dest/public/public_processor.d.ts +7 -11
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +8 -12
- package/dest/public/side_effect_trace.d.ts +1 -2
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +2 -2
- package/package.json +9 -9
- package/src/acvm/oracle/oracle.ts +1 -1
- package/src/acvm/oracle/typed_oracle.ts +6 -2
- package/src/avm/avm_gas.ts +1 -1
- package/src/avm/avm_memory_types.ts +28 -11
- package/src/avm/avm_simulator.ts +7 -1
- package/src/avm/fixtures/index.ts +2 -2
- package/src/avm/journal/journal.ts +3 -4
- package/src/avm/opcodes/accrued_substate.ts +17 -17
- package/src/avm/opcodes/arithmetic.ts +1 -1
- package/src/avm/opcodes/bitwise.ts +8 -7
- package/src/avm/opcodes/comparators.ts +1 -1
- package/src/avm/opcodes/contract.ts +3 -2
- package/src/avm/opcodes/control_flow.ts +1 -1
- package/src/avm/opcodes/conversion.ts +4 -4
- package/src/avm/opcodes/ec_add.ts +15 -8
- package/src/avm/opcodes/external_calls.ts +10 -10
- package/src/avm/opcodes/hashing.ts +8 -8
- package/src/avm/opcodes/instruction_impl.ts +0 -3
- package/src/avm/opcodes/memory.ts +3 -3
- package/src/avm/opcodes/misc.ts +4 -4
- package/src/avm/opcodes/multi_scalar_mul.ts +20 -12
- package/src/avm/opcodes/storage.ts +2 -2
- package/src/avm/serialization/instruction_serialization.ts +1 -1
- package/src/avm/test_utils.ts +1 -2
- package/src/client/client_execution_context.ts +6 -1
- package/src/client/db_oracle.ts +6 -2
- package/src/client/index.ts +1 -0
- package/src/client/private_execution.ts +36 -6
- package/src/client/view_data_oracle.ts +1 -2
- package/src/public/db_interfaces.ts +5 -2
- package/src/public/dual_side_effect_trace.ts +173 -0
- package/src/public/enqueued_call_side_effect_trace.ts +552 -0
- package/src/public/enqueued_call_simulator.ts +33 -11
- package/src/public/enqueued_calls_processor.ts +4 -6
- package/src/public/execution.ts +2 -4
- package/src/public/executor.ts +38 -9
- package/src/public/fee_payment.ts +4 -6
- package/src/public/hints_builder.ts +2 -2
- package/src/public/public_db_sources.ts +31 -22
- package/src/public/public_kernel_tail_simulator.ts +3 -3
- package/src/public/public_processor.ts +16 -16
- package/src/public/side_effect_trace.ts +2 -2
|
@@ -0,0 +1,552 @@
|
|
|
1
|
+
import { UnencryptedL2Log } from '@aztec/circuit-types';
|
|
2
|
+
import {
|
|
3
|
+
AvmContractInstanceHint,
|
|
4
|
+
AvmExecutionHints,
|
|
5
|
+
AvmExternalCallHint,
|
|
6
|
+
AvmKeyValueHint,
|
|
7
|
+
AztecAddress,
|
|
8
|
+
CallContext,
|
|
9
|
+
type CombinedConstantData,
|
|
10
|
+
type ContractInstanceWithAddress,
|
|
11
|
+
ContractStorageRead,
|
|
12
|
+
ContractStorageUpdateRequest,
|
|
13
|
+
EthAddress,
|
|
14
|
+
Gas,
|
|
15
|
+
L2ToL1Message,
|
|
16
|
+
LogHash,
|
|
17
|
+
MAX_ENCRYPTED_LOGS_PER_TX,
|
|
18
|
+
MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX,
|
|
19
|
+
MAX_L2_TO_L1_MSGS_PER_TX,
|
|
20
|
+
MAX_NOTE_ENCRYPTED_LOGS_PER_TX,
|
|
21
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
22
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX,
|
|
23
|
+
MAX_NULLIFIERS_PER_TX,
|
|
24
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
|
|
25
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
26
|
+
MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX,
|
|
27
|
+
MAX_PUBLIC_DATA_READS_PER_TX,
|
|
28
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
29
|
+
MAX_UNENCRYPTED_LOGS_PER_TX,
|
|
30
|
+
NoteHash,
|
|
31
|
+
Nullifier,
|
|
32
|
+
PublicAccumulatedData,
|
|
33
|
+
PublicAccumulatedDataArrayLengths,
|
|
34
|
+
PublicCallRequest,
|
|
35
|
+
PublicDataRead,
|
|
36
|
+
PublicDataUpdateRequest,
|
|
37
|
+
PublicInnerCallRequest,
|
|
38
|
+
PublicValidationRequestArrayLengths,
|
|
39
|
+
PublicValidationRequests,
|
|
40
|
+
ReadRequest,
|
|
41
|
+
RollupValidationRequests,
|
|
42
|
+
ScopedL2ToL1Message,
|
|
43
|
+
ScopedLogHash,
|
|
44
|
+
ScopedNoteHash,
|
|
45
|
+
type ScopedNullifier,
|
|
46
|
+
ScopedReadRequest,
|
|
47
|
+
TreeLeafReadRequest,
|
|
48
|
+
VMCircuitPublicInputs,
|
|
49
|
+
} from '@aztec/circuits.js';
|
|
50
|
+
import { computeVarArgsHash } from '@aztec/circuits.js/hash';
|
|
51
|
+
import { makeTuple } from '@aztec/foundation/array';
|
|
52
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
53
|
+
import { Fr } from '@aztec/foundation/fields';
|
|
54
|
+
import { createDebugLogger } from '@aztec/foundation/log';
|
|
55
|
+
|
|
56
|
+
import { type AvmContractCallResult } from '../avm/avm_contract_call_result.js';
|
|
57
|
+
import { type AvmExecutionEnvironment } from '../avm/avm_execution_environment.js';
|
|
58
|
+
import { SideEffectLimitReachedError } from './side_effect_errors.js';
|
|
59
|
+
import { type PublicSideEffectTraceInterface } from './side_effect_trace_interface.js';
|
|
60
|
+
|
|
61
|
+
export type TracedContractInstance = { exists: boolean } & ContractInstanceWithAddress;
|
|
62
|
+
|
|
63
|
+
/**
|
|
64
|
+
* A struct containing just the side effects as regular arrays
|
|
65
|
+
* as opposed to "Tuple" arrays used by circuit public inputs.
|
|
66
|
+
* This struct is helpful for testing and checking array lengths.
|
|
67
|
+
**/
|
|
68
|
+
export type SideEffects = {
|
|
69
|
+
contractStorageReads: ContractStorageRead[];
|
|
70
|
+
contractStorageUpdateRequests: ContractStorageUpdateRequest[];
|
|
71
|
+
|
|
72
|
+
noteHashReadRequests: TreeLeafReadRequest[];
|
|
73
|
+
noteHashes: ScopedNoteHash[];
|
|
74
|
+
|
|
75
|
+
nullifierReadRequests: ScopedReadRequest[];
|
|
76
|
+
nullifierNonExistentReadRequests: ScopedReadRequest[];
|
|
77
|
+
nullifiers: ScopedNullifier[];
|
|
78
|
+
|
|
79
|
+
l1ToL2MsgReadRequests: TreeLeafReadRequest[];
|
|
80
|
+
l2ToL1Msgs: ScopedL2ToL1Message[];
|
|
81
|
+
|
|
82
|
+
unencryptedLogs: UnencryptedL2Log[];
|
|
83
|
+
unencryptedLogsHashes: ScopedLogHash[];
|
|
84
|
+
};
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Trace side effects for an entire enqueued call.
|
|
88
|
+
*/
|
|
89
|
+
export class PublicEnqueuedCallSideEffectTrace implements PublicSideEffectTraceInterface {
|
|
90
|
+
public log = createDebugLogger('aztec:public_enqueued_call_side_effect_trace');
|
|
91
|
+
|
|
92
|
+
/** The side effect counter increments with every call to the trace. */
|
|
93
|
+
private sideEffectCounter: number;
|
|
94
|
+
|
|
95
|
+
// TODO(dbanks12): make contract address mandatory in ContractStorage* structs,
|
|
96
|
+
// and include it in serialization, or modify PublicData* structs for this.
|
|
97
|
+
private contractStorageReads: ContractStorageRead[] = [];
|
|
98
|
+
private contractStorageUpdateRequests: ContractStorageUpdateRequest[] = [];
|
|
99
|
+
|
|
100
|
+
private noteHashReadRequests: TreeLeafReadRequest[] = [];
|
|
101
|
+
private noteHashes: ScopedNoteHash[] = [];
|
|
102
|
+
|
|
103
|
+
private nullifierReadRequests: ScopedReadRequest[] = [];
|
|
104
|
+
private nullifierNonExistentReadRequests: ScopedReadRequest[] = [];
|
|
105
|
+
private nullifiers: ScopedNullifier[] = [];
|
|
106
|
+
|
|
107
|
+
private l1ToL2MsgReadRequests: TreeLeafReadRequest[] = [];
|
|
108
|
+
private l2ToL1Msgs: ScopedL2ToL1Message[] = [];
|
|
109
|
+
|
|
110
|
+
private unencryptedLogs: UnencryptedL2Log[] = [];
|
|
111
|
+
private unencryptedLogsHashes: ScopedLogHash[] = [];
|
|
112
|
+
|
|
113
|
+
private avmCircuitHints: AvmExecutionHints;
|
|
114
|
+
|
|
115
|
+
constructor(
|
|
116
|
+
/** The counter of this trace's first side effect. */
|
|
117
|
+
public readonly startSideEffectCounter: number = 0,
|
|
118
|
+
/** Track parent's (or previous kernel's) lengths so the AVM can properly enforce TX-wide limits,
|
|
119
|
+
* otherwise the public kernel can fail to prove because TX limits are breached.
|
|
120
|
+
*/
|
|
121
|
+
private readonly previousValidationRequestArrayLengths: PublicValidationRequestArrayLengths = PublicValidationRequestArrayLengths.empty(),
|
|
122
|
+
private readonly previousAccumulatedDataArrayLengths: PublicAccumulatedDataArrayLengths = PublicAccumulatedDataArrayLengths.empty(),
|
|
123
|
+
) {
|
|
124
|
+
this.sideEffectCounter = startSideEffectCounter;
|
|
125
|
+
this.avmCircuitHints = AvmExecutionHints.empty();
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
public fork() {
|
|
129
|
+
return new PublicEnqueuedCallSideEffectTrace(
|
|
130
|
+
this.sideEffectCounter,
|
|
131
|
+
new PublicValidationRequestArrayLengths(
|
|
132
|
+
this.previousValidationRequestArrayLengths.noteHashReadRequests + this.noteHashReadRequests.length,
|
|
133
|
+
this.previousValidationRequestArrayLengths.nullifierReadRequests + this.nullifierReadRequests.length,
|
|
134
|
+
this.previousValidationRequestArrayLengths.nullifierNonExistentReadRequests +
|
|
135
|
+
this.nullifierNonExistentReadRequests.length,
|
|
136
|
+
this.previousValidationRequestArrayLengths.l1ToL2MsgReadRequests + this.l1ToL2MsgReadRequests.length,
|
|
137
|
+
this.previousValidationRequestArrayLengths.publicDataReads + this.contractStorageReads.length,
|
|
138
|
+
),
|
|
139
|
+
new PublicAccumulatedDataArrayLengths(
|
|
140
|
+
this.previousAccumulatedDataArrayLengths.noteHashes + this.noteHashes.length,
|
|
141
|
+
this.previousAccumulatedDataArrayLengths.nullifiers + this.nullifiers.length,
|
|
142
|
+
this.previousAccumulatedDataArrayLengths.l2ToL1Msgs + this.l2ToL1Msgs.length,
|
|
143
|
+
this.previousAccumulatedDataArrayLengths.noteEncryptedLogsHashes,
|
|
144
|
+
this.previousAccumulatedDataArrayLengths.encryptedLogsHashes,
|
|
145
|
+
this.previousAccumulatedDataArrayLengths.unencryptedLogsHashes + this.unencryptedLogsHashes.length,
|
|
146
|
+
this.previousAccumulatedDataArrayLengths.publicDataUpdateRequests + this.contractStorageUpdateRequests.length,
|
|
147
|
+
this.previousAccumulatedDataArrayLengths.publicCallStack,
|
|
148
|
+
),
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
public getCounter() {
|
|
153
|
+
return this.sideEffectCounter;
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
private incrementSideEffectCounter() {
|
|
157
|
+
this.sideEffectCounter++;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
public tracePublicStorageRead(storageAddress: Fr, slot: Fr, value: Fr, _exists: boolean, _cached: boolean) {
|
|
161
|
+
// NOTE: exists and cached are unused for now but may be used for optimizations or kernel hints later
|
|
162
|
+
if (
|
|
163
|
+
this.contractStorageReads.length + this.previousValidationRequestArrayLengths.publicDataReads >=
|
|
164
|
+
MAX_PUBLIC_DATA_READS_PER_TX
|
|
165
|
+
) {
|
|
166
|
+
throw new SideEffectLimitReachedError('contract storage read', MAX_PUBLIC_DATA_READS_PER_TX);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
this.contractStorageReads.push(
|
|
170
|
+
new ContractStorageRead(slot, value, this.sideEffectCounter, AztecAddress.fromField(storageAddress)),
|
|
171
|
+
);
|
|
172
|
+
this.avmCircuitHints.storageValues.items.push(
|
|
173
|
+
new AvmKeyValueHint(/*key=*/ new Fr(this.sideEffectCounter), /*value=*/ value),
|
|
174
|
+
);
|
|
175
|
+
this.log.debug(`SLOAD cnt: ${this.sideEffectCounter} val: ${value} slot: ${slot}`);
|
|
176
|
+
this.incrementSideEffectCounter();
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
public tracePublicStorageWrite(storageAddress: Fr, slot: Fr, value: Fr) {
|
|
180
|
+
if (
|
|
181
|
+
this.contractStorageUpdateRequests.length + this.previousAccumulatedDataArrayLengths.publicDataUpdateRequests >=
|
|
182
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX
|
|
183
|
+
) {
|
|
184
|
+
throw new SideEffectLimitReachedError('contract storage write', MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX);
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
this.contractStorageUpdateRequests.push(
|
|
188
|
+
new ContractStorageUpdateRequest(slot, value, this.sideEffectCounter, storageAddress),
|
|
189
|
+
);
|
|
190
|
+
this.log.debug(`SSTORE cnt: ${this.sideEffectCounter} val: ${value} slot: ${slot}`);
|
|
191
|
+
this.incrementSideEffectCounter();
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
// TODO(8287): _exists can be removed once we have the vm properly handling the equality check
|
|
195
|
+
public traceNoteHashCheck(_storageAddress: Fr, noteHash: Fr, leafIndex: Fr, exists: boolean) {
|
|
196
|
+
// NOTE: storageAddress is unused because noteHash is an already-siloed leaf
|
|
197
|
+
if (
|
|
198
|
+
this.noteHashReadRequests.length + this.previousValidationRequestArrayLengths.noteHashReadRequests >=
|
|
199
|
+
MAX_NOTE_HASH_READ_REQUESTS_PER_TX
|
|
200
|
+
) {
|
|
201
|
+
throw new SideEffectLimitReachedError('note hash read request', MAX_NOTE_HASH_READ_REQUESTS_PER_TX);
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
this.noteHashReadRequests.push(new TreeLeafReadRequest(noteHash, leafIndex));
|
|
205
|
+
this.avmCircuitHints.noteHashExists.items.push(
|
|
206
|
+
new AvmKeyValueHint(/*key=*/ new Fr(leafIndex), /*value=*/ exists ? Fr.ONE : Fr.ZERO),
|
|
207
|
+
);
|
|
208
|
+
// NOTE: counter does not increment for note hash checks (because it doesn't rely on pending note hashes)
|
|
209
|
+
}
|
|
210
|
+
|
|
211
|
+
public traceNewNoteHash(storageAddress: Fr, noteHash: Fr) {
|
|
212
|
+
if (this.noteHashes.length + this.previousAccumulatedDataArrayLengths.noteHashes >= MAX_NOTE_HASHES_PER_TX) {
|
|
213
|
+
throw new SideEffectLimitReachedError('note hash', MAX_NOTE_HASHES_PER_TX);
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
this.noteHashes.push(new NoteHash(noteHash, this.sideEffectCounter).scope(AztecAddress.fromField(storageAddress)));
|
|
217
|
+
this.log.debug(`NEW_NOTE_HASH cnt: ${this.sideEffectCounter}`);
|
|
218
|
+
this.incrementSideEffectCounter();
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
public traceNullifierCheck(storageAddress: Fr, nullifier: Fr, _leafIndex: Fr, exists: boolean, _isPending: boolean) {
|
|
222
|
+
// NOTE: isPending and leafIndex are unused for now but may be used for optimizations or kernel hints later
|
|
223
|
+
this.enforceLimitOnNullifierChecks();
|
|
224
|
+
|
|
225
|
+
const readRequest = new ReadRequest(nullifier, this.sideEffectCounter).scope(
|
|
226
|
+
AztecAddress.fromField(storageAddress),
|
|
227
|
+
);
|
|
228
|
+
if (exists) {
|
|
229
|
+
this.nullifierReadRequests.push(readRequest);
|
|
230
|
+
} else {
|
|
231
|
+
this.nullifierNonExistentReadRequests.push(readRequest);
|
|
232
|
+
}
|
|
233
|
+
this.avmCircuitHints.nullifierExists.items.push(
|
|
234
|
+
new AvmKeyValueHint(/*key=*/ new Fr(this.sideEffectCounter), /*value=*/ new Fr(exists ? 1 : 0)),
|
|
235
|
+
);
|
|
236
|
+
this.log.debug(`NULLIFIER_EXISTS cnt: ${this.sideEffectCounter}`);
|
|
237
|
+
this.incrementSideEffectCounter();
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
public traceNewNullifier(storageAddress: Fr, nullifier: Fr) {
|
|
241
|
+
if (this.nullifiers.length + this.previousAccumulatedDataArrayLengths.nullifiers >= MAX_NULLIFIERS_PER_TX) {
|
|
242
|
+
throw new SideEffectLimitReachedError('nullifier', MAX_NULLIFIERS_PER_TX);
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
this.nullifiers.push(
|
|
246
|
+
new Nullifier(nullifier, this.sideEffectCounter, /*noteHash=*/ Fr.ZERO).scope(
|
|
247
|
+
AztecAddress.fromField(storageAddress),
|
|
248
|
+
),
|
|
249
|
+
);
|
|
250
|
+
this.log.debug(`NEW_NULLIFIER cnt: ${this.sideEffectCounter}`);
|
|
251
|
+
this.incrementSideEffectCounter();
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
// TODO(8287): _exists can be removed once we have the vm properly handling the equality check
|
|
255
|
+
public traceL1ToL2MessageCheck(_contractAddress: Fr, msgHash: Fr, msgLeafIndex: Fr, exists: boolean) {
|
|
256
|
+
// NOTE: contractAddress is unused because msgHash is an already-siloed leaf
|
|
257
|
+
if (
|
|
258
|
+
this.l1ToL2MsgReadRequests.length + this.previousValidationRequestArrayLengths.l1ToL2MsgReadRequests >=
|
|
259
|
+
MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX
|
|
260
|
+
) {
|
|
261
|
+
throw new SideEffectLimitReachedError('l1 to l2 message read request', MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX);
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
this.l1ToL2MsgReadRequests.push(new TreeLeafReadRequest(msgHash, msgLeafIndex));
|
|
265
|
+
this.avmCircuitHints.l1ToL2MessageExists.items.push(
|
|
266
|
+
new AvmKeyValueHint(/*key=*/ new Fr(msgLeafIndex), /*value=*/ exists ? Fr.ONE : Fr.ZERO),
|
|
267
|
+
);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public traceNewL2ToL1Message(contractAddress: Fr, recipient: Fr, content: Fr) {
|
|
271
|
+
if (this.l2ToL1Msgs.length + this.previousAccumulatedDataArrayLengths.l2ToL1Msgs >= MAX_L2_TO_L1_MSGS_PER_TX) {
|
|
272
|
+
throw new SideEffectLimitReachedError('l2 to l1 message', MAX_L2_TO_L1_MSGS_PER_TX);
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const recipientAddress = EthAddress.fromField(recipient);
|
|
276
|
+
this.l2ToL1Msgs.push(
|
|
277
|
+
new L2ToL1Message(recipientAddress, content, this.sideEffectCounter).scope(
|
|
278
|
+
AztecAddress.fromField(contractAddress),
|
|
279
|
+
),
|
|
280
|
+
);
|
|
281
|
+
this.log.debug(`NEW_L2_TO_L1_MSG cnt: ${this.sideEffectCounter}`);
|
|
282
|
+
this.incrementSideEffectCounter();
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
public traceUnencryptedLog(contractAddress: Fr, log: Fr[]) {
|
|
286
|
+
if (
|
|
287
|
+
this.unencryptedLogs.length + this.previousAccumulatedDataArrayLengths.unencryptedLogsHashes >=
|
|
288
|
+
MAX_UNENCRYPTED_LOGS_PER_TX
|
|
289
|
+
) {
|
|
290
|
+
throw new SideEffectLimitReachedError('unencrypted log', MAX_UNENCRYPTED_LOGS_PER_TX);
|
|
291
|
+
}
|
|
292
|
+
|
|
293
|
+
const ulog = new UnencryptedL2Log(
|
|
294
|
+
AztecAddress.fromField(contractAddress),
|
|
295
|
+
Buffer.concat(log.map(f => f.toBuffer())),
|
|
296
|
+
);
|
|
297
|
+
const basicLogHash = Fr.fromBuffer(ulog.hash());
|
|
298
|
+
this.unencryptedLogs.push(ulog);
|
|
299
|
+
// This length is for charging DA and is checked on-chain - has to be length of log preimage + 4 bytes.
|
|
300
|
+
// The .length call also has a +4 but that is unrelated
|
|
301
|
+
this.unencryptedLogsHashes.push(
|
|
302
|
+
new LogHash(basicLogHash, this.sideEffectCounter, new Fr(ulog.length + 4)).scope(
|
|
303
|
+
AztecAddress.fromField(contractAddress),
|
|
304
|
+
),
|
|
305
|
+
);
|
|
306
|
+
this.log.debug(`NEW_UNENCRYPTED_LOG cnt: ${this.sideEffectCounter}`);
|
|
307
|
+
this.incrementSideEffectCounter();
|
|
308
|
+
}
|
|
309
|
+
|
|
310
|
+
public traceGetContractInstance(instance: TracedContractInstance) {
|
|
311
|
+
this.enforceLimitOnNullifierChecks('(contract address nullifier from GETCONTRACTINSTANCE)');
|
|
312
|
+
// TODO(dbanks12): should emit a nullifier read request
|
|
313
|
+
|
|
314
|
+
this.avmCircuitHints.contractInstances.items.push(
|
|
315
|
+
new AvmContractInstanceHint(
|
|
316
|
+
instance.address,
|
|
317
|
+
new Fr(instance.exists ? 1 : 0),
|
|
318
|
+
instance.salt,
|
|
319
|
+
instance.deployer,
|
|
320
|
+
instance.contractClassId,
|
|
321
|
+
instance.initializationHash,
|
|
322
|
+
instance.publicKeys,
|
|
323
|
+
),
|
|
324
|
+
);
|
|
325
|
+
this.log.debug(`CONTRACT_INSTANCE cnt: ${this.sideEffectCounter}`);
|
|
326
|
+
this.incrementSideEffectCounter();
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
/**
|
|
330
|
+
* Trace a nested call.
|
|
331
|
+
* Accept some results from a finished nested call's trace into this one.
|
|
332
|
+
*/
|
|
333
|
+
public traceNestedCall(
|
|
334
|
+
/** The trace of the nested call. */
|
|
335
|
+
nestedCallTrace: this,
|
|
336
|
+
/** The execution environment of the nested call. */
|
|
337
|
+
_nestedEnvironment: AvmExecutionEnvironment,
|
|
338
|
+
/** How much gas was available for this public execution. */
|
|
339
|
+
startGasLeft: Gas,
|
|
340
|
+
/** How much gas was left after this public execution. */
|
|
341
|
+
endGasLeft: Gas,
|
|
342
|
+
/** Bytecode used for this execution. */
|
|
343
|
+
_bytecode: Buffer,
|
|
344
|
+
/** The call's results */
|
|
345
|
+
avmCallResults: AvmContractCallResult,
|
|
346
|
+
/** Function name for logging */
|
|
347
|
+
_functionName: string = 'unknown',
|
|
348
|
+
) {
|
|
349
|
+
// Store end side effect counter before it gets updated by absorbing nested call trace
|
|
350
|
+
const endSideEffectCounter = new Fr(this.sideEffectCounter);
|
|
351
|
+
|
|
352
|
+
// TODO(4805): check if some threshold is reached for max nested calls (to unique contracts?)
|
|
353
|
+
// TODO(dbanks12): should emit a nullifier read request. There should be two thresholds.
|
|
354
|
+
// one for max unique contract calls, and another based on max nullifier reads.
|
|
355
|
+
// Since this trace function happens _after_ a nested call, such threshold limits must take
|
|
356
|
+
// place in another trace function that occurs _before_ a nested call.
|
|
357
|
+
if (avmCallResults.reverted) {
|
|
358
|
+
this.absorbRevertedNestedTrace(nestedCallTrace);
|
|
359
|
+
} else {
|
|
360
|
+
this.absorbSuccessfulNestedTrace(nestedCallTrace);
|
|
361
|
+
}
|
|
362
|
+
|
|
363
|
+
const gasUsed = new Gas(startGasLeft.daGas - endGasLeft.daGas, startGasLeft.l2Gas - endGasLeft.l2Gas);
|
|
364
|
+
|
|
365
|
+
this.avmCircuitHints.externalCalls.items.push(
|
|
366
|
+
new AvmExternalCallHint(
|
|
367
|
+
/*success=*/ new Fr(avmCallResults.reverted ? 0 : 1),
|
|
368
|
+
avmCallResults.output,
|
|
369
|
+
gasUsed,
|
|
370
|
+
endSideEffectCounter,
|
|
371
|
+
),
|
|
372
|
+
);
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
public absorbSuccessfulNestedTrace(nestedTrace: this) {
|
|
376
|
+
this.sideEffectCounter = nestedTrace.sideEffectCounter;
|
|
377
|
+
this.contractStorageReads.push(...nestedTrace.contractStorageReads);
|
|
378
|
+
this.contractStorageUpdateRequests.push(...nestedTrace.contractStorageUpdateRequests);
|
|
379
|
+
this.noteHashReadRequests.push(...nestedTrace.noteHashReadRequests);
|
|
380
|
+
this.noteHashes.push(...nestedTrace.noteHashes);
|
|
381
|
+
this.nullifierReadRequests.push(...nestedTrace.nullifierReadRequests);
|
|
382
|
+
this.nullifierNonExistentReadRequests.push(...nestedTrace.nullifierNonExistentReadRequests);
|
|
383
|
+
this.nullifiers.push(...nestedTrace.nullifiers);
|
|
384
|
+
this.l1ToL2MsgReadRequests.push(...nestedTrace.l1ToL2MsgReadRequests);
|
|
385
|
+
this.l2ToL1Msgs.push(...nestedTrace.l2ToL1Msgs);
|
|
386
|
+
this.unencryptedLogs.push(...nestedTrace.unencryptedLogs);
|
|
387
|
+
this.unencryptedLogsHashes.push(...nestedTrace.unencryptedLogsHashes);
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
public absorbRevertedNestedTrace(nestedTrace: this) {
|
|
391
|
+
// All read requests, and any writes (storage & nullifiers) that
|
|
392
|
+
// require complex validation in public kernel (with end lifetimes)
|
|
393
|
+
// must be absorbed even on revert.
|
|
394
|
+
|
|
395
|
+
// TODO(dbanks12): What should happen to side effect counter on revert?
|
|
396
|
+
this.sideEffectCounter = nestedTrace.sideEffectCounter;
|
|
397
|
+
this.contractStorageReads.push(...nestedTrace.contractStorageReads);
|
|
398
|
+
this.contractStorageUpdateRequests.push(...nestedTrace.contractStorageUpdateRequests);
|
|
399
|
+
this.noteHashReadRequests.push(...nestedTrace.noteHashReadRequests);
|
|
400
|
+
// new noteHashes are tossed on revert
|
|
401
|
+
this.nullifierReadRequests.push(...nestedTrace.nullifierReadRequests);
|
|
402
|
+
this.nullifierNonExistentReadRequests.push(...nestedTrace.nullifierNonExistentReadRequests);
|
|
403
|
+
this.nullifiers.push(...nestedTrace.nullifiers);
|
|
404
|
+
this.l1ToL2MsgReadRequests.push(...nestedTrace.l1ToL2MsgReadRequests);
|
|
405
|
+
// new l2-to-l1 messages are tossed on revert
|
|
406
|
+
// new unencrypted logs are tossed on revert
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
public getSideEffects(): SideEffects {
|
|
410
|
+
return {
|
|
411
|
+
contractStorageReads: this.contractStorageReads,
|
|
412
|
+
contractStorageUpdateRequests: this.contractStorageUpdateRequests,
|
|
413
|
+
noteHashReadRequests: this.noteHashReadRequests,
|
|
414
|
+
noteHashes: this.noteHashes,
|
|
415
|
+
nullifierReadRequests: this.nullifierReadRequests,
|
|
416
|
+
nullifierNonExistentReadRequests: this.nullifierNonExistentReadRequests,
|
|
417
|
+
nullifiers: this.nullifiers,
|
|
418
|
+
l1ToL2MsgReadRequests: this.l1ToL2MsgReadRequests,
|
|
419
|
+
l2ToL1Msgs: this.l2ToL1Msgs,
|
|
420
|
+
unencryptedLogs: this.unencryptedLogs,
|
|
421
|
+
unencryptedLogsHashes: this.unencryptedLogsHashes,
|
|
422
|
+
};
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
public toVMCircuitPublicInputs(
|
|
426
|
+
/** Constants. */
|
|
427
|
+
constants: CombinedConstantData,
|
|
428
|
+
/** The execution environment of the nested call. */
|
|
429
|
+
avmEnvironment: AvmExecutionEnvironment,
|
|
430
|
+
/** How much gas was available for this public execution. */
|
|
431
|
+
startGasLeft: Gas,
|
|
432
|
+
/** How much gas was left after this public execution. */
|
|
433
|
+
endGasLeft: Gas,
|
|
434
|
+
/** The call's results */
|
|
435
|
+
avmCallResults: AvmContractCallResult,
|
|
436
|
+
): VMCircuitPublicInputs {
|
|
437
|
+
return new VMCircuitPublicInputs(
|
|
438
|
+
/*constants=*/ constants,
|
|
439
|
+
/*callRequest=*/ createPublicCallRequest(avmEnvironment),
|
|
440
|
+
/*publicCallStack=*/ makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PublicInnerCallRequest.empty),
|
|
441
|
+
/*previousValidationRequestArrayLengths=*/ this.previousValidationRequestArrayLengths,
|
|
442
|
+
/*validationRequests=*/ this.getValidationRequests(),
|
|
443
|
+
/*previousAccumulatedDataArrayLengths=*/ this.previousAccumulatedDataArrayLengths,
|
|
444
|
+
/*accumulatedData=*/ this.getAccumulatedData(startGasLeft.sub(endGasLeft)),
|
|
445
|
+
/*startSideEffectCounter=*/ this.startSideEffectCounter,
|
|
446
|
+
/*endSideEffectCounter=*/ this.sideEffectCounter,
|
|
447
|
+
/*startGasLeft=*/ startGasLeft,
|
|
448
|
+
// TODO(dbanks12): should have endGasLeft
|
|
449
|
+
/*transactionFee=*/ avmEnvironment.transactionFee,
|
|
450
|
+
/*reverted=*/ avmCallResults.reverted,
|
|
451
|
+
);
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
public getUnencryptedLogs() {
|
|
455
|
+
return this.unencryptedLogs;
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
public getAvmCircuitHints() {
|
|
459
|
+
return this.avmCircuitHints;
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
private getValidationRequests() {
|
|
463
|
+
return new PublicValidationRequests(
|
|
464
|
+
RollupValidationRequests.empty(), // TODO(dbanks12): what should this be?
|
|
465
|
+
padArrayEnd(this.noteHashReadRequests, TreeLeafReadRequest.empty(), MAX_NOTE_HASH_READ_REQUESTS_PER_TX),
|
|
466
|
+
padArrayEnd(this.nullifierReadRequests, ScopedReadRequest.empty(), MAX_NULLIFIER_READ_REQUESTS_PER_TX),
|
|
467
|
+
padArrayEnd(
|
|
468
|
+
this.nullifierNonExistentReadRequests,
|
|
469
|
+
ScopedReadRequest.empty(),
|
|
470
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
|
|
471
|
+
),
|
|
472
|
+
padArrayEnd(this.l1ToL2MsgReadRequests, TreeLeafReadRequest.empty(), MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_TX),
|
|
473
|
+
// TODO(dbanks12): this is only necessary until VMCircuitPublicInputs uses unsiloed storage slots and pairs storage accesses with contract address
|
|
474
|
+
padArrayEnd(
|
|
475
|
+
this.contractStorageReads.map(r => new PublicDataRead(r.storageSlot, r.currentValue, r.counter)),
|
|
476
|
+
PublicDataRead.empty(),
|
|
477
|
+
MAX_PUBLIC_DATA_READS_PER_TX,
|
|
478
|
+
),
|
|
479
|
+
);
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
private getAccumulatedData(gasUsed: Gas) {
|
|
483
|
+
return new PublicAccumulatedData(
|
|
484
|
+
padArrayEnd(this.noteHashes, ScopedNoteHash.empty(), MAX_NOTE_HASHES_PER_TX),
|
|
485
|
+
// TODO(dbanks12): should be able to use ScopedNullifier here
|
|
486
|
+
padArrayEnd(
|
|
487
|
+
this.nullifiers.map(n => new Nullifier(n.nullifier.value, n.nullifier.counter, n.nullifier.noteHash)),
|
|
488
|
+
Nullifier.empty(),
|
|
489
|
+
MAX_NULLIFIERS_PER_TX,
|
|
490
|
+
),
|
|
491
|
+
padArrayEnd(this.l2ToL1Msgs, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
|
|
492
|
+
/*noteEncryptedLogsHashes=*/ makeTuple(MAX_NOTE_ENCRYPTED_LOGS_PER_TX, LogHash.empty),
|
|
493
|
+
/*encryptedLogsHashes=*/ makeTuple(MAX_ENCRYPTED_LOGS_PER_TX, ScopedLogHash.empty),
|
|
494
|
+
padArrayEnd(this.unencryptedLogsHashes, ScopedLogHash.empty(), MAX_UNENCRYPTED_LOGS_PER_TX),
|
|
495
|
+
// TODO(dbanks12): this is only necessary until VMCircuitPublicInputs uses unsiloed storage slots and pairs storage accesses with contract address
|
|
496
|
+
padArrayEnd(
|
|
497
|
+
this.contractStorageUpdateRequests.map(w => new PublicDataUpdateRequest(w.storageSlot, w.newValue, w.counter)),
|
|
498
|
+
PublicDataUpdateRequest.empty(),
|
|
499
|
+
MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX,
|
|
500
|
+
),
|
|
501
|
+
/*publicCallStack=*/ makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PublicCallRequest.empty),
|
|
502
|
+
/*gasUsed=*/ gasUsed,
|
|
503
|
+
);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
private enforceLimitOnNullifierChecks(errorMsgOrigin: string = '') {
|
|
507
|
+
// NOTE: Why error if _either_ limit was reached? If user code emits either an existent or non-existent
|
|
508
|
+
// nullifier read request (NULLIFIEREXISTS, GETCONTRACTINSTANCE, *CALL), and one of the limits has been
|
|
509
|
+
// reached (MAX_NULLIFIER_NON_EXISTENT_RRS vs MAX_NULLIFIER_RRS), but not the other, we must prevent the
|
|
510
|
+
// sequencer from lying and saying "this nullifier exists, but MAX_NULLIFIER_RRS has been reached, so I'm
|
|
511
|
+
// going to skip the read request and just revert instead" when the nullifier actually doesn't exist
|
|
512
|
+
// (or vice versa). So, if either maximum has been reached, any nullifier-reading operation must error.
|
|
513
|
+
if (
|
|
514
|
+
this.nullifierReadRequests.length + this.previousValidationRequestArrayLengths.nullifierReadRequests >=
|
|
515
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX
|
|
516
|
+
) {
|
|
517
|
+
throw new SideEffectLimitReachedError(
|
|
518
|
+
`nullifier read request ${errorMsgOrigin}`,
|
|
519
|
+
MAX_NULLIFIER_READ_REQUESTS_PER_TX,
|
|
520
|
+
);
|
|
521
|
+
}
|
|
522
|
+
if (
|
|
523
|
+
this.nullifierNonExistentReadRequests.length +
|
|
524
|
+
this.previousValidationRequestArrayLengths.nullifierNonExistentReadRequests >=
|
|
525
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX
|
|
526
|
+
) {
|
|
527
|
+
throw new SideEffectLimitReachedError(
|
|
528
|
+
`nullifier non-existent read request ${errorMsgOrigin}`,
|
|
529
|
+
MAX_NULLIFIER_NON_EXISTENT_READ_REQUESTS_PER_TX,
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
|
|
535
|
+
/**
|
|
536
|
+
* Helper function to create a public execution request from an AVM execution environment
|
|
537
|
+
*/
|
|
538
|
+
function createPublicCallRequest(avmEnvironment: AvmExecutionEnvironment): PublicCallRequest {
|
|
539
|
+
const callContext = CallContext.from({
|
|
540
|
+
msgSender: avmEnvironment.sender,
|
|
541
|
+
storageContractAddress: avmEnvironment.storageAddress,
|
|
542
|
+
functionSelector: avmEnvironment.functionSelector,
|
|
543
|
+
isDelegateCall: avmEnvironment.isDelegateCall,
|
|
544
|
+
isStaticCall: avmEnvironment.isStaticCall,
|
|
545
|
+
});
|
|
546
|
+
return new PublicCallRequest(
|
|
547
|
+
avmEnvironment.address,
|
|
548
|
+
callContext,
|
|
549
|
+
computeVarArgsHash(avmEnvironment.calldata),
|
|
550
|
+
/*counter=*/ 0,
|
|
551
|
+
);
|
|
552
|
+
}
|
|
@@ -23,6 +23,7 @@ import {
|
|
|
23
23
|
L2ToL1Message,
|
|
24
24
|
LogHash,
|
|
25
25
|
MAX_L1_TO_L2_MSG_READ_REQUESTS_PER_CALL,
|
|
26
|
+
MAX_L2_GAS_PER_ENQUEUED_CALL,
|
|
26
27
|
MAX_L2_TO_L1_MSGS_PER_CALL,
|
|
27
28
|
MAX_NOTE_HASHES_PER_CALL,
|
|
28
29
|
MAX_NOTE_HASH_READ_REQUESTS_PER_CALL,
|
|
@@ -61,7 +62,7 @@ import { makeTuple } from '@aztec/foundation/array';
|
|
|
61
62
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
62
63
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
63
64
|
import { ProtocolCircuitVks } from '@aztec/noir-protocol-circuits-types';
|
|
64
|
-
import { type
|
|
65
|
+
import { type MerkleTreeReadOperations } from '@aztec/world-state';
|
|
65
66
|
|
|
66
67
|
import { type PublicExecutionResult, accumulatePublicReturnValues, collectExecutionResults } from './execution.js';
|
|
67
68
|
import { type PublicExecutor } from './executor.js';
|
|
@@ -102,7 +103,7 @@ export type EnqueuedCallResult = {
|
|
|
102
103
|
export class EnqueuedCallSimulator {
|
|
103
104
|
private log: DebugLogger;
|
|
104
105
|
constructor(
|
|
105
|
-
private db:
|
|
106
|
+
private db: MerkleTreeReadOperations,
|
|
106
107
|
private publicExecutor: PublicExecutor,
|
|
107
108
|
private publicKernelSimulator: PublicKernelCircuitSimulator,
|
|
108
109
|
private globalVariables: GlobalVariables,
|
|
@@ -120,39 +121,60 @@ export class EnqueuedCallSimulator {
|
|
|
120
121
|
transactionFee: Fr,
|
|
121
122
|
phase: PublicKernelPhase,
|
|
122
123
|
): Promise<EnqueuedCallResult> {
|
|
124
|
+
// Gas allocated to an enqueued call can be different from the available gas
|
|
125
|
+
// if there is more gas available than the max allocation per enqueued call.
|
|
126
|
+
const allocatedGas = new Gas(
|
|
127
|
+
/*daGas=*/ availableGas.daGas,
|
|
128
|
+
/*l2Gas=*/ Math.min(availableGas.l2Gas, MAX_L2_GAS_PER_ENQUEUED_CALL),
|
|
129
|
+
);
|
|
123
130
|
const pendingNullifiers = this.getSiloedPendingNullifiers(previousPublicKernelOutput);
|
|
124
131
|
const startSideEffectCounter = previousPublicKernelOutput.endSideEffectCounter + 1;
|
|
132
|
+
|
|
133
|
+
const prevAccumulatedData =
|
|
134
|
+
phase === PublicKernelPhase.SETUP
|
|
135
|
+
? previousPublicKernelOutput.endNonRevertibleData
|
|
136
|
+
: previousPublicKernelOutput.end;
|
|
137
|
+
const previousValidationRequestArrayLengths = PublicValidationRequestArrayLengths.new(
|
|
138
|
+
previousPublicKernelOutput.validationRequests,
|
|
139
|
+
);
|
|
140
|
+
const previousAccumulatedDataArrayLengths = PublicAccumulatedDataArrayLengths.new(prevAccumulatedData);
|
|
141
|
+
|
|
142
|
+
// If this is the first enqueued call in public, constants will be empty
|
|
143
|
+
// because private kernel does not expose them.
|
|
144
|
+
const constants = previousPublicKernelOutput.constants.clone();
|
|
145
|
+
constants.globalVariables = this.globalVariables;
|
|
146
|
+
|
|
125
147
|
const result = await this.publicExecutor.simulate(
|
|
126
148
|
executionRequest,
|
|
127
|
-
|
|
128
|
-
|
|
149
|
+
constants,
|
|
150
|
+
allocatedGas,
|
|
129
151
|
tx.data.constants.txContext,
|
|
130
152
|
pendingNullifiers,
|
|
131
153
|
transactionFee,
|
|
132
154
|
startSideEffectCounter,
|
|
155
|
+
previousValidationRequestArrayLengths,
|
|
156
|
+
previousAccumulatedDataArrayLengths,
|
|
133
157
|
);
|
|
134
158
|
|
|
135
159
|
const callStack = makeTuple(MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, PublicInnerCallRequest.empty);
|
|
136
160
|
callStack[0].item.contractAddress = callRequest.contractAddress;
|
|
137
161
|
callStack[0].item.callContext = callRequest.callContext;
|
|
138
162
|
callStack[0].item.argsHash = callRequest.argsHash;
|
|
139
|
-
|
|
140
|
-
phase === PublicKernelPhase.SETUP
|
|
141
|
-
? previousPublicKernelOutput.endNonRevertibleData
|
|
142
|
-
: previousPublicKernelOutput.end;
|
|
163
|
+
|
|
143
164
|
const accumulatedData = PublicAccumulatedData.empty();
|
|
144
165
|
accumulatedData.publicCallStack[0] = callRequest;
|
|
166
|
+
|
|
145
167
|
const startVMCircuitOutput = new VMCircuitPublicInputs(
|
|
146
168
|
previousPublicKernelOutput.constants,
|
|
147
169
|
callRequest,
|
|
148
170
|
callStack,
|
|
149
|
-
|
|
171
|
+
previousValidationRequestArrayLengths,
|
|
150
172
|
PublicValidationRequests.empty(),
|
|
151
|
-
|
|
173
|
+
previousAccumulatedDataArrayLengths,
|
|
152
174
|
accumulatedData,
|
|
153
175
|
startSideEffectCounter,
|
|
154
176
|
startSideEffectCounter,
|
|
155
|
-
|
|
177
|
+
allocatedGas,
|
|
156
178
|
result.transactionFee,
|
|
157
179
|
result.reverted,
|
|
158
180
|
);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type
|
|
2
|
+
type MerkleTreeReadOperations,
|
|
3
3
|
type NestedProcessReturnValues,
|
|
4
4
|
type ProcessedTx,
|
|
5
5
|
ProvingRequestType,
|
|
@@ -28,7 +28,7 @@ import {
|
|
|
28
28
|
} from '@aztec/circuits.js';
|
|
29
29
|
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
30
30
|
import { Timer } from '@aztec/foundation/timer';
|
|
31
|
-
import { ProtocolCircuitVks, getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types';
|
|
31
|
+
import { ProtocolCircuitVks, TubeVk, getVKIndex, getVKSiblingPath } from '@aztec/noir-protocol-circuits-types';
|
|
32
32
|
|
|
33
33
|
import { inspect } from 'util';
|
|
34
34
|
|
|
@@ -93,7 +93,7 @@ export class EnqueuedCallsProcessor {
|
|
|
93
93
|
}
|
|
94
94
|
|
|
95
95
|
static create(
|
|
96
|
-
db:
|
|
96
|
+
db: MerkleTreeReadOperations,
|
|
97
97
|
publicExecutor: PublicExecutor,
|
|
98
98
|
publicKernelSimulator: PublicKernelCircuitSimulator,
|
|
99
99
|
globalVariables: GlobalVariables,
|
|
@@ -377,9 +377,7 @@ export class EnqueuedCallsProcessor {
|
|
|
377
377
|
// The proof is not used in simulation.
|
|
378
378
|
const proof = makeEmptyRecursiveProof(NESTED_RECURSIVE_PROOF_LENGTH);
|
|
379
379
|
|
|
380
|
-
const vk = isFromPrivate
|
|
381
|
-
? ProtocolCircuitVks.PrivateKernelTailToPublicArtifact
|
|
382
|
-
: ProtocolCircuitVks.PublicKernelMergeArtifact;
|
|
380
|
+
const vk = isFromPrivate ? TubeVk : ProtocolCircuitVks.PublicKernelMergeArtifact;
|
|
383
381
|
const vkIndex = getVKIndex(vk);
|
|
384
382
|
const siblingPath = getVKSiblingPath(vkIndex);
|
|
385
383
|
|