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