@apibara/protocol 2.1.0-beta.46 → 2.1.0-beta.48
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.mjs +1 -1
- package/dist/rpc/index.cjs +1 -1
- package/dist/rpc/index.mjs +1 -1
- package/dist/shared/{protocol.2bd0b754.cjs → protocol.54f17699.cjs} +16 -8
- package/dist/shared/protocol.54f17699.cjs.map +1 -0
- package/dist/shared/{protocol.0a91111c.mjs → protocol.bde61588.mjs} +16 -8
- package/dist/shared/protocol.bde61588.mjs.map +1 -0
- package/package.json +1 -1
- package/src/rpc/chain-tracker.ts +25 -8
- package/src/rpc/data-stream.ts +6 -4
- package/dist/shared/protocol.0a91111c.mjs.map +0 -1
- package/dist/shared/protocol.2bd0b754.cjs.map +0 -1
package/dist/index.cjs
CHANGED
|
@@ -6,7 +6,7 @@ const assert = require('node:assert');
|
|
|
6
6
|
const consola = require('consola');
|
|
7
7
|
const niceGrpc = require('nice-grpc');
|
|
8
8
|
require('protobufjs/minimal.js');
|
|
9
|
-
const rpc_index = require('./shared/protocol.
|
|
9
|
+
const rpc_index = require('./shared/protocol.54f17699.cjs');
|
|
10
10
|
require('viem');
|
|
11
11
|
require('long');
|
|
12
12
|
|
package/dist/index.mjs
CHANGED
|
@@ -6,7 +6,7 @@ import consola from 'consola';
|
|
|
6
6
|
import { createChannel, createClient as createClient$1, Metadata } from 'nice-grpc';
|
|
7
7
|
export { ClientError, Metadata, ServerError, Status } from 'nice-grpc';
|
|
8
8
|
import 'protobufjs/minimal.js';
|
|
9
|
-
export { i as rpc } from './shared/protocol.
|
|
9
|
+
export { i as rpc } from './shared/protocol.bde61588.mjs';
|
|
10
10
|
import 'viem';
|
|
11
11
|
import 'long';
|
|
12
12
|
|
package/dist/rpc/index.cjs
CHANGED
package/dist/rpc/index.mjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
export { a as RpcClient, b as RpcDataStream, R as RpcStreamConfig, c as createRpcClient } from '../shared/protocol.
|
|
1
|
+
export { a as RpcClient, b as RpcDataStream, R as RpcStreamConfig, c as createRpcClient } from '../shared/protocol.bde61588.mjs';
|
|
2
2
|
import 'viem';
|
|
3
3
|
//# sourceMappingURL=index.mjs.map
|
|
@@ -66,7 +66,7 @@ class ChainTracker {
|
|
|
66
66
|
__privateSet(this, _finalized, newFinalized);
|
|
67
67
|
return true;
|
|
68
68
|
}
|
|
69
|
-
addToCanonicalChain(blockInfo) {
|
|
69
|
+
addToCanonicalChain({ blockInfo }) {
|
|
70
70
|
const existing = __privateGet(this, _canonical).get(blockInfo.blockNumber);
|
|
71
71
|
if (existing) {
|
|
72
72
|
if (existing.blockHash !== blockInfo.blockHash) {
|
|
@@ -77,7 +77,7 @@ class ChainTracker {
|
|
|
77
77
|
}
|
|
78
78
|
const parent = __privateGet(this, _canonical).get(blockInfo.blockNumber - 1n);
|
|
79
79
|
if (!parent) {
|
|
80
|
-
throw new Error("Parent block not
|
|
80
|
+
throw new Error("Parent block not in canonical chain");
|
|
81
81
|
}
|
|
82
82
|
if (parent.blockHash !== blockInfo.parentBlockHash) {
|
|
83
83
|
throw new Error("Parent block hash mismatch.");
|
|
@@ -182,17 +182,20 @@ class ChainTracker {
|
|
|
182
182
|
fetchCursor
|
|
183
183
|
}) {
|
|
184
184
|
const head = this.head();
|
|
185
|
+
const finalized = this.finalized();
|
|
185
186
|
if (cursor.orderKey > head.orderKey) {
|
|
186
187
|
return { canonical: false, reason: "cursor is ahead of head" };
|
|
187
188
|
}
|
|
189
|
+
const expectedInfo = await fetchCursor(cursor.orderKey);
|
|
188
190
|
if (!cursor.uniqueKey) {
|
|
189
|
-
|
|
190
|
-
if (fullInfo === null) {
|
|
191
|
+
if (expectedInfo === null) {
|
|
191
192
|
throw new Error("Failed to initialize canonical cursor");
|
|
192
193
|
}
|
|
193
|
-
|
|
194
|
+
if (expectedInfo.blockNumber > finalized.orderKey) {
|
|
195
|
+
__privateGet(this, _canonical).set(expectedInfo.blockNumber, expectedInfo);
|
|
196
|
+
}
|
|
197
|
+
return { canonical: true, fullCursor: blockInfoToCursor(expectedInfo) };
|
|
194
198
|
}
|
|
195
|
-
const expectedInfo = await fetchCursor(cursor.orderKey);
|
|
196
199
|
if (expectedInfo === null) {
|
|
197
200
|
return {
|
|
198
201
|
canonical: false,
|
|
@@ -218,6 +221,9 @@ class ChainTracker {
|
|
|
218
221
|
reason: `cursor hash does not match expected hash: ${cursor.uniqueKey} !== ${expectedCursor.uniqueKey}`
|
|
219
222
|
};
|
|
220
223
|
}
|
|
224
|
+
if (expectedInfo.blockNumber > finalized.orderKey) {
|
|
225
|
+
__privateGet(this, _canonical).set(expectedInfo.blockNumber, expectedInfo);
|
|
226
|
+
}
|
|
221
227
|
return { canonical: true, fullCursor: expectedCursor };
|
|
222
228
|
}
|
|
223
229
|
}
|
|
@@ -385,7 +391,9 @@ async function* produceNextBlock(state) {
|
|
|
385
391
|
orderKey: blockInfo.blockNumber,
|
|
386
392
|
uniqueKey: blockInfo.blockHash
|
|
387
393
|
};
|
|
388
|
-
const { status: headUpdateStatus } = state.chainTracker.addToCanonicalChain(
|
|
394
|
+
const { status: headUpdateStatus } = state.chainTracker.addToCanonicalChain({
|
|
395
|
+
blockInfo
|
|
396
|
+
});
|
|
389
397
|
if (headUpdateStatus !== "success") {
|
|
390
398
|
throw new Error("Failed to update head. Would cause reorg.");
|
|
391
399
|
}
|
|
@@ -525,4 +533,4 @@ exports.RpcDataStream = RpcDataStream;
|
|
|
525
533
|
exports.RpcStreamConfig = RpcStreamConfig;
|
|
526
534
|
exports.createRpcClient = createRpcClient;
|
|
527
535
|
exports.index = index;
|
|
528
|
-
//# sourceMappingURL=protocol.
|
|
536
|
+
//# sourceMappingURL=protocol.54f17699.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
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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"}
|
|
@@ -64,7 +64,7 @@ class ChainTracker {
|
|
|
64
64
|
__privateSet(this, _finalized, newFinalized);
|
|
65
65
|
return true;
|
|
66
66
|
}
|
|
67
|
-
addToCanonicalChain(blockInfo) {
|
|
67
|
+
addToCanonicalChain({ blockInfo }) {
|
|
68
68
|
const existing = __privateGet(this, _canonical).get(blockInfo.blockNumber);
|
|
69
69
|
if (existing) {
|
|
70
70
|
if (existing.blockHash !== blockInfo.blockHash) {
|
|
@@ -75,7 +75,7 @@ class ChainTracker {
|
|
|
75
75
|
}
|
|
76
76
|
const parent = __privateGet(this, _canonical).get(blockInfo.blockNumber - 1n);
|
|
77
77
|
if (!parent) {
|
|
78
|
-
throw new Error("Parent block not
|
|
78
|
+
throw new Error("Parent block not in canonical chain");
|
|
79
79
|
}
|
|
80
80
|
if (parent.blockHash !== blockInfo.parentBlockHash) {
|
|
81
81
|
throw new Error("Parent block hash mismatch.");
|
|
@@ -180,17 +180,20 @@ class ChainTracker {
|
|
|
180
180
|
fetchCursor
|
|
181
181
|
}) {
|
|
182
182
|
const head = this.head();
|
|
183
|
+
const finalized = this.finalized();
|
|
183
184
|
if (cursor.orderKey > head.orderKey) {
|
|
184
185
|
return { canonical: false, reason: "cursor is ahead of head" };
|
|
185
186
|
}
|
|
187
|
+
const expectedInfo = await fetchCursor(cursor.orderKey);
|
|
186
188
|
if (!cursor.uniqueKey) {
|
|
187
|
-
|
|
188
|
-
if (fullInfo === null) {
|
|
189
|
+
if (expectedInfo === null) {
|
|
189
190
|
throw new Error("Failed to initialize canonical cursor");
|
|
190
191
|
}
|
|
191
|
-
|
|
192
|
+
if (expectedInfo.blockNumber > finalized.orderKey) {
|
|
193
|
+
__privateGet(this, _canonical).set(expectedInfo.blockNumber, expectedInfo);
|
|
194
|
+
}
|
|
195
|
+
return { canonical: true, fullCursor: blockInfoToCursor(expectedInfo) };
|
|
192
196
|
}
|
|
193
|
-
const expectedInfo = await fetchCursor(cursor.orderKey);
|
|
194
197
|
if (expectedInfo === null) {
|
|
195
198
|
return {
|
|
196
199
|
canonical: false,
|
|
@@ -216,6 +219,9 @@ class ChainTracker {
|
|
|
216
219
|
reason: `cursor hash does not match expected hash: ${cursor.uniqueKey} !== ${expectedCursor.uniqueKey}`
|
|
217
220
|
};
|
|
218
221
|
}
|
|
222
|
+
if (expectedInfo.blockNumber > finalized.orderKey) {
|
|
223
|
+
__privateGet(this, _canonical).set(expectedInfo.blockNumber, expectedInfo);
|
|
224
|
+
}
|
|
219
225
|
return { canonical: true, fullCursor: expectedCursor };
|
|
220
226
|
}
|
|
221
227
|
}
|
|
@@ -383,7 +389,9 @@ async function* produceNextBlock(state) {
|
|
|
383
389
|
orderKey: blockInfo.blockNumber,
|
|
384
390
|
uniqueKey: blockInfo.blockHash
|
|
385
391
|
};
|
|
386
|
-
const { status: headUpdateStatus } = state.chainTracker.addToCanonicalChain(
|
|
392
|
+
const { status: headUpdateStatus } = state.chainTracker.addToCanonicalChain({
|
|
393
|
+
blockInfo
|
|
394
|
+
});
|
|
387
395
|
if (headUpdateStatus !== "success") {
|
|
388
396
|
throw new Error("Failed to update head. Would cause reorg.");
|
|
389
397
|
}
|
|
@@ -519,4 +527,4 @@ const index = {
|
|
|
519
527
|
};
|
|
520
528
|
|
|
521
529
|
export { RpcStreamConfig as R, RpcClient as a, RpcDataStream as b, createRpcClient as c, index as i };
|
|
522
|
-
//# sourceMappingURL=protocol.
|
|
530
|
+
//# sourceMappingURL=protocol.bde61588.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"protocol.bde61588.mjs","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":["finalized"],"mappings":"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"}
|
package/package.json
CHANGED
package/src/rpc/chain-tracker.ts
CHANGED
|
@@ -43,6 +43,10 @@ export class ChainTracker {
|
|
|
43
43
|
}
|
|
44
44
|
|
|
45
45
|
updateFinalized(newFinalized: BlockInfo) {
|
|
46
|
+
// console.debug(
|
|
47
|
+
// `updateFinalized: new=${newFinalized.blockNumber} old=${this.#finalized.blockNumber}`,
|
|
48
|
+
// );
|
|
49
|
+
|
|
46
50
|
if (newFinalized.blockNumber < this.#finalized.blockNumber) {
|
|
47
51
|
throw new Error("Finalized cursor moved backwards");
|
|
48
52
|
}
|
|
@@ -70,7 +74,9 @@ export class ChainTracker {
|
|
|
70
74
|
return true;
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
addToCanonicalChain(blockInfo: BlockInfo) {
|
|
77
|
+
addToCanonicalChain({ blockInfo }: { blockInfo: BlockInfo }) {
|
|
78
|
+
// console.debug(`addToCanonicalChain: block=${blockInfo.blockNumber}`);
|
|
79
|
+
|
|
74
80
|
const existing = this.#canonical.get(blockInfo.blockNumber);
|
|
75
81
|
|
|
76
82
|
if (existing) {
|
|
@@ -83,7 +89,7 @@ export class ChainTracker {
|
|
|
83
89
|
|
|
84
90
|
const parent = this.#canonical.get(blockInfo.blockNumber - 1n);
|
|
85
91
|
if (!parent) {
|
|
86
|
-
throw new Error("Parent block not
|
|
92
|
+
throw new Error("Parent block not in canonical chain");
|
|
87
93
|
}
|
|
88
94
|
|
|
89
95
|
if (parent.blockHash !== blockInfo.parentBlockHash) {
|
|
@@ -101,6 +107,10 @@ export class ChainTracker {
|
|
|
101
107
|
newHead,
|
|
102
108
|
fetchCursorByHash,
|
|
103
109
|
}: UpdateHeadArgs): Promise<UpdateHeadResult> {
|
|
110
|
+
// console.debug(
|
|
111
|
+
// `updateHead: new=${newHead.blockNumber} old=${this.#head.blockNumber}`,
|
|
112
|
+
// );
|
|
113
|
+
|
|
104
114
|
// No changes to the chain.
|
|
105
115
|
if (
|
|
106
116
|
newHead.blockNumber === this.#head.blockNumber &&
|
|
@@ -245,21 +255,24 @@ export class ChainTracker {
|
|
|
245
255
|
| { canonical: false; reason: string; fullCursor?: undefined }
|
|
246
256
|
> {
|
|
247
257
|
const head = this.head();
|
|
258
|
+
const finalized = this.finalized();
|
|
259
|
+
|
|
248
260
|
if (cursor.orderKey > head.orderKey) {
|
|
249
261
|
return { canonical: false, reason: "cursor is ahead of head" };
|
|
250
262
|
}
|
|
251
263
|
|
|
264
|
+
const expectedInfo = await fetchCursor(cursor.orderKey);
|
|
252
265
|
if (!cursor.uniqueKey) {
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
if (fullInfo === null) {
|
|
266
|
+
if (expectedInfo === null) {
|
|
256
267
|
throw new Error("Failed to initialize canonical cursor");
|
|
257
268
|
}
|
|
258
269
|
|
|
259
|
-
|
|
260
|
-
|
|
270
|
+
if (expectedInfo.blockNumber > finalized.orderKey) {
|
|
271
|
+
this.#canonical.set(expectedInfo.blockNumber, expectedInfo);
|
|
272
|
+
}
|
|
261
273
|
|
|
262
|
-
|
|
274
|
+
return { canonical: true, fullCursor: blockInfoToCursor(expectedInfo) };
|
|
275
|
+
}
|
|
263
276
|
|
|
264
277
|
if (expectedInfo === null) {
|
|
265
278
|
return {
|
|
@@ -295,6 +308,10 @@ export class ChainTracker {
|
|
|
295
308
|
};
|
|
296
309
|
}
|
|
297
310
|
|
|
311
|
+
if (expectedInfo.blockNumber > finalized.orderKey) {
|
|
312
|
+
this.#canonical.set(expectedInfo.blockNumber, expectedInfo);
|
|
313
|
+
}
|
|
314
|
+
|
|
298
315
|
return { canonical: true, fullCursor: expectedCursor };
|
|
299
316
|
}
|
|
300
317
|
}
|
package/src/rpc/data-stream.ts
CHANGED
|
@@ -142,8 +142,8 @@ async function* dataStreamLoop<TFilter, TBlock>(
|
|
|
142
142
|
|
|
143
143
|
const finalized = chainTracker.finalized();
|
|
144
144
|
|
|
145
|
-
// console.
|
|
146
|
-
// `
|
|
145
|
+
// console.debug(
|
|
146
|
+
// `RpcLoop: c=${cursor.orderKey} f=${finalized.orderKey} h=${chainTracker.head().orderKey}`,
|
|
147
147
|
// );
|
|
148
148
|
|
|
149
149
|
if (cursor.orderKey < finalized.orderKey) {
|
|
@@ -200,6 +200,7 @@ async function* backfillFinalizedBlocks<TFilter, TBlock>(
|
|
|
200
200
|
};
|
|
201
201
|
}
|
|
202
202
|
|
|
203
|
+
// Notice that we check that filteredData.endBlock <= finalized.orderKey above.
|
|
203
204
|
if (filterData.endBlock === finalized.orderKey) {
|
|
204
205
|
// Prepare for transition to non-finalized data.
|
|
205
206
|
state.cursor = finalized;
|
|
@@ -240,8 +241,9 @@ async function* produceNextBlock<TFilter, TBlock>(
|
|
|
240
241
|
uniqueKey: blockInfo.blockHash,
|
|
241
242
|
};
|
|
242
243
|
|
|
243
|
-
const { status: headUpdateStatus } =
|
|
244
|
-
|
|
244
|
+
const { status: headUpdateStatus } = state.chainTracker.addToCanonicalChain({
|
|
245
|
+
blockInfo,
|
|
246
|
+
});
|
|
245
247
|
|
|
246
248
|
if (headUpdateStatus !== "success") {
|
|
247
249
|
throw new Error("Failed to update head. Would cause reorg.");
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.0a91111c.mjs","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 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) {\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 found\");\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 // 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 if (cursor.orderKey > head.orderKey) {\n return { canonical: false, reason: \"cursor is ahead of head\" };\n }\n\n if (!cursor.uniqueKey) {\n const fullInfo = await fetchCursor(cursor.orderKey);\n\n if (fullInfo === null) {\n throw new Error(\"Failed to initialize canonical cursor\");\n }\n\n return { canonical: true, fullCursor: blockInfoToCursor(fullInfo) };\n }\n\n const expectedInfo = await fetchCursor(cursor.orderKey);\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 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.log(\n // `Loop: 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 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 } =\n state.chainTracker.addToCanonicalChain(blockInfo);\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":["finalized"],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"protocol.2bd0b754.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 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) {\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 found\");\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 // 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 if (cursor.orderKey > head.orderKey) {\n return { canonical: false, reason: \"cursor is ahead of head\" };\n }\n\n if (!cursor.uniqueKey) {\n const fullInfo = await fetchCursor(cursor.orderKey);\n\n if (fullInfo === null) {\n throw new Error(\"Failed to initialize canonical cursor\");\n }\n\n return { canonical: true, fullCursor: blockInfoToCursor(fullInfo) };\n }\n\n const expectedInfo = await fetchCursor(cursor.orderKey);\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 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.log(\n // `Loop: 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 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 } =\n state.chainTracker.addToCanonicalChain(blockInfo);\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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"}
|