@aztec/simulator 3.0.0-nightly.20251209 → 3.0.0-nightly.20251210
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/common/errors.d.ts +2 -2
- package/dest/common/errors.d.ts.map +1 -1
- package/dest/private/acvm/deserialize.d.ts +2 -2
- package/dest/private/acvm/deserialize.d.ts.map +1 -1
- package/dest/private/acvm/deserialize.js +1 -1
- package/dest/private/acvm/serialize.d.ts +2 -2
- package/dest/private/acvm/serialize.d.ts.map +1 -1
- package/dest/private/acvm/serialize.js +1 -1
- package/dest/private/circuit_recording/circuit_recorder.js +1 -1
- package/dest/public/avm/avm_context.d.ts +2 -2
- package/dest/public/avm/avm_context.d.ts.map +1 -1
- package/dest/public/avm/avm_contract_call_result.d.ts +2 -2
- package/dest/public/avm/avm_contract_call_result.d.ts.map +1 -1
- package/dest/public/avm/avm_execution_environment.d.ts +2 -2
- package/dest/public/avm/avm_execution_environment.d.ts.map +1 -1
- package/dest/public/avm/avm_execution_environment.js +1 -1
- package/dest/public/avm/avm_gas.d.ts +1 -1
- package/dest/public/avm/avm_gas.d.ts.map +1 -1
- package/dest/public/avm/avm_machine_state.d.ts +2 -2
- package/dest/public/avm/avm_machine_state.d.ts.map +1 -1
- package/dest/public/avm/avm_memory_types.d.ts +2 -2
- package/dest/public/avm/avm_memory_types.d.ts.map +1 -1
- package/dest/public/avm/avm_memory_types.js +1 -1
- package/dest/public/avm/avm_simulator.d.ts +2 -2
- package/dest/public/avm/avm_simulator.d.ts.map +1 -1
- package/dest/public/avm/avm_simulator.js +1 -1
- package/dest/public/avm/errors.d.ts +2 -2
- package/dest/public/avm/errors.d.ts.map +1 -1
- package/dest/public/avm/fixtures/avm_simulation_tester.js +1 -1
- package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts +2 -2
- package/dest/public/avm/fixtures/base_avm_simulation_tester.d.ts.map +1 -1
- package/dest/public/avm/fixtures/base_avm_simulation_tester.js +1 -1
- package/dest/public/avm/fixtures/initializers.d.ts +2 -2
- package/dest/public/avm/fixtures/initializers.d.ts.map +1 -1
- package/dest/public/avm/fixtures/initializers.js +1 -1
- package/dest/public/avm/fixtures/utils.d.ts +2 -2
- package/dest/public/avm/fixtures/utils.d.ts.map +1 -1
- package/dest/public/avm/fixtures/utils.js +1 -1
- package/dest/public/avm/opcodes/ec_add.js +2 -2
- package/dest/public/avm/opcodes/hashing.d.ts +1 -1
- package/dest/public/avm/opcodes/hashing.d.ts.map +1 -1
- package/dest/public/avm/opcodes/hashing.js +3 -1
- package/dest/public/avm/opcodes/memory.js +1 -1
- package/dest/public/avm/revert_reason.d.ts +2 -2
- package/dest/public/avm/revert_reason.d.ts.map +1 -1
- package/dest/public/avm/serialization/instruction_serialization.js +1 -1
- package/dest/public/avm/test_utils.d.ts +2 -2
- package/dest/public/avm/test_utils.d.ts.map +1 -1
- package/dest/public/avm/test_utils.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/db_interfaces.d.ts +2 -2
- package/dest/public/db_interfaces.d.ts.map +1 -1
- package/dest/public/debug_fn_name.d.ts +2 -2
- package/dest/public/debug_fn_name.d.ts.map +1 -1
- package/dest/public/fixtures/amm_test.js +2 -2
- package/dest/public/fixtures/bulk_test.js +1 -1
- package/dest/public/fixtures/custom_bytecode_tests.d.ts +2 -1
- package/dest/public/fixtures/custom_bytecode_tests.d.ts.map +1 -1
- package/dest/public/fixtures/custom_bytecode_tests.js +21 -0
- package/dest/public/fixtures/public_tx_simulation_tester.js +1 -1
- package/dest/public/fixtures/simple_contract_data_source.d.ts +10 -2
- package/dest/public/fixtures/simple_contract_data_source.d.ts.map +1 -1
- package/dest/public/fixtures/simple_contract_data_source.js +35 -0
- package/dest/public/fixtures/token_test.js +1 -1
- 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 +1 -1
- package/dest/public/fuzzing/avm_simulator_bin.d.ts +2 -0
- package/dest/public/fuzzing/avm_simulator_bin.d.ts.map +1 -0
- package/dest/public/fuzzing/avm_simulator_bin.js +123 -0
- package/dest/public/fuzzing/helpers.d.ts +14 -0
- package/dest/public/fuzzing/helpers.d.ts.map +1 -0
- package/dest/public/fuzzing/helpers.js +75 -0
- package/dest/public/hinting_db_sources.d.ts +2 -2
- package/dest/public/hinting_db_sources.d.ts.map +1 -1
- package/dest/public/hinting_db_sources.js +2 -2
- package/dest/public/public_db_sources.d.ts +2 -2
- package/dest/public/public_db_sources.d.ts.map +1 -1
- package/dest/public/public_db_sources.js +1 -1
- package/dest/public/public_processor/public_processor.js +1 -1
- package/dest/public/public_tx_simulator/contract_provider_for_cpp.js +1 -1
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts +2 -2
- package/dest/public/public_tx_simulator/measured_public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.d.ts +2 -2
- package/dest/public/public_tx_simulator/public_tx_context.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/public_tx_context.js +1 -1
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts +2 -2
- package/dest/public/public_tx_simulator/public_tx_simulator.d.ts.map +1 -1
- package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts +2 -2
- package/dest/public/public_tx_simulator/telemetry_public_tx_simulator.d.ts.map +1 -1
- package/dest/public/side_effect_trace.d.ts +2 -2
- package/dest/public/side_effect_trace.d.ts.map +1 -1
- package/dest/public/side_effect_trace.js +1 -1
- package/dest/public/side_effect_trace_interface.d.ts +2 -2
- package/dest/public/side_effect_trace_interface.d.ts.map +1 -1
- package/dest/public/state_manager/nullifiers.d.ts +2 -2
- package/dest/public/state_manager/nullifiers.d.ts.map +1 -1
- package/dest/public/state_manager/public_storage.d.ts +2 -2
- package/dest/public/state_manager/public_storage.d.ts.map +1 -1
- package/dest/public/state_manager/public_storage.js +1 -1
- package/dest/public/state_manager/state_manager.d.ts +2 -2
- package/dest/public/state_manager/state_manager.d.ts.map +1 -1
- package/dest/public/state_manager/state_manager.js +1 -1
- package/package.json +17 -17
- package/src/common/errors.ts +1 -1
- package/src/private/acvm/deserialize.ts +1 -1
- package/src/private/acvm/serialize.ts +1 -1
- package/src/private/circuit_recording/circuit_recorder.ts +1 -1
- package/src/public/avm/avm_context.ts +1 -1
- package/src/public/avm/avm_contract_call_result.ts +1 -1
- package/src/public/avm/avm_execution_environment.ts +1 -1
- package/src/public/avm/avm_gas.ts +3 -3
- package/src/public/avm/avm_machine_state.ts +1 -1
- package/src/public/avm/avm_memory_types.ts +1 -1
- package/src/public/avm/avm_simulator.ts +1 -1
- package/src/public/avm/errors.ts +1 -1
- package/src/public/avm/fixtures/avm_simulation_tester.ts +1 -1
- package/src/public/avm/fixtures/base_avm_simulation_tester.ts +1 -1
- package/src/public/avm/fixtures/initializers.ts +1 -1
- package/src/public/avm/fixtures/utils.ts +1 -1
- package/src/public/avm/opcodes/ec_add.ts +2 -2
- package/src/public/avm/opcodes/hashing.ts +3 -1
- package/src/public/avm/opcodes/memory.ts +1 -1
- package/src/public/avm/revert_reason.ts +1 -1
- package/src/public/avm/serialization/instruction_serialization.ts +1 -1
- package/src/public/avm/test_utils.ts +1 -1
- package/src/public/contracts_db_checkpoint.ts +1 -1
- package/src/public/db_interfaces.ts +1 -1
- package/src/public/debug_fn_name.ts +1 -1
- package/src/public/fixtures/amm_test.ts +2 -2
- package/src/public/fixtures/bulk_test.ts +1 -1
- package/src/public/fixtures/custom_bytecode_tests.ts +24 -0
- package/src/public/fixtures/public_tx_simulation_tester.ts +1 -1
- package/src/public/fixtures/simple_contract_data_source.ts +40 -1
- package/src/public/fixtures/token_test.ts +1 -1
- package/src/public/fixtures/utils.ts +1 -1
- package/src/public/fuzzing/avm_simulator_bin.ts +157 -0
- package/src/public/fuzzing/helpers.ts +154 -0
- package/src/public/hinting_db_sources.ts +2 -2
- package/src/public/public_db_sources.ts +1 -1
- package/src/public/public_processor/public_processor.ts +1 -1
- package/src/public/public_tx_simulator/contract_provider_for_cpp.ts +1 -1
- package/src/public/public_tx_simulator/measured_public_tx_simulator.ts +1 -1
- package/src/public/public_tx_simulator/public_tx_context.ts +1 -1
- package/src/public/public_tx_simulator/public_tx_simulator.ts +1 -1
- package/src/public/public_tx_simulator/telemetry_public_tx_simulator.ts +1 -1
- package/src/public/side_effect_trace.ts +1 -1
- package/src/public/side_effect_trace_interface.ts +1 -1
- package/src/public/state_manager/nullifiers.ts +1 -1
- package/src/public/state_manager/public_storage.ts +1 -1
- package/src/public/state_manager/state_manager.ts +2 -2
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { sha512 } from '@aztec/foundation/crypto';
|
|
1
|
+
import { sha512 } from '@aztec/foundation/crypto/sha512';
|
|
2
2
|
import { createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { Timer } from '@aztec/foundation/timer';
|
|
4
4
|
import type { ForeignCallHandler, ForeignCallInput, ForeignCallOutput } from '@aztec/noir-acvm_js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/
|
|
1
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
2
|
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';
|
|
@@ -26,9 +26,9 @@ export function makeGas(gasCost: Partial<Gas>) {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
/** Sums together multiple instances of Gas. */
|
|
29
|
-
export function sumGas(...gases: Partial<Gas>[]) {
|
|
30
|
-
return gases.reduce(
|
|
31
|
-
(acc
|
|
29
|
+
export function sumGas(...gases: Partial<Gas>[]): Gas {
|
|
30
|
+
return gases.reduce<Gas>(
|
|
31
|
+
(acc, gas) => ({
|
|
32
32
|
l2Gas: acc.l2Gas + (gas.l2Gas ?? 0),
|
|
33
33
|
daGas: acc.daGas + (gas.daGas ?? 0),
|
|
34
34
|
}),
|
|
@@ -8,7 +8,7 @@ import {
|
|
|
8
8
|
MEM_TAG_U128,
|
|
9
9
|
} from '@aztec/constants';
|
|
10
10
|
import { toBufferBE } from '@aztec/foundation/bigint-buffer';
|
|
11
|
-
import { Fr } from '@aztec/foundation/
|
|
11
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
12
12
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
13
13
|
import type { FunctionsOf } from '@aztec/foundation/types';
|
|
14
14
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/
|
|
1
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
2
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
3
3
|
import { Timer } from '@aztec/foundation/timer';
|
|
4
4
|
import type { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
package/src/public/avm/errors.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Fr } from '@aztec/foundation/
|
|
1
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
2
|
import { encodeArguments } from '@aztec/stdlib/abi';
|
|
3
3
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
4
4
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS } from '@aztec/constants';
|
|
2
|
-
import { Fr } from '@aztec/foundation/
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import { ProtocolContractAddress } from '@aztec/protocol-contracts';
|
|
5
5
|
import { getCanonicalAuthRegistry } from '@aztec/protocol-contracts/auth-registry';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { AVM_MAX_PROCESSABLE_L2_GAS } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber, SlotNumber } from '@aztec/foundation/branded-types';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
4
|
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
4
|
-
import { Fr } from '@aztec/foundation/fields';
|
|
5
5
|
import { PublicSimulatorConfig } from '@aztec/stdlib/avm';
|
|
6
6
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
7
7
|
import { GasFees } from '@aztec/stdlib/gas';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS } from '@aztec/constants';
|
|
2
2
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
3
|
-
import { Fr } from '@aztec/foundation/
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import {
|
|
5
5
|
type ContractArtifact,
|
|
6
6
|
type FunctionAbi,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Grumpkin } from '@aztec/foundation/crypto';
|
|
2
|
-
import { Point } from '@aztec/foundation/
|
|
1
|
+
import { Grumpkin } from '@aztec/foundation/crypto/grumpkin';
|
|
2
|
+
import { Point } from '@aztec/foundation/curves/grumpkin';
|
|
3
3
|
|
|
4
4
|
import type { AvmContext } from '../avm_context.js';
|
|
5
5
|
import { Field, TypeTag, Uint1 } from '../avm_memory_types.js';
|
|
@@ -1,4 +1,6 @@
|
|
|
1
|
-
import { keccakf1600
|
|
1
|
+
import { keccakf1600 } from '@aztec/foundation/crypto/keccak';
|
|
2
|
+
import { poseidon2Permutation } from '@aztec/foundation/crypto/poseidon';
|
|
3
|
+
import { sha256Compression } from '@aztec/foundation/crypto/sha256';
|
|
2
4
|
|
|
3
5
|
import type { AvmContext } from '../avm_context.js';
|
|
4
6
|
import { Field, TypeTag, Uint32, Uint64 } from '../avm_memory_types.js';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fr } from '@aztec/foundation/
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
2
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
3
3
|
import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
4
4
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { Fr } from '@aztec/foundation/
|
|
1
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
2
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
3
3
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
4
4
|
import type { ContractClassPublic, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { GeneratorIndex } from '@aztec/constants';
|
|
2
|
-
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto';
|
|
3
|
-
import { Fr } from '@aztec/foundation/
|
|
2
|
+
import { poseidon2HashWithSeparator } from '@aztec/foundation/crypto/poseidon';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import type { Logger } from '@aztec/foundation/log';
|
|
5
5
|
import { Timer } from '@aztec/foundation/timer';
|
|
6
6
|
import type { ContractArtifact } from '@aztec/stdlib/abi';
|
|
@@ -31,6 +31,30 @@ export async function addressingWithBaseTagIssueTest(isIndirect: boolean, tester
|
|
|
31
31
|
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
32
32
|
}
|
|
33
33
|
|
|
34
|
+
// First instruction sets a value with tag U64 at offset 0. Then a CalldataCopy instruction
|
|
35
|
+
// uses INDIRECT addressing to read from offset 0, which should fail because the value at
|
|
36
|
+
// offset 0 has tag U64 (not U32), making it an invalid address tag.
|
|
37
|
+
export async function addressingWithIndirectTagIssueTest(tester: PublicTxSimulationTester) {
|
|
38
|
+
// Set a U64 value at offset 0 - this will be used as an indirect address
|
|
39
|
+
const addressingMode = Addressing.fromModes([
|
|
40
|
+
AddressingMode.INDIRECT, // First operand (cdOffset) uses indirect addressing
|
|
41
|
+
AddressingMode.DIRECT,
|
|
42
|
+
AddressingMode.DIRECT,
|
|
43
|
+
]);
|
|
44
|
+
|
|
45
|
+
const bytecode = encodeToBytecode([
|
|
46
|
+
// Set a U64 value at offset 0 - this has the wrong tag for an address (should be U32)
|
|
47
|
+
new Set(/*indirect=*/ 0, /*dstOffset=*/ 0, TypeTag.UINT64, /*value=*/ 100n).as(Opcode.SET_64, Set.wireFormat64),
|
|
48
|
+
// Try to use indirect addressing: read from offset 0, which contains a U64 value
|
|
49
|
+
// This should fail because U64 is not a valid address tag (must be U32)
|
|
50
|
+
new CalldataCopy(/*indirect=*/ addressingMode.toWire(), /*copySize=*/ 1, /*cdOffset=*/ 0, /*dstOffset=*/ 1),
|
|
51
|
+
new Return(/*indirect=*/ 0, /*copySizeOffset=*/ 0, /*returnOffset=*/ 0),
|
|
52
|
+
]);
|
|
53
|
+
|
|
54
|
+
const txLabel = 'AddressingWithIndirectTagInvalid';
|
|
55
|
+
return await testCustomBytecode(bytecode, tester, txLabel);
|
|
56
|
+
}
|
|
57
|
+
|
|
34
58
|
export async function pcOutOfRangeTest(tester: PublicTxSimulationTester) {
|
|
35
59
|
const bytecode = encodeToBytecode([
|
|
36
60
|
new Jump(/*jumpOffset=*/ 123), // Jump to out-of-range pc offset.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DEFAULT_TEARDOWN_DA_GAS_LIMIT, DEFAULT_TEARDOWN_L2_GAS_LIMIT } from '@aztec/constants';
|
|
2
2
|
import { asyncMap } from '@aztec/foundation/async-map';
|
|
3
3
|
import { BlockNumber } from '@aztec/foundation/branded-types';
|
|
4
|
-
import { Fr } from '@aztec/foundation/
|
|
4
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
5
5
|
import { type ContractArtifact, encodeArguments } from '@aztec/stdlib/abi';
|
|
6
6
|
import { PublicSimulatorConfig, type PublicTxResult } from '@aztec/stdlib/avm';
|
|
7
7
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import
|
|
2
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
3
|
import { createLogger } from '@aztec/foundation/log';
|
|
4
4
|
import type { ContractArtifact, FunctionSelector } from '@aztec/stdlib/abi';
|
|
5
5
|
import type { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
6
6
|
import type { ContractClassPublic, ContractDataSource, ContractInstanceWithAddress } from '@aztec/stdlib/contract';
|
|
7
|
+
import { PublicKeys } from '@aztec/stdlib/keys';
|
|
7
8
|
|
|
8
9
|
import { getFunctionSelector } from '../avm/fixtures/utils.js';
|
|
9
10
|
|
|
@@ -119,4 +120,42 @@ export class SimpleContractDataSource implements ContractDataSource {
|
|
|
119
120
|
this.contractInstances.set(contractInstance.address.toString(), contractInstance);
|
|
120
121
|
return Promise.resolve();
|
|
121
122
|
}
|
|
123
|
+
|
|
124
|
+
/**
|
|
125
|
+
* FIXME: This is temporary
|
|
126
|
+
* Helper method for fuzzer: registers a contract with raw bytecode at a given address.
|
|
127
|
+
* Creates a minimal ContractClassPublic and ContractInstanceWithAddress.
|
|
128
|
+
* @param address - The contract address
|
|
129
|
+
* @param bytecode - The raw AVM bytecode
|
|
130
|
+
*/
|
|
131
|
+
async addContractWithBytecode(address: AztecAddress, bytecode: Buffer): Promise<void> {
|
|
132
|
+
// Generate a deterministic class ID from the bytecode
|
|
133
|
+
const classId = Fr.fromBufferReduce(bytecode.subarray(0, 32));
|
|
134
|
+
|
|
135
|
+
// Create minimal ContractClassPublic
|
|
136
|
+
const contractClass: ContractClassPublic = {
|
|
137
|
+
id: classId,
|
|
138
|
+
version: 1 as const,
|
|
139
|
+
artifactHash: Fr.ZERO,
|
|
140
|
+
privateFunctionsRoot: Fr.ZERO,
|
|
141
|
+
privateFunctions: [],
|
|
142
|
+
utilityFunctions: [],
|
|
143
|
+
packedBytecode: bytecode,
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Create minimal ContractInstanceWithAddress
|
|
147
|
+
const contractInstance: ContractInstanceWithAddress = {
|
|
148
|
+
address,
|
|
149
|
+
version: 1 as const,
|
|
150
|
+
salt: Fr.ZERO,
|
|
151
|
+
deployer: address, // Use the contract address as deployer
|
|
152
|
+
currentContractClassId: classId,
|
|
153
|
+
originalContractClassId: classId,
|
|
154
|
+
initializationHash: Fr.ZERO,
|
|
155
|
+
publicKeys: PublicKeys.default(),
|
|
156
|
+
};
|
|
157
|
+
|
|
158
|
+
await this.addContractClass(contractClass);
|
|
159
|
+
await this.addContractInstance(contractInstance);
|
|
160
|
+
}
|
|
122
161
|
}
|
|
@@ -9,7 +9,7 @@ import {
|
|
|
9
9
|
PRIVATE_LOG_SIZE_IN_FIELDS,
|
|
10
10
|
} from '@aztec/constants';
|
|
11
11
|
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
12
|
-
import { Fr } from '@aztec/foundation/
|
|
12
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
13
13
|
import { CONTRACT_INSTANCE_PUBLISHED_EVENT_TAG } from '@aztec/protocol-contracts';
|
|
14
14
|
import { bufferAsFields } from '@aztec/stdlib/abi';
|
|
15
15
|
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
@@ -0,0 +1,157 @@
|
|
|
1
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
2
|
+
import { EthAddress } from '@aztec/foundation/eth-address';
|
|
3
|
+
import { AvmCircuitPublicInputs, AvmTxHint, deserializeFromMessagePack } from '@aztec/stdlib/avm';
|
|
4
|
+
import { GlobalVariables } from '@aztec/stdlib/tx';
|
|
5
|
+
import { NativeWorldStateService } from '@aztec/world-state';
|
|
6
|
+
|
|
7
|
+
import { writeSync } from 'fs';
|
|
8
|
+
import { createInterface } from 'readline';
|
|
9
|
+
|
|
10
|
+
import { SimpleContractDataSource } from '../fixtures/simple_contract_data_source.js';
|
|
11
|
+
import { PublicContractsDB } from '../public_db_sources.js';
|
|
12
|
+
import { PublicTxSimulator } from '../public_tx_simulator/public_tx_simulator.js';
|
|
13
|
+
import { createFuzzerTx, registerContract } from './helpers.js';
|
|
14
|
+
|
|
15
|
+
// This cache holds opened world states to avoid reopening them for each invocation.
|
|
16
|
+
// It's a map so that in the future we could support multiple world states (if we had multiple fuzzers).
|
|
17
|
+
const worldStateCache = new Map<string, NativeWorldStateService>();
|
|
18
|
+
|
|
19
|
+
async function openExistingWorldState(dataDir: string, mapSizeKb: number): Promise<NativeWorldStateService> {
|
|
20
|
+
const cached = worldStateCache.get(dataDir);
|
|
21
|
+
if (cached) {
|
|
22
|
+
return cached;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const ws = await NativeWorldStateService.new(EthAddress.ZERO, dataDir, {
|
|
26
|
+
archiveTreeMapSizeKb: mapSizeKb,
|
|
27
|
+
nullifierTreeMapSizeKb: mapSizeKb,
|
|
28
|
+
noteHashTreeMapSizeKb: mapSizeKb,
|
|
29
|
+
messageTreeMapSizeKb: mapSizeKb,
|
|
30
|
+
publicDataTreeMapSizeKb: mapSizeKb,
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
worldStateCache.set(dataDir, ws);
|
|
34
|
+
return ws;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
async function simulateWithPublicTxSimulator(
|
|
38
|
+
dataDir: string,
|
|
39
|
+
mapSizeKb: number,
|
|
40
|
+
bytecode: Buffer,
|
|
41
|
+
cppTx: AvmTxHint,
|
|
42
|
+
cppGlobals: GlobalVariables,
|
|
43
|
+
): Promise<{ reverted: boolean; output: Fr[]; revertReason?: string; publicInputs: AvmCircuitPublicInputs }> {
|
|
44
|
+
const worldStateService = await openExistingWorldState(dataDir, mapSizeKb);
|
|
45
|
+
const merkleTrees = await worldStateService.fork();
|
|
46
|
+
|
|
47
|
+
// todo(ilyas): enable this once we can handle multiple bytecodes across multiple enqueued calls
|
|
48
|
+
// Concat all the enqueued calls, extract the de-duplicated contract addresses so we can register them
|
|
49
|
+
//const teardownCalls = cppTx.teardownEnqueuedCall ? [cppTx.teardownEnqueuedCall] : [];
|
|
50
|
+
//const contractAddresses = new Set([...cppTx.setupEnqueuedCalls, ...cppTx.appLogicEnqueuedCalls, ...teardownCalls].map(
|
|
51
|
+
// call => call.request.contractAddress,
|
|
52
|
+
//));
|
|
53
|
+
//await Promise.all([...contractAddresses].map(addr => registerContract(merkleTrees, addr)));
|
|
54
|
+
//await Promise.all(
|
|
55
|
+
// [...contractAddresses].map(addr => contractDataSource.addContractWithBytecode(addr, bytecode)),
|
|
56
|
+
//);
|
|
57
|
+
|
|
58
|
+
const contractAddress = cppTx.appLogicEnqueuedCalls[0].request.contractAddress;
|
|
59
|
+
await registerContract(merkleTrees, contractAddress);
|
|
60
|
+
const contractDataSource = new SimpleContractDataSource();
|
|
61
|
+
await contractDataSource.addContractWithBytecode(contractAddress, bytecode);
|
|
62
|
+
|
|
63
|
+
const contractsDb = new PublicContractsDB(contractDataSource);
|
|
64
|
+
|
|
65
|
+
const publicTxSimulator = new PublicTxSimulator(merkleTrees, contractsDb, cppGlobals, {
|
|
66
|
+
skipFeeEnforcement: true,
|
|
67
|
+
collectDebugLogs: false,
|
|
68
|
+
collectHints: false,
|
|
69
|
+
collectStatistics: false,
|
|
70
|
+
collectCallMetadata: false,
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
const tx = await createFuzzerTx(cppTx);
|
|
74
|
+
const result = await publicTxSimulator.simulate(tx);
|
|
75
|
+
|
|
76
|
+
const output = result.getAppLogicReturnValues().flatMap(rv => rv?.values?.filter(v => v != null) ?? []);
|
|
77
|
+
|
|
78
|
+
return {
|
|
79
|
+
reverted: !result.revertCode.isOK(),
|
|
80
|
+
output,
|
|
81
|
+
revertReason: result.findRevertReason()?.message,
|
|
82
|
+
publicInputs: result.publicInputs!,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function executeFromJson(jsonLine: string): Promise<void> {
|
|
87
|
+
try {
|
|
88
|
+
const input = JSON.parse(jsonLine.trim());
|
|
89
|
+
if (!input.bytecode || !input.ws_data_dir || !input.ws_map_size_kb || !input.tx || !input.globals) {
|
|
90
|
+
writeSync(
|
|
91
|
+
process.stdout.fd,
|
|
92
|
+
'Error: JSON must contain "bytecode", "ws_data_dir", "ws_map_size_kb", "tx", and "globals" fields\n',
|
|
93
|
+
);
|
|
94
|
+
return;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
const bytecode = Buffer.from(input.bytecode, 'base64');
|
|
98
|
+
const rawTx: object = deserializeFromMessagePack(Buffer.from(input.tx, 'base64'));
|
|
99
|
+
const tx = AvmTxHint.fromPlainObject(rawTx);
|
|
100
|
+
const rawGlobals = deserializeFromMessagePack(Buffer.from(input.globals, 'base64'));
|
|
101
|
+
const globals = GlobalVariables.fromPlainObject(rawGlobals);
|
|
102
|
+
|
|
103
|
+
const result = await simulateWithPublicTxSimulator(input.ws_data_dir, input.ws_map_size_kb, bytecode, tx, globals);
|
|
104
|
+
|
|
105
|
+
// todo(ilyas): Would be nice to serialize entire publicInputs for comparison, but it was extremely slow.
|
|
106
|
+
// Serialize endTreeSnapshots for comparison with C++ simulator
|
|
107
|
+
const endTreeSnapshots = {
|
|
108
|
+
l1ToL2MessageTree: {
|
|
109
|
+
root: result.publicInputs.endTreeSnapshots.l1ToL2MessageTree.root.toString(),
|
|
110
|
+
nextAvailableLeafIndex: result.publicInputs.endTreeSnapshots.l1ToL2MessageTree.nextAvailableLeafIndex,
|
|
111
|
+
},
|
|
112
|
+
noteHashTree: {
|
|
113
|
+
root: result.publicInputs.endTreeSnapshots.noteHashTree.root.toString(),
|
|
114
|
+
nextAvailableLeafIndex: result.publicInputs.endTreeSnapshots.noteHashTree.nextAvailableLeafIndex,
|
|
115
|
+
},
|
|
116
|
+
nullifierTree: {
|
|
117
|
+
root: result.publicInputs.endTreeSnapshots.nullifierTree.root.toString(),
|
|
118
|
+
nextAvailableLeafIndex: result.publicInputs.endTreeSnapshots.nullifierTree.nextAvailableLeafIndex,
|
|
119
|
+
},
|
|
120
|
+
publicDataTree: {
|
|
121
|
+
root: result.publicInputs.endTreeSnapshots.publicDataTree.root.toString(),
|
|
122
|
+
nextAvailableLeafIndex: result.publicInputs.endTreeSnapshots.publicDataTree.nextAvailableLeafIndex,
|
|
123
|
+
},
|
|
124
|
+
};
|
|
125
|
+
|
|
126
|
+
writeSync(
|
|
127
|
+
process.stdout.fd,
|
|
128
|
+
JSON.stringify({
|
|
129
|
+
reverted: result.reverted,
|
|
130
|
+
output: result.output.map(v => v?.toString() ?? '0'),
|
|
131
|
+
revertReason: result.revertReason,
|
|
132
|
+
endTreeSnapshots,
|
|
133
|
+
}) + '\n',
|
|
134
|
+
);
|
|
135
|
+
} catch (error: any) {
|
|
136
|
+
writeSync(
|
|
137
|
+
process.stdout.fd,
|
|
138
|
+
JSON.stringify({
|
|
139
|
+
reverted: true,
|
|
140
|
+
output: [],
|
|
141
|
+
revertReason: error.message,
|
|
142
|
+
}) + '\n',
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
function mainLoop() {
|
|
148
|
+
const rl = createInterface({ input: process.stdin, terminal: false });
|
|
149
|
+
rl.on('line', (line: string) => {
|
|
150
|
+
if (line.trim()) {
|
|
151
|
+
void executeFromJson(line);
|
|
152
|
+
}
|
|
153
|
+
});
|
|
154
|
+
rl.on('close', () => process.exit(0));
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
mainLoop();
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
import {
|
|
2
|
+
CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS,
|
|
3
|
+
MAX_ENQUEUED_CALLS_PER_TX,
|
|
4
|
+
MAX_L2_TO_L1_MSGS_PER_TX,
|
|
5
|
+
MAX_NOTE_HASHES_PER_TX,
|
|
6
|
+
MAX_NULLIFIERS_PER_TX,
|
|
7
|
+
MAX_PRIVATE_LOGS_PER_TX,
|
|
8
|
+
} from '@aztec/constants';
|
|
9
|
+
import { padArrayEnd } from '@aztec/foundation/collection';
|
|
10
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
11
|
+
import type { AvmTxHint } from '@aztec/stdlib/avm';
|
|
12
|
+
import { AztecAddress } from '@aztec/stdlib/aztec-address';
|
|
13
|
+
import { siloNullifier } from '@aztec/stdlib/hash';
|
|
14
|
+
import {
|
|
15
|
+
PartialPrivateTailPublicInputsForPublic,
|
|
16
|
+
PrivateKernelTailCircuitPublicInputs,
|
|
17
|
+
PrivateToPublicAccumulatedData,
|
|
18
|
+
PublicCallRequest,
|
|
19
|
+
} from '@aztec/stdlib/kernel';
|
|
20
|
+
import { PrivateLog } from '@aztec/stdlib/logs';
|
|
21
|
+
import { ScopedL2ToL1Message } from '@aztec/stdlib/messaging';
|
|
22
|
+
import { ChonkProof } from '@aztec/stdlib/proofs';
|
|
23
|
+
import { MerkleTreeId, type MerkleTreeWriteOperations } from '@aztec/stdlib/trees';
|
|
24
|
+
import { BlockHeader, HashedValues, Tx, TxConstantData, TxContext, TxHash } from '@aztec/stdlib/tx';
|
|
25
|
+
|
|
26
|
+
// Registers a contract by inserting its address nullifier into the nullifier tree
|
|
27
|
+
export async function registerContract(
|
|
28
|
+
merkleTrees: MerkleTreeWriteOperations,
|
|
29
|
+
contractAddress: AztecAddress,
|
|
30
|
+
): Promise<void> {
|
|
31
|
+
const contractAddressNullifier = await siloNullifier(
|
|
32
|
+
AztecAddress.fromNumber(CONTRACT_INSTANCE_REGISTRY_CONTRACT_ADDRESS),
|
|
33
|
+
contractAddress.toField(),
|
|
34
|
+
);
|
|
35
|
+
await merkleTrees.sequentialInsert(MerkleTreeId.NULLIFIER_TREE, [contractAddressNullifier.toBuffer()]);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Creates a TypeScript Tx object from a deserialized C++ Tx (AvmTxHint-like structure).
|
|
40
|
+
* This allows using PublicTxSimulator.simulate() with fuzzer-generated transactions.
|
|
41
|
+
*
|
|
42
|
+
* @param cppTx - Deserialized C++ Tx from msgpack (matches AvmTxHint structure)
|
|
43
|
+
* @returns A TypeScript Tx suitable for PublicTxSimulator
|
|
44
|
+
*/
|
|
45
|
+
export async function createFuzzerTx(cppTx: AvmTxHint): Promise<Tx> {
|
|
46
|
+
// Create TxHash from the C++ tx hash string
|
|
47
|
+
if (!cppTx.hash) {
|
|
48
|
+
throw new Error(`cppTx.hash is undefined. Keys: ${Object.keys(cppTx || {}).join(', ')}`);
|
|
49
|
+
}
|
|
50
|
+
const txHash = TxHash.fromString(cppTx.hash);
|
|
51
|
+
|
|
52
|
+
// Extract PublicCallRequest instances from enqueued calls
|
|
53
|
+
const setupCallRequests = cppTx.setupEnqueuedCalls.map(call => call.request);
|
|
54
|
+
const paddedSetupCalls = padArrayEnd(setupCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX);
|
|
55
|
+
|
|
56
|
+
const appLogicCallRequests = cppTx.appLogicEnqueuedCalls.map(call => call.request);
|
|
57
|
+
const paddedAppLogicCalls = padArrayEnd(appLogicCallRequests, PublicCallRequest.empty(), MAX_ENQUEUED_CALLS_PER_TX);
|
|
58
|
+
|
|
59
|
+
// Build non-revertible accumulated data from C++ tx
|
|
60
|
+
const emptyNonRevertible = PrivateToPublicAccumulatedData.empty();
|
|
61
|
+
const nonRevertibleAccumulatedData = new PrivateToPublicAccumulatedData(
|
|
62
|
+
padArrayEnd(cppTx.nonRevertibleAccumulatedData.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
63
|
+
padArrayEnd(cppTx.nonRevertibleAccumulatedData.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
|
|
64
|
+
padArrayEnd(
|
|
65
|
+
cppTx.nonRevertibleAccumulatedData.l2ToL1Messages,
|
|
66
|
+
ScopedL2ToL1Message.empty(),
|
|
67
|
+
MAX_L2_TO_L1_MSGS_PER_TX,
|
|
68
|
+
),
|
|
69
|
+
padArrayEnd(cppTx.nonRevertibleContractDeploymentData.privateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
|
|
70
|
+
emptyNonRevertible.contractClassLogsHashes,
|
|
71
|
+
paddedSetupCalls,
|
|
72
|
+
);
|
|
73
|
+
|
|
74
|
+
// Build revertible accumulated data from C++ tx
|
|
75
|
+
const emptyRevertible = PrivateToPublicAccumulatedData.empty();
|
|
76
|
+
const revertibleAccumulatedData = new PrivateToPublicAccumulatedData(
|
|
77
|
+
padArrayEnd(cppTx.revertibleAccumulatedData.noteHashes, Fr.ZERO, MAX_NOTE_HASHES_PER_TX),
|
|
78
|
+
padArrayEnd(cppTx.revertibleAccumulatedData.nullifiers, Fr.ZERO, MAX_NULLIFIERS_PER_TX),
|
|
79
|
+
padArrayEnd(cppTx.revertibleAccumulatedData.l2ToL1Messages, ScopedL2ToL1Message.empty(), MAX_L2_TO_L1_MSGS_PER_TX),
|
|
80
|
+
padArrayEnd(cppTx.revertibleContractDeploymentData.privateLogs, PrivateLog.empty(), MAX_PRIVATE_LOGS_PER_TX),
|
|
81
|
+
emptyRevertible.contractClassLogsHashes,
|
|
82
|
+
paddedAppLogicCalls,
|
|
83
|
+
);
|
|
84
|
+
|
|
85
|
+
// Build teardown call request (if exists)
|
|
86
|
+
const teardownCallRequest = cppTx.teardownEnqueuedCall?.request ?? PublicCallRequest.empty();
|
|
87
|
+
|
|
88
|
+
// Create forPublic structure
|
|
89
|
+
const forPublic = new PartialPrivateTailPublicInputsForPublic(
|
|
90
|
+
nonRevertibleAccumulatedData,
|
|
91
|
+
revertibleAccumulatedData,
|
|
92
|
+
teardownCallRequest,
|
|
93
|
+
);
|
|
94
|
+
|
|
95
|
+
// Build TxContext - gasSettings is already a proper GasSettings after AvmTxHint.fromPlainObject
|
|
96
|
+
const txContext = new TxContext(
|
|
97
|
+
Fr.ZERO, // chainId - this is fine because simulation actually reads from globalVariables not here
|
|
98
|
+
Fr.ZERO, // version - this is fine because simulation actually reads from globalVariables not here
|
|
99
|
+
cppTx.gasSettings,
|
|
100
|
+
);
|
|
101
|
+
|
|
102
|
+
// Build TxConstantData
|
|
103
|
+
const constants = new TxConstantData(
|
|
104
|
+
BlockHeader.empty(), // anchorBlockHeader (unused in simulation)
|
|
105
|
+
txContext,
|
|
106
|
+
Fr.ZERO, // vkTreeRoot - not needed for public simulation
|
|
107
|
+
Fr.ZERO, // protocolContractsHash - not needed for public simulation
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
const data = new PrivateKernelTailCircuitPublicInputs(
|
|
111
|
+
constants,
|
|
112
|
+
cppTx.gasUsedByPrivate,
|
|
113
|
+
cppTx.feePayer,
|
|
114
|
+
0n, // includeByTimestamp
|
|
115
|
+
forPublic,
|
|
116
|
+
undefined, // forRollup - not needed for public simulation
|
|
117
|
+
);
|
|
118
|
+
|
|
119
|
+
// todo(ilyas): I don't think we need to construct this, but keeping for now - the hashing could get costly with
|
|
120
|
+
// large number of enqueued calls or large calldata so keep an eye on this!
|
|
121
|
+
// Build publicFunctionCalldata from all enqueued calls
|
|
122
|
+
// Calldata is already Fr[] after AvmTxHint.fromPlainObject
|
|
123
|
+
const publicFunctionCalldata: HashedValues[] = [];
|
|
124
|
+
|
|
125
|
+
// Add setup calls
|
|
126
|
+
for (const call of cppTx.setupEnqueuedCalls || []) {
|
|
127
|
+
publicFunctionCalldata.push(await HashedValues.fromCalldata(call.calldata));
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
// Add app logic calls
|
|
131
|
+
for (const call of cppTx.appLogicEnqueuedCalls || []) {
|
|
132
|
+
publicFunctionCalldata.push(await HashedValues.fromCalldata(call.calldata));
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// Add teardown call if present
|
|
136
|
+
if (cppTx.teardownEnqueuedCall) {
|
|
137
|
+
publicFunctionCalldata.push(await HashedValues.fromCalldata(cppTx.teardownEnqueuedCall.calldata));
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
// Extract contract class log fields from ContractDeploymentData
|
|
141
|
+
const contractClassLogFields = [
|
|
142
|
+
...cppTx.nonRevertibleContractDeploymentData.contractClassLogs.map(log => log.fields),
|
|
143
|
+
...cppTx.revertibleContractDeploymentData.contractClassLogs.map(log => log.fields),
|
|
144
|
+
];
|
|
145
|
+
|
|
146
|
+
// Create the Tx
|
|
147
|
+
return new Tx(
|
|
148
|
+
txHash,
|
|
149
|
+
data,
|
|
150
|
+
ChonkProof.empty(), // No real proof needed for simulation
|
|
151
|
+
contractClassLogFields,
|
|
152
|
+
publicFunctionCalldata,
|
|
153
|
+
);
|
|
154
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import { sha256Trunc } from '@aztec/foundation/crypto';
|
|
3
|
-
import { Fr } from '@aztec/foundation/
|
|
2
|
+
import { sha256Trunc } from '@aztec/foundation/crypto/sha256';
|
|
3
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
4
4
|
import { type Logger, createLogger } from '@aztec/foundation/log';
|
|
5
5
|
import type { IndexedTreeLeafPreimage, SiblingPath } from '@aztec/foundation/trees';
|
|
6
6
|
import type { FunctionSelector } from '@aztec/stdlib/abi';
|
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
NULLIFIER_SUBTREE_HEIGHT,
|
|
5
5
|
PUBLIC_DATA_SUBTREE_HEIGHT,
|
|
6
6
|
} from '@aztec/constants';
|
|
7
|
-
import { Fr } from '@aztec/foundation/
|
|
7
|
+
import { Fr } from '@aztec/foundation/curves/bn254';
|
|
8
8
|
import { createLogger } from '@aztec/foundation/log';
|
|
9
9
|
import { Timer } from '@aztec/foundation/timer';
|
|
10
10
|
import { ContractClassPublishedEvent } from '@aztec/protocol-contracts/class-registry';
|