@aztec/pxe 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 (101) hide show
  1. package/dest/bin/index.js +3 -5
  2. package/dest/config/index.js +18 -21
  3. package/dest/config/package_info.js +4 -2
  4. package/dest/contract_data_oracle/index.js +69 -79
  5. package/dest/contract_data_oracle/private_functions_tree.js +44 -50
  6. package/dest/database/contracts/contract_artifact_db.js +3 -2
  7. package/dest/database/contracts/contract_instance_db.js +3 -2
  8. package/dest/database/index.js +0 -1
  9. package/dest/database/kv_pxe_database.js +243 -259
  10. package/dest/database/note_dao.js +28 -43
  11. package/dest/database/outgoing_note_dao.js +20 -34
  12. package/dest/database/pxe_database.js +4 -2
  13. package/dest/database/pxe_database_test_suite.js +296 -151
  14. package/dest/index.js +0 -1
  15. package/dest/kernel_oracle/index.js +9 -6
  16. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.js +68 -66
  17. package/dest/kernel_prover/hints/index.js +0 -1
  18. package/dest/kernel_prover/index.js +0 -1
  19. package/dest/kernel_prover/kernel_prover.js +60 -65
  20. package/dest/kernel_prover/proving_data_oracle.js +4 -2
  21. package/dest/note_decryption_utils/add_public_values_to_payload.js +8 -9
  22. package/dest/pxe_http/index.js +0 -1
  23. package/dest/pxe_http/pxe_http_server.js +8 -6
  24. package/dest/pxe_service/error_enriching.js +10 -13
  25. package/dest/pxe_service/index.js +0 -1
  26. package/dest/pxe_service/pxe_service.js +282 -290
  27. package/dest/pxe_service/test/pxe_test_suite.js +40 -27
  28. package/dest/simulator/index.js +1 -3
  29. package/dest/simulator_oracle/index.js +266 -231
  30. package/dest/simulator_oracle/tagging_utils.js +4 -6
  31. package/dest/synchronizer/index.js +0 -1
  32. package/dest/synchronizer/synchronizer.js +42 -42
  33. package/dest/utils/create_pxe_service.js +9 -9
  34. package/package.json +15 -15
  35. package/src/pxe_service/pxe_service.ts +6 -11
  36. package/dest/bin/index.d.ts +0 -3
  37. package/dest/bin/index.d.ts.map +0 -1
  38. package/dest/config/index.d.ts +0 -46
  39. package/dest/config/index.d.ts.map +0 -1
  40. package/dest/config/package_info.d.ts +0 -5
  41. package/dest/config/package_info.d.ts.map +0 -1
  42. package/dest/contract_data_oracle/index.d.ts +0 -104
  43. package/dest/contract_data_oracle/index.d.ts.map +0 -1
  44. package/dest/contract_data_oracle/private_functions_tree.d.ts +0 -65
  45. package/dest/contract_data_oracle/private_functions_tree.d.ts.map +0 -1
  46. package/dest/database/contracts/contract_artifact_db.d.ts +0 -20
  47. package/dest/database/contracts/contract_artifact_db.d.ts.map +0 -1
  48. package/dest/database/contracts/contract_instance_db.d.ts +0 -19
  49. package/dest/database/contracts/contract_instance_db.d.ts.map +0 -1
  50. package/dest/database/index.d.ts +0 -3
  51. package/dest/database/index.d.ts.map +0 -1
  52. package/dest/database/kv_pxe_database.d.ts +0 -55
  53. package/dest/database/kv_pxe_database.d.ts.map +0 -1
  54. package/dest/database/note_dao.d.ts +0 -103
  55. package/dest/database/note_dao.d.ts.map +0 -1
  56. package/dest/database/outgoing_note_dao.d.ts +0 -73
  57. package/dest/database/outgoing_note_dao.d.ts.map +0 -1
  58. package/dest/database/pxe_database.d.ts +0 -216
  59. package/dest/database/pxe_database.d.ts.map +0 -1
  60. package/dest/database/pxe_database_test_suite.d.ts +0 -7
  61. package/dest/database/pxe_database_test_suite.d.ts.map +0 -1
  62. package/dest/index.d.ts +0 -15
  63. package/dest/index.d.ts.map +0 -1
  64. package/dest/kernel_oracle/index.d.ts +0 -34
  65. package/dest/kernel_oracle/index.d.ts.map +0 -1
  66. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts +0 -28
  67. package/dest/kernel_prover/hints/build_private_kernel_reset_private_inputs.d.ts.map +0 -1
  68. package/dest/kernel_prover/hints/index.d.ts +0 -2
  69. package/dest/kernel_prover/hints/index.d.ts.map +0 -1
  70. package/dest/kernel_prover/index.d.ts +0 -3
  71. package/dest/kernel_prover/index.d.ts.map +0 -1
  72. package/dest/kernel_prover/kernel_prover.d.ts +0 -38
  73. package/dest/kernel_prover/kernel_prover.d.ts.map +0 -1
  74. package/dest/kernel_prover/proving_data_oracle.d.ts +0 -65
  75. package/dest/kernel_prover/proving_data_oracle.d.ts.map +0 -1
  76. package/dest/note_decryption_utils/add_public_values_to_payload.d.ts +0 -10
  77. package/dest/note_decryption_utils/add_public_values_to_payload.d.ts.map +0 -1
  78. package/dest/pxe_http/index.d.ts +0 -2
  79. package/dest/pxe_http/index.d.ts.map +0 -1
  80. package/dest/pxe_http/pxe_http_server.d.ts +0 -16
  81. package/dest/pxe_http/pxe_http_server.d.ts.map +0 -1
  82. package/dest/pxe_service/error_enriching.d.ts +0 -11
  83. package/dest/pxe_service/error_enriching.d.ts.map +0 -1
  84. package/dest/pxe_service/index.d.ts +0 -4
  85. package/dest/pxe_service/index.d.ts.map +0 -1
  86. package/dest/pxe_service/pxe_service.d.ts +0 -98
  87. package/dest/pxe_service/pxe_service.d.ts.map +0 -1
  88. package/dest/pxe_service/test/pxe_test_suite.d.ts +0 -3
  89. package/dest/pxe_service/test/pxe_test_suite.d.ts.map +0 -1
  90. package/dest/simulator/index.d.ts +0 -10
  91. package/dest/simulator/index.d.ts.map +0 -1
  92. package/dest/simulator_oracle/index.d.ts +0 -129
  93. package/dest/simulator_oracle/index.d.ts.map +0 -1
  94. package/dest/simulator_oracle/tagging_utils.d.ts +0 -16
  95. package/dest/simulator_oracle/tagging_utils.d.ts.map +0 -1
  96. package/dest/synchronizer/index.d.ts +0 -2
  97. package/dest/synchronizer/index.d.ts.map +0 -1
  98. package/dest/synchronizer/synchronizer.d.ts +0 -30
  99. package/dest/synchronizer/synchronizer.d.ts.map +0 -1
  100. package/dest/utils/create_pxe_service.d.ts +0 -16
  101. package/dest/utils/create_pxe_service.d.ts.map +0 -1
@@ -1,13 +1,11 @@
1
- var _SimulatorOracle_instances, _SimulatorOracle_findLeafIndex, _SimulatorOracle_getSiblingPath, _SimulatorOracle_calculateAppTaggingSecret, _SimulatorOracle_getIndexedTaggingSecretsForSenders, _SimulatorOracle_decryptTaggedLogs;
2
- import { __classPrivateFieldGet } from "tslib";
3
- import { L1NotePayload, MerkleTreeId, Note, TxHash, getNonNullifiedL1ToL2MessageWitness, } from '@aztec/circuit-types';
4
- import { Fr, FunctionSelector, IndexedTaggingSecret, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, PrivateLog, PublicLog, computeAddressSecret, computeTaggingSecretPoint, } from '@aztec/circuits.js';
1
+ import { L1NotePayload, MerkleTreeId, Note, TxHash, getNonNullifiedL1ToL2MessageWitness } from '@aztec/circuit-types';
2
+ import { Fr, FunctionSelector, IndexedTaggingSecret, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS, PrivateLog, PublicLog, computeAddressSecret, computeTaggingSecretPoint } from '@aztec/circuits.js';
5
3
  import { computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/circuits.js/hash';
6
- import { FunctionType, NoteSelector, encodeArguments, getFunctionArtifact, } from '@aztec/foundation/abi';
4
+ import { FunctionType, NoteSelector, encodeArguments, getFunctionArtifact } from '@aztec/foundation/abi';
7
5
  import { timesParallel } from '@aztec/foundation/collection';
8
6
  import { poseidon2Hash } from '@aztec/foundation/crypto';
9
7
  import { createLogger } from '@aztec/foundation/log';
10
- import { MessageLoadOracleInputs, } from '@aztec/simulator/client';
8
+ import { MessageLoadOracleInputs } from '@aztec/simulator/client';
11
9
  import { ContractDataOracle } from '../contract_data_oracle/index.js';
12
10
  import { NoteDao } from '../database/note_dao.js';
13
11
  import { getOrderedNoteItems } from '../note_decryption_utils/add_public_values_to_payload.js';
@@ -15,10 +13,14 @@ import { getAcirSimulator } from '../simulator/index.js';
15
13
  import { WINDOW_HALF_SIZE, getIndexedTaggingSecretsForTheWindow, getInitialIndexesMap } from './tagging_utils.js';
16
14
  /**
17
15
  * A data oracle that provides information needed for simulating a transaction.
18
- */
19
- export class SimulatorOracle {
20
- constructor(contractDataOracle, db, keyStore, aztecNode, simulationProvider, log = createLogger('pxe:simulator_oracle')) {
21
- _SimulatorOracle_instances.add(this);
16
+ */ export class SimulatorOracle {
17
+ contractDataOracle;
18
+ db;
19
+ keyStore;
20
+ aztecNode;
21
+ simulationProvider;
22
+ log;
23
+ constructor(contractDataOracle, db, keyStore, aztecNode, simulationProvider, log = createLogger('pxe:simulator_oracle')){
22
24
  this.contractDataOracle = contractDataOracle;
23
25
  this.db = db;
24
26
  this.keyStore = keyStore;
@@ -63,25 +65,25 @@ export class SimulatorOracle {
63
65
  contractAddress,
64
66
  storageSlot,
65
67
  status,
66
- scopes,
68
+ scopes
67
69
  });
68
- return noteDaos.map(({ contractAddress, storageSlot, nonce, note, noteHash, siloedNullifier, index }) => ({
69
- contractAddress,
70
- storageSlot,
71
- nonce,
72
- note,
73
- noteHash,
74
- siloedNullifier,
75
- // PXE can use this index to get full MembershipWitness
76
- index,
77
- }));
70
+ return noteDaos.map(({ contractAddress, storageSlot, nonce, note, noteHash, siloedNullifier, index })=>({
71
+ contractAddress,
72
+ storageSlot,
73
+ nonce,
74
+ note,
75
+ noteHash,
76
+ siloedNullifier,
77
+ // PXE can use this index to get full MembershipWitness
78
+ index
79
+ }));
78
80
  }
79
81
  async getFunctionArtifact(contractAddress, selector) {
80
82
  const artifact = await this.contractDataOracle.getFunctionArtifact(contractAddress, selector);
81
83
  const debug = await this.contractDataOracle.getFunctionDebugMetadata(contractAddress, selector);
82
84
  return {
83
85
  ...artifact,
84
- debug,
86
+ debug
85
87
  };
86
88
  }
87
89
  async getFunctionArtifactByName(contractAddress, functionName) {
@@ -90,14 +92,13 @@ export class SimulatorOracle {
90
92
  return artifact && getFunctionArtifact(artifact, functionName);
91
93
  }
92
94
  /**
93
- * Fetches a message from the db, given its key.
94
- * @param contractAddress - Address of a contract by which the message was emitted.
95
- * @param messageHash - Hash of the message.
96
- * @param secret - Secret used to compute a nullifier.
97
- * @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
98
- * @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
99
- */
100
- async getL1ToL2MembershipWitness(contractAddress, messageHash, secret) {
95
+ * Fetches a message from the db, given its key.
96
+ * @param contractAddress - Address of a contract by which the message was emitted.
97
+ * @param messageHash - Hash of the message.
98
+ * @param secret - Secret used to compute a nullifier.
99
+ * @dev Contract address and secret are only used to compute the nullifier to get non-nullified messages
100
+ * @returns The l1 to l2 membership witness (index of message in the tree and sibling path).
101
+ */ async getL1ToL2MembershipWitness(contractAddress, messageHash, secret) {
101
102
  const [messageIndex, siblingPath] = await getNonNullifiedL1ToL2MessageWitness(this.aztecNode, contractAddress, messageHash, secret);
102
103
  // Assuming messageIndex is what you intended to use for the index in MessageLoadOracleInputs
103
104
  return new MessageLoadOracleInputs(messageIndex, siblingPath);
@@ -107,27 +108,49 @@ export class SimulatorOracle {
107
108
  throw new Error('Unimplemented in private!');
108
109
  }
109
110
  /**
110
- * Gets the index of a commitment in the note hash tree.
111
- * @param commitment - The commitment.
112
- * @returns - The index of the commitment. Undefined if it does not exist in the tree.
113
- */
114
- async getCommitmentIndex(commitment) {
115
- return await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_findLeafIndex).call(this, 'latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
111
+ * Gets the index of a commitment in the note hash tree.
112
+ * @param commitment - The commitment.
113
+ * @returns - The index of the commitment. Undefined if it does not exist in the tree.
114
+ */ async getCommitmentIndex(commitment) {
115
+ return await this.#findLeafIndex('latest', MerkleTreeId.NOTE_HASH_TREE, commitment);
116
116
  }
117
117
  // We need this in public as part of the EXISTS calls - but isn't used in private
118
118
  getCommitmentValue(_leafIndex) {
119
119
  throw new Error('Unimplemented in private!');
120
120
  }
121
121
  async getNullifierIndex(nullifier) {
122
- return await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_findLeafIndex).call(this, 'latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
122
+ return await this.#findLeafIndex('latest', MerkleTreeId.NULLIFIER_TREE, nullifier);
123
+ }
124
+ async #findLeafIndex(blockNumber, treeId, leafValue) {
125
+ const [leafIndex] = await this.aztecNode.findLeavesIndexes(blockNumber, treeId, [
126
+ leafValue
127
+ ]);
128
+ return leafIndex;
123
129
  }
124
130
  async getMembershipWitness(blockNumber, treeId, leafValue) {
125
- const leafIndex = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_findLeafIndex).call(this, blockNumber, treeId, leafValue);
131
+ const leafIndex = await this.#findLeafIndex(blockNumber, treeId, leafValue);
126
132
  if (!leafIndex) {
127
133
  throw new Error(`Leaf value: ${leafValue} not found in ${MerkleTreeId[treeId]}`);
128
134
  }
129
- const siblingPath = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_getSiblingPath).call(this, blockNumber, treeId, leafIndex);
130
- return [new Fr(leafIndex), ...siblingPath];
135
+ const siblingPath = await this.#getSiblingPath(blockNumber, treeId, leafIndex);
136
+ return [
137
+ new Fr(leafIndex),
138
+ ...siblingPath
139
+ ];
140
+ }
141
+ async #getSiblingPath(blockNumber, treeId, leafIndex) {
142
+ switch(treeId){
143
+ case MerkleTreeId.NULLIFIER_TREE:
144
+ return (await this.aztecNode.getNullifierSiblingPath(blockNumber, leafIndex)).toFields();
145
+ case MerkleTreeId.NOTE_HASH_TREE:
146
+ return (await this.aztecNode.getNoteHashSiblingPath(blockNumber, leafIndex)).toFields();
147
+ case MerkleTreeId.PUBLIC_DATA_TREE:
148
+ return (await this.aztecNode.getPublicDataSiblingPath(blockNumber, leafIndex)).toFields();
149
+ case MerkleTreeId.ARCHIVE:
150
+ return (await this.aztecNode.getArchiveSiblingPath(blockNumber, leafIndex)).toFields();
151
+ default:
152
+ throw new Error('Not implemented');
153
+ }
131
154
  }
132
155
  async getNullifierMembershipWitnessAtLatestBlock(nullifier) {
133
156
  return this.getNullifierMembershipWitness(await this.getBlockNumber(), nullifier);
@@ -145,76 +168,118 @@ export class SimulatorOracle {
145
168
  return await this.aztecNode.getPublicDataTreeWitness(blockNumber, leafSlot);
146
169
  }
147
170
  /**
148
- * Retrieve the databases view of the Block Header object.
149
- * This structure is fed into the circuits simulator and is used to prove against certain historical roots.
150
- *
151
- * @returns A Promise that resolves to a BlockHeader object.
152
- */
153
- getBlockHeader() {
171
+ * Retrieve the databases view of the Block Header object.
172
+ * This structure is fed into the circuits simulator and is used to prove against certain historical roots.
173
+ *
174
+ * @returns A Promise that resolves to a BlockHeader object.
175
+ */ getBlockHeader() {
154
176
  return this.db.getBlockHeader();
155
177
  }
156
178
  /**
157
- * Fetches the current block number.
158
- * @returns The block number.
159
- */
160
- async getBlockNumber() {
179
+ * Fetches the current block number.
180
+ * @returns The block number.
181
+ */ async getBlockNumber() {
161
182
  return await this.aztecNode.getBlockNumber();
162
183
  }
163
184
  getDebugFunctionName(contractAddress, selector) {
164
185
  return this.contractDataOracle.getDebugFunctionName(contractAddress, selector);
165
186
  }
166
187
  /**
167
- * Returns the full contents of your address book.
168
- * This is used when calculating tags for incoming notes by deriving the shared secret, the contract-siloed tagging secret, and
169
- * finally the index specified tag. We will then query the node with this tag for each address in the address book.
170
- * @returns The full list of the users contact addresses.
171
- */
172
- getSenders() {
188
+ * Returns the full contents of your address book.
189
+ * This is used when calculating tags for incoming notes by deriving the shared secret, the contract-siloed tagging secret, and
190
+ * finally the index specified tag. We will then query the node with this tag for each address in the address book.
191
+ * @returns The full list of the users contact addresses.
192
+ */ getSenders() {
173
193
  return this.db.getSenderAddresses();
174
194
  }
175
195
  /**
176
- * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
177
- * Includes the next index to be used used for tagging with this secret.
178
- * @param contractAddress - The contract address to silo the secret for
179
- * @param sender - The address sending the note
180
- * @param recipient - The address receiving the note
181
- * @returns An indexed tagging secret that can be used to tag notes.
182
- */
183
- async getIndexedTaggingSecretAsSender(contractAddress, sender, recipient) {
196
+ * Returns the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
197
+ * Includes the next index to be used used for tagging with this secret.
198
+ * @param contractAddress - The contract address to silo the secret for
199
+ * @param sender - The address sending the note
200
+ * @param recipient - The address receiving the note
201
+ * @returns An indexed tagging secret that can be used to tag notes.
202
+ */ async getIndexedTaggingSecretAsSender(contractAddress, sender, recipient) {
184
203
  await this.syncTaggedLogsAsSender(contractAddress, sender, recipient);
185
- const appTaggingSecret = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_calculateAppTaggingSecret).call(this, contractAddress, sender, recipient);
186
- const [index] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
204
+ const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
205
+ const [index] = await this.db.getTaggingSecretsIndexesAsSender([
206
+ appTaggingSecret
207
+ ]);
187
208
  return new IndexedTaggingSecret(appTaggingSecret, index);
188
209
  }
189
210
  /**
190
- * Increments the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
191
- * @param contractAddress - The contract address to silo the secret for
192
- * @param sender - The address sending the note
193
- * @param recipient - The address receiving the note
194
- */
195
- async incrementAppTaggingSecretIndexAsSender(contractAddress, sender, recipient) {
196
- const secret = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_calculateAppTaggingSecret).call(this, contractAddress, sender, recipient);
211
+ * Increments the tagging secret for a given sender and recipient pair. For this to work, the ivsk_m of the sender must be known.
212
+ * @param contractAddress - The contract address to silo the secret for
213
+ * @param sender - The address sending the note
214
+ * @param recipient - The address receiving the note
215
+ */ async incrementAppTaggingSecretIndexAsSender(contractAddress, sender, recipient) {
216
+ const secret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
197
217
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
198
218
  this.log.debug(`Incrementing app tagging secret at ${contractName}(${contractAddress})`, {
199
219
  secret,
200
220
  sender,
201
221
  recipient,
202
222
  contractName,
203
- contractAddress,
223
+ contractAddress
204
224
  });
205
- const [index] = await this.db.getTaggingSecretsIndexesAsSender([secret]);
206
- await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(secret, index + 1)]);
225
+ const [index] = await this.db.getTaggingSecretsIndexesAsSender([
226
+ secret
227
+ ]);
228
+ await this.db.setTaggingSecretsIndexesAsSender([
229
+ new IndexedTaggingSecret(secret, index + 1)
230
+ ]);
231
+ }
232
+ async #calculateAppTaggingSecret(contractAddress, sender, recipient) {
233
+ const senderCompleteAddress = await this.getCompleteAddress(sender);
234
+ const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
235
+ const secretPoint = await computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
236
+ // Silo the secret so it can't be used to track other app's notes
237
+ const appSecret = poseidon2Hash([
238
+ secretPoint.x,
239
+ secretPoint.y,
240
+ contractAddress
241
+ ]);
242
+ return appSecret;
207
243
  }
208
244
  /**
209
- * Updates the local index of the shared tagging secret of a sender / recipient pair
210
- * if a log with a larger index is found from the node.
211
- * @param contractAddress - The address of the contract that the logs are tagged for
212
- * @param sender - The address of the sender, we must know the sender's ivsk_m.
213
- * @param recipient - The address of the recipient.
214
- */
215
- async syncTaggedLogsAsSender(contractAddress, sender, recipient) {
216
- const appTaggingSecret = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_calculateAppTaggingSecret).call(this, contractAddress, sender, recipient);
217
- const [oldIndex] = await this.db.getTaggingSecretsIndexesAsSender([appTaggingSecret]);
245
+ * Returns the indexed tagging secrets for a given recipient and all the senders in the address book
246
+ * This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
247
+ * of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
248
+ * so we're keeping it private for now.
249
+ * @param contractAddress - The contract address to silo the secret for
250
+ * @param recipient - The address receiving the notes
251
+ * @returns A list of indexed tagging secrets
252
+ */ async #getIndexedTaggingSecretsForSenders(contractAddress, recipient) {
253
+ const recipientCompleteAddress = await this.getCompleteAddress(recipient);
254
+ const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
255
+ // We implicitly add all PXE accounts as senders, this helps us decrypt tags on notes that we send to ourselves
256
+ // (recipient = us, sender = us)
257
+ const senders = [
258
+ ...await this.db.getSenderAddresses(),
259
+ ...await this.keyStore.getAccounts()
260
+ ].filter((address, index, self)=>index === self.findIndex((otherAddress)=>otherAddress.equals(address)));
261
+ const appTaggingSecrets = await Promise.all(senders.map(async (contact)=>{
262
+ const sharedSecret = await computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact);
263
+ return poseidon2Hash([
264
+ sharedSecret.x,
265
+ sharedSecret.y,
266
+ contractAddress
267
+ ]);
268
+ }));
269
+ const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
270
+ return appTaggingSecrets.map((secret, i)=>new IndexedTaggingSecret(secret, indexes[i]));
271
+ }
272
+ /**
273
+ * Updates the local index of the shared tagging secret of a sender / recipient pair
274
+ * if a log with a larger index is found from the node.
275
+ * @param contractAddress - The address of the contract that the logs are tagged for
276
+ * @param sender - The address of the sender, we must know the sender's ivsk_m.
277
+ * @param recipient - The address of the recipient.
278
+ */ async syncTaggedLogsAsSender(contractAddress, sender, recipient) {
279
+ const appTaggingSecret = await this.#calculateAppTaggingSecret(contractAddress, sender, recipient);
280
+ const [oldIndex] = await this.db.getTaggingSecretsIndexesAsSender([
281
+ appTaggingSecret
282
+ ]);
218
283
  // This algorithm works such that:
219
284
  // 1. If we find minimum consecutive empty logs in a window of logs we set the index to the index of the last log
220
285
  // we found and quit.
@@ -222,51 +287,55 @@ export class SimulatorOracle {
222
287
  // and repeat the process.
223
288
  const MIN_CONSECUTIVE_EMPTY_LOGS = 10;
224
289
  const WINDOW_SIZE = MIN_CONSECUTIVE_EMPTY_LOGS * 2;
225
- let [numConsecutiveEmptyLogs, currentIndex] = [0, oldIndex];
290
+ let [numConsecutiveEmptyLogs, currentIndex] = [
291
+ 0,
292
+ oldIndex
293
+ ];
226
294
  do {
227
295
  // We compute the tags for the current window of indexes
228
- const currentTags = await timesParallel(WINDOW_SIZE, i => {
296
+ const currentTags = await timesParallel(WINDOW_SIZE, (i)=>{
229
297
  const indexedAppTaggingSecret = new IndexedTaggingSecret(appTaggingSecret, currentIndex + i);
230
298
  return indexedAppTaggingSecret.computeSiloedTag(recipient, contractAddress);
231
299
  });
232
300
  // We fetch the logs for the tags
233
301
  const possibleLogs = await this.aztecNode.getLogsByTags(currentTags);
234
302
  // We find the index of the last log in the window that is not empty
235
- const indexOfLastLog = possibleLogs.findLastIndex(possibleLog => possibleLog.length !== 0);
303
+ const indexOfLastLog = possibleLogs.findLastIndex((possibleLog)=>possibleLog.length !== 0);
236
304
  if (indexOfLastLog === -1) {
237
- // We haven't found any logs in the current window so we stop looking
238
305
  break;
239
306
  }
240
307
  // We move the current index to that of the last log we found
241
308
  currentIndex += indexOfLastLog + 1;
242
309
  // We compute the number of consecutive empty logs we found and repeat the process if we haven't found enough.
243
310
  numConsecutiveEmptyLogs = WINDOW_SIZE - indexOfLastLog - 1;
244
- } while (numConsecutiveEmptyLogs < MIN_CONSECUTIVE_EMPTY_LOGS);
311
+ }while (numConsecutiveEmptyLogs < MIN_CONSECUTIVE_EMPTY_LOGS)
245
312
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
246
313
  if (currentIndex !== oldIndex) {
247
- await this.db.setTaggingSecretsIndexesAsSender([new IndexedTaggingSecret(appTaggingSecret, currentIndex)]);
314
+ await this.db.setTaggingSecretsIndexesAsSender([
315
+ new IndexedTaggingSecret(appTaggingSecret, currentIndex)
316
+ ]);
248
317
  this.log.debug(`Syncing logs for sender ${sender} at contract ${contractName}(${contractAddress})`, {
249
318
  sender,
250
319
  secret: appTaggingSecret,
251
320
  index: currentIndex,
252
321
  contractName,
253
- contractAddress,
322
+ contractAddress
254
323
  });
255
- }
256
- else {
324
+ } else {
257
325
  this.log.debug(`No new logs found for sender ${sender} at contract ${contractName}(${contractAddress})`);
258
326
  }
259
327
  }
260
328
  /**
261
- * Synchronizes the logs tagged with scoped addresses and all the senders in the address book.
262
- * Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
263
- * to sync.
264
- * @param contractAddress - The address of the contract that the logs are tagged for
265
- * @param recipient - The address of the recipient
266
- * @returns A list of encrypted logs tagged with the recipient's address
267
- */
268
- async syncTaggedLogs(contractAddress, maxBlockNumber, scopes) {
269
- this.log.verbose('Searching for tagged logs', { contract: contractAddress });
329
+ * Synchronizes the logs tagged with scoped addresses and all the senders in the address book.
330
+ * Returns the unsynched logs and updates the indexes of the secrets used to tag them until there are no more logs
331
+ * to sync.
332
+ * @param contractAddress - The address of the contract that the logs are tagged for
333
+ * @param recipient - The address of the recipient
334
+ * @returns A list of encrypted logs tagged with the recipient's address
335
+ */ async syncTaggedLogs(contractAddress, maxBlockNumber, scopes) {
336
+ this.log.verbose('Searching for tagged logs', {
337
+ contract: contractAddress
338
+ });
270
339
  // Ideally this algorithm would be implemented in noir, exposing its building blocks as oracles.
271
340
  // However it is impossible at the moment due to the language not supporting nested slices.
272
341
  // This nesting is necessary because for a given set of tags we don't
@@ -278,10 +347,10 @@ export class SimulatorOracle {
278
347
  // that a logs will be received ordered by a given tax index and that the tags won't be reused).
279
348
  const logsMap = new Map();
280
349
  const contractName = await this.contractDataOracle.getDebugContractName(contractAddress);
281
- for (const recipient of recipients) {
350
+ for (const recipient of recipients){
282
351
  const logsForRecipient = [];
283
352
  // Get all the secrets for the recipient and sender pairs (#9365)
284
- const secrets = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_getIndexedTaggingSecretsForSenders).call(this, contractAddress, recipient);
353
+ const secrets = await this.#getIndexedTaggingSecretsForSenders(contractAddress, recipient);
285
354
  // We fetch logs for a window of indexes in a range:
286
355
  // <latest_log_index - WINDOW_HALF_SIZE, latest_log_index + WINDOW_HALF_SIZE>.
287
356
  //
@@ -290,32 +359,32 @@ export class SimulatorOracle {
290
359
  // for logs the first time we don't receive any logs for a tag, we might never receive anything from that sender again.
291
360
  // Also there's a possibility that we have advanced our index, but the sender has reused it, so we might have missed
292
361
  // some logs. For these reasons, we have to look both back and ahead of the stored index.
293
- let secretsAndWindows = secrets.map(secret => {
362
+ let secretsAndWindows = secrets.map((secret)=>{
294
363
  return {
295
364
  appTaggingSecret: secret.appTaggingSecret,
296
365
  leftMostIndex: Math.max(0, secret.index - WINDOW_HALF_SIZE),
297
- rightMostIndex: secret.index + WINDOW_HALF_SIZE,
366
+ rightMostIndex: secret.index + WINDOW_HALF_SIZE
298
367
  };
299
368
  });
300
369
  // As we iterate we store the largest index we have seen for a given secret to later on store it in the db.
301
370
  const newLargestIndexMapToStore = {};
302
371
  // The initial/unmodified indexes of the secrets stored in a key-value map where key is the app tagging secret.
303
372
  const initialIndexesMap = getInitialIndexesMap(secrets);
304
- while (secretsAndWindows.length > 0) {
373
+ while(secretsAndWindows.length > 0){
305
374
  const secretsForTheWholeWindow = getIndexedTaggingSecretsForTheWindow(secretsAndWindows);
306
- const tagsForTheWholeWindow = await Promise.all(secretsForTheWholeWindow.map(secret => secret.computeSiloedTag(recipient, contractAddress)));
375
+ const tagsForTheWholeWindow = await Promise.all(secretsForTheWholeWindow.map((secret)=>secret.computeSiloedTag(recipient, contractAddress)));
307
376
  // We store the new largest indexes we find in the iteration in the following map to later on construct
308
377
  // a new set of secrets and windows to fetch logs for.
309
378
  const newLargestIndexMapForIteration = {};
310
379
  // Fetch the logs for the tags and iterate over them
311
380
  const logsByTags = await this.aztecNode.getLogsByTags(tagsForTheWholeWindow);
312
- logsByTags.forEach((logsByTag, logIndex) => {
381
+ logsByTags.forEach((logsByTag, logIndex)=>{
313
382
  if (logsByTag.length > 0) {
314
383
  // Check that public logs have the correct contract address
315
- const checkedLogsbyTag = logsByTag.filter(l => !l.isFromPublic || PublicLog.fromBuffer(l.logData).contractAddress.equals(contractAddress));
384
+ const checkedLogsbyTag = logsByTag.filter((l)=>!l.isFromPublic || PublicLog.fromBuffer(l.logData).contractAddress.equals(contractAddress));
316
385
  if (checkedLogsbyTag.length < logsByTag.length) {
317
- const discarded = logsByTag.filter(log => checkedLogsbyTag.find(filteredLog => filteredLog.equals(log)) === undefined);
318
- this.log.warn(`Discarded ${logsByTag.length - checkedLogsbyTag.length} public logs with mismatched contract address ${contractAddress}:`, discarded.map(l => PublicLog.fromBuffer(l.logData)));
386
+ const discarded = logsByTag.filter((log)=>checkedLogsbyTag.find((filteredLog)=>filteredLog.equals(log)) === undefined);
387
+ this.log.warn(`Discarded ${logsByTag.length - checkedLogsbyTag.length} public logs with mismatched contract address ${contractAddress}:`, discarded.map((l)=>PublicLog.fromBuffer(l.logData)));
319
388
  }
320
389
  // The logs for the given tag exist so we store them for later processing
321
390
  logsForRecipient.push(...checkedLogsbyTag);
@@ -327,16 +396,12 @@ export class SimulatorOracle {
327
396
  recipient,
328
397
  secret: secretCorrespondingToLog.appTaggingSecret,
329
398
  contractName,
330
- contractAddress,
399
+ contractAddress
331
400
  });
332
- if (secretCorrespondingToLog.index >= initialIndex &&
333
- (newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] === undefined ||
334
- secretCorrespondingToLog.index >=
335
- newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()])) {
401
+ if (secretCorrespondingToLog.index >= initialIndex && (newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] === undefined || secretCorrespondingToLog.index >= newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()])) {
336
402
  // We have found a new largest index so we store it for later processing (storing it in the db + fetching
337
403
  // the difference of the window sets of current and the next iteration)
338
- newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] =
339
- secretCorrespondingToLog.index + 1;
404
+ newLargestIndexMapForIteration[secretCorrespondingToLog.appTaggingSecret.toString()] = secretCorrespondingToLog.index + 1;
340
405
  this.log.debug(`Incrementing index to ${secretCorrespondingToLog.index + 1} at contract ${contractName}(${contractAddress})`);
341
406
  }
342
407
  }
@@ -345,19 +410,18 @@ export class SimulatorOracle {
345
410
  // for. Note that it's very unlikely that a new log from the current window would appear between the iterations
346
411
  // so we fetch the logs only for the difference of the window sets.
347
412
  const newSecretsAndWindows = [];
348
- for (const [appTaggingSecret, newIndex] of Object.entries(newLargestIndexMapForIteration)) {
349
- const secret = secrets.find(secret => secret.appTaggingSecret.toString() === appTaggingSecret);
413
+ for (const [appTaggingSecret, newIndex] of Object.entries(newLargestIndexMapForIteration)){
414
+ const secret = secrets.find((secret)=>secret.appTaggingSecret.toString() === appTaggingSecret);
350
415
  if (secret) {
351
416
  newSecretsAndWindows.push({
352
417
  appTaggingSecret: secret.appTaggingSecret,
353
418
  // We set the left most index to the new index to avoid fetching the same logs again
354
419
  leftMostIndex: newIndex,
355
- rightMostIndex: newIndex + WINDOW_HALF_SIZE,
420
+ rightMostIndex: newIndex + WINDOW_HALF_SIZE
356
421
  });
357
422
  // We store the new largest index in the map to later store it in the db.
358
423
  newLargestIndexMapToStore[appTaggingSecret] = newIndex;
359
- }
360
- else {
424
+ } else {
361
425
  throw new Error(`Secret not found for appTaggingSecret ${appTaggingSecret}. This is a bug as it should never happen!`);
362
426
  }
363
427
  }
@@ -365,24 +429,59 @@ export class SimulatorOracle {
365
429
  secretsAndWindows = newSecretsAndWindows;
366
430
  }
367
431
  // We filter the logs by block number and store them in the map.
368
- logsMap.set(recipient.toString(), logsForRecipient.filter(log => log.blockNumber <= maxBlockNumber));
432
+ logsMap.set(recipient.toString(), logsForRecipient.filter((log)=>log.blockNumber <= maxBlockNumber));
369
433
  // At this point we have processed all the logs for the recipient so we store the new largest indexes in the db.
370
- await this.db.setTaggingSecretsIndexesAsRecipient(Object.entries(newLargestIndexMapToStore).map(([appTaggingSecret, index]) => new IndexedTaggingSecret(Fr.fromHexString(appTaggingSecret), index)));
434
+ await this.db.setTaggingSecretsIndexesAsRecipient(Object.entries(newLargestIndexMapToStore).map(([appTaggingSecret, index])=>new IndexedTaggingSecret(Fr.fromHexString(appTaggingSecret), index)));
371
435
  }
372
436
  return logsMap;
373
437
  }
374
438
  /**
375
- * Processes the tagged logs returned by syncTaggedLogs by decrypting them and storing them in the database.
376
- * @param logs - The logs to process.
377
- * @param recipient - The recipient of the logs.
378
- */
379
- async processTaggedLogs(logs, recipient, simulator) {
380
- const decryptedLogs = await __classPrivateFieldGet(this, _SimulatorOracle_instances, "m", _SimulatorOracle_decryptTaggedLogs).call(this, logs, recipient);
439
+ * Decrypts logs tagged for a recipient and returns them.
440
+ * @param scopedLogs - The logs to decrypt.
441
+ * @param recipient - The recipient of the logs.
442
+ * @returns The decrypted notes.
443
+ */ async #decryptTaggedLogs(scopedLogs, recipient) {
444
+ const recipientCompleteAddress = await this.getCompleteAddress(recipient);
445
+ const ivskM = await this.keyStore.getMasterSecretKey(recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey);
446
+ const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
447
+ // Since we could have notes with the same index for different txs, we need
448
+ // to keep track of them scoping by txHash
449
+ const excludedIndices = new Map();
450
+ const decrypted = [];
451
+ for (const scopedLog of scopedLogs){
452
+ const payload = scopedLog.isFromPublic ? await L1NotePayload.decryptAsIncomingFromPublic(PublicLog.fromBuffer(scopedLog.logData), addressSecret) : await L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
453
+ if (!payload) {
454
+ this.log.verbose('Unable to decrypt log');
455
+ continue;
456
+ }
457
+ if (!excludedIndices.has(scopedLog.txHash.toString())) {
458
+ excludedIndices.set(scopedLog.txHash.toString(), new Set());
459
+ }
460
+ const note = await getOrderedNoteItems(this.db, payload);
461
+ const plaintext = [
462
+ payload.storageSlot,
463
+ payload.noteTypeId.toField(),
464
+ ...note.items
465
+ ];
466
+ decrypted.push({
467
+ plaintext,
468
+ txHash: scopedLog.txHash,
469
+ contractAddress: payload.contractAddress
470
+ });
471
+ }
472
+ return decrypted;
473
+ }
474
+ /**
475
+ * Processes the tagged logs returned by syncTaggedLogs by decrypting them and storing them in the database.
476
+ * @param logs - The logs to process.
477
+ * @param recipient - The recipient of the logs.
478
+ */ async processTaggedLogs(logs, recipient, simulator) {
479
+ const decryptedLogs = await this.#decryptTaggedLogs(logs, recipient);
381
480
  // We've produced the full NoteDao, which we'd be able to simply insert into the database. However, this is
382
481
  // only a temporary measure as we migrate from the PXE-driven discovery into the new contract-driven approach. We
383
482
  // discard most of the work done up to this point and reconstruct the note plaintext to then hand over to the
384
483
  // contract for further processing.
385
- for (const decryptedLog of decryptedLogs) {
484
+ for (const decryptedLog of decryptedLogs){
386
485
  // Log processing requires the note hashes in the tx in which the note was created. We are now assuming that the
387
486
  // note was included in the same block in which the log was delivered - note that partial notes will not work this
388
487
  // way.
@@ -398,32 +497,42 @@ export class SimulatorOracle {
398
497
  // Called when notes are delivered, usually as a result to a call to the process_log contract function
399
498
  async deliverNote(contractAddress, storageSlot, nonce, content, noteHash, nullifier, txHash, recipient) {
400
499
  const noteDao = await this.produceNoteDao(contractAddress, storageSlot, nonce, content, noteHash, nullifier, txHash, recipient);
401
- await this.db.addNotes([noteDao], recipient);
500
+ await this.db.addNotes([
501
+ noteDao
502
+ ], recipient);
402
503
  this.log.verbose('Added note', {
403
504
  contract: noteDao.contractAddress,
404
505
  slot: noteDao.storageSlot,
405
- nullifier: noteDao.siloedNullifier.toString,
506
+ nullifier: noteDao.siloedNullifier.toString
406
507
  });
407
508
  }
408
509
  async removeNullifiedNotes(contractAddress) {
409
- this.log.verbose('Removing nullified notes', { contract: contractAddress });
410
- for (const recipient of await this.keyStore.getAccounts()) {
411
- const currentNotesForRecipient = await this.db.getNotes({ contractAddress, owner: recipient });
412
- const nullifiersToCheck = currentNotesForRecipient.map(note => note.siloedNullifier);
510
+ this.log.verbose('Removing nullified notes', {
511
+ contract: contractAddress
512
+ });
513
+ for (const recipient of (await this.keyStore.getAccounts())){
514
+ const currentNotesForRecipient = await this.db.getNotes({
515
+ contractAddress,
516
+ owner: recipient
517
+ });
518
+ const nullifiersToCheck = currentNotesForRecipient.map((note)=>note.siloedNullifier);
413
519
  const nullifierIndexes = await this.aztecNode.findNullifiersIndexesWithBlock('latest', nullifiersToCheck);
414
- const foundNullifiers = nullifiersToCheck
415
- .map((nullifier, i) => {
520
+ const foundNullifiers = nullifiersToCheck.map((nullifier, i)=>{
416
521
  if (nullifierIndexes[i] !== undefined) {
417
- return { ...nullifierIndexes[i], ...{ data: nullifier } };
522
+ return {
523
+ ...nullifierIndexes[i],
524
+ ...{
525
+ data: nullifier
526
+ }
527
+ };
418
528
  }
419
- })
420
- .filter(nullifier => nullifier !== undefined);
529
+ }).filter((nullifier)=>nullifier !== undefined);
421
530
  const nullifiedNotes = await this.db.removeNullifiedNotes(foundNullifiers, await recipient.toAddressPoint());
422
- nullifiedNotes.forEach(noteDao => {
531
+ nullifiedNotes.forEach((noteDao)=>{
423
532
  this.log.verbose(`Removed note for contract ${noteDao.contractAddress} at slot ${noteDao.storageSlot}`, {
424
533
  contract: noteDao.contractAddress,
425
534
  slot: noteDao.storageSlot,
426
- nullifier: noteDao.siloedNullifier.toString(),
535
+ nullifier: noteDao.siloedNullifier.toString()
427
536
  });
428
537
  });
429
538
  }
@@ -444,7 +553,9 @@ export class SimulatorOracle {
444
553
  // locally synced block number which *should* be recent enough to be available. We avoid querying at 'latest' since
445
554
  // we want to avoid accidentally processing notes that only exist ahead in time of the locally synced state.
446
555
  const syncedBlockNumber = await this.db.getBlockNumber();
447
- const uniqueNoteHashTreeIndex = (await this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NOTE_HASH_TREE, [uniqueNoteHash]))[0];
556
+ const uniqueNoteHashTreeIndex = (await this.aztecNode.findLeavesIndexes(syncedBlockNumber, MerkleTreeId.NOTE_HASH_TREE, [
557
+ uniqueNoteHash
558
+ ]))[0];
448
559
  if (uniqueNoteHashTreeIndex === undefined) {
449
560
  throw new Error(`Note hash ${noteHash} (uniqued as ${uniqueNoteHash}) is not present on the tree at block ${syncedBlockNumber} (from tx ${txHash})`);
450
561
  }
@@ -466,12 +577,11 @@ export class SimulatorOracle {
466
577
  txHash.toString(),
467
578
  toBoundedVec(noteHashes, MAX_NOTE_HASHES_PER_TX),
468
579
  firstNullifier,
469
- recipient,
580
+ recipient
470
581
  ]),
471
- returnTypes: artifact.returnTypes,
582
+ returnTypes: artifact.returnTypes
472
583
  };
473
- await (simulator ??
474
- getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.simulationProvider, this.contractDataOracle)).runUnconstrained(execRequest, artifact, contractAddress, []);
584
+ await (simulator ?? getAcirSimulator(this.db, this.aztecNode, this.keyStore, this.simulationProvider, this.contractDataOracle)).runUnconstrained(execRequest, artifact, contractAddress, []);
475
585
  }
476
586
  dbStore(contractAddress, slot, values) {
477
587
  return this.db.dbStore(contractAddress, slot, values);
@@ -486,84 +596,9 @@ export class SimulatorOracle {
486
596
  return this.db.dbCopy(contractAddress, srcSlot, dstSlot, numEntries);
487
597
  }
488
598
  }
489
- _SimulatorOracle_instances = new WeakSet(), _SimulatorOracle_findLeafIndex = async function _SimulatorOracle_findLeafIndex(blockNumber, treeId, leafValue) {
490
- const [leafIndex] = await this.aztecNode.findLeavesIndexes(blockNumber, treeId, [leafValue]);
491
- return leafIndex;
492
- }, _SimulatorOracle_getSiblingPath = async function _SimulatorOracle_getSiblingPath(blockNumber, treeId, leafIndex) {
493
- switch (treeId) {
494
- case MerkleTreeId.NULLIFIER_TREE:
495
- return (await this.aztecNode.getNullifierSiblingPath(blockNumber, leafIndex)).toFields();
496
- case MerkleTreeId.NOTE_HASH_TREE:
497
- return (await this.aztecNode.getNoteHashSiblingPath(blockNumber, leafIndex)).toFields();
498
- case MerkleTreeId.PUBLIC_DATA_TREE:
499
- return (await this.aztecNode.getPublicDataSiblingPath(blockNumber, leafIndex)).toFields();
500
- case MerkleTreeId.ARCHIVE:
501
- return (await this.aztecNode.getArchiveSiblingPath(blockNumber, leafIndex)).toFields();
502
- default:
503
- throw new Error('Not implemented');
504
- }
505
- }, _SimulatorOracle_calculateAppTaggingSecret = async function _SimulatorOracle_calculateAppTaggingSecret(contractAddress, sender, recipient) {
506
- const senderCompleteAddress = await this.getCompleteAddress(sender);
507
- const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender);
508
- const secretPoint = await computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient);
509
- // Silo the secret so it can't be used to track other app's notes
510
- const appSecret = poseidon2Hash([secretPoint.x, secretPoint.y, contractAddress]);
511
- return appSecret;
512
- }, _SimulatorOracle_getIndexedTaggingSecretsForSenders =
513
- /**
514
- * Returns the indexed tagging secrets for a given recipient and all the senders in the address book
515
- * This method should be exposed as an oracle call to allow aztec.nr to perform the orchestration
516
- * of the syncTaggedLogs and processTaggedLogs methods. However, it is not possible to do so at the moment,
517
- * so we're keeping it private for now.
518
- * @param contractAddress - The contract address to silo the secret for
519
- * @param recipient - The address receiving the notes
520
- * @returns A list of indexed tagging secrets
521
- */
522
- async function _SimulatorOracle_getIndexedTaggingSecretsForSenders(contractAddress, recipient) {
523
- const recipientCompleteAddress = await this.getCompleteAddress(recipient);
524
- const recipientIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(recipient);
525
- // We implicitly add all PXE accounts as senders, this helps us decrypt tags on notes that we send to ourselves
526
- // (recipient = us, sender = us)
527
- const senders = [...(await this.db.getSenderAddresses()), ...(await this.keyStore.getAccounts())].filter((address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address)));
528
- const appTaggingSecrets = await Promise.all(senders.map(async (contact) => {
529
- const sharedSecret = await computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact);
530
- return poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]);
531
- }));
532
- const indexes = await this.db.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets);
533
- return appTaggingSecrets.map((secret, i) => new IndexedTaggingSecret(secret, indexes[i]));
534
- }, _SimulatorOracle_decryptTaggedLogs =
535
- /**
536
- * Decrypts logs tagged for a recipient and returns them.
537
- * @param scopedLogs - The logs to decrypt.
538
- * @param recipient - The recipient of the logs.
539
- * @returns The decrypted notes.
540
- */
541
- async function _SimulatorOracle_decryptTaggedLogs(scopedLogs, recipient) {
542
- const recipientCompleteAddress = await this.getCompleteAddress(recipient);
543
- const ivskM = await this.keyStore.getMasterSecretKey(recipientCompleteAddress.publicKeys.masterIncomingViewingPublicKey);
544
- const addressSecret = await computeAddressSecret(await recipientCompleteAddress.getPreaddress(), ivskM);
545
- // Since we could have notes with the same index for different txs, we need
546
- // to keep track of them scoping by txHash
547
- const excludedIndices = new Map();
548
- const decrypted = [];
549
- for (const scopedLog of scopedLogs) {
550
- const payload = scopedLog.isFromPublic
551
- ? await L1NotePayload.decryptAsIncomingFromPublic(PublicLog.fromBuffer(scopedLog.logData), addressSecret)
552
- : await L1NotePayload.decryptAsIncoming(PrivateLog.fromBuffer(scopedLog.logData), addressSecret);
553
- if (!payload) {
554
- this.log.verbose('Unable to decrypt log');
555
- continue;
556
- }
557
- if (!excludedIndices.has(scopedLog.txHash.toString())) {
558
- excludedIndices.set(scopedLog.txHash.toString(), new Set());
559
- }
560
- const note = await getOrderedNoteItems(this.db, payload);
561
- const plaintext = [payload.storageSlot, payload.noteTypeId.toField(), ...note.items];
562
- decrypted.push({ plaintext, txHash: scopedLog.txHash, contractAddress: payload.contractAddress });
563
- }
564
- return decrypted;
565
- };
566
599
  function toBoundedVec(array, maxLength) {
567
- return { storage: array.concat(Array(maxLength - array.length).fill(new Fr(0))), len: array.length };
600
+ return {
601
+ storage: array.concat(Array(maxLength - array.length).fill(new Fr(0))),
602
+ len: array.length
603
+ };
568
604
  }
569
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvc2ltdWxhdG9yX29yYWNsZS9pbmRleC50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOztBQUFBLE9BQU8sRUFJTCxhQUFhLEVBR2IsWUFBWSxFQUNaLElBQUksRUFJSixNQUFNLEVBRU4sbUNBQW1DLEdBQ3BDLE1BQU0sc0JBQXNCLENBQUM7QUFDOUIsT0FBTyxFQUtMLEVBQUUsRUFDRixnQkFBZ0IsRUFDaEIsb0JBQW9CLEVBR3BCLHNCQUFzQixFQUN0QiwwQkFBMEIsRUFDMUIsVUFBVSxFQUNWLFNBQVMsRUFDVCxvQkFBb0IsRUFDcEIseUJBQXlCLEdBQzFCLE1BQU0sb0JBQW9CLENBQUM7QUFDNUIsT0FBTyxFQUFFLHFCQUFxQixFQUFFLFlBQVksRUFBRSxhQUFhLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUM3RixPQUFPLEVBRUwsWUFBWSxFQUNaLFlBQVksRUFDWixlQUFlLEVBQ2YsbUJBQW1CLEdBQ3BCLE1BQU0sdUJBQXVCLENBQUM7QUFDL0IsT0FBTyxFQUFFLGFBQWEsRUFBRSxNQUFNLDhCQUE4QixDQUFDO0FBQzdELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsWUFBWSxFQUFFLE1BQU0sdUJBQXVCLENBQUM7QUFFckQsT0FBTyxFQUdMLHVCQUF1QixHQUV4QixNQUFNLHlCQUF5QixDQUFDO0FBRWpDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLGtDQUFrQyxDQUFDO0FBRXRFLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSx5QkFBeUIsQ0FBQztBQUNsRCxPQUFPLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSwwREFBMEQsQ0FBQztBQUMvRixPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQztBQUN6RCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsb0NBQW9DLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVsSDs7R0FFRztBQUNILE1BQU0sT0FBTyxlQUFlO0lBQzFCLFlBQ1Usa0JBQXNDLEVBQ3RDLEVBQWUsRUFDZixRQUFrQixFQUNsQixTQUFvQixFQUNwQixrQkFBc0MsRUFDdEMsTUFBTSxZQUFZLENBQUMsc0JBQXNCLENBQUM7O1FBTDFDLHVCQUFrQixHQUFsQixrQkFBa0IsQ0FBb0I7UUFDdEMsT0FBRSxHQUFGLEVBQUUsQ0FBYTtRQUNmLGFBQVEsR0FBUixRQUFRLENBQVU7UUFDbEIsY0FBUyxHQUFULFNBQVMsQ0FBVztRQUNwQix1QkFBa0IsR0FBbEIsa0JBQWtCLENBQW9CO1FBQ3RDLFFBQUcsR0FBSCxHQUFHLENBQXVDO0lBQ2pELENBQUM7SUFFSix1QkFBdUIsQ0FBQyxPQUFXLEVBQUUsZUFBNkI7UUFDaEUsT0FBTyxJQUFJLENBQUMsUUFBUSxDQUFDLHVCQUF1QixDQUFDLE9BQU8sRUFBRSxlQUFlLENBQUMsQ0FBQztJQUN6RSxDQUFDO0lBRUQsS0FBSyxDQUFDLGtCQUFrQixDQUFDLE9BQXFCO1FBQzVDLE1BQU0sZUFBZSxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxrQkFBa0IsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUNsRSxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDckIsTUFBTSxJQUFJLEtBQUssQ0FDYix3Q0FBd0MsT0FBTzs4UUFDdU4sQ0FDdlEsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLGVBQWUsQ0FBQztJQUN6QixDQUFDO0lBRUQsS0FBSyxDQUFDLG1CQUFtQixDQUFDLE9BQXFCO1FBQzdDLE1BQU0sUUFBUSxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUM1RCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxPQUFPLENBQUMsUUFBUSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1FBQ2xGLENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQsS0FBSyxDQUFDLGNBQWMsQ0FBQyxXQUFlO1FBQ2xDLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLENBQUM7UUFDMUQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2IsTUFBTSxJQUFJLEtBQUssQ0FBQyx5Q0FBeUMsV0FBVyxDQUFDLFFBQVEsRUFBRSxFQUFFLENBQUMsQ0FBQztRQUNyRixDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVELEtBQUssQ0FBQyxVQUFVO1FBQ2QsTUFBTSxPQUFPLEdBQUcsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLFVBQVUsRUFBRSxDQUFDO1FBQzNDLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNiLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLENBQUMsQ0FBQztRQUMzQyxDQUFDO1FBQ0QsT0FBTyxPQUFPLENBQUM7SUFDakIsQ0FBQztJQUVELEtBQUssQ0FBQyxRQUFRLENBQUMsZUFBNkIsRUFBRSxXQUFlLEVBQUUsTUFBa0IsRUFBRSxNQUF1QjtRQUN4RyxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsUUFBUSxDQUFDO1lBQ3RDLGVBQWU7WUFDZixXQUFXO1lBQ1gsTUFBTTtZQUNOLE1BQU07U0FDUCxDQUFDLENBQUM7UUFDSCxPQUFPLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQyxFQUFFLGVBQWUsRUFBRSxXQUFXLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxDQUFDO1lBQ3hHLGVBQWU7WUFDZixXQUFXO1lBQ1gsS0FBSztZQUNMLElBQUk7WUFDSixRQUFRO1lBQ1IsZUFBZTtZQUNmLHVEQUF1RDtZQUN2RCxLQUFLO1NBQ04sQ0FBQyxDQUFDLENBQUM7SUFDTixDQUFDO0lBRUQsS0FBSyxDQUFDLG1CQUFtQixDQUFDLGVBQTZCLEVBQUUsUUFBMEI7UUFDakYsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsbUJBQW1CLENBQUMsZUFBZSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzlGLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLHdCQUF3QixDQUFDLGVBQWUsRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNoRyxPQUFPO1lBQ0wsR0FBRyxRQUFRO1lBQ1gsS0FBSztTQUNOLENBQUM7SUFDSixDQUFDO0lBRUQsS0FBSyxDQUFDLHlCQUF5QixDQUM3QixlQUE2QixFQUM3QixZQUFvQjtRQUVwQixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxtQkFBbUIsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUNwRixNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxtQkFBbUIsQ0FBQyxRQUFRLENBQUMsZUFBZSxDQUFDLENBQUM7UUFDN0YsT0FBTyxRQUFRLElBQUksbUJBQW1CLENBQUMsUUFBUSxFQUFFLFlBQVksQ0FBQyxDQUFDO0lBQ2pFLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0gsS0FBSyxDQUFDLDBCQUEwQixDQUM5QixlQUE2QixFQUM3QixXQUFlLEVBQ2YsTUFBVTtRQUVWLE1BQU0sQ0FBQyxZQUFZLEVBQUUsV0FBVyxDQUFDLEdBQUcsTUFBTSxtQ0FBbUMsQ0FDM0UsSUFBSSxDQUFDLFNBQVMsRUFDZCxlQUFlLEVBQ2YsV0FBVyxFQUNYLE1BQU0sQ0FDUCxDQUFDO1FBRUYsNkZBQTZGO1FBQzdGLE9BQU8sSUFBSSx1QkFBdUIsQ0FBQyxZQUFZLEVBQUUsV0FBVyxDQUFDLENBQUM7SUFDaEUsQ0FBQztJQUVELHVCQUF1QjtJQUNoQixrQkFBa0IsQ0FBQyxVQUFrQjtRQUMxQyxNQUFNLElBQUksS0FBSyxDQUFDLDJCQUEyQixDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsa0JBQWtCLENBQUMsVUFBYztRQUNyQyxPQUFPLE1BQU0sdUJBQUEsSUFBSSxrRUFBZSxNQUFuQixJQUFJLEVBQWdCLFFBQVEsRUFBRSxZQUFZLENBQUMsY0FBYyxFQUFFLFVBQVUsQ0FBQyxDQUFDO0lBQ3RGLENBQUM7SUFFRCxpRkFBaUY7SUFDMUUsa0JBQWtCLENBQUMsVUFBa0I7UUFDMUMsTUFBTSxJQUFJLEtBQUssQ0FBQywyQkFBMkIsQ0FBQyxDQUFDO0lBQy9DLENBQUM7SUFFRCxLQUFLLENBQUMsaUJBQWlCLENBQUMsU0FBYTtRQUNuQyxPQUFPLE1BQU0sdUJBQUEsSUFBSSxrRUFBZSxNQUFuQixJQUFJLEVBQWdCLFFBQVEsRUFBRSxZQUFZLENBQUMsY0FBYyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQ3JGLENBQUM7SUFPTSxLQUFLLENBQUMsb0JBQW9CLENBQUMsV0FBbUIsRUFBRSxNQUFvQixFQUFFLFNBQWE7UUFDeEYsTUFBTSxTQUFTLEdBQUcsTUFBTSx1QkFBQSxJQUFJLGtFQUFlLE1BQW5CLElBQUksRUFBZ0IsV0FBVyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztRQUM1RSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUM7WUFDZixNQUFNLElBQUksS0FBSyxDQUFDLGVBQWUsU0FBUyxpQkFBaUIsWUFBWSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsQ0FBQztRQUNuRixDQUFDO1FBRUQsTUFBTSxXQUFXLEdBQUcsTUFBTSx1QkFBQSxJQUFJLG1FQUFnQixNQUFwQixJQUFJLEVBQWlCLFdBQVcsRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFL0UsT0FBTyxDQUFDLElBQUksRUFBRSxDQUFDLFNBQVMsQ0FBQyxFQUFFLEdBQUcsV0FBVyxDQUFDLENBQUM7SUFDN0MsQ0FBQztJQWlCTSxLQUFLLENBQUMsMENBQTBDLENBQUMsU0FBYTtRQUNuRSxPQUFPLElBQUksQ0FBQyw2QkFBNkIsQ0FBQyxNQUFNLElBQUksQ0FBQyxjQUFjLEVBQUUsRUFBRSxTQUFTLENBQUMsQ0FBQztJQUNwRixDQUFDO0lBRU0sNkJBQTZCLENBQ2xDLFdBQW1CLEVBQ25CLFNBQWE7UUFFYixPQUFPLElBQUksQ0FBQyxTQUFTLENBQUMsNkJBQTZCLENBQUMsV0FBVyxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQzlFLENBQUM7SUFFTSxnQ0FBZ0MsQ0FDckMsV0FBbUIsRUFDbkIsU0FBYTtRQUViLE9BQU8sSUFBSSxDQUFDLFNBQVMsQ0FBQyxnQ0FBZ0MsQ0FBQyxXQUFXLEVBQUUsU0FBUyxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUVNLEtBQUssQ0FBQyxRQUFRLENBQUMsV0FBbUI7UUFDdkMsT0FBTyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFTSxLQUFLLENBQUMsd0JBQXdCLENBQUMsV0FBbUIsRUFBRSxRQUFZO1FBQ3JFLE9BQU8sTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLHdCQUF3QixDQUFDLFdBQVcsRUFBRSxRQUFRLENBQUMsQ0FBQztJQUM5RSxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxjQUFjO1FBQ1osT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDLGNBQWMsRUFBRSxDQUFDO0lBQ2xDLENBQUM7SUFFRDs7O09BR0c7SUFDSSxLQUFLLENBQUMsY0FBYztRQUN6QixPQUFPLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxjQUFjLEVBQUUsQ0FBQztJQUMvQyxDQUFDO0lBRU0sb0JBQW9CLENBQUMsZUFBNkIsRUFBRSxRQUEwQjtRQUNuRixPQUFPLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxvQkFBb0IsQ0FBQyxlQUFlLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDakYsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksVUFBVTtRQUNmLE9BQU8sSUFBSSxDQUFDLEVBQUUsQ0FBQyxrQkFBa0IsRUFBRSxDQUFDO0lBQ3RDLENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ0ksS0FBSyxDQUFDLCtCQUErQixDQUMxQyxlQUE2QixFQUM3QixNQUFvQixFQUNwQixTQUF1QjtRQUV2QixNQUFNLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxlQUFlLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRXRFLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSx1QkFBQSxJQUFJLDhFQUEyQixNQUEvQixJQUFJLEVBQTRCLGVBQWUsRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDbkcsTUFBTSxDQUFDLEtBQUssQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztRQUVuRixPQUFPLElBQUksb0JBQW9CLENBQUMsZ0JBQWdCLEVBQUUsS0FBSyxDQUFDLENBQUM7SUFDM0QsQ0FBQztJQUVEOzs7OztPQUtHO0lBQ0ksS0FBSyxDQUFDLHNDQUFzQyxDQUNqRCxlQUE2QixFQUM3QixNQUFvQixFQUNwQixTQUF1QjtRQUV2QixNQUFNLE1BQU0sR0FBRyxNQUFNLHVCQUFBLElBQUksOEVBQTJCLE1BQS9CLElBQUksRUFBNEIsZUFBZSxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztRQUN6RixNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxvQkFBb0IsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUN6RixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxzQ0FBc0MsWUFBWSxJQUFJLGVBQWUsR0FBRyxFQUFFO1lBQ3ZGLE1BQU07WUFDTixNQUFNO1lBQ04sU0FBUztZQUNULFlBQVk7WUFDWixlQUFlO1NBQ2hCLENBQUMsQ0FBQztRQUVILE1BQU0sQ0FBQyxLQUFLLENBQUMsR0FBRyxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsZ0NBQWdDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDO1FBQ3pFLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLElBQUksb0JBQW9CLENBQUMsTUFBTSxFQUFFLEtBQUssR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDaEcsQ0FBQztJQTBDRDs7Ozs7O09BTUc7SUFDSSxLQUFLLENBQUMsc0JBQXNCLENBQ2pDLGVBQTZCLEVBQzdCLE1BQW9CLEVBQ3BCLFNBQXVCO1FBRXZCLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSx1QkFBQSxJQUFJLDhFQUEyQixNQUEvQixJQUFJLEVBQTRCLGVBQWUsRUFBRSxNQUFNLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFDbkcsTUFBTSxDQUFDLFFBQVEsQ0FBQyxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLGdCQUFnQixDQUFDLENBQUMsQ0FBQztRQUV0RixrQ0FBa0M7UUFDbEMsaUhBQWlIO1FBQ2pILHFCQUFxQjtRQUNyQixpSEFBaUg7UUFDakgsMEJBQTBCO1FBQzFCLE1BQU0sMEJBQTBCLEdBQUcsRUFBRSxDQUFDO1FBQ3RDLE1BQU0sV0FBVyxHQUFHLDBCQUEwQixHQUFHLENBQUMsQ0FBQztRQUVuRCxJQUFJLENBQUMsdUJBQXVCLEVBQUUsWUFBWSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsUUFBUSxDQUFDLENBQUM7UUFDNUQsR0FBRyxDQUFDO1lBQ0Ysd0RBQXdEO1lBQ3hELE1BQU0sV0FBVyxHQUFHLE1BQU0sYUFBYSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsRUFBRTtnQkFDdkQsTUFBTSx1QkFBdUIsR0FBRyxJQUFJLG9CQUFvQixDQUFDLGdCQUFnQixFQUFFLFlBQVksR0FBRyxDQUFDLENBQUMsQ0FBQztnQkFDN0YsT0FBTyx1QkFBdUIsQ0FBQyxnQkFBZ0IsQ0FBQyxTQUFTLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDOUUsQ0FBQyxDQUFDLENBQUM7WUFFSCxpQ0FBaUM7WUFDakMsTUFBTSxZQUFZLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQztZQUVyRSxvRUFBb0U7WUFDcEUsTUFBTSxjQUFjLEdBQUcsWUFBWSxDQUFDLGFBQWEsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFFM0YsSUFBSSxjQUFjLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQztnQkFDMUIscUVBQXFFO2dCQUNyRSxNQUFNO1lBQ1IsQ0FBQztZQUVELDZEQUE2RDtZQUM3RCxZQUFZLElBQUksY0FBYyxHQUFHLENBQUMsQ0FBQztZQUVuQyw4R0FBOEc7WUFDOUcsdUJBQXVCLEdBQUcsV0FBVyxHQUFHLGNBQWMsR0FBRyxDQUFDLENBQUM7UUFDN0QsQ0FBQyxRQUFRLHVCQUF1QixHQUFHLDBCQUEwQixFQUFFO1FBRS9ELE1BQU0sWUFBWSxHQUFHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLG9CQUFvQixDQUFDLGVBQWUsQ0FBQyxDQUFDO1FBQ3pGLElBQUksWUFBWSxLQUFLLFFBQVEsRUFBRSxDQUFDO1lBQzlCLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDLElBQUksb0JBQW9CLENBQUMsZ0JBQWdCLEVBQUUsWUFBWSxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBRTNHLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLDJCQUEyQixNQUFNLGdCQUFnQixZQUFZLElBQUksZUFBZSxHQUFHLEVBQUU7Z0JBQ2xHLE1BQU07Z0JBQ04sTUFBTSxFQUFFLGdCQUFnQjtnQkFDeEIsS0FBSyxFQUFFLFlBQVk7Z0JBQ25CLFlBQVk7Z0JBQ1osZUFBZTthQUNoQixDQUFDLENBQUM7UUFDTCxDQUFDO2FBQU0sQ0FBQztZQUNOLElBQUksQ0FBQyxHQUFHLENBQUMsS0FBSyxDQUFDLGdDQUFnQyxNQUFNLGdCQUFnQixZQUFZLElBQUksZUFBZSxHQUFHLENBQUMsQ0FBQztRQUMzRyxDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxLQUFLLENBQUMsY0FBYyxDQUN6QixlQUE2QixFQUM3QixjQUFzQixFQUN0QixNQUF1QjtRQUV2QixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQywyQkFBMkIsRUFBRSxFQUFFLFFBQVEsRUFBRSxlQUFlLEVBQUUsQ0FBQyxDQUFDO1FBRTdFLGdHQUFnRztRQUNoRywyRkFBMkY7UUFDM0YscUVBQXFFO1FBQ3JFLG1GQUFtRjtRQUNuRix3RkFBd0Y7UUFFeEYsTUFBTSxVQUFVLEdBQUcsTUFBTSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQUMsQ0FBQyxDQUFDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUN2RSwwR0FBMEc7UUFDMUcsK0dBQStHO1FBQy9HLGdHQUFnRztRQUNoRyxNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBMkIsQ0FBQztRQUNuRCxNQUFNLFlBQVksR0FBRyxNQUFNLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxvQkFBb0IsQ0FBQyxlQUFlLENBQUMsQ0FBQztRQUN6RixLQUFLLE1BQU0sU0FBUyxJQUFJLFVBQVUsRUFBRSxDQUFDO1lBQ25DLE1BQU0sZ0JBQWdCLEdBQW9CLEVBQUUsQ0FBQztZQUU3QyxpRUFBaUU7WUFDakUsTUFBTSxPQUFPLEdBQUcsTUFBTSx1QkFBQSxJQUFJLHVGQUFvQyxNQUF4QyxJQUFJLEVBQXFDLGVBQWUsRUFBRSxTQUFTLENBQUMsQ0FBQztZQUUzRixvREFBb0Q7WUFDcEQsaUZBQWlGO1lBQ2pGLEVBQUU7WUFDRiwyR0FBMkc7WUFDM0csZ0hBQWdIO1lBQ2hILHVIQUF1SDtZQUN2SCx1SEFBdUg7WUFDdkgseUZBQXlGO1lBQ3pGLElBQUksaUJBQWlCLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsRUFBRTtnQkFDM0MsT0FBTztvQkFDTCxnQkFBZ0IsRUFBRSxNQUFNLENBQUMsZ0JBQWdCO29CQUN6QyxhQUFhLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsTUFBTSxDQUFDLEtBQUssR0FBRyxnQkFBZ0IsQ0FBQztvQkFDM0QsY0FBYyxFQUFFLE1BQU0sQ0FBQyxLQUFLLEdBQUcsZ0JBQWdCO2lCQUNoRCxDQUFDO1lBQ0osQ0FBQyxDQUFDLENBQUM7WUFFSCwyR0FBMkc7WUFDM0csTUFBTSx5QkFBeUIsR0FBNEIsRUFBRSxDQUFDO1lBRTlELCtHQUErRztZQUMvRyxNQUFNLGlCQUFpQixHQUFHLG9CQUFvQixDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBRXhELE9BQU8saUJBQWlCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUNwQyxNQUFNLHdCQUF3QixHQUFHLG9DQUFvQyxDQUFDLGlCQUFpQixDQUFDLENBQUM7Z0JBQ3pGLE1BQU0scUJBQXFCLEdBQUcsTUFBTSxPQUFPLENBQUMsR0FBRyxDQUM3Qyx3QkFBd0IsQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxNQUFNLENBQUMsZ0JBQWdCLENBQUMsU0FBUyxFQUFFLGVBQWUsQ0FBQyxDQUFDLENBQzVGLENBQUM7Z0JBRUYsdUdBQXVHO2dCQUN2RyxzREFBc0Q7Z0JBQ3RELE1BQU0sOEJBQThCLEdBQTRCLEVBQUUsQ0FBQztnQkFFbkUsb0RBQW9EO2dCQUNwRCxNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsYUFBYSxDQUFDLHFCQUFxQixDQUFDLENBQUM7Z0JBRTdFLFVBQVUsQ0FBQyxPQUFPLENBQUMsQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLEVBQUU7b0JBQ3pDLElBQUksU0FBUyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQzt3QkFDekIsMkRBQTJEO3dCQUMzRCxNQUFNLGdCQUFnQixHQUFHLFNBQVMsQ0FBQyxNQUFNLENBQ3ZDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsWUFBWSxJQUFJLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLGVBQWUsQ0FBQyxNQUFNLENBQUMsZUFBZSxDQUFDLENBQ2hHLENBQUM7d0JBQ0YsSUFBSSxnQkFBZ0IsQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLE1BQU0sRUFBRSxDQUFDOzRCQUMvQyxNQUFNLFNBQVMsR0FBRyxTQUFTLENBQUMsTUFBTSxDQUNoQyxHQUFHLENBQUMsRUFBRSxDQUFDLGdCQUFnQixDQUFDLElBQUksQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDLFdBQVcsQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsS0FBSyxTQUFTLENBQ25GLENBQUM7NEJBQ0YsSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQ1gsYUFDRSxTQUFTLENBQUMsTUFBTSxHQUFHLGdCQUFnQixDQUFDLE1BQ3RDLGlEQUFpRCxlQUFlLEdBQUcsRUFDbkUsU0FBUyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQ3BELENBQUM7d0JBQ0osQ0FBQzt3QkFFRCx5RUFBeUU7d0JBQ3pFLGdCQUFnQixDQUFDLElBQUksQ0FBQyxHQUFHLGdCQUFnQixDQUFDLENBQUM7d0JBRTNDLHFHQUFxRzt3QkFDckcsdUNBQXVDO3dCQUN2QyxNQUFNLHdCQUF3QixHQUFHLHdCQUF3QixDQUFDLFFBQVEsQ0FBQyxDQUFDO3dCQUNwRSxNQUFNLFlBQVksR0FBRyxpQkFBaUIsQ0FBQyx3QkFBd0IsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDO3dCQUU3RixJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxTQUFTLGdCQUFnQixDQUFDLE1BQU0sc0JBQXNCLFNBQVMsRUFBRSxFQUFFOzRCQUNoRixTQUFTOzRCQUNULE1BQU0sRUFBRSx3QkFBd0IsQ0FBQyxnQkFBZ0I7NEJBQ2pELFlBQVk7NEJBQ1osZUFBZTt5QkFDaEIsQ0FBQyxDQUFDO3dCQUVILElBQ0Usd0JBQXdCLENBQUMsS0FBSyxJQUFJLFlBQVk7NEJBQzlDLENBQUMsOEJBQThCLENBQUMsd0JBQXdCLENBQUMsZ0JBQWdCLENBQUMsUUFBUSxFQUFFLENBQUMsS0FBSyxTQUFTO2dDQUNqRyx3QkFBd0IsQ0FBQyxLQUFLO29DQUM1Qiw4QkFBOEIsQ0FBQyx3QkFBd0IsQ0FBQyxnQkFBZ0IsQ0FBQyxRQUFRLEVBQUUsQ0FBQyxDQUFDLEVBQ3pGLENBQUM7NEJBQ0QseUdBQXlHOzRCQUN6Ryx1RUFBdUU7NEJBQ3ZFLDhCQUE4QixDQUFDLHdCQUF3QixDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxDQUFDO2dDQUNsRix3QkFBd0IsQ0FBQyxLQUFLLEdBQUcsQ0FBQyxDQUFDOzRCQUVyQyxJQUFJLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FDWix5QkFDRSx3QkFBd0IsQ0FBQyxLQUFLLEdBQUcsQ0FDbkMsZ0JBQWdCLFlBQVksSUFBSSxlQUFlLEdBQUcsQ0FDbkQsQ0FBQzt3QkFDSixDQUFDO29CQUNILENBQUM7Z0JBQ0gsQ0FBQyxDQUFDLENBQUM7Z0JBRUgsK0dBQStHO2dCQUMvRywrR0FBK0c7Z0JBQy9HLG1FQUFtRTtnQkFDbkUsTUFBTSxvQkFBb0IsR0FBRyxFQUFFLENBQUM7Z0JBQ2hDLEtBQUssTUFBTSxDQUFDLGdCQUFnQixFQUFFLFFBQVEsQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsOEJBQThCLENBQUMsRUFBRSxDQUFDO29CQUMxRixNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxFQUFFLENBQUMsTUFBTSxDQUFDLGdCQUFnQixDQUFDLFFBQVEsRUFBRSxLQUFLLGdCQUFnQixDQUFDLENBQUM7b0JBQy9GLElBQUksTUFBTSxFQUFFLENBQUM7d0JBQ1gsb0JBQW9CLENBQUMsSUFBSSxDQUFDOzRCQUN4QixnQkFBZ0IsRUFBRSxNQUFNLENBQUMsZ0JBQWdCOzRCQUN6QyxvRkFBb0Y7NEJBQ3BGLGFBQWEsRUFBRSxRQUFROzRCQUN2QixjQUFjLEVBQUUsUUFBUSxHQUFHLGdCQUFnQjt5QkFDNUMsQ0FBQyxDQUFDO3dCQUVILHlFQUF5RTt3QkFDekUseUJBQXlCLENBQUMsZ0JBQWdCLENBQUMsR0FBRyxRQUFRLENBQUM7b0JBQ3pELENBQUM7eUJBQU0sQ0FBQzt3QkFDTixNQUFNLElBQUksS0FBSyxDQUNiLHlDQUF5QyxnQkFBZ0IsNENBQTRDLENBQ3RHLENBQUM7b0JBQ0osQ0FBQztnQkFDSCxDQUFDO2dCQUVELDRFQUE0RTtnQkFDNUUsaUJBQWlCLEdBQUcsb0JBQW9CLENBQUM7WUFDM0MsQ0FBQztZQUVELGdFQUFnRTtZQUNoRSxPQUFPLENBQUMsR0FBRyxDQUNULFNBQVMsQ0FBQyxRQUFRLEVBQUUsRUFDcEIsZ0JBQWdCLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLFdBQVcsSUFBSSxjQUFjLENBQUMsQ0FDbEUsQ0FBQztZQUVGLGdIQUFnSDtZQUNoSCxNQUFNLElBQUksQ0FBQyxFQUFFLENBQUMsbUNBQW1DLENBQy9DLE1BQU0sQ0FBQyxPQUFPLENBQUMseUJBQXlCLENBQUMsQ0FBQyxHQUFHLENBQzNDLENBQUMsQ0FBQyxnQkFBZ0IsRUFBRSxLQUFLLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxvQkFBb0IsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLGdCQUFnQixDQUFDLEVBQUUsS0FBSyxDQUFDLENBQ25HLENBQ0YsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPLE9BQU8sQ0FBQztJQUNqQixDQUFDO0lBMkNEOzs7O09BSUc7SUFDSSxLQUFLLENBQUMsaUJBQWlCLENBQzVCLElBQXFCLEVBQ3JCLFNBQXVCLEVBQ3ZCLFNBQXlCO1FBRXpCLE1BQU0sYUFBYSxHQUFHLE1BQU0sdUJBQUEsSUFBSSxzRUFBbUIsTUFBdkIsSUFBSSxFQUFvQixJQUFJLEVBQUUsU0FBUyxDQUFDLENBQUM7UUFFckUsMkdBQTJHO1FBQzNHLGlIQUFpSDtRQUNqSCw2R0FBNkc7UUFDN0csbUNBQW1DO1FBQ25DLEtBQUssTUFBTSxZQUFZLElBQUksYUFBYSxFQUFFLENBQUM7WUFDekMsZ0hBQWdIO1lBQ2hILGtIQUFrSDtZQUNsSCxPQUFPO1lBQ1AsTUFBTSxRQUFRLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdkUsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUNkLE1BQU0sSUFBSSxLQUFLLENBQUMsd0NBQXdDLFlBQVksQ0FBQyxNQUFNLEVBQUUsQ0FBQyxDQUFDO1lBQ2pGLENBQUM7WUFFRCxvREFBb0Q7WUFDcEQsTUFBTSxJQUFJLENBQUMsY0FBYyxDQUN2QixZQUFZLENBQUMsZUFBZSxFQUM1QixZQUFZLENBQUMsU0FBUyxFQUN0QixZQUFZLENBQUMsTUFBTSxFQUNuQixRQUFRLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFDeEIsUUFBUSxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQyxDQUFDLEVBQzNCLFNBQVMsRUFDVCxTQUFTLENBQ1YsQ0FBQztRQUNKLENBQUM7UUFDRCxPQUFPO0lBQ1QsQ0FBQztJQUVELHNHQUFzRztJQUMvRixLQUFLLENBQUMsV0FBVyxDQUN0QixlQUE2QixFQUM3QixXQUFlLEVBQ2YsS0FBUyxFQUNULE9BQWEsRUFDYixRQUFZLEVBQ1osU0FBYSxFQUNiLE1BQVUsRUFDVixTQUF1QjtRQUV2QixNQUFNLE9BQU8sR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLENBQ3ZDLGVBQWUsRUFDZixXQUFXLEVBQ1gsS0FBSyxFQUNMLE9BQU8sRUFDUCxRQUFRLEVBQ1IsU0FBUyxFQUNULE1BQU0sRUFDTixTQUFTLENBQ1YsQ0FBQztRQUVGLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxRQUFRLENBQUMsQ0FBQyxPQUFPLENBQUMsRUFBRSxTQUFTLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxZQUFZLEVBQUU7WUFDN0IsUUFBUSxFQUFFLE9BQU8sQ0FBQyxlQUFlO1lBQ2pDLElBQUksRUFBRSxPQUFPLENBQUMsV0FBVztZQUN6QixTQUFTLEVBQUUsT0FBTyxDQUFDLGVBQWUsQ0FBQyxRQUFRO1NBQzVDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFTSxLQUFLLENBQUMsb0JBQW9CLENBQUMsZUFBNkI7UUFDN0QsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsMEJBQTBCLEVBQUUsRUFBRSxRQUFRLEVBQUUsZUFBZSxFQUFFLENBQUMsQ0FBQztRQUU1RSxLQUFLLE1BQU0sU0FBUyxJQUFJLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxXQUFXLEVBQUUsRUFBRSxDQUFDO1lBQzFELE1BQU0sd0JBQXdCLEdBQUcsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxFQUFFLGVBQWUsRUFBRSxLQUFLLEVBQUUsU0FBUyxFQUFFLENBQUMsQ0FBQztZQUMvRixNQUFNLGlCQUFpQixHQUFHLHdCQUF3QixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQztZQUNyRixNQUFNLGdCQUFnQixHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyw4QkFBOEIsQ0FBQyxRQUFRLEVBQUUsaUJBQWlCLENBQUMsQ0FBQztZQUUxRyxNQUFNLGVBQWUsR0FBRyxpQkFBaUI7aUJBQ3RDLEdBQUcsQ0FBQyxDQUFDLFNBQVMsRUFBRSxDQUFDLEVBQUUsRUFBRTtnQkFDcEIsSUFBSSxnQkFBZ0IsQ0FBQyxDQUFDLENBQUMsS0FBSyxTQUFTLEVBQUUsQ0FBQztvQkFDdEMsT0FBTyxFQUFFLEdBQUcsZ0JBQWdCLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxTQUFTLEVBQUUsRUFBaUIsQ0FBQztnQkFDM0UsQ0FBQztZQUNILENBQUMsQ0FBQztpQkFDRCxNQUFNLENBQUMsU0FBUyxDQUFDLEVBQUUsQ0FBQyxTQUFTLEtBQUssU0FBUyxDQUFrQixDQUFDO1lBRWpFLE1BQU0sY0FBYyxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxvQkFBb0IsQ0FBQyxlQUFlLEVBQUUsTUFBTSxTQUFTLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQztZQUM3RyxjQUFjLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFO2dCQUMvQixJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyw2QkFBNkIsT0FBTyxDQUFDLGVBQWUsWUFBWSxPQUFPLENBQUMsV0FBVyxFQUFFLEVBQUU7b0JBQ3RHLFFBQVEsRUFBRSxPQUFPLENBQUMsZUFBZTtvQkFDakMsSUFBSSxFQUFFLE9BQU8sQ0FBQyxXQUFXO29CQUN6QixTQUFTLEVBQUUsT0FBTyxDQUFDLGVBQWUsQ0FBQyxRQUFRLEVBQUU7aUJBQzlDLENBQUMsQ0FBQztZQUNMLENBQUMsQ0FBQyxDQUFDO1FBQ0wsQ0FBQztJQUNILENBQUM7SUFFRCxLQUFLLENBQUMsY0FBYyxDQUNsQixlQUE2QixFQUM3QixXQUFlLEVBQ2YsS0FBUyxFQUNULE9BQWEsRUFDYixRQUFZLEVBQ1osU0FBYSxFQUNiLE1BQVUsRUFDVixTQUF1QjtRQUV2Qiw2R0FBNkc7UUFDN0csdUJBQXVCO1FBRXZCLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxZQUFZLENBQUMsSUFBSSxNQUFNLENBQUMsTUFBTSxDQUFDLENBQUMsQ0FBQztRQUN0RSxJQUFJLE9BQU8sS0FBSyxTQUFTLEVBQUUsQ0FBQztZQUMxQixNQUFNLElBQUksS0FBSyxDQUFDLDBDQUEwQyxNQUFNLGlDQUFpQyxDQUFDLENBQUM7UUFDckcsQ0FBQztRQUVELDZHQUE2RztRQUM3Ryw2R0FBNkc7UUFDN0csTUFBTSxjQUFjLEdBQUcsTUFBTSxxQkFBcUIsQ0FBQyxLQUFLLEVBQUUsTUFBTSxZQUFZLENBQUMsZUFBZSxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7UUFDekcsTUFBTSxlQUFlLEdBQUcsTUFBTSxhQUFhLENBQUMsZUFBZSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRXhFLGlIQUFpSDtRQUNqSCxtSEFBbUg7UUFDbkgsbUhBQW1IO1FBQ25ILDRHQUE0RztRQUM1RyxNQUFNLGlCQUFpQixHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUN6RCxNQUFNLHVCQUF1QixHQUFHLENBQzlCLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxpQkFBaUIsQ0FBQyxpQkFBa0IsRUFBRSxZQUFZLENBQUMsY0FBYyxFQUFFLENBQUMsY0FBYyxDQUFDLENBQUMsQ0FDMUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNMLElBQUksdUJBQXVCLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDMUMsTUFBTSxJQUFJLEtBQUssQ0FDYixhQUFhLFFBQVEsZ0JBQWdCLGNBQWMseUNBQXlDLGlCQUFpQixhQUFhLE1BQU0sR0FBRyxDQUNwSSxDQUFDO1FBQ0osQ0FBQztRQUVELE9BQU8sSUFBSSxPQUFPLENBQ2hCLElBQUksSUFBSSxDQUFDLE9BQU8sQ0FBQyxFQUNqQixlQUFlLEVBQ2YsV0FBVyxFQUNYLEtBQUssRUFDTCxRQUFRLEVBQ1IsZUFBZSxFQUNmLElBQUksTUFBTSxDQUFDLE1BQU0sQ0FBQyxFQUNsQixPQUFPLENBQUMsV0FBWSxFQUNwQixPQUFPLENBQUMsU0FBVSxDQUFDLFFBQVEsRUFBRSxFQUM3Qix1QkFBdUIsRUFDdkIsTUFBTSxTQUFTLENBQUMsY0FBYyxFQUFFLEVBQ2hDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FDckIsQ0FBQztJQUNKLENBQUM7SUFFRCxLQUFLLENBQUMsY0FBYyxDQUNsQixlQUE2QixFQUM3QixZQUFrQixFQUNsQixNQUFjLEVBQ2QsVUFBZ0IsRUFDaEIsY0FBa0IsRUFDbEIsU0FBdUIsRUFDdkIsU0FBeUI7UUFFekIsTUFBTSxRQUFRLEdBQWlDLE1BQU0sSUFBSSxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUMseUJBQXlCLENBQzVHLGVBQWUsRUFDZixhQUFhLENBQ2QsQ0FBQztRQUNGLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUNkLE1BQU0sSUFBSSxLQUFLLENBQ2Isc0VBQXNFLGVBQWUsQ0FBQyxRQUFRLEVBQUUsR0FBRyxDQUNwRyxDQUFDO1FBQ0osQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFpQjtZQUNoQyxJQUFJLEVBQUUsUUFBUSxDQUFDLElBQUk7WUFDbkIsRUFBRSxFQUFFLGVBQWU7WUFDbkIsUUFBUSxFQUFFLE1BQU0sZ0JBQWdCLENBQUMscUJBQXFCLENBQUMsUUFBUSxDQUFDO1lBQ2hFLElBQUksRUFBRSxZQUFZLENBQUMsYUFBYTtZQUNoQyxRQUFRLEVBQUUsUUFBUSxDQUFDLFFBQVE7WUFDM0IsSUFBSSxFQUFFLGVBQWUsQ0FBQyxRQUFRLEVBQUU7Z0JBQzlCLFlBQVksQ0FBQyxZQUFZLEVBQUUsMEJBQTBCLENBQUM7Z0JBQ3RELE1BQU0sQ0FBQyxRQUFRLEVBQUU7Z0JBQ2pCLFlBQVksQ0FBQyxVQUFVLEVBQUUsc0JBQXNCLENBQUM7Z0JBQ2hELGNBQWM7Z0JBQ2QsU0FBUzthQUNWLENBQUM7WUFDRixXQUFXLEVBQUUsUUFBUSxDQUFDLFdBQVc7U0FDbEMsQ0FBQztRQUVGLE1BQU0sQ0FDSixTQUFTO1lBQ1QsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxJQUFJLENBQUMsU0FBUyxFQUFFLElBQUksQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLGtCQUFrQixFQUFFLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxDQUMzRyxDQUFDLGdCQUFnQixDQUNoQixXQUFXLEVBQ1gsUUFBUSxFQUNSLGVBQWUsRUFDZixFQUFFLENBQ0gsQ0FBQztJQUNKLENBQUM7SUFFRCxPQUFPLENBQUMsZUFBNkIsRUFBRSxJQUFRLEVBQUUsTUFBWTtRQUMzRCxPQUFPLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFDLGVBQWUsRUFBRSxJQUFJLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDeEQsQ0FBQztJQUVELE1BQU0sQ0FBQyxlQUE2QixFQUFFLElBQVE7UUFDNUMsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDL0MsQ0FBQztJQUVELFFBQVEsQ0FBQyxlQUE2QixFQUFFLElBQVE7UUFDOUMsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDLFFBQVEsQ0FBQyxlQUFlLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDakQsQ0FBQztJQUVELE1BQU0sQ0FBQyxlQUE2QixFQUFFLE9BQVcsRUFBRSxPQUFXLEVBQUUsVUFBa0I7UUFDaEYsT0FBTyxJQUFJLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxlQUFlLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxVQUFVLENBQUMsQ0FBQztJQUN2RSxDQUFDO0NBQ0Y7NkVBL29CQyxLQUFLLHlDQUFnQixXQUEwQixFQUFFLE1BQW9CLEVBQUUsU0FBYTtJQUNsRixNQUFNLENBQUMsU0FBUyxDQUFDLEdBQUcsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLGlCQUFpQixDQUFDLFdBQVcsRUFBRSxNQUFNLEVBQUUsQ0FBQyxTQUFTLENBQUMsQ0FBQyxDQUFDO0lBQzdGLE9BQU8sU0FBUyxDQUFDO0FBQ25CLENBQUMsb0NBYUQsS0FBSywwQ0FBaUIsV0FBbUIsRUFBRSxNQUFvQixFQUFFLFNBQWlCO0lBQ2hGLFFBQVEsTUFBTSxFQUFFLENBQUM7UUFDZixLQUFLLFlBQVksQ0FBQyxjQUFjO1lBQzlCLE9BQU8sQ0FBQyxNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsdUJBQXVCLENBQUMsV0FBVyxFQUFFLFNBQVMsQ0FBQyxDQUFDLENBQUMsUUFBUSxFQUFFLENBQUM7UUFDM0YsS0FBSyxZQUFZLENBQUMsY0FBYztZQUM5QixPQUFPLENBQUMsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLHNCQUFzQixDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzFGLEtBQUssWUFBWSxDQUFDLGdCQUFnQjtZQUNoQyxPQUFPLENBQUMsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLHdCQUF3QixDQUFDLFdBQVcsRUFBRSxTQUFTLENBQUMsQ0FBQyxDQUFDLFFBQVEsRUFBRSxDQUFDO1FBQzVGLEtBQUssWUFBWSxDQUFDLE9BQU87WUFDdkIsT0FBTyxDQUFDLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQyxXQUFXLEVBQUUsU0FBUyxDQUFDLENBQUMsQ0FBQyxRQUFRLEVBQUUsQ0FBQztRQUN6RjtZQUNFLE1BQU0sSUFBSSxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztJQUN2QyxDQUFDO0FBQ0gsQ0FBQywrQ0EwR0QsS0FBSyxxREFBNEIsZUFBNkIsRUFBRSxNQUFvQixFQUFFLFNBQXVCO0lBQzNHLE1BQU0scUJBQXFCLEdBQUcsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDcEUsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGlDQUFpQyxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ2pGLE1BQU0sV0FBVyxHQUFHLE1BQU0seUJBQXlCLENBQUMscUJBQXFCLEVBQUUsVUFBVSxFQUFFLFNBQVMsQ0FBQyxDQUFDO0lBQ2xHLGlFQUFpRTtJQUNqRSxNQUFNLFNBQVMsR0FBRyxhQUFhLENBQUMsQ0FBQyxXQUFXLENBQUMsQ0FBQyxFQUFFLFdBQVcsQ0FBQyxDQUFDLEVBQUUsZUFBZSxDQUFDLENBQUMsQ0FBQztJQUNqRixPQUFPLFNBQVMsQ0FBQztBQUNuQixDQUFDO0FBRUQ7Ozs7Ozs7O0dBUUc7QUFDSCxLQUFLLDhEQUNILGVBQTZCLEVBQzdCLFNBQXVCO0lBRXZCLE1BQU0sd0JBQXdCLEdBQUcsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDMUUsTUFBTSxhQUFhLEdBQUcsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLGlDQUFpQyxDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBRXZGLCtHQUErRztJQUMvRyxnQ0FBZ0M7SUFDaEMsTUFBTSxPQUFPLEdBQUcsQ0FBQyxHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsRUFBRSxDQUFDLGtCQUFrQixFQUFFLENBQUMsRUFBRSxHQUFHLENBQUMsTUFBTSxJQUFJLENBQUMsUUFBUSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUMsQ0FBQyxNQUFNLENBQ3RHLENBQUMsT0FBTyxFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUUsRUFBRSxDQUFDLEtBQUssS0FBSyxJQUFJLENBQUMsU0FBUyxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUNqRyxDQUFDO0lBQ0YsTUFBTSxpQkFBaUIsR0FBRyxNQUFNLE9BQU8sQ0FBQyxHQUFHLENBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsS0FBSyxFQUFDLE9BQU8sRUFBQyxFQUFFO1FBQzFCLE1BQU0sWUFBWSxHQUFHLE1BQU0seUJBQXlCLENBQUMsd0JBQXdCLEVBQUUsYUFBYSxFQUFFLE9BQU8sQ0FBQyxDQUFDO1FBQ3ZHLE9BQU8sYUFBYSxDQUFDLENBQUMsWUFBWSxDQUFDLENBQUMsRUFBRSxZQUFZLENBQUMsQ0FBQyxFQUFFLGVBQWUsQ0FBQyxDQUFDLENBQUM7SUFDMUUsQ0FBQyxDQUFDLENBQ0gsQ0FBQztJQUNGLE1BQU0sT0FBTyxHQUFHLE1BQU0sSUFBSSxDQUFDLEVBQUUsQ0FBQyxtQ0FBbUMsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQ3JGLE9BQU8saUJBQWlCLENBQUMsR0FBRyxDQUFDLENBQUMsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxvQkFBb0IsQ0FBQyxNQUFNLEVBQUUsT0FBTyxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQztBQUM1RixDQUFDO0FBdU9EOzs7OztHQUtHO0FBQ0gsS0FBSyw2Q0FBb0IsVUFBMkIsRUFBRSxTQUF1QjtJQUMzRSxNQUFNLHdCQUF3QixHQUFHLE1BQU0sSUFBSSxDQUFDLGtCQUFrQixDQUFDLFNBQVMsQ0FBQyxDQUFDO0lBQzFFLE1BQU0sS0FBSyxHQUFHLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxrQkFBa0IsQ0FDbEQsd0JBQXdCLENBQUMsVUFBVSxDQUFDLDhCQUE4QixDQUNuRSxDQUFDO0lBQ0YsTUFBTSxhQUFhLEdBQUcsTUFBTSxvQkFBb0IsQ0FBQyxNQUFNLHdCQUF3QixDQUFDLGFBQWEsRUFBRSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBRXhHLDJFQUEyRTtJQUMzRSwwQ0FBMEM7SUFDMUMsTUFBTSxlQUFlLEdBQTZCLElBQUksR0FBRyxFQUFFLENBQUM7SUFDNUQsTUFBTSxTQUFTLEdBQUcsRUFBRSxDQUFDO0lBRXJCLEtBQUssTUFBTSxTQUFTLElBQUksVUFBVSxFQUFFLENBQUM7UUFDbkMsTUFBTSxPQUFPLEdBQUcsU0FBUyxDQUFDLFlBQVk7WUFDcEMsQ0FBQyxDQUFDLE1BQU0sYUFBYSxDQUFDLDJCQUEyQixDQUFDLFNBQVMsQ0FBQyxVQUFVLENBQUMsU0FBUyxDQUFDLE9BQU8sQ0FBQyxFQUFFLGFBQWEsQ0FBQztZQUN6RyxDQUFDLENBQUMsTUFBTSxhQUFhLENBQUMsaUJBQWlCLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQyxTQUFTLENBQUMsT0FBTyxDQUFDLEVBQUUsYUFBYSxDQUFDLENBQUM7UUFFbkcsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ2IsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsdUJBQXVCLENBQUMsQ0FBQztZQUMxQyxTQUFTO1FBQ1gsQ0FBQztRQUVELElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxNQUFNLENBQUMsUUFBUSxFQUFFLENBQUMsRUFBRSxDQUFDO1lBQ3RELGVBQWUsQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUUsRUFBRSxJQUFJLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDOUQsQ0FBQztRQUVELE1BQU0sSUFBSSxHQUFHLE1BQU0sbUJBQW1CLENBQUMsSUFBSSxDQUFDLEVBQUUsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUN6RCxNQUFNLFNBQVMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxXQUFXLEVBQUUsT0FBTyxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxHQUFHLElBQUksQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUVyRixTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUUsU0FBUyxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsTUFBTSxFQUFFLGVBQWUsRUFBRSxPQUFPLENBQUMsZUFBZSxFQUFFLENBQUMsQ0FBQztJQUNwRyxDQUFDO0lBRUQsT0FBTyxTQUFTLENBQUM7QUFDbkIsQ0FBQztBQXNOSCxTQUFTLFlBQVksQ0FBQyxLQUFXLEVBQUUsU0FBaUI7SUFDbEQsT0FBTyxFQUFFLE9BQU8sRUFBRSxLQUFLLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDLE1BQU0sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsR0FBRyxFQUFFLEtBQUssQ0FBQyxNQUFNLEVBQUUsQ0FBQztBQUN2RyxDQUFDIn0=