@aztec/simulator 0.0.1-commit.64b6bbb → 0.0.1-commit.684755437
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/README.md +4 -4
- package/dest/private/circuit_recording/circuit_recorder.js +2 -2
- package/dest/public/avm/avm_gas.js +3 -3
- package/dest/public/avm/opcodes/accrued_substate.d.ts +2 -2
- package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/public/avm/opcodes/accrued_substate.js +3 -4
- package/dest/public/avm/serialization/bytecode_serialization.js +3 -3
- package/dest/public/avm/serialization/instruction_serialization.d.ts +2 -2
- package/dest/public/avm/serialization/instruction_serialization.d.ts.map +1 -1
- package/dest/public/avm/serialization/instruction_serialization.js +1 -1
- package/dest/public/fixtures/amm_test.js +2 -2
- package/dest/public/fixtures/opcode_spammer.d.ts +1 -1
- package/dest/public/fixtures/opcode_spammer.d.ts.map +1 -1
- package/dest/public/fixtures/opcode_spammer.js +6 -6
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts +6 -5
- package/dest/public/fixtures/public_tx_simulation_tester.d.ts.map +1 -1
- package/dest/public/fixtures/public_tx_simulation_tester.js +36 -9
- package/dest/public/fixtures/utils.d.ts +2 -2
- package/dest/public/fixtures/utils.d.ts.map +1 -1
- package/dest/public/fixtures/utils.js +6 -6
- package/dest/public/hinting_db_sources.d.ts +2 -2
- package/dest/public/hinting_db_sources.d.ts.map +1 -1
- package/dest/public/hinting_db_sources.js +1 -1
- package/dest/public/public_processor/guarded_merkle_tree.d.ts +2 -2
- package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -1
- package/dest/public/public_processor/guarded_merkle_tree.js +1 -1
- package/dest/public/public_processor/public_processor.d.ts +5 -3
- package/dest/public/public_processor/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor.js +43 -31
- package/dest/public/public_tx_simulator/cpp_public_tx_simulator.d.ts +1 -1
- package/dest/public/public_tx_simulator/cpp_public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/cpp_public_tx_simulator.js +2 -3
- package/dest/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.d.ts +1 -1
- package/dest/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.js +2 -2
- package/dest/public/public_tx_simulator/factories.d.ts +2 -2
- package/dest/public/public_tx_simulator/factories.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/factories.js +2 -2
- package/dest/public/public_tx_simulator/public_tx_simulator.js +2 -2
- package/dest/public/test_executor_metrics.d.ts +6 -1
- package/dest/public/test_executor_metrics.d.ts.map +1 -1
- package/dest/public/test_executor_metrics.js +22 -0
- package/package.json +16 -16
- package/src/private/circuit_recording/circuit_recorder.ts +2 -2
- package/src/public/avm/avm_gas.ts +2 -2
- package/src/public/avm/opcodes/accrued_substate.ts +3 -4
- package/src/public/avm/serialization/bytecode_serialization.ts +2 -2
- package/src/public/avm/serialization/instruction_serialization.ts +1 -1
- package/src/public/fixtures/amm_test.ts +2 -2
- package/src/public/fixtures/opcode_spammer.ts +6 -10
- package/src/public/fixtures/public_tx_simulation_tester.ts +51 -5
- package/src/public/fixtures/utils.ts +6 -5
- package/src/public/fuzzing/avm_fuzzer_simulator.ts +1 -1
- package/src/public/hinting_db_sources.ts +1 -1
- package/src/public/public_processor/guarded_merkle_tree.ts +1 -1
- package/src/public/public_processor/public_processor.ts +57 -42
- package/src/public/public_tx_simulator/cpp_public_tx_simulator.ts +2 -3
- package/src/public/public_tx_simulator/cpp_public_tx_simulator_with_hinted_dbs.ts +2 -2
- package/src/public/public_tx_simulator/factories.ts +2 -1
- package/src/public/public_tx_simulator/public_tx_simulator.ts +3 -3
- package/src/public/test_executor_metrics.ts +24 -0
|
@@ -110,7 +110,7 @@ const BASE_GAS_COSTS: Record<Opcode, Gas> = {
|
|
|
110
110
|
[Opcode.NULLIFIEREXISTS]: makeCost(c.AVM_NULLIFIEREXISTS_BASE_L2_GAS, 0),
|
|
111
111
|
[Opcode.EMITNULLIFIER]: makeCost(c.AVM_EMITNULLIFIER_BASE_L2_GAS, c.AVM_EMITNULLIFIER_BASE_DA_GAS),
|
|
112
112
|
[Opcode.L1TOL2MSGEXISTS]: makeCost(c.AVM_L1TOL2MSGEXISTS_BASE_L2_GAS, 0),
|
|
113
|
-
[Opcode.
|
|
113
|
+
[Opcode.EMITPUBLICLOG]: makeCost(c.AVM_EMITPUBLICLOG_BASE_L2_GAS, c.AVM_EMITPUBLICLOG_BASE_DA_GAS),
|
|
114
114
|
[Opcode.SENDL2TOL1MSG]: makeCost(c.AVM_SENDL2TOL1MSG_BASE_L2_GAS, c.AVM_SENDL2TOL1MSG_BASE_DA_GAS),
|
|
115
115
|
[Opcode.GETCONTRACTINSTANCE]: makeCost(c.AVM_GETCONTRACTINSTANCE_BASE_L2_GAS, 0),
|
|
116
116
|
[Opcode.CALL]: makeCost(c.AVM_CALL_BASE_L2_GAS, 0),
|
|
@@ -130,7 +130,7 @@ const DYNAMIC_GAS_COSTS = new Map<Opcode, Gas>([
|
|
|
130
130
|
[Opcode.CALLDATACOPY, makeCost(c.AVM_CALLDATACOPY_DYN_L2_GAS, 0)],
|
|
131
131
|
[Opcode.RETURNDATACOPY, makeCost(c.AVM_RETURNDATACOPY_DYN_L2_GAS, 0)],
|
|
132
132
|
// TODO: Call and static call based on bytecode length
|
|
133
|
-
[Opcode.
|
|
133
|
+
[Opcode.EMITPUBLICLOG, makeCost(c.AVM_EMITPUBLICLOG_DYN_L2_GAS, c.AVM_EMITPUBLICLOG_DYN_DA_GAS)],
|
|
134
134
|
[Opcode.TORADIXBE, makeCost(c.AVM_TORADIXBE_DYN_L2_GAS, 0)],
|
|
135
135
|
[Opcode.AND_8, makeCost(c.AVM_BITWISE_DYN_L2_GAS, 0)],
|
|
136
136
|
[Opcode.AND_16, makeCost(c.AVM_BITWISE_DYN_L2_GAS, 0)],
|
|
@@ -204,10 +204,9 @@ export class L1ToL2MessageExists extends Instruction {
|
|
|
204
204
|
}
|
|
205
205
|
}
|
|
206
206
|
|
|
207
|
-
export class
|
|
208
|
-
|
|
209
|
-
static
|
|
210
|
-
static readonly opcode: Opcode = Opcode.EMITUNENCRYPTEDLOG;
|
|
207
|
+
export class EmitPublicLog extends Instruction {
|
|
208
|
+
static type: string = 'EMITPUBLICLOG';
|
|
209
|
+
static readonly opcode: Opcode = Opcode.EMITPUBLICLOG;
|
|
211
210
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
212
211
|
static readonly wireFormat = [OperandType.UINT8, OperandType.UINT8, OperandType.UINT16, OperandType.UINT16];
|
|
213
212
|
|
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
EcAdd,
|
|
20
20
|
EmitNoteHash,
|
|
21
21
|
EmitNullifier,
|
|
22
|
-
|
|
22
|
+
EmitPublicLog,
|
|
23
23
|
Eq,
|
|
24
24
|
FieldDiv,
|
|
25
25
|
GetContractInstance,
|
|
@@ -129,7 +129,7 @@ export const INSTRUCTION_SET = new Map<Opcode, InstructionDeserializer>([
|
|
|
129
129
|
[L1ToL2MessageExists.opcode, Instruction.fromBuffer.bind(L1ToL2MessageExists)], // Messages
|
|
130
130
|
|
|
131
131
|
// Accrued Substate
|
|
132
|
-
[
|
|
132
|
+
[EmitPublicLog.opcode, Instruction.fromBuffer.bind(EmitPublicLog)],
|
|
133
133
|
[SendL2ToL1Message.opcode, Instruction.fromBuffer.bind(SendL2ToL1Message)],
|
|
134
134
|
[GetContractInstance.opcode, Instruction.fromBuffer.bind(GetContractInstance)],
|
|
135
135
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DomainSeparator } from '@aztec/constants';
|
|
2
2
|
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import type { Logger } from '@aztec/foundation/log';
|
|
@@ -326,6 +326,6 @@ async function removeLiquidity(
|
|
|
326
326
|
async function computePartialNoteValidityCommitment(partialNote: { commitment: Fr }, completer: AztecAddress) {
|
|
327
327
|
return await poseidon2HashWithSeparator(
|
|
328
328
|
[partialNote.commitment, completer],
|
|
329
|
-
|
|
329
|
+
DomainSeparator.PARTIAL_NOTE_VALIDITY_COMMITMENT,
|
|
330
330
|
);
|
|
331
331
|
}
|
|
@@ -143,7 +143,7 @@
|
|
|
143
143
|
* - `EMITNOTEHASH`: max 64 per TX
|
|
144
144
|
* - `EMITNULLIFIER`: max 63 per TX (one reserved for TX nullifier)
|
|
145
145
|
* - `SENDL2TOL1MSG`: max 8 per TX
|
|
146
|
-
* - `
|
|
146
|
+
* - `EMITPUBLICLOG`: limited by total log payload size
|
|
147
147
|
*
|
|
148
148
|
* By having the inner contract REVERT after emitting side effects, those effects are discarded, allowing the outer contract to call it again. This enables thousands of opcode executions per TX instead of just the limit.
|
|
149
149
|
*
|
|
@@ -182,7 +182,7 @@ import {
|
|
|
182
182
|
EcAdd,
|
|
183
183
|
EmitNoteHash,
|
|
184
184
|
EmitNullifier,
|
|
185
|
-
|
|
185
|
+
EmitPublicLog,
|
|
186
186
|
Eq,
|
|
187
187
|
FieldDiv,
|
|
188
188
|
GetContractInstance,
|
|
@@ -1242,17 +1242,15 @@ export const SPAM_CONFIGS: Partial<Record<Opcode, SpamConfig[]>> = {
|
|
|
1242
1242
|
},
|
|
1243
1243
|
],
|
|
1244
1244
|
|
|
1245
|
-
//
|
|
1246
|
-
[Opcode.
|
|
1245
|
+
// EMITPUBLICLOG - two configs: minimal (many small logs) and max-size (one large log)
|
|
1246
|
+
[Opcode.EMITPUBLICLOG]: [
|
|
1247
1247
|
{
|
|
1248
1248
|
label: 'Many empty logs, revert, repeat',
|
|
1249
1249
|
setup: [
|
|
1250
1250
|
{ offset: 0, value: new Uint32(0n) }, // logSize = 0 fields (minimal)
|
|
1251
1251
|
{ offset: 1, value: new Uint32(0n) }, // revertSize
|
|
1252
1252
|
],
|
|
1253
|
-
targetInstructions: () => [
|
|
1254
|
-
new EmitUnencryptedLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 1),
|
|
1255
|
-
], // logOffset doesn't matter when size is 0
|
|
1253
|
+
targetInstructions: () => [new EmitPublicLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 1)], // logOffset doesn't matter when size is 0
|
|
1256
1254
|
cleanupInstructions: () => [
|
|
1257
1255
|
new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/ 1, /*returnOffset=*/ 0).as(
|
|
1258
1256
|
Opcode.REVERT_8,
|
|
@@ -1276,9 +1274,7 @@ export const SPAM_CONFIGS: Partial<Record<Opcode, SpamConfig[]>> = {
|
|
|
1276
1274
|
// value: new Field(0n),
|
|
1277
1275
|
//})),
|
|
1278
1276
|
],
|
|
1279
|
-
targetInstructions: () => [
|
|
1280
|
-
new EmitUnencryptedLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 2),
|
|
1281
|
-
], // uses logOffset 2 (uninitialized Field(0))
|
|
1277
|
+
targetInstructions: () => [new EmitPublicLog(/*addressing_mode=*/ 0, /*logSizeOffset=*/ 0, /*logOffset=*/ 2)], // uses logOffset 2 (uninitialized Field(0))
|
|
1282
1278
|
cleanupInstructions: () => [
|
|
1283
1279
|
new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/ 1, /*returnOffset=*/ 0).as(
|
|
1284
1280
|
Opcode.REVERT_8,
|
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
DEFAULT_TEARDOWN_DA_GAS_LIMIT,
|
|
3
|
+
DEFAULT_TEARDOWN_L2_GAS_LIMIT,
|
|
4
|
+
PUBLIC_TX_L2_GAS_OVERHEAD,
|
|
5
|
+
TX_DA_GAS_OVERHEAD,
|
|
6
|
+
} from '@aztec/constants';
|
|
2
7
|
import { asyncMap } from '@aztec/foundation/async-map';
|
|
3
8
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
4
9
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
@@ -112,6 +117,7 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
112
117
|
feePayer: AztecAddress = sender,
|
|
113
118
|
/* need some unique first nullifier for note-nonce computations */
|
|
114
119
|
privateInsertions: TestPrivateInsertions = { nonRevertible: { nullifiers: [new Fr(420000 + this.txCount)] } },
|
|
120
|
+
gasLimits?: Gas,
|
|
115
121
|
): Promise<Tx> {
|
|
116
122
|
const setupCallRequests = await asyncMap(setupCalls, call =>
|
|
117
123
|
this.#createPubicCallRequestForCall(call, call.sender ?? sender),
|
|
@@ -131,9 +137,13 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
131
137
|
teardownCallRequest,
|
|
132
138
|
feePayer,
|
|
133
139
|
/*gasUsedByPrivate*/ teardownCall
|
|
134
|
-
? new Gas(
|
|
135
|
-
|
|
140
|
+
? new Gas(
|
|
141
|
+
DEFAULT_TEARDOWN_DA_GAS_LIMIT + TX_DA_GAS_OVERHEAD,
|
|
142
|
+
DEFAULT_TEARDOWN_L2_GAS_LIMIT + PUBLIC_TX_L2_GAS_OVERHEAD,
|
|
143
|
+
)
|
|
144
|
+
: new Gas(TX_DA_GAS_OVERHEAD, PUBLIC_TX_L2_GAS_OVERHEAD),
|
|
136
145
|
defaultGlobals(),
|
|
146
|
+
gasLimits,
|
|
137
147
|
);
|
|
138
148
|
}
|
|
139
149
|
|
|
@@ -146,8 +156,9 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
146
156
|
/* need some unique first nullifier for note-nonce computations */
|
|
147
157
|
privateInsertions?: TestPrivateInsertions,
|
|
148
158
|
txLabel: string = 'unlabeledTx',
|
|
159
|
+
gasLimits?: Gas,
|
|
149
160
|
): Promise<PublicTxResult> {
|
|
150
|
-
const tx = await this.createTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions);
|
|
161
|
+
const tx = await this.createTx(sender, setupCalls, appCalls, teardownCall, feePayer, privateInsertions, gasLimits);
|
|
151
162
|
|
|
152
163
|
await this.setFeePayerBalance(feePayer);
|
|
153
164
|
|
|
@@ -161,6 +172,8 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
161
172
|
}
|
|
162
173
|
const avmResult = await this.simulator.simulate(tx, fullTxLabel);
|
|
163
174
|
|
|
175
|
+
await this.#recordBytecodeSizes(fullTxLabel, [...setupCalls, ...appCalls, ...(teardownCall ? [teardownCall] : [])]);
|
|
176
|
+
|
|
164
177
|
// Something like this is often useful for debugging:
|
|
165
178
|
//if (avmResult.revertReason) {
|
|
166
179
|
// // resolve / enrich revert reason
|
|
@@ -190,8 +203,18 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
190
203
|
teardownCall?: TestEnqueuedCall,
|
|
191
204
|
feePayer?: AztecAddress,
|
|
192
205
|
privateInsertions?: TestPrivateInsertions,
|
|
206
|
+
gasLimits?: Gas,
|
|
193
207
|
): Promise<PublicTxResult> {
|
|
194
|
-
return await this.simulateTx(
|
|
208
|
+
return await this.simulateTx(
|
|
209
|
+
sender,
|
|
210
|
+
setupCalls,
|
|
211
|
+
appCalls,
|
|
212
|
+
teardownCall,
|
|
213
|
+
feePayer,
|
|
214
|
+
privateInsertions,
|
|
215
|
+
txLabel,
|
|
216
|
+
gasLimits,
|
|
217
|
+
);
|
|
195
218
|
}
|
|
196
219
|
|
|
197
220
|
/**
|
|
@@ -209,6 +232,7 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
209
232
|
teardownCall?: TestEnqueuedCall,
|
|
210
233
|
feePayer?: AztecAddress,
|
|
211
234
|
privateInsertions?: TestPrivateInsertions,
|
|
235
|
+
gasLimits?: Gas,
|
|
212
236
|
): Promise<PublicTxResult> {
|
|
213
237
|
return await this.simulateTxWithLabel(
|
|
214
238
|
txLabel,
|
|
@@ -218,6 +242,7 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
218
242
|
teardownCall,
|
|
219
243
|
feePayer,
|
|
220
244
|
privateInsertions,
|
|
245
|
+
gasLimits,
|
|
221
246
|
);
|
|
222
247
|
}
|
|
223
248
|
|
|
@@ -277,6 +302,27 @@ export class PublicTxSimulationTester extends BaseAvmSimulationTester {
|
|
|
277
302
|
|
|
278
303
|
return new PublicCallRequestWithCalldata(request, calldata);
|
|
279
304
|
}
|
|
305
|
+
|
|
306
|
+
// WARNING: Deduplicates by artifact name, so two different artifacts with the same name
|
|
307
|
+
// in a single tx would only record the first one's bytecode size.
|
|
308
|
+
async #recordBytecodeSizes(txLabel: string, calls: TestEnqueuedCall[]) {
|
|
309
|
+
const seenArtifactNames = new Set<string>();
|
|
310
|
+
for (const call of calls) {
|
|
311
|
+
const artifact = await this.contractDataSource.getContractArtifact(call.address);
|
|
312
|
+
if (!artifact || seenArtifactNames.has(artifact.name)) {
|
|
313
|
+
continue;
|
|
314
|
+
}
|
|
315
|
+
seenArtifactNames.add(artifact.name);
|
|
316
|
+
const instance = await this.contractDataSource.getContract(call.address);
|
|
317
|
+
if (!instance) {
|
|
318
|
+
continue;
|
|
319
|
+
}
|
|
320
|
+
const contractClass = await this.contractDataSource.getContractClass(instance.currentContractClassId);
|
|
321
|
+
if (contractClass) {
|
|
322
|
+
this.metrics.recordBytecodeSize(txLabel, artifact.name, contractClass.packedBytecode.length);
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
}
|
|
280
326
|
}
|
|
281
327
|
|
|
282
328
|
export function defaultGlobals() {
|
|
@@ -62,13 +62,14 @@ export async function createTxForPublicCalls(
|
|
|
62
62
|
feePayer = AztecAddress.zero(),
|
|
63
63
|
gasUsedByPrivate: Gas = Gas.empty(),
|
|
64
64
|
globals: GlobalVariables = GlobalVariables.empty(),
|
|
65
|
+
gasLimits?: Gas,
|
|
65
66
|
): Promise<Tx> {
|
|
66
67
|
assert(
|
|
67
68
|
setupCallRequests.length > 0 || appCallRequests.length > 0 || teardownCallRequest !== undefined,
|
|
68
69
|
"Can't create public tx with no enqueued calls",
|
|
69
70
|
);
|
|
70
71
|
// use max limits
|
|
71
|
-
|
|
72
|
+
gasLimits = gasLimits ?? new Gas(DEFAULT_DA_GAS_LIMIT, DEFAULT_L2_GAS_LIMIT);
|
|
72
73
|
|
|
73
74
|
const forPublic = PartialPrivateTailPublicInputsForPublic.empty();
|
|
74
75
|
|
|
@@ -134,13 +135,13 @@ export async function createTxForPublicCalls(
|
|
|
134
135
|
const txContext = new TxContext(Fr.zero(), Fr.zero(), gasSettings);
|
|
135
136
|
const header = BlockHeader.empty({ globalVariables: globals });
|
|
136
137
|
const constantData = new TxConstantData(header, txContext, Fr.zero(), Fr.zero());
|
|
137
|
-
const
|
|
138
|
+
const expirationTimestamp = 0n; // Not used in the simulator.
|
|
138
139
|
|
|
139
140
|
const txData = new PrivateKernelTailCircuitPublicInputs(
|
|
140
141
|
constantData,
|
|
141
142
|
/*gasUsed=*/ gasUsedByPrivate,
|
|
142
143
|
feePayer,
|
|
143
|
-
|
|
144
|
+
expirationTimestamp,
|
|
144
145
|
forPublic,
|
|
145
146
|
);
|
|
146
147
|
|
|
@@ -171,13 +172,13 @@ export async function createTxForPrivateOnly(
|
|
|
171
172
|
const gasSettings = new GasSettings(gasLimits, Gas.empty(), maxFeesPerGas, GasFees.empty());
|
|
172
173
|
const txContext = new TxContext(Fr.zero(), Fr.zero(), gasSettings);
|
|
173
174
|
const constantData = new TxConstantData(BlockHeader.empty(), txContext, Fr.zero(), Fr.zero());
|
|
174
|
-
const
|
|
175
|
+
const expirationTimestamp = 0n; // Not used in the simulator.
|
|
175
176
|
|
|
176
177
|
const txData = new PrivateKernelTailCircuitPublicInputs(
|
|
177
178
|
constantData,
|
|
178
179
|
/*gasUsed=*/ gasUsedByPrivate,
|
|
179
180
|
feePayer,
|
|
180
|
-
|
|
181
|
+
expirationTimestamp,
|
|
181
182
|
/*forPublic=*/ undefined,
|
|
182
183
|
forRollup,
|
|
183
184
|
);
|
|
@@ -146,7 +146,7 @@ async function createTxFromHint(cppTx: AvmTxHint): Promise<Tx> {
|
|
|
146
146
|
constants,
|
|
147
147
|
cppTx.gasUsedByPrivate,
|
|
148
148
|
cppTx.feePayer,
|
|
149
|
-
0n, //
|
|
149
|
+
0n, // expirationTimestamp
|
|
150
150
|
forPublic,
|
|
151
151
|
undefined, // forRollup - not needed for public simulation
|
|
152
152
|
);
|
|
@@ -572,7 +572,7 @@ export class HintingMerkleWriteOperations implements MerkleTreeWriteOperations {
|
|
|
572
572
|
return await this.db.close();
|
|
573
573
|
}
|
|
574
574
|
|
|
575
|
-
async [Symbol.
|
|
575
|
+
async [Symbol.asyncDispose](): Promise<void> {
|
|
576
576
|
await this.close();
|
|
577
577
|
}
|
|
578
578
|
|
|
@@ -82,7 +82,7 @@ export class GuardedMerkleTreeOperations implements MerkleTreeWriteOperations {
|
|
|
82
82
|
return this.guardAndPush(() => this.target.close());
|
|
83
83
|
}
|
|
84
84
|
|
|
85
|
-
async [Symbol.
|
|
85
|
+
async [Symbol.asyncDispose](): Promise<void> {
|
|
86
86
|
await this.close();
|
|
87
87
|
}
|
|
88
88
|
getTreeInfo(treeId: MerkleTreeId): Promise<TreeInfo> {
|
|
@@ -25,6 +25,7 @@ import type {
|
|
|
25
25
|
PublicProcessorValidator,
|
|
26
26
|
SequencerConfig,
|
|
27
27
|
} from '@aztec/stdlib/interfaces/server';
|
|
28
|
+
import { type DebugLog, type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
28
29
|
import { ProvingRequestType } from '@aztec/stdlib/proofs';
|
|
29
30
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
30
31
|
import {
|
|
@@ -130,7 +131,6 @@ class PublicProcessorTimeoutError extends Error {
|
|
|
130
131
|
*/
|
|
131
132
|
export class PublicProcessor implements Traceable {
|
|
132
133
|
private metrics: PublicProcessorMetrics;
|
|
133
|
-
|
|
134
134
|
constructor(
|
|
135
135
|
protected globalVariables: GlobalVariables,
|
|
136
136
|
private guardedMerkleTree: GuardedMerkleTreeOperations,
|
|
@@ -140,6 +140,7 @@ export class PublicProcessor implements Traceable {
|
|
|
140
140
|
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
141
141
|
private log: Logger,
|
|
142
142
|
private opts: Pick<SequencerConfig, 'fakeProcessingDelayPerTxMs' | 'fakeThrowAfterProcessingTxCount'> = {},
|
|
143
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
143
144
|
) {
|
|
144
145
|
this.metrics = new PublicProcessorMetrics(telemetryClient, 'PublicProcessor');
|
|
145
146
|
}
|
|
@@ -159,12 +160,13 @@ export class PublicProcessor implements Traceable {
|
|
|
159
160
|
txs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
160
161
|
limits: PublicProcessorLimits = {},
|
|
161
162
|
validator: PublicProcessorValidator = {},
|
|
162
|
-
): Promise<[ProcessedTx[], FailedTx[], Tx[], NestedProcessReturnValues[],
|
|
163
|
-
const { maxTransactions,
|
|
163
|
+
): Promise<[ProcessedTx[], FailedTx[], Tx[], NestedProcessReturnValues[], DebugLog[]]> {
|
|
164
|
+
const { maxTransactions, deadline, maxBlockGas, maxBlobFields, isBuildingProposal } = limits;
|
|
164
165
|
const { preprocessValidator, nullifierCache } = validator;
|
|
165
166
|
const result: ProcessedTx[] = [];
|
|
166
167
|
const usedTxs: Tx[] = [];
|
|
167
168
|
const failed: FailedTx[] = [];
|
|
169
|
+
const debugLogs: DebugLog[] = [];
|
|
168
170
|
const timer = new Timer();
|
|
169
171
|
|
|
170
172
|
let totalSizeInBytes = 0;
|
|
@@ -186,22 +188,23 @@ export class PublicProcessor implements Traceable {
|
|
|
186
188
|
break;
|
|
187
189
|
}
|
|
188
190
|
|
|
189
|
-
// Skip this tx if it'd exceed max block size
|
|
190
191
|
const txHash = tx.getTxHash().toString();
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
192
|
+
|
|
193
|
+
// Skip this tx if its estimated blob fields would exceed the limit.
|
|
194
|
+
// Only done during proposal building: during re-execution we must process the exact txs from the proposal.
|
|
195
|
+
const txBlobFields = tx.getPrivateTxEffectsSizeInFields();
|
|
196
|
+
if (isBuildingProposal && maxBlobFields !== undefined && totalBlobFields + txBlobFields > maxBlobFields) {
|
|
197
|
+
this.log.warn(
|
|
198
|
+
`Skipping tx ${txHash} with ${txBlobFields} fields from private side effects due to blob fields limit`,
|
|
199
|
+
{ txHash, txBlobFields, totalBlobFields, maxBlobFields },
|
|
200
|
+
);
|
|
199
201
|
continue;
|
|
200
202
|
}
|
|
201
203
|
|
|
202
|
-
// Skip this tx if its gas limit would exceed the block gas limit
|
|
204
|
+
// Skip this tx if its gas limit would exceed the block gas limit (either da or l2).
|
|
205
|
+
// Only done during proposal building: during re-execution we must process the exact txs from the proposal.
|
|
203
206
|
const txGasLimit = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
204
|
-
if (maxBlockGas !== undefined && totalBlockGas.add(txGasLimit).gtAny(maxBlockGas)) {
|
|
207
|
+
if (isBuildingProposal && maxBlockGas !== undefined && totalBlockGas.add(txGasLimit).gtAny(maxBlockGas)) {
|
|
205
208
|
this.log.warn(`Skipping processing of tx ${txHash} due to block gas limit`, {
|
|
206
209
|
txHash,
|
|
207
210
|
txGasLimit,
|
|
@@ -241,7 +244,7 @@ export class PublicProcessor implements Traceable {
|
|
|
241
244
|
this.contractsDB.createCheckpoint();
|
|
242
245
|
|
|
243
246
|
try {
|
|
244
|
-
const [processedTx, returnValues] = await this.processTx(tx, deadline);
|
|
247
|
+
const [processedTx, returnValues, txDebugLogs] = await this.processTx(tx, deadline);
|
|
245
248
|
|
|
246
249
|
// Inject a fake processing failure after N txs if requested
|
|
247
250
|
const fakeThrowAfter = this.opts.fakeThrowAfterProcessingTxCount;
|
|
@@ -250,23 +253,9 @@ export class PublicProcessor implements Traceable {
|
|
|
250
253
|
}
|
|
251
254
|
|
|
252
255
|
const txBlobFields = processedTx.txEffect.getNumBlobFields();
|
|
253
|
-
|
|
254
|
-
// If the actual size of this tx would exceed block size, skip it
|
|
255
256
|
const txSize = txBlobFields * Fr.SIZE_IN_BYTES;
|
|
256
|
-
if (maxBlockSize !== undefined && totalSizeInBytes + txSize > maxBlockSize) {
|
|
257
|
-
this.log.debug(`Skipping processed tx ${txHash} sized ${txSize} due to max block size.`, {
|
|
258
|
-
txHash,
|
|
259
|
-
sizeInBytes: txSize,
|
|
260
|
-
totalSizeInBytes,
|
|
261
|
-
maxBlockSize,
|
|
262
|
-
});
|
|
263
|
-
// Need to revert the checkpoint here and don't go any further
|
|
264
|
-
await checkpoint.revert();
|
|
265
|
-
this.contractsDB.revertCheckpoint();
|
|
266
|
-
continue;
|
|
267
|
-
}
|
|
268
257
|
|
|
269
|
-
// If the actual blob fields of this tx would exceed the limit, skip it
|
|
258
|
+
// If the actual blob fields of this tx would exceed the limit, skip it.
|
|
270
259
|
// Note: maxBlobFields already accounts for block end blob fields and previous blocks in checkpoint.
|
|
271
260
|
if (maxBlobFields !== undefined && totalBlobFields + txBlobFields > maxBlobFields) {
|
|
272
261
|
this.log.debug(
|
|
@@ -284,12 +273,34 @@ export class PublicProcessor implements Traceable {
|
|
|
284
273
|
continue;
|
|
285
274
|
}
|
|
286
275
|
|
|
276
|
+
// During re-execution, check if the actual gas used by this tx would push the block over the gas limit.
|
|
277
|
+
// Unlike the proposal-building check (which uses declared gas limits pessimistically before processing),
|
|
278
|
+
// this uses actual gas and stops processing when the limit is exceeded.
|
|
279
|
+
if (
|
|
280
|
+
!isBuildingProposal &&
|
|
281
|
+
maxBlockGas !== undefined &&
|
|
282
|
+
totalBlockGas.add(processedTx.gasUsed.totalGas).gtAny(maxBlockGas)
|
|
283
|
+
) {
|
|
284
|
+
this.log.warn(`Stopping re-execution since tx ${txHash} would push block gas over limit`, {
|
|
285
|
+
txHash,
|
|
286
|
+
txGas: processedTx.gasUsed.totalGas,
|
|
287
|
+
totalBlockGas,
|
|
288
|
+
maxBlockGas,
|
|
289
|
+
});
|
|
290
|
+
await checkpoint.revert();
|
|
291
|
+
this.contractsDB.revertCheckpoint();
|
|
292
|
+
break;
|
|
293
|
+
}
|
|
294
|
+
|
|
287
295
|
// FIXME(fcarreiro): it's ugly to have to notify the validator of nullifiers.
|
|
288
296
|
// I'd rather pass the validators the processedTx as well and let them deal with it.
|
|
289
297
|
nullifierCache?.addNullifiers(processedTx.txEffect.nullifiers.map(n => n.toBuffer()));
|
|
290
298
|
result.push(processedTx);
|
|
291
299
|
usedTxs.push(tx);
|
|
292
300
|
returns = returns.concat(returnValues);
|
|
301
|
+
debugLogs.push(...txDebugLogs);
|
|
302
|
+
|
|
303
|
+
this.debugLogStore.storeLogs(processedTx.hash.toString(), txDebugLogs);
|
|
293
304
|
|
|
294
305
|
totalPublicGas = totalPublicGas.add(processedTx.gasUsed.publicGas);
|
|
295
306
|
totalBlockGas = totalBlockGas.add(processedTx.gasUsed.totalGas);
|
|
@@ -363,7 +374,7 @@ export class PublicProcessor implements Traceable {
|
|
|
363
374
|
totalSizeInBytes,
|
|
364
375
|
});
|
|
365
376
|
|
|
366
|
-
return [result, failed, usedTxs, returns,
|
|
377
|
+
return [result, failed, usedTxs, returns, debugLogs];
|
|
367
378
|
}
|
|
368
379
|
|
|
369
380
|
private async checkWorldStateUnchanged(
|
|
@@ -383,8 +394,13 @@ export class PublicProcessor implements Traceable {
|
|
|
383
394
|
}
|
|
384
395
|
|
|
385
396
|
@trackSpan('PublicProcessor.processTx', tx => ({ [Attributes.TX_HASH]: tx.getTxHash().toString() }))
|
|
386
|
-
private async processTx(
|
|
387
|
-
|
|
397
|
+
private async processTx(
|
|
398
|
+
tx: Tx,
|
|
399
|
+
deadline: Date | undefined,
|
|
400
|
+
): Promise<[ProcessedTx, NestedProcessReturnValues[], DebugLog[]]> {
|
|
401
|
+
const [time, [processedTx, returnValues, debugLogs]] = await elapsed(() =>
|
|
402
|
+
this.processTxWithinDeadline(tx, deadline),
|
|
403
|
+
);
|
|
388
404
|
|
|
389
405
|
this.log.verbose(
|
|
390
406
|
!tx.hasPublicCalls()
|
|
@@ -407,7 +423,7 @@ export class PublicProcessor implements Traceable {
|
|
|
407
423
|
},
|
|
408
424
|
);
|
|
409
425
|
|
|
410
|
-
return [processedTx, returnValues ?? []];
|
|
426
|
+
return [processedTx, returnValues ?? [], debugLogs];
|
|
411
427
|
}
|
|
412
428
|
|
|
413
429
|
private async doTreeInsertionsForPrivateOnlyTx(processedTx: ProcessedTx): Promise<void> {
|
|
@@ -441,10 +457,9 @@ export class PublicProcessor implements Traceable {
|
|
|
441
457
|
private async processTxWithinDeadline(
|
|
442
458
|
tx: Tx,
|
|
443
459
|
deadline: Date | undefined,
|
|
444
|
-
): Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined]> {
|
|
445
|
-
const innerProcessFn: () => Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined]> =
|
|
446
|
-
? () => this.processTxWithPublicCalls(tx)
|
|
447
|
-
: () => this.processPrivateOnlyTx(tx);
|
|
460
|
+
): Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined, DebugLog[]]> {
|
|
461
|
+
const innerProcessFn: () => Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined, DebugLog[]]> =
|
|
462
|
+
tx.hasPublicCalls() ? () => this.processTxWithPublicCalls(tx) : () => this.processPrivateOnlyTx(tx);
|
|
448
463
|
|
|
449
464
|
// Fake a delay per tx if instructed (used for tests)
|
|
450
465
|
const fakeDelayPerTxMs = this.opts.fakeProcessingDelayPerTxMs;
|
|
@@ -512,7 +527,7 @@ export class PublicProcessor implements Traceable {
|
|
|
512
527
|
@trackSpan('PublicProcessor.processPrivateOnlyTx', (tx: Tx) => ({
|
|
513
528
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
514
529
|
}))
|
|
515
|
-
private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx, undefined]> {
|
|
530
|
+
private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx, undefined, DebugLog[]]> {
|
|
516
531
|
const gasFees = this.globalVariables.gasFees;
|
|
517
532
|
const transactionFee = computeTransactionFee(gasFees, tx.data.constants.txContext.gasSettings, tx.data.gasUsed);
|
|
518
533
|
|
|
@@ -537,13 +552,13 @@ export class PublicProcessor implements Traceable {
|
|
|
537
552
|
|
|
538
553
|
await this.contractsDB.addNewContracts(tx);
|
|
539
554
|
|
|
540
|
-
return [processedTx, undefined];
|
|
555
|
+
return [processedTx, undefined, []];
|
|
541
556
|
}
|
|
542
557
|
|
|
543
558
|
@trackSpan('PublicProcessor.processTxWithPublicCalls', tx => ({
|
|
544
559
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
545
560
|
}))
|
|
546
|
-
private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> {
|
|
561
|
+
private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[], DebugLog[]]> {
|
|
547
562
|
const timer = new Timer();
|
|
548
563
|
|
|
549
564
|
const result = await this.publicTxSimulator.simulate(tx);
|
|
@@ -581,7 +596,7 @@ export class PublicProcessor implements Traceable {
|
|
|
581
596
|
revertReason,
|
|
582
597
|
);
|
|
583
598
|
|
|
584
|
-
return [processedTx, appLogicReturnValues];
|
|
599
|
+
return [processedTx, appLogicReturnValues, result.logs ?? []];
|
|
585
600
|
}
|
|
586
601
|
|
|
587
602
|
/**
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Logger, type LoggerBindings, createLogger
|
|
1
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import { sleep } from '@aztec/foundation/sleep';
|
|
3
3
|
import { type CancellationToken, avmSimulate, cancelSimulation, createCancellationToken } from '@aztec/native';
|
|
4
4
|
import { ProtocolContractsList } from '@aztec/protocol-contracts';
|
|
@@ -100,8 +100,7 @@ export class CppPublicTxSimulator extends PublicTxSimulator implements PublicTxS
|
|
|
100
100
|
inputBuffer,
|
|
101
101
|
contractProvider,
|
|
102
102
|
wsCppHandle,
|
|
103
|
-
|
|
104
|
-
// TODO: re-enable logging
|
|
103
|
+
this.log.level,
|
|
105
104
|
undefined,
|
|
106
105
|
this.cancellationToken,
|
|
107
106
|
);
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type Logger, type LoggerBindings, createLogger
|
|
1
|
+
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
2
2
|
import { avmSimulateWithHintedDbs } from '@aztec/native';
|
|
3
3
|
import {
|
|
4
4
|
AvmCircuitInputs,
|
|
@@ -75,7 +75,7 @@ export class CppPublicTxSimulatorHintedDbs extends PublicTxSimulator implements
|
|
|
75
75
|
|
|
76
76
|
let resultBuffer: Buffer;
|
|
77
77
|
try {
|
|
78
|
-
resultBuffer = await avmSimulateWithHintedDbs(inputBuffer,
|
|
78
|
+
resultBuffer = await avmSimulateWithHintedDbs(inputBuffer, this.log.level);
|
|
79
79
|
} catch (error: any) {
|
|
80
80
|
throw new SimulationError(`C++ hinted simulation failed: ${error.message}`, []);
|
|
81
81
|
}
|
|
@@ -19,10 +19,11 @@ export function createPublicTxSimulatorForBlockBuilding(
|
|
|
19
19
|
globalVariables: GlobalVariables,
|
|
20
20
|
telemetryClient: TelemetryClient,
|
|
21
21
|
bindings?: LoggerBindings,
|
|
22
|
+
collectDebugLogs = false,
|
|
22
23
|
) {
|
|
23
24
|
const config = PublicSimulatorConfig.from({
|
|
24
25
|
skipFeeEnforcement: false,
|
|
25
|
-
collectDebugLogs
|
|
26
|
+
collectDebugLogs,
|
|
26
27
|
collectHints: false,
|
|
27
28
|
collectPublicInputs: false,
|
|
28
29
|
collectStatistics: false,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { MAX_PROCESSABLE_L2_GAS } from '@aztec/constants';
|
|
2
2
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { ProtocolContractAddress, ProtocolContractsList } from '@aztec/protocol-contracts';
|
|
@@ -199,8 +199,8 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
|
|
|
199
199
|
|
|
200
200
|
// Such transactions should be filtered by GasTxValidator.
|
|
201
201
|
assert(
|
|
202
|
-
context.getActualGasUsed().l2Gas <=
|
|
203
|
-
`Transaction consumes ${context.getActualGasUsed().l2Gas} L2 gas, which exceeds the
|
|
202
|
+
context.getActualGasUsed().l2Gas <= MAX_PROCESSABLE_L2_GAS,
|
|
203
|
+
`Transaction consumes ${context.getActualGasUsed().l2Gas} L2 gas, which exceeds the maximum processable gas of ${MAX_PROCESSABLE_L2_GAS}`,
|
|
204
204
|
);
|
|
205
205
|
await this.payFee(context);
|
|
206
206
|
|