@aztec/stdlib 3.0.0-nightly.20251222 → 3.0.0-nightly.20251224
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/checkpoint/checkpoint.d.ts +15 -1
- package/dest/checkpoint/checkpoint.d.ts.map +1 -1
- package/dest/checkpoint/checkpoint.js +26 -0
- package/dest/checkpoint/checkpoint_info.d.ts +9 -0
- package/dest/checkpoint/checkpoint_info.d.ts.map +1 -0
- package/dest/checkpoint/checkpoint_info.js +1 -0
- package/dest/contract/contract_class_id.js +1 -1
- package/dest/hash/hash.d.ts +1 -9
- package/dest/hash/hash.d.ts.map +1 -1
- package/dest/hash/hash.js +0 -12
- package/dest/interfaces/archiver.d.ts +1 -1
- package/dest/interfaces/archiver.d.ts.map +1 -1
- package/dest/interfaces/archiver.js +4 -1
- package/dest/interfaces/aztec-node-admin.d.ts +19 -7
- package/dest/interfaces/aztec-node-admin.d.ts.map +1 -1
- package/dest/interfaces/aztec-node.d.ts +10 -10
- package/dest/interfaces/aztec-node.d.ts.map +1 -1
- package/dest/interfaces/aztec-node.js +3 -3
- package/dest/interfaces/block-builder.d.ts +3 -2
- package/dest/interfaces/block-builder.d.ts.map +1 -1
- package/dest/interfaces/block-builder.js +9 -1
- package/dest/interfaces/configs.d.ts +35 -13
- package/dest/interfaces/configs.d.ts.map +1 -1
- package/dest/interfaces/configs.js +7 -3
- package/dest/interfaces/l2_logs_source.d.ts +12 -8
- package/dest/interfaces/l2_logs_source.d.ts.map +1 -1
- package/dest/interfaces/merkle_tree_operations.d.ts +2 -2
- package/dest/interfaces/merkle_tree_operations.d.ts.map +1 -1
- package/dest/interfaces/proving-job.d.ts +166 -166
- package/dest/interfaces/world_state.d.ts +10 -3
- package/dest/interfaces/world_state.d.ts.map +1 -1
- package/dest/kernel/private_circuit_public_inputs.d.ts +47 -47
- package/dest/kernel/private_circuit_public_inputs.d.ts.map +1 -1
- package/dest/kernel/private_circuit_public_inputs.js +59 -59
- package/dest/logs/index.d.ts +3 -1
- package/dest/logs/index.d.ts.map +1 -1
- package/dest/logs/index.js +2 -0
- package/dest/logs/siloed_tag.d.ts +23 -0
- package/dest/logs/siloed_tag.d.ts.map +1 -0
- package/dest/logs/siloed_tag.js +30 -0
- package/dest/logs/tag.d.ts +21 -0
- package/dest/logs/tag.d.ts.map +1 -0
- package/dest/logs/tag.js +30 -0
- package/dest/logs/tx_scoped_l2_log.d.ts +8 -2
- package/dest/logs/tx_scoped_l2_log.d.ts.map +1 -1
- package/dest/logs/tx_scoped_l2_log.js +13 -5
- package/dest/messaging/l1_to_l2_message.d.ts +1 -1
- package/dest/messaging/l1_to_l2_message.d.ts.map +1 -1
- package/dest/rollup/checkpoint_constant_data.d.ts +2 -1
- package/dest/rollup/checkpoint_constant_data.d.ts.map +1 -1
- package/dest/rollup/checkpoint_constant_data.js +1 -0
- package/dest/rollup/checkpoint_header.d.ts +5 -1
- package/dest/rollup/checkpoint_header.d.ts.map +1 -1
- package/dest/rollup/checkpoint_header.js +4 -1
- package/dest/schemas/schemas.d.ts +3 -1
- package/dest/schemas/schemas.d.ts.map +1 -1
- package/dest/schemas/schemas.js +1 -0
- package/dest/stats/stats.d.ts +10 -6
- package/dest/stats/stats.d.ts.map +1 -1
- package/dest/tx/global_variable_builder.d.ts +4 -2
- package/dest/tx/global_variable_builder.d.ts.map +1 -1
- package/dest/tx/global_variables.d.ts +6 -1
- package/dest/tx/global_variables.d.ts.map +1 -1
- package/package.json +8 -8
- package/src/checkpoint/checkpoint.ts +32 -0
- package/src/checkpoint/checkpoint_info.ts +9 -0
- package/src/contract/contract_class_id.ts +1 -1
- package/src/hash/hash.ts +0 -11
- package/src/interfaces/archiver.ts +8 -2
- package/src/interfaces/aztec-node.ts +17 -14
- package/src/interfaces/block-builder.ts +11 -1
- package/src/interfaces/configs.ts +36 -8
- package/src/interfaces/l2_logs_source.ts +12 -7
- package/src/interfaces/merkle_tree_operations.ts +4 -1
- package/src/interfaces/world_state.ts +7 -2
- package/src/kernel/private_circuit_public_inputs.ts +85 -85
- package/src/logs/index.ts +2 -0
- package/src/logs/siloed_tag.ts +44 -0
- package/src/logs/tag.ts +42 -0
- package/src/logs/tx_scoped_l2_log.ts +15 -5
- package/src/messaging/l1_to_l2_message.ts +1 -0
- package/src/rollup/checkpoint_constant_data.ts +1 -0
- package/src/rollup/checkpoint_header.ts +4 -0
- package/src/schemas/schemas.ts +3 -0
- package/src/stats/stats.ts +10 -5
- package/src/tx/global_variable_builder.ts +8 -1
- package/src/tx/global_variables.ts +6 -0
package/src/hash/hash.ts
CHANGED
|
@@ -69,17 +69,6 @@ export function computeProtocolNullifier(txRequestHash: Fr): Promise<Fr> {
|
|
|
69
69
|
return siloNullifier(AztecAddress.fromBigInt(NULL_MSG_SENDER_CONTRACT_ADDRESS), txRequestHash);
|
|
70
70
|
}
|
|
71
71
|
|
|
72
|
-
/**
|
|
73
|
-
* Computes a siloed private log tag, given the contract address and the unsiloed tag.
|
|
74
|
-
* A siloed private log tag effectively namespaces a log to a specific contract.
|
|
75
|
-
* @param contract - The contract address.
|
|
76
|
-
* @param unsiloedTag - The unsiloed tag.
|
|
77
|
-
* @returns A siloed private log tag.
|
|
78
|
-
*/
|
|
79
|
-
export function siloPrivateLog(contract: AztecAddress, unsiloedTag: Fr): Promise<Fr> {
|
|
80
|
-
return poseidon2Hash([contract, unsiloedTag]);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
72
|
/**
|
|
84
73
|
* Computes a public data tree value ready for insertion.
|
|
85
74
|
* @param value - Raw public data tree value to hash into a tree-insertion-ready value.
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
} from '../contract/index.js';
|
|
18
18
|
import { L1RollupConstantsSchema } from '../epoch-helpers/index.js';
|
|
19
19
|
import { LogFilterSchema } from '../logs/log_filter.js';
|
|
20
|
+
import { SiloedTag } from '../logs/siloed_tag.js';
|
|
21
|
+
import { Tag } from '../logs/tag.js';
|
|
20
22
|
import { TxScopedL2Log } from '../logs/tx_scoped_l2_log.js';
|
|
21
23
|
import type { L1ToL2MessageSource } from '../messaging/l1_to_l2_message_source.js';
|
|
22
24
|
import { optional, schemas } from '../schemas/schemas.js';
|
|
@@ -111,9 +113,13 @@ export const ArchiverApiSchema: ApiSchemaFor<ArchiverApi> = {
|
|
|
111
113
|
getBlockHeadersForEpoch: z.function().args(EpochNumberSchema).returns(z.array(BlockHeader.schema)),
|
|
112
114
|
isEpochComplete: z.function().args(EpochNumberSchema).returns(z.boolean()),
|
|
113
115
|
getL2Tips: z.function().args().returns(L2TipsSchema),
|
|
114
|
-
|
|
116
|
+
getPrivateLogsByTags: z
|
|
115
117
|
.function()
|
|
116
|
-
.args(z.array(
|
|
118
|
+
.args(z.array(SiloedTag.schema))
|
|
119
|
+
.returns(z.array(z.array(TxScopedL2Log.schema))),
|
|
120
|
+
getPublicLogsByTagsFromContract: z
|
|
121
|
+
.function()
|
|
122
|
+
.args(schemas.AztecAddress, z.array(Tag.schema))
|
|
117
123
|
.returns(z.array(z.array(TxScopedL2Log.schema))),
|
|
118
124
|
getPublicLogs: z.function().args(LogFilterSchema).returns(GetPublicLogsResponseSchema),
|
|
119
125
|
getContractClassLogs: z.function().args(LogFilterSchema).returns(GetContractClassLogsResponseSchema),
|
|
@@ -36,8 +36,8 @@ import {
|
|
|
36
36
|
ProtocolContractAddressesSchema,
|
|
37
37
|
} from '../contract/index.js';
|
|
38
38
|
import { GasFees } from '../gas/gas_fees.js';
|
|
39
|
+
import { SiloedTag, Tag, TxScopedL2Log } from '../logs/index.js';
|
|
39
40
|
import { type LogFilter, LogFilterSchema } from '../logs/log_filter.js';
|
|
40
|
-
import { TxScopedL2Log } from '../logs/tx_scoped_l2_log.js';
|
|
41
41
|
import { type ApiSchemaFor, optional, schemas } from '../schemas/schemas.js';
|
|
42
42
|
import { MerkleTreeId } from '../trees/merkle_tree_id.js';
|
|
43
43
|
import { NullifierMembershipWitness } from '../trees/nullifier_membership_witness.js';
|
|
@@ -338,14 +338,16 @@ export interface AztecNode
|
|
|
338
338
|
getContractClassLogs(filter: LogFilter): Promise<GetContractClassLogsResponse>;
|
|
339
339
|
|
|
340
340
|
/**
|
|
341
|
-
* Gets all logs that match any of the
|
|
342
|
-
*
|
|
343
|
-
* @param logsPerTag - How many logs to return per tag. Default 10 logs are returned for each tag
|
|
344
|
-
* @returns For each received tag, an array of matching logs and metadata (e.g. tx hash) is returned. An empty
|
|
345
|
-
* array implies no logs match that tag. There can be multiple logs for 1 tag because tag reuse can happen
|
|
346
|
-
* --> e.g. when sending a note from multiple unsynched devices.
|
|
341
|
+
* Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
|
|
342
|
+
* array implies no logs match that tag.
|
|
347
343
|
*/
|
|
348
|
-
|
|
344
|
+
getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]>;
|
|
345
|
+
|
|
346
|
+
/**
|
|
347
|
+
* Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
|
|
348
|
+
* logs is returned. An empty array implies no logs match that tag.
|
|
349
|
+
*/
|
|
350
|
+
getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]>;
|
|
349
351
|
|
|
350
352
|
/**
|
|
351
353
|
* Method to submit a transaction to the p2p pool.
|
|
@@ -481,7 +483,6 @@ export interface AztecNode
|
|
|
481
483
|
getAllowedPublicSetup(): Promise<AllowedElement[]>;
|
|
482
484
|
}
|
|
483
485
|
|
|
484
|
-
export const MAX_LOGS_PER_TAG = 10;
|
|
485
486
|
const MAX_SIGNATURES_PER_REGISTER_CALL = 100;
|
|
486
487
|
const MAX_SIGNATURE_LEN = 10000;
|
|
487
488
|
|
|
@@ -601,12 +602,14 @@ export const AztecNodeApiSchema: ApiSchemaFor<AztecNode> = {
|
|
|
601
602
|
|
|
602
603
|
getContractClassLogs: z.function().args(LogFilterSchema).returns(GetContractClassLogsResponseSchema),
|
|
603
604
|
|
|
604
|
-
|
|
605
|
+
getPrivateLogsByTags: z
|
|
605
606
|
.function()
|
|
606
|
-
.args(
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
607
|
+
.args(z.array(SiloedTag.schema).max(MAX_RPC_LEN))
|
|
608
|
+
.returns(z.array(z.array(TxScopedL2Log.schema))),
|
|
609
|
+
|
|
610
|
+
getPublicLogsByTagsFromContract: z
|
|
611
|
+
.function()
|
|
612
|
+
.args(schemas.AztecAddress, z.array(Tag.schema).max(MAX_RPC_LEN))
|
|
610
613
|
.returns(z.array(z.array(TxScopedL2Log.schema))),
|
|
611
614
|
|
|
612
615
|
sendTx: z.function().args(Tx.schema).returns(z.void()),
|
|
@@ -60,7 +60,17 @@ export interface BuildBlockResult {
|
|
|
60
60
|
|
|
61
61
|
export type FullNodeBlockBuilderConfig = Pick<L1RollupConstants, 'l1GenesisTime' | 'slotDuration'> &
|
|
62
62
|
Pick<ChainConfig, 'l1ChainId' | 'rollupVersion'> &
|
|
63
|
-
Pick<SequencerConfig, 'txPublicSetupAllowList' | 'fakeProcessingDelayPerTxMs'>;
|
|
63
|
+
Pick<SequencerConfig, 'txPublicSetupAllowList' | 'fakeProcessingDelayPerTxMs' | 'fakeThrowAfterProcessingTxCount'>;
|
|
64
|
+
|
|
65
|
+
export const FullNodeBlockBuilderConfigKeys: (keyof FullNodeBlockBuilderConfig)[] = [
|
|
66
|
+
'l1GenesisTime',
|
|
67
|
+
'slotDuration',
|
|
68
|
+
'l1ChainId',
|
|
69
|
+
'rollupVersion',
|
|
70
|
+
'txPublicSetupAllowList',
|
|
71
|
+
'fakeProcessingDelayPerTxMs',
|
|
72
|
+
'fakeThrowAfterProcessingTxCount',
|
|
73
|
+
] as const;
|
|
64
74
|
|
|
65
75
|
export interface IFullNodeBlockBuilder {
|
|
66
76
|
getConfig(): FullNodeBlockBuilderConfig;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { EthAddress } from '@aztec/foundation/eth-address';
|
|
2
|
+
import type { Prettify } from '@aztec/foundation/types';
|
|
2
3
|
|
|
3
4
|
import { z } from 'zod';
|
|
4
5
|
|
|
@@ -6,16 +7,16 @@ import type { AztecAddress } from '../aztec-address/index.js';
|
|
|
6
7
|
import { schemas, zodFor } from '../schemas/index.js';
|
|
7
8
|
import { type AllowedElement, AllowedElementSchema } from './allowed_element.js';
|
|
8
9
|
|
|
9
|
-
/**
|
|
10
|
-
* The sequencer configuration.
|
|
11
|
-
*/
|
|
10
|
+
/** Sequencer configuration */
|
|
12
11
|
export interface SequencerConfig {
|
|
13
12
|
/** The number of ms to wait between polling for pending txs. */
|
|
14
|
-
|
|
13
|
+
sequencerPollingIntervalMS?: number;
|
|
15
14
|
/** The maximum number of txs to include in a block. */
|
|
16
15
|
maxTxsPerBlock?: number;
|
|
17
16
|
/** The minimum number of txs to include in a block. */
|
|
18
17
|
minTxsPerBlock?: number;
|
|
18
|
+
/** The minimum number of valid txs (after execution) to include in a block. If not set, falls back to minTxsPerBlock. */
|
|
19
|
+
minValidTxsPerBlock?: number;
|
|
19
20
|
/** Whether to publish txs with the block proposals */
|
|
20
21
|
publishTxsWithProposals?: boolean;
|
|
21
22
|
/** The maximum L2 block gas. */
|
|
@@ -38,10 +39,12 @@ export interface SequencerConfig {
|
|
|
38
39
|
governanceProposerPayload?: EthAddress;
|
|
39
40
|
/** Whether to enforce the time table when building blocks */
|
|
40
41
|
enforceTimeTable?: boolean;
|
|
41
|
-
/** How
|
|
42
|
-
|
|
42
|
+
/** How much time (in seconds) we allow in the slot for publishing the L1 tx. */
|
|
43
|
+
l1PublishingTime?: number;
|
|
43
44
|
/** Used for testing to introduce a fake delay after processing each tx */
|
|
44
45
|
fakeProcessingDelayPerTxMs?: number;
|
|
46
|
+
/** Used for testing to throw an error after processing N txs */
|
|
47
|
+
fakeThrowAfterProcessingTxCount?: number;
|
|
45
48
|
/** How many seconds it takes for proposals and attestations to travel across the p2p layer (one-way) */
|
|
46
49
|
attestationPropagationTime?: number;
|
|
47
50
|
/** How many seconds before invalidating a block as a committee member (zero to never invalidate) */
|
|
@@ -60,12 +63,17 @@ export interface SequencerConfig {
|
|
|
60
63
|
fishermanMode?: boolean;
|
|
61
64
|
/** Shuffle attestation ordering to create invalid ordering (for testing only) */
|
|
62
65
|
shuffleAttestationOrdering?: boolean;
|
|
66
|
+
/** Duration per block in milliseconds when building multiple blocks per slot (default: undefined = single block per slot) */
|
|
67
|
+
blockDurationMs?: number;
|
|
68
|
+
/** Have sequencer build and publish an empty checkpoint if there are no txs */
|
|
69
|
+
buildCheckpointIfEmpty?: boolean;
|
|
63
70
|
}
|
|
64
71
|
|
|
65
72
|
export const SequencerConfigSchema = zodFor<SequencerConfig>()(
|
|
66
73
|
z.object({
|
|
67
|
-
|
|
74
|
+
sequencerPollingIntervalMS: z.number().optional(),
|
|
68
75
|
maxTxsPerBlock: z.number().optional(),
|
|
76
|
+
minValidTxsPerBlock: z.number().optional(),
|
|
69
77
|
minTxsPerBlock: z.number().optional(),
|
|
70
78
|
maxL2BlockGas: z.number().optional(),
|
|
71
79
|
publishTxsWithProposals: z.boolean().optional(),
|
|
@@ -77,9 +85,10 @@ export const SequencerConfigSchema = zodFor<SequencerConfig>()(
|
|
|
77
85
|
txPublicSetupAllowList: z.array(AllowedElementSchema).optional(),
|
|
78
86
|
maxBlockSizeInBytes: z.number().optional(),
|
|
79
87
|
governanceProposerPayload: schemas.EthAddress.optional(),
|
|
80
|
-
|
|
88
|
+
l1PublishingTime: z.number().optional(),
|
|
81
89
|
enforceTimeTable: z.boolean().optional(),
|
|
82
90
|
fakeProcessingDelayPerTxMs: z.number().optional(),
|
|
91
|
+
fakeThrowAfterProcessingTxCount: z.number().optional(),
|
|
83
92
|
attestationPropagationTime: z.number().optional(),
|
|
84
93
|
skipCollectingAttestations: z.boolean().optional(),
|
|
85
94
|
skipInvalidateBlockAsProposer: z.boolean().optional(),
|
|
@@ -89,5 +98,24 @@ export const SequencerConfigSchema = zodFor<SequencerConfig>()(
|
|
|
89
98
|
injectFakeAttestation: z.boolean().optional(),
|
|
90
99
|
fishermanMode: z.boolean().optional(),
|
|
91
100
|
shuffleAttestationOrdering: z.boolean().optional(),
|
|
101
|
+
blockDurationMs: z.number().positive().optional(),
|
|
102
|
+
buildCheckpointIfEmpty: z.boolean().optional(),
|
|
92
103
|
}),
|
|
93
104
|
);
|
|
105
|
+
|
|
106
|
+
type SequencerConfigOptionalKeys =
|
|
107
|
+
| 'governanceProposerPayload'
|
|
108
|
+
| 'blockDurationMs'
|
|
109
|
+
| 'coinbase'
|
|
110
|
+
| 'feeRecipient'
|
|
111
|
+
| 'acvmWorkingDirectory'
|
|
112
|
+
| 'acvmBinaryPath'
|
|
113
|
+
| 'fakeProcessingDelayPerTxMs'
|
|
114
|
+
| 'fakeThrowAfterProcessingTxCount'
|
|
115
|
+
| 'l1PublishingTime'
|
|
116
|
+
| 'txPublicSetupAllowList'
|
|
117
|
+
| 'minValidTxsPerBlock';
|
|
118
|
+
|
|
119
|
+
export type ResolvedSequencerConfig = Prettify<
|
|
120
|
+
Required<Omit<SequencerConfig, SequencerConfigOptionalKeys>> & Pick<SequencerConfig, SequencerConfigOptionalKeys>
|
|
121
|
+
>;
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import type { BlockNumber } from '@aztec/foundation/branded-types';
|
|
2
|
-
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
2
|
|
|
3
|
+
import type { AztecAddress } from '../aztec-address/index.js';
|
|
4
4
|
import type { LogFilter } from '../logs/log_filter.js';
|
|
5
|
+
import type { SiloedTag } from '../logs/siloed_tag.js';
|
|
6
|
+
import type { Tag } from '../logs/tag.js';
|
|
5
7
|
import type { TxScopedL2Log } from '../logs/tx_scoped_l2_log.js';
|
|
6
8
|
import type { GetContractClassLogsResponse, GetPublicLogsResponse } from './get_logs_response.js';
|
|
7
9
|
|
|
@@ -10,13 +12,16 @@ import type { GetContractClassLogsResponse, GetPublicLogsResponse } from './get_
|
|
|
10
12
|
*/
|
|
11
13
|
export interface L2LogsSource {
|
|
12
14
|
/**
|
|
13
|
-
* Gets all logs that match any of the
|
|
14
|
-
*
|
|
15
|
-
* @param logsPerTag - The maximum number of logs to return for each tag. Default returns everything
|
|
16
|
-
* @returns For each received tag, an array of matching logs is returned. An empty array implies no logs match
|
|
17
|
-
* that tag.
|
|
15
|
+
* Gets all private logs that match any of the `tags`. For each tag, an array of matching logs is returned. An empty
|
|
16
|
+
* array implies no logs match that tag.
|
|
18
17
|
*/
|
|
19
|
-
|
|
18
|
+
getPrivateLogsByTags(tags: SiloedTag[]): Promise<TxScopedL2Log[][]>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Gets all public logs that match any of the `tags` from the specified contract. For each tag, an array of matching
|
|
22
|
+
* logs is returned. An empty array implies no logs match that tag.
|
|
23
|
+
*/
|
|
24
|
+
getPublicLogsByTagsFromContract(contractAddress: AztecAddress, tags: Tag[]): Promise<TxScopedL2Log[][]>;
|
|
20
25
|
|
|
21
26
|
/**
|
|
22
27
|
* Gets public logs based on the provided filter.
|
|
@@ -251,7 +251,10 @@ export interface MerkleTreeCheckpointOperations {
|
|
|
251
251
|
revertAllCheckpoints(): Promise<void>;
|
|
252
252
|
}
|
|
253
253
|
|
|
254
|
-
export interface MerkleTreeWriteOperations
|
|
254
|
+
export interface MerkleTreeWriteOperations
|
|
255
|
+
extends MerkleTreeReadOperations,
|
|
256
|
+
MerkleTreeCheckpointOperations,
|
|
257
|
+
Disposable {
|
|
255
258
|
/**
|
|
256
259
|
* Appends leaves to a given tree.
|
|
257
260
|
* @param treeId - The tree to be updated.
|
|
@@ -42,8 +42,13 @@ export interface WorldStateSynchronizerStatus {
|
|
|
42
42
|
|
|
43
43
|
/** Provides writeable forks of the world state at a given block number. */
|
|
44
44
|
export interface ForkMerkleTreeOperations {
|
|
45
|
-
/**
|
|
46
|
-
|
|
45
|
+
/**
|
|
46
|
+
* Forks the world state at the given block number, defaulting to the latest one.
|
|
47
|
+
* @param block - The block number to fork at.
|
|
48
|
+
* @param opts - Optional parameters:
|
|
49
|
+
* - closeDelayMs: number of milliseconds to wait before closing the fork on dispose.
|
|
50
|
+
*/
|
|
51
|
+
fork(block?: BlockNumber, opts?: { closeDelayMs?: number }): Promise<MerkleTreeWriteOperations>;
|
|
47
52
|
|
|
48
53
|
/** Gets a handle that allows reading the state as it was at the given block number. */
|
|
49
54
|
getSnapshot(blockNumber: BlockNumber): MerkleTreeReadOperations;
|
|
@@ -57,6 +57,18 @@ export class PrivateCircuitPublicInputs {
|
|
|
57
57
|
* Pedersen hash of the return values of the corresponding function call.
|
|
58
58
|
*/
|
|
59
59
|
public returnsHash: Fr,
|
|
60
|
+
/**
|
|
61
|
+
* Header of a block whose state is used during private execution (not the block the transaction is included in).
|
|
62
|
+
*/
|
|
63
|
+
public anchorBlockHeader: BlockHeader,
|
|
64
|
+
/**
|
|
65
|
+
* Transaction context.
|
|
66
|
+
*
|
|
67
|
+
* Note: The chainId and version in the txContext are not redundant to the values in self.anchor_block_header.global_variables because
|
|
68
|
+
* they can be different in case of a protocol upgrade. In such a situation we could be using header from a block
|
|
69
|
+
* before the upgrade took place but be using the updated protocol to execute and prove the transaction.
|
|
70
|
+
*/
|
|
71
|
+
public txContext: TxContext,
|
|
60
72
|
/**
|
|
61
73
|
* The side-effect counter under which all side effects are non-revertible.
|
|
62
74
|
*/
|
|
@@ -69,6 +81,22 @@ export class PrivateCircuitPublicInputs {
|
|
|
69
81
|
* The highest timestamp of a block in which the transaction can still be included.
|
|
70
82
|
*/
|
|
71
83
|
public includeByTimestamp: UInt64,
|
|
84
|
+
/**
|
|
85
|
+
* The side effect counter at the start of this call.
|
|
86
|
+
*/
|
|
87
|
+
public startSideEffectCounter: Fr,
|
|
88
|
+
/**
|
|
89
|
+
* The end side effect counter for this call.
|
|
90
|
+
*/
|
|
91
|
+
public endSideEffectCounter: Fr,
|
|
92
|
+
/**
|
|
93
|
+
* The expected non revertible side effect counter for this call.
|
|
94
|
+
*/
|
|
95
|
+
public expectedNonRevertibleSideEffectCounter: Fr,
|
|
96
|
+
/**
|
|
97
|
+
* The expected revertible side effect counter for this call.
|
|
98
|
+
*/
|
|
99
|
+
public expectedRevertibleSideEffectCounter: Fr,
|
|
72
100
|
/**
|
|
73
101
|
* Read requests created by the corresponding function call.
|
|
74
102
|
*/
|
|
@@ -84,14 +112,6 @@ export class PrivateCircuitPublicInputs {
|
|
|
84
112
|
KeyValidationRequestAndGenerator,
|
|
85
113
|
typeof MAX_KEY_VALIDATION_REQUESTS_PER_CALL
|
|
86
114
|
>,
|
|
87
|
-
/**
|
|
88
|
-
* New note hashes created by the corresponding function call.
|
|
89
|
-
*/
|
|
90
|
-
public noteHashes: ClaimedLengthArray<NoteHash, typeof MAX_NOTE_HASHES_PER_CALL>,
|
|
91
|
-
/**
|
|
92
|
-
* New nullifiers created by the corresponding function call.
|
|
93
|
-
*/
|
|
94
|
-
public nullifiers: ClaimedLengthArray<Nullifier, typeof MAX_NULLIFIERS_PER_CALL>,
|
|
95
115
|
/**
|
|
96
116
|
* Private call requests made within the current kernel iteration.
|
|
97
117
|
*/
|
|
@@ -104,6 +124,14 @@ export class PrivateCircuitPublicInputs {
|
|
|
104
124
|
* Hash of the public teardown function.
|
|
105
125
|
*/
|
|
106
126
|
public publicTeardownCallRequest: PublicCallRequest,
|
|
127
|
+
/**
|
|
128
|
+
* New note hashes created by the corresponding function call.
|
|
129
|
+
*/
|
|
130
|
+
public noteHashes: ClaimedLengthArray<NoteHash, typeof MAX_NOTE_HASHES_PER_CALL>,
|
|
131
|
+
/**
|
|
132
|
+
* New nullifiers created by the corresponding function call.
|
|
133
|
+
*/
|
|
134
|
+
public nullifiers: ClaimedLengthArray<Nullifier, typeof MAX_NULLIFIERS_PER_CALL>,
|
|
107
135
|
/**
|
|
108
136
|
* New L2 to L1 messages created by the corresponding function call.
|
|
109
137
|
*/
|
|
@@ -116,34 +144,6 @@ export class PrivateCircuitPublicInputs {
|
|
|
116
144
|
* Hash of the contract class logs emitted in this function call.
|
|
117
145
|
*/
|
|
118
146
|
public contractClassLogsHashes: ClaimedLengthArray<CountedLogHash, typeof MAX_CONTRACT_CLASS_LOGS_PER_CALL>,
|
|
119
|
-
/**
|
|
120
|
-
* The side effect counter at the start of this call.
|
|
121
|
-
*/
|
|
122
|
-
public startSideEffectCounter: Fr,
|
|
123
|
-
/**
|
|
124
|
-
* The end side effect counter for this call.
|
|
125
|
-
*/
|
|
126
|
-
public endSideEffectCounter: Fr,
|
|
127
|
-
/**
|
|
128
|
-
* The expected non revertible side effect counter for this call.
|
|
129
|
-
*/
|
|
130
|
-
public expectedNonRevertibleSideEffectCounter: Fr,
|
|
131
|
-
/**
|
|
132
|
-
* The expected revertible side effect counter for this call.
|
|
133
|
-
*/
|
|
134
|
-
public expectedRevertibleSideEffectCounter: Fr,
|
|
135
|
-
/**
|
|
136
|
-
* Header of a block whose state is used during private execution (not the block the transaction is included in).
|
|
137
|
-
*/
|
|
138
|
-
public anchorBlockHeader: BlockHeader,
|
|
139
|
-
/**
|
|
140
|
-
* Transaction context.
|
|
141
|
-
*
|
|
142
|
-
* Note: The chainId and version in the txContext are not redundant to the values in self.anchor_block_header.global_variables because
|
|
143
|
-
* they can be different in case of a protocol upgrade. In such a situation we could be using header from a block
|
|
144
|
-
* before the upgrade took place but be using the updated protocol to execute and prove the transaction.
|
|
145
|
-
*/
|
|
146
|
-
public txContext: TxContext,
|
|
147
147
|
) {}
|
|
148
148
|
|
|
149
149
|
/**
|
|
@@ -166,28 +166,28 @@ export class PrivateCircuitPublicInputs {
|
|
|
166
166
|
reader.readObject(CallContext),
|
|
167
167
|
reader.readObject(Fr),
|
|
168
168
|
reader.readObject(Fr),
|
|
169
|
+
reader.readObject(BlockHeader),
|
|
170
|
+
reader.readObject(TxContext),
|
|
169
171
|
reader.readObject(Fr),
|
|
170
172
|
reader.readBoolean(),
|
|
171
173
|
reader.readUInt64(),
|
|
174
|
+
reader.readObject(Fr),
|
|
175
|
+
reader.readObject(Fr),
|
|
176
|
+
reader.readObject(Fr),
|
|
177
|
+
reader.readObject(Fr),
|
|
172
178
|
reader.readObject(ClaimedLengthArrayFromBuffer(ScopedReadRequest, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL)),
|
|
173
179
|
reader.readObject(ClaimedLengthArrayFromBuffer(ScopedReadRequest, MAX_NULLIFIER_READ_REQUESTS_PER_CALL)),
|
|
174
180
|
reader.readObject(
|
|
175
181
|
ClaimedLengthArrayFromBuffer(KeyValidationRequestAndGenerator, MAX_KEY_VALIDATION_REQUESTS_PER_CALL),
|
|
176
182
|
),
|
|
177
|
-
reader.readObject(ClaimedLengthArrayFromBuffer(NoteHash, MAX_NOTE_HASHES_PER_CALL)),
|
|
178
|
-
reader.readObject(ClaimedLengthArrayFromBuffer(Nullifier, MAX_NULLIFIERS_PER_CALL)),
|
|
179
183
|
reader.readObject(ClaimedLengthArrayFromBuffer(PrivateCallRequest, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL)),
|
|
180
184
|
reader.readObject(ClaimedLengthArrayFromBuffer(CountedPublicCallRequest, MAX_ENQUEUED_CALLS_PER_CALL)),
|
|
181
185
|
reader.readObject(PublicCallRequest),
|
|
186
|
+
reader.readObject(ClaimedLengthArrayFromBuffer(NoteHash, MAX_NOTE_HASHES_PER_CALL)),
|
|
187
|
+
reader.readObject(ClaimedLengthArrayFromBuffer(Nullifier, MAX_NULLIFIERS_PER_CALL)),
|
|
182
188
|
reader.readObject(ClaimedLengthArrayFromBuffer(CountedL2ToL1Message, MAX_L2_TO_L1_MSGS_PER_CALL)),
|
|
183
189
|
reader.readObject(ClaimedLengthArrayFromBuffer(PrivateLogData, MAX_PRIVATE_LOGS_PER_CALL)),
|
|
184
190
|
reader.readObject(ClaimedLengthArrayFromBuffer(CountedLogHash, MAX_CONTRACT_CLASS_LOGS_PER_CALL)),
|
|
185
|
-
reader.readObject(Fr),
|
|
186
|
-
reader.readObject(Fr),
|
|
187
|
-
reader.readObject(Fr),
|
|
188
|
-
reader.readObject(Fr),
|
|
189
|
-
reader.readObject(BlockHeader),
|
|
190
|
-
reader.readObject(TxContext),
|
|
191
191
|
);
|
|
192
192
|
}
|
|
193
193
|
|
|
@@ -197,28 +197,28 @@ export class PrivateCircuitPublicInputs {
|
|
|
197
197
|
reader.readObject(CallContext),
|
|
198
198
|
reader.readField(),
|
|
199
199
|
reader.readField(),
|
|
200
|
+
reader.readObject(BlockHeader),
|
|
201
|
+
reader.readObject(TxContext),
|
|
200
202
|
reader.readField(),
|
|
201
203
|
reader.readBoolean(),
|
|
202
204
|
reader.readU64(),
|
|
205
|
+
reader.readField(),
|
|
206
|
+
reader.readField(),
|
|
207
|
+
reader.readField(),
|
|
208
|
+
reader.readField(),
|
|
203
209
|
reader.readObject(ClaimedLengthArrayFromFields(ScopedReadRequest, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL)),
|
|
204
210
|
reader.readObject(ClaimedLengthArrayFromFields(ScopedReadRequest, MAX_NULLIFIER_READ_REQUESTS_PER_CALL)),
|
|
205
211
|
reader.readObject(
|
|
206
212
|
ClaimedLengthArrayFromFields(KeyValidationRequestAndGenerator, MAX_KEY_VALIDATION_REQUESTS_PER_CALL),
|
|
207
213
|
),
|
|
208
|
-
reader.readObject(ClaimedLengthArrayFromFields(NoteHash, MAX_NOTE_HASHES_PER_CALL)),
|
|
209
|
-
reader.readObject(ClaimedLengthArrayFromFields(Nullifier, MAX_NULLIFIERS_PER_CALL)),
|
|
210
214
|
reader.readObject(ClaimedLengthArrayFromFields(PrivateCallRequest, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL)),
|
|
211
215
|
reader.readObject(ClaimedLengthArrayFromFields(CountedPublicCallRequest, MAX_ENQUEUED_CALLS_PER_CALL)),
|
|
212
216
|
reader.readObject(PublicCallRequest),
|
|
217
|
+
reader.readObject(ClaimedLengthArrayFromFields(NoteHash, MAX_NOTE_HASHES_PER_CALL)),
|
|
218
|
+
reader.readObject(ClaimedLengthArrayFromFields(Nullifier, MAX_NULLIFIERS_PER_CALL)),
|
|
213
219
|
reader.readObject(ClaimedLengthArrayFromFields(CountedL2ToL1Message, MAX_L2_TO_L1_MSGS_PER_CALL)),
|
|
214
220
|
reader.readObject(ClaimedLengthArrayFromFields(PrivateLogData, MAX_PRIVATE_LOGS_PER_CALL)),
|
|
215
221
|
reader.readObject(ClaimedLengthArrayFromFields(CountedLogHash, MAX_CONTRACT_CLASS_LOGS_PER_CALL)),
|
|
216
|
-
reader.readField(),
|
|
217
|
-
reader.readField(),
|
|
218
|
-
reader.readField(),
|
|
219
|
-
reader.readField(),
|
|
220
|
-
reader.readObject(BlockHeader),
|
|
221
|
-
reader.readObject(TxContext),
|
|
222
222
|
);
|
|
223
223
|
}
|
|
224
224
|
|
|
@@ -231,26 +231,26 @@ export class PrivateCircuitPublicInputs {
|
|
|
231
231
|
CallContext.empty(),
|
|
232
232
|
Fr.ZERO,
|
|
233
233
|
Fr.ZERO,
|
|
234
|
+
BlockHeader.empty(),
|
|
235
|
+
TxContext.empty(),
|
|
234
236
|
Fr.ZERO,
|
|
235
237
|
false,
|
|
236
238
|
0n,
|
|
239
|
+
Fr.ZERO,
|
|
240
|
+
Fr.ZERO,
|
|
241
|
+
Fr.ZERO,
|
|
242
|
+
Fr.ZERO,
|
|
237
243
|
ClaimedLengthArray.empty(ScopedReadRequest, MAX_NOTE_HASH_READ_REQUESTS_PER_CALL),
|
|
238
244
|
ClaimedLengthArray.empty(ScopedReadRequest, MAX_NULLIFIER_READ_REQUESTS_PER_CALL),
|
|
239
245
|
ClaimedLengthArray.empty(KeyValidationRequestAndGenerator, MAX_KEY_VALIDATION_REQUESTS_PER_CALL),
|
|
240
|
-
ClaimedLengthArray.empty(NoteHash, MAX_NOTE_HASHES_PER_CALL),
|
|
241
|
-
ClaimedLengthArray.empty(Nullifier, MAX_NULLIFIERS_PER_CALL),
|
|
242
246
|
ClaimedLengthArray.empty(PrivateCallRequest, MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL),
|
|
243
247
|
ClaimedLengthArray.empty(CountedPublicCallRequest, MAX_ENQUEUED_CALLS_PER_CALL),
|
|
244
248
|
PublicCallRequest.empty(),
|
|
249
|
+
ClaimedLengthArray.empty(NoteHash, MAX_NOTE_HASHES_PER_CALL),
|
|
250
|
+
ClaimedLengthArray.empty(Nullifier, MAX_NULLIFIERS_PER_CALL),
|
|
245
251
|
ClaimedLengthArray.empty(CountedL2ToL1Message, MAX_L2_TO_L1_MSGS_PER_CALL),
|
|
246
252
|
ClaimedLengthArray.empty(PrivateLogData, MAX_PRIVATE_LOGS_PER_CALL),
|
|
247
253
|
ClaimedLengthArray.empty(CountedLogHash, MAX_CONTRACT_CLASS_LOGS_PER_CALL),
|
|
248
|
-
Fr.ZERO,
|
|
249
|
-
Fr.ZERO,
|
|
250
|
-
Fr.ZERO,
|
|
251
|
-
Fr.ZERO,
|
|
252
|
-
BlockHeader.empty(),
|
|
253
|
-
TxContext.empty(),
|
|
254
254
|
);
|
|
255
255
|
}
|
|
256
256
|
|
|
@@ -259,26 +259,26 @@ export class PrivateCircuitPublicInputs {
|
|
|
259
259
|
this.callContext.isEmpty() &&
|
|
260
260
|
this.argsHash.isZero() &&
|
|
261
261
|
this.returnsHash.isZero() &&
|
|
262
|
+
this.anchorBlockHeader.isEmpty() &&
|
|
263
|
+
this.txContext.isEmpty() &&
|
|
262
264
|
this.minRevertibleSideEffectCounter.isZero() &&
|
|
263
265
|
!this.isFeePayer &&
|
|
264
266
|
!this.includeByTimestamp &&
|
|
267
|
+
this.startSideEffectCounter.isZero() &&
|
|
268
|
+
this.endSideEffectCounter.isZero() &&
|
|
269
|
+
this.expectedNonRevertibleSideEffectCounter.isZero() &&
|
|
270
|
+
this.expectedRevertibleSideEffectCounter.isZero() &&
|
|
265
271
|
this.noteHashReadRequests.isEmpty() &&
|
|
266
272
|
this.nullifierReadRequests.isEmpty() &&
|
|
267
273
|
this.keyValidationRequestsAndGenerators.isEmpty() &&
|
|
268
|
-
this.noteHashes.isEmpty() &&
|
|
269
|
-
this.nullifiers.isEmpty() &&
|
|
270
274
|
this.privateCallRequests.isEmpty() &&
|
|
271
275
|
this.publicCallRequests.isEmpty() &&
|
|
272
276
|
this.publicTeardownCallRequest.isEmpty() &&
|
|
277
|
+
this.noteHashes.isEmpty() &&
|
|
278
|
+
this.nullifiers.isEmpty() &&
|
|
273
279
|
this.l2ToL1Msgs.isEmpty() &&
|
|
274
280
|
this.privateLogs.isEmpty() &&
|
|
275
|
-
this.contractClassLogsHashes.isEmpty()
|
|
276
|
-
this.startSideEffectCounter.isZero() &&
|
|
277
|
-
this.endSideEffectCounter.isZero() &&
|
|
278
|
-
this.expectedNonRevertibleSideEffectCounter.isZero() &&
|
|
279
|
-
this.expectedRevertibleSideEffectCounter.isZero() &&
|
|
280
|
-
this.anchorBlockHeader.isEmpty() &&
|
|
281
|
-
this.txContext.isEmpty()
|
|
281
|
+
this.contractClassLogsHashes.isEmpty()
|
|
282
282
|
);
|
|
283
283
|
}
|
|
284
284
|
|
|
@@ -292,26 +292,26 @@ export class PrivateCircuitPublicInputs {
|
|
|
292
292
|
fields.callContext,
|
|
293
293
|
fields.argsHash,
|
|
294
294
|
fields.returnsHash,
|
|
295
|
+
fields.anchorBlockHeader,
|
|
296
|
+
fields.txContext,
|
|
295
297
|
fields.minRevertibleSideEffectCounter,
|
|
296
298
|
fields.isFeePayer,
|
|
297
299
|
fields.includeByTimestamp,
|
|
300
|
+
fields.startSideEffectCounter,
|
|
301
|
+
fields.endSideEffectCounter,
|
|
302
|
+
fields.expectedNonRevertibleSideEffectCounter,
|
|
303
|
+
fields.expectedRevertibleSideEffectCounter,
|
|
298
304
|
fields.noteHashReadRequests,
|
|
299
305
|
fields.nullifierReadRequests,
|
|
300
306
|
fields.keyValidationRequestsAndGenerators,
|
|
301
|
-
fields.noteHashes,
|
|
302
|
-
fields.nullifiers,
|
|
303
307
|
fields.privateCallRequests,
|
|
304
308
|
fields.publicCallRequests,
|
|
305
309
|
fields.publicTeardownCallRequest,
|
|
310
|
+
fields.noteHashes,
|
|
311
|
+
fields.nullifiers,
|
|
306
312
|
fields.l2ToL1Msgs,
|
|
307
313
|
fields.privateLogs,
|
|
308
314
|
fields.contractClassLogsHashes,
|
|
309
|
-
fields.startSideEffectCounter,
|
|
310
|
-
fields.endSideEffectCounter,
|
|
311
|
-
fields.expectedNonRevertibleSideEffectCounter,
|
|
312
|
-
fields.expectedRevertibleSideEffectCounter,
|
|
313
|
-
fields.anchorBlockHeader,
|
|
314
|
-
fields.txContext,
|
|
315
315
|
] as const;
|
|
316
316
|
}
|
|
317
317
|
|
|
@@ -326,26 +326,26 @@ export class PrivateCircuitPublicInputs {
|
|
|
326
326
|
this.callContext,
|
|
327
327
|
this.argsHash,
|
|
328
328
|
this.returnsHash,
|
|
329
|
+
this.anchorBlockHeader,
|
|
330
|
+
this.txContext,
|
|
329
331
|
this.minRevertibleSideEffectCounter,
|
|
330
332
|
this.isFeePayer,
|
|
331
333
|
bigintToUInt64BE(this.includeByTimestamp),
|
|
334
|
+
this.startSideEffectCounter,
|
|
335
|
+
this.endSideEffectCounter,
|
|
336
|
+
this.expectedNonRevertibleSideEffectCounter,
|
|
337
|
+
this.expectedRevertibleSideEffectCounter,
|
|
332
338
|
this.noteHashReadRequests,
|
|
333
339
|
this.nullifierReadRequests,
|
|
334
340
|
this.keyValidationRequestsAndGenerators,
|
|
335
|
-
this.noteHashes,
|
|
336
|
-
this.nullifiers,
|
|
337
341
|
this.privateCallRequests,
|
|
338
342
|
this.publicCallRequests,
|
|
339
343
|
this.publicTeardownCallRequest,
|
|
344
|
+
this.noteHashes,
|
|
345
|
+
this.nullifiers,
|
|
340
346
|
this.l2ToL1Msgs,
|
|
341
347
|
this.privateLogs,
|
|
342
348
|
this.contractClassLogsHashes,
|
|
343
|
-
this.startSideEffectCounter,
|
|
344
|
-
this.endSideEffectCounter,
|
|
345
|
-
this.expectedNonRevertibleSideEffectCounter,
|
|
346
|
-
this.expectedRevertibleSideEffectCounter,
|
|
347
|
-
this.anchorBlockHeader,
|
|
348
|
-
this.txContext,
|
|
349
349
|
]);
|
|
350
350
|
}
|
|
351
351
|
|
package/src/logs/index.ts
CHANGED
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { poseidon2Hash } from '@aztec/foundation/crypto/poseidon';
|
|
2
|
+
import type { Fr } from '@aztec/foundation/curves/bn254';
|
|
3
|
+
import type { ZodFor } from '@aztec/foundation/schemas';
|
|
4
|
+
|
|
5
|
+
import type { AztecAddress } from '../aztec-address/index.js';
|
|
6
|
+
import { schemas } from '../schemas/schemas.js';
|
|
7
|
+
import type { Tag } from './tag.js';
|
|
8
|
+
|
|
9
|
+
/* eslint-disable @typescript-eslint/no-unsafe-declaration-merging */
|
|
10
|
+
|
|
11
|
+
/** Branding to ensure fields are not interchangeable types. */
|
|
12
|
+
export interface SiloedTag {
|
|
13
|
+
/** Brand. */
|
|
14
|
+
_branding: 'SiloedTag';
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Represents a tag used in private log as it "appears on the chain" - that is the tag is siloed with a contract
|
|
19
|
+
* address that emitted the log.
|
|
20
|
+
*/
|
|
21
|
+
export class SiloedTag {
|
|
22
|
+
constructor(public readonly value: Fr) {}
|
|
23
|
+
|
|
24
|
+
static async compute(tag: Tag, app: AztecAddress): Promise<SiloedTag> {
|
|
25
|
+
const siloedTag = await poseidon2Hash([app, tag.value]);
|
|
26
|
+
return new SiloedTag(siloedTag);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
toString(): string {
|
|
30
|
+
return this.value.toString();
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
toJSON(): string {
|
|
34
|
+
return this.value.toString();
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
equals(other: SiloedTag): boolean {
|
|
38
|
+
return this.value.equals(other.value);
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
static get schema(): ZodFor<SiloedTag> {
|
|
42
|
+
return schemas.Fr.transform((fr: Fr) => new SiloedTag(fr));
|
|
43
|
+
}
|
|
44
|
+
}
|