@aztec/simulator 0.66.0 → 0.67.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dest/acvm/acvm.js +3 -3
- package/dest/acvm/oracle/oracle.d.ts +1 -1
- package/dest/acvm/oracle/oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/oracle.js +3 -3
- package/dest/acvm/oracle/typed_oracle.d.ts +2 -2
- package/dest/acvm/oracle/typed_oracle.d.ts.map +1 -1
- package/dest/acvm/oracle/typed_oracle.js +3 -3
- package/dest/acvm/serialize.js +2 -2
- package/dest/avm/avm_context.d.ts +2 -2
- package/dest/avm/avm_context.d.ts.map +1 -1
- package/dest/avm/avm_context.js +3 -4
- package/dest/avm/avm_execution_environment.d.ts +4 -6
- package/dest/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/avm/avm_execution_environment.js +8 -13
- package/dest/avm/avm_memory_types.d.ts +2 -2
- package/dest/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/avm/avm_memory_types.js +3 -3
- package/dest/avm/avm_simulator.d.ts +3 -3
- package/dest/avm/avm_simulator.d.ts.map +1 -1
- package/dest/avm/avm_simulator.js +22 -13
- package/dest/avm/errors.d.ts +3 -3
- package/dest/avm/errors.d.ts.map +1 -1
- package/dest/avm/errors.js +8 -15
- package/dest/avm/fixtures/index.d.ts.map +1 -1
- package/dest/avm/fixtures/index.js +4 -4
- package/dest/avm/journal/journal.d.ts +15 -4
- package/dest/avm/journal/journal.d.ts.map +1 -1
- package/dest/avm/journal/journal.js +108 -29
- package/dest/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/avm/opcodes/external_calls.js +4 -11
- package/dest/avm/opcodes/misc.d.ts.map +1 -1
- package/dest/avm/opcodes/misc.js +3 -3
- package/dest/client/client_execution_context.d.ts +3 -3
- package/dest/client/client_execution_context.d.ts.map +1 -1
- package/dest/client/client_execution_context.js +14 -8
- package/dest/client/db_oracle.d.ts +2 -2
- package/dest/client/db_oracle.d.ts.map +1 -1
- package/dest/client/execution_note_cache.d.ts +9 -1
- package/dest/client/execution_note_cache.d.ts.map +1 -1
- package/dest/client/execution_note_cache.js +10 -3
- package/dest/client/private_execution.d.ts.map +1 -1
- package/dest/client/private_execution.js +4 -4
- package/dest/client/simulator.d.ts.map +1 -1
- package/dest/client/simulator.js +4 -4
- package/dest/client/unconstrained_execution.d.ts.map +1 -1
- package/dest/client/unconstrained_execution.js +3 -3
- package/dest/client/view_data_oracle.d.ts +2 -2
- package/dest/client/view_data_oracle.d.ts.map +1 -1
- package/dest/client/view_data_oracle.js +5 -6
- package/dest/common/debug_fn_name.d.ts +2 -2
- package/dest/common/debug_fn_name.d.ts.map +1 -1
- package/dest/common/debug_fn_name.js +8 -14
- package/dest/providers/acvm_native.js +4 -4
- package/dest/providers/factory.d.ts +2 -2
- package/dest/providers/factory.d.ts.map +1 -1
- package/dest/providers/factory.js +4 -4
- package/dest/public/enqueued_call_side_effect_trace.d.ts +11 -23
- package/dest/public/enqueued_call_side_effect_trace.d.ts.map +1 -1
- package/dest/public/enqueued_call_side_effect_trace.js +37 -58
- package/dest/public/executor_metrics.d.ts.map +1 -1
- package/dest/public/executor_metrics.js +2 -5
- package/dest/public/fixtures/index.d.ts +24 -1
- package/dest/public/fixtures/index.d.ts.map +1 -1
- package/dest/public/fixtures/index.js +15 -9
- package/dest/public/index.d.ts +0 -1
- package/dest/public/index.d.ts.map +1 -1
- package/dest/public/index.js +1 -2
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +4 -4
- package/dest/public/public_processor.d.ts +7 -8
- package/dest/public/public_processor.d.ts.map +1 -1
- package/dest/public/public_processor.js +30 -22
- package/dest/public/public_tx_context.d.ts +13 -10
- package/dest/public/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_context.js +46 -31
- package/dest/public/public_tx_simulator.d.ts +2 -2
- package/dest/public/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator.js +43 -23
- package/dest/public/side_effect_trace_interface.d.ts +4 -17
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/public/transitional_adapters.d.ts +2 -2
- package/dest/public/transitional_adapters.d.ts.map +1 -1
- package/dest/public/transitional_adapters.js +28 -24
- package/package.json +16 -9
- package/src/acvm/acvm.ts +2 -2
- package/src/acvm/oracle/oracle.ts +2 -2
- package/src/acvm/oracle/typed_oracle.ts +3 -3
- package/src/acvm/serialize.ts +1 -1
- package/src/avm/avm_context.ts +2 -3
- package/src/avm/avm_execution_environment.ts +6 -31
- package/src/avm/avm_memory_types.ts +2 -2
- package/src/avm/avm_simulator.ts +24 -20
- package/src/avm/errors.ts +12 -14
- package/src/avm/fixtures/index.ts +2 -3
- package/src/avm/journal/journal.ts +189 -63
- package/src/avm/opcodes/external_calls.ts +3 -19
- package/src/avm/opcodes/misc.ts +2 -2
- package/src/client/client_execution_context.ts +17 -9
- package/src/client/db_oracle.ts +2 -2
- package/src/client/execution_note_cache.ts +13 -3
- package/src/client/private_execution.ts +3 -3
- package/src/client/simulator.ts +4 -4
- package/src/client/unconstrained_execution.ts +2 -2
- package/src/client/view_data_oracle.ts +5 -6
- package/src/common/debug_fn_name.ts +7 -13
- package/src/providers/acvm_native.ts +3 -3
- package/src/providers/factory.ts +3 -3
- package/src/public/enqueued_call_side_effect_trace.ts +54 -74
- package/src/public/executor_metrics.ts +0 -4
- package/src/public/fixtures/index.ts +23 -10
- package/src/public/index.ts +0 -1
- package/src/public/public_db_sources.ts +3 -3
- package/src/public/public_processor.ts +46 -47
- package/src/public/public_tx_context.ts +52 -32
- package/src/public/public_tx_simulator.ts +58 -38
- package/src/public/side_effect_trace_interface.ts +8 -15
- package/src/public/transitional_adapters.ts +39 -24
- package/dest/public/dual_side_effect_trace.d.ts +0 -77
- package/dest/public/dual_side_effect_trace.d.ts.map +0 -1
- package/dest/public/dual_side_effect_trace.js +0 -119
- package/dest/public/side_effect_trace.d.ts +0 -96
- package/dest/public/side_effect_trace.d.ts.map +0 -1
- package/dest/public/side_effect_trace.js +0 -309
- package/src/public/dual_side_effect_trace.ts +0 -242
- package/src/public/side_effect_trace.ts +0 -536
|
@@ -13,17 +13,17 @@ import {
|
|
|
13
13
|
} from '@aztec/circuit-types';
|
|
14
14
|
import {
|
|
15
15
|
type AztecAddress,
|
|
16
|
+
type BlockHeader,
|
|
16
17
|
type ContractDataSource,
|
|
17
18
|
Fr,
|
|
18
19
|
type GlobalVariables,
|
|
19
|
-
type Header,
|
|
20
20
|
MAX_NOTE_HASHES_PER_TX,
|
|
21
21
|
MAX_NULLIFIERS_PER_TX,
|
|
22
22
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
23
23
|
PublicDataWrite,
|
|
24
24
|
} from '@aztec/circuits.js';
|
|
25
25
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
26
|
-
import {
|
|
26
|
+
import { createLogger } from '@aztec/foundation/log';
|
|
27
27
|
import { Timer } from '@aztec/foundation/timer';
|
|
28
28
|
import { ContractClassRegisteredEvent, ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
29
29
|
import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
@@ -47,13 +47,19 @@ export class PublicProcessorFactory {
|
|
|
47
47
|
*/
|
|
48
48
|
public create(
|
|
49
49
|
merkleTree: MerkleTreeWriteOperations,
|
|
50
|
-
maybeHistoricalHeader:
|
|
50
|
+
maybeHistoricalHeader: BlockHeader | undefined,
|
|
51
51
|
globalVariables: GlobalVariables,
|
|
52
52
|
): PublicProcessor {
|
|
53
53
|
const historicalHeader = maybeHistoricalHeader ?? merkleTree.getInitialHeader();
|
|
54
54
|
|
|
55
55
|
const worldStateDB = new WorldStateDB(merkleTree, this.contractDataSource);
|
|
56
|
-
const publicTxSimulator = new PublicTxSimulator(
|
|
56
|
+
const publicTxSimulator = new PublicTxSimulator(
|
|
57
|
+
merkleTree,
|
|
58
|
+
worldStateDB,
|
|
59
|
+
this.telemetryClient,
|
|
60
|
+
globalVariables,
|
|
61
|
+
/*doMerkleOperations=*/ true,
|
|
62
|
+
);
|
|
57
63
|
|
|
58
64
|
return new PublicProcessor(
|
|
59
65
|
merkleTree,
|
|
@@ -75,11 +81,11 @@ export class PublicProcessor {
|
|
|
75
81
|
constructor(
|
|
76
82
|
protected db: MerkleTreeWriteOperations,
|
|
77
83
|
protected globalVariables: GlobalVariables,
|
|
78
|
-
protected historicalHeader:
|
|
84
|
+
protected historicalHeader: BlockHeader,
|
|
79
85
|
protected worldStateDB: WorldStateDB,
|
|
80
86
|
protected publicTxSimulator: PublicTxSimulator,
|
|
81
87
|
telemetryClient: TelemetryClient,
|
|
82
|
-
private log =
|
|
88
|
+
private log = createLogger('simulator:public-processor'),
|
|
83
89
|
) {
|
|
84
90
|
this.metrics = new PublicProcessorMetrics(telemetryClient, 'PublicProcessor');
|
|
85
91
|
}
|
|
@@ -115,12 +121,26 @@ export class PublicProcessor {
|
|
|
115
121
|
const [processedTx, returnValues] = !tx.hasPublicCalls()
|
|
116
122
|
? await this.processPrivateOnlyTx(tx)
|
|
117
123
|
: await this.processTxWithPublicCalls(tx);
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
+
|
|
125
|
+
this.log.verbose(
|
|
126
|
+
!tx.hasPublicCalls()
|
|
127
|
+
? `Processed tx ${processedTx.hash} with no public calls`
|
|
128
|
+
: `Processed tx ${processedTx.hash} with ${tx.enqueuedPublicFunctionCalls.length} public calls`,
|
|
129
|
+
{
|
|
130
|
+
txHash: processedTx.hash,
|
|
131
|
+
txFee: processedTx.txEffect.transactionFee.toBigInt(),
|
|
132
|
+
revertCode: processedTx.txEffect.revertCode.getCode(),
|
|
133
|
+
revertReason: processedTx.revertReason,
|
|
134
|
+
gasUsed: processedTx.gasUsed,
|
|
135
|
+
publicDataWriteCount: processedTx.txEffect.publicDataWrites.length,
|
|
136
|
+
nullifierCount: processedTx.txEffect.nullifiers.length,
|
|
137
|
+
noteHashCount: processedTx.txEffect.noteHashes.length,
|
|
138
|
+
contractClassLogCount: processedTx.txEffect.contractClassLogs.getTotalLogCount(),
|
|
139
|
+
unencryptedLogCount: processedTx.txEffect.unencryptedLogs.getTotalLogCount(),
|
|
140
|
+
privateLogCount: processedTx.txEffect.privateLogs.length,
|
|
141
|
+
l2ToL1MessageCount: processedTx.txEffect.l2ToL1Msgs.length,
|
|
142
|
+
},
|
|
143
|
+
);
|
|
124
144
|
|
|
125
145
|
// Commit the state updates from this transaction
|
|
126
146
|
await this.worldStateDB.commit();
|
|
@@ -188,16 +208,11 @@ export class PublicProcessor {
|
|
|
188
208
|
}
|
|
189
209
|
|
|
190
210
|
/**
|
|
191
|
-
* Creates the
|
|
192
|
-
*
|
|
193
|
-
*
|
|
194
|
-
* See build_or_patch_payment_update_request in base_rollup_inputs.nr for more details.
|
|
211
|
+
* Creates the public data write for paying the tx fee.
|
|
212
|
+
* This is used in private only txs, since for txs with public calls
|
|
213
|
+
* the avm handles the fee payment itself.
|
|
195
214
|
*/
|
|
196
|
-
private async getFeePaymentPublicDataWrite(
|
|
197
|
-
publicDataWrites: PublicDataWrite[],
|
|
198
|
-
txFee: Fr,
|
|
199
|
-
feePayer: AztecAddress,
|
|
200
|
-
): Promise<PublicDataWrite | undefined> {
|
|
215
|
+
private async getFeePaymentPublicDataWrite(txFee: Fr, feePayer: AztecAddress): Promise<PublicDataWrite | undefined> {
|
|
201
216
|
if (feePayer.isZero()) {
|
|
202
217
|
this.log.debug(`No one is paying the fee of ${txFee.toBigInt()}`);
|
|
203
218
|
return;
|
|
@@ -209,11 +224,7 @@ export class PublicProcessor {
|
|
|
209
224
|
|
|
210
225
|
this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${feePayer}`);
|
|
211
226
|
|
|
212
|
-
const
|
|
213
|
-
|
|
214
|
-
const balance = existingBalanceWrite
|
|
215
|
-
? existingBalanceWrite.value
|
|
216
|
-
: await this.worldStateDB.storageRead(feeJuiceAddress, balanceSlot);
|
|
227
|
+
const balance = await this.worldStateDB.storageRead(feeJuiceAddress, balanceSlot);
|
|
217
228
|
|
|
218
229
|
if (balance.lt(txFee)) {
|
|
219
230
|
throw new Error(
|
|
@@ -234,12 +245,7 @@ export class PublicProcessor {
|
|
|
234
245
|
const gasFees = this.globalVariables.gasFees;
|
|
235
246
|
const transactionFee = tx.data.gasUsed.computeFee(gasFees);
|
|
236
247
|
|
|
237
|
-
const
|
|
238
|
-
const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite(
|
|
239
|
-
accumulatedData.publicDataWrites,
|
|
240
|
-
transactionFee,
|
|
241
|
-
tx.data.feePayer,
|
|
242
|
-
);
|
|
248
|
+
const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite(transactionFee, tx.data.feePayer);
|
|
243
249
|
|
|
244
250
|
const processedTx = makeProcessedTxFromPrivateOnlyTx(
|
|
245
251
|
tx,
|
|
@@ -247,6 +253,13 @@ export class PublicProcessor {
|
|
|
247
253
|
feePaymentPublicDataWrite,
|
|
248
254
|
this.globalVariables,
|
|
249
255
|
);
|
|
256
|
+
|
|
257
|
+
this.metrics.recordClassRegistration(
|
|
258
|
+
...tx.contractClassLogs
|
|
259
|
+
.unrollLogs()
|
|
260
|
+
.filter(log => ContractClassRegisteredEvent.isContractClassRegisteredEvent(log.data))
|
|
261
|
+
.map(log => ContractClassRegisteredEvent.fromLog(log.data)),
|
|
262
|
+
);
|
|
250
263
|
return [processedTx];
|
|
251
264
|
}
|
|
252
265
|
|
|
@@ -283,21 +296,7 @@ export class PublicProcessor {
|
|
|
283
296
|
const durationMs = timer.ms();
|
|
284
297
|
this.metrics.recordTx(phaseCount, durationMs);
|
|
285
298
|
|
|
286
|
-
const
|
|
287
|
-
const feePaymentPublicDataWrite = await this.getFeePaymentPublicDataWrite(
|
|
288
|
-
data.accumulatedData.publicDataWrites,
|
|
289
|
-
data.transactionFee,
|
|
290
|
-
tx.data.feePayer,
|
|
291
|
-
);
|
|
292
|
-
|
|
293
|
-
const processedTx = makeProcessedTxFromTxWithPublicCalls(
|
|
294
|
-
tx,
|
|
295
|
-
avmProvingRequest,
|
|
296
|
-
feePaymentPublicDataWrite,
|
|
297
|
-
gasUsed,
|
|
298
|
-
revertCode,
|
|
299
|
-
revertReason,
|
|
300
|
-
);
|
|
299
|
+
const processedTx = makeProcessedTxFromTxWithPublicCalls(tx, avmProvingRequest, gasUsed, revertCode, revertReason);
|
|
301
300
|
|
|
302
301
|
const returnValues = processedPhases.find(({ phase }) => phase === TxExecutionPhase.APP_LOGIC)?.returnValues ?? [];
|
|
303
302
|
|
|
@@ -13,10 +13,12 @@ import {
|
|
|
13
13
|
AppendOnlyTreeSnapshot,
|
|
14
14
|
AvmCircuitInputs,
|
|
15
15
|
type AvmCircuitPublicInputs,
|
|
16
|
+
type AztecAddress,
|
|
16
17
|
Fr,
|
|
17
18
|
Gas,
|
|
18
19
|
type GasSettings,
|
|
19
20
|
type GlobalVariables,
|
|
21
|
+
MAX_L2_GAS_PER_TX_PUBLIC_PORTION,
|
|
20
22
|
type PrivateToPublicAccumulatedData,
|
|
21
23
|
type PublicCallRequest,
|
|
22
24
|
PublicCircuitPublicInputs,
|
|
@@ -25,16 +27,14 @@ import {
|
|
|
25
27
|
TreeSnapshots,
|
|
26
28
|
countAccumulatedItems,
|
|
27
29
|
} from '@aztec/circuits.js';
|
|
28
|
-
import { type
|
|
30
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
29
31
|
|
|
30
32
|
import { strict as assert } from 'assert';
|
|
31
33
|
import { inspect } from 'util';
|
|
32
34
|
|
|
33
35
|
import { AvmPersistableStateManager } from '../avm/index.js';
|
|
34
|
-
import { DualSideEffectTrace } from './dual_side_effect_trace.js';
|
|
35
36
|
import { PublicEnqueuedCallSideEffectTrace, SideEffectArrayLengths } from './enqueued_call_side_effect_trace.js';
|
|
36
37
|
import { type WorldStateDB } from './public_db_sources.js';
|
|
37
|
-
import { PublicSideEffectTrace } from './side_effect_trace.js';
|
|
38
38
|
import { generateAvmCircuitPublicInputs } from './transitional_adapters.js';
|
|
39
39
|
import { getCallRequestsByPhase, getExecutionRequestsByPhase } from './utils.js';
|
|
40
40
|
|
|
@@ -42,10 +42,10 @@ import { getCallRequestsByPhase, getExecutionRequestsByPhase } from './utils.js'
|
|
|
42
42
|
* The transaction-level context for public execution.
|
|
43
43
|
*/
|
|
44
44
|
export class PublicTxContext {
|
|
45
|
-
private log:
|
|
45
|
+
private log: Logger;
|
|
46
46
|
|
|
47
47
|
/* Gas used including private, teardown gas _limit_, setup and app logic */
|
|
48
|
-
private
|
|
48
|
+
private gasUsedByPublic: Gas = Gas.empty();
|
|
49
49
|
/* Gas actually used during teardown (different from limit) */
|
|
50
50
|
public teardownGasUsed: Gas = Gas.empty();
|
|
51
51
|
|
|
@@ -62,8 +62,9 @@ export class PublicTxContext {
|
|
|
62
62
|
public readonly state: PhaseStateManager,
|
|
63
63
|
private readonly globalVariables: GlobalVariables,
|
|
64
64
|
private readonly startStateReference: StateReference,
|
|
65
|
-
private readonly startGasUsed: Gas,
|
|
66
65
|
private readonly gasSettings: GasSettings,
|
|
66
|
+
private readonly gasUsedByPrivate: Gas,
|
|
67
|
+
private readonly gasAllocatedToPublic: Gas,
|
|
67
68
|
private readonly setupCallRequests: PublicCallRequest[],
|
|
68
69
|
private readonly appLogicCallRequests: PublicCallRequest[],
|
|
69
70
|
private readonly teardownCallRequests: PublicCallRequest[],
|
|
@@ -72,10 +73,10 @@ export class PublicTxContext {
|
|
|
72
73
|
private readonly teardownExecutionRequests: PublicExecutionRequest[],
|
|
73
74
|
public readonly nonRevertibleAccumulatedDataFromPrivate: PrivateToPublicAccumulatedData,
|
|
74
75
|
public readonly revertibleAccumulatedDataFromPrivate: PrivateToPublicAccumulatedData,
|
|
76
|
+
public readonly feePayer: AztecAddress,
|
|
75
77
|
public trace: PublicEnqueuedCallSideEffectTrace, // FIXME(dbanks12): should be private
|
|
76
78
|
) {
|
|
77
|
-
this.log =
|
|
78
|
-
this.gasUsed = startGasUsed;
|
|
79
|
+
this.log = createLogger(`simulator:public_tx_context`);
|
|
79
80
|
}
|
|
80
81
|
|
|
81
82
|
public static async create(
|
|
@@ -87,9 +88,9 @@ export class PublicTxContext {
|
|
|
87
88
|
) {
|
|
88
89
|
const nonRevertibleAccumulatedDataFromPrivate = tx.data.forPublic!.nonRevertibleAccumulatedData;
|
|
89
90
|
|
|
90
|
-
const innerCallTrace = new PublicSideEffectTrace();
|
|
91
91
|
const previousAccumulatedDataArrayLengths = new SideEffectArrayLengths(
|
|
92
92
|
/*publicDataWrites*/ 0,
|
|
93
|
+
/*protocolPublicDataWrites*/ 0,
|
|
93
94
|
countAccumulatedItems(nonRevertibleAccumulatedDataFromPrivate.noteHashes),
|
|
94
95
|
/*nullifiers=*/ 0,
|
|
95
96
|
countAccumulatedItems(nonRevertibleAccumulatedDataFromPrivate.l2ToL1Msgs),
|
|
@@ -99,17 +100,22 @@ export class PublicTxContext {
|
|
|
99
100
|
/*startSideEffectCounter=*/ 0,
|
|
100
101
|
previousAccumulatedDataArrayLengths,
|
|
101
102
|
);
|
|
102
|
-
const trace = new DualSideEffectTrace(innerCallTrace, enqueuedCallTrace);
|
|
103
103
|
|
|
104
104
|
// Transaction level state manager that will be forked for revertible phases.
|
|
105
|
-
const txStateManager = await AvmPersistableStateManager.create(worldStateDB,
|
|
105
|
+
const txStateManager = await AvmPersistableStateManager.create(worldStateDB, enqueuedCallTrace, doMerkleOperations);
|
|
106
|
+
|
|
107
|
+
const gasSettings = tx.data.constants.txContext.gasSettings;
|
|
108
|
+
const gasUsedByPrivate = tx.data.gasUsed;
|
|
109
|
+
// Gas allocated to public is "whatever's left" after private, but with some max applied.
|
|
110
|
+
const gasAllocatedToPublic = applyMaxToAvailableGas(gasSettings.gasLimits.sub(gasUsedByPrivate));
|
|
106
111
|
|
|
107
112
|
return new PublicTxContext(
|
|
108
113
|
new PhaseStateManager(txStateManager),
|
|
109
114
|
globalVariables,
|
|
110
115
|
await db.getStateReference(),
|
|
111
|
-
|
|
112
|
-
|
|
116
|
+
gasSettings,
|
|
117
|
+
gasUsedByPrivate,
|
|
118
|
+
gasAllocatedToPublic,
|
|
113
119
|
getCallRequestsByPhase(tx, TxExecutionPhase.SETUP),
|
|
114
120
|
getCallRequestsByPhase(tx, TxExecutionPhase.APP_LOGIC),
|
|
115
121
|
getCallRequestsByPhase(tx, TxExecutionPhase.TEARDOWN),
|
|
@@ -118,6 +124,7 @@ export class PublicTxContext {
|
|
|
118
124
|
getExecutionRequestsByPhase(tx, TxExecutionPhase.TEARDOWN),
|
|
119
125
|
tx.data.forPublic!.nonRevertibleAccumulatedData,
|
|
120
126
|
tx.data.forPublic!.revertibleAccumulatedData,
|
|
127
|
+
tx.data.feePayer,
|
|
121
128
|
enqueuedCallTrace,
|
|
122
129
|
);
|
|
123
130
|
}
|
|
@@ -230,13 +237,14 @@ export class PublicTxContext {
|
|
|
230
237
|
}
|
|
231
238
|
|
|
232
239
|
/**
|
|
233
|
-
* How much gas is left
|
|
240
|
+
* How much gas is left as of the specified phase?
|
|
234
241
|
*/
|
|
235
|
-
|
|
242
|
+
getGasLeftAtPhase(phase: TxExecutionPhase): Gas {
|
|
236
243
|
if (phase === TxExecutionPhase.TEARDOWN) {
|
|
237
|
-
return this.gasSettings.teardownGasLimits;
|
|
244
|
+
return applyMaxToAvailableGas(this.gasSettings.teardownGasLimits);
|
|
238
245
|
} else {
|
|
239
|
-
|
|
246
|
+
const gasLeftForPublic = this.gasAllocatedToPublic.sub(this.gasUsedByPublic);
|
|
247
|
+
return gasLeftForPublic;
|
|
240
248
|
}
|
|
241
249
|
}
|
|
242
250
|
|
|
@@ -247,10 +255,18 @@ export class PublicTxContext {
|
|
|
247
255
|
if (phase === TxExecutionPhase.TEARDOWN) {
|
|
248
256
|
this.teardownGasUsed = this.teardownGasUsed.add(gas);
|
|
249
257
|
} else {
|
|
250
|
-
this.
|
|
258
|
+
this.gasUsedByPublic = this.gasUsedByPublic.add(gas);
|
|
251
259
|
}
|
|
252
260
|
}
|
|
253
261
|
|
|
262
|
+
/**
|
|
263
|
+
* The gasUsed by public and private,
|
|
264
|
+
* as if the entire teardown gas limit was consumed.
|
|
265
|
+
*/
|
|
266
|
+
getTotalGasUsed(): Gas {
|
|
267
|
+
return this.gasUsedByPrivate.add(this.gasUsedByPublic);
|
|
268
|
+
}
|
|
269
|
+
|
|
254
270
|
/**
|
|
255
271
|
* Compute the gas used using the actual gas used during teardown instead
|
|
256
272
|
* of the teardown gas limit.
|
|
@@ -261,14 +277,7 @@ export class PublicTxContext {
|
|
|
261
277
|
assert(this.halted, 'Can only compute actual gas used after tx execution ends');
|
|
262
278
|
const requireTeardown = this.teardownCallRequests.length > 0;
|
|
263
279
|
const teardownGasLimits = requireTeardown ? this.gasSettings.teardownGasLimits : Gas.empty();
|
|
264
|
-
return this.
|
|
265
|
-
}
|
|
266
|
-
|
|
267
|
-
/**
|
|
268
|
-
* The gasUsed as if the entire teardown gas limit was consumed.
|
|
269
|
-
*/
|
|
270
|
-
getGasUsedForFee(): Gas {
|
|
271
|
-
return this.gasUsed;
|
|
280
|
+
return this.getTotalGasUsed().sub(teardownGasLimits).add(this.teardownGasUsed);
|
|
272
281
|
}
|
|
273
282
|
|
|
274
283
|
/**
|
|
@@ -288,10 +297,10 @@ export class PublicTxContext {
|
|
|
288
297
|
* Should only be called during or after teardown.
|
|
289
298
|
*/
|
|
290
299
|
private getTransactionFeeUnsafe(): Fr {
|
|
291
|
-
const txFee = this.
|
|
300
|
+
const txFee = this.getTotalGasUsed().computeFee(this.globalVariables.gasFees);
|
|
292
301
|
this.log.debug(`Computed tx fee`, {
|
|
293
302
|
txFee,
|
|
294
|
-
gasUsed: inspect(this.
|
|
303
|
+
gasUsed: inspect(this.getTotalGasUsed()),
|
|
295
304
|
gasFees: inspect(this.globalVariables.gasFees),
|
|
296
305
|
});
|
|
297
306
|
return txFee;
|
|
@@ -324,15 +333,16 @@ export class PublicTxContext {
|
|
|
324
333
|
this.trace,
|
|
325
334
|
this.globalVariables,
|
|
326
335
|
this.startStateReference,
|
|
327
|
-
this.
|
|
336
|
+
/*startGasUsed=*/ this.gasUsedByPrivate,
|
|
328
337
|
this.gasSettings,
|
|
338
|
+
this.feePayer,
|
|
329
339
|
this.setupCallRequests,
|
|
330
340
|
this.appLogicCallRequests,
|
|
331
341
|
this.teardownCallRequests,
|
|
332
342
|
this.nonRevertibleAccumulatedDataFromPrivate,
|
|
333
343
|
this.revertibleAccumulatedDataFromPrivate,
|
|
334
344
|
endTreeSnapshots,
|
|
335
|
-
/*endGasUsed=*/ this.
|
|
345
|
+
/*endGasUsed=*/ this.getTotalGasUsed(),
|
|
336
346
|
this.getTransactionFeeUnsafe(),
|
|
337
347
|
this.revertCode,
|
|
338
348
|
);
|
|
@@ -367,12 +377,12 @@ export class PublicTxContext {
|
|
|
367
377
|
* transaction level one.
|
|
368
378
|
*/
|
|
369
379
|
class PhaseStateManager {
|
|
370
|
-
private log:
|
|
380
|
+
private log: Logger;
|
|
371
381
|
|
|
372
382
|
private currentlyActiveStateManager: AvmPersistableStateManager | undefined;
|
|
373
383
|
|
|
374
384
|
constructor(private readonly txStateManager: AvmPersistableStateManager) {
|
|
375
|
-
this.log =
|
|
385
|
+
this.log = createLogger(`simulator:public_phase_state_manager`);
|
|
376
386
|
}
|
|
377
387
|
|
|
378
388
|
fork() {
|
|
@@ -405,3 +415,13 @@ class PhaseStateManager {
|
|
|
405
415
|
this.currentlyActiveStateManager = undefined;
|
|
406
416
|
}
|
|
407
417
|
}
|
|
418
|
+
|
|
419
|
+
/**
|
|
420
|
+
* Apply L2 gas maximum.
|
|
421
|
+
*/
|
|
422
|
+
function applyMaxToAvailableGas(availableGas: Gas) {
|
|
423
|
+
return new Gas(
|
|
424
|
+
/*daGas=*/ availableGas.daGas,
|
|
425
|
+
/*l2Gas=*/ Math.min(availableGas.l2Gas, MAX_L2_GAS_PER_TX_PUBLIC_PORTION),
|
|
426
|
+
);
|
|
427
|
+
}
|
|
@@ -10,16 +10,10 @@ import {
|
|
|
10
10
|
UnencryptedFunctionL2Logs,
|
|
11
11
|
} from '@aztec/circuit-types';
|
|
12
12
|
import { type AvmSimulationStats } from '@aztec/circuit-types/stats';
|
|
13
|
-
import {
|
|
14
|
-
|
|
15
|
-
Gas,
|
|
16
|
-
type GlobalVariables,
|
|
17
|
-
MAX_L2_GAS_PER_ENQUEUED_CALL,
|
|
18
|
-
type PublicCallRequest,
|
|
19
|
-
type RevertCode,
|
|
20
|
-
} from '@aztec/circuits.js';
|
|
21
|
-
import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log';
|
|
13
|
+
import { type Fr, type Gas, type GlobalVariables, type PublicCallRequest, type RevertCode } from '@aztec/circuits.js';
|
|
14
|
+
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
22
15
|
import { Timer } from '@aztec/foundation/timer';
|
|
16
|
+
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
23
17
|
import { Attributes, type TelemetryClient, type Tracer, trackSpan } from '@aztec/telemetry-client';
|
|
24
18
|
|
|
25
19
|
import { strict as assert } from 'assert';
|
|
@@ -29,6 +23,7 @@ import { type AvmPersistableStateManager, AvmSimulator } from '../avm/index.js';
|
|
|
29
23
|
import { NullifierCollisionError } from '../avm/journal/nullifiers.js';
|
|
30
24
|
import { getPublicFunctionDebugName } from '../common/debug_fn_name.js';
|
|
31
25
|
import { ExecutorMetrics } from './executor_metrics.js';
|
|
26
|
+
import { computeFeePayerBalanceStorageSlot } from './fee_payment.js';
|
|
32
27
|
import { type WorldStateDB } from './public_db_sources.js';
|
|
33
28
|
import { PublicTxContext } from './public_tx_context.js';
|
|
34
29
|
|
|
@@ -53,17 +48,16 @@ export type PublicTxResult = {
|
|
|
53
48
|
export class PublicTxSimulator {
|
|
54
49
|
metrics: ExecutorMetrics;
|
|
55
50
|
|
|
56
|
-
private log:
|
|
51
|
+
private log: Logger;
|
|
57
52
|
|
|
58
53
|
constructor(
|
|
59
54
|
private db: MerkleTreeReadOperations,
|
|
60
55
|
private worldStateDB: WorldStateDB,
|
|
61
56
|
telemetryClient: TelemetryClient,
|
|
62
57
|
private globalVariables: GlobalVariables,
|
|
63
|
-
private realAvmProvingRequests: boolean = true,
|
|
64
58
|
private doMerkleOperations: boolean = false,
|
|
65
59
|
) {
|
|
66
|
-
this.log =
|
|
60
|
+
this.log = createLogger(`simulator:public_tx_simulator`);
|
|
67
61
|
this.metrics = new ExecutorMetrics(telemetryClient, 'PublicTxSimulator');
|
|
68
62
|
}
|
|
69
63
|
|
|
@@ -75,8 +69,9 @@ export class PublicTxSimulator {
|
|
|
75
69
|
* @param tx - The transaction to simulate.
|
|
76
70
|
* @returns The result of the transaction's public execution.
|
|
77
71
|
*/
|
|
78
|
-
async simulate(tx: Tx): Promise<PublicTxResult> {
|
|
79
|
-
|
|
72
|
+
public async simulate(tx: Tx): Promise<PublicTxResult> {
|
|
73
|
+
const txHash = tx.getTxHash();
|
|
74
|
+
this.log.debug(`Simulating ${tx.enqueuedPublicFunctionCalls.length} public calls for tx ${txHash}`, { txHash });
|
|
80
75
|
|
|
81
76
|
const context = await PublicTxContext.create(
|
|
82
77
|
this.db,
|
|
@@ -107,11 +102,14 @@ export class PublicTxSimulator {
|
|
|
107
102
|
const appLogicResult: ProcessedPhase = await this.simulateAppLogicPhase(context);
|
|
108
103
|
processedPhases.push(appLogicResult);
|
|
109
104
|
}
|
|
105
|
+
|
|
110
106
|
if (context.hasPhase(TxExecutionPhase.TEARDOWN)) {
|
|
111
107
|
const teardownResult: ProcessedPhase = await this.simulateTeardownPhase(context);
|
|
112
108
|
processedPhases.push(teardownResult);
|
|
113
109
|
}
|
|
110
|
+
|
|
114
111
|
context.halt();
|
|
112
|
+
await this.payFee(context);
|
|
115
113
|
|
|
116
114
|
const endStateReference = await this.db.getStateReference();
|
|
117
115
|
|
|
@@ -210,7 +208,12 @@ export class PublicTxSimulator {
|
|
|
210
208
|
const callRequests = context.getCallRequestsForPhase(phase);
|
|
211
209
|
const executionRequests = context.getExecutionRequestsForPhase(phase);
|
|
212
210
|
|
|
213
|
-
this.log.debug(`
|
|
211
|
+
this.log.debug(`Processing phase ${TxExecutionPhase[phase]} for tx ${context.getTxHash()}`, {
|
|
212
|
+
txHash: context.getTxHash().toString(),
|
|
213
|
+
phase: TxExecutionPhase[phase],
|
|
214
|
+
callRequests: callRequests.length,
|
|
215
|
+
executionRequests: executionRequests.length,
|
|
216
|
+
});
|
|
214
217
|
|
|
215
218
|
const returnValues: NestedProcessReturnValues[] = [];
|
|
216
219
|
let reverted = false;
|
|
@@ -265,29 +268,22 @@ export class PublicTxSimulator {
|
|
|
265
268
|
): Promise<AvmFinalizedCallResult> {
|
|
266
269
|
const stateManager = context.state.getActiveStateManager();
|
|
267
270
|
const address = executionRequest.callContext.contractAddress;
|
|
268
|
-
const
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
const availableGas = context.getGasLeftForPhase(phase);
|
|
272
|
-
// Gas allocated to an enqueued call can be different from the available gas
|
|
273
|
-
// if there is more gas available than the max allocation per enqueued call.
|
|
274
|
-
const allocatedGas = new Gas(
|
|
275
|
-
/*daGas=*/ availableGas.daGas,
|
|
276
|
-
/*l2Gas=*/ Math.min(availableGas.l2Gas, MAX_L2_GAS_PER_ENQUEUED_CALL),
|
|
277
|
-
);
|
|
271
|
+
const fnName = await getPublicFunctionDebugName(this.worldStateDB, address, executionRequest.args);
|
|
272
|
+
|
|
273
|
+
const allocatedGas = context.getGasLeftAtPhase(phase);
|
|
278
274
|
|
|
279
275
|
const result = await this.simulateEnqueuedCallInternal(
|
|
280
276
|
context.state.getActiveStateManager(),
|
|
281
277
|
executionRequest,
|
|
282
278
|
allocatedGas,
|
|
283
|
-
context.getTransactionFee(phase),
|
|
279
|
+
/*transactionFee=*/ context.getTransactionFee(phase),
|
|
284
280
|
fnName,
|
|
285
281
|
);
|
|
286
282
|
|
|
287
|
-
const gasUsed = allocatedGas.sub(result.gasLeft);
|
|
283
|
+
const gasUsed = allocatedGas.sub(result.gasLeft); // by enqueued call
|
|
288
284
|
context.consumeGas(phase, gasUsed);
|
|
289
|
-
this.log.
|
|
290
|
-
`
|
|
285
|
+
this.log.debug(
|
|
286
|
+
`Simulated enqueued public call consumed ${gasUsed.l2Gas} L2 gas ending with ${result.gasLeft.l2Gas} L2 gas left.`,
|
|
291
287
|
);
|
|
292
288
|
|
|
293
289
|
stateManager.traceEnqueuedCall(callRequest, executionRequest.args, result.reverted);
|
|
@@ -329,18 +325,16 @@ export class PublicTxSimulator {
|
|
|
329
325
|
): Promise<AvmFinalizedCallResult> {
|
|
330
326
|
const address = executionRequest.callContext.contractAddress;
|
|
331
327
|
const sender = executionRequest.callContext.msgSender;
|
|
332
|
-
const selector = executionRequest.callContext.functionSelector;
|
|
333
328
|
|
|
334
|
-
this.log.
|
|
335
|
-
`
|
|
329
|
+
this.log.debug(
|
|
330
|
+
`Executing enqueued public call to external function ${fnName}@${address} with ${allocatedGas.l2Gas} allocated L2 gas.`,
|
|
336
331
|
);
|
|
337
332
|
const timer = new Timer();
|
|
338
333
|
|
|
339
|
-
const simulator = AvmSimulator.create(
|
|
334
|
+
const simulator = await AvmSimulator.create(
|
|
340
335
|
stateManager,
|
|
341
336
|
address,
|
|
342
337
|
sender,
|
|
343
|
-
selector,
|
|
344
338
|
transactionFee,
|
|
345
339
|
this.globalVariables,
|
|
346
340
|
executionRequest.callContext.isStaticCall,
|
|
@@ -350,10 +344,10 @@ export class PublicTxSimulator {
|
|
|
350
344
|
const avmCallResult = await simulator.execute();
|
|
351
345
|
const result = avmCallResult.finalize();
|
|
352
346
|
|
|
353
|
-
this.log.
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
347
|
+
this.log.debug(
|
|
348
|
+
result.reverted
|
|
349
|
+
? `Simulation of enqueued public call ${fnName} reverted with reason ${result.revertReason}.`
|
|
350
|
+
: `Simulation of enqueued public call ${fnName} completed successfully.`,
|
|
357
351
|
{
|
|
358
352
|
eventName: 'avm-simulation',
|
|
359
353
|
appCircuitName: fnName,
|
|
@@ -404,4 +398,30 @@ export class PublicTxSimulator {
|
|
|
404
398
|
}
|
|
405
399
|
}
|
|
406
400
|
}
|
|
401
|
+
|
|
402
|
+
private async payFee(context: PublicTxContext) {
|
|
403
|
+
const txFee = context.getTransactionFee(TxExecutionPhase.TEARDOWN);
|
|
404
|
+
|
|
405
|
+
if (context.feePayer.isZero()) {
|
|
406
|
+
this.log.debug(`No one is paying the fee of ${txFee.toBigInt()}`);
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const feeJuiceAddress = ProtocolContractAddress.FeeJuice;
|
|
411
|
+
const balanceSlot = computeFeePayerBalanceStorageSlot(context.feePayer);
|
|
412
|
+
|
|
413
|
+
this.log.debug(`Deducting ${txFee.toBigInt()} balance in Fee Juice for ${context.feePayer}`);
|
|
414
|
+
const stateManager = context.state.getActiveStateManager();
|
|
415
|
+
|
|
416
|
+
const currentBalance = await stateManager.readStorage(feeJuiceAddress, balanceSlot);
|
|
417
|
+
|
|
418
|
+
if (currentBalance.lt(txFee)) {
|
|
419
|
+
throw new Error(
|
|
420
|
+
`Not enough balance for fee payer to pay for transaction (got ${currentBalance.toBigInt()} needs ${txFee.toBigInt()})`,
|
|
421
|
+
);
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
const updatedBalance = currentBalance.sub(txFee);
|
|
425
|
+
await stateManager.writeStorage(feeJuiceAddress, balanceSlot, updatedBalance, true);
|
|
426
|
+
}
|
|
407
427
|
}
|
|
@@ -10,7 +10,7 @@ import {
|
|
|
10
10
|
import { type AztecAddress } from '@aztec/foundation/aztec-address';
|
|
11
11
|
import { type Fr } from '@aztec/foundation/fields';
|
|
12
12
|
|
|
13
|
-
import { type
|
|
13
|
+
import { type AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
|
|
14
14
|
import { type AvmExecutionEnvironment } from '../avm/avm_execution_environment.js';
|
|
15
15
|
import { type EnqueuedPublicCallExecutionResultWithSideEffects, type PublicFunctionCallResult } from './execution.js';
|
|
16
16
|
|
|
@@ -31,6 +31,7 @@ export interface PublicSideEffectTraceInterface {
|
|
|
31
31
|
contractAddress: AztecAddress,
|
|
32
32
|
slot: Fr, // This is the storage slot not the computed leaf slot
|
|
33
33
|
value: Fr,
|
|
34
|
+
protocolWrite: boolean,
|
|
34
35
|
lowLeafPreimage?: PublicDataTreeLeafPreimage,
|
|
35
36
|
lowLeafIndex?: Fr,
|
|
36
37
|
lowLeafPath?: Fr[],
|
|
@@ -66,6 +67,9 @@ export interface PublicSideEffectTraceInterface {
|
|
|
66
67
|
contractAddress: AztecAddress,
|
|
67
68
|
exists: boolean,
|
|
68
69
|
instance?: SerializableContractInstance,
|
|
70
|
+
lowLeafPreimage?: NullifierLeafPreimage,
|
|
71
|
+
lowLeafIndex?: Fr,
|
|
72
|
+
lowLeafPath?: Fr[],
|
|
69
73
|
): void;
|
|
70
74
|
traceGetBytecode(
|
|
71
75
|
contractAddress: AztecAddress,
|
|
@@ -73,20 +77,9 @@ export interface PublicSideEffectTraceInterface {
|
|
|
73
77
|
bytecode?: Buffer,
|
|
74
78
|
contractInstance?: SerializableContractInstance,
|
|
75
79
|
contractClass?: ContractClassIdPreimage,
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
nestedCallTrace: PublicSideEffectTraceInterface,
|
|
80
|
-
/** The execution environment of the nested call. */
|
|
81
|
-
nestedEnvironment: AvmExecutionEnvironment,
|
|
82
|
-
/** How much gas was available for this public execution. */
|
|
83
|
-
startGasLeft: Gas,
|
|
84
|
-
/** Bytecode used for this execution. */
|
|
85
|
-
bytecode: Buffer,
|
|
86
|
-
/** The call's results */
|
|
87
|
-
avmCallResults: AvmContractCallResult,
|
|
88
|
-
/** Function name */
|
|
89
|
-
functionName: string,
|
|
80
|
+
lowLeafPreimage?: NullifierLeafPreimage,
|
|
81
|
+
lowLeafIndex?: Fr,
|
|
82
|
+
lowLeafPath?: Fr[],
|
|
90
83
|
): void;
|
|
91
84
|
traceEnqueuedCall(
|
|
92
85
|
/** The call request from private that enqueued this call. */
|