@eclesia/indexer-engine 2.14.1 → 3.0.0
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/indexer/index.cjs +26 -16
- package/dist/indexer/index.cjs.map +1 -1
- package/dist/indexer/index.d.cts +4 -5
- package/dist/indexer/index.d.cts.map +1 -1
- package/dist/indexer/index.d.mts +4 -5
- package/dist/indexer/index.d.mts.map +1 -1
- package/dist/indexer/index.mjs +26 -16
- package/dist/indexer/index.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +11 -1
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +11 -1
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/package.json +1 -1
package/dist/indexer/index.cjs
CHANGED
|
@@ -76,9 +76,9 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
76
76
|
prometheus = null;
|
|
77
77
|
/** Number of retry attempts for error recovery */
|
|
78
78
|
retryCount = 0;
|
|
79
|
-
/**
|
|
79
|
+
/** RPC client for ad-hoc queries (CometClient or custom client via connectFn) */
|
|
80
80
|
client;
|
|
81
|
-
/**
|
|
81
|
+
/** RPC client for block and validator queries (CometClient or custom client via connectFn) */
|
|
82
82
|
blockClient;
|
|
83
83
|
/** Winston logger instance */
|
|
84
84
|
log;
|
|
@@ -200,12 +200,13 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
200
200
|
this.blockClient.disconnect();
|
|
201
201
|
this.log.verbose("Disconnected from RPC");
|
|
202
202
|
}
|
|
203
|
-
const
|
|
203
|
+
const connectFn = this.config.connectFn ?? __cosmjs_tendermint_rpc.connectComet;
|
|
204
|
+
const connectTimeoutPromise = new Promise((_resolve, reject) => {
|
|
204
205
|
setTimeout(reject, require_constants.CONNECT_TIMEOUT_MS, []);
|
|
205
206
|
});
|
|
206
|
-
this.client = await Promise.race([(
|
|
207
|
+
this.client = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);
|
|
207
208
|
this.log.info("Connected to RPC for ad hoc queries");
|
|
208
|
-
this.blockClient = await Promise.race([(
|
|
209
|
+
this.blockClient = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);
|
|
209
210
|
this.log.info("Connected to RPC for block & validator info");
|
|
210
211
|
return true;
|
|
211
212
|
} catch (error) {
|
|
@@ -257,7 +258,7 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
257
258
|
this.log.verbose("Removed existing block listener and subscription");
|
|
258
259
|
}
|
|
259
260
|
if (!this.config.usePolling) this.subscription = this.client.subscribeNewBlock ? this.client.subscribeNewBlock() : null;
|
|
260
|
-
const statusPromise = new Promise((
|
|
261
|
+
const statusPromise = new Promise((_resolve, reject) => {
|
|
261
262
|
setTimeout(reject, require_constants.RPC_TIMEOUT_MS, false);
|
|
262
263
|
});
|
|
263
264
|
this.latestHeight = (await Promise.race([this.client.status(), statusPromise])).syncInfo.latestBlockHeight;
|
|
@@ -266,8 +267,9 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
266
267
|
if (this.config.usePolling) this.pollForBlock();
|
|
267
268
|
else if (this.subscription) this.subscription.addListener(this.blockListener);
|
|
268
269
|
else {
|
|
269
|
-
this.
|
|
270
|
-
|
|
270
|
+
this.log.info("WebSocket subscription not available, falling back to polling");
|
|
271
|
+
this.config.usePolling = true;
|
|
272
|
+
this.pollForBlock();
|
|
271
273
|
}
|
|
272
274
|
} catch (e) {
|
|
273
275
|
this.log.error("Failed to set up block listening: " + e);
|
|
@@ -297,7 +299,7 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
297
299
|
this.log.silly("Started db tx");
|
|
298
300
|
let height, timestamp;
|
|
299
301
|
if (this.isMinimal(this.blockQueue)) {
|
|
300
|
-
const timeoutPromise = new Promise((
|
|
302
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
301
303
|
setTimeout(reject, require_constants.QUEUE_DEQUEUE_TIMEOUT_MS, []);
|
|
302
304
|
});
|
|
303
305
|
const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);
|
|
@@ -307,7 +309,7 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
307
309
|
timestamp = (0, __cosmjs_tendermint_rpc.toRfc3339WithNanoseconds)(toProcess[0].block.header.time);
|
|
308
310
|
await this.processBlock(toProcess[0], toProcess[1]);
|
|
309
311
|
} else {
|
|
310
|
-
const timeoutPromise = new Promise((
|
|
312
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
311
313
|
setTimeout(reject, require_constants.QUEUE_DEQUEUE_TIMEOUT_MS, []);
|
|
312
314
|
});
|
|
313
315
|
const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);
|
|
@@ -347,7 +349,6 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
347
349
|
this.log.error("Error ending transaction. Must be a DB error: " + dbe);
|
|
348
350
|
}
|
|
349
351
|
this.tryToRecover = true;
|
|
350
|
-
this.retryCount++;
|
|
351
352
|
break;
|
|
352
353
|
}
|
|
353
354
|
this.retryCount = 0;
|
|
@@ -402,6 +403,18 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
402
403
|
this.heightToProcess = height;
|
|
403
404
|
this.log.debug("Processing block: %d", height);
|
|
404
405
|
const timestamp = (0, __cosmjs_tendermint_rpc.toRfc3339WithNanoseconds)(block.block.header.time);
|
|
406
|
+
if (this.config.processBlockFn) {
|
|
407
|
+
await this.config.processBlockFn(block, block_results, {
|
|
408
|
+
asyncEmit: this.asyncEmit,
|
|
409
|
+
log: this.log,
|
|
410
|
+
prometheus: this.prometheus,
|
|
411
|
+
height,
|
|
412
|
+
timestamp
|
|
413
|
+
}, validators);
|
|
414
|
+
endTimer?.();
|
|
415
|
+
this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());
|
|
416
|
+
return;
|
|
417
|
+
}
|
|
405
418
|
await this.asyncEmit("block", {
|
|
406
419
|
value: {
|
|
407
420
|
block,
|
|
@@ -523,7 +536,7 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
523
536
|
this.log.debug("Fetching: " + i);
|
|
524
537
|
try {
|
|
525
538
|
if (this.isMinimal(this.blockQueue)) {
|
|
526
|
-
const timeoutPromise = new Promise((
|
|
539
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
527
540
|
setTimeout(reject, require_constants.RPC_TIMEOUT_MS, false);
|
|
528
541
|
});
|
|
529
542
|
const toIndex = Promise.race([Promise.all([this.blockClient.block(i), this.blockClient.blockResults(i)]), timeoutPromise]).catch((e) => {
|
|
@@ -534,7 +547,7 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
534
547
|
});
|
|
535
548
|
this.blockQueue.enqueue(toIndex);
|
|
536
549
|
} else {
|
|
537
|
-
const timeoutPromise = new Promise((
|
|
550
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
538
551
|
setTimeout(reject, require_constants.RPC_TIMEOUT_MS, false);
|
|
539
552
|
});
|
|
540
553
|
const q = cosmjs_types_cosmos_staking_v1beta1_query_js.QueryValidatorsRequest.fromPartial({ pagination: { limit: require_constants.PAGINATION_LIMITS.VALIDATORS } });
|
|
@@ -584,7 +597,6 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
584
597
|
} catch (_e) {
|
|
585
598
|
this.tryToRecover = true;
|
|
586
599
|
this.setStatus("FAILED");
|
|
587
|
-
this.retryCount++;
|
|
588
600
|
throw new Error("RPC not responding. Query at: " + path);
|
|
589
601
|
}
|
|
590
602
|
}
|
|
@@ -601,7 +613,6 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
601
613
|
this.prometheus?.recordError("block");
|
|
602
614
|
this.log.error("Block queue is full. Cannot add new block");
|
|
603
615
|
this.tryToRecover = true;
|
|
604
|
-
this.retryCount++;
|
|
605
616
|
return;
|
|
606
617
|
}
|
|
607
618
|
try {
|
|
@@ -636,7 +647,6 @@ var EcleciaIndexer = class extends require_index.EclesiaEmitter {
|
|
|
636
647
|
} catch (e) {
|
|
637
648
|
this.log.error("Error polling for new block: " + e);
|
|
638
649
|
this.tryToRecover = true;
|
|
639
|
-
this.retryCount++;
|
|
640
650
|
}
|
|
641
651
|
}
|
|
642
652
|
readGenesis() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["DEFAULT_START_HEIGHT","DEFAULT_BATCH_SIZE","DEFAULT_POLLING_INTERVAL_MS","DEFAULT_HEALTH_CHECK_PORT","DEFAULT_PROMETHEUS_PORT","EclesiaEmitter","CircularBuffer","IndexerMetrics","CONNECT_TIMEOUT_MS","RPCError","statusPromise: Promise<StatusResponse>","RPC_TIMEOUT_MS","timeoutPromise: ReturnType<typeof this.blockQueue.dequeue>","QUEUE_DEQUEUE_TIMEOUT_MS","QueryValidatorsResponse","PERIODIC_INTERVALS","beginBlockEvents: readonly Event[] | readonly Event38[]","endBlockEvents: readonly Event[] | readonly Event38[]","decodeAttr","Tx","events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }>","eventsToAdd: typeof events","MsgExec","events","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]>","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>","QueryValidatorsRequest","PAGINATION_LIMITS","Parser","Pick","StreamArray","Batch","GENESIS_BATCH_SIZE","StreamValues"],"sources":["../../src/indexer/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\n/* eslint-disable max-lines */\nimport {\n createHash,\n} from \"node:crypto\";\nimport * as fs from \"node:fs\";\n\nimport {\n BlockResponse, BlockResultsResponse, CometClient, connectComet, Event, StatusResponse, toRfc3339WithNanoseconds,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event as Event38,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses.js\";\nimport {\n MsgExec,\n} from \"cosmjs-types/cosmos/authz/v1beta1/tx.js\";\nimport {\n QueryValidatorsRequest,\n QueryValidatorsResponse,\n} from \"cosmjs-types/cosmos/staking/v1beta1/query.js\";\nimport {\n Validator,\n} from \"cosmjs-types/cosmos/staking/v1beta1/staking.js\";\nimport {\n Tx,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx.js\";\nimport Fastify, {\n FastifyInstance,\n} from \"fastify\";\nimport {\n chain,\n} from \"stream-chain\";\nimport Parser from \"stream-json\";\nimport Pick from \"stream-json/filters/Pick.js\";\nimport StreamArray from \"stream-json/streamers/StreamArray.js\";\nimport StreamValues from \"stream-json/streamers/StreamValues.js\";\nimport Batch from \"stream-json/utils/Batch.js\";\nimport {\n v4 as uuidv4,\n} from \"uuid\";\nimport * as winston from \"winston\";\n\nimport {\n CONNECT_TIMEOUT_MS,\n DEFAULT_BATCH_SIZE, DEFAULT_HEALTH_CHECK_PORT, DEFAULT_POLLING_INTERVAL_MS, DEFAULT_PROMETHEUS_PORT, DEFAULT_START_HEIGHT,\n GENESIS_BATCH_SIZE, PAGINATION_LIMITS, PERIODIC_INTERVALS, QUEUE_DEQUEUE_TIMEOUT_MS, RPC_TIMEOUT_MS,\n} from \"../constants.js\";\nimport {\n EclesiaEmitter,\n} from \"../emitter/index.js\";\nimport {\n RPCError,\n} from \"../errors/index.js\";\nimport {\n IndexerMetrics,\n} from \"../metrics/index.js\";\nimport {\n CircularBuffer,\n} from \"../promise-queue/index.js\";\nimport {\n BlockQueue, EcleciaIndexerConfig, EmitFunc, MinimalBlockQueue,\n UUIDEvent, WithHeightAndUUID,\n} from \"../types/index.js\";\nimport {\n decodeAttr,\n} from \"../utils/index.js\";\nimport {\n validateFilePath, validatePort, validatePositiveInteger, validateUrl,\n} from \"../validation/index.js\";\n\n/** Default configuration for the Eclesia indexer */\nexport const defaultIndexerConfig = {\n startHeight: DEFAULT_START_HEIGHT, // Start indexing from block 1\n batchSize: DEFAULT_BATCH_SIZE, // Process blocks in batches of 500\n modules: [], // No modules enabled by default\n getNextHeight: () => DEFAULT_START_HEIGHT, // Default height retrieval function\n logLevel: \"info\" as EcleciaIndexerConfig[\"logLevel\"], // Default log level\n usePolling: false, // Use WebSocket subscription by default\n pollingInterval: DEFAULT_POLLING_INTERVAL_MS, // Poll every 5 seconds when polling enabled\n shouldProcessGenesis: () => false, // Skip genesis processing by default\n minimal: true, // Use minimal indexing by default\n enableHealthcheck: true, // Enable health check server by default\n healthCheckPort: DEFAULT_HEALTH_CHECK_PORT, // Default health check port\n enablePrometheus: false, // Disable Prometheus metrics server by default\n prometheusPort: DEFAULT_PROMETHEUS_PORT, // Default Prometheus metrics server port\n init: () => Promise.resolve(), // No-op initialization function\n beginTransaction: () => Promise.resolve(), // No-op transaction begin function\n endTransaction: (_status: boolean) => Promise.resolve(), // No-op transaction end function\n};\n\n/**\n * Core blockchain indexer that connects to Tendermint RPC and processes blocks\n * Extends EclesiaEmitter to provide event-driven architecture for modules\n */\nexport class EcleciaIndexer extends EclesiaEmitter {\n /** Indexer configuration settings */\n public config: EcleciaIndexerConfig;\n\n /** Fastify HTTP server for health checks */\n private fastify: FastifyInstance | null = null;\n\n /** Prometheus HTTP server instance */\n private prometheusServer: FastifyInstance | null = null;\n\n /** Indicates if the indexer has started */\n private started: boolean = false;\n\n /** Queue for managing block processing pipeline */\n private blockQueue: BlockQueue;\n\n /** Latest block height from the chain */\n private latestHeight!: number;\n\n /** Next block height to process */\n public heightToProcess!: number;\n\n /** Whether the indexer has been initialized */\n private initialized = false;\n\n /** Prometheus metrics server instance */\n public prometheus: IndexerMetrics | null = null;\n\n /** Number of retry attempts for error recovery */\n private retryCount = 0;\n\n /** CometBFT client for ad-hoc queries */\n public client!: CometClient;\n\n /** CometBFT client for block and validator queries */\n public blockClient!: CometClient;\n\n /** Winston logger instance */\n public log: winston.Logger;\n\n /** Flag indicating if indexer should attempt recovery */\n private tryToRecover: boolean = false;\n\n /** Health check status for monitoring */\n private healthCheck = {\n status: \"CONNECTING\",\n };\n\n /** WebSocket subscription for new block notifications */\n private subscription: ReturnType<CometClient[\"subscribeNewBlock\"]> | null = null;\n\n /** Timeout handler for block reception */\n private blockTimeout: NodeJS.Timeout | null = null;\n\n /**\n * Creates a new Eclesia indexer instance\n * @param config - Indexer configuration options\n */\n constructor(config: EcleciaIndexerConfig) {\n super();\n\n // Validate required configuration\n validateUrl(config.rpcUrl, \"rpcUrl\");\n validatePositiveInteger(config.batchSize, \"batchSize\");\n\n // Validate optional genesis path if processing genesis\n if (config.genesisPath) {\n validateFilePath(config.genesisPath, \"genesisPath\");\n }\n\n // Validate health check port if provided\n if (config.healthCheckPort !== undefined) {\n validatePort(config.healthCheckPort, \"healthCheckPort\");\n }\n\n // Validate prometheus port if provided\n if (config.prometheusPort !== undefined) {\n validatePort(config.prometheusPort, \"prometheusPort\");\n }\n\n // Validate start height if provided\n if (config.startHeight !== undefined) {\n validatePositiveInteger(config.startHeight, \"startHeight\");\n }\n\n // Validate polling interval if provided\n if (config.pollingInterval !== undefined) {\n validatePositiveInteger(config.pollingInterval, \"pollingInterval\");\n }\n\n this.config = {\n ...defaultIndexerConfig,\n ...config,\n };\n\n // Initialize logger first so it can be used by queue error handler\n const {\n printf,\n } = winston.format;\n\n const eclesiaFormat = printf(({\n level, message, timestamp,\n }) => {\n return `${timestamp} [${level.toUpperCase()}]:\\t${message}`;\n });\n this.log = winston.createLogger({\n level: this.config.logLevel,\n defaultMeta: {\n service: \"Eclesia Indexer\",\n },\n transports: [\n new winston.transports.File({\n filename: \"error.log\",\n level: \"error\",\n }),\n new winston.transports.File({\n filename: \"combined.log\",\n }),\n new winston.transports.Console({\n format: winston.format.combine(winston.format.splat(),\n winston.format.timestamp(),\n eclesiaFormat,\n winston.format.colorize({\n all: true,\n })),\n }),\n ],\n });\n\n // Initialize block queue based on minimal or full indexing mode\n // Pass error handler that uses the logger\n const queueErrorHandler = (e: unknown) => {\n this.prometheus?.recordError(\"rpc\");\n this.log.error(\"Error enqueueing block data: \" + e);\n };\n\n if (this.config.minimal) {\n // Minimal mode: only store block and block results\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse]>(this.config.batchSize, queueErrorHandler);\n }\n else {\n // Full mode: also store validator information\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>(this.config.batchSize, queueErrorHandler);\n }\n\n this.on(\"_unhandled\",\n (msg) => {\n if (msg.uuid) {\n this.log.verbose(\"Unhandled event: \" + msg.type);\n this.emit(\"uuid\",\n {\n status: true,\n uuid: msg.uuid,\n });\n }\n });\n if (this.config.enablePrometheus) {\n this.prometheus = new IndexerMetrics();\n this.prometheusServer = Fastify({\n logger: false,\n });\n this.prometheusServer.get(\"/metrics\",\n async (_req, res) => {\n res.header(\"Content-Type\", this.prometheus!.registry.contentType);\n res.send(await this.prometheus!.getMetrics());\n },\n );\n\n const prometheusPort = this.config.prometheusPort\n ?? (process.env.PROMETHEUS_PORT ? parseInt(process.env.PROMETHEUS_PORT, 10) : DEFAULT_PROMETHEUS_PORT);\n this.prometheusServer.listen({\n port: prometheusPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Prometheus error: \" + err);\n this.prometheus?.recordError(\"metrics_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start metrics server\",\n });\n }\n });\n }\n if (this.config.enableHealthcheck) {\n this.fastify = Fastify({\n logger: false,\n });\n this.fastify.get(\"/health\",\n async (_request, reply) => {\n const code = this.healthCheck.status == \"OK\"\n ? 200\n : 503;\n reply.code(code).send(this.healthCheck);\n });\n const healthPort = this.config.healthCheckPort\n ?? (process.env.HEALTH_CHECK_PORT ? parseInt(process.env.HEALTH_CHECK_PORT, 10) : DEFAULT_HEALTH_CHECK_PORT);\n this.fastify.listen({\n port: healthPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Health check server error: \" + err);\n this.prometheus?.recordError(\"health_check_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start health check server\",\n });\n }\n });\n }\n }\n\n private setStatus(status: string) {\n this.healthCheck.status = status;\n }\n\n private blockListener = {\n next: (data: {\n header: {\n height: number\n }\n }) => {\n this.newBlockReceived(data.header.height);\n },\n };\n\n private isMinimal(_blockqueue: BlockQueue): _blockqueue is MinimalBlockQueue {\n if (this.config.minimal) {\n return true;\n }\n else {\n return false;\n }\n }\n\n public async connect() {\n try {\n if (this.client && this.tryToRecover) {\n this.log.verbose(\"Recover from error. Attempting to disconnect from RPC\");\n this.client.disconnect();\n this.blockClient.disconnect();\n this.log.verbose(\"Disconnected from RPC\");\n }\n const connectTimeoutPromise = new Promise<ReturnType<typeof connectComet>>((resolve, reject) => {\n setTimeout(reject, CONNECT_TIMEOUT_MS, []);\n });\n this.client = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for ad hoc queries\");\n this.blockClient = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for block & validator info\");\n\n return true;\n }\n catch (error) {\n this.log.error(\"RPC connection error: \" + error);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return false;\n }\n }\n\n private async initialize() {\n if (!this.initialized) {\n try {\n if (this.config.init) {\n await this.config.init();\n }\n }\n catch (e) {\n this.log.error(\"Failed to initialize indexer: \" + e);\n\n this.prometheus?.recordError(\"init_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n if (await this.config.shouldProcessGenesis()) {\n try {\n if (this.config.genesisPath) {\n await this.parseGenesis();\n }\n }\n catch (e) {\n this.log.error(\"Failed to parse genesis: \" + e);\n\n this.prometheus?.recordError(\"genesis_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n this.initialized = true;\n }\n }\n\n public stop() {\n this.started = false;\n }\n\n private clearBlockQueue() {\n if (this.blockQueue) {\n this.blockQueue.clear();\n this.log.verbose(\"Starting, clearing block queue\");\n }\n }\n\n private async setupBlockListening() {\n const connected = await this.connect();\n if (!connected) {\n this.setStatus(\"FAILED\");\n throw new RPCError(\"Failed to connect to RPC\");\n }\n\n try {\n if (!this.config.usePolling && this.subscription) {\n this.subscription.removeListener(this.blockListener);\n this.subscription = null;\n this.log.verbose(\"Removed existing block listener and subscription\");\n }\n if (!this.config.usePolling) {\n this.subscription = this.client.subscribeNewBlock\n ? this.client.subscribeNewBlock()\n : null;\n }\n const statusPromise: Promise<StatusResponse> = new Promise((resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const status = await Promise.race([this.client.status(), statusPromise]);\n this.latestHeight = status.syncInfo.latestBlockHeight;\n this.log.info(\"Current chain height: \" + this.latestHeight);\n\n this.heightToProcess = await this.config.getNextHeight();\n if (this.config.usePolling) {\n this.pollForBlock();\n }\n else {\n if (this.subscription) {\n this.subscription.addListener(this.blockListener);\n }\n else {\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"Could not subscribe to new blocks\");\n }\n }\n }\n catch (e) {\n this.log.error(\"Failed to set up block listening: \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n\n public async start() {\n this.started = true;\n this.clearBlockQueue();\n await this.initialize();\n try {\n await this.setupBlockListening();\n this.log.debug(\"Starting main processing loop\");\n this.tryToRecover = false;\n this.fetcher().catch((e) => {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"Error in fetching service: \" + e);\n });\n }\n catch (_e) {\n // Continue and attempt to recover\n }\n\n while (\n this.started // break out when stopped\n && !this.tryToRecover // break out for recoverable errors\n && (this.config.endHeight === undefined || this.heightToProcess <= this.config.endHeight) // break out if end height configured and reached\n && this.blockQueue.size() > 0 // break out if no blocks to process\n ) {\n // await the dequeued promise is essentially awaiting fetched data for that block\n try {\n this.prometheus?.updateRetryCount(this.retryCount);\n // Index block inside a db transaction to ensure data consistency\n await this.config.beginTransaction();\n this.log.silly(\"Started db tx\");\n let height, timestamp;\n\n // Main block processing (minimal)\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1]) {\n throw new RPCError(\"Could not fetch block(minimal)\");\n }\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1]);\n }\n // Main block processing (full)\n else {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1] || !toProcess[2]) {\n throw new RPCError(\"Could not fetch block(full)\");\n }\n\n this.log.silly(\"Decoded block\");\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1],\n QueryValidatorsResponse.decode(toProcess[2]).validators);\n }\n\n // Emit events to trigger periodic operations every 50, 100 and 1000 blocks\n if (height % PERIODIC_INTERVALS.LARGE == 0) {\n await this.asyncEmit(\"periodic/large\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.MEDIUM == 0) {\n await this.asyncEmit(\"periodic/medium\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.SMALL == 0) {\n await this.asyncEmit(\"periodic/small\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n this.log.silly(\"Handled periodic events\");\n\n await this.config.endTransaction(true);\n\n this.log.silly(\"Committed db tx\");\n }\n catch (e) {\n // any error here is likely recoverable (e.g. RPC timeout, DB error)\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block processing error: \" + e);\n this.setStatus(\"FAILED\");\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.tryToRecover = true;\n this.retryCount++;\n // Exit processing loop to attempt recovery\n break;\n }\n // Reset retry count and status on successful block processing\n this.retryCount = 0;\n this.setStatus(\"OK\");\n }\n\n // Normal exit from processing loop\n if (!this.started) {\n this.log.info(\"Indexer manually stopped.\");\n return;\n }\n if (this.config.endHeight !== undefined && this.heightToProcess >= this.config.endHeight!) {\n this.log.info(\"Reached configured end height. Stopping indexer.\");\n this.stop();\n return;\n }\n\n // Abnormal exit\n if (this.retryCount < 3) {\n this.log.debug(\"Indexer retryCount: \" + this.retryCount);\n this.retryCount++;\n this.log.info(\"Indexer is restarting\");\n // Attempt recovery after brief delay\n setTimeout(() => this.start(),\n this.retryCount * 5000);\n }\n else {\n this.log.info(\"Indexer failed too many times. Exiting.\");\n this.emit(\"fatal-error\", {\n error: new Error(\"Max retry attempts exceeded\"),\n message: \"Indexer failed too many times\",\n retryCount: this.retryCount,\n });\n }\n }\n\n public asyncEmit: EmitFunc<keyof WithHeightAndUUID<EventMap>> = async (\n type,\n event,\n ) => {\n event.uuid = uuidv4();\n\n /*\n * More than 1 listener can be registered for an event type\n * Fortunately these are all set up during module init() so we have a consistent count\n * so we can count responses to resolve when complete\n * values are irrelevant as promise resolution is only used for flow control\n */\n let listenerCount = this.handled.get(type);\n if (!listenerCount) {\n // Setting listenerCount to 1 (the unhandled listener)\n listenerCount = 1;\n }\n let listenersResponded = 0;\n const prom = new Promise<void>((resolve, reject) => {\n const returnFunc = (ev: UUIDEvent) => {\n if (ev.uuid == event.uuid) {\n if (ev.status) {\n listenersResponded++;\n if (listenersResponded == listenerCount) {\n // All listeners have done their thing so we can remove listener, resolve and continue execution\n this.off(\"uuid\",\n returnFunc);\n resolve();\n }\n }\n else {\n // At least 1 listener is reporting an error. Reject and handle exception at the original asyncEmit location\n reject(ev.error);\n }\n }\n };\n this.on(\"uuid\",\n returnFunc);\n });\n this.emit(type,\n event);\n\n return prom;\n };\n\n private async processBlock(block: BlockResponse, block_results: BlockResultsResponse | BlockResultsResponse38, validators?: Validator[]) {\n const endTimer = this.prometheus?.timeBlockProcessing();\n const height = block.block.header.height;\n this.heightToProcess = height;\n this.log.debug(\"Processing block: %d\",\n height);\n // Initialize height & timestamp to be used for this block-processing run\n const timestamp = toRfc3339WithNanoseconds(block.block.header.time);\n\n // Use & await asyncEmit to ensure db insertions in order\n\n /*\n * Emit block information to any interested modules.\n * Primarily the required block module listens to this\n */\n await this.asyncEmit(\"block\",\n {\n value: {\n block,\n block_results,\n },\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled block event\");\n\n let beginBlockEvents: readonly Event[] | readonly Event38[];\n let endBlockEvents: readonly Event[] | readonly Event38[];\n if ((block_results as BlockResultsResponse38).finalizeBlockEvents) {\n beginBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"begin_block\")) as readonly Event38[];\n endBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"end_block\")) as readonly Event38[];\n }\n else {\n beginBlockEvents = (block_results as BlockResultsResponse).beginBlockEvents;\n endBlockEvents = (block_results as BlockResultsResponse).endBlockEvents;\n }\n // Deal with begin_block events first\n await this.asyncEmit(\"begin_block\",\n {\n value: {\n events: beginBlockEvents!,\n validators,\n },\n height,\n timestamp,\n });\n\n this.log.silly(\"Modules handled begin_block events\");\n\n // Then individual tx_events\n await this.asyncEmit(\"tx_events\",\n {\n value: block_results.results,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled tx events\");\n\n // Emit details and result for each tx msg separately\n for (let t = 0; t < block.block.txs.length; t++) {\n const tx = Tx.decode(block.block.txs[t]);\n\n const result = block_results.results[t].code;\n const txlog = block_results.results[t].log;\n\n if (result != 0) {\n // Tx failed. Ignore\n continue;\n }\n if (tx.body && tx.body.memo != \"\") {\n const txHash = createHash(\"sha256\").update(block.block.txs[t])\n .digest(\"hex\");\n await this.asyncEmit(\"tx_memo\",\n {\n value: {\n txHash,\n txBody: tx.body,\n },\n height,\n timestamp,\n });\n }\n // parsing log rather than using events directly in order to have msg_index available to filter appropriate events for each msg\n let events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }> = txlog\n ? JSON.parse(txlog)\n : [];\n if (events.length == 0) {\n const eventsToAdd: typeof events = [];\n this.log.silly(\"No events found in tx log. Parsing events for msg_index\");\n for (let m = 0; m < block_results.results[t].events.length; m++) {\n if (block_results.results[t].events[m].attributes.find(a => decodeAttr(a.key) == \"msg_index\")) {\n const mi = decodeAttr(block_results.results[t].events[m].attributes.find(a => decodeAttr(a.key) == \"msg_index\")?.value ?? \"\");\n if (mi != \"\") {\n const miNum = parseInt(mi);\n let ev = eventsToAdd.find(x => x.msg_index == miNum);\n if (!ev) {\n ev = {\n msg_index: miNum,\n events: [block_results.results[t].events[m]],\n };\n eventsToAdd.push(ev);\n }\n else {\n ev.events.push(block_results.results[t].events[m] as Event);\n }\n }\n }\n }\n events = events.concat(eventsToAdd);\n }\n const msgs = tx.body?.messages;\n\n if (msgs) {\n for (let i = 0; i < msgs.length; i++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + msgs[i].typeUrl);\n const msgevents\n = msgs.length > 1\n ? events.find(x => x.msg_index == i)?.events\n : events[0].events;\n await this.asyncEmit(msgs[i].typeUrl as never,\n {\n value: {\n tx: msgs[i].value as never,\n events: msgevents,\n } as never,\n height,\n timestamp,\n });\n if (msgs[i].typeUrl == \"/cosmos.authz.v1beta1.MsgExec\") {\n const authzMsgs = MsgExec.decode(msgs[i].value).msgs;\n if (authzMsgs) {\n for (let r = 0; r < authzMsgs.length; r++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + authzMsgs[r].typeUrl);\n const authzMsgEvents = msgevents?.reduce((events, evt) => {\n if (evt.attributes.filter(x => decodeAttr(x.key) == \"authz_msg_index\" && decodeAttr(x.value) == \"\" + r).length > 0) {\n events.push(evt);\n }\n return events;\n },\n [] as (Event | Event38)[]);\n await this.asyncEmit(authzMsgs[r].typeUrl as never,\n {\n value: {\n tx: authzMsgs[r].value as never,\n events: authzMsgEvents,\n } as never,\n height,\n timestamp,\n });\n }\n }\n }\n }\n }\n }\n this.log.silly(\"Modules handled msg events\");\n this.prometheus?.recordTransactions(block.block.txs.length);\n // Then deal with end_block events\n await this.asyncEmit(\"end_block\",\n {\n value: endBlockEvents!,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled end_block events\");\n\n endTimer?.();\n this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());\n }\n\n private async fetcher() {\n for (let i = this.heightToProcess; i <= this.latestHeight; i++) {\n // If some other async process triggers recovery, exit the fetching loop\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n this.log.debug(\"Fetching: \" + i);\n try {\n // Main fetching logic for minimal indexer\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]> = new Promise((resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([Promise.all([this.blockClient.block(i) as Promise<BlockResponse>, this.blockClient.blockResults(i) as Promise<BlockResultsResponse>]), timeoutPromise]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>;\n this.blockQueue.enqueue(toIndex);\n }\n else {\n // Main fetching logic for minimal indexer\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]> = new Promise((resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: PAGINATION_LIMITS.VALIDATORS,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([\n Promise.all([\n this.blockClient.block(i) as Promise<BlockResponse>,\n this.blockClient.blockResults(i) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n i,\n false),\n ]),\n timeoutPromise,\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n this.blockQueue.enqueue(toIndex);\n }\n }\n catch (e) {\n this.log.error(\"Fetching error: \" + e);\n break;\n }\n await this.blockQueue.continue();\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n }\n // If we exit the fetching loop without errors, we are synced\n if (!this.tryToRecover) {\n this.blockQueue.setSynced();\n this.log.info(\"Synced to latest height\");\n }\n }\n\n public async callABCI(path: string, data: Uint8Array, height?: number, adHoc: boolean = true): Promise<Uint8Array> {\n try {\n const endTimer = this.prometheus?.timeRpcCall(path) ?? void 0;\n const abciq = await\n (adHoc\n ? this.client\n : this.blockClient).abciQuery({\n path,\n data,\n height: height,\n });\n endTimer?.();\n if (abciq) {\n return abciq.value;\n }\n else {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n catch (_e) {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n this.retryCount++;\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n\n private newBlockReceived(height: number): void {\n if (this.blockTimeout) {\n clearTimeout(this.blockTimeout);\n }\n this.blockTimeout = setTimeout(() => {\n this.tryToRecover = true;\n }, 30000);\n this.log.info(\"Received new block: %d\",\n height);\n if (height == this.latestHeight) {\n return;\n }\n // If we are synced, add to end of queue\n if (this.blockQueue.synced && !this.tryToRecover) {\n this.latestHeight = height;\n if (this.blockQueue.size() + 1 == this.config.batchSize) {\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block queue is full. Cannot add new block\");\n this.tryToRecover = true;\n this.retryCount++;\n return;\n }\n try {\n if (this.isMinimal(this.blockQueue)) {\n this.blockQueue.enqueue(Promise.all([this.client.block(height) as Promise<BlockResponse>, this.client.blockResults(height) as Promise<BlockResultsResponse>]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>);\n }\n else {\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: 1000n,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n this.blockQueue.enqueue(Promise.all([\n this.client.block(height) as Promise<BlockResponse>,\n this.client.blockResults(height) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n height,\n false),\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>);\n }\n }\n catch (e) {\n this.log.error(\"New Block Received error: \" + e);\n }\n }\n else {\n this.latestHeight = height;\n }\n }\n\n private async pollForBlock() {\n try {\n const status = await this.client.status();\n if (status.syncInfo.latestBlockHeight > this.latestHeight) {\n while (this.latestHeight < status.syncInfo.latestBlockHeight) {\n this.newBlockReceived(this.latestHeight + 1);\n }\n }\n setTimeout(() => {\n this.pollForBlock();\n },\n this.config.pollingInterval);\n }\n catch (e) {\n this.log.error(\"Error polling for new block: \" + e);\n this.tryToRecover = true;\n this.retryCount++;\n }\n }\n\n private readGenesis(): Parser.Parser {\n if (this.config.genesisPath) {\n return fs.createReadStream(this.config.genesisPath).pipe(Parser.parser());\n }\n else {\n throw new Error(\"Genesis path not set\");\n }\n }\n\n private async setArrayReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n let counter = 0;\n let chunkCounter = 0;\n\n // Wrapper processor that handles transaction chunking\n const chunkProcessor = async (data: unknown) => {\n chunkCounter++;\n this.log.debug(`Processing genesis chunk ${chunkCounter}`);\n\n await processor(data);\n\n // Commit and restart transaction every 5 chunks (5000 entries)\n // This prevents timeout on large genesis files\n if (chunkCounter % 5 === 0) {\n this.log.debug(`Committing transaction after chunk ${chunkCounter}`);\n await this.config.endTransaction(true);\n await this.config.beginTransaction();\n }\n };\n\n chain([\n this.readGenesis(),\n ...pickers,\n StreamArray.streamArray(),\n Batch.batch({\n batchSize: GENESIS_BATCH_SIZE,\n }),\n chunkProcessor,\n ])\n .on(\"data\",\n (data) => {\n if (data && Array.isArray(data)) {\n counter = counter + data.length;\n }\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries in ${chunkCounter} chunks`);\n resolve(true);\n });\n }\n catch (_e) {\n this.log.verbose(\"Error in setArrayReader: \" + _e);\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async setValueReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n\n let counter = 0;\n chain([this.readGenesis(), ...pickers, StreamValues.streamValues(), processor])\n .on(\"data\",\n (_data) => {\n counter++;\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries`);\n resolve(true);\n });\n }\n catch (_e) {\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async parseGenesis() {\n this.log.info(\"Parsing genesis\");\n await this.config.beginTransaction();\n try {\n this.log.info(\"Starting genesis import\");\n this.log.debug(\"Importing genesis file...\");\n\n for (const [key, _value] of this.handled) {\n if (key.startsWith(\"genesis/\")) {\n const genesisEntry = key.split(\"/\");\n\n this.log.verbose(\"Importing \" + key + \"...\");\n if (genesisEntry[1] == \"array\") {\n await this.setArrayReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.map((x: {\n value: never\n }) => x.value),\n } as never);\n return data;\n });\n }\n else {\n await this.setValueReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.value,\n } as never);\n return data;\n });\n }\n }\n }\n\n this.log.info(\"Importing gen TXs...\");\n\n await this.setArrayReader(\"app_state.genutil.gen_txs\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n for (let j = 0; j < data.length; j++) {\n const gentx = data[j].value;\n for (let i = 0; i < gentx.body.messages.length; i++) {\n const msg = gentx.body.messages[i];\n await this.asyncEmit((\"gentx\" + msg[\"@type\"]) as never,\n {\n value: msg,\n } as never);\n }\n }\n return data;\n });\n await this.config.endTransaction(true);\n\n this.log.info(\"Finished importing\");\n }\n catch (e) {\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.log.error(\"Failed to import genesis\");\n throw e;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["DEFAULT_START_HEIGHT","DEFAULT_BATCH_SIZE","DEFAULT_POLLING_INTERVAL_MS","DEFAULT_HEALTH_CHECK_PORT","DEFAULT_PROMETHEUS_PORT","EclesiaEmitter","CircularBuffer","IndexerMetrics","connectComet","CONNECT_TIMEOUT_MS","RPCError","statusPromise: Promise<StatusResponse>","RPC_TIMEOUT_MS","timeoutPromise: ReturnType<typeof this.blockQueue.dequeue>","QUEUE_DEQUEUE_TIMEOUT_MS","QueryValidatorsResponse","PERIODIC_INTERVALS","beginBlockEvents: readonly Event[] | readonly Event38[]","endBlockEvents: readonly Event[] | readonly Event38[]","decodeAttr","Tx","events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }>","eventsToAdd: typeof events","MsgExec","events","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]>","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>","QueryValidatorsRequest","PAGINATION_LIMITS","Parser","Pick","StreamArray","Batch","GENESIS_BATCH_SIZE","StreamValues"],"sources":["../../src/indexer/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\n/* eslint-disable max-lines */\nimport {\n createHash,\n} from \"node:crypto\";\nimport * as fs from \"node:fs\";\n\nimport {\n BlockResponse, BlockResultsResponse, connectComet, Event, StatusResponse, toRfc3339WithNanoseconds,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event as Event38,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses.js\";\nimport {\n MsgExec,\n} from \"cosmjs-types/cosmos/authz/v1beta1/tx.js\";\nimport {\n QueryValidatorsRequest,\n QueryValidatorsResponse,\n} from \"cosmjs-types/cosmos/staking/v1beta1/query.js\";\nimport {\n Tx,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx.js\";\nimport Fastify, {\n FastifyInstance,\n} from \"fastify\";\nimport {\n chain,\n} from \"stream-chain\";\nimport Parser from \"stream-json\";\nimport Pick from \"stream-json/filters/Pick.js\";\nimport StreamArray from \"stream-json/streamers/StreamArray.js\";\nimport StreamValues from \"stream-json/streamers/StreamValues.js\";\nimport Batch from \"stream-json/utils/Batch.js\";\nimport {\n v4 as uuidv4,\n} from \"uuid\";\nimport * as winston from \"winston\";\n\nimport {\n CONNECT_TIMEOUT_MS,\n DEFAULT_BATCH_SIZE, DEFAULT_HEALTH_CHECK_PORT, DEFAULT_POLLING_INTERVAL_MS, DEFAULT_PROMETHEUS_PORT, DEFAULT_START_HEIGHT,\n GENESIS_BATCH_SIZE, PAGINATION_LIMITS, PERIODIC_INTERVALS, QUEUE_DEQUEUE_TIMEOUT_MS, RPC_TIMEOUT_MS,\n} from \"../constants.js\";\nimport {\n EclesiaEmitter,\n} from \"../emitter/index.js\";\nimport {\n RPCError,\n} from \"../errors/index.js\";\nimport {\n IndexerMetrics,\n} from \"../metrics/index.js\";\nimport {\n CircularBuffer,\n} from \"../promise-queue/index.js\";\nimport {\n BlockQueue, EcleciaIndexerConfig, EmitFunc, MinimalBlockQueue,\n UUIDEvent, WithHeightAndUUID,\n} from \"../types/index.js\";\nimport {\n decodeAttr,\n} from \"../utils/index.js\";\nimport {\n validateFilePath, validatePort, validatePositiveInteger, validateUrl,\n} from \"../validation/index.js\";\n\n/** Default configuration for the Eclesia indexer */\nexport const defaultIndexerConfig = {\n startHeight: DEFAULT_START_HEIGHT, // Start indexing from block 1\n batchSize: DEFAULT_BATCH_SIZE, // Process blocks in batches of 500\n modules: [], // No modules enabled by default\n getNextHeight: () => DEFAULT_START_HEIGHT, // Default height retrieval function\n logLevel: \"info\" as EcleciaIndexerConfig[\"logLevel\"], // Default log level\n usePolling: false, // Use WebSocket subscription by default\n pollingInterval: DEFAULT_POLLING_INTERVAL_MS, // Poll every 5 seconds when polling enabled\n shouldProcessGenesis: () => false, // Skip genesis processing by default\n minimal: true, // Use minimal indexing by default\n enableHealthcheck: true, // Enable health check server by default\n healthCheckPort: DEFAULT_HEALTH_CHECK_PORT, // Default health check port\n enablePrometheus: false, // Disable Prometheus metrics server by default\n prometheusPort: DEFAULT_PROMETHEUS_PORT, // Default Prometheus metrics server port\n init: () => Promise.resolve(), // No-op initialization function\n beginTransaction: () => Promise.resolve(), // No-op transaction begin function\n endTransaction: (_status: boolean) => Promise.resolve(), // No-op transaction end function\n};\n\n/**\n * Core blockchain indexer that connects to Tendermint RPC and processes blocks\n * Extends EclesiaEmitter to provide event-driven architecture for modules\n */\nexport class EcleciaIndexer extends EclesiaEmitter {\n /** Indexer configuration settings */\n public config: EcleciaIndexerConfig;\n\n /** Fastify HTTP server for health checks */\n private fastify: FastifyInstance | null = null;\n\n /** Prometheus HTTP server instance */\n private prometheusServer: FastifyInstance | null = null;\n\n /** Indicates if the indexer has started */\n private started: boolean = false;\n\n /** Queue for managing block processing pipeline */\n private blockQueue: BlockQueue;\n\n /** Latest block height from the chain */\n private latestHeight!: number;\n\n /** Next block height to process */\n public heightToProcess!: number;\n\n /** Whether the indexer has been initialized */\n private initialized = false;\n\n /** Prometheus metrics server instance */\n public prometheus: IndexerMetrics | null = null;\n\n /** Number of retry attempts for error recovery */\n private retryCount = 0;\n\n /** RPC client for ad-hoc queries (CometClient or custom client via connectFn) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public client!: any;\n\n /** RPC client for block and validator queries (CometClient or custom client via connectFn) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public blockClient!: any;\n\n /** Winston logger instance */\n public log: winston.Logger;\n\n /** Flag indicating if indexer should attempt recovery */\n private tryToRecover: boolean = false;\n\n /** Health check status for monitoring */\n private healthCheck = {\n status: \"CONNECTING\",\n };\n\n /** WebSocket subscription for new block notifications */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private subscription: any | null = null;\n\n /** Timeout handler for block reception */\n private blockTimeout: NodeJS.Timeout | null = null;\n\n /**\n * Creates a new Eclesia indexer instance\n * @param config - Indexer configuration options\n */\n constructor(config: EcleciaIndexerConfig) {\n super();\n\n // Validate required configuration\n validateUrl(config.rpcUrl, \"rpcUrl\");\n validatePositiveInteger(config.batchSize, \"batchSize\");\n\n // Validate optional genesis path if processing genesis\n if (config.genesisPath) {\n validateFilePath(config.genesisPath, \"genesisPath\");\n }\n\n // Validate health check port if provided\n if (config.healthCheckPort !== undefined) {\n validatePort(config.healthCheckPort, \"healthCheckPort\");\n }\n\n // Validate prometheus port if provided\n if (config.prometheusPort !== undefined) {\n validatePort(config.prometheusPort, \"prometheusPort\");\n }\n\n // Validate start height if provided\n if (config.startHeight !== undefined) {\n validatePositiveInteger(config.startHeight, \"startHeight\");\n }\n\n // Validate polling interval if provided\n if (config.pollingInterval !== undefined) {\n validatePositiveInteger(config.pollingInterval, \"pollingInterval\");\n }\n\n this.config = {\n ...defaultIndexerConfig,\n ...config,\n };\n\n // Initialize logger first so it can be used by queue error handler\n const {\n printf,\n } = winston.format;\n\n const eclesiaFormat = printf(({\n level, message, timestamp,\n }) => {\n return `${timestamp} [${level.toUpperCase()}]:\\t${message}`;\n });\n this.log = winston.createLogger({\n level: this.config.logLevel,\n defaultMeta: {\n service: \"Eclesia Indexer\",\n },\n transports: [\n new winston.transports.File({\n filename: \"error.log\",\n level: \"error\",\n }),\n new winston.transports.File({\n filename: \"combined.log\",\n }),\n new winston.transports.Console({\n format: winston.format.combine(winston.format.splat(),\n winston.format.timestamp(),\n eclesiaFormat,\n winston.format.colorize({\n all: true,\n })),\n }),\n ],\n });\n\n // Initialize block queue based on minimal or full indexing mode\n // Pass error handler that uses the logger\n const queueErrorHandler = (e: unknown) => {\n this.prometheus?.recordError(\"rpc\");\n this.log.error(\"Error enqueueing block data: \" + e);\n };\n\n if (this.config.minimal) {\n // Minimal mode: only store block and block results\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse]>(this.config.batchSize, queueErrorHandler);\n }\n else {\n // Full mode: also store validator information\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>(this.config.batchSize, queueErrorHandler);\n }\n\n this.on(\"_unhandled\",\n (msg) => {\n if (msg.uuid) {\n this.log.verbose(\"Unhandled event: \" + msg.type);\n this.emit(\"uuid\",\n {\n status: true,\n uuid: msg.uuid,\n });\n }\n });\n if (this.config.enablePrometheus) {\n this.prometheus = new IndexerMetrics();\n this.prometheusServer = Fastify({\n logger: false,\n });\n this.prometheusServer.get(\"/metrics\",\n async (_req, res) => {\n res.header(\"Content-Type\", this.prometheus!.registry.contentType);\n res.send(await this.prometheus!.getMetrics());\n },\n );\n\n const prometheusPort = this.config.prometheusPort\n ?? (process.env.PROMETHEUS_PORT ? parseInt(process.env.PROMETHEUS_PORT, 10) : DEFAULT_PROMETHEUS_PORT);\n this.prometheusServer.listen({\n port: prometheusPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Prometheus error: \" + err);\n this.prometheus?.recordError(\"metrics_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start metrics server\",\n });\n }\n });\n }\n if (this.config.enableHealthcheck) {\n this.fastify = Fastify({\n logger: false,\n });\n this.fastify.get(\"/health\",\n async (_request, reply) => {\n const code = this.healthCheck.status == \"OK\"\n ? 200\n : 503;\n reply.code(code).send(this.healthCheck);\n });\n const healthPort = this.config.healthCheckPort\n ?? (process.env.HEALTH_CHECK_PORT ? parseInt(process.env.HEALTH_CHECK_PORT, 10) : DEFAULT_HEALTH_CHECK_PORT);\n this.fastify.listen({\n port: healthPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Health check server error: \" + err);\n this.prometheus?.recordError(\"health_check_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start health check server\",\n });\n }\n });\n }\n }\n\n private setStatus(status: string) {\n this.healthCheck.status = status;\n }\n\n private blockListener = {\n next: (data: {\n header: {\n height: number\n }\n }) => {\n this.newBlockReceived(data.header.height);\n },\n };\n\n private isMinimal(_blockqueue: BlockQueue): _blockqueue is MinimalBlockQueue {\n if (this.config.minimal) {\n return true;\n }\n else {\n return false;\n }\n }\n\n public async connect() {\n try {\n if (this.client && this.tryToRecover) {\n this.log.verbose(\"Recover from error. Attempting to disconnect from RPC\");\n this.client.disconnect();\n this.blockClient.disconnect();\n this.log.verbose(\"Disconnected from RPC\");\n }\n const connectFn = this.config.connectFn ?? connectComet;\n const connectTimeoutPromise = new Promise<never>((_resolve, reject) => {\n setTimeout(reject, CONNECT_TIMEOUT_MS, []);\n });\n this.client = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for ad hoc queries\");\n this.blockClient = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for block & validator info\");\n\n return true;\n }\n catch (error) {\n this.log.error(\"RPC connection error: \" + error);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return false;\n }\n }\n\n private async initialize() {\n if (!this.initialized) {\n try {\n if (this.config.init) {\n await this.config.init();\n }\n }\n catch (e) {\n this.log.error(\"Failed to initialize indexer: \" + e);\n\n this.prometheus?.recordError(\"init_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n if (await this.config.shouldProcessGenesis()) {\n try {\n if (this.config.genesisPath) {\n await this.parseGenesis();\n }\n }\n catch (e) {\n this.log.error(\"Failed to parse genesis: \" + e);\n\n this.prometheus?.recordError(\"genesis_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n this.initialized = true;\n }\n }\n\n public stop() {\n this.started = false;\n }\n\n private clearBlockQueue() {\n if (this.blockQueue) {\n this.blockQueue.clear();\n this.log.verbose(\"Starting, clearing block queue\");\n }\n }\n\n private async setupBlockListening() {\n const connected = await this.connect();\n if (!connected) {\n this.setStatus(\"FAILED\");\n throw new RPCError(\"Failed to connect to RPC\");\n }\n\n try {\n if (!this.config.usePolling && this.subscription) {\n this.subscription.removeListener(this.blockListener);\n this.subscription = null;\n this.log.verbose(\"Removed existing block listener and subscription\");\n }\n if (!this.config.usePolling) {\n this.subscription = this.client.subscribeNewBlock\n ? this.client.subscribeNewBlock()\n : null;\n }\n const statusPromise: Promise<StatusResponse> = new Promise((_resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const status = await Promise.race([this.client.status(), statusPromise]);\n this.latestHeight = status.syncInfo.latestBlockHeight;\n this.log.info(\"Current chain height: \" + this.latestHeight);\n\n this.heightToProcess = await this.config.getNextHeight();\n if (this.config.usePolling) {\n this.pollForBlock();\n }\n else {\n if (this.subscription) {\n this.subscription.addListener(this.blockListener);\n }\n else {\n // Fall back to polling if subscription is not available (e.g. custom RPC client)\n this.log.info(\"WebSocket subscription not available, falling back to polling\");\n this.config.usePolling = true;\n this.pollForBlock();\n }\n }\n }\n catch (e) {\n this.log.error(\"Failed to set up block listening: \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n\n public async start() {\n this.started = true;\n this.clearBlockQueue();\n await this.initialize();\n try {\n await this.setupBlockListening();\n this.log.debug(\"Starting main processing loop\");\n this.tryToRecover = false;\n this.fetcher().catch((e) => {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"Error in fetching service: \" + e);\n });\n }\n catch (_e) {\n // Continue and attempt to recover\n }\n\n while (\n this.started // break out when stopped\n && !this.tryToRecover // break out for recoverable errors\n && (this.config.endHeight === undefined || this.heightToProcess <= this.config.endHeight) // break out if end height configured and reached\n && this.blockQueue.size() > 0 // break out if no blocks to process\n ) {\n // await the dequeued promise is essentially awaiting fetched data for that block\n try {\n this.prometheus?.updateRetryCount(this.retryCount);\n // Index block inside a db transaction to ensure data consistency\n await this.config.beginTransaction();\n this.log.silly(\"Started db tx\");\n let height, timestamp;\n\n // Main block processing (minimal)\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((_resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1]) {\n throw new RPCError(\"Could not fetch block(minimal)\");\n }\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1]);\n }\n // Main block processing (full)\n else {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((_resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1] || !toProcess[2]) {\n throw new RPCError(\"Could not fetch block(full)\");\n }\n\n this.log.silly(\"Decoded block\");\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1],\n QueryValidatorsResponse.decode(toProcess[2]).validators);\n }\n\n // Emit events to trigger periodic operations every 50, 100 and 1000 blocks\n if (height % PERIODIC_INTERVALS.LARGE == 0) {\n await this.asyncEmit(\"periodic/large\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.MEDIUM == 0) {\n await this.asyncEmit(\"periodic/medium\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.SMALL == 0) {\n await this.asyncEmit(\"periodic/small\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n this.log.silly(\"Handled periodic events\");\n\n await this.config.endTransaction(true);\n\n this.log.silly(\"Committed db tx\");\n }\n catch (e) {\n // any error here is likely recoverable (e.g. RPC timeout, DB error)\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block processing error: \" + e);\n this.setStatus(\"FAILED\");\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.tryToRecover = true;\n // Exit processing loop to attempt recovery\n break;\n }\n // Reset retry count and status on successful block processing\n this.retryCount = 0;\n this.setStatus(\"OK\");\n }\n\n // Normal exit from processing loop\n if (!this.started) {\n this.log.info(\"Indexer manually stopped.\");\n return;\n }\n if (this.config.endHeight !== undefined && this.heightToProcess >= this.config.endHeight!) {\n this.log.info(\"Reached configured end height. Stopping indexer.\");\n this.stop();\n return;\n }\n\n // Abnormal exit\n if (this.retryCount < 3) {\n this.log.debug(\"Indexer retryCount: \" + this.retryCount);\n this.retryCount++;\n this.log.info(\"Indexer is restarting\");\n // Attempt recovery after brief delay\n setTimeout(() => this.start(),\n this.retryCount * 5000);\n }\n else {\n this.log.info(\"Indexer failed too many times. Exiting.\");\n this.emit(\"fatal-error\", {\n error: new Error(\"Max retry attempts exceeded\"),\n message: \"Indexer failed too many times\",\n retryCount: this.retryCount,\n });\n }\n }\n\n public asyncEmit: EmitFunc<keyof WithHeightAndUUID<EventMap>> = async (\n type,\n event,\n ) => {\n event.uuid = uuidv4();\n\n /*\n * More than 1 listener can be registered for an event type\n * Fortunately these are all set up during module init() so we have a consistent count\n * so we can count responses to resolve when complete\n * values are irrelevant as promise resolution is only used for flow control\n */\n let listenerCount = this.handled.get(type);\n if (!listenerCount) {\n // Setting listenerCount to 1 (the unhandled listener)\n listenerCount = 1;\n }\n let listenersResponded = 0;\n const prom = new Promise<void>((resolve, reject) => {\n const returnFunc = (ev: UUIDEvent) => {\n if (ev.uuid == event.uuid) {\n if (ev.status) {\n listenersResponded++;\n if (listenersResponded == listenerCount) {\n // All listeners have done their thing so we can remove listener, resolve and continue execution\n this.off(\"uuid\",\n returnFunc);\n resolve();\n }\n }\n else {\n // At least 1 listener is reporting an error. Reject and handle exception at the original asyncEmit location\n reject(ev.error);\n }\n }\n };\n this.on(\"uuid\",\n returnFunc);\n });\n this.emit(type,\n event);\n\n return prom;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private async processBlock(block: any, block_results: any, validators?: any) {\n const endTimer = this.prometheus?.timeBlockProcessing();\n const height = block.block.header.height;\n this.heightToProcess = height;\n this.log.debug(\"Processing block: %d\",\n height);\n // Initialize height & timestamp to be used for this block-processing run\n const timestamp = toRfc3339WithNanoseconds(block.block.header.time);\n\n // Use custom block processor if provided (for non-Cosmos SDK chains like Gno)\n if (this.config.processBlockFn) {\n await this.config.processBlockFn(block, block_results, {\n asyncEmit: this.asyncEmit,\n log: this.log,\n prometheus: this.prometheus,\n height,\n timestamp,\n }, validators);\n endTimer?.();\n this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());\n return;\n }\n\n // Default Cosmos SDK block processing logic\n\n // Use & await asyncEmit to ensure db insertions in order\n\n /*\n * Emit block information to any interested modules.\n * Primarily the required block module listens to this\n */\n await this.asyncEmit(\"block\",\n {\n value: {\n block,\n block_results,\n },\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled block event\");\n\n let beginBlockEvents: readonly Event[] | readonly Event38[];\n let endBlockEvents: readonly Event[] | readonly Event38[];\n if ((block_results as BlockResultsResponse38).finalizeBlockEvents) {\n beginBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"begin_block\")) as readonly Event38[];\n endBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"end_block\")) as readonly Event38[];\n }\n else {\n beginBlockEvents = (block_results as BlockResultsResponse).beginBlockEvents;\n endBlockEvents = (block_results as BlockResultsResponse).endBlockEvents;\n }\n // Deal with begin_block events first\n await this.asyncEmit(\"begin_block\",\n {\n value: {\n events: beginBlockEvents!,\n validators,\n },\n height,\n timestamp,\n });\n\n this.log.silly(\"Modules handled begin_block events\");\n\n // Then individual tx_events\n await this.asyncEmit(\"tx_events\",\n {\n value: block_results.results,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled tx events\");\n\n // Emit details and result for each tx msg separately\n for (let t = 0; t < block.block.txs.length; t++) {\n const tx = Tx.decode(block.block.txs[t]);\n\n const result = block_results.results[t].code;\n const txlog = block_results.results[t].log;\n\n if (result != 0) {\n // Tx failed. Ignore\n continue;\n }\n if (tx.body && tx.body.memo != \"\") {\n const txHash = createHash(\"sha256\").update(block.block.txs[t])\n .digest(\"hex\");\n await this.asyncEmit(\"tx_memo\",\n {\n value: {\n txHash,\n txBody: tx.body,\n },\n height,\n timestamp,\n });\n }\n // parsing log rather than using events directly in order to have msg_index available to filter appropriate events for each msg\n let events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }> = txlog\n ? JSON.parse(txlog)\n : [];\n if (events.length == 0) {\n const eventsToAdd: typeof events = [];\n this.log.silly(\"No events found in tx log. Parsing events for msg_index\");\n for (let m = 0; m < block_results.results[t].events.length; m++) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (block_results.results[t].events[m].attributes.find((a: any) => decodeAttr(a.key) == \"msg_index\")) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const mi = decodeAttr(block_results.results[t].events[m].attributes.find((a: any) => decodeAttr(a.key) == \"msg_index\")?.value ?? \"\");\n if (mi != \"\") {\n const miNum = parseInt(mi);\n let ev = eventsToAdd.find(x => x.msg_index == miNum);\n if (!ev) {\n ev = {\n msg_index: miNum,\n events: [block_results.results[t].events[m]],\n };\n eventsToAdd.push(ev);\n }\n else {\n ev.events.push(block_results.results[t].events[m] as Event);\n }\n }\n }\n }\n events = events.concat(eventsToAdd);\n }\n const msgs = tx.body?.messages;\n\n if (msgs) {\n for (let i = 0; i < msgs.length; i++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + msgs[i].typeUrl);\n const msgevents\n = msgs.length > 1\n ? events.find(x => x.msg_index == i)?.events\n : events[0].events;\n await this.asyncEmit(msgs[i].typeUrl as never,\n {\n value: {\n tx: msgs[i].value as never,\n events: msgevents,\n } as never,\n height,\n timestamp,\n });\n if (msgs[i].typeUrl == \"/cosmos.authz.v1beta1.MsgExec\") {\n const authzMsgs = MsgExec.decode(msgs[i].value).msgs;\n if (authzMsgs) {\n for (let r = 0; r < authzMsgs.length; r++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + authzMsgs[r].typeUrl);\n const authzMsgEvents = msgevents?.reduce((events, evt) => {\n if (evt.attributes.filter(x => decodeAttr(x.key) == \"authz_msg_index\" && decodeAttr(x.value) == \"\" + r).length > 0) {\n events.push(evt);\n }\n return events;\n },\n [] as (Event | Event38)[]);\n await this.asyncEmit(authzMsgs[r].typeUrl as never,\n {\n value: {\n tx: authzMsgs[r].value as never,\n events: authzMsgEvents,\n } as never,\n height,\n timestamp,\n });\n }\n }\n }\n }\n }\n }\n this.log.silly(\"Modules handled msg events\");\n this.prometheus?.recordTransactions(block.block.txs.length);\n // Then deal with end_block events\n await this.asyncEmit(\"end_block\",\n {\n value: endBlockEvents!,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled end_block events\");\n\n endTimer?.();\n this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());\n }\n\n private async fetcher() {\n for (let i = this.heightToProcess; i <= this.latestHeight; i++) {\n // If some other async process triggers recovery, exit the fetching loop\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n this.log.debug(\"Fetching: \" + i);\n try {\n // Main fetching logic for minimal indexer\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]> = new Promise((_resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([Promise.all([this.blockClient.block(i) as Promise<BlockResponse>, this.blockClient.blockResults(i) as Promise<BlockResultsResponse>]), timeoutPromise]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>;\n this.blockQueue.enqueue(toIndex);\n }\n else {\n // Main fetching logic for minimal indexer\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]> = new Promise((_resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: PAGINATION_LIMITS.VALIDATORS,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([\n Promise.all([\n this.blockClient.block(i) as Promise<BlockResponse>,\n this.blockClient.blockResults(i) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n i,\n false),\n ]),\n timeoutPromise,\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n this.blockQueue.enqueue(toIndex);\n }\n }\n catch (e) {\n this.log.error(\"Fetching error: \" + e);\n break;\n }\n await this.blockQueue.continue();\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n }\n // If we exit the fetching loop without errors, we are synced\n if (!this.tryToRecover) {\n this.blockQueue.setSynced();\n this.log.info(\"Synced to latest height\");\n }\n }\n\n public async callABCI(path: string, data: Uint8Array, height?: number, adHoc: boolean = true): Promise<Uint8Array> {\n try {\n const endTimer = this.prometheus?.timeRpcCall(path) ?? void 0;\n const abciq = await\n (adHoc\n ? this.client\n : this.blockClient).abciQuery({\n path,\n data,\n height: height,\n });\n endTimer?.();\n if (abciq) {\n return abciq.value;\n }\n else {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n catch (_e) {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n\n private newBlockReceived(height: number): void {\n if (this.blockTimeout) {\n clearTimeout(this.blockTimeout);\n }\n this.blockTimeout = setTimeout(() => {\n this.tryToRecover = true;\n }, 30000);\n this.log.info(\"Received new block: %d\",\n height);\n if (height == this.latestHeight) {\n return;\n }\n // If we are synced, add to end of queue\n if (this.blockQueue.synced && !this.tryToRecover) {\n this.latestHeight = height;\n if (this.blockQueue.size() + 1 == this.config.batchSize) {\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block queue is full. Cannot add new block\");\n this.tryToRecover = true;\n return;\n }\n try {\n if (this.isMinimal(this.blockQueue)) {\n this.blockQueue.enqueue(Promise.all([this.client.block(height) as Promise<BlockResponse>, this.client.blockResults(height) as Promise<BlockResultsResponse>]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>);\n }\n else {\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: 1000n,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n this.blockQueue.enqueue(Promise.all([\n this.client.block(height) as Promise<BlockResponse>,\n this.client.blockResults(height) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n height,\n false),\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>);\n }\n }\n catch (e) {\n this.log.error(\"New Block Received error: \" + e);\n }\n }\n else {\n this.latestHeight = height;\n }\n }\n\n private async pollForBlock() {\n try {\n const status = await this.client.status();\n if (status.syncInfo.latestBlockHeight > this.latestHeight) {\n while (this.latestHeight < status.syncInfo.latestBlockHeight) {\n this.newBlockReceived(this.latestHeight + 1);\n }\n }\n setTimeout(() => {\n this.pollForBlock();\n },\n this.config.pollingInterval);\n }\n catch (e) {\n this.log.error(\"Error polling for new block: \" + e);\n this.tryToRecover = true;\n }\n }\n\n private readGenesis(): Parser.Parser {\n if (this.config.genesisPath) {\n return fs.createReadStream(this.config.genesisPath).pipe(Parser.parser());\n }\n else {\n throw new Error(\"Genesis path not set\");\n }\n }\n\n private async setArrayReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n let counter = 0;\n let chunkCounter = 0;\n\n // Wrapper processor that handles transaction chunking\n const chunkProcessor = async (data: unknown) => {\n chunkCounter++;\n this.log.debug(`Processing genesis chunk ${chunkCounter}`);\n\n await processor(data);\n\n // Commit and restart transaction every 5 chunks (5000 entries)\n // This prevents timeout on large genesis files\n if (chunkCounter % 5 === 0) {\n this.log.debug(`Committing transaction after chunk ${chunkCounter}`);\n await this.config.endTransaction(true);\n await this.config.beginTransaction();\n }\n };\n\n chain([\n this.readGenesis(),\n ...pickers,\n StreamArray.streamArray(),\n Batch.batch({\n batchSize: GENESIS_BATCH_SIZE,\n }),\n chunkProcessor,\n ])\n .on(\"data\",\n (data) => {\n if (data && Array.isArray(data)) {\n counter = counter + data.length;\n }\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries in ${chunkCounter} chunks`);\n resolve(true);\n });\n }\n catch (_e) {\n this.log.verbose(\"Error in setArrayReader: \" + _e);\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async setValueReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n\n let counter = 0;\n chain([this.readGenesis(), ...pickers, StreamValues.streamValues(), processor])\n .on(\"data\",\n (_data) => {\n counter++;\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries`);\n resolve(true);\n });\n }\n catch (_e) {\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async parseGenesis() {\n this.log.info(\"Parsing genesis\");\n await this.config.beginTransaction();\n try {\n this.log.info(\"Starting genesis import\");\n this.log.debug(\"Importing genesis file...\");\n\n for (const [key, _value] of this.handled) {\n if (key.startsWith(\"genesis/\")) {\n const genesisEntry = key.split(\"/\");\n\n this.log.verbose(\"Importing \" + key + \"...\");\n if (genesisEntry[1] == \"array\") {\n await this.setArrayReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.map((x: {\n value: never\n }) => x.value),\n } as never);\n return data;\n });\n }\n else {\n await this.setValueReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.value,\n } as never);\n return data;\n });\n }\n }\n }\n\n this.log.info(\"Importing gen TXs...\");\n\n await this.setArrayReader(\"app_state.genutil.gen_txs\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n for (let j = 0; j < data.length; j++) {\n const gentx = data[j].value;\n for (let i = 0; i < gentx.body.messages.length; i++) {\n const msg = gentx.body.messages[i];\n await this.asyncEmit((\"gentx\" + msg[\"@type\"]) as never,\n {\n value: msg,\n } as never);\n }\n }\n return data;\n });\n await this.config.endTransaction(true);\n\n this.log.info(\"Finished importing\");\n }\n catch (e) {\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.log.error(\"Failed to import genesis\");\n throw e;\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/indexer/index.d.cts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { IndexerMetrics } from "../metrics/index.cjs";
|
|
2
2
|
import { EcleciaIndexerConfig, EmitFunc, WithHeightAndUUID } from "../types/index.cjs";
|
|
3
3
|
import { EclesiaEmitter } from "../emitter/index.cjs";
|
|
4
|
-
import { CometClient } from "@cosmjs/tendermint-rpc";
|
|
5
4
|
import * as winston from "winston";
|
|
6
5
|
|
|
7
6
|
//#region src/indexer/index.d.ts
|
|
@@ -49,10 +48,10 @@ declare class EcleciaIndexer extends EclesiaEmitter {
|
|
|
49
48
|
prometheus: IndexerMetrics | null;
|
|
50
49
|
/** Number of retry attempts for error recovery */
|
|
51
50
|
private retryCount;
|
|
52
|
-
/**
|
|
53
|
-
client:
|
|
54
|
-
/**
|
|
55
|
-
blockClient:
|
|
51
|
+
/** RPC client for ad-hoc queries (CometClient or custom client via connectFn) */
|
|
52
|
+
client: any;
|
|
53
|
+
/** RPC client for block and validator queries (CometClient or custom client via connectFn) */
|
|
54
|
+
blockClient: any;
|
|
56
55
|
/** Winston logger instance */
|
|
57
56
|
log: winston.Logger;
|
|
58
57
|
/** Flag indicating if indexer should attempt recovery */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/indexer/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/indexer/index.ts"],"sourcesContent":[],"mappings":";;;;;;;cAoEa;EAAA,WAAA,EAAA,MAAA;EAKS,SAAA,EAAA,MAAA;;;EAWa,QAAA,EAXb,oBAWa,CAAA,UAAA,CAAA;EAAA,UAAA,EAAA,OAAA;EAOtB,eAAA,EAAe,MAAA;EAEX,oBAAA,EAAA,GAAA,GAAA,OAAA;EAwBI,OAAA,EAAA,OAAA;EAcP,iBAAQ,EAAA,OAAA;EAqBA,eAAA,EAAA,MAAA;EAoLA,gBAAA,EAAA,OAAA;EAyHF,cAAA,EAAA,MAAA;EAoJiC,IAAA,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;EAAlB,gBAAA,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;EAAf,cAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,GArgBe,OAqgBf,CAAA,IAAA,CAAA;CAuTwB;;;;;cArzB/B,cAAA,SAAuB,cAAA;;UAEnB;;;;;;;;;;;;;;;;cAwBI;;;;;;;;OAcP,OAAA,CAAQ;;;;;;;;;;;;;sBAqBA;;;;aAoLA;;;;;WAyHF;aAoJA,eAAe,kBAAkB;;;+BAuTT,+CAAqD,QAAQ"}
|
package/dist/indexer/index.d.mts
CHANGED
|
@@ -1,7 +1,6 @@
|
|
|
1
1
|
import { IndexerMetrics } from "../metrics/index.mjs";
|
|
2
2
|
import { EcleciaIndexerConfig, EmitFunc, WithHeightAndUUID } from "../types/index.mjs";
|
|
3
3
|
import { EclesiaEmitter } from "../emitter/index.mjs";
|
|
4
|
-
import { CometClient } from "@cosmjs/tendermint-rpc";
|
|
5
4
|
import * as winston from "winston";
|
|
6
5
|
|
|
7
6
|
//#region src/indexer/index.d.ts
|
|
@@ -49,10 +48,10 @@ declare class EcleciaIndexer extends EclesiaEmitter {
|
|
|
49
48
|
prometheus: IndexerMetrics | null;
|
|
50
49
|
/** Number of retry attempts for error recovery */
|
|
51
50
|
private retryCount;
|
|
52
|
-
/**
|
|
53
|
-
client:
|
|
54
|
-
/**
|
|
55
|
-
blockClient:
|
|
51
|
+
/** RPC client for ad-hoc queries (CometClient or custom client via connectFn) */
|
|
52
|
+
client: any;
|
|
53
|
+
/** RPC client for block and validator queries (CometClient or custom client via connectFn) */
|
|
54
|
+
blockClient: any;
|
|
56
55
|
/** Winston logger instance */
|
|
57
56
|
log: winston.Logger;
|
|
58
57
|
/** Flag indicating if indexer should attempt recovery */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/indexer/index.ts"],"sourcesContent":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/indexer/index.ts"],"sourcesContent":[],"mappings":";;;;;;;cAoEa;EAAA,WAAA,EAAA,MAAA;EAKS,SAAA,EAAA,MAAA;;;EAWa,QAAA,EAXb,oBAWa,CAAA,UAAA,CAAA;EAAA,UAAA,EAAA,OAAA;EAOtB,eAAA,EAAe,MAAA;EAEX,oBAAA,EAAA,GAAA,GAAA,OAAA;EAwBI,OAAA,EAAA,OAAA;EAcP,iBAAQ,EAAA,OAAA;EAqBA,eAAA,EAAA,MAAA;EAoLA,gBAAA,EAAA,OAAA;EAyHF,cAAA,EAAA,MAAA;EAoJiC,IAAA,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;EAAlB,gBAAA,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;EAAf,cAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,GArgBe,OAqgBf,CAAA,IAAA,CAAA;CAuTwB;;;;;cArzB/B,cAAA,SAAuB,cAAA;;UAEnB;;;;;;;;;;;;;;;;cAwBI;;;;;;;;OAcP,OAAA,CAAQ;;;;;;;;;;;;;sBAqBA;;;;aAoLA;;;;;WAyHF;aAoJA,eAAe,kBAAkB;;;+BAuTT,+CAAqD,QAAQ"}
|
package/dist/indexer/index.mjs
CHANGED
|
@@ -67,9 +67,9 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
67
67
|
prometheus = null;
|
|
68
68
|
/** Number of retry attempts for error recovery */
|
|
69
69
|
retryCount = 0;
|
|
70
|
-
/**
|
|
70
|
+
/** RPC client for ad-hoc queries (CometClient or custom client via connectFn) */
|
|
71
71
|
client;
|
|
72
|
-
/**
|
|
72
|
+
/** RPC client for block and validator queries (CometClient or custom client via connectFn) */
|
|
73
73
|
blockClient;
|
|
74
74
|
/** Winston logger instance */
|
|
75
75
|
log;
|
|
@@ -191,12 +191,13 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
191
191
|
this.blockClient.disconnect();
|
|
192
192
|
this.log.verbose("Disconnected from RPC");
|
|
193
193
|
}
|
|
194
|
-
const
|
|
194
|
+
const connectFn = this.config.connectFn ?? connectComet;
|
|
195
|
+
const connectTimeoutPromise = new Promise((_resolve, reject) => {
|
|
195
196
|
setTimeout(reject, CONNECT_TIMEOUT_MS, []);
|
|
196
197
|
});
|
|
197
|
-
this.client = await Promise.race([
|
|
198
|
+
this.client = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);
|
|
198
199
|
this.log.info("Connected to RPC for ad hoc queries");
|
|
199
|
-
this.blockClient = await Promise.race([
|
|
200
|
+
this.blockClient = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);
|
|
200
201
|
this.log.info("Connected to RPC for block & validator info");
|
|
201
202
|
return true;
|
|
202
203
|
} catch (error) {
|
|
@@ -248,7 +249,7 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
248
249
|
this.log.verbose("Removed existing block listener and subscription");
|
|
249
250
|
}
|
|
250
251
|
if (!this.config.usePolling) this.subscription = this.client.subscribeNewBlock ? this.client.subscribeNewBlock() : null;
|
|
251
|
-
const statusPromise = new Promise((
|
|
252
|
+
const statusPromise = new Promise((_resolve, reject) => {
|
|
252
253
|
setTimeout(reject, RPC_TIMEOUT_MS, false);
|
|
253
254
|
});
|
|
254
255
|
this.latestHeight = (await Promise.race([this.client.status(), statusPromise])).syncInfo.latestBlockHeight;
|
|
@@ -257,8 +258,9 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
257
258
|
if (this.config.usePolling) this.pollForBlock();
|
|
258
259
|
else if (this.subscription) this.subscription.addListener(this.blockListener);
|
|
259
260
|
else {
|
|
260
|
-
this.
|
|
261
|
-
|
|
261
|
+
this.log.info("WebSocket subscription not available, falling back to polling");
|
|
262
|
+
this.config.usePolling = true;
|
|
263
|
+
this.pollForBlock();
|
|
262
264
|
}
|
|
263
265
|
} catch (e) {
|
|
264
266
|
this.log.error("Failed to set up block listening: " + e);
|
|
@@ -288,7 +290,7 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
288
290
|
this.log.silly("Started db tx");
|
|
289
291
|
let height, timestamp;
|
|
290
292
|
if (this.isMinimal(this.blockQueue)) {
|
|
291
|
-
const timeoutPromise = new Promise((
|
|
293
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
292
294
|
setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);
|
|
293
295
|
});
|
|
294
296
|
const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);
|
|
@@ -298,7 +300,7 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
298
300
|
timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);
|
|
299
301
|
await this.processBlock(toProcess[0], toProcess[1]);
|
|
300
302
|
} else {
|
|
301
|
-
const timeoutPromise = new Promise((
|
|
303
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
302
304
|
setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);
|
|
303
305
|
});
|
|
304
306
|
const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);
|
|
@@ -338,7 +340,6 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
338
340
|
this.log.error("Error ending transaction. Must be a DB error: " + dbe);
|
|
339
341
|
}
|
|
340
342
|
this.tryToRecover = true;
|
|
341
|
-
this.retryCount++;
|
|
342
343
|
break;
|
|
343
344
|
}
|
|
344
345
|
this.retryCount = 0;
|
|
@@ -393,6 +394,18 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
393
394
|
this.heightToProcess = height;
|
|
394
395
|
this.log.debug("Processing block: %d", height);
|
|
395
396
|
const timestamp = toRfc3339WithNanoseconds(block.block.header.time);
|
|
397
|
+
if (this.config.processBlockFn) {
|
|
398
|
+
await this.config.processBlockFn(block, block_results, {
|
|
399
|
+
asyncEmit: this.asyncEmit,
|
|
400
|
+
log: this.log,
|
|
401
|
+
prometheus: this.prometheus,
|
|
402
|
+
height,
|
|
403
|
+
timestamp
|
|
404
|
+
}, validators);
|
|
405
|
+
endTimer?.();
|
|
406
|
+
this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());
|
|
407
|
+
return;
|
|
408
|
+
}
|
|
396
409
|
await this.asyncEmit("block", {
|
|
397
410
|
value: {
|
|
398
411
|
block,
|
|
@@ -514,7 +527,7 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
514
527
|
this.log.debug("Fetching: " + i);
|
|
515
528
|
try {
|
|
516
529
|
if (this.isMinimal(this.blockQueue)) {
|
|
517
|
-
const timeoutPromise = new Promise((
|
|
530
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
518
531
|
setTimeout(reject, RPC_TIMEOUT_MS, false);
|
|
519
532
|
});
|
|
520
533
|
const toIndex = Promise.race([Promise.all([this.blockClient.block(i), this.blockClient.blockResults(i)]), timeoutPromise]).catch((e) => {
|
|
@@ -525,7 +538,7 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
525
538
|
});
|
|
526
539
|
this.blockQueue.enqueue(toIndex);
|
|
527
540
|
} else {
|
|
528
|
-
const timeoutPromise = new Promise((
|
|
541
|
+
const timeoutPromise = new Promise((_resolve, reject) => {
|
|
529
542
|
setTimeout(reject, RPC_TIMEOUT_MS, false);
|
|
530
543
|
});
|
|
531
544
|
const q = QueryValidatorsRequest.fromPartial({ pagination: { limit: PAGINATION_LIMITS.VALIDATORS } });
|
|
@@ -575,7 +588,6 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
575
588
|
} catch (_e) {
|
|
576
589
|
this.tryToRecover = true;
|
|
577
590
|
this.setStatus("FAILED");
|
|
578
|
-
this.retryCount++;
|
|
579
591
|
throw new Error("RPC not responding. Query at: " + path);
|
|
580
592
|
}
|
|
581
593
|
}
|
|
@@ -592,7 +604,6 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
592
604
|
this.prometheus?.recordError("block");
|
|
593
605
|
this.log.error("Block queue is full. Cannot add new block");
|
|
594
606
|
this.tryToRecover = true;
|
|
595
|
-
this.retryCount++;
|
|
596
607
|
return;
|
|
597
608
|
}
|
|
598
609
|
try {
|
|
@@ -627,7 +638,6 @@ var EcleciaIndexer = class extends EclesiaEmitter {
|
|
|
627
638
|
} catch (e) {
|
|
628
639
|
this.log.error("Error polling for new block: " + e);
|
|
629
640
|
this.tryToRecover = true;
|
|
630
|
-
this.retryCount++;
|
|
631
641
|
}
|
|
632
642
|
}
|
|
633
643
|
readGenesis() {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":["statusPromise: Promise<StatusResponse>","timeoutPromise: ReturnType<typeof this.blockQueue.dequeue>","uuidv4","beginBlockEvents: readonly Event[] | readonly Event38[]","endBlockEvents: readonly Event[] | readonly Event38[]","events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }>","eventsToAdd: typeof events","events","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]>","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>"],"sources":["../../src/indexer/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\n/* eslint-disable max-lines */\nimport {\n createHash,\n} from \"node:crypto\";\nimport * as fs from \"node:fs\";\n\nimport {\n BlockResponse, BlockResultsResponse, CometClient, connectComet, Event, StatusResponse, toRfc3339WithNanoseconds,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event as Event38,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses.js\";\nimport {\n MsgExec,\n} from \"cosmjs-types/cosmos/authz/v1beta1/tx.js\";\nimport {\n QueryValidatorsRequest,\n QueryValidatorsResponse,\n} from \"cosmjs-types/cosmos/staking/v1beta1/query.js\";\nimport {\n Validator,\n} from \"cosmjs-types/cosmos/staking/v1beta1/staking.js\";\nimport {\n Tx,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx.js\";\nimport Fastify, {\n FastifyInstance,\n} from \"fastify\";\nimport {\n chain,\n} from \"stream-chain\";\nimport Parser from \"stream-json\";\nimport Pick from \"stream-json/filters/Pick.js\";\nimport StreamArray from \"stream-json/streamers/StreamArray.js\";\nimport StreamValues from \"stream-json/streamers/StreamValues.js\";\nimport Batch from \"stream-json/utils/Batch.js\";\nimport {\n v4 as uuidv4,\n} from \"uuid\";\nimport * as winston from \"winston\";\n\nimport {\n CONNECT_TIMEOUT_MS,\n DEFAULT_BATCH_SIZE, DEFAULT_HEALTH_CHECK_PORT, DEFAULT_POLLING_INTERVAL_MS, DEFAULT_PROMETHEUS_PORT, DEFAULT_START_HEIGHT,\n GENESIS_BATCH_SIZE, PAGINATION_LIMITS, PERIODIC_INTERVALS, QUEUE_DEQUEUE_TIMEOUT_MS, RPC_TIMEOUT_MS,\n} from \"../constants.js\";\nimport {\n EclesiaEmitter,\n} from \"../emitter/index.js\";\nimport {\n RPCError,\n} from \"../errors/index.js\";\nimport {\n IndexerMetrics,\n} from \"../metrics/index.js\";\nimport {\n CircularBuffer,\n} from \"../promise-queue/index.js\";\nimport {\n BlockQueue, EcleciaIndexerConfig, EmitFunc, MinimalBlockQueue,\n UUIDEvent, WithHeightAndUUID,\n} from \"../types/index.js\";\nimport {\n decodeAttr,\n} from \"../utils/index.js\";\nimport {\n validateFilePath, validatePort, validatePositiveInteger, validateUrl,\n} from \"../validation/index.js\";\n\n/** Default configuration for the Eclesia indexer */\nexport const defaultIndexerConfig = {\n startHeight: DEFAULT_START_HEIGHT, // Start indexing from block 1\n batchSize: DEFAULT_BATCH_SIZE, // Process blocks in batches of 500\n modules: [], // No modules enabled by default\n getNextHeight: () => DEFAULT_START_HEIGHT, // Default height retrieval function\n logLevel: \"info\" as EcleciaIndexerConfig[\"logLevel\"], // Default log level\n usePolling: false, // Use WebSocket subscription by default\n pollingInterval: DEFAULT_POLLING_INTERVAL_MS, // Poll every 5 seconds when polling enabled\n shouldProcessGenesis: () => false, // Skip genesis processing by default\n minimal: true, // Use minimal indexing by default\n enableHealthcheck: true, // Enable health check server by default\n healthCheckPort: DEFAULT_HEALTH_CHECK_PORT, // Default health check port\n enablePrometheus: false, // Disable Prometheus metrics server by default\n prometheusPort: DEFAULT_PROMETHEUS_PORT, // Default Prometheus metrics server port\n init: () => Promise.resolve(), // No-op initialization function\n beginTransaction: () => Promise.resolve(), // No-op transaction begin function\n endTransaction: (_status: boolean) => Promise.resolve(), // No-op transaction end function\n};\n\n/**\n * Core blockchain indexer that connects to Tendermint RPC and processes blocks\n * Extends EclesiaEmitter to provide event-driven architecture for modules\n */\nexport class EcleciaIndexer extends EclesiaEmitter {\n /** Indexer configuration settings */\n public config: EcleciaIndexerConfig;\n\n /** Fastify HTTP server for health checks */\n private fastify: FastifyInstance | null = null;\n\n /** Prometheus HTTP server instance */\n private prometheusServer: FastifyInstance | null = null;\n\n /** Indicates if the indexer has started */\n private started: boolean = false;\n\n /** Queue for managing block processing pipeline */\n private blockQueue: BlockQueue;\n\n /** Latest block height from the chain */\n private latestHeight!: number;\n\n /** Next block height to process */\n public heightToProcess!: number;\n\n /** Whether the indexer has been initialized */\n private initialized = false;\n\n /** Prometheus metrics server instance */\n public prometheus: IndexerMetrics | null = null;\n\n /** Number of retry attempts for error recovery */\n private retryCount = 0;\n\n /** CometBFT client for ad-hoc queries */\n public client!: CometClient;\n\n /** CometBFT client for block and validator queries */\n public blockClient!: CometClient;\n\n /** Winston logger instance */\n public log: winston.Logger;\n\n /** Flag indicating if indexer should attempt recovery */\n private tryToRecover: boolean = false;\n\n /** Health check status for monitoring */\n private healthCheck = {\n status: \"CONNECTING\",\n };\n\n /** WebSocket subscription for new block notifications */\n private subscription: ReturnType<CometClient[\"subscribeNewBlock\"]> | null = null;\n\n /** Timeout handler for block reception */\n private blockTimeout: NodeJS.Timeout | null = null;\n\n /**\n * Creates a new Eclesia indexer instance\n * @param config - Indexer configuration options\n */\n constructor(config: EcleciaIndexerConfig) {\n super();\n\n // Validate required configuration\n validateUrl(config.rpcUrl, \"rpcUrl\");\n validatePositiveInteger(config.batchSize, \"batchSize\");\n\n // Validate optional genesis path if processing genesis\n if (config.genesisPath) {\n validateFilePath(config.genesisPath, \"genesisPath\");\n }\n\n // Validate health check port if provided\n if (config.healthCheckPort !== undefined) {\n validatePort(config.healthCheckPort, \"healthCheckPort\");\n }\n\n // Validate prometheus port if provided\n if (config.prometheusPort !== undefined) {\n validatePort(config.prometheusPort, \"prometheusPort\");\n }\n\n // Validate start height if provided\n if (config.startHeight !== undefined) {\n validatePositiveInteger(config.startHeight, \"startHeight\");\n }\n\n // Validate polling interval if provided\n if (config.pollingInterval !== undefined) {\n validatePositiveInteger(config.pollingInterval, \"pollingInterval\");\n }\n\n this.config = {\n ...defaultIndexerConfig,\n ...config,\n };\n\n // Initialize logger first so it can be used by queue error handler\n const {\n printf,\n } = winston.format;\n\n const eclesiaFormat = printf(({\n level, message, timestamp,\n }) => {\n return `${timestamp} [${level.toUpperCase()}]:\\t${message}`;\n });\n this.log = winston.createLogger({\n level: this.config.logLevel,\n defaultMeta: {\n service: \"Eclesia Indexer\",\n },\n transports: [\n new winston.transports.File({\n filename: \"error.log\",\n level: \"error\",\n }),\n new winston.transports.File({\n filename: \"combined.log\",\n }),\n new winston.transports.Console({\n format: winston.format.combine(winston.format.splat(),\n winston.format.timestamp(),\n eclesiaFormat,\n winston.format.colorize({\n all: true,\n })),\n }),\n ],\n });\n\n // Initialize block queue based on minimal or full indexing mode\n // Pass error handler that uses the logger\n const queueErrorHandler = (e: unknown) => {\n this.prometheus?.recordError(\"rpc\");\n this.log.error(\"Error enqueueing block data: \" + e);\n };\n\n if (this.config.minimal) {\n // Minimal mode: only store block and block results\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse]>(this.config.batchSize, queueErrorHandler);\n }\n else {\n // Full mode: also store validator information\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>(this.config.batchSize, queueErrorHandler);\n }\n\n this.on(\"_unhandled\",\n (msg) => {\n if (msg.uuid) {\n this.log.verbose(\"Unhandled event: \" + msg.type);\n this.emit(\"uuid\",\n {\n status: true,\n uuid: msg.uuid,\n });\n }\n });\n if (this.config.enablePrometheus) {\n this.prometheus = new IndexerMetrics();\n this.prometheusServer = Fastify({\n logger: false,\n });\n this.prometheusServer.get(\"/metrics\",\n async (_req, res) => {\n res.header(\"Content-Type\", this.prometheus!.registry.contentType);\n res.send(await this.prometheus!.getMetrics());\n },\n );\n\n const prometheusPort = this.config.prometheusPort\n ?? (process.env.PROMETHEUS_PORT ? parseInt(process.env.PROMETHEUS_PORT, 10) : DEFAULT_PROMETHEUS_PORT);\n this.prometheusServer.listen({\n port: prometheusPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Prometheus error: \" + err);\n this.prometheus?.recordError(\"metrics_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start metrics server\",\n });\n }\n });\n }\n if (this.config.enableHealthcheck) {\n this.fastify = Fastify({\n logger: false,\n });\n this.fastify.get(\"/health\",\n async (_request, reply) => {\n const code = this.healthCheck.status == \"OK\"\n ? 200\n : 503;\n reply.code(code).send(this.healthCheck);\n });\n const healthPort = this.config.healthCheckPort\n ?? (process.env.HEALTH_CHECK_PORT ? parseInt(process.env.HEALTH_CHECK_PORT, 10) : DEFAULT_HEALTH_CHECK_PORT);\n this.fastify.listen({\n port: healthPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Health check server error: \" + err);\n this.prometheus?.recordError(\"health_check_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start health check server\",\n });\n }\n });\n }\n }\n\n private setStatus(status: string) {\n this.healthCheck.status = status;\n }\n\n private blockListener = {\n next: (data: {\n header: {\n height: number\n }\n }) => {\n this.newBlockReceived(data.header.height);\n },\n };\n\n private isMinimal(_blockqueue: BlockQueue): _blockqueue is MinimalBlockQueue {\n if (this.config.minimal) {\n return true;\n }\n else {\n return false;\n }\n }\n\n public async connect() {\n try {\n if (this.client && this.tryToRecover) {\n this.log.verbose(\"Recover from error. Attempting to disconnect from RPC\");\n this.client.disconnect();\n this.blockClient.disconnect();\n this.log.verbose(\"Disconnected from RPC\");\n }\n const connectTimeoutPromise = new Promise<ReturnType<typeof connectComet>>((resolve, reject) => {\n setTimeout(reject, CONNECT_TIMEOUT_MS, []);\n });\n this.client = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for ad hoc queries\");\n this.blockClient = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for block & validator info\");\n\n return true;\n }\n catch (error) {\n this.log.error(\"RPC connection error: \" + error);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return false;\n }\n }\n\n private async initialize() {\n if (!this.initialized) {\n try {\n if (this.config.init) {\n await this.config.init();\n }\n }\n catch (e) {\n this.log.error(\"Failed to initialize indexer: \" + e);\n\n this.prometheus?.recordError(\"init_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n if (await this.config.shouldProcessGenesis()) {\n try {\n if (this.config.genesisPath) {\n await this.parseGenesis();\n }\n }\n catch (e) {\n this.log.error(\"Failed to parse genesis: \" + e);\n\n this.prometheus?.recordError(\"genesis_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n this.initialized = true;\n }\n }\n\n public stop() {\n this.started = false;\n }\n\n private clearBlockQueue() {\n if (this.blockQueue) {\n this.blockQueue.clear();\n this.log.verbose(\"Starting, clearing block queue\");\n }\n }\n\n private async setupBlockListening() {\n const connected = await this.connect();\n if (!connected) {\n this.setStatus(\"FAILED\");\n throw new RPCError(\"Failed to connect to RPC\");\n }\n\n try {\n if (!this.config.usePolling && this.subscription) {\n this.subscription.removeListener(this.blockListener);\n this.subscription = null;\n this.log.verbose(\"Removed existing block listener and subscription\");\n }\n if (!this.config.usePolling) {\n this.subscription = this.client.subscribeNewBlock\n ? this.client.subscribeNewBlock()\n : null;\n }\n const statusPromise: Promise<StatusResponse> = new Promise((resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const status = await Promise.race([this.client.status(), statusPromise]);\n this.latestHeight = status.syncInfo.latestBlockHeight;\n this.log.info(\"Current chain height: \" + this.latestHeight);\n\n this.heightToProcess = await this.config.getNextHeight();\n if (this.config.usePolling) {\n this.pollForBlock();\n }\n else {\n if (this.subscription) {\n this.subscription.addListener(this.blockListener);\n }\n else {\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"Could not subscribe to new blocks\");\n }\n }\n }\n catch (e) {\n this.log.error(\"Failed to set up block listening: \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n\n public async start() {\n this.started = true;\n this.clearBlockQueue();\n await this.initialize();\n try {\n await this.setupBlockListening();\n this.log.debug(\"Starting main processing loop\");\n this.tryToRecover = false;\n this.fetcher().catch((e) => {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"Error in fetching service: \" + e);\n });\n }\n catch (_e) {\n // Continue and attempt to recover\n }\n\n while (\n this.started // break out when stopped\n && !this.tryToRecover // break out for recoverable errors\n && (this.config.endHeight === undefined || this.heightToProcess <= this.config.endHeight) // break out if end height configured and reached\n && this.blockQueue.size() > 0 // break out if no blocks to process\n ) {\n // await the dequeued promise is essentially awaiting fetched data for that block\n try {\n this.prometheus?.updateRetryCount(this.retryCount);\n // Index block inside a db transaction to ensure data consistency\n await this.config.beginTransaction();\n this.log.silly(\"Started db tx\");\n let height, timestamp;\n\n // Main block processing (minimal)\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1]) {\n throw new RPCError(\"Could not fetch block(minimal)\");\n }\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1]);\n }\n // Main block processing (full)\n else {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1] || !toProcess[2]) {\n throw new RPCError(\"Could not fetch block(full)\");\n }\n\n this.log.silly(\"Decoded block\");\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1],\n QueryValidatorsResponse.decode(toProcess[2]).validators);\n }\n\n // Emit events to trigger periodic operations every 50, 100 and 1000 blocks\n if (height % PERIODIC_INTERVALS.LARGE == 0) {\n await this.asyncEmit(\"periodic/large\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.MEDIUM == 0) {\n await this.asyncEmit(\"periodic/medium\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.SMALL == 0) {\n await this.asyncEmit(\"periodic/small\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n this.log.silly(\"Handled periodic events\");\n\n await this.config.endTransaction(true);\n\n this.log.silly(\"Committed db tx\");\n }\n catch (e) {\n // any error here is likely recoverable (e.g. RPC timeout, DB error)\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block processing error: \" + e);\n this.setStatus(\"FAILED\");\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.tryToRecover = true;\n this.retryCount++;\n // Exit processing loop to attempt recovery\n break;\n }\n // Reset retry count and status on successful block processing\n this.retryCount = 0;\n this.setStatus(\"OK\");\n }\n\n // Normal exit from processing loop\n if (!this.started) {\n this.log.info(\"Indexer manually stopped.\");\n return;\n }\n if (this.config.endHeight !== undefined && this.heightToProcess >= this.config.endHeight!) {\n this.log.info(\"Reached configured end height. Stopping indexer.\");\n this.stop();\n return;\n }\n\n // Abnormal exit\n if (this.retryCount < 3) {\n this.log.debug(\"Indexer retryCount: \" + this.retryCount);\n this.retryCount++;\n this.log.info(\"Indexer is restarting\");\n // Attempt recovery after brief delay\n setTimeout(() => this.start(),\n this.retryCount * 5000);\n }\n else {\n this.log.info(\"Indexer failed too many times. Exiting.\");\n this.emit(\"fatal-error\", {\n error: new Error(\"Max retry attempts exceeded\"),\n message: \"Indexer failed too many times\",\n retryCount: this.retryCount,\n });\n }\n }\n\n public asyncEmit: EmitFunc<keyof WithHeightAndUUID<EventMap>> = async (\n type,\n event,\n ) => {\n event.uuid = uuidv4();\n\n /*\n * More than 1 listener can be registered for an event type\n * Fortunately these are all set up during module init() so we have a consistent count\n * so we can count responses to resolve when complete\n * values are irrelevant as promise resolution is only used for flow control\n */\n let listenerCount = this.handled.get(type);\n if (!listenerCount) {\n // Setting listenerCount to 1 (the unhandled listener)\n listenerCount = 1;\n }\n let listenersResponded = 0;\n const prom = new Promise<void>((resolve, reject) => {\n const returnFunc = (ev: UUIDEvent) => {\n if (ev.uuid == event.uuid) {\n if (ev.status) {\n listenersResponded++;\n if (listenersResponded == listenerCount) {\n // All listeners have done their thing so we can remove listener, resolve and continue execution\n this.off(\"uuid\",\n returnFunc);\n resolve();\n }\n }\n else {\n // At least 1 listener is reporting an error. Reject and handle exception at the original asyncEmit location\n reject(ev.error);\n }\n }\n };\n this.on(\"uuid\",\n returnFunc);\n });\n this.emit(type,\n event);\n\n return prom;\n };\n\n private async processBlock(block: BlockResponse, block_results: BlockResultsResponse | BlockResultsResponse38, validators?: Validator[]) {\n const endTimer = this.prometheus?.timeBlockProcessing();\n const height = block.block.header.height;\n this.heightToProcess = height;\n this.log.debug(\"Processing block: %d\",\n height);\n // Initialize height & timestamp to be used for this block-processing run\n const timestamp = toRfc3339WithNanoseconds(block.block.header.time);\n\n // Use & await asyncEmit to ensure db insertions in order\n\n /*\n * Emit block information to any interested modules.\n * Primarily the required block module listens to this\n */\n await this.asyncEmit(\"block\",\n {\n value: {\n block,\n block_results,\n },\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled block event\");\n\n let beginBlockEvents: readonly Event[] | readonly Event38[];\n let endBlockEvents: readonly Event[] | readonly Event38[];\n if ((block_results as BlockResultsResponse38).finalizeBlockEvents) {\n beginBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"begin_block\")) as readonly Event38[];\n endBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"end_block\")) as readonly Event38[];\n }\n else {\n beginBlockEvents = (block_results as BlockResultsResponse).beginBlockEvents;\n endBlockEvents = (block_results as BlockResultsResponse).endBlockEvents;\n }\n // Deal with begin_block events first\n await this.asyncEmit(\"begin_block\",\n {\n value: {\n events: beginBlockEvents!,\n validators,\n },\n height,\n timestamp,\n });\n\n this.log.silly(\"Modules handled begin_block events\");\n\n // Then individual tx_events\n await this.asyncEmit(\"tx_events\",\n {\n value: block_results.results,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled tx events\");\n\n // Emit details and result for each tx msg separately\n for (let t = 0; t < block.block.txs.length; t++) {\n const tx = Tx.decode(block.block.txs[t]);\n\n const result = block_results.results[t].code;\n const txlog = block_results.results[t].log;\n\n if (result != 0) {\n // Tx failed. Ignore\n continue;\n }\n if (tx.body && tx.body.memo != \"\") {\n const txHash = createHash(\"sha256\").update(block.block.txs[t])\n .digest(\"hex\");\n await this.asyncEmit(\"tx_memo\",\n {\n value: {\n txHash,\n txBody: tx.body,\n },\n height,\n timestamp,\n });\n }\n // parsing log rather than using events directly in order to have msg_index available to filter appropriate events for each msg\n let events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }> = txlog\n ? JSON.parse(txlog)\n : [];\n if (events.length == 0) {\n const eventsToAdd: typeof events = [];\n this.log.silly(\"No events found in tx log. Parsing events for msg_index\");\n for (let m = 0; m < block_results.results[t].events.length; m++) {\n if (block_results.results[t].events[m].attributes.find(a => decodeAttr(a.key) == \"msg_index\")) {\n const mi = decodeAttr(block_results.results[t].events[m].attributes.find(a => decodeAttr(a.key) == \"msg_index\")?.value ?? \"\");\n if (mi != \"\") {\n const miNum = parseInt(mi);\n let ev = eventsToAdd.find(x => x.msg_index == miNum);\n if (!ev) {\n ev = {\n msg_index: miNum,\n events: [block_results.results[t].events[m]],\n };\n eventsToAdd.push(ev);\n }\n else {\n ev.events.push(block_results.results[t].events[m] as Event);\n }\n }\n }\n }\n events = events.concat(eventsToAdd);\n }\n const msgs = tx.body?.messages;\n\n if (msgs) {\n for (let i = 0; i < msgs.length; i++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + msgs[i].typeUrl);\n const msgevents\n = msgs.length > 1\n ? events.find(x => x.msg_index == i)?.events\n : events[0].events;\n await this.asyncEmit(msgs[i].typeUrl as never,\n {\n value: {\n tx: msgs[i].value as never,\n events: msgevents,\n } as never,\n height,\n timestamp,\n });\n if (msgs[i].typeUrl == \"/cosmos.authz.v1beta1.MsgExec\") {\n const authzMsgs = MsgExec.decode(msgs[i].value).msgs;\n if (authzMsgs) {\n for (let r = 0; r < authzMsgs.length; r++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + authzMsgs[r].typeUrl);\n const authzMsgEvents = msgevents?.reduce((events, evt) => {\n if (evt.attributes.filter(x => decodeAttr(x.key) == \"authz_msg_index\" && decodeAttr(x.value) == \"\" + r).length > 0) {\n events.push(evt);\n }\n return events;\n },\n [] as (Event | Event38)[]);\n await this.asyncEmit(authzMsgs[r].typeUrl as never,\n {\n value: {\n tx: authzMsgs[r].value as never,\n events: authzMsgEvents,\n } as never,\n height,\n timestamp,\n });\n }\n }\n }\n }\n }\n }\n this.log.silly(\"Modules handled msg events\");\n this.prometheus?.recordTransactions(block.block.txs.length);\n // Then deal with end_block events\n await this.asyncEmit(\"end_block\",\n {\n value: endBlockEvents!,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled end_block events\");\n\n endTimer?.();\n this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());\n }\n\n private async fetcher() {\n for (let i = this.heightToProcess; i <= this.latestHeight; i++) {\n // If some other async process triggers recovery, exit the fetching loop\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n this.log.debug(\"Fetching: \" + i);\n try {\n // Main fetching logic for minimal indexer\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]> = new Promise((resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([Promise.all([this.blockClient.block(i) as Promise<BlockResponse>, this.blockClient.blockResults(i) as Promise<BlockResultsResponse>]), timeoutPromise]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>;\n this.blockQueue.enqueue(toIndex);\n }\n else {\n // Main fetching logic for minimal indexer\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]> = new Promise((resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: PAGINATION_LIMITS.VALIDATORS,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([\n Promise.all([\n this.blockClient.block(i) as Promise<BlockResponse>,\n this.blockClient.blockResults(i) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n i,\n false),\n ]),\n timeoutPromise,\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n this.blockQueue.enqueue(toIndex);\n }\n }\n catch (e) {\n this.log.error(\"Fetching error: \" + e);\n break;\n }\n await this.blockQueue.continue();\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n }\n // If we exit the fetching loop without errors, we are synced\n if (!this.tryToRecover) {\n this.blockQueue.setSynced();\n this.log.info(\"Synced to latest height\");\n }\n }\n\n public async callABCI(path: string, data: Uint8Array, height?: number, adHoc: boolean = true): Promise<Uint8Array> {\n try {\n const endTimer = this.prometheus?.timeRpcCall(path) ?? void 0;\n const abciq = await\n (adHoc\n ? this.client\n : this.blockClient).abciQuery({\n path,\n data,\n height: height,\n });\n endTimer?.();\n if (abciq) {\n return abciq.value;\n }\n else {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n catch (_e) {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n this.retryCount++;\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n\n private newBlockReceived(height: number): void {\n if (this.blockTimeout) {\n clearTimeout(this.blockTimeout);\n }\n this.blockTimeout = setTimeout(() => {\n this.tryToRecover = true;\n }, 30000);\n this.log.info(\"Received new block: %d\",\n height);\n if (height == this.latestHeight) {\n return;\n }\n // If we are synced, add to end of queue\n if (this.blockQueue.synced && !this.tryToRecover) {\n this.latestHeight = height;\n if (this.blockQueue.size() + 1 == this.config.batchSize) {\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block queue is full. Cannot add new block\");\n this.tryToRecover = true;\n this.retryCount++;\n return;\n }\n try {\n if (this.isMinimal(this.blockQueue)) {\n this.blockQueue.enqueue(Promise.all([this.client.block(height) as Promise<BlockResponse>, this.client.blockResults(height) as Promise<BlockResultsResponse>]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>);\n }\n else {\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: 1000n,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n this.blockQueue.enqueue(Promise.all([\n this.client.block(height) as Promise<BlockResponse>,\n this.client.blockResults(height) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n height,\n false),\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>);\n }\n }\n catch (e) {\n this.log.error(\"New Block Received error: \" + e);\n }\n }\n else {\n this.latestHeight = height;\n }\n }\n\n private async pollForBlock() {\n try {\n const status = await this.client.status();\n if (status.syncInfo.latestBlockHeight > this.latestHeight) {\n while (this.latestHeight < status.syncInfo.latestBlockHeight) {\n this.newBlockReceived(this.latestHeight + 1);\n }\n }\n setTimeout(() => {\n this.pollForBlock();\n },\n this.config.pollingInterval);\n }\n catch (e) {\n this.log.error(\"Error polling for new block: \" + e);\n this.tryToRecover = true;\n this.retryCount++;\n }\n }\n\n private readGenesis(): Parser.Parser {\n if (this.config.genesisPath) {\n return fs.createReadStream(this.config.genesisPath).pipe(Parser.parser());\n }\n else {\n throw new Error(\"Genesis path not set\");\n }\n }\n\n private async setArrayReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n let counter = 0;\n let chunkCounter = 0;\n\n // Wrapper processor that handles transaction chunking\n const chunkProcessor = async (data: unknown) => {\n chunkCounter++;\n this.log.debug(`Processing genesis chunk ${chunkCounter}`);\n\n await processor(data);\n\n // Commit and restart transaction every 5 chunks (5000 entries)\n // This prevents timeout on large genesis files\n if (chunkCounter % 5 === 0) {\n this.log.debug(`Committing transaction after chunk ${chunkCounter}`);\n await this.config.endTransaction(true);\n await this.config.beginTransaction();\n }\n };\n\n chain([\n this.readGenesis(),\n ...pickers,\n StreamArray.streamArray(),\n Batch.batch({\n batchSize: GENESIS_BATCH_SIZE,\n }),\n chunkProcessor,\n ])\n .on(\"data\",\n (data) => {\n if (data && Array.isArray(data)) {\n counter = counter + data.length;\n }\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries in ${chunkCounter} chunks`);\n resolve(true);\n });\n }\n catch (_e) {\n this.log.verbose(\"Error in setArrayReader: \" + _e);\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async setValueReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n\n let counter = 0;\n chain([this.readGenesis(), ...pickers, StreamValues.streamValues(), processor])\n .on(\"data\",\n (_data) => {\n counter++;\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries`);\n resolve(true);\n });\n }\n catch (_e) {\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async parseGenesis() {\n this.log.info(\"Parsing genesis\");\n await this.config.beginTransaction();\n try {\n this.log.info(\"Starting genesis import\");\n this.log.debug(\"Importing genesis file...\");\n\n for (const [key, _value] of this.handled) {\n if (key.startsWith(\"genesis/\")) {\n const genesisEntry = key.split(\"/\");\n\n this.log.verbose(\"Importing \" + key + \"...\");\n if (genesisEntry[1] == \"array\") {\n await this.setArrayReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.map((x: {\n value: never\n }) => x.value),\n } as never);\n return data;\n });\n }\n else {\n await this.setValueReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.value,\n } as never);\n return data;\n });\n }\n }\n }\n\n this.log.info(\"Importing gen TXs...\");\n\n await this.setArrayReader(\"app_state.genutil.gen_txs\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n for (let j = 0; j < data.length; j++) {\n const gentx = data[j].value;\n for (let i = 0; i < gentx.body.messages.length; i++) {\n const msg = gentx.body.messages[i];\n await this.asyncEmit((\"gentx\" + msg[\"@type\"]) as never,\n {\n value: msg,\n } as never);\n }\n }\n return data;\n });\n await this.config.endTransaction(true);\n\n this.log.info(\"Finished importing\");\n }\n catch (e) {\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.log.error(\"Failed to import genesis\");\n throw e;\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":["statusPromise: Promise<StatusResponse>","timeoutPromise: ReturnType<typeof this.blockQueue.dequeue>","uuidv4","beginBlockEvents: readonly Event[] | readonly Event38[]","endBlockEvents: readonly Event[] | readonly Event38[]","events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }>","eventsToAdd: typeof events","events","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]>","timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>"],"sources":["../../src/indexer/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\n/* eslint-disable max-lines */\nimport {\n createHash,\n} from \"node:crypto\";\nimport * as fs from \"node:fs\";\n\nimport {\n BlockResponse, BlockResultsResponse, connectComet, Event, StatusResponse, toRfc3339WithNanoseconds,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event as Event38,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses.js\";\nimport {\n MsgExec,\n} from \"cosmjs-types/cosmos/authz/v1beta1/tx.js\";\nimport {\n QueryValidatorsRequest,\n QueryValidatorsResponse,\n} from \"cosmjs-types/cosmos/staking/v1beta1/query.js\";\nimport {\n Tx,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx.js\";\nimport Fastify, {\n FastifyInstance,\n} from \"fastify\";\nimport {\n chain,\n} from \"stream-chain\";\nimport Parser from \"stream-json\";\nimport Pick from \"stream-json/filters/Pick.js\";\nimport StreamArray from \"stream-json/streamers/StreamArray.js\";\nimport StreamValues from \"stream-json/streamers/StreamValues.js\";\nimport Batch from \"stream-json/utils/Batch.js\";\nimport {\n v4 as uuidv4,\n} from \"uuid\";\nimport * as winston from \"winston\";\n\nimport {\n CONNECT_TIMEOUT_MS,\n DEFAULT_BATCH_SIZE, DEFAULT_HEALTH_CHECK_PORT, DEFAULT_POLLING_INTERVAL_MS, DEFAULT_PROMETHEUS_PORT, DEFAULT_START_HEIGHT,\n GENESIS_BATCH_SIZE, PAGINATION_LIMITS, PERIODIC_INTERVALS, QUEUE_DEQUEUE_TIMEOUT_MS, RPC_TIMEOUT_MS,\n} from \"../constants.js\";\nimport {\n EclesiaEmitter,\n} from \"../emitter/index.js\";\nimport {\n RPCError,\n} from \"../errors/index.js\";\nimport {\n IndexerMetrics,\n} from \"../metrics/index.js\";\nimport {\n CircularBuffer,\n} from \"../promise-queue/index.js\";\nimport {\n BlockQueue, EcleciaIndexerConfig, EmitFunc, MinimalBlockQueue,\n UUIDEvent, WithHeightAndUUID,\n} from \"../types/index.js\";\nimport {\n decodeAttr,\n} from \"../utils/index.js\";\nimport {\n validateFilePath, validatePort, validatePositiveInteger, validateUrl,\n} from \"../validation/index.js\";\n\n/** Default configuration for the Eclesia indexer */\nexport const defaultIndexerConfig = {\n startHeight: DEFAULT_START_HEIGHT, // Start indexing from block 1\n batchSize: DEFAULT_BATCH_SIZE, // Process blocks in batches of 500\n modules: [], // No modules enabled by default\n getNextHeight: () => DEFAULT_START_HEIGHT, // Default height retrieval function\n logLevel: \"info\" as EcleciaIndexerConfig[\"logLevel\"], // Default log level\n usePolling: false, // Use WebSocket subscription by default\n pollingInterval: DEFAULT_POLLING_INTERVAL_MS, // Poll every 5 seconds when polling enabled\n shouldProcessGenesis: () => false, // Skip genesis processing by default\n minimal: true, // Use minimal indexing by default\n enableHealthcheck: true, // Enable health check server by default\n healthCheckPort: DEFAULT_HEALTH_CHECK_PORT, // Default health check port\n enablePrometheus: false, // Disable Prometheus metrics server by default\n prometheusPort: DEFAULT_PROMETHEUS_PORT, // Default Prometheus metrics server port\n init: () => Promise.resolve(), // No-op initialization function\n beginTransaction: () => Promise.resolve(), // No-op transaction begin function\n endTransaction: (_status: boolean) => Promise.resolve(), // No-op transaction end function\n};\n\n/**\n * Core blockchain indexer that connects to Tendermint RPC and processes blocks\n * Extends EclesiaEmitter to provide event-driven architecture for modules\n */\nexport class EcleciaIndexer extends EclesiaEmitter {\n /** Indexer configuration settings */\n public config: EcleciaIndexerConfig;\n\n /** Fastify HTTP server for health checks */\n private fastify: FastifyInstance | null = null;\n\n /** Prometheus HTTP server instance */\n private prometheusServer: FastifyInstance | null = null;\n\n /** Indicates if the indexer has started */\n private started: boolean = false;\n\n /** Queue for managing block processing pipeline */\n private blockQueue: BlockQueue;\n\n /** Latest block height from the chain */\n private latestHeight!: number;\n\n /** Next block height to process */\n public heightToProcess!: number;\n\n /** Whether the indexer has been initialized */\n private initialized = false;\n\n /** Prometheus metrics server instance */\n public prometheus: IndexerMetrics | null = null;\n\n /** Number of retry attempts for error recovery */\n private retryCount = 0;\n\n /** RPC client for ad-hoc queries (CometClient or custom client via connectFn) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public client!: any;\n\n /** RPC client for block and validator queries (CometClient or custom client via connectFn) */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n public blockClient!: any;\n\n /** Winston logger instance */\n public log: winston.Logger;\n\n /** Flag indicating if indexer should attempt recovery */\n private tryToRecover: boolean = false;\n\n /** Health check status for monitoring */\n private healthCheck = {\n status: \"CONNECTING\",\n };\n\n /** WebSocket subscription for new block notifications */\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private subscription: any | null = null;\n\n /** Timeout handler for block reception */\n private blockTimeout: NodeJS.Timeout | null = null;\n\n /**\n * Creates a new Eclesia indexer instance\n * @param config - Indexer configuration options\n */\n constructor(config: EcleciaIndexerConfig) {\n super();\n\n // Validate required configuration\n validateUrl(config.rpcUrl, \"rpcUrl\");\n validatePositiveInteger(config.batchSize, \"batchSize\");\n\n // Validate optional genesis path if processing genesis\n if (config.genesisPath) {\n validateFilePath(config.genesisPath, \"genesisPath\");\n }\n\n // Validate health check port if provided\n if (config.healthCheckPort !== undefined) {\n validatePort(config.healthCheckPort, \"healthCheckPort\");\n }\n\n // Validate prometheus port if provided\n if (config.prometheusPort !== undefined) {\n validatePort(config.prometheusPort, \"prometheusPort\");\n }\n\n // Validate start height if provided\n if (config.startHeight !== undefined) {\n validatePositiveInteger(config.startHeight, \"startHeight\");\n }\n\n // Validate polling interval if provided\n if (config.pollingInterval !== undefined) {\n validatePositiveInteger(config.pollingInterval, \"pollingInterval\");\n }\n\n this.config = {\n ...defaultIndexerConfig,\n ...config,\n };\n\n // Initialize logger first so it can be used by queue error handler\n const {\n printf,\n } = winston.format;\n\n const eclesiaFormat = printf(({\n level, message, timestamp,\n }) => {\n return `${timestamp} [${level.toUpperCase()}]:\\t${message}`;\n });\n this.log = winston.createLogger({\n level: this.config.logLevel,\n defaultMeta: {\n service: \"Eclesia Indexer\",\n },\n transports: [\n new winston.transports.File({\n filename: \"error.log\",\n level: \"error\",\n }),\n new winston.transports.File({\n filename: \"combined.log\",\n }),\n new winston.transports.Console({\n format: winston.format.combine(winston.format.splat(),\n winston.format.timestamp(),\n eclesiaFormat,\n winston.format.colorize({\n all: true,\n })),\n }),\n ],\n });\n\n // Initialize block queue based on minimal or full indexing mode\n // Pass error handler that uses the logger\n const queueErrorHandler = (e: unknown) => {\n this.prometheus?.recordError(\"rpc\");\n this.log.error(\"Error enqueueing block data: \" + e);\n };\n\n if (this.config.minimal) {\n // Minimal mode: only store block and block results\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse]>(this.config.batchSize, queueErrorHandler);\n }\n else {\n // Full mode: also store validator information\n this.blockQueue = new CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>(this.config.batchSize, queueErrorHandler);\n }\n\n this.on(\"_unhandled\",\n (msg) => {\n if (msg.uuid) {\n this.log.verbose(\"Unhandled event: \" + msg.type);\n this.emit(\"uuid\",\n {\n status: true,\n uuid: msg.uuid,\n });\n }\n });\n if (this.config.enablePrometheus) {\n this.prometheus = new IndexerMetrics();\n this.prometheusServer = Fastify({\n logger: false,\n });\n this.prometheusServer.get(\"/metrics\",\n async (_req, res) => {\n res.header(\"Content-Type\", this.prometheus!.registry.contentType);\n res.send(await this.prometheus!.getMetrics());\n },\n );\n\n const prometheusPort = this.config.prometheusPort\n ?? (process.env.PROMETHEUS_PORT ? parseInt(process.env.PROMETHEUS_PORT, 10) : DEFAULT_PROMETHEUS_PORT);\n this.prometheusServer.listen({\n port: prometheusPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Prometheus error: \" + err);\n this.prometheus?.recordError(\"metrics_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start metrics server\",\n });\n }\n });\n }\n if (this.config.enableHealthcheck) {\n this.fastify = Fastify({\n logger: false,\n });\n this.fastify.get(\"/health\",\n async (_request, reply) => {\n const code = this.healthCheck.status == \"OK\"\n ? 200\n : 503;\n reply.code(code).send(this.healthCheck);\n });\n const healthPort = this.config.healthCheckPort\n ?? (process.env.HEALTH_CHECK_PORT ? parseInt(process.env.HEALTH_CHECK_PORT, 10) : DEFAULT_HEALTH_CHECK_PORT);\n this.fastify.listen({\n port: healthPort,\n host: \"0.0.0.0\",\n },\n (err) => {\n if (err) {\n this.log.error(\"Health check server error: \" + err);\n this.prometheus?.recordError(\"health_check_server\");\n this.emit(\"fatal-error\", {\n error: err,\n message: \"Failed to start health check server\",\n });\n }\n });\n }\n }\n\n private setStatus(status: string) {\n this.healthCheck.status = status;\n }\n\n private blockListener = {\n next: (data: {\n header: {\n height: number\n }\n }) => {\n this.newBlockReceived(data.header.height);\n },\n };\n\n private isMinimal(_blockqueue: BlockQueue): _blockqueue is MinimalBlockQueue {\n if (this.config.minimal) {\n return true;\n }\n else {\n return false;\n }\n }\n\n public async connect() {\n try {\n if (this.client && this.tryToRecover) {\n this.log.verbose(\"Recover from error. Attempting to disconnect from RPC\");\n this.client.disconnect();\n this.blockClient.disconnect();\n this.log.verbose(\"Disconnected from RPC\");\n }\n const connectFn = this.config.connectFn ?? connectComet;\n const connectTimeoutPromise = new Promise<never>((_resolve, reject) => {\n setTimeout(reject, CONNECT_TIMEOUT_MS, []);\n });\n this.client = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for ad hoc queries\");\n this.blockClient = await Promise.race([connectFn(this.config.rpcUrl), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for block & validator info\");\n\n return true;\n }\n catch (error) {\n this.log.error(\"RPC connection error: \" + error);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return false;\n }\n }\n\n private async initialize() {\n if (!this.initialized) {\n try {\n if (this.config.init) {\n await this.config.init();\n }\n }\n catch (e) {\n this.log.error(\"Failed to initialize indexer: \" + e);\n\n this.prometheus?.recordError(\"init_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n if (await this.config.shouldProcessGenesis()) {\n try {\n if (this.config.genesisPath) {\n await this.parseGenesis();\n }\n }\n catch (e) {\n this.log.error(\"Failed to parse genesis: \" + e);\n\n this.prometheus?.recordError(\"genesis_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n this.initialized = true;\n }\n }\n\n public stop() {\n this.started = false;\n }\n\n private clearBlockQueue() {\n if (this.blockQueue) {\n this.blockQueue.clear();\n this.log.verbose(\"Starting, clearing block queue\");\n }\n }\n\n private async setupBlockListening() {\n const connected = await this.connect();\n if (!connected) {\n this.setStatus(\"FAILED\");\n throw new RPCError(\"Failed to connect to RPC\");\n }\n\n try {\n if (!this.config.usePolling && this.subscription) {\n this.subscription.removeListener(this.blockListener);\n this.subscription = null;\n this.log.verbose(\"Removed existing block listener and subscription\");\n }\n if (!this.config.usePolling) {\n this.subscription = this.client.subscribeNewBlock\n ? this.client.subscribeNewBlock()\n : null;\n }\n const statusPromise: Promise<StatusResponse> = new Promise((_resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const status = await Promise.race([this.client.status(), statusPromise]);\n this.latestHeight = status.syncInfo.latestBlockHeight;\n this.log.info(\"Current chain height: \" + this.latestHeight);\n\n this.heightToProcess = await this.config.getNextHeight();\n if (this.config.usePolling) {\n this.pollForBlock();\n }\n else {\n if (this.subscription) {\n this.subscription.addListener(this.blockListener);\n }\n else {\n // Fall back to polling if subscription is not available (e.g. custom RPC client)\n this.log.info(\"WebSocket subscription not available, falling back to polling\");\n this.config.usePolling = true;\n this.pollForBlock();\n }\n }\n }\n catch (e) {\n this.log.error(\"Failed to set up block listening: \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n\n public async start() {\n this.started = true;\n this.clearBlockQueue();\n await this.initialize();\n try {\n await this.setupBlockListening();\n this.log.debug(\"Starting main processing loop\");\n this.tryToRecover = false;\n this.fetcher().catch((e) => {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"Error in fetching service: \" + e);\n });\n }\n catch (_e) {\n // Continue and attempt to recover\n }\n\n while (\n this.started // break out when stopped\n && !this.tryToRecover // break out for recoverable errors\n && (this.config.endHeight === undefined || this.heightToProcess <= this.config.endHeight) // break out if end height configured and reached\n && this.blockQueue.size() > 0 // break out if no blocks to process\n ) {\n // await the dequeued promise is essentially awaiting fetched data for that block\n try {\n this.prometheus?.updateRetryCount(this.retryCount);\n // Index block inside a db transaction to ensure data consistency\n await this.config.beginTransaction();\n this.log.silly(\"Started db tx\");\n let height, timestamp;\n\n // Main block processing (minimal)\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((_resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1]) {\n throw new RPCError(\"Could not fetch block(minimal)\");\n }\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1]);\n }\n // Main block processing (full)\n else {\n const timeoutPromise: ReturnType<typeof this.blockQueue.dequeue> = new Promise((_resolve, reject) => {\n setTimeout(reject, QUEUE_DEQUEUE_TIMEOUT_MS, []);\n });\n const toProcess = await Promise.race([this.blockQueue.dequeue(), timeoutPromise]);\n this.log.silly(\"Retrieved block data\");\n if (!toProcess || !toProcess[0] || !toProcess[1] || !toProcess[2]) {\n throw new RPCError(\"Could not fetch block(full)\");\n }\n\n this.log.silly(\"Decoded block\");\n height = toProcess[0].block.header.height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.processBlock(toProcess[0],\n toProcess[1],\n QueryValidatorsResponse.decode(toProcess[2]).validators);\n }\n\n // Emit events to trigger periodic operations every 50, 100 and 1000 blocks\n if (height % PERIODIC_INTERVALS.LARGE == 0) {\n await this.asyncEmit(\"periodic/large\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.MEDIUM == 0) {\n await this.asyncEmit(\"periodic/medium\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n if (height % PERIODIC_INTERVALS.SMALL == 0) {\n await this.asyncEmit(\"periodic/small\",\n {\n value: null,\n height,\n timestamp,\n });\n }\n this.log.silly(\"Handled periodic events\");\n\n await this.config.endTransaction(true);\n\n this.log.silly(\"Committed db tx\");\n }\n catch (e) {\n // any error here is likely recoverable (e.g. RPC timeout, DB error)\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block processing error: \" + e);\n this.setStatus(\"FAILED\");\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.tryToRecover = true;\n // Exit processing loop to attempt recovery\n break;\n }\n // Reset retry count and status on successful block processing\n this.retryCount = 0;\n this.setStatus(\"OK\");\n }\n\n // Normal exit from processing loop\n if (!this.started) {\n this.log.info(\"Indexer manually stopped.\");\n return;\n }\n if (this.config.endHeight !== undefined && this.heightToProcess >= this.config.endHeight!) {\n this.log.info(\"Reached configured end height. Stopping indexer.\");\n this.stop();\n return;\n }\n\n // Abnormal exit\n if (this.retryCount < 3) {\n this.log.debug(\"Indexer retryCount: \" + this.retryCount);\n this.retryCount++;\n this.log.info(\"Indexer is restarting\");\n // Attempt recovery after brief delay\n setTimeout(() => this.start(),\n this.retryCount * 5000);\n }\n else {\n this.log.info(\"Indexer failed too many times. Exiting.\");\n this.emit(\"fatal-error\", {\n error: new Error(\"Max retry attempts exceeded\"),\n message: \"Indexer failed too many times\",\n retryCount: this.retryCount,\n });\n }\n }\n\n public asyncEmit: EmitFunc<keyof WithHeightAndUUID<EventMap>> = async (\n type,\n event,\n ) => {\n event.uuid = uuidv4();\n\n /*\n * More than 1 listener can be registered for an event type\n * Fortunately these are all set up during module init() so we have a consistent count\n * so we can count responses to resolve when complete\n * values are irrelevant as promise resolution is only used for flow control\n */\n let listenerCount = this.handled.get(type);\n if (!listenerCount) {\n // Setting listenerCount to 1 (the unhandled listener)\n listenerCount = 1;\n }\n let listenersResponded = 0;\n const prom = new Promise<void>((resolve, reject) => {\n const returnFunc = (ev: UUIDEvent) => {\n if (ev.uuid == event.uuid) {\n if (ev.status) {\n listenersResponded++;\n if (listenersResponded == listenerCount) {\n // All listeners have done their thing so we can remove listener, resolve and continue execution\n this.off(\"uuid\",\n returnFunc);\n resolve();\n }\n }\n else {\n // At least 1 listener is reporting an error. Reject and handle exception at the original asyncEmit location\n reject(ev.error);\n }\n }\n };\n this.on(\"uuid\",\n returnFunc);\n });\n this.emit(type,\n event);\n\n return prom;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n private async processBlock(block: any, block_results: any, validators?: any) {\n const endTimer = this.prometheus?.timeBlockProcessing();\n const height = block.block.header.height;\n this.heightToProcess = height;\n this.log.debug(\"Processing block: %d\",\n height);\n // Initialize height & timestamp to be used for this block-processing run\n const timestamp = toRfc3339WithNanoseconds(block.block.header.time);\n\n // Use custom block processor if provided (for non-Cosmos SDK chains like Gno)\n if (this.config.processBlockFn) {\n await this.config.processBlockFn(block, block_results, {\n asyncEmit: this.asyncEmit,\n log: this.log,\n prometheus: this.prometheus,\n height,\n timestamp,\n }, validators);\n endTimer?.();\n this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());\n return;\n }\n\n // Default Cosmos SDK block processing logic\n\n // Use & await asyncEmit to ensure db insertions in order\n\n /*\n * Emit block information to any interested modules.\n * Primarily the required block module listens to this\n */\n await this.asyncEmit(\"block\",\n {\n value: {\n block,\n block_results,\n },\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled block event\");\n\n let beginBlockEvents: readonly Event[] | readonly Event38[];\n let endBlockEvents: readonly Event[] | readonly Event38[];\n if ((block_results as BlockResultsResponse38).finalizeBlockEvents) {\n beginBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"begin_block\")) as readonly Event38[];\n endBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => x.attributes.find(a => decodeAttr(a.key) == \"mode\" && decodeAttr(a.value) == \"end_block\")) as readonly Event38[];\n }\n else {\n beginBlockEvents = (block_results as BlockResultsResponse).beginBlockEvents;\n endBlockEvents = (block_results as BlockResultsResponse).endBlockEvents;\n }\n // Deal with begin_block events first\n await this.asyncEmit(\"begin_block\",\n {\n value: {\n events: beginBlockEvents!,\n validators,\n },\n height,\n timestamp,\n });\n\n this.log.silly(\"Modules handled begin_block events\");\n\n // Then individual tx_events\n await this.asyncEmit(\"tx_events\",\n {\n value: block_results.results,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled tx events\");\n\n // Emit details and result for each tx msg separately\n for (let t = 0; t < block.block.txs.length; t++) {\n const tx = Tx.decode(block.block.txs[t]);\n\n const result = block_results.results[t].code;\n const txlog = block_results.results[t].log;\n\n if (result != 0) {\n // Tx failed. Ignore\n continue;\n }\n if (tx.body && tx.body.memo != \"\") {\n const txHash = createHash(\"sha256\").update(block.block.txs[t])\n .digest(\"hex\");\n await this.asyncEmit(\"tx_memo\",\n {\n value: {\n txHash,\n txBody: tx.body,\n },\n height,\n timestamp,\n });\n }\n // parsing log rather than using events directly in order to have msg_index available to filter appropriate events for each msg\n let events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }> = txlog\n ? JSON.parse(txlog)\n : [];\n if (events.length == 0) {\n const eventsToAdd: typeof events = [];\n this.log.silly(\"No events found in tx log. Parsing events for msg_index\");\n for (let m = 0; m < block_results.results[t].events.length; m++) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n if (block_results.results[t].events[m].attributes.find((a: any) => decodeAttr(a.key) == \"msg_index\")) {\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const mi = decodeAttr(block_results.results[t].events[m].attributes.find((a: any) => decodeAttr(a.key) == \"msg_index\")?.value ?? \"\");\n if (mi != \"\") {\n const miNum = parseInt(mi);\n let ev = eventsToAdd.find(x => x.msg_index == miNum);\n if (!ev) {\n ev = {\n msg_index: miNum,\n events: [block_results.results[t].events[m]],\n };\n eventsToAdd.push(ev);\n }\n else {\n ev.events.push(block_results.results[t].events[m] as Event);\n }\n }\n }\n }\n events = events.concat(eventsToAdd);\n }\n const msgs = tx.body?.messages;\n\n if (msgs) {\n for (let i = 0; i < msgs.length; i++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + msgs[i].typeUrl);\n const msgevents\n = msgs.length > 1\n ? events.find(x => x.msg_index == i)?.events\n : events[0].events;\n await this.asyncEmit(msgs[i].typeUrl as never,\n {\n value: {\n tx: msgs[i].value as never,\n events: msgevents,\n } as never,\n height,\n timestamp,\n });\n if (msgs[i].typeUrl == \"/cosmos.authz.v1beta1.MsgExec\") {\n const authzMsgs = MsgExec.decode(msgs[i].value).msgs;\n if (authzMsgs) {\n for (let r = 0; r < authzMsgs.length; r++) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + authzMsgs[r].typeUrl);\n const authzMsgEvents = msgevents?.reduce((events, evt) => {\n if (evt.attributes.filter(x => decodeAttr(x.key) == \"authz_msg_index\" && decodeAttr(x.value) == \"\" + r).length > 0) {\n events.push(evt);\n }\n return events;\n },\n [] as (Event | Event38)[]);\n await this.asyncEmit(authzMsgs[r].typeUrl as never,\n {\n value: {\n tx: authzMsgs[r].value as never,\n events: authzMsgEvents,\n } as never,\n height,\n timestamp,\n });\n }\n }\n }\n }\n }\n }\n this.log.silly(\"Modules handled msg events\");\n this.prometheus?.recordTransactions(block.block.txs.length);\n // Then deal with end_block events\n await this.asyncEmit(\"end_block\",\n {\n value: endBlockEvents!,\n height,\n timestamp,\n });\n this.log.silly(\"Modules handled end_block events\");\n\n endTimer?.();\n this.prometheus?.updateBlockMetrics(height, this.latestHeight, this.blockQueue.size());\n }\n\n private async fetcher() {\n for (let i = this.heightToProcess; i <= this.latestHeight; i++) {\n // If some other async process triggers recovery, exit the fetching loop\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n this.log.debug(\"Fetching: \" + i);\n try {\n // Main fetching logic for minimal indexer\n if (this.isMinimal(this.blockQueue)) {\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse]> = new Promise((_resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([Promise.all([this.blockClient.block(i) as Promise<BlockResponse>, this.blockClient.blockResults(i) as Promise<BlockResultsResponse>]), timeoutPromise]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.prometheus?.recordError(\"rpc\");\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>;\n this.blockQueue.enqueue(toIndex);\n }\n else {\n // Main fetching logic for minimal indexer\n const timeoutPromise: Promise<[BlockResponse, BlockResultsResponse, Uint8Array]> = new Promise((_resolve, reject) => {\n setTimeout(reject,\n RPC_TIMEOUT_MS,\n false);\n });\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: PAGINATION_LIMITS.VALIDATORS,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = Promise.race([\n Promise.all([\n this.blockClient.block(i) as Promise<BlockResponse>,\n this.blockClient.blockResults(i) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n i,\n false),\n ]),\n timeoutPromise,\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + i + \" : \" + e);\n this.tryToRecover = true;\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n this.blockQueue.enqueue(toIndex);\n }\n }\n catch (e) {\n this.log.error(\"Fetching error: \" + e);\n break;\n }\n await this.blockQueue.continue();\n if (this.tryToRecover) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n }\n // If we exit the fetching loop without errors, we are synced\n if (!this.tryToRecover) {\n this.blockQueue.setSynced();\n this.log.info(\"Synced to latest height\");\n }\n }\n\n public async callABCI(path: string, data: Uint8Array, height?: number, adHoc: boolean = true): Promise<Uint8Array> {\n try {\n const endTimer = this.prometheus?.timeRpcCall(path) ?? void 0;\n const abciq = await\n (adHoc\n ? this.client\n : this.blockClient).abciQuery({\n path,\n data,\n height: height,\n });\n endTimer?.();\n if (abciq) {\n return abciq.value;\n }\n else {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n catch (_e) {\n this.tryToRecover = true;\n this.setStatus(\"FAILED\");\n throw new Error(\"RPC not responding. Query at: \" + path);\n }\n }\n\n private newBlockReceived(height: number): void {\n if (this.blockTimeout) {\n clearTimeout(this.blockTimeout);\n }\n this.blockTimeout = setTimeout(() => {\n this.tryToRecover = true;\n }, 30000);\n this.log.info(\"Received new block: %d\",\n height);\n if (height == this.latestHeight) {\n return;\n }\n // If we are synced, add to end of queue\n if (this.blockQueue.synced && !this.tryToRecover) {\n this.latestHeight = height;\n if (this.blockQueue.size() + 1 == this.config.batchSize) {\n this.prometheus?.recordError(\"block\");\n this.log.error(\"Block queue is full. Cannot add new block\");\n this.tryToRecover = true;\n return;\n }\n try {\n if (this.isMinimal(this.blockQueue)) {\n this.blockQueue.enqueue(Promise.all([this.client.block(height) as Promise<BlockResponse>, this.client.blockResults(height) as Promise<BlockResultsResponse>]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>);\n }\n else {\n const q = QueryValidatorsRequest.fromPartial({\n pagination: {\n limit: 1000n,\n },\n });\n const vals = QueryValidatorsRequest.encode(q).finish();\n this.blockQueue.enqueue(Promise.all([\n this.client.block(height) as Promise<BlockResponse>,\n this.client.blockResults(height) as Promise<BlockResultsResponse>,\n this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\",\n vals,\n height,\n false),\n ]).catch((e) => {\n this.log.error(\"Error fetching block: \" + height + \" : \" + e);\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse, Uint8Array]>);\n }\n }\n catch (e) {\n this.log.error(\"New Block Received error: \" + e);\n }\n }\n else {\n this.latestHeight = height;\n }\n }\n\n private async pollForBlock() {\n try {\n const status = await this.client.status();\n if (status.syncInfo.latestBlockHeight > this.latestHeight) {\n while (this.latestHeight < status.syncInfo.latestBlockHeight) {\n this.newBlockReceived(this.latestHeight + 1);\n }\n }\n setTimeout(() => {\n this.pollForBlock();\n },\n this.config.pollingInterval);\n }\n catch (e) {\n this.log.error(\"Error polling for new block: \" + e);\n this.tryToRecover = true;\n }\n }\n\n private readGenesis(): Parser.Parser {\n if (this.config.genesisPath) {\n return fs.createReadStream(this.config.genesisPath).pipe(Parser.parser());\n }\n else {\n throw new Error(\"Genesis path not set\");\n }\n }\n\n private async setArrayReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n let counter = 0;\n let chunkCounter = 0;\n\n // Wrapper processor that handles transaction chunking\n const chunkProcessor = async (data: unknown) => {\n chunkCounter++;\n this.log.debug(`Processing genesis chunk ${chunkCounter}`);\n\n await processor(data);\n\n // Commit and restart transaction every 5 chunks (5000 entries)\n // This prevents timeout on large genesis files\n if (chunkCounter % 5 === 0) {\n this.log.debug(`Committing transaction after chunk ${chunkCounter}`);\n await this.config.endTransaction(true);\n await this.config.beginTransaction();\n }\n };\n\n chain([\n this.readGenesis(),\n ...pickers,\n StreamArray.streamArray(),\n Batch.batch({\n batchSize: GENESIS_BATCH_SIZE,\n }),\n chunkProcessor,\n ])\n .on(\"data\",\n (data) => {\n if (data && Array.isArray(data)) {\n counter = counter + data.length;\n }\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries in ${chunkCounter} chunks`);\n resolve(true);\n });\n }\n catch (_e) {\n this.log.verbose(\"Error in setArrayReader: \" + _e);\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async setValueReader(path: string, processor: (chunk: unknown) => Promise<void>): Promise<boolean> {\n const readPromise = new Promise<boolean>((resolve, reject) => {\n try {\n const filters = path.split(\".\");\n const pickers = filters.map(filter => Pick.pick({\n filter,\n }));\n\n let counter = 0;\n chain([this.readGenesis(), ...pickers, StreamValues.streamValues(), processor])\n .on(\"data\",\n (_data) => {\n counter++;\n })\n .on(\"end\",\n () => {\n this.log.info(`Processed ${counter} entries`);\n resolve(true);\n });\n }\n catch (_e) {\n reject();\n }\n });\n\n return readPromise;\n }\n\n private async parseGenesis() {\n this.log.info(\"Parsing genesis\");\n await this.config.beginTransaction();\n try {\n this.log.info(\"Starting genesis import\");\n this.log.debug(\"Importing genesis file...\");\n\n for (const [key, _value] of this.handled) {\n if (key.startsWith(\"genesis/\")) {\n const genesisEntry = key.split(\"/\");\n\n this.log.verbose(\"Importing \" + key + \"...\");\n if (genesisEntry[1] == \"array\") {\n await this.setArrayReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.map((x: {\n value: never\n }) => x.value),\n } as never);\n return data;\n });\n }\n else {\n await this.setValueReader(genesisEntry[2],\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n await this.asyncEmit(key as never,\n {\n value: data.value,\n } as never);\n return data;\n });\n }\n }\n }\n\n this.log.info(\"Importing gen TXs...\");\n\n await this.setArrayReader(\"app_state.genutil.gen_txs\",\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n async (data: any) => {\n for (let j = 0; j < data.length; j++) {\n const gentx = data[j].value;\n for (let i = 0; i < gentx.body.messages.length; i++) {\n const msg = gentx.body.messages[i];\n await this.asyncEmit((\"gentx\" + msg[\"@type\"]) as never,\n {\n value: msg,\n } as never);\n }\n }\n return data;\n });\n await this.config.endTransaction(true);\n\n this.log.info(\"Finished importing\");\n }\n catch (e) {\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction. Must be a DB error: \" + dbe);\n }\n this.log.error(\"Failed to import genesis\");\n throw e;\n }\n }\n}\n"],"mappings":"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"}
|
package/dist/types/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\nimport {\n BlockResponse, BlockResultsResponse,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses\";\nimport {\n Validator,\n} from \"cosmjs-types/cosmos/staking/v1beta1/staking\";\nimport {\n TxBody,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx\";\n\nimport {\n EcleciaIndexer,\n} from \"../indexer\";\nimport {\n CircularBuffer,\n} from \"../promise-queue\";\n\n/** Configuration interface for the Eclesia indexer */\nexport type EcleciaIndexerConfig = {\n startHeight?: number // Block height to start indexing from\n endHeight?: number // Block height to stop indexing at (optional)\n batchSize: number // Number of blocks to process in parallel\n modules: string[] // List of module names to enable\n getNextHeight: () => number | PromiseLike<number> // Function to determine next block to process\n logLevel: \"error\" | \"warn\" | \"info\" | \"http\" | \"verbose\" | \"debug\" | \"silly\" // Logging verbosity level\n rpcUrl: string // Tendermint RPC endpoint URL\n shouldProcessGenesis: () => Promise<boolean> // Whether to process genesis state\n genesisPath?: string // Path to genesis file\n usePolling?: boolean // Use polling instead of WebSocket subscription\n pollingInterval?: number // Interval between polls in milliseconds\n minimal?: boolean // Use minimal indexing mode (blocks only)\n enableHealthcheck?: boolean // Enable health check HTTP server\n healthCheckPort?: number // Port for health check HTTP server (default: 8888)\n enablePrometheus?: boolean // Enable Prometheus metrics server\n prometheusPort?: number // Port for Prometheus metrics server (default: 9090)\n init?: () => Promise<void> // Custom initialization function\n beginTransaction: () => Promise<void> // Function to begin database transaction\n endTransaction: (status: boolean) => Promise<void> // Function to end database transaction\n};\n\n/** Queue for full indexing mode with validator data */\nexport type FullBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n\n/** Queue for minimal indexing mode without validator data */\nexport type MinimalBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse]>;\n\n/** Union type for block queues */\nexport type BlockQueue = FullBlockQueue | MinimalBlockQueue;\n\n/** Utility type to add height, timestamp, and UUID to event types */\nexport type WithHeightAndUUID<T> = {\n [K in keyof T]: T[K] & {\n uuid?: string // Unique identifier for event tracking\n height?: number // Block height when event occurred\n timestamp?: string // Block timestamp when event occurred\n };\n};\n\n/** Function signature for emitting events asynchronously */\nexport type EmitFunc<K extends keyof WithHeightAndUUID<EventMap>> = (\n t: K,\n e: WithHeightAndUUID<EventMap>[K],\n) => Promise<void | void[]>;\n\nexport type LogEvent = {\n type: \"log\" | \"info\" | \"warning\" | \"error\" | \"verbose\" | \"transient\"\n message: string\n};\nexport type UUIDEvent = {\n uuid: string\n error?: string\n status: boolean\n};\nexport type Events = {\n log: LogEvent\n uuid: UUIDEvent\n \"fatal-error\": {\n error: Error\n message: string\n retryCount?: number\n }\n begin_block: {\n value: {\n events: BlockResultsResponse[\"beginBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n validators: Validator[] | undefined\n }\n }\n\n block: {\n value: {\n block: BlockResponse\n block_results: BlockResultsResponse | BlockResultsResponse38\n }\n }\n end_block: {\n value: BlockResultsResponse[\"endBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n }\n tx_events: {\n value: BlockResultsResponse[\"results\"] | BlockResultsResponse38[\"results\"]\n }\n tx_memo: {\n value: {\n txHash: string\n txBody: TxBody\n }\n }\n _unhandled: {\n type: string\n event: unknown\n }\n \"periodic/small\": {\n value: null\n }\n \"periodic/medium\": {\n value: null\n }\n \"periodic/large\": {\n value: null\n }\n};\nexport type TxResult<T> = {\n tx: T\n events: Event[]\n};\n\n/** Interface that all indexing modules must implement */\nexport interface IndexingModule {\n indexer: EcleciaIndexer // Reference to the main indexer instance\n name: string // Unique module name\n depends: string[] // Array of module names this module depends on\n provides: string[] // Array of capabilities this module provides\n setup: () => Promise<void> // Async setup function for database schema initialization\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n init: (...args: any[]) => void // Initialization function called by the indexer\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\nimport {\n BlockResponse, BlockResultsResponse,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses\";\nimport {\n Validator,\n} from \"cosmjs-types/cosmos/staking/v1beta1/staking\";\nimport {\n TxBody,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx\";\n\nimport {\n EcleciaIndexer,\n} from \"../indexer\";\nimport {\n CircularBuffer,\n} from \"../promise-queue\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/** Function signature for custom block processing logic */\nexport type ProcessBlockFn = (\n block: any,\n blockResults: any,\n context: {\n asyncEmit: EmitFunc<any>\n log: any\n prometheus: any\n height: number\n timestamp: string\n },\n validators?: any,\n) => Promise<void>;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/** Configuration interface for the Eclesia indexer */\nexport type EcleciaIndexerConfig = {\n startHeight?: number // Block height to start indexing from\n endHeight?: number // Block height to stop indexing at (optional)\n batchSize: number // Number of blocks to process in parallel\n modules: string[] // List of module names to enable\n getNextHeight: () => number | PromiseLike<number> // Function to determine next block to process\n logLevel: \"error\" | \"warn\" | \"info\" | \"http\" | \"verbose\" | \"debug\" | \"silly\" // Logging verbosity level\n rpcUrl: string // Tendermint RPC endpoint URL\n shouldProcessGenesis: () => Promise<boolean> // Whether to process genesis state\n genesisPath?: string // Path to genesis file\n usePolling?: boolean // Use polling instead of WebSocket subscription\n pollingInterval?: number // Interval between polls in milliseconds\n minimal?: boolean // Use minimal indexing mode (blocks only)\n enableHealthcheck?: boolean // Enable health check HTTP server\n healthCheckPort?: number // Port for health check HTTP server (default: 8888)\n enablePrometheus?: boolean // Enable Prometheus metrics server\n prometheusPort?: number // Port for Prometheus metrics server (default: 9090)\n init?: () => Promise<void> // Custom initialization function\n beginTransaction: () => Promise<void> // Function to begin database transaction\n endTransaction: (status: boolean) => Promise<void> // Function to end database transaction\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n connectFn?: (url: string) => Promise<any> // Custom RPC connect function (replaces connectComet)\n processBlockFn?: ProcessBlockFn // Custom block processing function for non-Cosmos chains\n};\n\n/** Queue for full indexing mode with validator data */\nexport type FullBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n\n/** Queue for minimal indexing mode without validator data */\nexport type MinimalBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse]>;\n\n/** Union type for block queues */\nexport type BlockQueue = FullBlockQueue | MinimalBlockQueue;\n\n/** Utility type to add height, timestamp, and UUID to event types */\nexport type WithHeightAndUUID<T> = {\n [K in keyof T]: T[K] & {\n uuid?: string // Unique identifier for event tracking\n height?: number // Block height when event occurred\n timestamp?: string // Block timestamp when event occurred\n };\n};\n\n/** Function signature for emitting events asynchronously */\nexport type EmitFunc<K extends keyof WithHeightAndUUID<EventMap>> = (\n t: K,\n e: WithHeightAndUUID<EventMap>[K],\n) => Promise<void | void[]>;\n\nexport type LogEvent = {\n type: \"log\" | \"info\" | \"warning\" | \"error\" | \"verbose\" | \"transient\"\n message: string\n};\nexport type UUIDEvent = {\n uuid: string\n error?: string\n status: boolean\n};\nexport type Events = {\n log: LogEvent\n uuid: UUIDEvent\n \"fatal-error\": {\n error: Error\n message: string\n retryCount?: number\n }\n begin_block: {\n value: {\n events: BlockResultsResponse[\"beginBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n validators: Validator[] | undefined\n }\n }\n\n block: {\n value: {\n block: BlockResponse\n block_results: BlockResultsResponse | BlockResultsResponse38\n }\n }\n end_block: {\n value: BlockResultsResponse[\"endBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n }\n tx_events: {\n value: BlockResultsResponse[\"results\"] | BlockResultsResponse38[\"results\"]\n }\n tx_memo: {\n value: {\n txHash: string\n txBody: TxBody\n }\n }\n _unhandled: {\n type: string\n event: unknown\n }\n \"periodic/small\": {\n value: null\n }\n \"periodic/medium\": {\n value: null\n }\n \"periodic/large\": {\n value: null\n }\n};\nexport type TxResult<T> = {\n tx: T\n events: Event[]\n};\n\n/** Interface that all indexing modules must implement */\nexport interface IndexingModule {\n indexer: EcleciaIndexer // Reference to the main indexer instance\n name: string // Unique module name\n depends: string[] // Array of module names this module depends on\n provides: string[] // Array of capabilities this module provides\n setup: () => Promise<void> // Async setup function for database schema initialization\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n init: (...args: any[]) => void // Initialization function called by the indexer\n}\n"],"mappings":""}
|
package/dist/types/index.d.cts
CHANGED
|
@@ -7,8 +7,16 @@ import { TxBody } from "cosmjs-types/cosmos/tx/v1beta1/tx";
|
|
|
7
7
|
|
|
8
8
|
//#region src/types/index.d.ts
|
|
9
9
|
declare namespace index_d_exports {
|
|
10
|
-
export { BlockQueue, EcleciaIndexerConfig, EmitFunc, Events, FullBlockQueue, IndexingModule, LogEvent, MinimalBlockQueue, TxResult, UUIDEvent, WithHeightAndUUID };
|
|
10
|
+
export { BlockQueue, EcleciaIndexerConfig, EmitFunc, Events, FullBlockQueue, IndexingModule, LogEvent, MinimalBlockQueue, ProcessBlockFn, TxResult, UUIDEvent, WithHeightAndUUID };
|
|
11
11
|
}
|
|
12
|
+
/** Function signature for custom block processing logic */
|
|
13
|
+
type ProcessBlockFn = (block: any, blockResults: any, context: {
|
|
14
|
+
asyncEmit: EmitFunc<any>;
|
|
15
|
+
log: any;
|
|
16
|
+
prometheus: any;
|
|
17
|
+
height: number;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
}, validators?: any) => Promise<void>;
|
|
12
20
|
/** Configuration interface for the Eclesia indexer */
|
|
13
21
|
type EcleciaIndexerConfig = {
|
|
14
22
|
startHeight?: number;
|
|
@@ -30,6 +38,8 @@ type EcleciaIndexerConfig = {
|
|
|
30
38
|
init?: () => Promise<void>;
|
|
31
39
|
beginTransaction: () => Promise<void>;
|
|
32
40
|
endTransaction: (status: boolean) => Promise<void>;
|
|
41
|
+
connectFn?: (url: string) => Promise<any>;
|
|
42
|
+
processBlockFn?: ProcessBlockFn;
|
|
33
43
|
};
|
|
34
44
|
/** Queue for full indexing mode with validator data */
|
|
35
45
|
type FullBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;KAuBY,cAAA;aAIG;;;;;wBAOV;;KAIO,oBAAA;;;;;gCAKoB;;;EApBpB,oBAAc,EAAA,GAAA,GAuBI,OAnBf,CAAA,OAOV,CAAA;EAIO,WAAA,CAAA,EAAA,MAAA;EAKoB,UAAA,CAAA,EAAA,OAAA;EAGF,eAAA,CAAA,EAAA,MAAA;EASf,OAAA,CAAA,EAAA,OAAA;EACW,iBAAA,CAAA,EAAA,OAAA;EACa,eAAA,CAAA,EAAA,MAAA;EAER,gBAAA,CAAA,EAAA,OAAA;EACZ,cAAA,CAAA,EAAA,MAAA;EAAc,IAAA,CAAA,EAAA,GAAA,GALlB,OAKkB,CAAA,IAAA,CAAA;EAIrB,gBAAA,EAAc,GAAA,GARA,OAQA,CAAA,IAAA,CAAA;EAAmB,cAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,GAPN,OAOM,CAAA,IAAA,CAAA;EAAe,SAAA,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAL7B,OAK6B,CAAA,GAAA,CAAA;EAAsB,cAAA,CAAA,EAJ/D,cAI+D;CAArD;;AAGjB,KAHA,cAAA,GAAiB,cAGA,CAAA,CAHgB,aAGhB,EAH+B,oBAG/B,EAHqD,UAGrD,CAAA,CAAA;;AAAkC,KAAnD,iBAAA,GAAoB,cAA+B,CAAA,CAAf,aAAe,EAAA,oBAAA,CAAA,CAAA;;AAAjB,KAGlC,UAAA,GAAa,cAHqB,GAGJ,iBAHI;AAG9C;AAGY,KAAA,iBAAiB,CAAA,CAAA,CAAA,GAAA,QACf,MAAA,CAAA,GAAI,CAAJ,CAAM,CAAN,CAAA,GAAA;EAAI,IAAA,CAAA,EAAA,MAAA;EAAE,MAAA,CAAA,EAAA,MAAA;EAAC,SAAA,CAAA,EAAA,MAAA;AAQT,CAAA,EAA2C;;AAClD,KADO,QACP,CAAA,YAAA,MADgC,iBAChC,CADkD,QAClD,CAAA,CAAA,GAAA,CAAA,CAAA,EAAA,GAAA,EAAA,CAAA,EACA,iBADA,CACkB,QADlB,CAAA,CAC4B,GAD5B,CAAA,EAAA,GAEA,OAFA,CAAA,IAAA,GAAA,IAAA,EAAA,CAAA;AACkB,KAGX,QAAA,GAHW;EAAlB,IAAA,EAAA,KAAA,GAAA,MAAA,GAAA,SAAA,GAAA,OAAA,GAAA,SAAA,GAAA,WAAA;EAA4B,OAAA,EAAA,MAAA;CAC5B;AAAO,KAMA,SAAA,GANA;EAEA,IAAA,EAAA,MAAQ;EAIR,KAAA,CAAA,EAAA,MAAS;EAKT,MAAA,EAAA,OAAM;CACX;AACC,KAFI,MAAA,GAEJ;EAEG,GAAA,EAHJ,QAGI;EAMG,IAAA,EARN,SAQM;EAA2C,aAAA,EAAA;IACvC,KAAA,EAPP,KAOO;IAML,OAAA,EAAA,MAAA;IACQ,UAAA,CAAA,EAAA,MAAA;EAAuB,CAAA;EAIjC,WAAA,EAAA;IAAyC,KAAA,EAAA;MAGzC,MAAA,EAfG,oBAeH,CAAA,kBAAA,CAAA,GAf8C,sBAe9C,CAAA,qBAAA,CAAA;MAAkC,UAAA,EAd3B,SAc2B,EAAA,GAAA,SAAA;IAK/B,CAAA;EAAM,CAAA;EAiBR,KAAA,EAAA;IAMK,KAAA,EAAA;aApCJ;qBACQ,uBAAuB;;;;WAIjC,yCAAyC;;;WAGzC,kCAAkC;;;;;cAK/B;;;;;;;;;;;;;;;;;KAiBF;MACN;UACI;;;UAIO,cAAA;WACN;;;;eAII"}
|
package/dist/types/index.d.mts
CHANGED
|
@@ -7,8 +7,16 @@ import { TxBody } from "cosmjs-types/cosmos/tx/v1beta1/tx";
|
|
|
7
7
|
|
|
8
8
|
//#region src/types/index.d.ts
|
|
9
9
|
declare namespace index_d_exports {
|
|
10
|
-
export { BlockQueue, EcleciaIndexerConfig, EmitFunc, Events, FullBlockQueue, IndexingModule, LogEvent, MinimalBlockQueue, TxResult, UUIDEvent, WithHeightAndUUID };
|
|
10
|
+
export { BlockQueue, EcleciaIndexerConfig, EmitFunc, Events, FullBlockQueue, IndexingModule, LogEvent, MinimalBlockQueue, ProcessBlockFn, TxResult, UUIDEvent, WithHeightAndUUID };
|
|
11
11
|
}
|
|
12
|
+
/** Function signature for custom block processing logic */
|
|
13
|
+
type ProcessBlockFn = (block: any, blockResults: any, context: {
|
|
14
|
+
asyncEmit: EmitFunc<any>;
|
|
15
|
+
log: any;
|
|
16
|
+
prometheus: any;
|
|
17
|
+
height: number;
|
|
18
|
+
timestamp: string;
|
|
19
|
+
}, validators?: any) => Promise<void>;
|
|
12
20
|
/** Configuration interface for the Eclesia indexer */
|
|
13
21
|
type EcleciaIndexerConfig = {
|
|
14
22
|
startHeight?: number;
|
|
@@ -30,6 +38,8 @@ type EcleciaIndexerConfig = {
|
|
|
30
38
|
init?: () => Promise<void>;
|
|
31
39
|
beginTransaction: () => Promise<void>;
|
|
32
40
|
endTransaction: (status: boolean) => Promise<void>;
|
|
41
|
+
connectFn?: (url: string) => Promise<any>;
|
|
42
|
+
processBlockFn?: ProcessBlockFn;
|
|
33
43
|
};
|
|
34
44
|
/** Queue for full indexing mode with validator data */
|
|
35
45
|
type FullBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":[],"mappings":";;;;;;;;;;;;KAuBY,cAAA;aAIG;;;;;wBAOV;;KAIO,oBAAA;;;;;gCAKoB;;;EApBpB,oBAAc,EAAA,GAAA,GAuBI,OAnBf,CAAA,OAOV,CAAA;EAIO,WAAA,CAAA,EAAA,MAAA;EAKoB,UAAA,CAAA,EAAA,OAAA;EAGF,eAAA,CAAA,EAAA,MAAA;EASf,OAAA,CAAA,EAAA,OAAA;EACW,iBAAA,CAAA,EAAA,OAAA;EACa,eAAA,CAAA,EAAA,MAAA;EAER,gBAAA,CAAA,EAAA,OAAA;EACZ,cAAA,CAAA,EAAA,MAAA;EAAc,IAAA,CAAA,EAAA,GAAA,GALlB,OAKkB,CAAA,IAAA,CAAA;EAIrB,gBAAA,EAAc,GAAA,GARA,OAQA,CAAA,IAAA,CAAA;EAAmB,cAAA,EAAA,CAAA,MAAA,EAAA,OAAA,EAAA,GAPN,OAOM,CAAA,IAAA,CAAA;EAAe,SAAA,CAAA,EAAA,CAAA,GAAA,EAAA,MAAA,EAAA,GAL7B,OAK6B,CAAA,GAAA,CAAA;EAAsB,cAAA,CAAA,EAJ/D,cAI+D;CAArD;;AAGjB,KAHA,cAAA,GAAiB,cAGA,CAAA,CAHgB,aAGhB,EAH+B,oBAG/B,EAHqD,UAGrD,CAAA,CAAA;;AAAkC,KAAnD,iBAAA,GAAoB,cAA+B,CAAA,CAAf,aAAe,EAAA,oBAAA,CAAA,CAAA;;AAAjB,KAGlC,UAAA,GAAa,cAHqB,GAGJ,iBAHI;AAG9C;AAGY,KAAA,iBAAiB,CAAA,CAAA,CAAA,GAAA,QACf,MAAA,CAAA,GAAI,CAAJ,CAAM,CAAN,CAAA,GAAA;EAAI,IAAA,CAAA,EAAA,MAAA;EAAE,MAAA,CAAA,EAAA,MAAA;EAAC,SAAA,CAAA,EAAA,MAAA;AAQT,CAAA,EAA2C;;AAClD,KADO,QACP,CAAA,YAAA,MADgC,iBAChC,CADkD,QAClD,CAAA,CAAA,GAAA,CAAA,CAAA,EAAA,GAAA,EAAA,CAAA,EACA,iBADA,CACkB,QADlB,CAAA,CAC4B,GAD5B,CAAA,EAAA,GAEA,OAFA,CAAA,IAAA,GAAA,IAAA,EAAA,CAAA;AACkB,KAGX,QAAA,GAHW;EAAlB,IAAA,EAAA,KAAA,GAAA,MAAA,GAAA,SAAA,GAAA,OAAA,GAAA,SAAA,GAAA,WAAA;EAA4B,OAAA,EAAA,MAAA;CAC5B;AAAO,KAMA,SAAA,GANA;EAEA,IAAA,EAAA,MAAQ;EAIR,KAAA,CAAA,EAAA,MAAS;EAKT,MAAA,EAAA,OAAM;CACX;AACC,KAFI,MAAA,GAEJ;EAEG,GAAA,EAHJ,QAGI;EAMG,IAAA,EARN,SAQM;EAA2C,aAAA,EAAA;IACvC,KAAA,EAPP,KAOO;IAML,OAAA,EAAA,MAAA;IACQ,UAAA,CAAA,EAAA,MAAA;EAAuB,CAAA;EAIjC,WAAA,EAAA;IAAyC,KAAA,EAAA;MAGzC,MAAA,EAfG,oBAeH,CAAA,kBAAA,CAAA,GAf8C,sBAe9C,CAAA,qBAAA,CAAA;MAAkC,UAAA,EAd3B,SAc2B,EAAA,GAAA,SAAA;IAK/B,CAAA;EAAM,CAAA;EAiBR,KAAA,EAAA;IAMK,KAAA,EAAA;aApCJ;qBACQ,uBAAuB;;;;WAIjC,yCAAyC;;;WAGzC,kCAAkC;;;;;cAK/B;;;;;;;;;;;;;;;;;KAiBF;MACN;UACI;;;UAIO,cAAA;WACN;;;;eAII"}
|
package/dist/types/index.mjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\nimport {\n BlockResponse, BlockResultsResponse,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses\";\nimport {\n Validator,\n} from \"cosmjs-types/cosmos/staking/v1beta1/staking\";\nimport {\n TxBody,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx\";\n\nimport {\n EcleciaIndexer,\n} from \"../indexer\";\nimport {\n CircularBuffer,\n} from \"../promise-queue\";\n\n/** Configuration interface for the Eclesia indexer */\nexport type EcleciaIndexerConfig = {\n startHeight?: number // Block height to start indexing from\n endHeight?: number // Block height to stop indexing at (optional)\n batchSize: number // Number of blocks to process in parallel\n modules: string[] // List of module names to enable\n getNextHeight: () => number | PromiseLike<number> // Function to determine next block to process\n logLevel: \"error\" | \"warn\" | \"info\" | \"http\" | \"verbose\" | \"debug\" | \"silly\" // Logging verbosity level\n rpcUrl: string // Tendermint RPC endpoint URL\n shouldProcessGenesis: () => Promise<boolean> // Whether to process genesis state\n genesisPath?: string // Path to genesis file\n usePolling?: boolean // Use polling instead of WebSocket subscription\n pollingInterval?: number // Interval between polls in milliseconds\n minimal?: boolean // Use minimal indexing mode (blocks only)\n enableHealthcheck?: boolean // Enable health check HTTP server\n healthCheckPort?: number // Port for health check HTTP server (default: 8888)\n enablePrometheus?: boolean // Enable Prometheus metrics server\n prometheusPort?: number // Port for Prometheus metrics server (default: 9090)\n init?: () => Promise<void> // Custom initialization function\n beginTransaction: () => Promise<void> // Function to begin database transaction\n endTransaction: (status: boolean) => Promise<void> // Function to end database transaction\n};\n\n/** Queue for full indexing mode with validator data */\nexport type FullBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n\n/** Queue for minimal indexing mode without validator data */\nexport type MinimalBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse]>;\n\n/** Union type for block queues */\nexport type BlockQueue = FullBlockQueue | MinimalBlockQueue;\n\n/** Utility type to add height, timestamp, and UUID to event types */\nexport type WithHeightAndUUID<T> = {\n [K in keyof T]: T[K] & {\n uuid?: string // Unique identifier for event tracking\n height?: number // Block height when event occurred\n timestamp?: string // Block timestamp when event occurred\n };\n};\n\n/** Function signature for emitting events asynchronously */\nexport type EmitFunc<K extends keyof WithHeightAndUUID<EventMap>> = (\n t: K,\n e: WithHeightAndUUID<EventMap>[K],\n) => Promise<void | void[]>;\n\nexport type LogEvent = {\n type: \"log\" | \"info\" | \"warning\" | \"error\" | \"verbose\" | \"transient\"\n message: string\n};\nexport type UUIDEvent = {\n uuid: string\n error?: string\n status: boolean\n};\nexport type Events = {\n log: LogEvent\n uuid: UUIDEvent\n \"fatal-error\": {\n error: Error\n message: string\n retryCount?: number\n }\n begin_block: {\n value: {\n events: BlockResultsResponse[\"beginBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n validators: Validator[] | undefined\n }\n }\n\n block: {\n value: {\n block: BlockResponse\n block_results: BlockResultsResponse | BlockResultsResponse38\n }\n }\n end_block: {\n value: BlockResultsResponse[\"endBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n }\n tx_events: {\n value: BlockResultsResponse[\"results\"] | BlockResultsResponse38[\"results\"]\n }\n tx_memo: {\n value: {\n txHash: string\n txBody: TxBody\n }\n }\n _unhandled: {\n type: string\n event: unknown\n }\n \"periodic/small\": {\n value: null\n }\n \"periodic/medium\": {\n value: null\n }\n \"periodic/large\": {\n value: null\n }\n};\nexport type TxResult<T> = {\n tx: T\n events: Event[]\n};\n\n/** Interface that all indexing modules must implement */\nexport interface IndexingModule {\n indexer: EcleciaIndexer // Reference to the main indexer instance\n name: string // Unique module name\n depends: string[] // Array of module names this module depends on\n provides: string[] // Array of capabilities this module provides\n setup: () => Promise<void> // Async setup function for database schema initialization\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n init: (...args: any[]) => void // Initialization function called by the indexer\n}\n"],"mappings":""}
|
|
1
|
+
{"version":3,"file":"index.mjs","names":[],"sources":["../../src/types/index.ts"],"sourcesContent":["/* eslint-disable @stylistic/no-multi-spaces */\nimport {\n BlockResponse, BlockResultsResponse,\n} from \"@cosmjs/tendermint-rpc\";\nimport {\n BlockResultsResponse as BlockResultsResponse38, Event,\n} from \"@cosmjs/tendermint-rpc/build/comet38/responses\";\nimport {\n Validator,\n} from \"cosmjs-types/cosmos/staking/v1beta1/staking\";\nimport {\n TxBody,\n} from \"cosmjs-types/cosmos/tx/v1beta1/tx\";\n\nimport {\n EcleciaIndexer,\n} from \"../indexer\";\nimport {\n CircularBuffer,\n} from \"../promise-queue\";\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\n/** Function signature for custom block processing logic */\nexport type ProcessBlockFn = (\n block: any,\n blockResults: any,\n context: {\n asyncEmit: EmitFunc<any>\n log: any\n prometheus: any\n height: number\n timestamp: string\n },\n validators?: any,\n) => Promise<void>;\n/* eslint-enable @typescript-eslint/no-explicit-any */\n\n/** Configuration interface for the Eclesia indexer */\nexport type EcleciaIndexerConfig = {\n startHeight?: number // Block height to start indexing from\n endHeight?: number // Block height to stop indexing at (optional)\n batchSize: number // Number of blocks to process in parallel\n modules: string[] // List of module names to enable\n getNextHeight: () => number | PromiseLike<number> // Function to determine next block to process\n logLevel: \"error\" | \"warn\" | \"info\" | \"http\" | \"verbose\" | \"debug\" | \"silly\" // Logging verbosity level\n rpcUrl: string // Tendermint RPC endpoint URL\n shouldProcessGenesis: () => Promise<boolean> // Whether to process genesis state\n genesisPath?: string // Path to genesis file\n usePolling?: boolean // Use polling instead of WebSocket subscription\n pollingInterval?: number // Interval between polls in milliseconds\n minimal?: boolean // Use minimal indexing mode (blocks only)\n enableHealthcheck?: boolean // Enable health check HTTP server\n healthCheckPort?: number // Port for health check HTTP server (default: 8888)\n enablePrometheus?: boolean // Enable Prometheus metrics server\n prometheusPort?: number // Port for Prometheus metrics server (default: 9090)\n init?: () => Promise<void> // Custom initialization function\n beginTransaction: () => Promise<void> // Function to begin database transaction\n endTransaction: (status: boolean) => Promise<void> // Function to end database transaction\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n connectFn?: (url: string) => Promise<any> // Custom RPC connect function (replaces connectComet)\n processBlockFn?: ProcessBlockFn // Custom block processing function for non-Cosmos chains\n};\n\n/** Queue for full indexing mode with validator data */\nexport type FullBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse, Uint8Array]>;\n\n/** Queue for minimal indexing mode without validator data */\nexport type MinimalBlockQueue = CircularBuffer<[BlockResponse, BlockResultsResponse]>;\n\n/** Union type for block queues */\nexport type BlockQueue = FullBlockQueue | MinimalBlockQueue;\n\n/** Utility type to add height, timestamp, and UUID to event types */\nexport type WithHeightAndUUID<T> = {\n [K in keyof T]: T[K] & {\n uuid?: string // Unique identifier for event tracking\n height?: number // Block height when event occurred\n timestamp?: string // Block timestamp when event occurred\n };\n};\n\n/** Function signature for emitting events asynchronously */\nexport type EmitFunc<K extends keyof WithHeightAndUUID<EventMap>> = (\n t: K,\n e: WithHeightAndUUID<EventMap>[K],\n) => Promise<void | void[]>;\n\nexport type LogEvent = {\n type: \"log\" | \"info\" | \"warning\" | \"error\" | \"verbose\" | \"transient\"\n message: string\n};\nexport type UUIDEvent = {\n uuid: string\n error?: string\n status: boolean\n};\nexport type Events = {\n log: LogEvent\n uuid: UUIDEvent\n \"fatal-error\": {\n error: Error\n message: string\n retryCount?: number\n }\n begin_block: {\n value: {\n events: BlockResultsResponse[\"beginBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n validators: Validator[] | undefined\n }\n }\n\n block: {\n value: {\n block: BlockResponse\n block_results: BlockResultsResponse | BlockResultsResponse38\n }\n }\n end_block: {\n value: BlockResultsResponse[\"endBlockEvents\"] | BlockResultsResponse38[\"finalizeBlockEvents\"]\n }\n tx_events: {\n value: BlockResultsResponse[\"results\"] | BlockResultsResponse38[\"results\"]\n }\n tx_memo: {\n value: {\n txHash: string\n txBody: TxBody\n }\n }\n _unhandled: {\n type: string\n event: unknown\n }\n \"periodic/small\": {\n value: null\n }\n \"periodic/medium\": {\n value: null\n }\n \"periodic/large\": {\n value: null\n }\n};\nexport type TxResult<T> = {\n tx: T\n events: Event[]\n};\n\n/** Interface that all indexing modules must implement */\nexport interface IndexingModule {\n indexer: EcleciaIndexer // Reference to the main indexer instance\n name: string // Unique module name\n depends: string[] // Array of module names this module depends on\n provides: string[] // Array of capabilities this module provides\n setup: () => Promise<void> // Async setup function for database schema initialization\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n init: (...args: any[]) => void // Initialization function called by the indexer\n}\n"],"mappings":""}
|