@aztec/simulator 0.0.1-commit.f2ce05ee → 0.0.1-commit.f5a9928
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/client.d.ts +1 -3
- package/dest/client.d.ts.map +1 -1
- package/dest/client.js +0 -2
- 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.d.ts +36 -23
- package/dest/private/circuit_recording/circuit_recorder.d.ts.map +1 -1
- package/dest/private/circuit_recording/circuit_recorder.js +65 -69
- package/dest/private/circuit_recording/file_circuit_recorder.d.ts +7 -19
- package/dest/private/circuit_recording/file_circuit_recorder.d.ts.map +1 -1
- package/dest/private/circuit_recording/file_circuit_recorder.js +38 -42
- package/dest/private/circuit_recording/simulator_recorder_wrapper.d.ts +1 -1
- package/dest/private/circuit_recording/simulator_recorder_wrapper.d.ts.map +1 -1
- package/dest/private/circuit_recording/simulator_recorder_wrapper.js +11 -14
- package/dest/public/avm/avm_gas.js +3 -3
- 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 +18 -3
- 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 +4 -1
- 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/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/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/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/amm_test.js +4 -4
- 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 +33 -6
- package/dest/public/fixtures/custom_bytecode_tester.d.ts +1 -1
- package/dest/public/fixtures/custom_bytecode_tester.d.ts.map +1 -1
- package/dest/public/fixtures/custom_bytecode_tester.js +2 -2
- package/dest/public/fixtures/custom_bytecode_tests.d.ts +8 -1
- package/dest/public/fixtures/custom_bytecode_tests.d.ts.map +1 -1
- package/dest/public/fixtures/custom_bytecode_tests.js +91 -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 +8 -16
- 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 +38 -9
- package/dest/public/fixtures/token_test.js +3 -3
- 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 +21 -20
- package/dest/public/hinting_db_sources.d.ts +5 -5
- package/dest/public/hinting_db_sources.d.ts.map +1 -1
- package/dest/public/hinting_db_sources.js +8 -7
- 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 +5 -5
- package/dest/public/public_processor/guarded_merkle_tree.d.ts.map +1 -1
- package/dest/public/public_processor/guarded_merkle_tree.js +5 -5
- package/dest/public/public_processor/public_processor.d.ts +8 -5
- package/dest/public/public_processor/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor/public_processor.js +121 -67
- 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 +5 -4
- 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/state_manager/state_manager.js +1 -1
- 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/client.ts +0 -2
- package/src/private/acvm_wasm.ts +4 -1
- package/src/private/circuit_recording/circuit_recorder.ts +84 -78
- package/src/private/circuit_recording/file_circuit_recorder.ts +38 -48
- package/src/private/circuit_recording/simulator_recorder_wrapper.ts +9 -15
- package/src/public/avm/avm_gas.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 +23 -3
- package/src/public/avm/fixtures/utils.ts +4 -1
- package/src/public/avm/opcodes/accrued_substate.ts +3 -4
- 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/avm/serialization/bytecode_serialization.ts +2 -2
- package/src/public/avm/serialization/instruction_serialization.ts +1 -1
- package/src/public/contracts_db_checkpoint.ts +1 -1
- package/src/public/fixtures/amm_test.ts +4 -4
- package/src/public/fixtures/bulk_test.ts +31 -6
- package/src/public/fixtures/custom_bytecode_tester.ts +2 -2
- package/src/public/fixtures/custom_bytecode_tests.ts +209 -2
- package/src/public/fixtures/opcode_spammer.ts +10 -18
- package/src/public/fixtures/public_tx_simulation_tester.ts +45 -5
- package/src/public/fixtures/token_test.ts +3 -3
- package/src/public/fixtures/utils.ts +23 -24
- package/src/public/fuzzing/avm_fuzzer_simulator.ts +1 -1
- package/src/public/hinting_db_sources.ts +10 -7
- package/src/public/public_db_sources.ts +21 -14
- package/src/public/public_processor/guarded_merkle_tree.ts +6 -6
- package/src/public/public_processor/public_processor.ts +158 -88
- package/src/public/public_processor/public_processor_metrics.ts +12 -0
- package/src/public/public_tx_simulator/contract_provider_for_cpp.ts +5 -4
- 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/state_manager/state_manager.ts +1 -1
- package/src/public/test_executor_metrics.ts +24 -0
|
@@ -1,9 +1,14 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
3
|
+
MAX_NULLIFIERS_PER_TX,
|
|
4
|
+
MAX_TX_BLOB_DATA_SIZE_IN_FIELDS,
|
|
5
|
+
NULLIFIER_SUBTREE_HEIGHT,
|
|
6
|
+
} from '@aztec/constants';
|
|
2
7
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
3
8
|
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
9
|
import { type Logger, type LoggerBindings, createLogger } from '@aztec/foundation/log';
|
|
5
10
|
import { sleep } from '@aztec/foundation/sleep';
|
|
6
|
-
import { DateProvider, Timer, elapsed,
|
|
11
|
+
import { DateProvider, Timer, elapsed, execWithSignal } from '@aztec/foundation/timer';
|
|
7
12
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
8
13
|
import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
|
|
9
14
|
import { computeFeePayerBalanceLeafSlot, computeFeePayerBalanceStorageSlot } from '@aztec/protocol-contracts/fee-juice';
|
|
@@ -25,6 +30,7 @@ import type {
|
|
|
25
30
|
PublicProcessorValidator,
|
|
26
31
|
SequencerConfig,
|
|
27
32
|
} from '@aztec/stdlib/interfaces/server';
|
|
33
|
+
import { type DebugLog, type DebugLogStore, NullDebugLogStore } from '@aztec/stdlib/logs';
|
|
28
34
|
import { ProvingRequestType } from '@aztec/stdlib/proofs';
|
|
29
35
|
import { MerkleTreeId } from '@aztec/stdlib/trees';
|
|
30
36
|
import {
|
|
@@ -75,17 +81,15 @@ export class PublicProcessorFactory {
|
|
|
75
81
|
/**
|
|
76
82
|
* Creates a new instance of a PublicProcessor.
|
|
77
83
|
* @param globalVariables - The global variables for the block being processed.
|
|
78
|
-
* @param
|
|
84
|
+
* @param contractsDB - Optional pre-populated contracts DB; a fresh one is constructed if omitted.
|
|
79
85
|
* @returns A new instance of a PublicProcessor.
|
|
80
86
|
*/
|
|
81
87
|
public create(
|
|
82
88
|
merkleTree: MerkleTreeWriteOperations,
|
|
83
89
|
globalVariables: GlobalVariables,
|
|
84
90
|
config: PublicSimulatorConfig,
|
|
91
|
+
contractsDB: PublicContractsDB = new PublicContractsDB(this.contractDataSource, this.log.getBindings()),
|
|
85
92
|
): PublicProcessor {
|
|
86
|
-
const bindings = this.log.getBindings();
|
|
87
|
-
const contractsDB = new PublicContractsDB(this.contractDataSource, bindings);
|
|
88
|
-
|
|
89
93
|
const guardedFork = new GuardedMerkleTreeOperations(merkleTree);
|
|
90
94
|
const publicTxSimulator = this.createPublicTxSimulator(guardedFork, contractsDB, globalVariables, config);
|
|
91
95
|
|
|
@@ -96,7 +100,7 @@ export class PublicProcessorFactory {
|
|
|
96
100
|
publicTxSimulator,
|
|
97
101
|
this.dateProvider,
|
|
98
102
|
this.telemetryClient,
|
|
99
|
-
createLogger('simulator:public-processor',
|
|
103
|
+
createLogger('simulator:public-processor', this.log.getBindings()),
|
|
100
104
|
);
|
|
101
105
|
}
|
|
102
106
|
|
|
@@ -124,13 +128,23 @@ class PublicProcessorTimeoutError extends Error {
|
|
|
124
128
|
}
|
|
125
129
|
}
|
|
126
130
|
|
|
131
|
+
class PublicProcessorAbortError extends Error {
|
|
132
|
+
constructor(message: string = 'Aborted while processing tx') {
|
|
133
|
+
super(message);
|
|
134
|
+
this.name = 'PublicProcessorAbortError';
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function isPublicProcessorInterruptError(err: any) {
|
|
139
|
+
return err?.name === 'PublicProcessorTimeoutError' || err?.name === 'PublicProcessorAbortError';
|
|
140
|
+
}
|
|
141
|
+
|
|
127
142
|
/**
|
|
128
143
|
* Converts Txs lifted from the P2P module into ProcessedTx objects by executing
|
|
129
144
|
* any public function calls in them. Txs with private calls only are unaffected.
|
|
130
145
|
*/
|
|
131
146
|
export class PublicProcessor implements Traceable {
|
|
132
147
|
private metrics: PublicProcessorMetrics;
|
|
133
|
-
|
|
134
148
|
constructor(
|
|
135
149
|
protected globalVariables: GlobalVariables,
|
|
136
150
|
private guardedMerkleTree: GuardedMerkleTreeOperations,
|
|
@@ -140,6 +154,7 @@ export class PublicProcessor implements Traceable {
|
|
|
140
154
|
telemetryClient: TelemetryClient = getTelemetryClient(),
|
|
141
155
|
private log: Logger,
|
|
142
156
|
private opts: Pick<SequencerConfig, 'fakeProcessingDelayPerTxMs' | 'fakeThrowAfterProcessingTxCount'> = {},
|
|
157
|
+
private debugLogStore: DebugLogStore = new NullDebugLogStore(),
|
|
143
158
|
) {
|
|
144
159
|
this.metrics = new PublicProcessorMetrics(telemetryClient, 'PublicProcessor');
|
|
145
160
|
}
|
|
@@ -159,12 +174,13 @@ export class PublicProcessor implements Traceable {
|
|
|
159
174
|
txs: Iterable<Tx> | AsyncIterable<Tx>,
|
|
160
175
|
limits: PublicProcessorLimits = {},
|
|
161
176
|
validator: PublicProcessorValidator = {},
|
|
162
|
-
): Promise<[ProcessedTx[], FailedTx[], Tx[], NestedProcessReturnValues[],
|
|
163
|
-
const { maxTransactions,
|
|
177
|
+
): Promise<[ProcessedTx[], FailedTx[], Tx[], NestedProcessReturnValues[], DebugLog[]]> {
|
|
178
|
+
const { maxTransactions, deadline, maxBlockGas, maxBlobFields, isBuildingProposal, signal } = limits;
|
|
164
179
|
const { preprocessValidator, nullifierCache } = validator;
|
|
165
180
|
const result: ProcessedTx[] = [];
|
|
166
181
|
const usedTxs: Tx[] = [];
|
|
167
182
|
const failed: FailedTx[] = [];
|
|
183
|
+
const debugLogs: DebugLog[] = [];
|
|
168
184
|
const timer = new Timer();
|
|
169
185
|
|
|
170
186
|
let totalSizeInBytes = 0;
|
|
@@ -172,6 +188,8 @@ export class PublicProcessor implements Traceable {
|
|
|
172
188
|
let totalPublicGas = new Gas(0, 0);
|
|
173
189
|
let totalBlockGas = new Gas(0, 0);
|
|
174
190
|
let totalBlobFields = 0;
|
|
191
|
+
let silentlySkippedCount = 0;
|
|
192
|
+
let totalSilentlySkippedDurationMs = 0;
|
|
175
193
|
|
|
176
194
|
for await (const tx of txs) {
|
|
177
195
|
// Only process up to the max tx limit
|
|
@@ -180,28 +198,33 @@ export class PublicProcessor implements Traceable {
|
|
|
180
198
|
break;
|
|
181
199
|
}
|
|
182
200
|
|
|
183
|
-
// Bail if we've hit the deadline
|
|
201
|
+
// Bail if we've hit the deadline or have been interrupted.
|
|
184
202
|
if (deadline && this.dateProvider.now() > +deadline) {
|
|
185
203
|
this.log.warn(`Stopping tx processing due to timeout.`);
|
|
186
204
|
break;
|
|
187
205
|
}
|
|
206
|
+
if (signal?.aborted) {
|
|
207
|
+
this.log.warn(`Stopping tx processing due to abort signal.`);
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
188
210
|
|
|
189
|
-
// Skip this tx if it'd exceed max block size
|
|
190
211
|
const txHash = tx.getTxHash().toString();
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
212
|
+
|
|
213
|
+
// Skip this tx if its estimated blob fields would exceed the limit.
|
|
214
|
+
// Only done during proposal building: during re-execution we must process the exact txs from the proposal.
|
|
215
|
+
const txBlobFields = tx.getPrivateTxEffectsSizeInFields();
|
|
216
|
+
if (isBuildingProposal && maxBlobFields !== undefined && totalBlobFields + txBlobFields > maxBlobFields) {
|
|
217
|
+
this.log.warn(
|
|
218
|
+
`Skipping tx ${txHash} with ${txBlobFields} fields from private side effects due to blob fields limit`,
|
|
219
|
+
{ txHash, txBlobFields, totalBlobFields, maxBlobFields },
|
|
220
|
+
);
|
|
199
221
|
continue;
|
|
200
222
|
}
|
|
201
223
|
|
|
202
|
-
// Skip this tx if its gas limit would exceed the block gas limit
|
|
224
|
+
// Skip this tx if its gas limit would exceed the block gas limit (either da or l2).
|
|
225
|
+
// Only done during proposal building: during re-execution we must process the exact txs from the proposal.
|
|
203
226
|
const txGasLimit = tx.data.constants.txContext.gasSettings.gasLimits;
|
|
204
|
-
if (maxBlockGas !== undefined && totalBlockGas.add(txGasLimit).gtAny(maxBlockGas)) {
|
|
227
|
+
if (isBuildingProposal && maxBlockGas !== undefined && totalBlockGas.add(txGasLimit).gtAny(maxBlockGas)) {
|
|
205
228
|
this.log.warn(`Skipping processing of tx ${txHash} due to block gas limit`, {
|
|
206
229
|
txHash,
|
|
207
230
|
txGasLimit,
|
|
@@ -221,11 +244,6 @@ export class PublicProcessor implements Traceable {
|
|
|
221
244
|
failed.push({ tx, error: new Error(`Tx failed preprocess validation: ${reason}`) });
|
|
222
245
|
returns.push(new NestedProcessReturnValues([]));
|
|
223
246
|
continue;
|
|
224
|
-
} else if (result.result === 'skipped') {
|
|
225
|
-
const reason = result.reason.join(', ');
|
|
226
|
-
this.log.debug(`Skipping tx ${txHash.toString()} due to pre-process validation: ${reason}`);
|
|
227
|
-
returns.push(new NestedProcessReturnValues([]));
|
|
228
|
-
continue;
|
|
229
247
|
} else {
|
|
230
248
|
this.log.trace(`Tx ${txHash.toString()} is valid before processing.`);
|
|
231
249
|
}
|
|
@@ -241,7 +259,9 @@ export class PublicProcessor implements Traceable {
|
|
|
241
259
|
this.contractsDB.createCheckpoint();
|
|
242
260
|
|
|
243
261
|
try {
|
|
244
|
-
const [processedTx, returnValues] = await
|
|
262
|
+
const [txProcessingTimeMs, [processedTx, returnValues, txDebugLogs]] = await elapsed(() =>
|
|
263
|
+
this.processTx(tx, deadline, signal),
|
|
264
|
+
);
|
|
245
265
|
|
|
246
266
|
// Inject a fake processing failure after N txs if requested
|
|
247
267
|
const fakeThrowAfter = this.opts.fakeThrowAfterProcessingTxCount;
|
|
@@ -250,23 +270,25 @@ export class PublicProcessor implements Traceable {
|
|
|
250
270
|
}
|
|
251
271
|
|
|
252
272
|
const txBlobFields = processedTx.txEffect.getNumBlobFields();
|
|
253
|
-
|
|
254
|
-
// If the actual size of this tx would exceed block size, skip it
|
|
255
273
|
const txSize = txBlobFields * Fr.SIZE_IN_BYTES;
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
274
|
+
|
|
275
|
+
// A single tx's effects must fit within the per-tx blob encoding: the rollup circuit encodes each
|
|
276
|
+
// tx into a fixed [Field; MAX_TX_BLOB_DATA_SIZE_IN_FIELDS] array, so a larger tx effect cannot be
|
|
277
|
+
// proven. The per-category side-effect limits already guarantee this upstream, so reaching here means
|
|
278
|
+
// the tx is malformed; reject it as invalid rather than letting it poison proving.
|
|
279
|
+
if (txBlobFields > MAX_TX_BLOB_DATA_SIZE_IN_FIELDS) {
|
|
280
|
+
const error = new Error(
|
|
281
|
+
`Tx ${txHash} produced ${txBlobFields} blob fields, exceeding the per-tx maximum of ${MAX_TX_BLOB_DATA_SIZE_IN_FIELDS}`,
|
|
282
|
+
);
|
|
283
|
+
this.log.error(error.message, { txHash, txBlobFields });
|
|
264
284
|
await checkpoint.revert();
|
|
265
285
|
this.contractsDB.revertCheckpoint();
|
|
286
|
+
failed.push({ tx, error });
|
|
287
|
+
returns.push(new NestedProcessReturnValues([]));
|
|
266
288
|
continue;
|
|
267
289
|
}
|
|
268
290
|
|
|
269
|
-
// If the actual blob fields of this tx would exceed the limit, skip it
|
|
291
|
+
// If the actual blob fields of this tx would exceed the limit, skip it.
|
|
270
292
|
// Note: maxBlobFields already accounts for block end blob fields and previous blocks in checkpoint.
|
|
271
293
|
if (maxBlobFields !== undefined && totalBlobFields + txBlobFields > maxBlobFields) {
|
|
272
294
|
this.log.debug(
|
|
@@ -276,35 +298,60 @@ export class PublicProcessor implements Traceable {
|
|
|
276
298
|
txBlobFields,
|
|
277
299
|
totalBlobFields,
|
|
278
300
|
maxBlobFields,
|
|
301
|
+
txProcessingTimeMs,
|
|
279
302
|
},
|
|
280
303
|
);
|
|
304
|
+
silentlySkippedCount += 1;
|
|
305
|
+
totalSilentlySkippedDurationMs += txProcessingTimeMs;
|
|
306
|
+
this.metrics.recordSilentlySkipped(txProcessingTimeMs);
|
|
281
307
|
// Need to revert the checkpoint here and don't go any further
|
|
282
308
|
await checkpoint.revert();
|
|
283
309
|
this.contractsDB.revertCheckpoint();
|
|
284
310
|
continue;
|
|
285
311
|
}
|
|
286
312
|
|
|
313
|
+
// During re-execution, check if the actual gas used by this tx would push the block over the gas limit.
|
|
314
|
+
// Unlike the proposal-building check (which uses declared gas limits pessimistically before processing),
|
|
315
|
+
// this uses actual gas and stops processing when the limit is exceeded.
|
|
316
|
+
if (
|
|
317
|
+
!isBuildingProposal &&
|
|
318
|
+
maxBlockGas !== undefined &&
|
|
319
|
+
totalBlockGas.add(processedTx.gasUsed.totalGas).gtAny(maxBlockGas)
|
|
320
|
+
) {
|
|
321
|
+
this.log.warn(`Stopping re-execution since tx ${txHash} would push block gas over limit`, {
|
|
322
|
+
txHash,
|
|
323
|
+
txGas: processedTx.gasUsed.totalGas,
|
|
324
|
+
totalBlockGas,
|
|
325
|
+
maxBlockGas,
|
|
326
|
+
});
|
|
327
|
+
await checkpoint.revert();
|
|
328
|
+
this.contractsDB.revertCheckpoint();
|
|
329
|
+
break;
|
|
330
|
+
}
|
|
331
|
+
|
|
287
332
|
// FIXME(fcarreiro): it's ugly to have to notify the validator of nullifiers.
|
|
288
333
|
// I'd rather pass the validators the processedTx as well and let them deal with it.
|
|
289
334
|
nullifierCache?.addNullifiers(processedTx.txEffect.nullifiers.map(n => n.toBuffer()));
|
|
290
335
|
result.push(processedTx);
|
|
291
336
|
usedTxs.push(tx);
|
|
292
337
|
returns = returns.concat(returnValues);
|
|
338
|
+
debugLogs.push(...txDebugLogs);
|
|
339
|
+
|
|
340
|
+
this.debugLogStore.storeLogs(processedTx.hash.toString(), txDebugLogs);
|
|
293
341
|
|
|
294
342
|
totalPublicGas = totalPublicGas.add(processedTx.gasUsed.publicGas);
|
|
295
343
|
totalBlockGas = totalBlockGas.add(processedTx.gasUsed.totalGas);
|
|
296
344
|
totalSizeInBytes += txSize;
|
|
297
345
|
totalBlobFields += txBlobFields;
|
|
346
|
+
|
|
347
|
+
// Commit the tx-level contracts checkpoint on success
|
|
348
|
+
this.contractsDB.commitCheckpoint();
|
|
298
349
|
} catch (err: any) {
|
|
299
|
-
if (err
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
//
|
|
303
|
-
// Signal cancellation AND WAIT for the simulation to actually stop.
|
|
304
|
-
// This is critical because C++ might be in the middle of a slow operation (e.g., pad_trees)
|
|
305
|
-
// and won't check the cancellation flag until that operation completes.
|
|
306
|
-
// Without waiting, we'd proceed to revert checkpoints while C++ is still writing to state.
|
|
307
|
-
// Wait for C++ to stop gracefully.
|
|
350
|
+
if (isPublicProcessorInterruptError(err)) {
|
|
351
|
+
const interruptReason = err.name === 'PublicProcessorTimeoutError' ? 'timeout' : 'abort signal';
|
|
352
|
+
this.log.warn(`Stopping tx processing due to ${interruptReason}.`);
|
|
353
|
+
// The tx may still be executing on a worker thread (C++ via NAPI).
|
|
354
|
+
// Signal cancellation AND WAIT for the simulation to actually stop before touching fork checkpoints.
|
|
308
355
|
await this.publicTxSimulator.cancel?.();
|
|
309
356
|
|
|
310
357
|
// Now stop the guarded fork to prevent any further TS-side access to the world state.
|
|
@@ -314,14 +361,10 @@ export class PublicProcessor implements Traceable {
|
|
|
314
361
|
// 1. At least one outstanding checkpoint that has not been committed (the one created before we processed the tx).
|
|
315
362
|
// 2. Possible state updates on that checkpoint or any others created during execution.
|
|
316
363
|
|
|
317
|
-
//
|
|
318
|
-
//
|
|
319
|
-
//
|
|
320
|
-
await checkpoint.
|
|
321
|
-
|
|
322
|
-
// Now we want to revert any/all remaining checkpoints, destroying any outstanding state updates.
|
|
323
|
-
// This needs to be done directly on the underlying fork as the guarded fork has been stopped.
|
|
324
|
-
await this.guardedMerkleTree.getUnderlyingFork().revertAllCheckpoints();
|
|
364
|
+
// Revert all checkpoints at or above this checkpoint's depth (inclusive), destroying any outstanding state
|
|
365
|
+
// updates from this tx and any nested checkpoints created during execution. This preserves any checkpoints
|
|
366
|
+
// created by callers below our depth.
|
|
367
|
+
await checkpoint.revertToCheckpoint();
|
|
325
368
|
|
|
326
369
|
// Revert any contracts added to the DB for the tx.
|
|
327
370
|
this.contractsDB.revertCheckpoint();
|
|
@@ -333,9 +376,9 @@ export class PublicProcessor implements Traceable {
|
|
|
333
376
|
break;
|
|
334
377
|
}
|
|
335
378
|
|
|
336
|
-
// Roll back state to start of TX before proceeding to next TX
|
|
337
|
-
|
|
338
|
-
await
|
|
379
|
+
// Roll back state to start of TX before proceeding to next TX.
|
|
380
|
+
// Reverts all checkpoints at or above this checkpoint's depth, preserving any caller checkpoints below.
|
|
381
|
+
await checkpoint.revertToCheckpoint();
|
|
339
382
|
this.contractsDB.revertCheckpoint();
|
|
340
383
|
const errorMessage = err instanceof Error || err instanceof AssertionError ? err.message : 'Unknown error';
|
|
341
384
|
this.log.warn(`Failed to process tx ${txHash.toString()}: ${errorMessage} ${err?.stack}`);
|
|
@@ -347,7 +390,6 @@ export class PublicProcessor implements Traceable {
|
|
|
347
390
|
} finally {
|
|
348
391
|
// Base case is we always commit the checkpoint. Using the ForkCheckpoint means this has no effect if the tx was previously reverted
|
|
349
392
|
await checkpoint.commit();
|
|
350
|
-
this.contractsDB.commitCheckpointOkIfNone();
|
|
351
393
|
}
|
|
352
394
|
}
|
|
353
395
|
|
|
@@ -355,15 +397,26 @@ export class PublicProcessor implements Traceable {
|
|
|
355
397
|
const rate = duration > 0 ? totalPublicGas.l2Gas / duration : 0;
|
|
356
398
|
this.metrics.recordAllTxs(totalPublicGas, rate);
|
|
357
399
|
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
400
|
+
const silentlySkippedDurationMs = Math.round(totalSilentlySkippedDurationMs);
|
|
401
|
+
this.log.info(
|
|
402
|
+
`Processed ${result.length} successful txs and ${failed.length} failed txs ` +
|
|
403
|
+
`(${silentlySkippedCount} silently skipped, ${silentlySkippedDurationMs}ms wasted) ` +
|
|
404
|
+
`in ${duration}s`,
|
|
405
|
+
{
|
|
406
|
+
blockNumber: this.globalVariables.blockNumber,
|
|
407
|
+
successfulCount: result.length,
|
|
408
|
+
failedCount: failed.length,
|
|
409
|
+
duration,
|
|
410
|
+
rate,
|
|
411
|
+
totalPublicGas,
|
|
412
|
+
totalBlockGas,
|
|
413
|
+
totalSizeInBytes,
|
|
414
|
+
silentlySkippedCount,
|
|
415
|
+
silentlySkippedDurationMs,
|
|
416
|
+
},
|
|
417
|
+
);
|
|
365
418
|
|
|
366
|
-
return [result, failed, usedTxs, returns,
|
|
419
|
+
return [result, failed, usedTxs, returns, debugLogs];
|
|
367
420
|
}
|
|
368
421
|
|
|
369
422
|
private async checkWorldStateUnchanged(
|
|
@@ -383,8 +436,14 @@ export class PublicProcessor implements Traceable {
|
|
|
383
436
|
}
|
|
384
437
|
|
|
385
438
|
@trackSpan('PublicProcessor.processTx', tx => ({ [Attributes.TX_HASH]: tx.getTxHash().toString() }))
|
|
386
|
-
private async processTx(
|
|
387
|
-
|
|
439
|
+
private async processTx(
|
|
440
|
+
tx: Tx,
|
|
441
|
+
deadline: Date | undefined,
|
|
442
|
+
signal: AbortSignal | undefined,
|
|
443
|
+
): Promise<[ProcessedTx, NestedProcessReturnValues[], DebugLog[]]> {
|
|
444
|
+
const [time, [processedTx, returnValues, debugLogs]] = await elapsed(() =>
|
|
445
|
+
this.processTxWithinDeadline(tx, deadline, signal),
|
|
446
|
+
);
|
|
388
447
|
|
|
389
448
|
this.log.verbose(
|
|
390
449
|
!tx.hasPublicCalls()
|
|
@@ -407,7 +466,7 @@ export class PublicProcessor implements Traceable {
|
|
|
407
466
|
},
|
|
408
467
|
);
|
|
409
468
|
|
|
410
|
-
return [processedTx, returnValues ?? []];
|
|
469
|
+
return [processedTx, returnValues ?? [], debugLogs];
|
|
411
470
|
}
|
|
412
471
|
|
|
413
472
|
private async doTreeInsertionsForPrivateOnlyTx(processedTx: ProcessedTx): Promise<void> {
|
|
@@ -437,14 +496,14 @@ export class PublicProcessor implements Traceable {
|
|
|
437
496
|
this.metrics.recordTreeInsertions(Number(treeInsertionEnd - treeInsertionStart) / 1_000);
|
|
438
497
|
}
|
|
439
498
|
|
|
440
|
-
/** Processes the given tx within deadline
|
|
499
|
+
/** Processes the given tx within deadline or until the signal is aborted. */
|
|
441
500
|
private async processTxWithinDeadline(
|
|
442
501
|
tx: Tx,
|
|
443
502
|
deadline: Date | undefined,
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
: () => this.processPrivateOnlyTx(tx);
|
|
503
|
+
signal: AbortSignal | undefined,
|
|
504
|
+
): Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined, DebugLog[]]> {
|
|
505
|
+
const innerProcessFn: () => Promise<[ProcessedTx, NestedProcessReturnValues[] | undefined, DebugLog[]]> =
|
|
506
|
+
tx.hasPublicCalls() ? () => this.processTxWithPublicCalls(tx) : () => this.processPrivateOnlyTx(tx);
|
|
448
507
|
|
|
449
508
|
// Fake a delay per tx if instructed (used for tests)
|
|
450
509
|
const fakeDelayPerTxMs = this.opts.fakeProcessingDelayPerTxMs;
|
|
@@ -458,27 +517,38 @@ export class PublicProcessor implements Traceable {
|
|
|
458
517
|
}
|
|
459
518
|
: innerProcessFn;
|
|
460
519
|
|
|
461
|
-
|
|
520
|
+
const processingSignal = this.getProcessingSignal(tx, deadline, signal);
|
|
521
|
+
if (!processingSignal) {
|
|
462
522
|
return await processFn();
|
|
463
523
|
}
|
|
464
524
|
|
|
465
|
-
|
|
525
|
+
return await execWithSignal(
|
|
526
|
+
() => processFn(),
|
|
527
|
+
processingSignal,
|
|
528
|
+
signal =>
|
|
529
|
+
signal.reason?.name === 'TimeoutError' ? new PublicProcessorTimeoutError() : new PublicProcessorAbortError(),
|
|
530
|
+
);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
private getProcessingSignal(tx: Tx, deadline: Date | undefined, signal: AbortSignal | undefined) {
|
|
534
|
+
if (!deadline) {
|
|
535
|
+
return signal;
|
|
536
|
+
}
|
|
537
|
+
|
|
466
538
|
const timeout = +deadline - this.dateProvider.now();
|
|
467
539
|
if (timeout <= 0) {
|
|
468
540
|
throw new PublicProcessorTimeoutError();
|
|
469
541
|
}
|
|
470
542
|
|
|
543
|
+
const txHash = tx.getTxHash();
|
|
471
544
|
this.log.debug(`Processing tx ${txHash.toString()} within ${timeout}ms`, {
|
|
472
545
|
deadline: deadline.toISOString(),
|
|
473
546
|
now: new Date(this.dateProvider.now()).toISOString(),
|
|
474
547
|
txHash,
|
|
475
548
|
});
|
|
476
549
|
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
timeout,
|
|
480
|
-
() => new PublicProcessorTimeoutError(),
|
|
481
|
-
);
|
|
550
|
+
const timeoutSignal = AbortSignal.timeout(timeout);
|
|
551
|
+
return signal ? AbortSignal.any([signal, timeoutSignal]) : timeoutSignal;
|
|
482
552
|
}
|
|
483
553
|
|
|
484
554
|
/**
|
|
@@ -512,7 +582,7 @@ export class PublicProcessor implements Traceable {
|
|
|
512
582
|
@trackSpan('PublicProcessor.processPrivateOnlyTx', (tx: Tx) => ({
|
|
513
583
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
514
584
|
}))
|
|
515
|
-
private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx, undefined]> {
|
|
585
|
+
private async processPrivateOnlyTx(tx: Tx): Promise<[ProcessedTx, undefined, DebugLog[]]> {
|
|
516
586
|
const gasFees = this.globalVariables.gasFees;
|
|
517
587
|
const transactionFee = computeTransactionFee(gasFees, tx.data.constants.txContext.gasSettings, tx.data.gasUsed);
|
|
518
588
|
|
|
@@ -535,15 +605,15 @@ export class PublicProcessor implements Traceable {
|
|
|
535
605
|
// Fee payment insertion has already been done. Do the rest.
|
|
536
606
|
await this.doTreeInsertionsForPrivateOnlyTx(processedTx);
|
|
537
607
|
|
|
538
|
-
|
|
608
|
+
this.contractsDB.addNewContracts(tx);
|
|
539
609
|
|
|
540
|
-
return [processedTx, undefined];
|
|
610
|
+
return [processedTx, undefined, []];
|
|
541
611
|
}
|
|
542
612
|
|
|
543
613
|
@trackSpan('PublicProcessor.processTxWithPublicCalls', tx => ({
|
|
544
614
|
[Attributes.TX_HASH]: tx.getTxHash().toString(),
|
|
545
615
|
}))
|
|
546
|
-
private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[]]> {
|
|
616
|
+
private async processTxWithPublicCalls(tx: Tx): Promise<[ProcessedTx, NestedProcessReturnValues[], DebugLog[]]> {
|
|
547
617
|
const timer = new Timer();
|
|
548
618
|
|
|
549
619
|
const result = await this.publicTxSimulator.simulate(tx);
|
|
@@ -581,7 +651,7 @@ export class PublicProcessor implements Traceable {
|
|
|
581
651
|
revertReason,
|
|
582
652
|
);
|
|
583
653
|
|
|
584
|
-
return [processedTx, appLogicReturnValues];
|
|
654
|
+
return [processedTx, appLogicReturnValues, result.logs ?? []];
|
|
585
655
|
}
|
|
586
656
|
|
|
587
657
|
/**
|
|
@@ -30,6 +30,9 @@ export class PublicProcessorMetrics {
|
|
|
30
30
|
|
|
31
31
|
private treeInsertionDuration: Histogram;
|
|
32
32
|
|
|
33
|
+
private silentlySkippedCount: UpDownCounter;
|
|
34
|
+
private silentlySkippedDuration: Histogram;
|
|
35
|
+
|
|
33
36
|
constructor(client: TelemetryClient, name = 'PublicProcessor') {
|
|
34
37
|
this.tracer = client.getTracer(name);
|
|
35
38
|
const meter = client.getMeter(name);
|
|
@@ -60,6 +63,10 @@ export class PublicProcessorMetrics {
|
|
|
60
63
|
this.gasRate = meter.createHistogram(Metrics.PUBLIC_PROCESSOR_GAS_RATE);
|
|
61
64
|
|
|
62
65
|
this.treeInsertionDuration = meter.createHistogram(Metrics.PUBLIC_PROCESSOR_TREE_INSERTION);
|
|
66
|
+
|
|
67
|
+
this.silentlySkippedCount = createUpDownCounterWithDefault(meter, Metrics.PUBLIC_PROCESSOR_SILENTLY_SKIPPED_COUNT);
|
|
68
|
+
|
|
69
|
+
this.silentlySkippedDuration = meter.createHistogram(Metrics.PUBLIC_PROCESSOR_SILENTLY_SKIPPED_DURATION);
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
recordPhaseDuration(phaseName: TxExecutionPhase, durationMs: number) {
|
|
@@ -123,4 +130,9 @@ export class PublicProcessorMetrics {
|
|
|
123
130
|
recordTreeInsertions(durationUs: number) {
|
|
124
131
|
this.treeInsertionDuration.record(Math.ceil(durationUs));
|
|
125
132
|
}
|
|
133
|
+
|
|
134
|
+
recordSilentlySkipped(durationMs: number) {
|
|
135
|
+
this.silentlySkippedCount.add(1);
|
|
136
|
+
this.silentlySkippedDuration.record(Math.ceil(durationMs));
|
|
137
|
+
}
|
|
126
138
|
}
|
|
@@ -23,7 +23,7 @@ export class ContractProviderForCpp implements ContractProvider {
|
|
|
23
23
|
public getContractInstance = async (address: string): Promise<Buffer | undefined> => {
|
|
24
24
|
this.log.trace(`Contract provider callback: getContractInstance(${address})`);
|
|
25
25
|
|
|
26
|
-
const aztecAddr = AztecAddress.
|
|
26
|
+
const aztecAddr = AztecAddress.fromStringUnsafe(address);
|
|
27
27
|
|
|
28
28
|
const instance = await this.contractsDB.getContractInstance(aztecAddr, this.globalVariables.timestamp);
|
|
29
29
|
|
|
@@ -52,6 +52,7 @@ export class ContractProviderForCpp implements ContractProvider {
|
|
|
52
52
|
return serializeWithMessagePack(contractClass);
|
|
53
53
|
};
|
|
54
54
|
|
|
55
|
+
// eslint-disable-next-line require-await
|
|
55
56
|
public addContracts = async (contractDeploymentDataBuffer: Buffer): Promise<void> => {
|
|
56
57
|
this.log.trace(`Contract provider callback: addContracts`);
|
|
57
58
|
|
|
@@ -61,8 +62,8 @@ export class ContractProviderForCpp implements ContractProvider {
|
|
|
61
62
|
const contractDeploymentData = ContractDeploymentData.fromPlainObject(rawData);
|
|
62
63
|
|
|
63
64
|
// Add contracts to the contracts DB
|
|
64
|
-
this.log.trace(`Calling contractsDB.
|
|
65
|
-
|
|
65
|
+
this.log.trace(`Calling contractsDB.addContractsFromLogs`);
|
|
66
|
+
this.contractsDB.addContractsFromLogs(contractDeploymentData);
|
|
66
67
|
};
|
|
67
68
|
|
|
68
69
|
public getBytecodeCommitment = async (classId: string): Promise<Buffer | undefined> => {
|
|
@@ -87,7 +88,7 @@ export class ContractProviderForCpp implements ContractProvider {
|
|
|
87
88
|
this.log.trace(`Contract provider callback: getDebugFunctionName(${address}, ${selector})`);
|
|
88
89
|
|
|
89
90
|
// Parse address and selector strings
|
|
90
|
-
const aztecAddr = AztecAddress.
|
|
91
|
+
const aztecAddr = AztecAddress.fromStringUnsafe(address);
|
|
91
92
|
const selectorFr = Fr.fromString(selector);
|
|
92
93
|
const functionSelector = FunctionSelector.fromFieldOrUndefined(selectorFr);
|
|
93
94
|
|
|
@@ -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,
|
|
@@ -174,14 +174,8 @@ export class PublicTxContext {
|
|
|
174
174
|
}
|
|
175
175
|
if (phase === TxExecutionPhase.SETUP) {
|
|
176
176
|
this.log.warn(`Setup phase reverted! The transaction will be thrown out.`);
|
|
177
|
-
} else if (phase === TxExecutionPhase.APP_LOGIC) {
|
|
178
|
-
this.revertCode = RevertCode.
|
|
179
|
-
} else if (phase === TxExecutionPhase.TEARDOWN) {
|
|
180
|
-
if (this.revertCode.equals(RevertCode.APP_LOGIC_REVERTED)) {
|
|
181
|
-
this.revertCode = RevertCode.BOTH_REVERTED;
|
|
182
|
-
} else {
|
|
183
|
-
this.revertCode = RevertCode.TEARDOWN_REVERTED;
|
|
184
|
-
}
|
|
177
|
+
} else if (phase === TxExecutionPhase.APP_LOGIC || phase === TxExecutionPhase.TEARDOWN) {
|
|
178
|
+
this.revertCode = RevertCode.REVERTED;
|
|
185
179
|
}
|
|
186
180
|
}
|
|
187
181
|
|
|
@@ -247,8 +241,12 @@ export class PublicTxContext {
|
|
|
247
241
|
}
|
|
248
242
|
|
|
249
243
|
/**
|
|
250
|
-
* The gasUsed by public and private,
|
|
251
|
-
*
|
|
244
|
+
* The gasUsed by public and private, as if the entire teardown gas limit was consumed.
|
|
245
|
+
*
|
|
246
|
+
* This is intentional: teardown is used for gas accounting and refunds, so the transaction
|
|
247
|
+
* fee must be deterministic _before_ teardown executes. If fees depended on teardown's actual
|
|
248
|
+
* consumption there would be a circular dependency. Billing the full teardown gas limit
|
|
249
|
+
* (set by the user) makes the fee known in advance and available to the teardown function.
|
|
252
250
|
*/
|
|
253
251
|
getTotalGasUsed(): Gas {
|
|
254
252
|
return this.gasUsedByPrivate.add(this.gasUsedByPublic);
|