@apibara/protocol 2.1.0-beta.52 → 2.1.0-beta.54
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/dist/index.cjs +1 -1
- package/dist/index.d.cts +1 -1
- package/dist/index.d.mts +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1 -1
- package/dist/rpc/index.cjs +1 -1
- package/dist/rpc/index.d.cts +1 -1
- package/dist/rpc/index.d.mts +1 -1
- package/dist/rpc/index.d.ts +1 -1
- package/dist/rpc/index.mjs +1 -1
- package/dist/shared/{protocol.6ab8d6dd.d.mts → protocol.1a69a01d.d.mts} +15 -14
- package/dist/shared/{protocol.8407f25e.d.ts → protocol.1b2e5598.d.ts} +15 -14
- package/dist/shared/{protocol.7aa4aab6.d.cts → protocol.5dc2fc0d.d.cts} +15 -14
- package/dist/shared/{protocol.54f17699.cjs → protocol.a44ea889.cjs} +125 -74
- package/dist/shared/protocol.a44ea889.cjs.map +1 -0
- package/dist/shared/{protocol.bde61588.mjs → protocol.e329df99.mjs} +125 -74
- package/dist/shared/protocol.e329df99.mjs.map +1 -0
- package/package.json +2 -1
- package/src/rpc/chain-tracker.ts +83 -16
- package/src/rpc/config.ts +16 -17
- package/src/rpc/data-stream.ts +102 -39
- package/src/rpc/index.ts +3 -2
- package/dist/shared/protocol.54f17699.cjs.map +0 -1
- package/dist/shared/protocol.bde61588.mjs.map +0 -1
package/src/rpc/chain-tracker.ts
CHANGED
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import { fromHex } from "viem";
|
|
2
2
|
import type { Bytes, Cursor } from "../common";
|
|
3
|
-
import type { BlockInfo } from "./config";
|
|
3
|
+
import type { BlockInfo, FetchCursorRangeArgs } from "./config";
|
|
4
4
|
import { blockInfoToCursor } from "./helpers";
|
|
5
5
|
|
|
6
6
|
type UpdateHeadArgs = {
|
|
7
7
|
newHead: BlockInfo;
|
|
8
8
|
fetchCursorByHash: (hash: Bytes) => Promise<BlockInfo | null>;
|
|
9
|
+
fetchCursorRange: (args: FetchCursorRangeArgs) => Promise<BlockInfo[]>;
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
type UpdateHeadResult =
|
|
@@ -24,10 +25,21 @@ export class ChainTracker {
|
|
|
24
25
|
#finalized: BlockInfo;
|
|
25
26
|
#head: BlockInfo;
|
|
26
27
|
#canonical: Map<bigint, BlockInfo>;
|
|
28
|
+
#batchSize: bigint;
|
|
27
29
|
|
|
28
|
-
constructor({
|
|
30
|
+
constructor({
|
|
31
|
+
head,
|
|
32
|
+
finalized,
|
|
33
|
+
batchSize,
|
|
34
|
+
}: {
|
|
35
|
+
finalized: BlockInfo;
|
|
36
|
+
head: BlockInfo;
|
|
37
|
+
batchSize: bigint;
|
|
38
|
+
}) {
|
|
29
39
|
this.#finalized = finalized;
|
|
30
40
|
this.#head = head;
|
|
41
|
+
this.#batchSize = batchSize;
|
|
42
|
+
|
|
31
43
|
this.#canonical = new Map([
|
|
32
44
|
[finalized.blockNumber, finalized],
|
|
33
45
|
[head.blockNumber, head],
|
|
@@ -106,6 +118,7 @@ export class ChainTracker {
|
|
|
106
118
|
async updateHead({
|
|
107
119
|
newHead,
|
|
108
120
|
fetchCursorByHash,
|
|
121
|
+
fetchCursorRange,
|
|
109
122
|
}: UpdateHeadArgs): Promise<UpdateHeadResult> {
|
|
110
123
|
// console.debug(
|
|
111
124
|
// `updateHead: new=${newHead.blockNumber} old=${this.#head.blockNumber}`,
|
|
@@ -192,10 +205,47 @@ export class ChainTracker {
|
|
|
192
205
|
// The new chain is longer and we need the missing blocks.
|
|
193
206
|
// This may result in reorgs.
|
|
194
207
|
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
208
|
+
// console.log(
|
|
209
|
+
// `Moving from ${this.#head.blockNumber} to ${newHead.blockNumber} (${newHead.blockNumber - this.#head.blockNumber} blocks)`,
|
|
210
|
+
// );
|
|
211
|
+
|
|
212
|
+
let currentBlockNumber = this.#head.blockNumber + 1n;
|
|
213
|
+
|
|
214
|
+
while (true) {
|
|
215
|
+
let endBlockNumber = currentBlockNumber + this.#batchSize;
|
|
216
|
+
if (endBlockNumber > newHead.blockNumber) {
|
|
217
|
+
endBlockNumber = newHead.blockNumber;
|
|
218
|
+
}
|
|
219
|
+
|
|
220
|
+
const missing = await fetchCursorRange({
|
|
221
|
+
startBlockNumber: currentBlockNumber,
|
|
222
|
+
endBlockNumber,
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
for (const block of missing) {
|
|
226
|
+
const canonicalParent = this.#canonical.get(block.blockNumber - 1n);
|
|
227
|
+
if (
|
|
228
|
+
!canonicalParent ||
|
|
229
|
+
canonicalParent.blockHash !== block.parentBlockHash
|
|
230
|
+
) {
|
|
231
|
+
throw new Error(
|
|
232
|
+
"Chain reorganization detected. Recovery not implemented",
|
|
233
|
+
);
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
this.#canonical.set(block.blockNumber, block);
|
|
237
|
+
|
|
238
|
+
// console.log(`Applied block ${block.blockNumber}`);
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
if (endBlockNumber === newHead.blockNumber) {
|
|
242
|
+
break;
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
currentBlockNumber = endBlockNumber + 1n;
|
|
246
|
+
}
|
|
198
247
|
|
|
248
|
+
/*
|
|
199
249
|
while (true) {
|
|
200
250
|
const parent = await fetchCursorByHash(current.parentBlockHash);
|
|
201
251
|
|
|
@@ -226,24 +276,39 @@ export class ChainTracker {
|
|
|
226
276
|
blocksToApply.push(parent);
|
|
227
277
|
current = parent;
|
|
228
278
|
}
|
|
279
|
+
*/
|
|
280
|
+
// throw new Error("FUCK IT");
|
|
229
281
|
|
|
230
|
-
for (const block of blocksToApply.reverse()) {
|
|
231
|
-
|
|
232
|
-
}
|
|
282
|
+
// for (const block of blocksToApply.reverse()) {
|
|
283
|
+
// this.#canonical.set(block.blockNumber, block);
|
|
284
|
+
// }
|
|
233
285
|
|
|
234
|
-
const previousHead = this.#head;
|
|
286
|
+
// const previousHead = this.#head;
|
|
235
287
|
this.#head = newHead;
|
|
236
288
|
|
|
237
|
-
if (reorgDetected) {
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
289
|
+
// if (reorgDetected) {
|
|
290
|
+
// return {
|
|
291
|
+
// status: "reorg",
|
|
292
|
+
// cursor: blockInfoToCursor(previousHead),
|
|
293
|
+
// };
|
|
294
|
+
// }
|
|
243
295
|
|
|
244
296
|
return { status: "success" };
|
|
245
297
|
}
|
|
246
298
|
|
|
299
|
+
isCanonical({ orderKey, uniqueKey }: Cursor) {
|
|
300
|
+
if (!uniqueKey) {
|
|
301
|
+
return true;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const block = this.#canonical.get(orderKey);
|
|
305
|
+
if (!block) {
|
|
306
|
+
return true;
|
|
307
|
+
}
|
|
308
|
+
|
|
309
|
+
return block.blockHash === uniqueKey;
|
|
310
|
+
}
|
|
311
|
+
|
|
247
312
|
async initializeStartingCursor({
|
|
248
313
|
cursor,
|
|
249
314
|
fetchCursor,
|
|
@@ -319,9 +384,11 @@ export class ChainTracker {
|
|
|
319
384
|
export function createChainTracker({
|
|
320
385
|
head,
|
|
321
386
|
finalized,
|
|
387
|
+
batchSize,
|
|
322
388
|
}: {
|
|
323
389
|
head: BlockInfo;
|
|
324
390
|
finalized: BlockInfo;
|
|
391
|
+
batchSize: bigint;
|
|
325
392
|
}): ChainTracker {
|
|
326
|
-
return new ChainTracker({ finalized, head });
|
|
393
|
+
return new ChainTracker({ finalized, head, batchSize });
|
|
327
394
|
}
|
package/src/rpc/config.ts
CHANGED
|
@@ -2,7 +2,7 @@ import type { Bytes, Cursor } from "../common";
|
|
|
2
2
|
|
|
3
3
|
export type FetchBlockRangeArgs<TFilter> = {
|
|
4
4
|
startBlock: bigint;
|
|
5
|
-
|
|
5
|
+
maxBlock: bigint;
|
|
6
6
|
force: boolean;
|
|
7
7
|
filter: TFilter;
|
|
8
8
|
};
|
|
@@ -25,23 +25,21 @@ export type BlockInfo = {
|
|
|
25
25
|
parentBlockHash: Bytes;
|
|
26
26
|
};
|
|
27
27
|
|
|
28
|
-
export type
|
|
29
|
-
|
|
30
|
-
expectedParentBlockHash: Bytes;
|
|
28
|
+
export type FetchBlockByHashArgs<TFilter> = {
|
|
29
|
+
blockHash: Bytes;
|
|
31
30
|
isAtHead: boolean;
|
|
32
31
|
filter: TFilter;
|
|
33
32
|
};
|
|
34
33
|
|
|
35
|
-
export type
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
};
|
|
34
|
+
export type FetchBlockByHashResult<TBlock> = {
|
|
35
|
+
data: FetchBlockResult<TBlock>;
|
|
36
|
+
blockInfo: BlockInfo;
|
|
37
|
+
};
|
|
38
|
+
|
|
39
|
+
export type FetchCursorRangeArgs = {
|
|
40
|
+
startBlockNumber: bigint;
|
|
41
|
+
endBlockNumber: bigint;
|
|
42
|
+
};
|
|
45
43
|
|
|
46
44
|
export type FetchCursorArgs =
|
|
47
45
|
| {
|
|
@@ -74,6 +72,7 @@ export abstract class RpcStreamConfig<TFilter, TBlock> {
|
|
|
74
72
|
abstract headRefreshIntervalMs(): number;
|
|
75
73
|
abstract finalizedRefreshIntervalMs(): number;
|
|
76
74
|
|
|
75
|
+
abstract fetchCursorRange(args: FetchCursorRangeArgs): Promise<BlockInfo[]>;
|
|
77
76
|
abstract fetchCursor(args: FetchCursorArgs): Promise<BlockInfo | null>;
|
|
78
77
|
|
|
79
78
|
abstract validateFilter(filter: TFilter): ValidateFilterResult;
|
|
@@ -82,7 +81,7 @@ export abstract class RpcStreamConfig<TFilter, TBlock> {
|
|
|
82
81
|
args: FetchBlockRangeArgs<TFilter>,
|
|
83
82
|
): Promise<FetchBlockRangeResult<TBlock>>;
|
|
84
83
|
|
|
85
|
-
abstract
|
|
86
|
-
args:
|
|
87
|
-
): Promise<
|
|
84
|
+
abstract fetchBlockByHash(
|
|
85
|
+
args: FetchBlockByHashArgs<TFilter>,
|
|
86
|
+
): Promise<FetchBlockByHashResult<TBlock>>;
|
|
88
87
|
}
|
package/src/rpc/data-stream.ts
CHANGED
|
@@ -14,10 +14,14 @@ type State<TFilter, TBlock> = {
|
|
|
14
14
|
cursor: Cursor;
|
|
15
15
|
// When the finalized block was last refreshed.
|
|
16
16
|
lastFinalizedRefresh: number;
|
|
17
|
+
// When the head was last refreshed.
|
|
18
|
+
lastHeadRefresh: number;
|
|
17
19
|
// When the last heartbeat was sent.
|
|
18
20
|
lastHeartbeat: number;
|
|
19
21
|
// When the last backfill message was sent.
|
|
20
22
|
lastBackfillMessage: number;
|
|
23
|
+
// The last empty header sent.
|
|
24
|
+
lastEmptyBlockNumber: bigint | undefined;
|
|
21
25
|
// Track the chain's state.
|
|
22
26
|
chainTracker: ChainTracker;
|
|
23
27
|
// Heartbeat interval in milliseconds.
|
|
@@ -71,6 +75,7 @@ export class RpcDataStream<TFilter, TBlock> {
|
|
|
71
75
|
const chainTracker = createChainTracker({
|
|
72
76
|
head,
|
|
73
77
|
finalized,
|
|
78
|
+
batchSize: 20n,
|
|
74
79
|
});
|
|
75
80
|
|
|
76
81
|
let cursor: Cursor;
|
|
@@ -97,7 +102,9 @@ export class RpcDataStream<TFilter, TBlock> {
|
|
|
97
102
|
cursor,
|
|
98
103
|
lastHeartbeat: Date.now(),
|
|
99
104
|
lastFinalizedRefresh: Date.now(),
|
|
105
|
+
lastHeadRefresh: Date.now(),
|
|
100
106
|
lastBackfillMessage: Date.now(),
|
|
107
|
+
lastEmptyBlockNumber: undefined,
|
|
101
108
|
chainTracker,
|
|
102
109
|
config: this.config,
|
|
103
110
|
heartbeatIntervalMs: this.heartbeatIntervalMs,
|
|
@@ -156,7 +163,7 @@ async function* dataStreamLoop<TFilter, TBlock>(
|
|
|
156
163
|
if (isAtHead(state)) {
|
|
157
164
|
yield* waitForHeadChange(state);
|
|
158
165
|
} else {
|
|
159
|
-
yield*
|
|
166
|
+
yield* produceLiveBlocks(state);
|
|
160
167
|
}
|
|
161
168
|
}
|
|
162
169
|
}
|
|
@@ -174,7 +181,7 @@ async function* backfillFinalizedBlocks<TFilter, TBlock>(
|
|
|
174
181
|
|
|
175
182
|
const filterData = await config.fetchBlockRange({
|
|
176
183
|
startBlock: cursor.orderKey + 1n,
|
|
177
|
-
|
|
184
|
+
maxBlock: finalized.orderKey,
|
|
178
185
|
force,
|
|
179
186
|
filter,
|
|
180
187
|
});
|
|
@@ -209,59 +216,108 @@ async function* backfillFinalizedBlocks<TFilter, TBlock>(
|
|
|
209
216
|
}
|
|
210
217
|
}
|
|
211
218
|
|
|
212
|
-
// This is a generator to possibly produce data for
|
|
219
|
+
// This is a generator to possibly produce data for live blocks.
|
|
213
220
|
//
|
|
214
221
|
// It's a generator because it's not guaranteed to produce data for the next block.
|
|
215
|
-
async function*
|
|
222
|
+
async function* produceLiveBlocks<TFilter, TBlock>(
|
|
216
223
|
state: State<TFilter, TBlock>,
|
|
217
224
|
): AsyncGenerator<StreamDataResponse<TBlock>> {
|
|
218
|
-
const
|
|
225
|
+
const { config, cursor, chainTracker, filter } = state;
|
|
219
226
|
|
|
220
|
-
if (
|
|
221
|
-
|
|
222
|
-
|
|
227
|
+
if (shouldRefreshHead(state)) {
|
|
228
|
+
const maybeNewHead = await config.fetchCursor({ blockTag: "latest" });
|
|
229
|
+
if (maybeNewHead === null) {
|
|
230
|
+
throw new Error("Failed to fetch the latest block");
|
|
231
|
+
}
|
|
223
232
|
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
});
|
|
233
|
+
const result = await chainTracker.updateHead({
|
|
234
|
+
newHead: maybeNewHead,
|
|
235
|
+
fetchCursorByHash: (blockHash) => config.fetchCursor({ blockHash }),
|
|
236
|
+
fetchCursorRange: (args) => config.fetchCursorRange(args),
|
|
237
|
+
});
|
|
230
238
|
|
|
231
|
-
|
|
239
|
+
state.lastHeadRefresh = Date.now();
|
|
232
240
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
241
|
+
if (result.status === "reorg") {
|
|
242
|
+
const { cursor } = result;
|
|
243
|
+
// Only handle reorgs if they involve blocks already processed.
|
|
244
|
+
if (
|
|
245
|
+
cursor.orderKey < state.cursor.orderKey ||
|
|
246
|
+
(state.lastEmptyBlockNumber !== undefined &&
|
|
247
|
+
cursor.orderKey < state.lastEmptyBlockNumber)
|
|
248
|
+
) {
|
|
249
|
+
state.cursor = cursor;
|
|
250
|
+
|
|
251
|
+
yield {
|
|
252
|
+
_tag: "invalidate",
|
|
253
|
+
invalidate: { cursor },
|
|
254
|
+
};
|
|
236
255
|
|
|
237
|
-
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
258
|
+
}
|
|
259
|
+
}
|
|
238
260
|
|
|
239
|
-
|
|
240
|
-
orderKey: blockInfo.blockNumber,
|
|
241
|
-
uniqueKey: blockInfo.blockHash,
|
|
242
|
-
};
|
|
261
|
+
const head = chainTracker.head();
|
|
243
262
|
|
|
244
|
-
const
|
|
245
|
-
|
|
263
|
+
const filterData = await config.fetchBlockRange({
|
|
264
|
+
startBlock: cursor.orderKey + 1n,
|
|
265
|
+
maxBlock: head.orderKey,
|
|
266
|
+
force: false,
|
|
267
|
+
filter,
|
|
246
268
|
});
|
|
247
269
|
|
|
248
|
-
if (
|
|
249
|
-
|
|
270
|
+
if (filterData.data.length === 0 && head.uniqueKey !== undefined) {
|
|
271
|
+
// Send an empty block if we reached the head, but don't update the cursor.
|
|
272
|
+
if (
|
|
273
|
+
state.lastEmptyBlockNumber === undefined ||
|
|
274
|
+
head.orderKey > state.lastEmptyBlockNumber
|
|
275
|
+
) {
|
|
276
|
+
const { data } = await config.fetchBlockByHash({
|
|
277
|
+
blockHash: head.uniqueKey,
|
|
278
|
+
isAtHead: true,
|
|
279
|
+
filter,
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
yield {
|
|
283
|
+
_tag: "data",
|
|
284
|
+
data: {
|
|
285
|
+
cursor: data.cursor,
|
|
286
|
+
endCursor: data.endCursor,
|
|
287
|
+
data: [data.block],
|
|
288
|
+
finality: "accepted",
|
|
289
|
+
production: "live",
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
|
|
293
|
+
state.lastEmptyBlockNumber = head.orderKey;
|
|
294
|
+
}
|
|
250
295
|
}
|
|
251
296
|
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
297
|
+
for (const { cursor, endCursor, block } of filterData.data) {
|
|
298
|
+
if (!chainTracker.isCanonical(endCursor)) {
|
|
299
|
+
throw new Error("Trying to process non-canonical block");
|
|
300
|
+
}
|
|
255
301
|
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
302
|
+
if (block !== null) {
|
|
303
|
+
state.lastHeartbeat = Date.now();
|
|
304
|
+
const production = isAtHead(state) ? "live" : "backfill";
|
|
305
|
+
|
|
306
|
+
yield {
|
|
307
|
+
_tag: "data",
|
|
308
|
+
data: {
|
|
309
|
+
cursor,
|
|
310
|
+
endCursor,
|
|
311
|
+
data: [block],
|
|
312
|
+
finality: "accepted",
|
|
313
|
+
production,
|
|
314
|
+
},
|
|
315
|
+
};
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
state.cursor = {
|
|
319
|
+
orderKey: endCursor.orderKey,
|
|
320
|
+
uniqueKey: endCursor.uniqueKey,
|
|
265
321
|
};
|
|
266
322
|
}
|
|
267
323
|
}
|
|
@@ -291,6 +347,7 @@ async function* waitForHeadChange<TBlock>(
|
|
|
291
347
|
const result = await chainTracker.updateHead({
|
|
292
348
|
newHead: maybeNewHead,
|
|
293
349
|
fetchCursorByHash: (blockHash) => config.fetchCursor({ blockHash }),
|
|
350
|
+
fetchCursorRange: (args) => config.fetchCursorRange(args),
|
|
294
351
|
});
|
|
295
352
|
|
|
296
353
|
switch (result.status) {
|
|
@@ -356,6 +413,12 @@ function shouldRefreshFinalized(state: State<unknown, unknown>): boolean {
|
|
|
356
413
|
return now - lastFinalizedRefresh >= config.finalizedRefreshIntervalMs();
|
|
357
414
|
}
|
|
358
415
|
|
|
416
|
+
function shouldRefreshHead(state: State<unknown, unknown>): boolean {
|
|
417
|
+
const { lastHeadRefresh, config } = state;
|
|
418
|
+
const now = Date.now();
|
|
419
|
+
return now - lastHeadRefresh >= config.headRefreshIntervalMs();
|
|
420
|
+
}
|
|
421
|
+
|
|
359
422
|
function isAtHead(state: State<unknown, unknown>): boolean {
|
|
360
423
|
const head = state.chainTracker.head();
|
|
361
424
|
return state.cursor.orderKey === head.orderKey;
|
package/src/rpc/index.ts
CHANGED
|
@@ -3,10 +3,11 @@ export {
|
|
|
3
3
|
type FetchBlockRangeArgs,
|
|
4
4
|
type FetchBlockResult,
|
|
5
5
|
type FetchBlockRangeResult,
|
|
6
|
-
type
|
|
7
|
-
type
|
|
6
|
+
type FetchBlockByHashArgs,
|
|
7
|
+
type FetchBlockByHashResult,
|
|
8
8
|
type ValidateFilterResult,
|
|
9
9
|
type FetchCursorArgs,
|
|
10
|
+
type FetchCursorRangeArgs,
|
|
10
11
|
RpcStreamConfig,
|
|
11
12
|
} from "./config";
|
|
12
13
|
export { RpcClient, createRpcClient } from "./client";
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.54f17699.cjs","sources":["../../src/rpc/config.ts","../../src/rpc/helpers.ts","../../src/rpc/chain-tracker.ts","../../src/rpc/data-stream.ts","../../src/rpc/client.ts"],"sourcesContent":["import type { Bytes, Cursor } from \"../common\";\n\nexport type FetchBlockRangeArgs<TFilter> = {\n startBlock: bigint;\n finalizedBlock: bigint;\n force: boolean;\n filter: TFilter;\n};\n\nexport type FetchBlockRangeResult<TBlock> = {\n startBlock: bigint;\n endBlock: bigint;\n data: FetchBlockResult<TBlock>[];\n};\n\nexport type FetchBlockResult<TBlock> = {\n block: TBlock | null;\n cursor: Cursor | undefined;\n endCursor: Cursor;\n};\n\nexport type BlockInfo = {\n blockNumber: bigint;\n blockHash: Bytes;\n parentBlockHash: Bytes;\n};\n\nexport type FetchBlockByNumberArgs<TFilter> = {\n blockNumber: bigint;\n expectedParentBlockHash: Bytes;\n isAtHead: boolean;\n filter: TFilter;\n};\n\nexport type FetchBlockByNumberResult<TBlock> =\n | {\n status: \"success\";\n data: FetchBlockResult<TBlock>;\n blockInfo: BlockInfo;\n }\n | {\n status: \"reorg\";\n blockInfo: BlockInfo;\n };\n\nexport type FetchCursorArgs =\n | {\n blockTag: \"latest\" | \"finalized\";\n blockNumber?: undefined;\n blockHash?: undefined;\n }\n | {\n blockTag?: undefined;\n blockNumber: bigint;\n blockHash?: undefined;\n }\n | {\n blockTag?: undefined;\n blockNumber?: undefined;\n blockHash: Bytes;\n };\n\nexport type ValidateFilterResult =\n | {\n valid: true;\n error?: undefined;\n }\n | {\n valid: false;\n error: string;\n };\n\nexport abstract class RpcStreamConfig<TFilter, TBlock> {\n abstract headRefreshIntervalMs(): number;\n abstract finalizedRefreshIntervalMs(): number;\n\n abstract fetchCursor(args: FetchCursorArgs): Promise<BlockInfo | null>;\n\n abstract validateFilter(filter: TFilter): ValidateFilterResult;\n\n abstract fetchBlockRange(\n args: FetchBlockRangeArgs<TFilter>,\n ): Promise<FetchBlockRangeResult<TBlock>>;\n\n abstract fetchBlockByNumber(\n args: FetchBlockByNumberArgs<TFilter>,\n ): Promise<FetchBlockByNumberResult<TBlock>>;\n}\n","import type { Cursor } from \"../common\";\nimport type { BlockInfo } from \"./config\";\n\nexport function blockInfoToCursor(blockInfo: BlockInfo): Cursor {\n return {\n orderKey: blockInfo.blockNumber,\n uniqueKey: blockInfo.blockHash,\n };\n}\n","import { fromHex } from \"viem\";\nimport type { Bytes, Cursor } from \"../common\";\nimport type { BlockInfo } from \"./config\";\nimport { blockInfoToCursor } from \"./helpers\";\n\ntype UpdateHeadArgs = {\n newHead: BlockInfo;\n fetchCursorByHash: (hash: Bytes) => Promise<BlockInfo | null>;\n};\n\ntype UpdateHeadResult =\n | {\n status: \"unchanged\";\n }\n | {\n status: \"success\";\n }\n | {\n status: \"reorg\";\n cursor: Cursor;\n };\n\nexport class ChainTracker {\n #finalized: BlockInfo;\n #head: BlockInfo;\n #canonical: Map<bigint, BlockInfo>;\n\n constructor({ head, finalized }: { finalized: BlockInfo; head: BlockInfo }) {\n this.#finalized = finalized;\n this.#head = head;\n this.#canonical = new Map([\n [finalized.blockNumber, finalized],\n [head.blockNumber, head],\n ]);\n }\n\n head(): Cursor {\n return blockInfoToCursor(this.#head);\n }\n\n finalized(): Cursor {\n return blockInfoToCursor(this.#finalized);\n }\n\n updateFinalized(newFinalized: BlockInfo) {\n // console.debug(\n // `updateFinalized: new=${newFinalized.blockNumber} old=${this.#finalized.blockNumber}`,\n // );\n\n if (newFinalized.blockNumber < this.#finalized.blockNumber) {\n throw new Error(\"Finalized cursor moved backwards\");\n }\n\n if (newFinalized.blockNumber === this.#finalized.blockNumber) {\n if (newFinalized.blockHash !== this.#finalized.blockHash) {\n throw new Error(\"Received a different finalized cursor\");\n }\n\n return false;\n }\n\n // Delete all blocks that are now finalized.\n for (\n let bn = this.#finalized.blockNumber;\n bn < newFinalized.blockNumber;\n bn++\n ) {\n this.#canonical.delete(bn);\n }\n\n this.#canonical.set(newFinalized.blockNumber, newFinalized);\n this.#finalized = newFinalized;\n\n return true;\n }\n\n addToCanonicalChain({ blockInfo }: { blockInfo: BlockInfo }) {\n // console.debug(`addToCanonicalChain: block=${blockInfo.blockNumber}`);\n\n const existing = this.#canonical.get(blockInfo.blockNumber);\n\n if (existing) {\n if (existing.blockHash !== blockInfo.blockHash) {\n throw new Error(\n `Block already exists in canonical chain: previous ${existing.blockHash}, new ${blockInfo.blockHash}`,\n );\n }\n }\n\n const parent = this.#canonical.get(blockInfo.blockNumber - 1n);\n if (!parent) {\n throw new Error(\"Parent block not in canonical chain\");\n }\n\n if (parent.blockHash !== blockInfo.parentBlockHash) {\n throw new Error(\"Parent block hash mismatch.\");\n }\n\n this.#canonical.set(blockInfo.blockNumber, blockInfo);\n\n // console.log(\"Canon updated: \", canonical);\n\n return { status: \"success\" };\n }\n\n async updateHead({\n newHead,\n fetchCursorByHash,\n }: UpdateHeadArgs): Promise<UpdateHeadResult> {\n // console.debug(\n // `updateHead: new=${newHead.blockNumber} old=${this.#head.blockNumber}`,\n // );\n\n // No changes to the chain.\n if (\n newHead.blockNumber === this.#head.blockNumber &&\n newHead.blockHash === this.#head.blockHash\n ) {\n return { status: \"unchanged\" };\n }\n\n // Most common case: the new head is the block after the current head.\n if (\n newHead.blockNumber === this.#head.blockNumber + 1n &&\n newHead.parentBlockHash === this.#head.blockHash\n ) {\n this.#canonical.set(newHead.blockNumber, newHead);\n this.#head = newHead;\n return { status: \"success\" };\n }\n\n // The new chain is not longer.\n if (newHead.blockNumber <= this.#head.blockNumber) {\n // console.log(\"head=\", this.#head, \"newhead=\", newHead);\n let currentNewHead = newHead;\n // Delete all blocks from canonical chain after the new head.\n for (\n let bn = newHead.blockNumber + 1n;\n bn <= this.#head.blockNumber;\n bn++\n ) {\n this.#canonical.delete(bn);\n }\n\n // Check if the chain was simply shrunk to this block.\n const existing = this.#canonical.get(currentNewHead.blockNumber);\n if (existing && existing.blockHash === currentNewHead.blockHash) {\n this.#head = existing;\n return {\n status: \"reorg\",\n cursor: blockInfoToCursor(existing),\n };\n }\n\n while (currentNewHead.blockNumber > this.#finalized.blockNumber) {\n this.#canonical.delete(currentNewHead.blockNumber);\n\n const canonicalParent = this.#canonical.get(\n currentNewHead.blockNumber - 1n,\n );\n\n if (!canonicalParent) {\n throw new Error(\n \"Cannot reconcile new head with canonical chain: missing parent in canonical chain\",\n );\n }\n\n // We found the common ancestor.\n if (canonicalParent.blockHash === currentNewHead.parentBlockHash) {\n this.#head = canonicalParent;\n return {\n status: \"reorg\",\n cursor: blockInfoToCursor(canonicalParent),\n };\n }\n\n const parent = await fetchCursorByHash(currentNewHead.parentBlockHash);\n\n if (!parent) {\n throw new Error(\n \"Cannot reconcile new head with canonical chain: failed to fetch parent\",\n );\n }\n\n currentNewHead = parent;\n }\n\n throw new Error(\"Cannot reconcile new head with canonical chain.\");\n }\n\n // In all other cases we need to \"join\" the new head with the existing chain.\n // The new chain is longer and we need the missing blocks.\n // This may result in reorgs.\n\n let current = newHead;\n let reorgDetected = false;\n const blocksToApply = [newHead];\n\n while (true) {\n const parent = await fetchCursorByHash(current.parentBlockHash);\n\n if (!parent) {\n throw new Error(\n \"Cannot reconcile new head with canonical chain: failed to fetch parent\",\n );\n }\n\n if (parent.blockNumber === this.#head.blockNumber) {\n if (parent.blockHash === this.#head.blockHash) {\n break;\n }\n\n const headParent = this.#canonical.get(this.#head.blockNumber - 1n);\n if (!headParent) {\n throw new Error(\n \"Cannot reconcile new head with canonical chain: missing parent in canonical chain\",\n );\n }\n\n // Update current head.\n this.#canonical.delete(this.#head.blockNumber);\n this.#head = headParent;\n reorgDetected = true;\n }\n\n blocksToApply.push(parent);\n current = parent;\n }\n\n for (const block of blocksToApply.reverse()) {\n this.#canonical.set(block.blockNumber, block);\n }\n\n const previousHead = this.#head;\n this.#head = newHead;\n\n if (reorgDetected) {\n return {\n status: \"reorg\",\n cursor: blockInfoToCursor(previousHead),\n };\n }\n\n return { status: \"success\" };\n }\n\n async initializeStartingCursor({\n cursor,\n fetchCursor,\n }: {\n cursor: Cursor;\n fetchCursor: (blockNumber: bigint) => Promise<BlockInfo | null>;\n }): Promise<\n | { canonical: true; reason?: undefined; fullCursor: Cursor }\n | { canonical: false; reason: string; fullCursor?: undefined }\n > {\n const head = this.head();\n const finalized = this.finalized();\n\n if (cursor.orderKey > head.orderKey) {\n return { canonical: false, reason: \"cursor is ahead of head\" };\n }\n\n const expectedInfo = await fetchCursor(cursor.orderKey);\n if (!cursor.uniqueKey) {\n if (expectedInfo === null) {\n throw new Error(\"Failed to initialize canonical cursor\");\n }\n\n if (expectedInfo.blockNumber > finalized.orderKey) {\n this.#canonical.set(expectedInfo.blockNumber, expectedInfo);\n }\n\n return { canonical: true, fullCursor: blockInfoToCursor(expectedInfo) };\n }\n\n if (expectedInfo === null) {\n return {\n canonical: false,\n reason: \"expected block does not exist\",\n };\n }\n\n const expectedCursor = blockInfoToCursor(expectedInfo);\n\n // These two checks are redundant, but they are kept to avoid issues with bad config implementations.\n if (!expectedCursor.uniqueKey) {\n return {\n canonical: false,\n reason: \"expected cursor has no unique key (hash)\",\n };\n }\n\n if (expectedCursor.orderKey !== cursor.orderKey) {\n return {\n canonical: false,\n reason: \"cursor order key does not match expected order key\",\n };\n }\n\n if (\n fromHex(expectedCursor.uniqueKey, \"bigint\") !==\n fromHex(cursor.uniqueKey, \"bigint\")\n ) {\n return {\n canonical: false,\n reason: `cursor hash does not match expected hash: ${cursor.uniqueKey} !== ${expectedCursor.uniqueKey}`,\n };\n }\n\n if (expectedInfo.blockNumber > finalized.orderKey) {\n this.#canonical.set(expectedInfo.blockNumber, expectedInfo);\n }\n\n return { canonical: true, fullCursor: expectedCursor };\n }\n}\n\nexport function createChainTracker({\n head,\n finalized,\n}: {\n head: BlockInfo;\n finalized: BlockInfo;\n}): ChainTracker {\n return new ChainTracker({ finalized, head });\n}\n","import type { StreamDataOptions } from \"../client\";\nimport type { Cursor } from \"../common\";\nimport type { StreamDataRequest, StreamDataResponse } from \"../stream\";\nimport { type ChainTracker, createChainTracker } from \"./chain-tracker\";\nimport type { RpcStreamConfig } from \"./config\";\nimport { blockInfoToCursor } from \"./helpers\";\n\nconst DEFAULT_HEARTBEAT_INTERVAL_MS = 30_000;\n\ntype State<TFilter, TBlock> = {\n // The network-specific config.\n config: RpcStreamConfig<TFilter, TBlock>;\n // The current cursor, that is the last block that was filtered.\n cursor: Cursor;\n // When the finalized block was last refreshed.\n lastFinalizedRefresh: number;\n // When the last heartbeat was sent.\n lastHeartbeat: number;\n // When the last backfill message was sent.\n lastBackfillMessage: number;\n // Track the chain's state.\n chainTracker: ChainTracker;\n // Heartbeat interval in milliseconds.\n heartbeatIntervalMs: number;\n // The request filter.\n filter: TFilter;\n // The request options.\n options?: StreamDataOptions;\n};\n\nexport class RpcDataStream<TFilter, TBlock> {\n private heartbeatIntervalMs: number;\n\n constructor(\n private config: RpcStreamConfig<TFilter, TBlock>,\n private request: StreamDataRequest<TFilter>,\n private options?: StreamDataOptions,\n ) {\n this.heartbeatIntervalMs = request.heartbeatInterval\n ? Number(request.heartbeatInterval.seconds) * 1000\n : DEFAULT_HEARTBEAT_INTERVAL_MS;\n }\n\n async *[Symbol.asyncIterator](): AsyncIterator<StreamDataResponse<TBlock>> {\n const startingState = await this.initialize();\n yield* dataStreamLoop(startingState);\n }\n\n private async initialize(): Promise<State<TFilter, TBlock>> {\n if (this.request.filter.length === 0) {\n throw new Error(\"Request.filter: empty.\");\n }\n\n if (this.request.filter.length > 1) {\n throw new Error(\"Request.filter: only one filter is supported.\");\n }\n\n const [head, finalized] = await Promise.all([\n this.config.fetchCursor({ blockTag: \"latest\" }),\n this.config.fetchCursor({ blockTag: \"finalized\" }),\n ]);\n\n if (finalized === null) {\n throw new Error(\"EvmRpcStream requires a finalized block\");\n }\n\n if (head === null) {\n throw new Error(\"EvmRpcStream requires a chain with blocks.\");\n }\n\n const chainTracker = createChainTracker({\n head,\n finalized,\n });\n\n let cursor: Cursor;\n if (this.request.startingCursor) {\n cursor = this.request.startingCursor;\n\n const { canonical, reason, fullCursor } =\n await chainTracker.initializeStartingCursor({\n cursor,\n fetchCursor: (blockNumber) =>\n this.config.fetchCursor({ blockNumber }),\n });\n\n if (!canonical) {\n throw new Error(`Starting cursor is not canonical: ${reason}`);\n }\n\n cursor = fullCursor;\n } else {\n cursor = { orderKey: -1n };\n }\n\n return {\n cursor,\n lastHeartbeat: Date.now(),\n lastFinalizedRefresh: Date.now(),\n lastBackfillMessage: Date.now(),\n chainTracker,\n config: this.config,\n heartbeatIntervalMs: this.heartbeatIntervalMs,\n filter: this.request.filter[0],\n options: this.options,\n };\n }\n}\n\nasync function* dataStreamLoop<TFilter, TBlock>(\n state: State<TFilter, TBlock>,\n): AsyncGenerator<StreamDataResponse<TBlock>> {\n while (shouldContinue(state)) {\n const { cursor, chainTracker } = state;\n\n // Always check for heartbeats first to ensure we don't miss any.\n if (shouldSendHeartbeat(state)) {\n state.lastHeartbeat = Date.now();\n yield { _tag: \"heartbeat\" };\n }\n\n if (shouldRefreshFinalized(state)) {\n const finalizedInfo = await state.config.fetchCursor({\n blockTag: \"finalized\",\n });\n\n if (finalizedInfo === null) {\n throw new Error(\"Failed to fetch finalized cursor\");\n }\n\n const finalized = blockInfoToCursor(finalizedInfo);\n const finalizedChanged =\n state.chainTracker.updateFinalized(finalizedInfo);\n\n // Only send finalized if it's needed.\n if (finalizedChanged && state.cursor.orderKey > finalized.orderKey) {\n yield { _tag: \"finalize\", finalize: { cursor: finalized } };\n }\n\n state.lastFinalizedRefresh = Date.now();\n }\n\n const finalized = chainTracker.finalized();\n\n // console.debug(\n // `RpcLoop: c=${cursor.orderKey} f=${finalized.orderKey} h=${chainTracker.head().orderKey}`,\n // );\n\n if (cursor.orderKey < finalized.orderKey) {\n yield* backfillFinalizedBlocks(state);\n } else {\n // If we're at the head, wait for a change.\n //\n // We don't want to produce a block immediately, but re-run the loop so\n // that it's like any other iteration.\n if (isAtHead(state)) {\n yield* waitForHeadChange(state);\n } else {\n yield* produceNextBlock(state);\n }\n }\n }\n}\n\nasync function* backfillFinalizedBlocks<TFilter, TBlock>(\n state: State<TFilter, TBlock>,\n): AsyncGenerator<StreamDataResponse<TBlock>> {\n const { cursor, chainTracker, config, filter } = state;\n const finalized = chainTracker.finalized();\n\n // While backfilling we want to regularly send some blocks (even if empty) so\n // that the client can store the cursor.\n const force = shouldForceBackfill(state);\n\n const filterData = await config.fetchBlockRange({\n startBlock: cursor.orderKey + 1n,\n finalizedBlock: finalized.orderKey,\n force,\n filter,\n });\n\n if (filterData.endBlock > finalized.orderKey) {\n throw new Error(\n \"Network-specific stream returned invalid data, crossing the finalized block.\",\n );\n }\n\n for (const data of filterData.data) {\n state.lastHeartbeat = Date.now();\n state.lastBackfillMessage = Date.now();\n yield {\n _tag: \"data\",\n data: {\n cursor: data.cursor,\n endCursor: data.endCursor,\n data: [data.block],\n finality: \"finalized\",\n production: \"backfill\",\n },\n };\n }\n\n // Notice that we check that filteredData.endBlock <= finalized.orderKey above.\n if (filterData.endBlock === finalized.orderKey) {\n // Prepare for transition to non-finalized data.\n state.cursor = finalized;\n } else {\n state.cursor = { orderKey: filterData.endBlock };\n }\n}\n\n// This is a generator to possibly produce data for the next block.\n//\n// It's a generator because it's not guaranteed to produce data for the next block.\nasync function* produceNextBlock<TFilter, TBlock>(\n state: State<TFilter, TBlock>,\n): AsyncGenerator<StreamDataResponse<TBlock>> {\n const currentBlockHash = state.cursor.uniqueKey;\n\n if (currentBlockHash === undefined) {\n throw new Error(\"Live production phase without cursor's hash.\");\n }\n\n const result = await state.config.fetchBlockByNumber({\n blockNumber: state.cursor.orderKey + 1n,\n isAtHead: isAtHead(state),\n expectedParentBlockHash: currentBlockHash,\n filter: state.filter,\n });\n\n // TODO: use the output of result to update the chain tracker.\n\n if (result.status === \"reorg\") {\n throw new Error(\"Reorg not implemented\");\n }\n\n const { data, blockInfo } = result;\n\n state.cursor = {\n orderKey: blockInfo.blockNumber,\n uniqueKey: blockInfo.blockHash,\n };\n\n const { status: headUpdateStatus } = state.chainTracker.addToCanonicalChain({\n blockInfo,\n });\n\n if (headUpdateStatus !== \"success\") {\n throw new Error(\"Failed to update head. Would cause reorg.\");\n }\n\n if (data.block !== null) {\n state.lastHeartbeat = Date.now();\n const production = isAtHead(state) ? \"live\" : \"backfill\";\n\n yield {\n _tag: \"data\",\n data: {\n cursor: data.cursor,\n endCursor: data.endCursor,\n data: [data.block],\n finality: \"accepted\",\n production,\n },\n };\n }\n}\n\nasync function* waitForHeadChange<TBlock>(\n state: State<unknown, TBlock>,\n): AsyncGenerator<StreamDataResponse<TBlock>> {\n const { chainTracker, config } = state;\n\n const heartbeatDeadline = state.lastHeartbeat + state.heartbeatIntervalMs;\n const finalizedRefreshDeadline =\n state.lastFinalizedRefresh + config.finalizedRefreshIntervalMs();\n\n while (true) {\n const now = Date.now();\n // Allow the outer loop to send the heartbeat message or refresh finalized blocks.\n if (now >= heartbeatDeadline || now >= finalizedRefreshDeadline) {\n return;\n }\n\n const maybeNewHead = await config.fetchCursor({ blockTag: \"latest\" });\n\n if (maybeNewHead === null) {\n throw new Error(\"Failed to fetch the latest block\");\n }\n\n const result = await chainTracker.updateHead({\n newHead: maybeNewHead,\n fetchCursorByHash: (blockHash) => config.fetchCursor({ blockHash }),\n });\n\n switch (result.status) {\n case \"unchanged\": {\n const heartbeatTimeout = heartbeatDeadline - now;\n const finalizedTimeout = finalizedRefreshDeadline - now;\n\n // Wait until whatever happens next.\n await sleep(\n Math.min(\n heartbeatTimeout,\n finalizedTimeout,\n config.headRefreshIntervalMs(),\n ),\n );\n\n break;\n }\n case \"reorg\": {\n const { cursor } = result;\n // Only handle reorgs if they involve blocks already processed.\n if (cursor.orderKey < state.cursor.orderKey) {\n state.cursor = cursor;\n\n yield {\n _tag: \"invalidate\",\n invalidate: { cursor },\n };\n }\n\n break;\n }\n case \"success\": {\n // Chain grew without any issues. Go back to the top-level loop to produce data.\n return;\n }\n }\n }\n}\n\nfunction shouldSendHeartbeat(state: State<unknown, unknown>): boolean {\n const { heartbeatIntervalMs, lastHeartbeat } = state;\n const now = Date.now();\n return now - lastHeartbeat >= heartbeatIntervalMs;\n}\n\nfunction shouldForceBackfill(state: State<unknown, unknown>): boolean {\n const { lastBackfillMessage, heartbeatIntervalMs } = state;\n const now = Date.now();\n return now - lastBackfillMessage >= heartbeatIntervalMs;\n}\n\nfunction shouldContinue(state: State<unknown, unknown>): boolean {\n const { endingCursor } = state.options || {};\n if (endingCursor === undefined) return true;\n\n return state.cursor.orderKey < endingCursor.orderKey;\n}\n\nfunction shouldRefreshFinalized(state: State<unknown, unknown>): boolean {\n const { lastFinalizedRefresh, config } = state;\n const now = Date.now();\n return now - lastFinalizedRefresh >= config.finalizedRefreshIntervalMs();\n}\n\nfunction isAtHead(state: State<unknown, unknown>): boolean {\n const head = state.chainTracker.head();\n return state.cursor.orderKey === head.orderKey;\n}\n\nfunction sleep(duration: number): Promise<void> {\n return new Promise((resolve) => setTimeout(resolve, duration));\n}\n","import type { Client, ClientCallOptions, StreamDataOptions } from \"../client\";\nimport type { Cursor } from \"../common\";\nimport type { StatusRequest, StatusResponse } from \"../status\";\nimport type { StreamDataRequest, StreamDataResponse } from \"../stream\";\nimport type { RpcStreamConfig } from \"./config\";\nimport { RpcDataStream } from \"./data-stream\";\nimport { blockInfoToCursor } from \"./helpers\";\n\nexport class RpcClient<TFilter, TBlock> implements Client<TFilter, TBlock> {\n constructor(private config: RpcStreamConfig<TFilter, TBlock>) {}\n\n async status(\n _request?: StatusRequest,\n _options?: ClientCallOptions,\n ): Promise<StatusResponse> {\n const [currentHead, finalized] = await Promise.all([\n this.config.fetchCursor({ blockTag: \"latest\" }),\n this.config.fetchCursor({ blockTag: \"finalized\" }),\n ]);\n\n const starting: Cursor = { orderKey: 0n };\n\n return {\n currentHead: currentHead ? blockInfoToCursor(currentHead) : undefined,\n lastIngested: currentHead ? blockInfoToCursor(currentHead) : undefined,\n finalized: finalized ? blockInfoToCursor(finalized) : undefined,\n starting,\n };\n }\n\n streamData(\n request: StreamDataRequest<TFilter>,\n options?: StreamDataOptions,\n ): AsyncIterable<StreamDataResponse<TBlock>> {\n const index = 0;\n for (const filter of request.filter) {\n const { valid, error } = this.config.validateFilter(filter);\n if (!valid) {\n throw new Error(`Filter at position ${index} is invalid: ${error}`);\n }\n }\n\n return new RpcDataStream(this.config, request, options);\n }\n}\n\nexport function createRpcClient<TFilter, TBlock>(\n config: RpcStreamConfig<TFilter, TBlock>,\n): RpcClient<TFilter, TBlock> {\n return new RpcClient(config);\n}\n"],"names":["fromHex","finalized"],"mappings":"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"}
|