@aztec/txe 0.76.4 → 0.77.0-testnet-ignition.21

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