@aztec/simulator 0.0.1-commit.7b97ef96e → 0.0.1-commit.7cbc774
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/private/acvm_wasm.d.ts +1 -1
- package/dest/private/acvm_wasm.d.ts.map +1 -1
- package/dest/private/acvm_wasm.js +3 -1
- package/dest/private/circuit_recording/circuit_recorder.js +2 -2
- package/dest/public/avm/avm_simulator.js +1 -1
- package/dest/public/avm/calldata.d.ts +1 -1
- package/dest/public/avm/calldata.d.ts.map +1 -1
- package/dest/public/avm/calldata.js +3 -2
- package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts +2 -1
- package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -1
- package/dest/public/avm/fixtures/base_avm_simulation_tester.js +17 -2
- package/dest/public/avm/fixtures/utils.d.ts +1 -1
- package/dest/public/avm/fixtures/utils.d.ts.map +1 -1
- package/dest/public/avm/fixtures/utils.js +3 -0
- package/dest/public/avm/opcodes/contract.d.ts +3 -2
- package/dest/public/avm/opcodes/contract.d.ts.map +1 -1
- package/dest/public/avm/opcodes/contract.js +5 -1
- package/dest/public/avm/opcodes/ec_add.d.ts +2 -4
- package/dest/public/avm/opcodes/ec_add.d.ts.map +1 -1
- package/dest/public/avm/opcodes/ec_add.js +13 -27
- package/dest/public/contracts_db_checkpoint.d.ts +2 -2
- package/dest/public/contracts_db_checkpoint.d.ts.map +1 -1
- package/dest/public/contracts_db_checkpoint.js +1 -1
- package/dest/public/fixtures/bulk_test.d.ts +1 -1
- package/dest/public/fixtures/bulk_test.d.ts.map +1 -1
- package/dest/public/fixtures/bulk_test.js +31 -4
- package/dest/public/fixtures/custom_bytecode_tests.d.ts +3 -1
- package/dest/public/fixtures/custom_bytecode_tests.d.ts.map +1 -1
- package/dest/public/fixtures/custom_bytecode_tests.js +61 -1
- 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 +2 -10
- 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 +37 -10
- 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 +15 -16
- package/dest/public/hinting_db_sources.d.ts +4 -4
- package/dest/public/hinting_db_sources.d.ts.map +1 -1
- package/dest/public/hinting_db_sources.js +7 -6
- package/dest/public/public_db_sources.d.ts +6 -3
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +16 -10
- package/dest/public/public_processor/guarded_merkle_tree.d.ts +4 -4
- package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -1
- package/dest/public/public_processor/guarded_merkle_tree.js +4 -4
- package/dest/public/public_processor/public_processor.d.ts +8 -6
- package/dest/public/public_processor/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor.js +98 -69
- package/dest/public/public_processor/public_processor_metrics.d.ts +4 -1
- package/dest/public/public_processor/public_processor_metrics.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor_metrics.js +8 -0
- package/dest/public/public_tx_simulator/contract_provider_for_cpp.d.ts +1 -1
- package/dest/public/public_tx_simulator/contract_provider_for_cpp.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/contract_provider_for_cpp.js +3 -2
- 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_context.d.ts +7 -3
- package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.js +8 -10
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +6 -2
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.js +14 -9
- 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/acvm_wasm.ts +4 -1
- package/src/private/circuit_recording/circuit_recorder.ts +2 -2
- package/src/public/avm/avm_simulator.ts +1 -1
- package/src/public/avm/calldata.ts +3 -2
- package/src/public/avm/fixtures/base_avm_simulation_tester.ts +22 -2
- package/src/public/avm/fixtures/utils.ts +3 -0
- package/src/public/avm/opcodes/contract.ts +5 -1
- package/src/public/avm/opcodes/ec_add.ts +12 -31
- package/src/public/avm/opcodes/external_calls.ts +1 -1
- package/src/public/contracts_db_checkpoint.ts +1 -1
- package/src/public/fixtures/bulk_test.ts +29 -4
- package/src/public/fixtures/custom_bytecode_tests.ts +139 -1
- package/src/public/fixtures/opcode_spammer.ts +4 -8
- package/src/public/fixtures/public_tx_simulation_tester.ts +47 -6
- package/src/public/fixtures/utils.ts +22 -18
- package/src/public/hinting_db_sources.ts +9 -6
- package/src/public/public_db_sources.ts +21 -14
- package/src/public/public_processor/guarded_merkle_tree.ts +5 -5
- package/src/public/public_processor/public_processor.ts +124 -81
- package/src/public/public_processor/public_processor_metrics.ts +12 -0
- package/src/public/public_tx_simulator/contract_provider_for_cpp.ts +3 -2
- 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_context.ts +8 -10
- package/src/public/public_tx_simulator/public_tx_simulator.ts +14 -10
- package/src/public/test_executor_metrics.ts +24 -0
|
@@ -2,10 +2,8 @@ import {
|
|
|
2
2
|
CONTRACT_CLASS_PUBLISHED_MAGIC_VALUE,
|
|
3
3
|
CONTRACT_CLASS_REGISTRY_CONTRACT_ADDRESS,
|
|
4
4
|
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
DEFAULT_TEARDOWN_DA_GAS_LIMIT,
|
|
8
|
-
DEFAULT_TEARDOWN_L2_GAS_LIMIT,
|
|
5
|
+
MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT,
|
|
6
|
+
MAX_PROCESSABLE_L2_GAS,
|
|
9
7
|
PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
10
8
|
} from '@aztec/constants';
|
|
11
9
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
@@ -14,7 +12,13 @@ import { CONTRACT_INSTANCE_PUBLISHED_EVENT_TAG } from '@aztec/protocol-contracts
|
|
|
14
12
|
import { bufferAsFields } from '@aztec/stdlib/abi';
|
|
15
13
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
16
14
|
import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
17
|
-
import {
|
|
15
|
+
import {
|
|
16
|
+
FALLBACK_TEARDOWN_DA_GAS_LIMIT,
|
|
17
|
+
FALLBACK_TEARDOWN_L2_GAS_LIMIT,
|
|
18
|
+
Gas,
|
|
19
|
+
GasFees,
|
|
20
|
+
GasSettings,
|
|
21
|
+
} from '@aztec/stdlib/gas';
|
|
18
22
|
import { siloNullifier } from '@aztec/stdlib/hash';
|
|
19
23
|
import {
|
|
20
24
|
LogHash,
|
|
@@ -62,13 +66,14 @@ export async function createTxForPublicCalls(
|
|
|
62
66
|
feePayer = AztecAddress.zero(),
|
|
63
67
|
gasUsedByPrivate: Gas = Gas.empty(),
|
|
64
68
|
globals: GlobalVariables = GlobalVariables.empty(),
|
|
69
|
+
gasLimits?: Gas,
|
|
65
70
|
): Promise<Tx> {
|
|
66
71
|
assert(
|
|
67
72
|
setupCallRequests.length > 0 || appCallRequests.length > 0 || teardownCallRequest !== undefined,
|
|
68
73
|
"Can't create public tx with no enqueued calls",
|
|
69
74
|
);
|
|
70
75
|
// use max limits
|
|
71
|
-
|
|
76
|
+
gasLimits = gasLimits ?? new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
|
|
72
77
|
|
|
73
78
|
const forPublic = PartialPrivateTailPublicInputsForPublic.empty();
|
|
74
79
|
|
|
@@ -128,7 +133,7 @@ export async function createTxForPublicCalls(
|
|
|
128
133
|
|
|
129
134
|
const maxFeesPerGas = feePayer.isZero() ? GasFees.empty() : new GasFees(10, 10);
|
|
130
135
|
const teardownGasLimits = teardownCallRequest
|
|
131
|
-
? new Gas(
|
|
136
|
+
? new Gas(FALLBACK_TEARDOWN_DA_GAS_LIMIT, FALLBACK_TEARDOWN_L2_GAS_LIMIT)
|
|
132
137
|
: Gas.empty();
|
|
133
138
|
const gasSettings = new GasSettings(gasLimits, teardownGasLimits, maxFeesPerGas, GasFees.empty());
|
|
134
139
|
const txContext = new TxContext(Fr.zero(), Fr.zero(), gasSettings);
|
|
@@ -163,7 +168,7 @@ export async function createTxForPrivateOnly(
|
|
|
163
168
|
gasUsedByPrivate: Gas = new Gas(10, 10),
|
|
164
169
|
): Promise<Tx> {
|
|
165
170
|
// use max limits
|
|
166
|
-
const gasLimits = new Gas(
|
|
171
|
+
const gasLimits = new Gas(MAX_PROCESSABLE_DA_GAS_PER_CHECKPOINT, MAX_PROCESSABLE_L2_GAS);
|
|
167
172
|
|
|
168
173
|
const forRollup = PartialPrivateTailPublicInputsForRollup.empty();
|
|
169
174
|
|
|
@@ -228,17 +233,15 @@ export async function addNewContractInstanceToTx(
|
|
|
228
233
|
contractInstance: ContractInstanceWithAddress,
|
|
229
234
|
skipNullifierInsertion = false,
|
|
230
235
|
) {
|
|
231
|
-
//
|
|
232
|
-
// is not broadcast in such private logs
|
|
236
|
+
// Only ivpk_m is broadcast as a point (x, y); the other five keys are hashes.
|
|
233
237
|
const publicKeysAsFields = [
|
|
234
|
-
contractInstance.publicKeys.
|
|
235
|
-
contractInstance.publicKeys.
|
|
236
|
-
contractInstance.publicKeys.
|
|
237
|
-
contractInstance.publicKeys.
|
|
238
|
-
contractInstance.publicKeys.
|
|
239
|
-
contractInstance.publicKeys.
|
|
240
|
-
contractInstance.publicKeys.
|
|
241
|
-
contractInstance.publicKeys.masterTaggingPublicKey.y,
|
|
238
|
+
contractInstance.publicKeys.npkMHash,
|
|
239
|
+
contractInstance.publicKeys.ivpkM.x,
|
|
240
|
+
contractInstance.publicKeys.ivpkM.y,
|
|
241
|
+
contractInstance.publicKeys.ovpkMHash,
|
|
242
|
+
contractInstance.publicKeys.tpkMHash,
|
|
243
|
+
contractInstance.publicKeys.mspkMHash,
|
|
244
|
+
contractInstance.publicKeys.fbpkMHash,
|
|
242
245
|
];
|
|
243
246
|
const logFields = [
|
|
244
247
|
CONTRACT_INSTANCE_PUBLISHED_EVENT_TAG,
|
|
@@ -247,6 +250,7 @@ export async function addNewContractInstanceToTx(
|
|
|
247
250
|
new Fr(contractInstance.salt),
|
|
248
251
|
contractInstance.currentContractClassId,
|
|
249
252
|
contractInstance.initializationHash,
|
|
253
|
+
contractInstance.immutablesHash,
|
|
250
254
|
...publicKeysAsFields,
|
|
251
255
|
contractInstance.deployer.toField(),
|
|
252
256
|
];
|
|
@@ -83,6 +83,7 @@ export class HintingPublicContractsDB implements PublicContractsDBInterface {
|
|
|
83
83
|
instance.currentContractClassId,
|
|
84
84
|
instance.originalContractClassId,
|
|
85
85
|
instance.initializationHash,
|
|
86
|
+
instance.immutablesHash,
|
|
86
87
|
instance.publicKeys,
|
|
87
88
|
),
|
|
88
89
|
);
|
|
@@ -410,12 +411,12 @@ export class HintingMerkleWriteOperations implements MerkleTreeWriteOperations {
|
|
|
410
411
|
}
|
|
411
412
|
}
|
|
412
413
|
|
|
413
|
-
public async createCheckpoint(): Promise<
|
|
414
|
+
public async createCheckpoint(): Promise<number> {
|
|
414
415
|
const actionCounter = this.checkpointActionCounter++;
|
|
415
416
|
const oldCheckpointId = this.getCurrentCheckpointId();
|
|
416
417
|
const treesStateHash = await this.getTreesStateHash();
|
|
417
418
|
|
|
418
|
-
await this.db.createCheckpoint();
|
|
419
|
+
const depth = await this.db.createCheckpoint();
|
|
419
420
|
this.checkpointStack.push(this.nextCheckpointId++);
|
|
420
421
|
const newCheckpointId = this.getCurrentCheckpointId();
|
|
421
422
|
|
|
@@ -424,14 +425,16 @@ export class HintingMerkleWriteOperations implements MerkleTreeWriteOperations {
|
|
|
424
425
|
HintingMerkleWriteOperations.log.trace(
|
|
425
426
|
`[createCheckpoint:${actionCounter}] Checkpoint evolved ${oldCheckpointId} -> ${newCheckpointId} at trees state ${treesStateHash}.`,
|
|
426
427
|
);
|
|
428
|
+
|
|
429
|
+
return depth;
|
|
427
430
|
}
|
|
428
431
|
|
|
429
|
-
public
|
|
430
|
-
throw new Error('
|
|
432
|
+
public commitAllCheckpointsTo(_depth: number): Promise<void> {
|
|
433
|
+
throw new Error('commitAllCheckpointsTo is not supported in HintingMerkleWriteOperations.');
|
|
431
434
|
}
|
|
432
435
|
|
|
433
|
-
public
|
|
434
|
-
throw new Error('
|
|
436
|
+
public revertAllCheckpointsTo(_depth: number): Promise<void> {
|
|
437
|
+
throw new Error('revertAllCheckpointsTo is not supported in HintingMerkleWriteOperations.');
|
|
435
438
|
}
|
|
436
439
|
|
|
437
440
|
public async commitCheckpoint(): Promise<void> {
|
|
@@ -55,10 +55,11 @@ export class PublicContractsDB implements PublicContractsDBInterface {
|
|
|
55
55
|
this.log = createLogger('simulator:contracts-data-source', bindings);
|
|
56
56
|
}
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
/** Parses raw log data from the C++/NAPI bridge and inserts the resulting contracts into the current checkpoint. */
|
|
59
|
+
public addContractsFromLogs(contractDeploymentData: ContractDeploymentData): void {
|
|
59
60
|
const currentState = this.getCurrentState();
|
|
60
61
|
|
|
61
|
-
|
|
62
|
+
this.addContractClassesFromEvents(
|
|
62
63
|
ContractClassPublishedEvent.extractContractClassEvents(contractDeploymentData.getContractClassLogs()),
|
|
63
64
|
currentState,
|
|
64
65
|
);
|
|
@@ -69,10 +70,18 @@ export class PublicContractsDB implements PublicContractsDBInterface {
|
|
|
69
70
|
);
|
|
70
71
|
}
|
|
71
72
|
|
|
72
|
-
public
|
|
73
|
+
public addNewContracts(tx: Tx): void {
|
|
73
74
|
const contractDeploymentData = AllContractDeploymentData.fromTx(tx);
|
|
74
|
-
|
|
75
|
-
|
|
75
|
+
this.addContractsFromLogs(contractDeploymentData.getNonRevertibleContractDeploymentData());
|
|
76
|
+
this.addContractsFromLogs(contractDeploymentData.getRevertibleContractDeploymentData());
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
/** Inserts typed contract instances directly into the current checkpoint. */
|
|
80
|
+
public addContracts(contractInstances?: ContractInstanceWithAddress[]): void {
|
|
81
|
+
const currentState = this.getCurrentState();
|
|
82
|
+
for (const instance of contractInstances ?? []) {
|
|
83
|
+
currentState.addInstance(instance.address, instance);
|
|
84
|
+
}
|
|
76
85
|
}
|
|
77
86
|
|
|
78
87
|
/**
|
|
@@ -81,7 +90,7 @@ export class PublicContractsDB implements PublicContractsDBInterface {
|
|
|
81
90
|
*/
|
|
82
91
|
public createCheckpoint(): void {
|
|
83
92
|
const currentState = this.getCurrentState();
|
|
84
|
-
const newState = currentState.
|
|
93
|
+
const newState = currentState.fork();
|
|
85
94
|
this.contractStateStack.push(newState);
|
|
86
95
|
}
|
|
87
96
|
|
|
@@ -174,17 +183,15 @@ export class PublicContractsDB implements PublicContractsDBInterface {
|
|
|
174
183
|
return await this.dataSource.getDebugFunctionName(address, selector);
|
|
175
184
|
}
|
|
176
185
|
|
|
177
|
-
private
|
|
186
|
+
private addContractClassesFromEvents(
|
|
178
187
|
contractClassEvents: ContractClassPublishedEvent[],
|
|
179
188
|
state: ContractsDbCheckpoint,
|
|
180
189
|
) {
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}),
|
|
187
|
-
);
|
|
190
|
+
for (const event of contractClassEvents) {
|
|
191
|
+
this.log.debug(`Adding class ${event.contractClassId.toString()} to contract state`);
|
|
192
|
+
const contractClass = event.toContractClassPublic();
|
|
193
|
+
state.addClass(event.contractClassId, contractClass);
|
|
194
|
+
}
|
|
188
195
|
}
|
|
189
196
|
|
|
190
197
|
private addContractInstancesFromEvents(
|
|
@@ -134,7 +134,7 @@ export class GuardedMerkleTreeOperations implements MerkleTreeWriteOperations {
|
|
|
134
134
|
): Promise<(BlockNumber | undefined)[]> {
|
|
135
135
|
return this.guardAndPush(() => this.target.getBlockNumbersForLeafIndices(treeId, leafIndices));
|
|
136
136
|
}
|
|
137
|
-
createCheckpoint(): Promise<
|
|
137
|
+
createCheckpoint(): Promise<number> {
|
|
138
138
|
return this.guardAndPush(() => this.target.createCheckpoint());
|
|
139
139
|
}
|
|
140
140
|
commitCheckpoint(): Promise<void> {
|
|
@@ -143,11 +143,11 @@ export class GuardedMerkleTreeOperations implements MerkleTreeWriteOperations {
|
|
|
143
143
|
revertCheckpoint(): Promise<void> {
|
|
144
144
|
return this.guardAndPush(() => this.target.revertCheckpoint());
|
|
145
145
|
}
|
|
146
|
-
|
|
147
|
-
return this.guardAndPush(() => this.target.
|
|
146
|
+
commitAllCheckpointsTo(depth: number): Promise<void> {
|
|
147
|
+
return this.guardAndPush(() => this.target.commitAllCheckpointsTo(depth));
|
|
148
148
|
}
|
|
149
|
-
|
|
150
|
-
return this.guardAndPush(() => this.target.
|
|
149
|
+
revertAllCheckpointsTo(depth: number): Promise<void> {
|
|
150
|
+
return this.guardAndPush(() => this.target.revertAllCheckpointsTo(depth));
|
|
151
151
|
}
|
|
152
152
|
findSiblingPaths<ID extends MerkleTreeId>(
|
|
153
153
|
treeId: ID,
|
|
@@ -3,7 +3,7 @@ import { padArrayEnd } from '@aztec/foundation/collection';
|
|
|
3
3
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import { sleep } from '@aztec/foundation/sleep';
|
|
6
|
-
import { DateProvider, Timer, elapsed,
|
|
6
|
+
import { DateProvider, Timer, elapsed, execWithSignal } from '@aztec/foundation/timer';
|
|
7
7
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
8
8
|
import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
|
|
9
9
|
import { computeFeePayerBalanceLeafSlot, computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
@@ -25,7 +25,7 @@ import type {
|
|
|
25
25
|
PublicProcessorValidator,
|
|
26
26
|
SequencerConfig,
|
|
27
27
|
} from '@aztec/stdlib/interfaces/server';
|
|
28
|
-
import type
|
|
28
|
+
import { type DebugLog, type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
29
29
|
import { ProvingRequestType } from '@aztec/stdlib/proofs';
|
|
30
30
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
31
31
|
import {
|
|
@@ -76,17 +76,15 @@ export class PublicProcessorFactory {
|
|
|
76
76
|
/**
|
|
77
77
|
* Creates a new instance of a PublicProcessor.
|
|
78
78
|
* @param globalVariables - The global variables for the block being processed.
|
|
79
|
-
* @param
|
|
79
|
+
* @param contractsDB - Optional pre-populated contracts DB; a fresh one is constructed if omitted.
|
|
80
80
|
* @returns A new instance of a PublicProcessor.
|
|
81
81
|
*/
|
|
82
82
|
public create(
|
|
83
83
|
merkleTree: MerkleTreeWriteOperations,
|
|
84
84
|
globalVariables: GlobalVariables,
|
|
85
85
|
config: PublicSimulatorConfig,
|
|
86
|
+
contractsDB: PublicContractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings()),
|
|
86
87
|
): PublicProcessor {
|
|
87
|
-
const bindings = this.log.getBindings();
|
|
88
|
-
const contractsDB = new PublicContractsDB(this.contractDataSource, bindings);
|
|
89
|
-
|
|
90
88
|
const guardedFork = new GuardedMerkleTreeOperations(merkleTree);
|
|
91
89
|
const publicTxSimulator = this.createPublicTxSimulator(guardedFork, contractsDB, globalVariables, config);
|
|
92
90
|
|
|
@@ -97,7 +95,7 @@ export class PublicProcessorFactory {
|
|
|
97
95
|
publicTxSimulator,
|
|
98
96
|
this.dateProvider,
|
|
99
97
|
this.telemetryClient,
|
|
100
|
-
createLogger('simulator:public-processor',
|
|
98
|
+
createLogger('simulator:public-processor', this.log.getBindings()),
|
|
101
99
|
);
|
|
102
100
|
}
|
|
103
101
|
|
|
@@ -125,6 +123,17 @@ class PublicProcessorTimeoutError extends Error {
|
|
|
125
123
|
}
|
|
126
124
|
}
|
|
127
125
|
|
|
126
|
+
class PublicProcessorAbortError extends Error {
|
|
127
|
+
constructor(message: string = 'Aborted while processing tx') {
|
|
128
|
+
super(message);
|
|
129
|
+
this.name = 'PublicProcessorAbortError';
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function isPublicProcessorInterruptError(err: any) {
|
|
134
|
+
return err?.name === 'PublicProcessorTimeoutError' || err?.name === 'PublicProcessorAbortError';
|
|
135
|
+
}
|
|
136
|
+
|
|
128
137
|
/**
|
|
129
138
|
* Converts Txs lifted from the P2P module into ProcessedTx objects by executing
|
|
130
139
|
* any public function calls in them. Txs with private calls only are unaffected.
|
|
@@ -140,6 +149,7 @@ export class PublicProcessor implements Traceable {
|
|
|
140
149
|
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
141
150
|
private log: Logger,
|
|
142
151
|
private opts: Pick<SequencerConfig, 'fakeProcessingDelayPerTxMs' | 'fakeThrowAfterProcessingTxCount'> = {},
|
|
152
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
143
153
|
) {
|
|
144
154
|
this.metrics = new PublicProcessorMetrics(telemetryClient, 'PublicProcessor');
|
|
145
155
|
}
|
|
@@ -159,8 +169,8 @@ export class PublicProcessor implements Traceable {
|
|
|
159
169
|
txs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
160
170
|
limits: PublicProcessorLimits = {},
|
|
161
171
|
validator: PublicProcessorValidator = {},
|
|
162
|
-
): Promise<[ProcessedTx[], FailedTx[], Tx[], NestedProcessReturnValues[],
|
|
163
|
-
const { maxTransactions,
|
|
172
|
+
): Promise<[ProcessedTx[], FailedTx[], Tx[], NestedProcessReturnValues[], DebugLog[]]> {
|
|
173
|
+
const { maxTransactions, deadline, maxBlockGas, maxBlobFields, isBuildingProposal, signal } = limits;
|
|
164
174
|
const { preprocessValidator, nullifierCache } = validator;
|
|
165
175
|
const result: ProcessedTx[] = [];
|
|
166
176
|
const usedTxs: Tx[] = [];
|
|
@@ -173,6 +183,8 @@ export class PublicProcessor implements Traceable {
|
|
|
173
183
|
let totalPublicGas = new Gas(0, 0);
|
|
174
184
|
let totalBlockGas = new Gas(0, 0);
|
|
175
185
|
let totalBlobFields = 0;
|
|
186
|
+
let silentlySkippedCount = 0;
|
|
187
|
+
let totalSilentlySkippedDurationMs = 0;
|
|
176
188
|
|
|
177
189
|
for await (const tx of txs) {
|
|
178
190
|
// Only process up to the max tx limit
|
|
@@ -181,28 +193,33 @@ export class PublicProcessor implements Traceable {
|
|
|
181
193
|
break;
|
|
182
194
|
}
|
|
183
195
|
|
|
184
|
-
// Bail if we've hit the deadline
|
|
196
|
+
// Bail if we've hit the deadline or have been interrupted.
|
|
185
197
|
if (deadline && this.dateProvider.now() > +deadline) {
|
|
186
198
|
this.log.warn(`Stopping tx processing due to timeout.`);
|
|
187
199
|
break;
|
|
188
200
|
}
|
|
201
|
+
if (signal?.aborted) {
|
|
202
|
+
this.log.warn(`Stopping tx processing due to abort signal.`);
|
|
203
|
+
break;
|
|
204
|
+
}
|
|
189
205
|
|
|
190
|
-
// Skip this tx if it'd exceed max block size
|
|
191
206
|
const txHash = tx.getTxHash().toString();
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
207
|
+
|
|
208
|
+
// Skip this tx if its estimated blob fields would exceed the limit.
|
|
209
|
+
// Only done during proposal building: during re-execution we must process the exact txs from the proposal.
|
|
210
|
+
const txBlobFields = tx.getPrivateTxEffectsSizeInFields();
|
|
211
|
+
if (isBuildingProposal && maxBlobFields !== undefined && totalBlobFields + txBlobFields > maxBlobFields) {
|
|
212
|
+
this.log.warn(
|
|
213
|
+
`Skipping tx ${txHash} with ${txBlobFields} fields from private side effects due to blob fields limit`,
|
|
214
|
+
{ txHash, txBlobFields, totalBlobFields, maxBlobFields },
|
|
215
|
+
);
|
|
200
216
|
continue;
|
|
201
217
|
}
|
|
202
218
|
|
|
203
|
-
// Skip this tx if its gas limit would exceed the block gas limit
|
|
219
|
+
// Skip this tx if its gas limit would exceed the block gas limit (either da or l2).
|
|
220
|
+
// Only done during proposal building: during re-execution we must process the exact txs from the proposal.
|
|
204
221
|
const txGasLimit = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
205
|
-
if (maxBlockGas !== undefined && totalBlockGas.add(txGasLimit).gtAny(maxBlockGas)) {
|
|
222
|
+
if (isBuildingProposal && maxBlockGas !== undefined && totalBlockGas.add(txGasLimit).gtAny(maxBlockGas)) {
|
|
206
223
|
this.log.warn(`Skipping processing of tx ${txHash} due to block gas limit`, {
|
|
207
224
|
txHash,
|
|
208
225
|
txGasLimit,
|
|
@@ -222,11 +239,6 @@ export class PublicProcessor implements Traceable {
|
|
|
222
239
|
failed.push({ tx, error: new Error(`Tx failed preprocess validation: ${reason}`) });
|
|
223
240
|
returns.push(new NestedProcessReturnValues([]));
|
|
224
241
|
continue;
|
|
225
|
-
} else if (result.result === 'skipped') {
|
|
226
|
-
const reason = result.reason.join(', ');
|
|
227
|
-
this.log.debug(`Skipping tx ${txHash.toString()} due to pre-process validation: ${reason}`);
|
|
228
|
-
returns.push(new NestedProcessReturnValues([]));
|
|
229
|
-
continue;
|
|
230
242
|
} else {
|
|
231
243
|
this.log.trace(`Tx ${txHash.toString()} is valid before processing.`);
|
|
232
244
|
}
|
|
@@ -242,7 +254,9 @@ export class PublicProcessor implements Traceable {
|
|
|
242
254
|
this.contractsDB.createCheckpoint();
|
|
243
255
|
|
|
244
256
|
try {
|
|
245
|
-
const [processedTx, returnValues, txDebugLogs] = await
|
|
257
|
+
const [txProcessingTimeMs, [processedTx, returnValues, txDebugLogs]] = await elapsed(() =>
|
|
258
|
+
this.processTx(tx, deadline, signal),
|
|
259
|
+
);
|
|
246
260
|
|
|
247
261
|
// Inject a fake processing failure after N txs if requested
|
|
248
262
|
const fakeThrowAfter = this.opts.fakeThrowAfterProcessingTxCount;
|
|
@@ -251,23 +265,9 @@ export class PublicProcessor implements Traceable {
|
|
|
251
265
|
}
|
|
252
266
|
|
|
253
267
|
const txBlobFields = processedTx.txEffect.getNumBlobFields();
|
|
254
|
-
|
|
255
|
-
// If the actual size of this tx would exceed block size, skip it
|
|
256
268
|
const txSize = txBlobFields * Fr.SIZE_IN_BYTES;
|
|
257
|
-
if (maxBlockSize !== undefined && totalSizeInBytes + txSize > maxBlockSize) {
|
|
258
|
-
this.log.debug(`Skipping processed tx ${txHash} sized ${txSize} due to max block size.`, {
|
|
259
|
-
txHash,
|
|
260
|
-
sizeInBytes: txSize,
|
|
261
|
-
totalSizeInBytes,
|
|
262
|
-
maxBlockSize,
|
|
263
|
-
});
|
|
264
|
-
// Need to revert the checkpoint here and don't go any further
|
|
265
|
-
await checkpoint.revert();
|
|
266
|
-
this.contractsDB.revertCheckpoint();
|
|
267
|
-
continue;
|
|
268
|
-
}
|
|
269
269
|
|
|
270
|
-
// If the actual blob fields of this tx would exceed the limit, skip it
|
|
270
|
+
// If the actual blob fields of this tx would exceed the limit, skip it.
|
|
271
271
|
// Note: maxBlobFields already accounts for block end blob fields and previous blocks in checkpoint.
|
|
272
272
|
if (maxBlobFields !== undefined && totalBlobFields + txBlobFields > maxBlobFields) {
|
|
273
273
|
this.log.debug(
|
|
@@ -277,14 +277,37 @@ export class PublicProcessor implements Traceable {
|
|
|
277
277
|
txBlobFields,
|
|
278
278
|
totalBlobFields,
|
|
279
279
|
maxBlobFields,
|
|
280
|
+
txProcessingTimeMs,
|
|
280
281
|
},
|
|
281
282
|
);
|
|
283
|
+
silentlySkippedCount += 1;
|
|
284
|
+
totalSilentlySkippedDurationMs += txProcessingTimeMs;
|
|
285
|
+
this.metrics.recordSilentlySkipped(txProcessingTimeMs);
|
|
282
286
|
// Need to revert the checkpoint here and don't go any further
|
|
283
287
|
await checkpoint.revert();
|
|
284
288
|
this.contractsDB.revertCheckpoint();
|
|
285
289
|
continue;
|
|
286
290
|
}
|
|
287
291
|
|
|
292
|
+
// During re-execution, check if the actual gas used by this tx would push the block over the gas limit.
|
|
293
|
+
// Unlike the proposal-building check (which uses declared gas limits pessimistically before processing),
|
|
294
|
+
// this uses actual gas and stops processing when the limit is exceeded.
|
|
295
|
+
if (
|
|
296
|
+
!isBuildingProposal &&
|
|
297
|
+
maxBlockGas !== undefined &&
|
|
298
|
+
totalBlockGas.add(processedTx.gasUsed.totalGas).gtAny(maxBlockGas)
|
|
299
|
+
) {
|
|
300
|
+
this.log.warn(`Stopping re-execution since tx ${txHash} would push block gas over limit`, {
|
|
301
|
+
txHash,
|
|
302
|
+
txGas: processedTx.gasUsed.totalGas,
|
|
303
|
+
totalBlockGas,
|
|
304
|
+
maxBlockGas,
|
|
305
|
+
});
|
|
306
|
+
await checkpoint.revert();
|
|
307
|
+
this.contractsDB.revertCheckpoint();
|
|
308
|
+
break;
|
|
309
|
+
}
|
|
310
|
+
|
|
288
311
|
// FIXME(fcarreiro): it's ugly to have to notify the validator of nullifiers.
|
|
289
312
|
// I'd rather pass the validators the processedTx as well and let them deal with it.
|
|
290
313
|
nullifierCache?.addNullifiers(processedTx.txEffect.nullifiers.map(n => n.toBuffer()));
|
|
@@ -293,20 +316,21 @@ export class PublicProcessor implements Traceable {
|
|
|
293
316
|
returns = returns.concat(returnValues);
|
|
294
317
|
debugLogs.push(...txDebugLogs);
|
|
295
318
|
|
|
319
|
+
this.debugLogStore.storeLogs(processedTx.hash.toString(), txDebugLogs);
|
|
320
|
+
|
|
296
321
|
totalPublicGas = totalPublicGas.add(processedTx.gasUsed.publicGas);
|
|
297
322
|
totalBlockGas = totalBlockGas.add(processedTx.gasUsed.totalGas);
|
|
298
323
|
totalSizeInBytes += txSize;
|
|
299
324
|
totalBlobFields += txBlobFields;
|
|
325
|
+
|
|
326
|
+
// Commit the tx-level contracts checkpoint on success
|
|
327
|
+
this.contractsDB.commitCheckpoint();
|
|
300
328
|
} catch (err: any) {
|
|
301
|
-
if (err
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
//
|
|
305
|
-
// Signal cancellation AND WAIT for the simulation to actually stop.
|
|
306
|
-
// This is critical because C++ might be in the middle of a slow operation (e.g., pad_trees)
|
|
307
|
-
// and won't check the cancellation flag until that operation completes.
|
|
308
|
-
// Without waiting, we'd proceed to revert checkpoints while C++ is still writing to state.
|
|
309
|
-
// Wait for C++ to stop gracefully.
|
|
329
|
+
if (isPublicProcessorInterruptError(err)) {
|
|
330
|
+
const interruptReason = err.name === 'PublicProcessorTimeoutError' ? 'timeout' : 'abort signal';
|
|
331
|
+
this.log.warn(`Stopping tx processing due to ${interruptReason}.`);
|
|
332
|
+
// The tx may still be executing on a worker thread (C++ via NAPI).
|
|
333
|
+
// Signal cancellation AND WAIT for the simulation to actually stop before touching fork checkpoints.
|
|
310
334
|
await this.publicTxSimulator.cancel?.();
|
|
311
335
|
|
|
312
336
|
// Now stop the guarded fork to prevent any further TS-side access to the world state.
|
|
@@ -316,14 +340,10 @@ export class PublicProcessor implements Traceable {
|
|
|
316
340
|
// 1. At least one outstanding checkpoint that has not been committed (the one created before we processed the tx).
|
|
317
341
|
// 2. Possible state updates on that checkpoint or any others created during execution.
|
|
318
342
|
|
|
319
|
-
//
|
|
320
|
-
//
|
|
321
|
-
//
|
|
322
|
-
await checkpoint.
|
|
323
|
-
|
|
324
|
-
// Now we want to revert any/all remaining checkpoints, destroying any outstanding state updates.
|
|
325
|
-
// This needs to be done directly on the underlying fork as the guarded fork has been stopped.
|
|
326
|
-
await this.guardedMerkleTree.getUnderlyingFork().revertAllCheckpoints();
|
|
343
|
+
// Revert all checkpoints at or above this checkpoint's depth (inclusive), destroying any outstanding state
|
|
344
|
+
// updates from this tx and any nested checkpoints created during execution. This preserves any checkpoints
|
|
345
|
+
// created by callers below our depth.
|
|
346
|
+
await checkpoint.revertToCheckpoint();
|
|
327
347
|
|
|
328
348
|
// Revert any contracts added to the DB for the tx.
|
|
329
349
|
this.contractsDB.revertCheckpoint();
|
|
@@ -335,9 +355,9 @@ export class PublicProcessor implements Traceable {
|
|
|
335
355
|
break;
|
|
336
356
|
}
|
|
337
357
|
|
|
338
|
-
// Roll back state to start of TX before proceeding to next TX
|
|
339
|
-
|
|
340
|
-
await
|
|
358
|
+
// Roll back state to start of TX before proceeding to next TX.
|
|
359
|
+
// Reverts all checkpoints at or above this checkpoint's depth, preserving any caller checkpoints below.
|
|
360
|
+
await checkpoint.revertToCheckpoint();
|
|
341
361
|
this.contractsDB.revertCheckpoint();
|
|
342
362
|
const errorMessage = err instanceof Error || err instanceof AssertionError ? err.message : 'Unknown error';
|
|
343
363
|
this.log.warn(`Failed to process tx ${txHash.toString()}: ${errorMessage} ${err?.stack}`);
|
|
@@ -349,7 +369,6 @@ export class PublicProcessor implements Traceable {
|
|
|
349
369
|
} finally {
|
|
350
370
|
// Base case is we always commit the checkpoint. Using the ForkCheckpoint means this has no effect if the tx was previously reverted
|
|
351
371
|
await checkpoint.commit();
|
|
352
|
-
this.contractsDB.commitCheckpointOkIfNone();
|
|
353
372
|
}
|
|
354
373
|
}
|
|
355
374
|
|
|
@@ -357,15 +376,26 @@ export class PublicProcessor implements Traceable {
|
|
|
357
376
|
const rate = duration > 0 ? totalPublicGas.l2Gas / duration : 0;
|
|
358
377
|
this.metrics.recordAllTxs(totalPublicGas, rate);
|
|
359
378
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
379
|
+
const silentlySkippedDurationMs = Math.round(totalSilentlySkippedDurationMs);
|
|
380
|
+
this.log.info(
|
|
381
|
+
`Processed ${result.length} successful txs and ${failed.length} failed txs ` +
|
|
382
|
+
`(${silentlySkippedCount} silently skipped, ${silentlySkippedDurationMs}ms wasted) ` +
|
|
383
|
+
`in ${duration}s`,
|
|
384
|
+
{
|
|
385
|
+
blockNumber: this.globalVariables.blockNumber,
|
|
386
|
+
successfulCount: result.length,
|
|
387
|
+
failedCount: failed.length,
|
|
388
|
+
duration,
|
|
389
|
+
rate,
|
|
390
|
+
totalPublicGas,
|
|
391
|
+
totalBlockGas,
|
|
392
|
+
totalSizeInBytes,
|
|
393
|
+
silentlySkippedCount,
|
|
394
|
+
silentlySkippedDurationMs,
|
|
395
|
+
},
|
|
396
|
+
);
|
|
367
397
|
|
|
368
|
-
return [result, failed, usedTxs, returns,
|
|
398
|
+
return [result, failed, usedTxs, returns, debugLogs];
|
|
369
399
|
}
|
|
370
400
|
|
|
371
401
|
private async checkWorldStateUnchanged(
|
|
@@ -388,9 +418,10 @@ export class PublicProcessor implements Traceable {
|
|
|
388
418
|
private async processTx(
|
|
389
419
|
tx: Tx,
|
|
390
420
|
deadline: Date | undefined,
|
|
421
|
+
signal: AbortSignal | undefined,
|
|
391
422
|
): Promise<[ProcessedTx, NestedProcessReturnValues[], DebugLog[]]> {
|
|
392
423
|
const [time, [processedTx, returnValues, debugLogs]] = await elapsed(() =>
|
|
393
|
-
this.processTxWithinDeadline(tx, deadline),
|
|
424
|
+
this.processTxWithinDeadline(tx, deadline, signal),
|
|
394
425
|
);
|
|
395
426
|
|
|
396
427
|
this.log.verbose(
|
|
@@ -444,10 +475,11 @@ export class PublicProcessor implements Traceable {
|
|
|
444
475
|
this.metrics.recordTreeInsertions(Number(treeInsertionEnd - treeInsertionStart) / 1_000);
|
|
445
476
|
}
|
|
446
477
|
|
|
447
|
-
/** Processes the given tx within deadline
|
|
478
|
+
/** Processes the given tx within deadline or until the signal is aborted. */
|
|
448
479
|
private async processTxWithinDeadline(
|
|
449
480
|
tx: Tx,
|
|
450
481
|
deadline: Date | undefined,
|
|
482
|
+
signal: AbortSignal | undefined,
|
|
451
483
|
): Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined, DebugLog[]]> {
|
|
452
484
|
const innerProcessFn: () => Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined, DebugLog[]]> =
|
|
453
485
|
tx.hasPublicCalls() ? () => this.processTxWithPublicCalls(tx) : () => this.processPrivateOnlyTx(tx);
|
|
@@ -464,27 +496,38 @@ export class PublicProcessor implements Traceable {
|
|
|
464
496
|
}
|
|
465
497
|
: innerProcessFn;
|
|
466
498
|
|
|
467
|
-
|
|
499
|
+
const processingSignal = this.getProcessingSignal(tx, deadline, signal);
|
|
500
|
+
if (!processingSignal) {
|
|
468
501
|
return await processFn();
|
|
469
502
|
}
|
|
470
503
|
|
|
471
|
-
|
|
504
|
+
return await execWithSignal(
|
|
505
|
+
() => processFn(),
|
|
506
|
+
processingSignal,
|
|
507
|
+
signal =>
|
|
508
|
+
signal.reason?.name === 'TimeoutError' ? new PublicProcessorTimeoutError() : new PublicProcessorAbortError(),
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
private getProcessingSignal(tx: Tx, deadline: Date | undefined, signal: AbortSignal | undefined) {
|
|
513
|
+
if (!deadline) {
|
|
514
|
+
return signal;
|
|
515
|
+
}
|
|
516
|
+
|
|
472
517
|
const timeout = +deadline - this.dateProvider.now();
|
|
473
518
|
if (timeout <= 0) {
|
|
474
519
|
throw new PublicProcessorTimeoutError();
|
|
475
520
|
}
|
|
476
521
|
|
|
522
|
+
const txHash = tx.getTxHash();
|
|
477
523
|
this.log.debug(`Processing tx ${txHash.toString()} within ${timeout}ms`, {
|
|
478
524
|
deadline: deadline.toISOString(),
|
|
479
525
|
now: new Date(this.dateProvider.now()).toISOString(),
|
|
480
526
|
txHash,
|
|
481
527
|
});
|
|
482
528
|
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
timeout,
|
|
486
|
-
() => new PublicProcessorTimeoutError(),
|
|
487
|
-
);
|
|
529
|
+
const timeoutSignal = AbortSignal.timeout(timeout);
|
|
530
|
+
return signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
488
531
|
}
|
|
489
532
|
|
|
490
533
|
/**
|
|
@@ -541,7 +584,7 @@ export class PublicProcessor implements Traceable {
|
|
|
541
584
|
// Fee payment insertion has already been done. Do the rest.
|
|
542
585
|
await this.doTreeInsertionsForPrivateOnlyTx(processedTx);
|
|
543
586
|
|
|
544
|
-
|
|
587
|
+
this.contractsDB.addNewContracts(tx);
|
|
545
588
|
|
|
546
589
|
return [processedTx, undefined, []];
|
|
547
590
|
}
|