@aztec/txe 0.74.0 → 0.75.0-commit.c03ba01a2a4122e43e90d5133ba017e54b90e9d2

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.
Files changed (36) hide show
  1. package/dest/bin/index.js +3 -5
  2. package/dest/index.js +112 -64
  3. package/dest/node/txe_node.js +292 -338
  4. package/dest/oracle/txe_oracle.js +208 -147
  5. package/dest/txe_service/txe_service.js +194 -118
  6. package/dest/util/encoding.js +16 -7
  7. package/dest/util/expected_failure_error.js +1 -2
  8. package/dest/util/txe_database.js +5 -9
  9. package/dest/util/txe_public_contract_data_source.js +21 -12
  10. package/dest/util/txe_world_state_db.js +7 -8
  11. package/package.json +14 -15
  12. package/src/index.ts +109 -35
  13. package/src/node/txe_node.ts +4 -0
  14. package/src/oracle/txe_oracle.ts +8 -29
  15. package/src/txe_service/txe_service.ts +14 -46
  16. package/src/util/encoding.ts +3 -3
  17. package/dest/bin/index.d.ts +0 -3
  18. package/dest/bin/index.d.ts.map +0 -1
  19. package/dest/index.d.ts +0 -8
  20. package/dest/index.d.ts.map +0 -1
  21. package/dest/node/txe_node.d.ts +0 -354
  22. package/dest/node/txe_node.d.ts.map +0 -1
  23. package/dest/oracle/txe_oracle.d.ts +0 -132
  24. package/dest/oracle/txe_oracle.d.ts.map +0 -1
  25. package/dest/txe_service/txe_service.d.ts +0 -204
  26. package/dest/txe_service/txe_service.d.ts.map +0 -1
  27. package/dest/util/encoding.d.ts +0 -29
  28. package/dest/util/encoding.d.ts.map +0 -1
  29. package/dest/util/expected_failure_error.d.ts +0 -4
  30. package/dest/util/expected_failure_error.d.ts.map +0 -1
  31. package/dest/util/txe_database.d.ts +0 -10
  32. package/dest/util/txe_database.d.ts.map +0 -1
  33. package/dest/util/txe_public_contract_data_source.d.ts +0 -18
  34. package/dest/util/txe_public_contract_data_source.d.ts.map +0 -1
  35. package/dest/util/txe_world_state_db.d.ts +0 -16
  36. package/dest/util/txe_world_state_db.d.ts.map +0 -1
@@ -1,125 +1,126 @@
1
- var _TXENode_logsByTags, _TXENode_txEffectsByTxHash, _TXENode_txReceiptsByTxHash, _TXENode_blockNumberToNullifiers, _TXENode_noteIndex, _TXENode_logger;
2
- import { __classPrivateFieldGet, __classPrivateFieldSet } from "tslib";
3
1
  import { createLogger } from '@aztec/aztec.js';
4
- import { L2BlockHash, TxHash, TxReceipt, TxScopedL2Log, } from '@aztec/circuit-types';
5
- import { PUBLIC_LOG_DATA_SIZE_IN_FIELDS, } from '@aztec/circuits.js';
2
+ import { L2BlockHash, TxHash, TxReceipt, TxScopedL2Log } from '@aztec/circuit-types';
3
+ import { PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/circuits.js';
6
4
  import { poseidon2Hash } from '@aztec/foundation/crypto';
7
5
  import { Fr } from '@aztec/foundation/fields';
8
6
  export class TXENode {
9
- constructor(blockNumber, version, chainId, nativeWorldStateService, baseFork) {
7
+ blockNumber;
8
+ version;
9
+ chainId;
10
+ nativeWorldStateService;
11
+ baseFork;
12
+ #logsByTags;
13
+ #txEffectsByTxHash;
14
+ #txReceiptsByTxHash;
15
+ #blockNumberToNullifiers;
16
+ #noteIndex;
17
+ #logger;
18
+ constructor(blockNumber, version, chainId, nativeWorldStateService, baseFork){
10
19
  this.blockNumber = blockNumber;
11
20
  this.version = version;
12
21
  this.chainId = chainId;
13
22
  this.nativeWorldStateService = nativeWorldStateService;
14
23
  this.baseFork = baseFork;
15
- _TXENode_logsByTags.set(this, new Map());
16
- _TXENode_txEffectsByTxHash.set(this, new Map());
17
- _TXENode_txReceiptsByTxHash.set(this, new Map());
18
- _TXENode_blockNumberToNullifiers.set(this, new Map());
19
- _TXENode_noteIndex.set(this, 0);
20
- _TXENode_logger.set(this, createLogger('aztec:txe_node'));
21
- }
22
- /**
23
- * Fetches the current block number.
24
- * @returns The block number.
25
- */
26
- getBlockNumber() {
24
+ this.#logsByTags = new Map();
25
+ this.#txEffectsByTxHash = new Map();
26
+ this.#txReceiptsByTxHash = new Map();
27
+ this.#blockNumberToNullifiers = new Map();
28
+ this.#noteIndex = 0;
29
+ this.#logger = createLogger('aztec:txe_node');
30
+ }
31
+ /**
32
+ * Fetches the current block number.
33
+ * @returns The block number.
34
+ */ getBlockNumber() {
27
35
  return Promise.resolve(this.blockNumber);
28
36
  }
29
37
  /**
30
- * Sets the current block number of the node.
31
- * @param - The block number to set.
32
- */
33
- setBlockNumber(blockNumber) {
38
+ * Sets the current block number of the node.
39
+ * @param - The block number to set.
40
+ */ setBlockNumber(blockNumber) {
34
41
  this.blockNumber = blockNumber;
35
42
  }
36
43
  /**
37
- * Get a tx effect.
38
- * @param txHash - The hash of a transaction which resulted in the returned tx effect.
39
- * @returns The requested tx effect.
40
- */
41
- getTxEffect(txHash) {
42
- const txEffect = __classPrivateFieldGet(this, _TXENode_txEffectsByTxHash, "f").get(txHash.toString());
44
+ * Get a tx effect.
45
+ * @param txHash - The hash of a transaction which resulted in the returned tx effect.
46
+ * @returns The requested tx effect.
47
+ */ getTxEffect(txHash) {
48
+ const txEffect = this.#txEffectsByTxHash.get(txHash.toString());
43
49
  return Promise.resolve(txEffect);
44
50
  }
45
51
  /**
46
- * Sets a tx effect and receipt for a given block number.
47
- * @param blockNumber - The block number that this tx effect resides.
48
- * @param txHash - The transaction hash of the transaction.
49
- * @param effect - The tx effect to set.
50
- */
51
- async setTxEffect(blockNumber, txHash, effect) {
52
+ * Sets a tx effect and receipt for a given block number.
53
+ * @param blockNumber - The block number that this tx effect resides.
54
+ * @param txHash - The transaction hash of the transaction.
55
+ * @param effect - The tx effect to set.
56
+ */ async setTxEffect(blockNumber, txHash, effect) {
52
57
  // We are not creating real blocks on which membership proofs can be constructed - we instead define its hash as
53
58
  // simply the hash of the block number.
54
- const blockHash = await poseidon2Hash([blockNumber]);
55
- __classPrivateFieldGet(this, _TXENode_txEffectsByTxHash, "f").set(txHash.toString(), {
59
+ const blockHash = await poseidon2Hash([
60
+ blockNumber
61
+ ]);
62
+ this.#txEffectsByTxHash.set(txHash.toString(), {
56
63
  l2BlockHash: blockHash.toString(),
57
64
  l2BlockNumber: blockNumber,
58
- data: effect,
65
+ data: effect
59
66
  });
60
67
  // We also set the receipt since we want to be able to serve `getTxReceipt` - we don't care about most values here,
61
68
  // but we do need to be able to retrieve the block number of a given txHash.
62
- __classPrivateFieldGet(this, _TXENode_txReceiptsByTxHash, "f").set(txHash.toString(), new TxReceipt(txHash, TxReceipt.statusFromRevertCode(effect.revertCode), '', undefined, new L2BlockHash(blockHash.toBuffer()), blockNumber, undefined));
69
+ this.#txReceiptsByTxHash.set(txHash.toString(), new TxReceipt(txHash, TxReceipt.statusFromRevertCode(effect.revertCode), '', undefined, new L2BlockHash(blockHash.toBuffer()), blockNumber, undefined));
63
70
  }
64
71
  /**
65
- * Returns the indexes of the given nullifiers in the nullifier tree,
66
- * scoped to the block they were included in.
67
- * @param blockNumber - The block number at which to get the data.
68
- * @param nullifiers - The nullifiers to search for.
69
- * @returns The block scoped indexes of the given nullifiers in the nullifier tree, or undefined if not found.
70
- */
71
- async findNullifiersIndexesWithBlock(blockNumber, nullifiers) {
72
+ * Returns the indexes of the given nullifiers in the nullifier tree,
73
+ * scoped to the block they were included in.
74
+ * @param blockNumber - The block number at which to get the data.
75
+ * @param nullifiers - The nullifiers to search for.
76
+ * @returns The block scoped indexes of the given nullifiers in the nullifier tree, or undefined if not found.
77
+ */ async findNullifiersIndexesWithBlock(blockNumber, nullifiers) {
72
78
  const parsedBlockNumber = blockNumber === 'latest' ? await this.getBlockNumber() : blockNumber;
73
79
  const nullifiersInBlock = [];
74
- for (const [key, val] of __classPrivateFieldGet(this, _TXENode_blockNumberToNullifiers, "f").entries()) {
80
+ for (const [key, val] of this.#blockNumberToNullifiers.entries()){
75
81
  if (key < parsedBlockNumber) {
76
82
  nullifiersInBlock.push(...val);
77
83
  }
78
84
  }
79
- return nullifiers.map(nullifier => {
80
- const possibleNullifierIndex = nullifiersInBlock.findIndex(nullifierInBlock => nullifierInBlock.equals(nullifier));
81
- return possibleNullifierIndex === -1
82
- ? undefined
83
- : {
84
- l2BlockNumber: parsedBlockNumber,
85
- l2BlockHash: new Fr(parsedBlockNumber).toString(),
86
- data: BigInt(possibleNullifierIndex),
87
- };
85
+ return nullifiers.map((nullifier)=>{
86
+ const possibleNullifierIndex = nullifiersInBlock.findIndex((nullifierInBlock)=>nullifierInBlock.equals(nullifier));
87
+ return possibleNullifierIndex === -1 ? undefined : {
88
+ l2BlockNumber: parsedBlockNumber,
89
+ l2BlockHash: new Fr(parsedBlockNumber).toString(),
90
+ data: BigInt(possibleNullifierIndex)
91
+ };
88
92
  });
89
93
  }
90
94
  /**
91
- * Returns the indexes of the given nullifiers in the nullifier tree,
92
- * scoped to the block they were included in.
93
- * @param blockNumber - The block number at which to get the data.
94
- * @param nullifiers - The nullifiers to search for.
95
- * @returns The block scoped indexes of the given nullifiers in the nullifier tree, or undefined if not found.
96
- */
97
- setNullifiersIndexesWithBlock(blockNumber, nullifiers) {
98
- __classPrivateFieldGet(this, _TXENode_blockNumberToNullifiers, "f").set(blockNumber, nullifiers);
95
+ * Returns the indexes of the given nullifiers in the nullifier tree,
96
+ * scoped to the block they were included in.
97
+ * @param blockNumber - The block number at which to get the data.
98
+ * @param nullifiers - The nullifiers to search for.
99
+ * @returns The block scoped indexes of the given nullifiers in the nullifier tree, or undefined if not found.
100
+ */ setNullifiersIndexesWithBlock(blockNumber, nullifiers) {
101
+ this.#blockNumberToNullifiers.set(blockNumber, nullifiers);
99
102
  }
100
103
  /**
101
- * Adds note logs to the txe node, given a block
102
- * @param blockNumber - The block number at which to add the note logs.
103
- * @param privateLogs - The privateLogs that contain the note logs to be added.
104
- */
105
- addNoteLogsByTags(blockNumber, privateLogs) {
106
- privateLogs.forEach(log => {
104
+ * Adds note logs to the txe node, given a block
105
+ * @param blockNumber - The block number at which to add the note logs.
106
+ * @param privateLogs - The privateLogs that contain the note logs to be added.
107
+ */ addNoteLogsByTags(blockNumber, privateLogs) {
108
+ privateLogs.forEach((log)=>{
107
109
  const tag = log.fields[0];
108
- const currentLogs = __classPrivateFieldGet(this, _TXENode_logsByTags, "f").get(tag.toString()) ?? [];
109
- const scopedLog = new TxScopedL2Log(new TxHash(new Fr(blockNumber)), __classPrivateFieldGet(this, _TXENode_noteIndex, "f"), blockNumber, false, log.toBuffer());
110
+ const currentLogs = this.#logsByTags.get(tag.toString()) ?? [];
111
+ const scopedLog = new TxScopedL2Log(new TxHash(new Fr(blockNumber)), this.#noteIndex, blockNumber, false, log.toBuffer());
110
112
  currentLogs.push(scopedLog);
111
- __classPrivateFieldGet(this, _TXENode_logsByTags, "f").set(tag.toString(), currentLogs);
113
+ this.#logsByTags.set(tag.toString(), currentLogs);
112
114
  });
113
115
  // TODO: DISTINGUISH BETWEEN EVENT LOGS AND NOTE LOGS ?
114
- __classPrivateFieldSet(this, _TXENode_noteIndex, __classPrivateFieldGet(this, _TXENode_noteIndex, "f") + privateLogs.length, "f");
116
+ this.#noteIndex += privateLogs.length;
115
117
  }
116
118
  /**
117
- * Adds public logs to the txe node, given a block
118
- * @param blockNumber - The block number at which to add the public logs.
119
- * @param publicLogs - The public logs to be added.
120
- */
121
- addPublicLogsByTags(blockNumber, publicLogs) {
122
- publicLogs.forEach(log => {
119
+ * Adds public logs to the txe node, given a block
120
+ * @param blockNumber - The block number at which to add the public logs.
121
+ * @param publicLogs - The public logs to be added.
122
+ */ addPublicLogsByTags(blockNumber, publicLogs) {
123
+ publicLogs.forEach((log)=>{
123
124
  // Check that each log stores 3 lengths in its first field. If not, it's not a tagged log:
124
125
  const firstFieldBuf = log.log[0].toBuffer();
125
126
  // See macros/note/mod/ and see how finalization_log[0] is constructed, to understand this monstrosity. (It wasn't me).
@@ -127,7 +128,7 @@ export class TXENode {
127
128
  if (!firstFieldBuf.subarray(0, 27).equals(Buffer.alloc(27)) || firstFieldBuf[29] !== 0) {
128
129
  // See parseLogFromPublic - the first field of a tagged log is 5 bytes structured:
129
130
  // [ publicLen[0], publicLen[1], 0, privateLen[0], privateLen[1]]
130
- __classPrivateFieldGet(this, _TXENode_logger, "f").warn(`Skipping public log with invalid first field: ${log.log[0]}`);
131
+ this.#logger.warn(`Skipping public log with invalid first field: ${log.log[0]}`);
131
132
  return;
132
133
  }
133
134
  // Check that the length values line up with the log contents
@@ -136,411 +137,364 @@ export class TXENode {
136
137
  // Add 1 for the first field holding lengths
137
138
  const totalLogLength = 1 + publicValuesLength + privateValuesLength;
138
139
  // Note that zeroes can be valid log values, so we can only assert that we do not go over the given length
139
- if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find(f => !f.isZero())) {
140
- __classPrivateFieldGet(this, _TXENode_logger, "f").warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
140
+ if (totalLogLength > PUBLIC_LOG_DATA_SIZE_IN_FIELDS || log.log.slice(totalLogLength).find((f)=>!f.isZero())) {
141
+ this.#logger.warn(`Skipping invalid tagged public log with first field: ${log.log[0]}`);
141
142
  return;
142
143
  }
143
144
  // The first elt stores lengths => tag is in fields[1]
144
145
  const tag = log.log[1];
145
- __classPrivateFieldGet(this, _TXENode_logger, "f").verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.getBlockNumber()}`);
146
- const currentLogs = __classPrivateFieldGet(this, _TXENode_logsByTags, "f").get(tag.toString()) ?? [];
147
- const scopedLog = new TxScopedL2Log(new TxHash(new Fr(blockNumber)), __classPrivateFieldGet(this, _TXENode_noteIndex, "f"), blockNumber, true, log.toBuffer());
146
+ this.#logger.verbose(`Found tagged public log with tag ${tag.toString()} in block ${this.getBlockNumber()}`);
147
+ const currentLogs = this.#logsByTags.get(tag.toString()) ?? [];
148
+ const scopedLog = new TxScopedL2Log(new TxHash(new Fr(blockNumber)), this.#noteIndex, blockNumber, true, log.toBuffer());
148
149
  currentLogs.push(scopedLog);
149
- __classPrivateFieldGet(this, _TXENode_logsByTags, "f").set(tag.toString(), currentLogs);
150
+ this.#logsByTags.set(tag.toString(), currentLogs);
150
151
  });
151
152
  }
152
153
  /**
153
- * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
154
- * @param tags - The tags to filter the logs by.
155
- * @returns For each received tag, an array of matching logs and metadata (e.g. tx hash) is returned. An empty
156
- array implies no logs match that tag.
157
- */
158
- getLogsByTags(tags) {
159
- const noteLogs = tags.map(tag => __classPrivateFieldGet(this, _TXENode_logsByTags, "f").get(tag.toString()) ?? []);
154
+ * Gets all logs that match any of the received tags (i.e. logs with their first field equal to a tag).
155
+ * @param tags - The tags to filter the logs by.
156
+ * @returns For each received tag, an array of matching logs and metadata (e.g. tx hash) is returned. An empty
157
+ array implies no logs match that tag.
158
+ */ getLogsByTags(tags) {
159
+ const noteLogs = tags.map((tag)=>this.#logsByTags.get(tag.toString()) ?? []);
160
160
  return Promise.resolve(noteLogs);
161
161
  }
162
162
  /**
163
- * Returns the tips of the L2 chain.
164
- */
165
- getL2Tips() {
163
+ * Returns the tips of the L2 chain.
164
+ */ getL2Tips() {
166
165
  throw new Error('TXE Node method getL2Tips not implemented');
167
166
  }
168
167
  /**
169
- * Find the indexes of the given leaves in the given tree.
170
- * @param blockNumber - The block number at which to get the data or 'latest' for latest data
171
- * @param treeId - The tree to search in.
172
- * @param leafValue - The values to search for
173
- * @returns The indexes of the given leaves in the given tree or undefined if not found.
174
- */
175
- async findLeavesIndexes(blockNumber, treeId, leafValues) {
168
+ * Find the indexes of the given leaves in the given tree.
169
+ * @param blockNumber - The block number at which to get the data or 'latest' for latest data
170
+ * @param treeId - The tree to search in.
171
+ * @param leafValue - The values to search for
172
+ * @returns The indexes of the given leaves in the given tree or undefined if not found.
173
+ */ async findLeavesIndexes(blockNumber, treeId, leafValues) {
176
174
  // Temporary workaround to be able to respond this query: the trees are currently stored in the TXE oracle, but we
177
175
  // hold a reference to them.
178
176
  // We should likely migrate this so that the trees are owned by the node.
179
177
  // TODO: blockNumber is being passed as undefined, figure out why
180
- const db = blockNumber === (await this.getBlockNumber()) || blockNumber === 'latest' || blockNumber === undefined
181
- ? this.baseFork
182
- : this.nativeWorldStateService.getSnapshot(blockNumber);
183
- return await db.findLeafIndices(treeId, leafValues.map(x => x.toBuffer()));
184
- }
185
- /**
186
- * Returns a sibling path for the given index in the nullifier tree.
187
- * @param blockNumber - The block number at which to get the data.
188
- * @param leafIndex - The index of the leaf for which the sibling path is required.
189
- * @returns The sibling path for the leaf index.
190
- */
191
- getNullifierSiblingPath(_blockNumber, _leafIndex) {
178
+ const db = blockNumber === await this.getBlockNumber() || blockNumber === 'latest' || blockNumber === undefined ? this.baseFork : this.nativeWorldStateService.getSnapshot(blockNumber);
179
+ return await db.findLeafIndices(treeId, leafValues.map((x)=>x.toBuffer()));
180
+ }
181
+ /**
182
+ * Returns a sibling path for the given index in the nullifier tree.
183
+ * @param blockNumber - The block number at which to get the data.
184
+ * @param leafIndex - The index of the leaf for which the sibling path is required.
185
+ * @returns The sibling path for the leaf index.
186
+ */ getNullifierSiblingPath(_blockNumber, _leafIndex) {
192
187
  throw new Error('TXE Node method getNullifierSiblingPath not implemented');
193
188
  }
194
189
  /**
195
- * Returns a sibling path for the given index in the note hash tree.
196
- * @param blockNumber - The block number at which to get the data.
197
- * @param leafIndex - The index of the leaf for which the sibling path is required.
198
- * @returns The sibling path for the leaf index.
199
- */
200
- getNoteHashSiblingPath(_blockNumber, _leafIndex) {
190
+ * Returns a sibling path for the given index in the note hash tree.
191
+ * @param blockNumber - The block number at which to get the data.
192
+ * @param leafIndex - The index of the leaf for which the sibling path is required.
193
+ * @returns The sibling path for the leaf index.
194
+ */ getNoteHashSiblingPath(_blockNumber, _leafIndex) {
201
195
  throw new Error('TXE Node method getNoteHashSiblingPath not implemented');
202
196
  }
203
197
  /**
204
- * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
205
- * @param blockNumber - The block number at which to get the data.
206
- * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
207
- * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
208
- */
209
- getL1ToL2MessageMembershipWitness(_blockNumber, _l1ToL2Message) {
198
+ * Returns the index and a sibling path for a leaf in the committed l1 to l2 data tree.
199
+ * @param blockNumber - The block number at which to get the data.
200
+ * @param l1ToL2Message - The l1ToL2Message to get the index / sibling path for.
201
+ * @returns A tuple of the index and the sibling path of the L1ToL2Message (undefined if not found).
202
+ */ getL1ToL2MessageMembershipWitness(_blockNumber, _l1ToL2Message) {
210
203
  throw new Error('TXE Node method getL1ToL2MessageMembershipWitness not implemented');
211
204
  }
212
205
  /**
213
- * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
214
- * @param l1ToL2Message - The L1 to L2 message to check.
215
- * @returns Whether the message is synced and ready to be included in a block.
216
- */
217
- isL1ToL2MessageSynced(_l1ToL2Message) {
206
+ * Returns whether an L1 to L2 message is synced by archiver and if it's ready to be included in a block.
207
+ * @param l1ToL2Message - The L1 to L2 message to check.
208
+ * @returns Whether the message is synced and ready to be included in a block.
209
+ */ isL1ToL2MessageSynced(_l1ToL2Message) {
218
210
  throw new Error('TXE Node method isL1ToL2MessageSynced not implemented');
219
211
  }
220
212
  /**
221
- * Returns a membership witness of an l2ToL1Message in an ephemeral l2 to l1 message tree.
222
- * @dev Membership witness is a consists of the index and the sibling path of the l2ToL1Message.
223
- * @remarks This tree is considered ephemeral because it is created on-demand by: taking all the l2ToL1 messages
224
- * in a single block, and then using them to make a variable depth append-only tree with these messages as leaves.
225
- * The tree is discarded immediately after calculating what we need from it.
226
- * @param blockNumber - The block number at which to get the data.
227
- * @param l2ToL1Message - The l2ToL1Message to get the membership witness for.
228
- * @returns A tuple of the index and the sibling path of the L2ToL1Message.
229
- */
230
- getL2ToL1MessageMembershipWitness(_blockNumber, _l2ToL1Message) {
213
+ * Returns a membership witness of an l2ToL1Message in an ephemeral l2 to l1 message tree.
214
+ * @dev Membership witness is a consists of the index and the sibling path of the l2ToL1Message.
215
+ * @remarks This tree is considered ephemeral because it is created on-demand by: taking all the l2ToL1 messages
216
+ * in a single block, and then using them to make a variable depth append-only tree with these messages as leaves.
217
+ * The tree is discarded immediately after calculating what we need from it.
218
+ * @param blockNumber - The block number at which to get the data.
219
+ * @param l2ToL1Message - The l2ToL1Message to get the membership witness for.
220
+ * @returns A tuple of the index and the sibling path of the L2ToL1Message.
221
+ */ getL2ToL1MessageMembershipWitness(_blockNumber, _l2ToL1Message) {
231
222
  throw new Error('TXE Node method getL2ToL1MessageMembershipWitness not implemented');
232
223
  }
233
224
  /**
234
- * Returns a sibling path for a leaf in the committed historic blocks tree.
235
- * @param blockNumber - The block number at which to get the data.
236
- * @param leafIndex - Index of the leaf in the tree.
237
- * @returns The sibling path.
238
- */
239
- getArchiveSiblingPath(_blockNumber, _leafIndex) {
225
+ * Returns a sibling path for a leaf in the committed historic blocks tree.
226
+ * @param blockNumber - The block number at which to get the data.
227
+ * @param leafIndex - Index of the leaf in the tree.
228
+ * @returns The sibling path.
229
+ */ getArchiveSiblingPath(_blockNumber, _leafIndex) {
240
230
  throw new Error('TXE Node method getArchiveSiblingPath not implemented');
241
231
  }
242
232
  /**
243
- * Returns a sibling path for a leaf in the committed public data tree.
244
- * @param blockNumber - The block number at which to get the data.
245
- * @param leafIndex - Index of the leaf in the tree.
246
- * @returns The sibling path.
247
- */
248
- getPublicDataSiblingPath(_blockNumber, _leafIndex) {
233
+ * Returns a sibling path for a leaf in the committed public data tree.
234
+ * @param blockNumber - The block number at which to get the data.
235
+ * @param leafIndex - Index of the leaf in the tree.
236
+ * @returns The sibling path.
237
+ */ getPublicDataSiblingPath(_blockNumber, _leafIndex) {
249
238
  throw new Error('TXE Node method getPublicDataSiblingPath not implemented');
250
239
  }
251
240
  /**
252
- * Returns a nullifier membership witness for a given nullifier at a given block.
253
- * @param blockNumber - The block number at which to get the data.
254
- * @param nullifier - Nullifier we try to find witness for.
255
- * @returns The nullifier membership witness (if found).
256
- */
257
- getNullifierMembershipWitness(_blockNumber, _nullifier) {
241
+ * Returns a nullifier membership witness for a given nullifier at a given block.
242
+ * @param blockNumber - The block number at which to get the data.
243
+ * @param nullifier - Nullifier we try to find witness for.
244
+ * @returns The nullifier membership witness (if found).
245
+ */ getNullifierMembershipWitness(_blockNumber, _nullifier) {
258
246
  throw new Error('TXE Node method getNullifierMembershipWitness not implemented');
259
247
  }
260
248
  /**
261
- * Returns a low nullifier membership witness for a given nullifier at a given block.
262
- * @param blockNumber - The block number at which to get the data.
263
- * @param nullifier - Nullifier we try to find the low nullifier witness for.
264
- * @returns The low nullifier membership witness (if found).
265
- * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
266
- * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
267
- * we are trying to prove non-inclusion for.
268
- */
269
- getLowNullifierMembershipWitness(_blockNumber, _nullifier) {
249
+ * Returns a low nullifier membership witness for a given nullifier at a given block.
250
+ * @param blockNumber - The block number at which to get the data.
251
+ * @param nullifier - Nullifier we try to find the low nullifier witness for.
252
+ * @returns The low nullifier membership witness (if found).
253
+ * @remarks Low nullifier witness can be used to perform a nullifier non-inclusion proof by leveraging the "linked
254
+ * list structure" of leaves and proving that a lower nullifier is pointing to a bigger next value than the nullifier
255
+ * we are trying to prove non-inclusion for.
256
+ */ getLowNullifierMembershipWitness(_blockNumber, _nullifier) {
270
257
  throw new Error('TXE Node method getLowNullifierMembershipWitness not implemented');
271
258
  }
272
259
  /**
273
- * Returns a public data tree witness for a given leaf slot at a given block.
274
- * @param blockNumber - The block number at which to get the data.
275
- * @param leafSlot - The leaf slot we try to find the witness for.
276
- * @returns The public data witness (if found).
277
- * @remarks The witness can be used to compute the current value of the public data tree leaf. If the low leaf preimage corresponds to an
278
- * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value
279
- * is contained in the leaf preimage.
280
- */
281
- getPublicDataTreeWitness(_blockNumber, _leafSlot) {
260
+ * Returns a public data tree witness for a given leaf slot at a given block.
261
+ * @param blockNumber - The block number at which to get the data.
262
+ * @param leafSlot - The leaf slot we try to find the witness for.
263
+ * @returns The public data witness (if found).
264
+ * @remarks The witness can be used to compute the current value of the public data tree leaf. If the low leaf preimage corresponds to an
265
+ * "in range" slot, means that the slot doesn't exist and the value is 0. If the low leaf preimage corresponds to the exact slot, the current value
266
+ * is contained in the leaf preimage.
267
+ */ getPublicDataTreeWitness(_blockNumber, _leafSlot) {
282
268
  throw new Error('TXE Node method getPublicDataTreeWitness not implemented');
283
269
  }
284
270
  /**
285
- * Get a block specified by its number.
286
- * @param number - The block number being requested.
287
- * @returns The requested block.
288
- */
289
- getBlock(_number) {
271
+ * Get a block specified by its number.
272
+ * @param number - The block number being requested.
273
+ * @returns The requested block.
274
+ */ getBlock(_number) {
290
275
  throw new Error('TXE Node method getBlock not implemented');
291
276
  }
292
277
  /**
293
- * Fetches the latest proven block number.
294
- * @returns The block number.
295
- */
296
- getProvenBlockNumber() {
278
+ * Fetches the latest proven block number.
279
+ * @returns The block number.
280
+ */ getProvenBlockNumber() {
297
281
  throw new Error('TXE Node method getProvenBlockNumber not implemented');
298
282
  }
299
283
  /**
300
- * Method to determine if the node is ready to accept transactions.
301
- * @returns - Flag indicating the readiness for tx submission.
302
- */
303
- isReady() {
284
+ * Method to determine if the node is ready to accept transactions.
285
+ * @returns - Flag indicating the readiness for tx submission.
286
+ */ isReady() {
304
287
  throw new Error('TXE Node method isReady not implemented');
305
288
  }
306
289
  /**
307
- * Method to request blocks. Will attempt to return all requested blocks but will return only those available.
308
- * @param from - The start of the range of blocks to return.
309
- * @param limit - The maximum number of blocks to return.
310
- * @returns The blocks requested.
311
- */
312
- getBlocks(_from, _limit) {
290
+ * Method to request blocks. Will attempt to return all requested blocks but will return only those available.
291
+ * @param from - The start of the range of blocks to return.
292
+ * @param limit - The maximum number of blocks to return.
293
+ * @returns The blocks requested.
294
+ */ getBlocks(_from, _limit) {
313
295
  throw new Error('TXE Node method getBlocks not implemented');
314
296
  }
315
297
  /**
316
- * Method to fetch the version of the package.
317
- * @returns The node package version
318
- */
319
- getNodeVersion() {
298
+ * Method to fetch the version of the package.
299
+ * @returns The node package version
300
+ */ getNodeVersion() {
320
301
  throw new Error('TXE Node method getNodeVersion not implemented');
321
302
  }
322
303
  /**
323
- * Method to fetch the version of the rollup the node is connected to.
324
- * @returns The rollup version.
325
- */
326
- getVersion() {
304
+ * Method to fetch the version of the rollup the node is connected to.
305
+ * @returns The rollup version.
306
+ */ getVersion() {
327
307
  return Promise.resolve(this.version);
328
308
  }
329
309
  /**
330
- * Method to fetch the chain id of the base-layer for the rollup.
331
- * @returns The chain id.
332
- */
333
- getChainId() {
310
+ * Method to fetch the chain id of the base-layer for the rollup.
311
+ * @returns The chain id.
312
+ */ getChainId() {
334
313
  return Promise.resolve(this.chainId);
335
314
  }
336
315
  /**
337
- * Method to fetch the currently deployed l1 contract addresses.
338
- * @returns The deployed contract addresses.
339
- */
340
- getL1ContractAddresses() {
316
+ * Method to fetch the currently deployed l1 contract addresses.
317
+ * @returns The deployed contract addresses.
318
+ */ getL1ContractAddresses() {
341
319
  throw new Error('TXE Node method getL1ContractAddresses not implemented');
342
320
  }
343
321
  /**
344
- * Method to fetch the protocol contract addresses.
345
- */
346
- getProtocolContractAddresses() {
322
+ * Method to fetch the protocol contract addresses.
323
+ */ getProtocolContractAddresses() {
347
324
  throw new Error('TXE Node method getProtocolContractAddresses not implemented');
348
325
  }
349
326
  /**
350
- * Method to add a contract artifact to the database.
351
- * @param aztecAddress
352
- * @param artifact
353
- */
354
- registerContractFunctionSignatures(_address, _signatures) {
327
+ * Method to add a contract artifact to the database.
328
+ * @param aztecAddress
329
+ * @param artifact
330
+ */ registerContractFunctionSignatures(_address, _signatures) {
355
331
  throw new Error('TXE Node method addContractArtifact not implemented');
356
332
  }
357
333
  /**
358
- * Gets public logs based on the provided filter.
359
- * @param filter - The filter to apply to the logs.
360
- * @returns The requested logs.
361
- */
362
- getPublicLogs(_filter) {
334
+ * Gets public logs based on the provided filter.
335
+ * @param filter - The filter to apply to the logs.
336
+ * @returns The requested logs.
337
+ */ getPublicLogs(_filter) {
363
338
  throw new Error('TXE Node method getPublicLogs not implemented');
364
339
  }
365
340
  /**
366
- * Gets contract class logs based on the provided filter.
367
- * @param filter - The filter to apply to the logs.
368
- * @returns The requested logs.
369
- */
370
- getContractClassLogs(_filter) {
341
+ * Gets contract class logs based on the provided filter.
342
+ * @param filter - The filter to apply to the logs.
343
+ * @returns The requested logs.
344
+ */ getContractClassLogs(_filter) {
371
345
  throw new Error('TXE Node method getContractClassLogs not implemented');
372
346
  }
373
347
  /**
374
- * Method to submit a transaction to the p2p pool.
375
- * @param tx - The transaction to be submitted.
376
- * @returns Nothing.
377
- */
378
- sendTx(_tx) {
348
+ * Method to submit a transaction to the p2p pool.
349
+ * @param tx - The transaction to be submitted.
350
+ * @returns Nothing.
351
+ */ sendTx(_tx) {
379
352
  throw new Error('TXE Node method sendTx not implemented');
380
353
  }
381
354
  /**
382
- * Fetches a transaction receipt for a given transaction hash. Returns a mined receipt if it was added
383
- * to the chain, a pending receipt if it's still in the mempool of the connected Aztec node, or a dropped
384
- * receipt if not found in the connected Aztec node.
385
- *
386
- * @param txHash - The transaction hash.
387
- * @returns A receipt of the transaction.
388
- */
389
- getTxReceipt(txHash) {
390
- const txEffect = __classPrivateFieldGet(this, _TXENode_txReceiptsByTxHash, "f").get(txHash.toString());
355
+ * Fetches a transaction receipt for a given transaction hash. Returns a mined receipt if it was added
356
+ * to the chain, a pending receipt if it's still in the mempool of the connected Aztec node, or a dropped
357
+ * receipt if not found in the connected Aztec node.
358
+ *
359
+ * @param txHash - The transaction hash.
360
+ * @returns A receipt of the transaction.
361
+ */ getTxReceipt(txHash) {
362
+ const txEffect = this.#txReceiptsByTxHash.get(txHash.toString());
391
363
  if (!txEffect) {
392
364
  throw new Error('Unknown txHash');
393
365
  }
394
366
  return Promise.resolve(txEffect);
395
367
  }
396
368
  /**
397
- * Method to retrieve pending txs.
398
- * @returns The pending txs.
399
- */
400
- getPendingTxs() {
369
+ * Method to retrieve pending txs.
370
+ * @returns The pending txs.
371
+ */ getPendingTxs() {
401
372
  throw new Error('TXE Node method getPendingTxs not implemented');
402
373
  }
403
374
  /**
404
- * Retrieves the number of pending txs
405
- * @returns The number of pending txs.
406
- */
407
- getPendingTxCount() {
375
+ * Retrieves the number of pending txs
376
+ * @returns The number of pending txs.
377
+ */ getPendingTxCount() {
408
378
  throw new Error('TXE Node method getPendingTxCount not implemented');
409
379
  }
410
380
  /**
411
- * Method to retrieve a single pending tx.
412
- * @param txHash - The transaction hash to return.
413
- * @returns The pending tx if it exists.
414
- */
415
- getTxByHash(_txHash) {
381
+ * Method to retrieve a single pending tx.
382
+ * @param txHash - The transaction hash to return.
383
+ * @returns The pending tx if it exists.
384
+ */ getTxByHash(_txHash) {
385
+ throw new Error('TXE Node method getTxByHash not implemented');
386
+ }
387
+ getTxsByHash(_txHashes) {
416
388
  throw new Error('TXE Node method getTxByHash not implemented');
417
389
  }
418
390
  /**
419
- * Gets the storage value at the given contract storage slot.
420
- *
421
- * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
422
- * Aztec's version of `eth_getStorageAt`.
423
- *
424
- * @param contract - Address of the contract to query.
425
- * @param slot - Slot to query.
426
- * @param blockNumber - The block number at which to get the data or 'latest'.
427
- * @returns Storage value at the given contract slot.
428
- */
429
- getPublicStorageAt(_contract, _slot, _blockNumber) {
391
+ * Gets the storage value at the given contract storage slot.
392
+ *
393
+ * @remarks The storage slot here refers to the slot as it is defined in Noir not the index in the merkle tree.
394
+ * Aztec's version of `eth_getStorageAt`.
395
+ *
396
+ * @param contract - Address of the contract to query.
397
+ * @param slot - Slot to query.
398
+ * @param blockNumber - The block number at which to get the data or 'latest'.
399
+ * @returns Storage value at the given contract slot.
400
+ */ getPublicStorageAt(_contract, _slot, _blockNumber) {
430
401
  throw new Error('TXE Node method getPublicStorageAt not implemented');
431
402
  }
432
403
  /**
433
- * Returns the currently committed block header.
434
- * @returns The current committed block header.
435
- */
436
- getBlockHeader(_blockNumber) {
404
+ * Returns the currently committed block header.
405
+ * @returns The current committed block header.
406
+ */ getBlockHeader(_blockNumber) {
437
407
  throw new Error('TXE Node method getBlockHeader not implemented');
438
408
  }
439
409
  /**
440
- * Simulates the public part of a transaction with the current state.
441
- * This currently just checks that the transaction execution succeeds.
442
- * @param tx - The transaction to simulate.
443
- **/
444
- simulatePublicCalls(_tx, _enforceFeePayment = false) {
410
+ * Simulates the public part of a transaction with the current state.
411
+ * This currently just checks that the transaction execution succeeds.
412
+ * @param tx - The transaction to simulate.
413
+ **/ simulatePublicCalls(_tx, _enforceFeePayment = false) {
445
414
  throw new Error('TXE Node method simulatePublicCalls not implemented');
446
415
  }
447
416
  /**
448
- * Returns true if the transaction is valid for inclusion at the current state. Valid transactions can be
449
- * made invalid by *other* transactions if e.g. they emit the same nullifiers, or come become invalid
450
- * due to e.g. the max_block_number property.
451
- * @param tx - The transaction to validate for correctness.
452
- * @param isSimulation - True if the transaction is a simulated one without generated proofs. (Optional)
453
- */
454
- isValidTx(_tx, _isSimulation) {
417
+ * Returns true if the transaction is valid for inclusion at the current state. Valid transactions can be
418
+ * made invalid by *other* transactions if e.g. they emit the same nullifiers, or come become invalid
419
+ * due to e.g. the max_block_number property.
420
+ * @param tx - The transaction to validate for correctness.
421
+ * @param isSimulation - True if the transaction is a simulated one without generated proofs. (Optional)
422
+ */ isValidTx(_tx, _isSimulation) {
455
423
  throw new Error('TXE Node method isValidTx not implemented');
456
424
  }
457
425
  /**
458
- * Updates the configuration of this node.
459
- * @param config - Updated configuration to be merged with the current one.
460
- */
461
- setConfig(_config) {
426
+ * Updates the configuration of this node.
427
+ * @param config - Updated configuration to be merged with the current one.
428
+ */ setConfig(_config) {
462
429
  throw new Error('TXE Node method setConfig not implemented');
463
430
  }
464
431
  /**
465
- * Returns a registered contract class given its id.
466
- * @param id - Id of the contract class.
467
- */
468
- getContractClass(_id) {
432
+ * Returns a registered contract class given its id.
433
+ * @param id - Id of the contract class.
434
+ */ getContractClass(_id) {
469
435
  throw new Error('TXE Node method getContractClass not implemented');
470
436
  }
471
437
  /**
472
- * Returns a publicly deployed contract instance given its address.
473
- * @param address - Address of the deployed contract.
474
- */
475
- getContract(_address) {
438
+ * Returns a publicly deployed contract instance given its address.
439
+ * @param address - Address of the deployed contract.
440
+ */ getContract(_address) {
476
441
  throw new Error('TXE Node method getContract not implemented');
477
442
  }
478
- /** Forces the next block to be built bypassing all time and pending checks. Useful for testing. */
479
- flushTxs() {
443
+ /** Forces the next block to be built bypassing all time and pending checks. Useful for testing. */ flushTxs() {
480
444
  throw new Error('TXE Node method flushTxs not implemented');
481
445
  }
482
446
  /**
483
- * Returns the ENR of this node for peer discovery, if available.
484
- */
485
- getEncodedEnr() {
447
+ * Returns the ENR of this node for peer discovery, if available.
448
+ */ getEncodedEnr() {
486
449
  throw new Error('TXE Node method getEncodedEnr not implemented');
487
450
  }
488
451
  /**
489
- * Receives a quote for an epoch proof and stores it in its EpochProofQuotePool
490
- * @param quote - The quote to store
491
- */
492
- addEpochProofQuote(_quote) {
452
+ * Receives a quote for an epoch proof and stores it in its EpochProofQuotePool
453
+ * @param quote - The quote to store
454
+ */ addEpochProofQuote(_quote) {
493
455
  throw new Error('TXE Node method addEpochProofQuote not implemented');
494
456
  }
495
457
  /**
496
- * Returns the received quotes for a given epoch
497
- * @param epoch - The epoch for which to get the quotes
498
- */
499
- getEpochProofQuotes(_epoch) {
458
+ * Returns the received quotes for a given epoch
459
+ * @param epoch - The epoch for which to get the quotes
460
+ */ getEpochProofQuotes(_epoch) {
500
461
  throw new Error('TXE Node method getEpochProofQuotes not implemented');
501
462
  }
502
463
  /**
503
- * Adds a contract class bypassing the registerer.
504
- * TODO(#10007): Remove this method.
505
- * @param contractClass - The class to register.
506
- */
507
- addContractClass(_contractClass) {
464
+ * Adds a contract class bypassing the registerer.
465
+ * TODO(#10007): Remove this method.
466
+ * @param contractClass - The class to register.
467
+ */ addContractClass(_contractClass) {
508
468
  throw new Error('TXE Node method addContractClass not implemented');
509
469
  }
510
470
  /**
511
- * Method to fetch the current base fees.
512
- * @returns The current base fees.
513
- */
514
- getCurrentBaseFees() {
471
+ * Method to fetch the current base fees.
472
+ * @returns The current base fees.
473
+ */ getCurrentBaseFees() {
515
474
  throw new Error('TXE Node method getCurrentBaseFees not implemented');
516
475
  }
517
476
  /**
518
- * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
519
- * @param from - The block number from which to begin retrieving logs.
520
- * @param limit - The maximum number of blocks to retrieve logs from.
521
- * @returns An array of private logs from the specified range of blocks.
522
- */
523
- getPrivateLogs(_from, _limit) {
477
+ * Retrieves all private logs from up to `limit` blocks, starting from the block number `from`.
478
+ * @param from - The block number from which to begin retrieving logs.
479
+ * @param limit - The maximum number of blocks to retrieve logs from.
480
+ * @returns An array of private logs from the specified range of blocks.
481
+ */ getPrivateLogs(_from, _limit) {
524
482
  throw new Error('TXE Node method getPrivateLogs not implemented');
525
483
  }
526
484
  /**
527
- * Find the block numbers of the given leaf indices in the given tree.
528
- * @param blockNumber - The block number at which to get the data or 'latest' for latest data
529
- * @param treeId - The tree to search in.
530
- * @param leafIndices - The values to search for
531
- * @returns The indexes of the given leaves in the given tree or undefined if not found.
532
- */
533
- findBlockNumbersForIndexes(_blockNumber, _treeId, _leafIndices) {
485
+ * Find the block numbers of the given leaf indices in the given tree.
486
+ * @param blockNumber - The block number at which to get the data or 'latest' for latest data
487
+ * @param treeId - The tree to search in.
488
+ * @param leafIndices - The values to search for
489
+ * @returns The indexes of the given leaves in the given tree or undefined if not found.
490
+ */ findBlockNumbersForIndexes(_blockNumber, _treeId, _leafIndices) {
534
491
  throw new Error('TXE Node method findBlockNumbersForIndexes not implemented');
535
492
  }
536
493
  /**
537
- * Returns the information about the server's node. Includes current Node version, compatible Noir version,
538
- * L1 chain identifier, protocol version, and L1 address of the rollup contract.
539
- * @returns - The node information.
540
- */
541
- getNodeInfo() {
494
+ * Returns the information about the server's node. Includes current Node version, compatible Noir version,
495
+ * L1 chain identifier, protocol version, and L1 address of the rollup contract.
496
+ * @returns - The node information.
497
+ */ getNodeInfo() {
542
498
  throw new Error('TXE Node method getNodeInfo not implemented');
543
499
  }
544
500
  }
545
- _TXENode_logsByTags = new WeakMap(), _TXENode_txEffectsByTxHash = new WeakMap(), _TXENode_txReceiptsByTxHash = new WeakMap(), _TXENode_blockNumberToNullifiers = new WeakMap(), _TXENode_noteIndex = new WeakMap(), _TXENode_logger = new WeakMap();
546
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidHhlX25vZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbm9kZS90eGVfbm9kZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBT0wsV0FBVyxFQWVYLE1BQU0sRUFDTixTQUFTLEVBQ1QsYUFBYSxHQUVkLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQVlMLDhCQUE4QixHQUkvQixNQUFNLG9CQUFvQixDQUFDO0FBRTVCLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsRUFBRSxFQUFFLE1BQU0sMEJBQTBCLENBQUM7QUFHOUMsTUFBTSxPQUFPLE9BQU87SUFTbEIsWUFDVSxXQUFtQixFQUNuQixPQUFlLEVBQ2YsT0FBZSxFQUNmLHVCQUFnRCxFQUNoRCxRQUFtQztRQUpuQyxnQkFBVyxHQUFYLFdBQVcsQ0FBUTtRQUNuQixZQUFPLEdBQVAsT0FBTyxDQUFRO1FBQ2YsWUFBTyxHQUFQLE9BQU8sQ0FBUTtRQUNmLDRCQUF1QixHQUF2Qix1QkFBdUIsQ0FBeUI7UUFDaEQsYUFBUSxHQUFSLFFBQVEsQ0FBMkI7UUFiN0MsOEJBQWMsSUFBSSxHQUFHLEVBQTJCLEVBQUM7UUFDakQscUNBQXFCLElBQUksR0FBRyxFQUE2QixFQUFDO1FBQzFELHNDQUFzQixJQUFJLEdBQUcsRUFBcUIsRUFBQztRQUNuRCwyQ0FBMkIsSUFBSSxHQUFHLEVBQWdCLEVBQUM7UUFDbkQsNkJBQWEsQ0FBQyxFQUFDO1FBRWYsMEJBQVUsWUFBWSxDQUFDLGdCQUFnQixDQUFDLEVBQUM7SUFRdEMsQ0FBQztJQUVKOzs7T0FHRztJQUNILGNBQWM7UUFDWixPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7O09BR0c7SUFDSCxjQUFjLENB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