@aztec/simulator 0.0.1-commit.2ed92850 → 0.0.1-commit.3469e52
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/public/avm/avm_context.d.ts +3 -3
- package/dest/public/avm/avm_context.d.ts.map +1 -1
- package/dest/public/avm/avm_contract_call_result.d.ts +6 -6
- package/dest/public/avm/avm_contract_call_result.d.ts.map +1 -1
- package/dest/public/avm/avm_contract_call_result.js +3 -3
- package/dest/public/avm/avm_execution_environment.d.ts +5 -6
- package/dest/public/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/public/avm/avm_machine_state.d.ts +5 -6
- package/dest/public/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/public/avm/avm_machine_state.js +2 -3
- package/dest/public/avm/avm_memory_types.d.ts +1 -1
- package/dest/public/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/public/avm/avm_memory_types.js +0 -3
- package/dest/public/avm/avm_simulator.d.ts +2 -3
- package/dest/public/avm/avm_simulator.d.ts.map +1 -1
- package/dest/public/avm/avm_simulator.js +4 -5
- package/dest/public/avm/fixtures/avm_simulation_tester.d.ts +1 -1
- package/dest/public/avm/fixtures/avm_simulation_tester.d.ts.map +1 -1
- package/dest/public/avm/fixtures/avm_simulation_tester.js +2 -3
- package/dest/public/avm/fixtures/initializers.d.ts +1 -1
- package/dest/public/avm/fixtures/initializers.d.ts.map +1 -1
- package/dest/public/avm/fixtures/initializers.js +1 -2
- package/dest/public/avm/opcodes/accrued_substate.d.ts +1 -1
- package/dest/public/avm/opcodes/accrued_substate.d.ts.map +1 -1
- package/dest/public/avm/opcodes/accrued_substate.js +0 -4
- package/dest/public/avm/opcodes/contract.d.ts +1 -1
- package/dest/public/avm/opcodes/contract.d.ts.map +1 -1
- package/dest/public/avm/opcodes/contract.js +4 -4
- package/dest/public/avm/opcodes/external_calls.d.ts +1 -1
- package/dest/public/avm/opcodes/external_calls.d.ts.map +1 -1
- package/dest/public/avm/opcodes/external_calls.js +7 -7
- package/dest/public/avm/opcodes/memory.js +1 -1
- package/dest/public/avm/opcodes/storage.d.ts +12 -13
- package/dest/public/avm/opcodes/storage.d.ts.map +1 -1
- package/dest/public/avm/opcodes/storage.js +20 -30
- package/dest/public/debug_fn_name.d.ts +4 -4
- package/dest/public/debug_fn_name.d.ts.map +1 -1
- package/dest/public/debug_fn_name.js +5 -7
- 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 -20
- package/dest/public/fuzzing/avm_simulator_bin.js +4 -7
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.js +3 -4
- package/package.json +16 -16
- package/src/public/avm/avm_context.ts +2 -2
- package/src/public/avm/avm_contract_call_result.ts +6 -8
- package/src/public/avm/avm_execution_environment.ts +4 -9
- package/src/public/avm/avm_machine_state.ts +5 -6
- package/src/public/avm/avm_memory_types.ts +0 -4
- package/src/public/avm/avm_simulator.ts +5 -8
- package/src/public/avm/fixtures/avm_simulation_tester.ts +2 -8
- package/src/public/avm/fixtures/initializers.ts +1 -2
- package/src/public/avm/opcodes/accrued_substate.ts +0 -6
- package/src/public/avm/opcodes/contract.ts +4 -1
- package/src/public/avm/opcodes/external_calls.ts +7 -8
- package/src/public/avm/opcodes/memory.ts +1 -1
- package/src/public/avm/opcodes/storage.ts +20 -28
- package/src/public/debug_fn_name.ts +8 -10
- package/src/public/fixtures/opcode_spammer.ts +8 -37
- package/src/public/fuzzing/avm_simulator_bin.ts +1 -11
- package/src/public/public_tx_simulator/public_tx_simulator.ts +3 -8
- package/dest/public/avm/calldata.d.ts +0 -51
- package/dest/public/avm/calldata.d.ts.map +0 -1
- package/dest/public/avm/calldata.js +0 -63
- package/src/public/avm/calldata.ts +0 -100
|
@@ -3,8 +3,6 @@ import type { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
|
3
3
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
4
|
import type { GlobalVariables } from '@aztec/stdlib/tx';
|
|
5
5
|
|
|
6
|
-
import type { CallData } from './calldata.js';
|
|
7
|
-
|
|
8
6
|
/**
|
|
9
7
|
* Contains variables that remain constant during AVM execution
|
|
10
8
|
* These variables are provided by the public kernel circuit
|
|
@@ -17,13 +15,13 @@ export class AvmExecutionEnvironment {
|
|
|
17
15
|
public readonly transactionFee: Fr,
|
|
18
16
|
public readonly globals: GlobalVariables,
|
|
19
17
|
public readonly isStaticCall: boolean,
|
|
20
|
-
public readonly calldata:
|
|
18
|
+
public readonly calldata: Fr[],
|
|
21
19
|
public readonly config: PublicSimulatorConfig,
|
|
22
20
|
) {}
|
|
23
21
|
|
|
24
22
|
private deriveEnvironmentForNestedCallInternal(
|
|
25
23
|
targetAddress: AztecAddress,
|
|
26
|
-
calldata:
|
|
24
|
+
calldata: Fr[],
|
|
27
25
|
isStaticCall: boolean,
|
|
28
26
|
): AvmExecutionEnvironment {
|
|
29
27
|
return new AvmExecutionEnvironment(
|
|
@@ -38,14 +36,11 @@ export class AvmExecutionEnvironment {
|
|
|
38
36
|
);
|
|
39
37
|
}
|
|
40
38
|
|
|
41
|
-
public deriveEnvironmentForNestedCall(targetAddress: AztecAddress, calldata:
|
|
39
|
+
public deriveEnvironmentForNestedCall(targetAddress: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment {
|
|
42
40
|
return this.deriveEnvironmentForNestedCallInternal(targetAddress, calldata, /*isStaticCall=*/ false);
|
|
43
41
|
}
|
|
44
42
|
|
|
45
|
-
public deriveEnvironmentForNestedStaticCall(
|
|
46
|
-
targetAddress: AztecAddress,
|
|
47
|
-
calldata: CallData,
|
|
48
|
-
): AvmExecutionEnvironment {
|
|
43
|
+
public deriveEnvironmentForNestedStaticCall(targetAddress: AztecAddress, calldata: Fr[]): AvmExecutionEnvironment {
|
|
49
44
|
return this.deriveEnvironmentForNestedCallInternal(targetAddress, calldata, /*isStaticCall=*/ true);
|
|
50
45
|
}
|
|
51
46
|
}
|
|
@@ -2,7 +2,6 @@ import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
|
2
2
|
|
|
3
3
|
import type { Gas } from './avm_gas.js';
|
|
4
4
|
import { TaggedMemory } from './avm_memory_types.js';
|
|
5
|
-
import { type ReturnData, ReturnDataArray } from './calldata.js';
|
|
6
5
|
import { type AvmRevertReason, OutOfGasError } from './errors.js';
|
|
7
6
|
|
|
8
7
|
/**
|
|
@@ -40,7 +39,7 @@ export class AvmMachineState {
|
|
|
40
39
|
/** program counter of the next instruction, byte based */
|
|
41
40
|
public nextPc: number = 0;
|
|
42
41
|
/** return/revertdata of the last nested call. */
|
|
43
|
-
public nestedReturndata:
|
|
42
|
+
public nestedReturndata: Fr[] = [];
|
|
44
43
|
/** Tracks whether the last external call was successful */
|
|
45
44
|
public nestedCallSuccess: boolean = false;
|
|
46
45
|
/**
|
|
@@ -67,7 +66,7 @@ export class AvmMachineState {
|
|
|
67
66
|
/** Signals that execution has reverted normally (this does not cover exceptional halts) */
|
|
68
67
|
private reverted: boolean = false;
|
|
69
68
|
/** Output data must NOT be modified once it is set */
|
|
70
|
-
private output:
|
|
69
|
+
private output: Fr[] = [];
|
|
71
70
|
|
|
72
71
|
// Metrics only - not needed for execution
|
|
73
72
|
/** instruction counter, including nested calls */
|
|
@@ -130,7 +129,7 @@ export class AvmMachineState {
|
|
|
130
129
|
* Output data must NOT be modified once it is set
|
|
131
130
|
* @param output
|
|
132
131
|
*/
|
|
133
|
-
public return(output:
|
|
132
|
+
public return(output: Fr[]) {
|
|
134
133
|
this.halted = true;
|
|
135
134
|
this.output = output;
|
|
136
135
|
}
|
|
@@ -140,7 +139,7 @@ export class AvmMachineState {
|
|
|
140
139
|
* Output data must NOT be modified once it is set
|
|
141
140
|
* @param output
|
|
142
141
|
*/
|
|
143
|
-
public revert(output:
|
|
142
|
+
public revert(output: Fr[]) {
|
|
144
143
|
this.halted = true;
|
|
145
144
|
this.reverted = true;
|
|
146
145
|
this.output = output;
|
|
@@ -154,7 +153,7 @@ export class AvmMachineState {
|
|
|
154
153
|
return this.reverted;
|
|
155
154
|
}
|
|
156
155
|
|
|
157
|
-
public getOutput():
|
|
156
|
+
public getOutput(): Fr[] {
|
|
158
157
|
return this.output;
|
|
159
158
|
}
|
|
160
159
|
|
|
@@ -369,10 +369,6 @@ export class TaggedMemory implements TaggedMemoryInterface {
|
|
|
369
369
|
* Check tags for all memory in the specified range.
|
|
370
370
|
*/
|
|
371
371
|
public checkTagsRange(tag: TypeTag, startOffset: number, size: number) {
|
|
372
|
-
if (startOffset + size > TaggedMemory.MAX_MEMORY_SIZE) {
|
|
373
|
-
throw new MemorySliceOutOfRangeError(startOffset, size);
|
|
374
|
-
}
|
|
375
|
-
|
|
376
372
|
for (let offset = startOffset; offset < startOffset + size; offset++) {
|
|
377
373
|
this.checkTag(tag, offset);
|
|
378
374
|
}
|
|
@@ -15,7 +15,6 @@ import { AvmExecutionEnvironment } from './avm_execution_environment.js';
|
|
|
15
15
|
import type { Gas } from './avm_gas.js';
|
|
16
16
|
import { AvmMachineState } from './avm_machine_state.js';
|
|
17
17
|
import type { AvmSimulatorInterface } from './avm_simulator_interface.js';
|
|
18
|
-
import { type CallData, ReturnDataArray } from './calldata.js';
|
|
19
18
|
import { AvmRevertReason, InvalidProgramCounterError } from './errors.js';
|
|
20
19
|
import type { Instruction } from './opcodes/instruction.js';
|
|
21
20
|
import { revertReasonFromExceptionalHalt, revertReasonFromExplicitRevert } from './revert_reason.js';
|
|
@@ -50,7 +49,7 @@ export class AvmSimulator implements AvmSimulatorInterface {
|
|
|
50
49
|
// This will be used by the CALL opcode to create a new simulator. It is required to
|
|
51
50
|
// avoid a dependency cycle.
|
|
52
51
|
context.provideSimulator = AvmSimulator.build;
|
|
53
|
-
this.log = createLogger(`simulator:avm(calldata[0]: ${context.environment.calldata
|
|
52
|
+
this.log = createLogger(`simulator:avm(calldata[0]: ${context.environment.calldata[0]})`);
|
|
54
53
|
// Turn on tallying if explicitly enabled or if trace logging
|
|
55
54
|
if (enableTallying || this.log.isLevelEnabled('trace')) {
|
|
56
55
|
this.tallyPrintFunction = this.printOpcodeTallies;
|
|
@@ -75,7 +74,7 @@ export class AvmSimulator implements AvmSimulatorInterface {
|
|
|
75
74
|
transactionFee: Fr,
|
|
76
75
|
globals: GlobalVariables,
|
|
77
76
|
isStaticCall: boolean,
|
|
78
|
-
calldata:
|
|
77
|
+
calldata: Fr[],
|
|
79
78
|
allocatedGas: Gas,
|
|
80
79
|
config: PublicSimulatorConfig,
|
|
81
80
|
) {
|
|
@@ -184,9 +183,7 @@ export class AvmSimulator implements AvmSimulatorInterface {
|
|
|
184
183
|
|
|
185
184
|
const output = machineState.getOutput();
|
|
186
185
|
const reverted = machineState.getReverted();
|
|
187
|
-
const revertReason = reverted
|
|
188
|
-
? await revertReasonFromExplicitRevert(output.bestEffortReadAll(), this.context)
|
|
189
|
-
: undefined;
|
|
186
|
+
const revertReason = reverted ? await revertReasonFromExplicitRevert(output, this.context) : undefined;
|
|
190
187
|
const results = new AvmContractCallResult(
|
|
191
188
|
reverted,
|
|
192
189
|
output,
|
|
@@ -223,7 +220,7 @@ export class AvmSimulator implements AvmSimulatorInterface {
|
|
|
223
220
|
// Note: "exceptional halts" cannot return data, hence [].
|
|
224
221
|
const results = new AvmContractCallResult(
|
|
225
222
|
/*reverted=*/ true,
|
|
226
|
-
/*output=*/
|
|
223
|
+
/*output=*/ [],
|
|
227
224
|
noGasLeft,
|
|
228
225
|
revertReason,
|
|
229
226
|
machineState.instrCounter,
|
|
@@ -253,7 +250,7 @@ export class AvmSimulator implements AvmSimulatorInterface {
|
|
|
253
250
|
this.log.warn(message);
|
|
254
251
|
return new AvmContractCallResult(
|
|
255
252
|
/*reverted=*/ true,
|
|
256
|
-
/*output=*/
|
|
253
|
+
/*output=*/ [],
|
|
257
254
|
/*gasLeft=*/ { l2Gas: 0, daGas: 0 }, // consumes all allocated gas
|
|
258
255
|
revertReason,
|
|
259
256
|
);
|
|
@@ -13,7 +13,6 @@ import { SimpleContractDataSource } from '../../fixtures/simple_contract_data_so
|
|
|
13
13
|
import { PublicContractsDB, PublicTreesDB } from '../../public_db_sources.js';
|
|
14
14
|
import { PublicPersistableStateManager } from '../../state_manager/state_manager.js';
|
|
15
15
|
import { AvmSimulator } from '../avm_simulator.js';
|
|
16
|
-
import { CallDataArray } from '../calldata.js';
|
|
17
16
|
import { BaseAvmSimulationTester } from './base_avm_simulation_tester.js';
|
|
18
17
|
import { initContext, initExecutionEnvironment } from './initializers.js';
|
|
19
18
|
import {
|
|
@@ -90,7 +89,7 @@ export class AvmSimulationTester extends BaseAvmSimulationTester {
|
|
|
90
89
|
collectCallMetadata: true,
|
|
91
90
|
});
|
|
92
91
|
const environment = initExecutionEnvironment({
|
|
93
|
-
calldata
|
|
92
|
+
calldata,
|
|
94
93
|
globals,
|
|
95
94
|
address,
|
|
96
95
|
sender,
|
|
@@ -106,12 +105,7 @@ export class AvmSimulationTester extends BaseAvmSimulationTester {
|
|
|
106
105
|
if (result.reverted) {
|
|
107
106
|
this.logger.error(`Error in ${fnName}:`);
|
|
108
107
|
this.logger.error(
|
|
109
|
-
resolveContractAssertionMessage(
|
|
110
|
-
fnName,
|
|
111
|
-
result.revertReason!,
|
|
112
|
-
result.output.bestEffortReadAll(),
|
|
113
|
-
contractArtifact,
|
|
114
|
-
)!,
|
|
108
|
+
resolveContractAssertionMessage(fnName, result.revertReason!, result.output, contractArtifact)!,
|
|
115
109
|
);
|
|
116
110
|
} else {
|
|
117
111
|
this.logger.info(`Simulation of function ${fnName} succeeded!`);
|
|
@@ -19,7 +19,6 @@ import { AvmContext } from '../avm_context.js';
|
|
|
19
19
|
import { AvmExecutionEnvironment } from '../avm_execution_environment.js';
|
|
20
20
|
import { AvmMachineState } from '../avm_machine_state.js';
|
|
21
21
|
import { AvmSimulator } from '../avm_simulator.js';
|
|
22
|
-
import { CallDataArray } from '../calldata.js';
|
|
23
22
|
import { DEFAULT_TIMESTAMP } from './utils.js';
|
|
24
23
|
|
|
25
24
|
/**
|
|
@@ -71,7 +70,7 @@ export function initExecutionEnvironment(overrides?: Partial<AvmExecutionEnviron
|
|
|
71
70
|
overrides?.transactionFee ?? Fr.zero(),
|
|
72
71
|
overrides?.globals ?? GlobalVariables.empty(),
|
|
73
72
|
overrides?.isStaticCall ?? false,
|
|
74
|
-
overrides?.calldata ??
|
|
73
|
+
overrides?.calldata ?? [],
|
|
75
74
|
overrides?.config ?? PublicSimulatorConfig.empty(),
|
|
76
75
|
);
|
|
77
76
|
}
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { MAX_ETH_ADDRESS_VALUE } from '@aztec/constants';
|
|
2
|
-
|
|
3
1
|
import { NullifierCollisionError } from '../../side_effect_errors.js';
|
|
4
2
|
import type { AvmContext } from '../avm_context.js';
|
|
5
3
|
import { TypeTag, Uint1 } from '../avm_memory_types.js';
|
|
@@ -284,10 +282,6 @@ export class SendL2ToL1Message extends Instruction {
|
|
|
284
282
|
memory.checkTags(TypeTag.FIELD, recipientOffset, contentOffset);
|
|
285
283
|
|
|
286
284
|
const recipient = memory.get(recipientOffset).toFr();
|
|
287
|
-
|
|
288
|
-
if (recipient.toBigInt() > MAX_ETH_ADDRESS_VALUE) {
|
|
289
|
-
throw new InstructionExecutionError(`SENDL2TOL1MSG: Recipient address is too large`);
|
|
290
|
-
}
|
|
291
285
|
const content = memory.get(contentOffset).toFr();
|
|
292
286
|
context.persistableState.writeL2ToL1Message(context.environment.address, recipient, content);
|
|
293
287
|
}
|
|
@@ -67,6 +67,9 @@ export class GetContractInstance extends Instruction {
|
|
|
67
67
|
}
|
|
68
68
|
}
|
|
69
69
|
|
|
70
|
-
|
|
70
|
+
const existsOffset = dstOffset;
|
|
71
|
+
const memberValueOffset = dstOffset + 1;
|
|
72
|
+
memory.set(existsOffset, new Uint1(exists ? 1 : 0));
|
|
73
|
+
memory.set(memberValueOffset, memberValue);
|
|
71
74
|
}
|
|
72
75
|
}
|
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import type { AvmContext } from '../avm_context.js';
|
|
2
2
|
import type { AvmContractCallResult } from '../avm_contract_call_result.js';
|
|
3
3
|
import { type Field, TypeTag, Uint1 } from '../avm_memory_types.js';
|
|
4
|
-
import { CallDataMemory, ReturnDataMemory } from '../calldata.js';
|
|
5
4
|
import { Opcode, OperandType } from '../serialization/instruction_serialization.js';
|
|
6
5
|
import { Addressing } from './addressing_mode.js';
|
|
7
6
|
import { Instruction } from './instruction.js';
|
|
@@ -46,8 +45,8 @@ abstract class ExternalCall extends Instruction {
|
|
|
46
45
|
memory.checkTag(TypeTag.UINT32, argsSizeOffset);
|
|
47
46
|
|
|
48
47
|
const calldataSize = memory.get(argsSizeOffset).toNumber();
|
|
49
|
-
|
|
50
|
-
const calldata =
|
|
48
|
+
// This is a DOS vector. CalldataSize is chosen by the bytecode, and can be arbitrarily large leading to a OOM here.
|
|
49
|
+
const calldata = memory.getSlice(argsOffset, calldataSize).map(f => f.toFr());
|
|
51
50
|
|
|
52
51
|
const callAddress = memory.getAs<Field>(addrOffset);
|
|
53
52
|
// If we are already in a static call, we propagate the environment.
|
|
@@ -74,8 +73,8 @@ abstract class ExternalCall extends Instruction {
|
|
|
74
73
|
const success = !nestedCallResults.reverted;
|
|
75
74
|
|
|
76
75
|
// Save return/revert data for later.
|
|
77
|
-
const
|
|
78
|
-
context.machineState.nestedReturndata =
|
|
76
|
+
const fullReturnData = nestedCallResults.output;
|
|
77
|
+
context.machineState.nestedReturndata = fullReturnData;
|
|
79
78
|
|
|
80
79
|
// Track the success status directly
|
|
81
80
|
context.machineState.nestedCallSuccess = success;
|
|
@@ -90,7 +89,7 @@ abstract class ExternalCall extends Instruction {
|
|
|
90
89
|
// (in Noir code).
|
|
91
90
|
if (!success) {
|
|
92
91
|
context.machineState.collectedRevertInfo = {
|
|
93
|
-
revertDataRepresentative:
|
|
92
|
+
revertDataRepresentative: fullReturnData,
|
|
94
93
|
recursiveRevertReason: nestedCallResults.revertReason!,
|
|
95
94
|
};
|
|
96
95
|
}
|
|
@@ -196,7 +195,7 @@ export class Return extends Instruction {
|
|
|
196
195
|
memory.checkTag(TypeTag.UINT32, returnSizeOffset);
|
|
197
196
|
const returnSize = memory.get(returnSizeOffset).toNumber();
|
|
198
197
|
|
|
199
|
-
const output =
|
|
198
|
+
const output = memory.getSlice(returnOffset, returnSize).map(word => word.toFr());
|
|
200
199
|
|
|
201
200
|
context.machineState.return(output);
|
|
202
201
|
}
|
|
@@ -244,7 +243,7 @@ export class Revert extends Instruction {
|
|
|
244
243
|
|
|
245
244
|
memory.checkTag(TypeTag.UINT32, retSizeOffset);
|
|
246
245
|
const retSize = memory.get(retSizeOffset).toNumber();
|
|
247
|
-
const output =
|
|
246
|
+
const output = memory.getSlice(returnOffset, retSize).map(word => word.toFr());
|
|
248
247
|
|
|
249
248
|
context.machineState.revert(output);
|
|
250
249
|
}
|
|
@@ -242,7 +242,7 @@ export class ReturndataSize extends Instruction {
|
|
|
242
242
|
const operands = [this.dstOffset];
|
|
243
243
|
const [dstOffset] = addressing.resolve(operands, memory);
|
|
244
244
|
|
|
245
|
-
memory.set(dstOffset, new Uint32(context.machineState.nestedReturndata.length
|
|
245
|
+
memory.set(dstOffset, new Uint32(context.machineState.nestedReturndata.length));
|
|
246
246
|
}
|
|
247
247
|
}
|
|
248
248
|
|
|
@@ -5,9 +5,7 @@ import { Opcode, OperandType } from '../serialization/instruction_serialization.
|
|
|
5
5
|
import { Addressing } from './addressing_mode.js';
|
|
6
6
|
import { Instruction } from './instruction.js';
|
|
7
7
|
|
|
8
|
-
|
|
9
|
-
static readonly type: string = 'SSTORE';
|
|
10
|
-
static readonly opcode = Opcode.SSTORE;
|
|
8
|
+
abstract class BaseStorageInstruction extends Instruction {
|
|
11
9
|
// Informs (de)serialization. See Instruction.deserialize.
|
|
12
10
|
public static readonly wireFormat: OperandType[] = [
|
|
13
11
|
OperandType.UINT8,
|
|
@@ -17,12 +15,21 @@ export class SStore extends Instruction {
|
|
|
17
15
|
];
|
|
18
16
|
|
|
19
17
|
constructor(
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
18
|
+
protected addressingMode: number,
|
|
19
|
+
protected aOffset: number,
|
|
20
|
+
protected bOffset: number,
|
|
23
21
|
) {
|
|
24
22
|
super();
|
|
25
23
|
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export class SStore extends BaseStorageInstruction {
|
|
27
|
+
static readonly type: string = 'SSTORE';
|
|
28
|
+
static readonly opcode = Opcode.SSTORE;
|
|
29
|
+
|
|
30
|
+
constructor(addressingMode: number, srcOffset: number, slotOffset: number) {
|
|
31
|
+
super(addressingMode, srcOffset, slotOffset);
|
|
32
|
+
}
|
|
26
33
|
|
|
27
34
|
public async execute(context: AvmContext): Promise<void> {
|
|
28
35
|
if (context.environment.isStaticCall) {
|
|
@@ -36,7 +43,7 @@ export class SStore extends Instruction {
|
|
|
36
43
|
this.baseGasCost(addressing.indirectOperandsCount(), addressing.relativeOperandsCount()),
|
|
37
44
|
);
|
|
38
45
|
|
|
39
|
-
const operands = [this.
|
|
46
|
+
const operands = [this.aOffset, this.bOffset];
|
|
40
47
|
const [srcOffset, slotOffset] = addressing.resolve(operands, memory);
|
|
41
48
|
// We read before tag checking since it's needed for gas cost calculation
|
|
42
49
|
const slot = memory.get(slotOffset).toFr();
|
|
@@ -53,25 +60,12 @@ export class SStore extends Instruction {
|
|
|
53
60
|
}
|
|
54
61
|
}
|
|
55
62
|
|
|
56
|
-
export class SLoad extends
|
|
63
|
+
export class SLoad extends BaseStorageInstruction {
|
|
57
64
|
static readonly type: string = 'SLOAD';
|
|
58
65
|
static readonly opcode = Opcode.SLOAD;
|
|
59
|
-
// Informs (de)serialization. See Instruction.deserialize.
|
|
60
|
-
public static readonly wireFormat: OperandType[] = [
|
|
61
|
-
OperandType.UINT8,
|
|
62
|
-
OperandType.UINT8,
|
|
63
|
-
OperandType.UINT16,
|
|
64
|
-
OperandType.UINT16,
|
|
65
|
-
OperandType.UINT16,
|
|
66
|
-
];
|
|
67
66
|
|
|
68
|
-
constructor(
|
|
69
|
-
|
|
70
|
-
private slotOffset: number,
|
|
71
|
-
private contractAddressOffset: number,
|
|
72
|
-
private dstOffset: number,
|
|
73
|
-
) {
|
|
74
|
-
super();
|
|
67
|
+
constructor(addressingMode: number, slotOffset: number, dstOffset: number) {
|
|
68
|
+
super(addressingMode, slotOffset, dstOffset);
|
|
75
69
|
}
|
|
76
70
|
|
|
77
71
|
public async execute(context: AvmContext): Promise<void> {
|
|
@@ -82,14 +76,12 @@ export class SLoad extends Instruction {
|
|
|
82
76
|
this.baseGasCost(addressing.indirectOperandsCount(), addressing.relativeOperandsCount()),
|
|
83
77
|
);
|
|
84
78
|
|
|
85
|
-
const operands = [this.
|
|
86
|
-
const [slotOffset,
|
|
79
|
+
const operands = [this.aOffset, this.bOffset];
|
|
80
|
+
const [slotOffset, dstOffset] = addressing.resolve(operands, memory);
|
|
87
81
|
memory.checkTag(TypeTag.FIELD, slotOffset);
|
|
88
|
-
memory.checkTag(TypeTag.FIELD, contractAddressOffset);
|
|
89
82
|
|
|
90
83
|
const slot = memory.get(slotOffset).toFr();
|
|
91
|
-
const
|
|
92
|
-
const value = await context.persistableState.readStorage(contractAddress, slot);
|
|
84
|
+
const value = await context.persistableState.readStorage(context.environment.address, slot);
|
|
93
85
|
memory.set(dstOffset, new Field(value));
|
|
94
86
|
}
|
|
95
87
|
}
|
|
@@ -1,21 +1,20 @@
|
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
1
2
|
import { FunctionSelector } from '@aztec/stdlib/abi';
|
|
2
3
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
4
|
|
|
4
|
-
import type { CallData } from './avm/calldata.js';
|
|
5
5
|
import type { PublicContractsDBInterface } from './db_interfaces.js';
|
|
6
6
|
|
|
7
7
|
export async function getPublicFunctionDebugName(
|
|
8
8
|
db: PublicContractsDBInterface,
|
|
9
9
|
contractAddress: AztecAddress,
|
|
10
|
-
calldata:
|
|
10
|
+
calldata: Fr[],
|
|
11
11
|
): Promise<string> {
|
|
12
12
|
// Public function is dispatched and therefore the target function is passed in the first argument.
|
|
13
|
-
|
|
14
|
-
if (!selectorField) {
|
|
13
|
+
if (!calldata[0]) {
|
|
15
14
|
return `<calldata[0] undefined> (Contract Address: ${contractAddress})`;
|
|
16
15
|
}
|
|
17
|
-
const fallbackName = `<calldata[0]:${
|
|
18
|
-
const selector = FunctionSelector.fromFieldOrUndefined(
|
|
16
|
+
const fallbackName = `<calldata[0]:${calldata[0].toString()}> (Contract Address: ${contractAddress})`;
|
|
17
|
+
const selector = FunctionSelector.fromFieldOrUndefined(calldata[0]);
|
|
19
18
|
if (!selector) {
|
|
20
19
|
return fallbackName;
|
|
21
20
|
}
|
|
@@ -33,14 +32,13 @@ export async function getPublicFunctionDebugName(
|
|
|
33
32
|
export async function getPublicFunctionSelectorAndName(
|
|
34
33
|
db: PublicContractsDBInterface,
|
|
35
34
|
contractAddress: AztecAddress,
|
|
36
|
-
calldata:
|
|
35
|
+
calldata: Fr[],
|
|
37
36
|
): Promise<{ functionSelector?: FunctionSelector; functionName?: string }> {
|
|
38
37
|
// Public function is dispatched and therefore the target function is passed in the first argument.
|
|
39
|
-
|
|
40
|
-
if (!selectorField) {
|
|
38
|
+
if (!calldata[0]) {
|
|
41
39
|
return {};
|
|
42
40
|
}
|
|
43
|
-
const selector = FunctionSelector.fromFieldOrUndefined(
|
|
41
|
+
const selector = FunctionSelector.fromFieldOrUndefined(calldata[0]);
|
|
44
42
|
if (!selector) {
|
|
45
43
|
return {};
|
|
46
44
|
}
|
|
@@ -966,63 +966,34 @@ export const SPAM_CONFIGS: Partial<Record<Opcode, SpamConfig[]>> = {
|
|
|
966
966
|
[Opcode.SLOAD]: [
|
|
967
967
|
{
|
|
968
968
|
label: 'Cold read (slot not written)',
|
|
969
|
-
setup: [
|
|
970
|
-
|
|
971
|
-
() => [
|
|
972
|
-
// Get current contract address into offset 1
|
|
973
|
-
new GetEnvVar(/*addressing_mode=*/ 0, /*dstOffset=*/ 1, /*varEnum=*/ 0).as(
|
|
974
|
-
Opcode.GETENVVAR_16,
|
|
975
|
-
GetEnvVar.wireFormat16,
|
|
976
|
-
),
|
|
977
|
-
],
|
|
978
|
-
],
|
|
979
|
-
targetInstructions: () => [
|
|
980
|
-
new SLoad(/*addressing_mode=*/ 0, /*slotOffset=*/ 0, /*contractAddressOffset=*/ 1, /*dstOffset=*/ 2),
|
|
981
|
-
],
|
|
969
|
+
setup: [{ offset: 0, value: new Field(Fr.random()) }], // random slot
|
|
970
|
+
targetInstructions: () => [new SLoad(/*addressing_mode=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1)],
|
|
982
971
|
},
|
|
983
972
|
{
|
|
984
973
|
label: 'Warm read (from tree)',
|
|
985
974
|
// Uses pre-inserted storage from insertWarmTreeEntries() which is called after contract deployment
|
|
986
|
-
setup: [
|
|
987
|
-
|
|
988
|
-
() => [
|
|
989
|
-
// Get current contract address into offset 1
|
|
990
|
-
new GetEnvVar(/*addressing_mode=*/ 0, /*dstOffset=*/ 1, /*varEnum=*/ 0).as(
|
|
991
|
-
Opcode.GETENVVAR_16,
|
|
992
|
-
GetEnvVar.wireFormat16,
|
|
993
|
-
),
|
|
994
|
-
],
|
|
995
|
-
],
|
|
996
|
-
targetInstructions: () => [
|
|
997
|
-
new SLoad(/*addressing_mode=*/ 0, /*slotOffset=*/ 0, /*contractAddressOffset=*/ 1, /*dstOffset=*/ 2),
|
|
998
|
-
],
|
|
975
|
+
setup: [{ offset: 0, value: new Field(WARM_STORAGE_SLOT) }], // pre-inserted slot
|
|
976
|
+
targetInstructions: () => [new SLoad(/*addressing_mode=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 1)],
|
|
999
977
|
},
|
|
1000
978
|
{
|
|
1001
979
|
label: 'Warm read (SSTORE first, unique slot per SLOAD)',
|
|
1002
|
-
// Memory layout: slot (incremented), value, constant 1,
|
|
980
|
+
// Memory layout: slot (incremented), value, constant 1, revertSize, loaded value
|
|
1003
981
|
setup: [
|
|
1004
982
|
{ offset: 0, value: new Field(Fr.random()) }, // slot (will be incremented)
|
|
1005
983
|
{ offset: 1, value: new Field(Fr.random()) }, // value to store
|
|
1006
984
|
{ offset: 2, value: new Field(1n) }, // constant 1 for ADD
|
|
1007
|
-
()
|
|
1008
|
-
// Get current contract address into offset 3
|
|
1009
|
-
new GetEnvVar(/*addressing_mode=*/ 0, /*dstOffset=*/ 3, /*varEnum=*/ 0).as(
|
|
1010
|
-
Opcode.GETENVVAR_16,
|
|
1011
|
-
GetEnvVar.wireFormat16,
|
|
1012
|
-
),
|
|
1013
|
-
],
|
|
1014
|
-
{ offset: 4, value: new Uint32(0n) }, // revertSize
|
|
985
|
+
{ offset: 3, value: new Uint32(0n) }, // revertSize
|
|
1015
986
|
],
|
|
1016
987
|
targetInstructions: () => [
|
|
1017
988
|
new SStore(/*addressing_mode=*/ 0, /*srcOffset=*/ 1, /*slotOffset=*/ 0),
|
|
1018
|
-
new SLoad(/*addressing_mode=*/ 0, /*slotOffset=*/ 0, /*
|
|
989
|
+
new SLoad(/*addressing_mode=*/ 0, /*slotOffset=*/ 0, /*dstOffset=*/ 4),
|
|
1019
990
|
new Add(/*addressing_mode=*/ 0, /*aOffset=*/ 0, /*bOffset=*/ 2, /*dstOffset=*/ 0).as(
|
|
1020
991
|
Opcode.ADD_8,
|
|
1021
992
|
Add.wireFormat8,
|
|
1022
993
|
), // slot++
|
|
1023
994
|
],
|
|
1024
995
|
cleanupInstructions: () => [
|
|
1025
|
-
new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/
|
|
996
|
+
new Revert(/*addressing_mode=*/ 0, /*retSizeOffset=*/ 3, /*returnOffset=*/ 0).as(
|
|
1026
997
|
Opcode.REVERT_8,
|
|
1027
998
|
Revert.wireFormat8,
|
|
1028
999
|
),
|
|
@@ -3,7 +3,6 @@ import { EthAddress } from '@aztec/foundation/eth-address';
|
|
|
3
3
|
import {
|
|
4
4
|
AvmCircuitPublicInputs,
|
|
5
5
|
type AvmTxHint,
|
|
6
|
-
PublicTxEffect,
|
|
7
6
|
deserializeFromMessagePack,
|
|
8
7
|
serializeWithMessagePack,
|
|
9
8
|
} from '@aztec/stdlib/avm';
|
|
@@ -59,13 +58,7 @@ async function simulateWithFuzzer(
|
|
|
59
58
|
rawPublicDataWrites: any[], // Public data tree writes to apply before simulation
|
|
60
59
|
rawNoteHashes: any[], // Note hashes to apply before simulation
|
|
61
60
|
protocolContracts: ProtocolContracts, // Protocol contracts mapping from C++
|
|
62
|
-
): Promise<{
|
|
63
|
-
reverted: boolean;
|
|
64
|
-
output: Fr[];
|
|
65
|
-
revertReason?: string;
|
|
66
|
-
publicInputs: AvmCircuitPublicInputs;
|
|
67
|
-
publicTxEffect: PublicTxEffect;
|
|
68
|
-
}> {
|
|
61
|
+
): Promise<{ reverted: boolean; output: Fr[]; revertReason?: string; publicInputs: AvmCircuitPublicInputs }> {
|
|
69
62
|
const worldStateService = await openExistingWorldState(dataDir, mapSizeKb);
|
|
70
63
|
|
|
71
64
|
const simulator = await AvmFuzzerSimulator.create(worldStateService, globals, protocolContracts);
|
|
@@ -97,7 +90,6 @@ async function simulateWithFuzzer(
|
|
|
97
90
|
output,
|
|
98
91
|
revertReason: result.findRevertReason()?.message,
|
|
99
92
|
publicInputs: result.publicInputs!,
|
|
100
|
-
publicTxEffect: result.publicTxEffect,
|
|
101
93
|
};
|
|
102
94
|
}
|
|
103
95
|
|
|
@@ -127,7 +119,6 @@ async function execute(base64Line: string): Promise<void> {
|
|
|
127
119
|
output: result.output,
|
|
128
120
|
revertReason: result.revertReason ?? '',
|
|
129
121
|
endTreeSnapshots: result.publicInputs.endTreeSnapshots,
|
|
130
|
-
publicTxEffect: result.publicTxEffect,
|
|
131
122
|
});
|
|
132
123
|
const base64Response = resultBuffer.toString('base64') + '\n';
|
|
133
124
|
await writeOutput(base64Response);
|
|
@@ -138,7 +129,6 @@ async function execute(base64Line: string): Promise<void> {
|
|
|
138
129
|
output: [] as Fr[],
|
|
139
130
|
revertReason: `Unexpected Error ${error.message}`,
|
|
140
131
|
endTreeSnapshots: TreeSnapshots.empty(),
|
|
141
|
-
publicTxEffect: PublicTxEffect.empty(),
|
|
142
132
|
});
|
|
143
133
|
await writeOutput(errorResult.toString('base64') + '\n');
|
|
144
134
|
}
|
|
@@ -19,7 +19,6 @@ import {
|
|
|
19
19
|
import { strict as assert } from 'assert';
|
|
20
20
|
|
|
21
21
|
import type { AvmFinalizedCallResult } from '../avm/avm_contract_call_result.js';
|
|
22
|
-
import { CallDataArray } from '../avm/calldata.js';
|
|
23
22
|
import { AvmSimulator } from '../avm/index.js';
|
|
24
23
|
import { getPublicFunctionDebugName } from '../debug_fn_name.js';
|
|
25
24
|
import { HintingMerkleWriteOperations, HintingPublicContractsDB } from '../hinting_db_sources.js';
|
|
@@ -268,7 +267,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
|
|
|
268
267
|
|
|
269
268
|
const enqueuedCallResult = await this.simulateEnqueuedCall(phase, context, callRequest);
|
|
270
269
|
|
|
271
|
-
returnValues.push(new NestedProcessReturnValues(enqueuedCallResult.output
|
|
270
|
+
returnValues.push(new NestedProcessReturnValues(enqueuedCallResult.output));
|
|
272
271
|
|
|
273
272
|
if (enqueuedCallResult.reverted) {
|
|
274
273
|
reverted = true;
|
|
@@ -298,11 +297,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
|
|
|
298
297
|
): Promise<AvmFinalizedCallResult> {
|
|
299
298
|
const stateManager = context.state.getActiveStateManager();
|
|
300
299
|
const contractAddress = callRequest.request.contractAddress;
|
|
301
|
-
const fnName = await getPublicFunctionDebugName(
|
|
302
|
-
this.contractsDB,
|
|
303
|
-
contractAddress,
|
|
304
|
-
new CallDataArray(callRequest.calldata),
|
|
305
|
-
);
|
|
300
|
+
const fnName = await getPublicFunctionDebugName(this.contractsDB, contractAddress, callRequest.calldata);
|
|
306
301
|
|
|
307
302
|
const allocatedGas = context.getGasLeftAtPhase(phase);
|
|
308
303
|
|
|
@@ -362,7 +357,7 @@ export class PublicTxSimulator implements PublicTxSimulatorInterface {
|
|
|
362
357
|
transactionFee,
|
|
363
358
|
this.globalVariables,
|
|
364
359
|
request.isStaticCall,
|
|
365
|
-
|
|
360
|
+
calldata,
|
|
366
361
|
allocatedGas,
|
|
367
362
|
this.config,
|
|
368
363
|
);
|
|
@@ -1,51 +0,0 @@
|
|
|
1
|
-
import type { Fr } from '@aztec/foundation/schemas';
|
|
2
|
-
import { TaggedMemory } from './avm_memory_types.js';
|
|
3
|
-
export interface LazyReader {
|
|
4
|
-
bestEffortReadAll(readCap?: number): Fr[];
|
|
5
|
-
readAll(): Fr[];
|
|
6
|
-
read(idx: number): Fr | undefined;
|
|
7
|
-
slice(start: number, end: number): Fr[];
|
|
8
|
-
length(): number;
|
|
9
|
-
}
|
|
10
|
-
export declare class LazyReaderMemory implements LazyReader {
|
|
11
|
-
private memory;
|
|
12
|
-
private offset;
|
|
13
|
-
private size;
|
|
14
|
-
constructor(memory: TaggedMemory, offset: number, size: number);
|
|
15
|
-
bestEffortReadAll(readCap?: number): Fr[];
|
|
16
|
-
read(idx: number): Fr | undefined;
|
|
17
|
-
slice(start: number, end: number): Fr[];
|
|
18
|
-
readAll(): Fr[];
|
|
19
|
-
length(): number;
|
|
20
|
-
}
|
|
21
|
-
export declare class LazyReaderArray implements LazyReader {
|
|
22
|
-
private array;
|
|
23
|
-
constructor(array: Fr[]);
|
|
24
|
-
bestEffortReadAll(readCap?: number): Fr[];
|
|
25
|
-
read(idx: number): Fr | undefined;
|
|
26
|
-
slice(start: number, end: number): Fr[];
|
|
27
|
-
readAll(): Fr[];
|
|
28
|
-
length(): number;
|
|
29
|
-
}
|
|
30
|
-
declare const CallDataBrand: unique symbol;
|
|
31
|
-
declare const ReturnDataBrand: unique symbol;
|
|
32
|
-
export type CallData = LazyReader & {
|
|
33
|
-
readonly [CallDataBrand]: true;
|
|
34
|
-
};
|
|
35
|
-
export type ReturnData = LazyReader & {
|
|
36
|
-
readonly [ReturnDataBrand]: true;
|
|
37
|
-
};
|
|
38
|
-
export declare class CallDataArray extends LazyReaderArray implements CallData {
|
|
39
|
-
readonly [CallDataBrand]: true;
|
|
40
|
-
}
|
|
41
|
-
export declare class CallDataMemory extends LazyReaderMemory implements CallData {
|
|
42
|
-
readonly [CallDataBrand]: true;
|
|
43
|
-
}
|
|
44
|
-
export declare class ReturnDataArray extends LazyReaderArray implements ReturnData {
|
|
45
|
-
readonly [ReturnDataBrand]: true;
|
|
46
|
-
}
|
|
47
|
-
export declare class ReturnDataMemory extends LazyReaderMemory implements ReturnData {
|
|
48
|
-
readonly [ReturnDataBrand]: true;
|
|
49
|
-
}
|
|
50
|
-
export {};
|
|
51
|
-
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY2FsbGRhdGEuZC50cyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uLy4uL3NyYy9wdWJsaWMvYXZtL2NhbGxkYXRhLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sS0FBSyxFQUFFLEVBQUUsRUFBRSxNQUFNLDJCQUEyQixDQUFDO0FBRXBELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUtyRCxNQUFNLFdBQVcsVUFBVTtJQUN6QixpQkFBaUIsQ0FBQyxPQUFPLENBQUMsRUFBRSxNQUFNLEdBQUcsRUFBRSxFQUFFLENBQUM7SUFDMUMsT0FBTyxJQUFJLEVBQUUsRUFBRSxDQUFDO0lBQ2hCLElBQUksQ0FBQyxHQUFHLEVBQUUsTUFBTSxHQUFHLEVBQUUsR0FBRyxTQUFTLENBQUM7SUFDbEMsS0FBSyxDQUFDLEtBQUssRUFBRSxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sR0FBRyxFQUFFLEVBQUUsQ0FBQztJQUN4QyxNQUFNLElBQUksTUFBTSxDQUFDO0NBQ2xCO0FBRUQscUJBQWEsZ0JBQWlCLFlBQVcsVUFBVTtJQUUvQyxPQUFPLENBQUMsTUFBTTtJQUNkLE9BQU8sQ0FBQyxNQUFNO0lBQ2QsT0FBTyxDQUFDLElBQUk7SUFIZCxZQUNVLE1BQU0sRUFBRSxZQUFZLEVBQ3BCLE1BQU0sRUFBRSxNQUFNLEVBQ2QsSUFBSSxFQUFFLE1BQU0sRUFDbEI7SUFFRyxpQkFBaUIsQ0FBQyxPQUFPLFNBQStCLEdBQUcsRUFBRSxFQUFFLENBR3JFO0lBRU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxNQUFNLEdBQUcsRUFBRSxHQUFHLFNBQVMsQ0FLdkM7SUFFTSxLQUFLLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLEVBQUUsRUFBRSxDQUk3QztJQUVNLE9BQU8sSUFBSSxFQUFFLEVBQUUsQ0FFckI7SUFFTSxNQUFNLElBQUksTUFBTSxDQUV0QjtDQUNGO0FBRUQscUJBQWEsZUFBZ0IsWUFBVyxVQUFVO0lBQ3BDLE9BQU8sQ0FBQyxLQUFLO0lBQXpCLFlBQW9CLEtBQUssRUFBRSxFQUFFLEVBQUUsRUFBSTtJQUU1QixpQkFBaUIsQ0FBQyxPQUFPLFNBQStCLEdBQUcsRUFBRSxFQUFFLENBRXJFO0lBRU0sSUFBSSxDQUFDLEdBQUcsRUFBRSxNQUFNLEdBQUcsRUFBRSxHQUFHLFNBQVMsQ0FFdkM7SUFFTSxLQUFLLENBQUMsS0FBSyxFQUFFLE1BQU0sRUFBRSxHQUFHLEVBQUUsTUFBTSxHQUFHLEVBQUUsRUFBRSxDQUU3QztJQUVNLE9BQU8sSUFBSSxFQUFFLEVBQUUsQ0FFckI7SUFFTSxNQUFNLElBQUksTUFBTSxDQUV0QjtDQUNGO0FBR0QsT0FBTyxDQUFDLE1BQU0sYUFBYSxFQUFFLE9BQU8sTUFBTSxDQUFDO0FBQzNDLE9BQU8sQ0FBQyxNQUFNLGVBQWUsRUFBRSxPQUFPLE1BQU0sQ0FBQztBQUU3QyxNQUFNLE1BQU0sUUFBUSxHQUFHLFVBQVUsR0FBRztJQUNsQyxRQUFRLENBQUMsQ0FBQyxhQUFhLENBQUMsRUFBRSxJQUFJLENBQUM7Q0FDaEMsQ0FBQztBQUVGLE1BQU0sTUFBTSxVQUFVLEdBQUcsVUFBVSxHQUFHO0lBQ3BDLFFBQVEsQ0FBQyxDQUFDLGVBQWUsQ0FBQyxFQUFFLElBQUksQ0FBQztDQUNsQyxDQUFDO0FBRUYscUJBQWEsYUFBYyxTQUFRLGVBQWdCLFlBQVcsUUFBUTtJQUNwRSxTQUFpQixDQUFDLGFBQWEsQ0FBQyxFQUFFLElBQUksQ0FBQztDQUN4QztBQUVELHFCQUFhLGNBQWUsU0FBUSxnQkFBaUIsWUFBVyxRQUFRO0lBQ3RFLFNBQWlCLENBQUMsYUFBYSxDQUFDLEVBQUUsSUFBSSxDQUFDO0NBQ3hDO0FBRUQscUJBQWEsZUFBZ0IsU0FBUSxlQUFnQixZQUFXLFVBQVU7SUFDeEUsU0FBaUIsQ0FBQyxlQUFlLENBQUMsRUFBRSxJQUFJLENBQUM7Q0FDMUM7QUFFRCxxQkFBYSxnQkFBaUIsU0FBUSxnQkFBaUIsWUFBVyxVQUFVO0lBQzFFLFNBQWlCLENBQUMsZUFBZSxDQUFDLEVBQUUsSUFBSSxDQUFDO0NBQzFDIn0=
|