@eclesia/indexer-engine 2.14.4 → 2.16.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/_virtual/rolldown_runtime.cjs +20 -15
- package/dist/_virtual/rolldown_runtime.mjs +10 -30
- package/dist/constants.cjs +31 -2
- package/dist/constants.cjs.map +1 -1
- package/dist/constants.d.cts +27 -3
- package/dist/constants.d.cts.map +1 -1
- package/dist/constants.d.mts +27 -3
- package/dist/constants.d.mts.map +1 -1
- package/dist/constants.mjs +27 -3
- package/dist/constants.mjs.map +1 -1
- package/dist/emitter/index.cjs +25 -7
- package/dist/emitter/index.cjs.map +1 -1
- package/dist/emitter/index.d.cts +8 -1
- package/dist/emitter/index.d.cts.map +1 -1
- package/dist/emitter/index.d.mts +8 -1
- package/dist/emitter/index.d.mts.map +1 -1
- package/dist/emitter/index.mjs +25 -7
- package/dist/emitter/index.mjs.map +1 -1
- package/dist/index.cjs +6 -0
- package/dist/index.d.cts +3 -3
- package/dist/index.d.mts +3 -3
- package/dist/index.mjs +3 -3
- package/dist/indexer/index.cjs +498 -225
- package/dist/indexer/index.cjs.map +1 -1
- package/dist/indexer/index.d.cts +111 -7
- package/dist/indexer/index.d.cts.map +1 -1
- package/dist/indexer/index.d.mts +111 -7
- package/dist/indexer/index.d.mts.map +1 -1
- package/dist/indexer/index.mjs +496 -224
- package/dist/indexer/index.mjs.map +1 -1
- package/dist/metrics/index.cjs +14 -0
- package/dist/metrics/index.cjs.map +1 -1
- package/dist/metrics/index.d.cts +7 -0
- package/dist/metrics/index.d.cts.map +1 -1
- package/dist/metrics/index.d.mts +7 -0
- package/dist/metrics/index.d.mts.map +1 -1
- package/dist/metrics/index.mjs +14 -0
- package/dist/metrics/index.mjs.map +1 -1
- package/dist/mocks/index.cjs +3 -1
- package/dist/mocks/index.cjs.map +1 -1
- package/dist/mocks/index.d.cts +2 -2
- package/dist/mocks/index.d.mts +2 -2
- package/dist/mocks/index.mjs +4 -2
- package/dist/mocks/index.mjs.map +1 -1
- package/dist/mocks/rpc-client.cjs +185 -20
- package/dist/mocks/rpc-client.cjs.map +1 -1
- package/dist/mocks/rpc-client.d.cts +26 -10
- package/dist/mocks/rpc-client.d.cts.map +1 -1
- package/dist/mocks/rpc-client.d.mts +26 -10
- package/dist/mocks/rpc-client.d.mts.map +1 -1
- package/dist/mocks/rpc-client.mjs +184 -22
- package/dist/mocks/rpc-client.mjs.map +1 -1
- package/dist/promise-queue/index.cjs +10 -4
- package/dist/promise-queue/index.cjs.map +1 -1
- package/dist/promise-queue/index.d.cts +1 -4
- package/dist/promise-queue/index.d.cts.map +1 -1
- package/dist/promise-queue/index.d.mts +1 -4
- package/dist/promise-queue/index.d.mts.map +1 -1
- package/dist/promise-queue/index.mjs +10 -4
- package/dist/promise-queue/index.mjs.map +1 -1
- package/dist/types/index.cjs.map +1 -1
- package/dist/types/index.d.cts +28 -5
- package/dist/types/index.d.cts.map +1 -1
- package/dist/types/index.d.mts +28 -5
- package/dist/types/index.d.mts.map +1 -1
- package/dist/types/index.mjs.map +1 -1
- package/dist/utils/index.cjs +6 -1
- package/dist/utils/index.cjs.map +1 -1
- package/dist/utils/index.d.cts +3 -2
- package/dist/utils/index.d.mts +3 -2
- package/dist/utils/index.mjs +7 -2
- package/dist/utils/index.mjs.map +1 -1
- package/dist/utils/text.cjs +31 -0
- package/dist/utils/text.cjs.map +1 -1
- package/dist/utils/text.d.cts +24 -1
- package/dist/utils/text.d.cts.map +1 -1
- package/dist/utils/text.d.mts +24 -1
- package/dist/utils/text.d.mts.map +1 -1
- package/dist/utils/text.mjs +30 -1
- package/dist/utils/text.mjs.map +1 -1
- package/dist/utils/timeout.cjs +32 -0
- package/dist/utils/timeout.cjs.map +1 -0
- package/dist/utils/timeout.d.cts +18 -0
- package/dist/utils/timeout.d.cts.map +1 -0
- package/dist/utils/timeout.d.mts +18 -0
- package/dist/utils/timeout.d.mts.map +1 -0
- package/dist/utils/timeout.mjs +30 -0
- package/dist/utils/timeout.mjs.map +1 -0
- package/package.json +35 -34
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/ascii.cjs +0 -32
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/ascii.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/ascii.mjs +0 -29
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/ascii.mjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/base64.cjs +0 -67
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/base64.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/base64.mjs +0 -64
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/base64.mjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/bech32.cjs +0 -80
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/bech32.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/bech32.mjs +0 -77
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/bech32.mjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/hex.cjs +0 -33
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/hex.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/hex.mjs +0 -30
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/hex.mjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/index.cjs +0 -106
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/index.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/index.mjs +0 -103
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/index.mjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/rfc3339.cjs +0 -52
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/rfc3339.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/rfc3339.mjs +0 -49
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/rfc3339.mjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/utf8.cjs +0 -31
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/utf8.cjs.map +0 -1
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/utf8.mjs +0 -28
- package/dist/node_modules/.pnpm/@cosmjs_encoding@0.36.0/node_modules/@cosmjs/encoding/build/utf8.mjs.map +0 -1
- package/dist/node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.cjs +0 -98
- package/dist/node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.cjs.map +0 -1
- package/dist/node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.mjs +0 -95
- package/dist/node_modules/.pnpm/base64-js@1.5.1/node_modules/base64-js/index.mjs.map +0 -1
|
@@ -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) {\n this.log.verbose(\"Recover from error. Attempting to disconnect from RPC\");\n try {\n this.client.disconnect();\n }\n catch (_e) { /* empty */ }\n try {\n this.blockClient?.disconnect();\n }\n catch (_e) { /* empty */ }\n this.log.verbose(\"Disconnected from RPC\");\n }\n const connectTimeoutPromise = new Promise<ReturnType<typeof connectComet>>((resolve, reject) => {\n setTimeout(reject, CONNECT_TIMEOUT_MS, new RPCError(\"RPC connection timed out\"));\n });\n this.log.info(\"Attempting to connected to RPC: \" + this.config.rpcUrl);\n this.client = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);\n await Promise.race([this.client.status(), connectTimeoutPromise]);\n this.log.info(\"Connected to RPC for ad hoc queries\");\n this.blockClient = await Promise.race([connectComet(this.config.rpcUrl), connectTimeoutPromise]);\n await Promise.race([this.blockClient.status(), 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 new RPCError(\"RPC status call timed out\"));\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 // 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 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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"}
|
|
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","redactUrl","CircularBuffer","IndexerMetrics","DEFAULT_BIND_HOST","RPCError","ConfigurationError","MAX_FAILURES_PER_BLOCK","IDLE_CHECK_INTERVAL_MS","withTimeout","RPC_TIMEOUT_MS","CONNECT_TIMEOUT_MS","status: StatusResponse","lastProcessed: number | undefined","failingHeight: number | undefined","height: number","timestamp: string","QueryValidatorsResponse","PERIODIC_INTERVALS","retryDelay","RETRY_BASE_DELAY_MS","RETRY_MAX_DELAY_MS","beginBlockEvents: readonly Event[] | readonly Event38[]","endBlockEvents: readonly Event[] | readonly Event38[]","hasBlockEventMode","Tx","events: Array<{\n msg_index?: number\n events: (Event | Event38)[]\n }>","eventsToAdd: typeof events","decodeAttr","MsgExec","events","validators: Validator[]","key: Uint8Array | undefined","QueryValidatorsRequest","PAGINATION_LIMITS","GENESIS_BATCH_SIZE"],"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 pick from \"stream-json/filters/pick.js\";\nimport parser from \"stream-json/parser.js\";\nimport streamArray from \"stream-json/streamers/stream-array.js\";\nimport streamValues from \"stream-json/streamers/stream-values.js\";\nimport batch from \"stream-json/utils/batch.js\";\nimport * as winston from \"winston\";\n\nimport {\n CONNECT_TIMEOUT_MS,\n DEFAULT_BATCH_SIZE, DEFAULT_BIND_HOST, DEFAULT_HEALTH_CHECK_PORT, DEFAULT_POLLING_INTERVAL_MS, DEFAULT_PROMETHEUS_PORT, DEFAULT_START_HEIGHT,\n GENESIS_BATCH_SIZE, IDLE_CHECK_INTERVAL_MS, MAX_FAILURES_PER_BLOCK, PAGINATION_LIMITS, PERIODIC_INTERVALS, RETRY_BASE_DELAY_MS, RETRY_MAX_DELAY_MS, RPC_TIMEOUT_MS,\n} from \"../constants.js\";\nimport {\n EclesiaEmitter,\n} from \"../emitter/index.js\";\nimport {\n ConfigurationError, 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, EclesiaIndexerConfig, EmitFunc, MinimalBlockQueue, WithHeightAndUUID,\n} from \"../types/index.js\";\nimport {\n decodeAttr, hasBlockEventMode, redactUrl, retryDelay, withTimeout,\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 EclesiaIndexerConfig[\"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 EclesiaIndexer extends EclesiaEmitter {\n /** Indexer configuration settings */\n public config: EclesiaIndexerConfig;\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 /** Timer for the next poll in polling mode */\n private pollTimer: NodeJS.Timeout | null = null;\n\n /** Bumped on every (re)start and stop so a polling chain from a previous run exits */\n private pollGeneration = 0;\n\n /** Bumped on every start() so callbacks left over from a previous run cannot trigger recovery in this one */\n private runGeneration = 0;\n\n /**\n * Rejecters of waits parked in waitForBlockData(). Each entry is removed as soon as its block\n * arrives, so a healthy run keeps this empty instead of accumulating one entry per block.\n */\n private blockWaiters = new Set<(error: Error) => void>();\n\n /** Pending restart timer */\n private retryTimer: NodeJS.Timeout | null = null;\n\n /** Resolves when the indexer has stopped for good: stop() was called, endHeight was reached, or it gave up */\n private stopped: Promise<void> = Promise.resolve();\n\n private resolveStopped: () => void = () => {};\n\n /** Next height the fetcher will request; advances as fetches are enqueued */\n private nextFetchHeight = 0;\n\n /** Whether a fetcher loop is active, and for which run */\n private fetcherRunning = false;\n\n private fetcherGeneration = 0;\n\n private fetcherToken = 0;\n\n /** Height of the block whose processing failed most recently, and how many times in a row */\n private lastFailedHeight: number | undefined;\n\n private sameHeightFailures = 0;\n\n /**\n * Creates a new Eclesia indexer instance\n * @param config - Indexer configuration options\n */\n constructor(config: EclesiaIndexerConfig) {\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 // Explicit undefined values (typical when config is assembled from env vars) must not\n // override the defaults, so drop them before merging\n const provided = Object.fromEntries(\n Object.entries(config).filter(([, value]) => value !== undefined),\n ) as EclesiaIndexerConfig;\n this.config = {\n ...defaultIndexerConfig,\n ...provided,\n };\n\n // Structured logging to stdout only: files, rotation and shipping are the deployment's job.\n // Errors are passed as { error } so their stack survives; the text format prints it under\n // the message and the json format emits it as a nested object.\n const errorFormat = winston.format((info) => {\n const error = info.error;\n if (error instanceof Error) {\n info.error = {\n name: error.name,\n message: error.message,\n stack: error.stack,\n };\n }\n else if (error !== undefined && (typeof error !== \"object\" || error === null)) {\n info.error = {\n message: String(error),\n };\n }\n return info;\n });\n const textFormat = winston.format.printf(({\n level, message, timestamp, error,\n }) => {\n const detail = error as {\n stack?: string\n message?: string\n } | undefined;\n const suffix = detail ? \"\\n\" + (detail.stack ?? detail.message ?? \"\") : \"\";\n return `${timestamp} [${level.toUpperCase()}]:\\t${message}${suffix}`;\n });\n this.log = winston.createLogger({\n level: this.config.logLevel,\n defaultMeta: {\n service: \"Eclesia Indexer\",\n },\n transports: [\n new winston.transports.Console({\n format: this.config.logFormat === \"json\"\n ? winston.format.combine(winston.format.splat(),\n winston.format.timestamp(),\n errorFormat(),\n winston.format.json())\n : winston.format.combine(winston.format.splat(),\n winston.format.timestamp(),\n errorFormat(),\n textFormat,\n winston.format.colorize({\n all: true,\n })),\n }),\n ],\n });\n\n // cosmjs cannot subscribe to blocks over plain HTTP; that needs a ws:// or wss:// URL.\n // Switch to polling now instead of failing after several restarts.\n const protocol = new URL(this.config.rpcUrl).protocol;\n if (!this.config.usePolling && (protocol === \"http:\" || protocol === \"https:\")) {\n this.log.warn(\"rpcUrl \" + redactUrl(this.config.rpcUrl) + \" is HTTP, which cannot deliver block subscriptions; polling every \" + this.config.pollingInterval + \" ms instead (use a ws:// or wss:// URL for WebSocket mode)\");\n this.config.usePolling = true;\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\", {\n error: e,\n });\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 // Guarded: this runs once per unhandled message, and winston formats a record before\n // the transport drops it by level\n if (msg.type !== \"uuid\" && this.log.isVerboseEnabled()) {\n this.log.verbose(\"Unhandled event: \" + msg.type);\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: this.config.prometheusHost ?? DEFAULT_BIND_HOST,\n },\n (err) => {\n if (err) {\n this.log.error(\"Prometheus server error\", {\n error: err,\n });\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 // WAITING means caught up with an idle chain, which is healthy\n const code = this.healthCheck.status == \"OK\" || this.healthCheck.status == \"WAITING\"\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: this.config.healthCheckHost ?? DEFAULT_BIND_HOST,\n },\n (err) => {\n if (err) {\n this.log.error(\"Health check server error\", {\n error: err,\n });\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 this.prometheus?.setWaiting(status === \"WAITING\");\n }\n\n /**\n * Marks the current run for recovery and wakes the main loop if it is parked waiting for a\n * block. Callbacks left over from a previous run pass their generation and are ignored.\n */\n private requestRecovery(reason: string, generation: number = this.runGeneration): void {\n if (generation !== this.runGeneration) {\n this.log.debug(\"Ignoring recovery request from a previous run: \" + reason);\n return;\n }\n if (!this.tryToRecover) {\n this.log.warn(\"Recovery requested: \" + reason);\n }\n this.tryToRecover = true;\n this.wakeBlockWaiters(\"Recovery requested while waiting for block data\");\n }\n\n /** Rejects every wait parked in waitForBlockData() */\n private wakeBlockWaiters(reason: string): void {\n const waiters = [...this.blockWaiters];\n this.blockWaiters.clear();\n for (const reject of waiters) {\n reject(new RPCError(reason));\n }\n }\n\n /**\n * Refuses to index a chain other than the configured one. An RPC pool that mixes networks, or\n * a wrong URL, would otherwise write a different chain's blocks into the database.\n */\n private assertChainId(network: string): void {\n if (this.config.chainId !== undefined && network !== this.config.chainId) {\n throw new ConfigurationError(\"RPC serves chain \" + network + \" but chainId is configured as \" + this.config.chainId, {\n expected: this.config.chainId,\n actual: network,\n });\n }\n }\n\n /** Counts consecutive processing failures per block height */\n private noteBlockFailure(height: number): void {\n if (height === this.lastFailedHeight) {\n this.sameHeightFailures++;\n }\n else {\n this.lastFailedHeight = height;\n this.sameHeightFailures = 1;\n }\n }\n\n /** True once one block has failed maxFailuresPerBlock times in a row */\n private isStuck(): boolean {\n return this.lastFailedHeight !== undefined\n && this.sameHeightFailures >= (this.config.maxFailuresPerBlock ?? MAX_FAILURES_PER_BLOCK);\n }\n\n /**\n * Waits for the next dequeued block but wakes early when recovery or stop is requested, so a\n * loop parked on an empty queue never waits for a block that will not come.\n */\n private waitForBlockData<T>(dequeued: Promise<T>): Promise<T> {\n if (this.tryToRecover || !this.started) {\n return Promise.reject(new RPCError(\"Recovery requested while waiting for block data\"));\n }\n return new Promise<T>((resolve, reject) => {\n this.blockWaiters.add(reject);\n dequeued.then((value) => {\n this.blockWaiters.delete(reject);\n resolve(value);\n },\n (error) => {\n this.blockWaiters.delete(reject);\n reject(error);\n });\n });\n }\n\n /** (Re)arms the idle check that runs when no block has been announced for a while */\n private armIdleCheck(): void {\n if (this.blockTimeout) {\n clearTimeout(this.blockTimeout);\n }\n this.blockTimeout = setTimeout(() => {\n this.checkLiveness();\n }, IDLE_CHECK_INTERVAL_MS);\n }\n\n /**\n * Runs when no block has been announced for IDLE_CHECK_INTERVAL_MS. A chain that has stopped\n * producing blocks (halt, upgrade, slow chain) is not an error: the indexer reports WAITING and\n * checks again later. Recovery is requested only when the chain has moved on without us, which\n * means the subscription is dead, or when the RPC cannot be reached at all.\n */\n private async checkLiveness(): Promise<void> {\n if (!this.started) {\n return;\n }\n const generation = this.runGeneration;\n try {\n const status = await withTimeout(this.client.status(), RPC_TIMEOUT_MS, new RPCError(\"RPC status call timed out\"));\n if (!this.started || generation !== this.runGeneration) {\n return;\n }\n const chainHeight = status.syncInfo.latestBlockHeight;\n if (chainHeight > this.latestHeight) {\n this.requestRecovery(\"chain is at \" + chainHeight + \" but nothing was announced since \" + this.latestHeight, generation);\n return;\n }\n this.log.info(\"No new block for \" + IDLE_CHECK_INTERVAL_MS / 1000 + \" s, chain height is still \" + chainHeight);\n this.setStatus(\"WAITING\");\n this.armIdleCheck();\n }\n catch (e) {\n this.log.error(\"Liveness check failed\", {\n error: e,\n });\n this.requestRecovery(\"RPC unreachable during liveness check\", generation);\n }\n }\n\n private blockListener = {\n next: (data: {\n header: {\n height: number\n }\n }) => {\n this.newBlockReceived(data.header.height);\n },\n error: (error: unknown) => {\n this.log.error(\"Block subscription error\", {\n error,\n });\n this.requestRecovery(\"block subscription errored\");\n },\n complete: () => {\n if (this.started) {\n this.requestRecovery(\"block subscription closed by the node\");\n }\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) {\n this.log.verbose(\"Recover from error. Attempting to disconnect from RPC\");\n try {\n this.client.disconnect();\n }\n catch (_e) { /* empty */ }\n try {\n this.blockClient?.disconnect();\n }\n catch (_e) { /* empty */ }\n this.log.verbose(\"Disconnected from RPC\");\n }\n this.log.info(\"Attempting to connect to RPC: \" + redactUrl(this.config.rpcUrl));\n this.client = await this.connectWithTimeout();\n await withTimeout(this.client.status(), CONNECT_TIMEOUT_MS, new RPCError(\"RPC status call timed out\"));\n this.log.info(\"Connected to RPC for ad hoc queries\");\n this.blockClient = await this.connectWithTimeout();\n await withTimeout(this.blockClient.status(), CONNECT_TIMEOUT_MS, new RPCError(\"RPC status call timed out\"));\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\", {\n error,\n });\n this.prometheus?.recordError(\"rpc\");\n this.requestRecovery(\"RPC connection failed\");\n return false;\n }\n }\n\n /**\n * Opens one CometBFT client with its own timeout. If the timeout wins, the client\n * that may still arrive is disconnected so a slow RPC never leaks a socket.\n */\n private async connectWithTimeout(): Promise<CometClient> {\n let timedOut = false;\n const pending = connectComet(this.config.rpcUrl);\n pending.then((client) => {\n if (timedOut) {\n try {\n client.disconnect();\n }\n catch (_e) { /* empty */ }\n }\n }).catch(() => { /* surfaced through the race below */ });\n try {\n return await withTimeout(pending, CONNECT_TIMEOUT_MS, new RPCError(\"RPC connection timed out\"));\n }\n catch (e) {\n timedOut = true;\n throw e;\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\", {\n error: e,\n });\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 else {\n this.log.warn(\"shouldProcessGenesis() returned true but no genesisPath is configured, skipping genesis import\");\n }\n }\n catch (e) {\n this.log.error(\"Failed to parse genesis\", {\n error: e,\n });\n\n this.prometheus?.recordError(\"genesis_error\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n this.initialized = true;\n }\n }\n\n /**\n * Stops the indexer and releases everything that would keep the process alive:\n * the block subscription, polling and inactivity timers, both RPC clients and the\n * health and metrics servers. Safe to call more than once.\n */\n public async stop(): Promise<void> {\n this.started = false;\n this.resolveStopped();\n if (this.retryTimer) {\n clearTimeout(this.retryTimer);\n this.retryTimer = null;\n }\n this.wakeBlockWaiters(\"Indexer stopped while waiting for block data\");\n this.stopPolling();\n if (this.blockTimeout) {\n clearTimeout(this.blockTimeout);\n this.blockTimeout = null;\n }\n if (this.subscription) {\n try {\n this.subscription.removeListener(this.blockListener);\n }\n catch (_e) { /* empty */ }\n this.subscription = null;\n }\n for (const client of [this.client, this.blockClient]) {\n try {\n client?.disconnect();\n }\n catch (_e) { /* empty */ }\n }\n const servers = [this.fastify, this.prometheusServer];\n this.fastify = null;\n this.prometheusServer = null;\n await Promise.all(servers.map(server => server?.close().catch((e: unknown) => {\n this.log.warn(\"Error closing HTTP server\", {\n error: e,\n });\n })));\n this.log.info(\"Indexer stopped\");\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 status: StatusResponse = await withTimeout(this.client.status(), RPC_TIMEOUT_MS, new RPCError(\"RPC status call timed out\"));\n this.assertChainId(status.nodeInfo.network);\n this.latestHeight = status.syncInfo.latestBlockHeight;\n this.log.info(\"Connected to \" + status.nodeInfo.network + \", current chain height: \" + this.latestHeight);\n\n this.heightToProcess = await this.config.getNextHeight();\n this.nextFetchHeight = this.heightToProcess;\n if (this.config.usePolling) {\n this.startPolling();\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 // A subscription that never delivers anything must still be noticed\n this.armIdleCheck();\n }\n catch (e) {\n this.log.error(\"Failed to set up block listening\", {\n error: e,\n });\n this.prometheus?.recordError(\"rpc\");\n this.setStatus(\"FAILED\");\n throw e;\n }\n }\n\n /**\n * Resolves once the indexer has stopped for good: stop() was called, endHeight was reached, or\n * a fatal-error was emitted. Restarts with backoff do not resolve it. Use it to keep a caller\n * waiting for the whole run rather than for the first loop exit.\n */\n public whenStopped(): Promise<void> {\n return this.stopped;\n }\n\n public async start() {\n if (!this.started) {\n // A fresh run (not a restart after backoff) gets a fresh completion promise\n this.stopped = new Promise<void>((resolve) => {\n this.resolveStopped = resolve;\n });\n }\n this.started = true;\n this.runGeneration++;\n const generation = this.runGeneration;\n this.tryToRecover = false;\n this.blockWaiters.clear();\n this.clearBlockQueue();\n await this.initialize();\n try {\n await this.setupBlockListening();\n this.log.debug(\"Starting main processing loop\");\n this.fetcher().catch((e) => {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n this.log.error(\"Error in fetching service\", {\n error: e,\n });\n this.requestRecovery(\"fetcher failed\", generation);\n });\n }\n catch (e) {\n this.requestRecovery(\"block listening setup failed: \" + e, generation);\n }\n\n let lastProcessed: number | undefined;\n while (this.started && !this.tryToRecover) {\n let txOpen = false;\n let failingHeight: number | undefined;\n try {\n this.prometheus?.updateRetryCount(this.retryCount);\n if (this.blockQueue.synced && this.blockQueue.size() <= 1) {\n // Only the sentinel is queued: we are at the chain tip. Waiting here is normal and can\n // last hours during a halt or an upgrade, so no transaction is held while we wait.\n this.setStatus(\"WAITING\");\n }\n let height: number;\n let timestamp: string;\n\n // Main block processing (minimal)\n if (this.isMinimal(this.blockQueue)) {\n const toProcess = await this.waitForBlockData(this.blockQueue.dequeue());\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 failingHeight = height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n // Index block inside a db transaction to ensure data consistency\n await this.config.beginTransaction();\n txOpen = true;\n this.log.silly(\"Started db tx\");\n await this.processBlock(toProcess[0],\n toProcess[1]);\n }\n // Main block processing (full)\n else {\n const toProcess = await this.waitForBlockData(this.blockQueue.dequeue());\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 failingHeight = height;\n timestamp = toRfc3339WithNanoseconds(toProcess[0].block.header.time);\n await this.config.beginTransaction();\n txOpen = true;\n this.log.silly(\"Started db tx\");\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 txOpen = false;\n lastProcessed = height;\n this.lastFailedHeight = undefined;\n this.sameHeightFailures = 0;\n\n this.log.silly(\"Committed db tx\");\n }\n catch (e) {\n if (txOpen) {\n try {\n await this.config.endTransaction(false);\n }\n catch (dbe) {\n this.prometheus?.recordError(\"database\");\n this.log.error(\"Error ending transaction\", {\n error: dbe,\n });\n }\n }\n if (!this.started) {\n // stop() woke us up; nothing failed\n break;\n }\n if (failingHeight !== undefined) {\n // The data was there and processing failed: count it against this block\n this.noteBlockFailure(failingHeight);\n }\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\", {\n error: e,\n });\n this.setStatus(\"FAILED\");\n this.requestRecovery(\"block processing failed\", generation);\n break;\n }\n // Reset retry count and status on successful block processing\n this.retryCount = 0;\n this.setStatus(\"OK\");\n if (this.config.endHeight !== undefined && lastProcessed !== undefined && lastProcessed >= this.config.endHeight) {\n this.log.info(\"Reached configured end height \" + this.config.endHeight + \". Stopping indexer.\");\n await this.stop();\n return;\n }\n }\n\n // Normal exit from processing loop\n if (!this.started) {\n this.log.info(\"Indexer manually stopped.\");\n return;\n }\n\n // A block that keeps failing after its data was fetched is a bug or bad data, not an outage.\n // Give up loudly instead of retrying it forever.\n if (this.isStuck()) {\n const height = this.lastFailedHeight;\n this.log.error(\"Block \" + height + \" failed \" + this.sameHeightFailures + \" times in a row. This is a deterministic failure in a handler or the data, not an outage. Giving up.\");\n this.started = false;\n this.emit(\"fatal-error\", {\n error: new Error(\"Block \" + height + \" failed \" + this.sameHeightFailures + \" times in a row\"),\n message: \"Block processing is stuck\",\n retryCount: this.retryCount,\n height,\n });\n this.resolveStopped();\n return;\n }\n\n // Abnormal exit: restart with exponential backoff. Retries are unlimited unless maxRetries\n // is configured, because an RPC or database outage of any length must not kill the indexer.\n this.retryCount++;\n if (this.config.maxRetries !== undefined && this.retryCount > this.config.maxRetries) {\n this.log.error(\"Indexer failed \" + this.retryCount + \" times in a row, giving up (maxRetries=\" + this.config.maxRetries + \")\");\n this.started = false;\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 this.resolveStopped();\n return;\n }\n const delay = retryDelay(this.retryCount, RETRY_BASE_DELAY_MS, RETRY_MAX_DELAY_MS);\n this.log.warn(\"Indexer is restarting in \" + delay / 1000 + \" s (attempt \" + this.retryCount + \")\");\n this.retryTimer = setTimeout(() => {\n this.retryTimer = null;\n this.start().catch((e) => {\n this.log.error(\"Restart failed\", {\n error: e,\n });\n });\n }, delay);\n }\n\n /**\n * Emits an event and waits for its handlers. Handlers run one after another in registration\n * order: they share one database connection and one transaction, so interleaving them at\n * await points would let two handlers read and write the same rows in an unpredictable order,\n * and a failure in one would leave the others mid-flight while the block is rolled back. The\n * first rejection propagates and stops the remaining handlers.\n */\n public asyncEmit: EmitFunc<keyof WithHeightAndUUID<EventMap>> = async (\n type,\n event,\n ) => {\n const handlers = this.handlersFor(type);\n if (handlers.length === 0) {\n // Same routing as emit(): the _unhandled listener logs it at verbose level\n this.emit(type,\n event);\n return;\n }\n for (const handler of handlers) {\n await handler(event);\n }\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 // Cosmos SDK 0.50+ tags each finalize_block event with mode=BeginBlock / mode=EndBlock (baseapp.go)\n beginBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => hasBlockEventMode(x, \"BeginBlock\")) as readonly Event38[];\n endBlockEvents = (block_results as BlockResultsResponse38).finalizeBlockEvents.filter(x => hasBlockEventMode(x, \"EndBlock\")) 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 }> = [];\n if (txlog) {\n try {\n const parsed = JSON.parse(txlog);\n if (Array.isArray(parsed)) {\n events = parsed;\n }\n }\n catch (_e) {\n // Not every chain writes a JSON log; the msg_index attributes below cover those\n this.log.silly(\"Tx log is not JSON, using msg_index attributes instead\");\n }\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 if (this.log.isSillyEnabled()) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + msgs[i].typeUrl);\n }\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 if (this.log.isSillyEnabled()) {\n this.log.silly(\"Indexer broadcasting msg for handling: \" + authzMsgs[r].typeUrl);\n }\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 /**\n * Fetches every height from nextFetchHeight up to latestHeight, waiting for queue space\n * before each fetch. Serves the initial catch-up and live blocks alike: a new announcement\n * only moves latestHeight and starts this loop if it is not already running, so bursts and\n * skipped announcements are handled by the same code and the queue can never overflow.\n */\n private async fetcher() {\n if (this.fetcherRunning && this.fetcherGeneration === this.runGeneration) {\n return;\n }\n const generation = this.runGeneration;\n const token = ++this.fetcherToken;\n this.fetcherRunning = true;\n this.fetcherGeneration = generation;\n try {\n while (\n this.nextFetchHeight <= this.latestHeight\n && (this.config.endHeight === undefined || this.nextFetchHeight <= this.config.endHeight)\n ) {\n // If some other async process triggers recovery, exit the fetching loop\n if (this.tryToRecover || !this.started || generation !== this.runGeneration) {\n this.log.verbose(\"Exiting fetcher loop. Attempting to recover indexer\");\n break;\n }\n const i = this.nextFetchHeight;\n this.log.debug(\"Fetching: \" + i);\n try {\n // Main fetching logic for minimal indexer\n if (this.isMinimal(this.blockQueue)) {\n // We do not await here so that multiple fetches can be in-flight\n const toIndex = withTimeout(Promise.all([this.blockClient.block(i) as Promise<BlockResponse>, this.blockClient.blockResults(i) as Promise<BlockResultsResponse>]), RPC_TIMEOUT_MS, new RPCError(\"Timed out fetching block \" + i)).catch((e) => {\n this.log.error(\"Error fetching block \" + i, {\n error: e,\n });\n this.prometheus?.recordError(\"rpc\");\n this.requestRecovery(\"fetch failed for block \" + i, generation);\n return Promise.resolve([]);\n }) as Promise<[BlockResponse, BlockResultsResponse]>;\n this.blockQueue.enqueue(toIndex);\n }\n else {\n // Full indexer: block, block results and the complete validator set\n const toIndex = withTimeout(Promise.all([this.blockClient.block(i) as Promise<BlockResponse>, this.blockClient.blockResults(i) as Promise<BlockResultsResponse>, this.fetchValidatorSet(i)]), RPC_TIMEOUT_MS, new RPCError(\"Timed out fetching block \" + i)).catch((e) => {\n this.log.error(\"Error fetching block \" + i, {\n error: e,\n });\n this.prometheus?.recordError(\"rpc\");\n this.requestRecovery(\"fetch failed for block \" + i, generation);\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\", {\n error: e,\n });\n break;\n }\n this.nextFetchHeight = i + 1;\n // Resolves immediately while the queue has room, otherwise when the processor dequeues\n await this.blockQueue.continue();\n }\n // Caught up with everything announced so far\n if (!this.tryToRecover && this.started && generation === this.runGeneration && !this.blockQueue.synced) {\n this.blockQueue.setSynced();\n this.log.info(\"Synced to latest height\");\n }\n }\n finally {\n if (this.fetcherToken === token) {\n this.fetcherRunning = false;\n }\n }\n }\n\n /**\n * Runs an ABCI query. A transport failure (RPC down, timeout, empty reply) requests a recovery.\n * A reply with a non-zero code is the chain answering \"no\" (pruned height, unknown path, bad\n * key): it is thrown as an RPCError with the code and log, and no recovery is requested for\n * ad-hoc queries, so modules can catch it. Block-pipeline queries reject into the fetcher,\n * which requests recovery itself.\n */\n public async callABCI(path: string, data: Uint8Array, height?: number, adHoc: boolean = true): Promise<Uint8Array> {\n let abciq;\n const endTimer = this.prometheus?.timeRpcCall(path) ?? void 0;\n try {\n abciq = await\n (adHoc\n ? this.client\n : this.blockClient).abciQuery({\n path,\n data,\n height: height,\n });\n }\n catch (e) {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n this.requestRecovery(\"ABCI query failed for \" + path);\n throw new RPCError(\"RPC not responding. Query at: \" + path + \" (\" + e + \")\");\n }\n finally {\n endTimer?.();\n }\n if (!abciq) {\n this.setStatus(\"FAILED\");\n this.prometheus?.recordError(\"rpc\");\n this.requestRecovery(\"empty ABCI response for \" + path);\n throw new RPCError(\"RPC not responding. Query at: \" + path);\n }\n if (abciq.code) {\n // Previously an error reply decoded as an empty result (for example zero validators)\n this.prometheus?.recordError(\"rpc\");\n throw new RPCError(\"ABCI query \" + path + \" failed with code \" + abciq.code + (abciq.log ? \": \" + abciq.log : \"\"));\n }\n return abciq.value;\n }\n\n /**\n * Fetches the complete validator set at a height, following pagination, and returns it\n * re-encoded as a single QueryValidatorsResponse so the block queue payload keeps its shape.\n * Chains with more validators than one page (1000) were silently truncated before.\n */\n private async fetchValidatorSet(height: number): Promise<Uint8Array> {\n const validators: Validator[] = [];\n let key: Uint8Array | undefined;\n do {\n const request = QueryValidatorsRequest.fromPartial({\n pagination: key\n ? {\n limit: PAGINATION_LIMITS.VALIDATORS,\n key,\n }\n : {\n limit: PAGINATION_LIMITS.VALIDATORS,\n },\n });\n const page = QueryValidatorsResponse.decode(\n await this.callABCI(\"/cosmos.staking.v1beta1.Query/Validators\", QueryValidatorsRequest.encode(request).finish(), height, false),\n );\n validators.push(...page.validators);\n key = page.pagination?.nextKey && page.pagination.nextKey.length > 0 ? page.pagination.nextKey : undefined;\n } while (key);\n return QueryValidatorsResponse.encode(QueryValidatorsResponse.fromPartial({\n validators,\n })).finish();\n }\n\n private newBlockReceived(height: number): void {\n this.armIdleCheck();\n this.log.info(\"Received new block: %d\",\n height);\n if (height <= this.latestHeight) {\n // Re-announced, or from a lagging node behind a load balancer: never move backwards\n return;\n }\n this.latestHeight = height;\n if (this.tryToRecover || !this.started) {\n return;\n }\n // The fetcher requests every height up to latestHeight and waits for queue space as it\n // goes, so a burst of blocks or an announcement that skipped heights is handled exactly\n // like the initial catch-up. Nothing to do if it is already running.\n this.fetcher().catch((e) => {\n this.log.error(\"Error in fetching service\", {\n error: e,\n });\n this.requestRecovery(\"fetcher failed\");\n });\n }\n\n /** Starts a single polling chain, retiring any chain left over from a previous run */\n private startPolling(): void {\n this.stopPolling();\n const generation = ++this.pollGeneration;\n this.pollForBlock(generation);\n }\n\n private stopPolling(): void {\n this.pollGeneration++;\n if (this.pollTimer) {\n clearTimeout(this.pollTimer);\n this.pollTimer = null;\n }\n }\n\n private async pollForBlock(generation: number) {\n if (!this.started || generation !== this.pollGeneration) {\n return;\n }\n try {\n const status = await this.client.status();\n // A restart or stop may have happened while waiting on the RPC\n if (!this.started || generation !== this.pollGeneration) {\n return;\n }\n if (status.syncInfo.latestBlockHeight > this.latestHeight) {\n this.newBlockReceived(status.syncInfo.latestBlockHeight);\n }\n }\n catch (e) {\n this.log.error(\"Error polling for new block\", {\n error: e,\n });\n this.prometheus?.recordError(\"rpc\");\n this.requestRecovery(\"polling failed\");\n // Recovery restarts polling from setupBlockListening\n return;\n }\n this.pollTimer = setTimeout(() => {\n this.pollForBlock(generation);\n },\n this.config.pollingInterval);\n }\n\n private readGenesis(): fs.ReadStream {\n if (this.config.genesisPath) {\n return fs.createReadStream(this.config.genesisPath);\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({\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 // Pass the chunk on so the \"data\" listener below can count what was processed\n return data;\n };\n\n chain([\n this.readGenesis(),\n parser(),\n ...pickers,\n streamArray(),\n 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 // stream-chain re-emits parser and processor errors here; without a listener Node\n // raises them as an uncaught exception and parseGenesis never rolls back\n .on(\"error\",\n (e) => {\n this.log.error(\"Error reading genesis array \" + path, {\n error: e,\n });\n reject(e);\n });\n }\n catch (e) {\n this.log.verbose(\"Error in setArrayReader: \" + e);\n reject(e);\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({\n filter,\n }));\n\n let counter = 0;\n chain([this.readGenesis(), parser(), ...pickers, 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 .on(\"error\",\n (e) => {\n this.log.error(\"Error reading genesis value \" + path, {\n error: e,\n });\n reject(e);\n });\n }\n catch (e) {\n this.log.verbose(\"Error in setValueReader: \" + e);\n reject(e);\n }\n });\n\n return readPromise;\n }\n\n private async parseGenesis() {\n this.log.info(\"Parsing genesis\");\n // Lets the storage layer mark the import as in progress before anything is written\n await this.config.onGenesisStart?.();\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 // Recorded inside the last transaction, so \"complete\" commits together with the final chunk\n await this.config.onGenesisComplete?.();\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\", {\n error: dbe,\n });\n }\n this.log.error(\"Failed to import genesis\");\n throw e;\n }\n }\n}\n\n/** @deprecated Misspelling kept for compatibility, use EclesiaIndexer. Removed in 3.0. */\nexport const EcleciaIndexer = EclesiaIndexer;\n/** @deprecated Misspelling kept for compatibility, use EclesiaIndexer. Removed in 3.0. */\nexport type EcleciaIndexer = EclesiaIndexer;\n"],"mappings":"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"}
|
package/dist/indexer/index.d.cts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { IndexerMetrics } from "../metrics/index.cjs";
|
|
2
|
-
import {
|
|
2
|
+
import { EclesiaIndexerConfig, EmitFunc, WithHeightAndUUID } from "../types/index.cjs";
|
|
3
3
|
import { EclesiaEmitter } from "../emitter/index.cjs";
|
|
4
4
|
import { CometClient } from "@cosmjs/tendermint-rpc";
|
|
5
5
|
import * as winston from "winston";
|
|
@@ -11,7 +11,7 @@ declare const defaultIndexerConfig: {
|
|
|
11
11
|
batchSize: number;
|
|
12
12
|
modules: never[];
|
|
13
13
|
getNextHeight: () => number;
|
|
14
|
-
logLevel:
|
|
14
|
+
logLevel: EclesiaIndexerConfig["logLevel"];
|
|
15
15
|
usePolling: boolean;
|
|
16
16
|
pollingInterval: number;
|
|
17
17
|
shouldProcessGenesis: () => boolean;
|
|
@@ -28,9 +28,9 @@ declare const defaultIndexerConfig: {
|
|
|
28
28
|
* Core blockchain indexer that connects to Tendermint RPC and processes blocks
|
|
29
29
|
* Extends EclesiaEmitter to provide event-driven architecture for modules
|
|
30
30
|
*/
|
|
31
|
-
declare class
|
|
31
|
+
declare class EclesiaIndexer extends EclesiaEmitter {
|
|
32
32
|
/** Indexer configuration settings */
|
|
33
|
-
config:
|
|
33
|
+
config: EclesiaIndexerConfig;
|
|
34
34
|
/** Fastify HTTP server for health checks */
|
|
35
35
|
private fastify;
|
|
36
36
|
/** Prometheus HTTP server instance */
|
|
@@ -63,31 +63,135 @@ declare class EcleciaIndexer extends EclesiaEmitter {
|
|
|
63
63
|
private subscription;
|
|
64
64
|
/** Timeout handler for block reception */
|
|
65
65
|
private blockTimeout;
|
|
66
|
+
/** Timer for the next poll in polling mode */
|
|
67
|
+
private pollTimer;
|
|
68
|
+
/** Bumped on every (re)start and stop so a polling chain from a previous run exits */
|
|
69
|
+
private pollGeneration;
|
|
70
|
+
/** Bumped on every start() so callbacks left over from a previous run cannot trigger recovery in this one */
|
|
71
|
+
private runGeneration;
|
|
72
|
+
/**
|
|
73
|
+
* Rejecters of waits parked in waitForBlockData(). Each entry is removed as soon as its block
|
|
74
|
+
* arrives, so a healthy run keeps this empty instead of accumulating one entry per block.
|
|
75
|
+
*/
|
|
76
|
+
private blockWaiters;
|
|
77
|
+
/** Pending restart timer */
|
|
78
|
+
private retryTimer;
|
|
79
|
+
/** Resolves when the indexer has stopped for good: stop() was called, endHeight was reached, or it gave up */
|
|
80
|
+
private stopped;
|
|
81
|
+
private resolveStopped;
|
|
82
|
+
/** Next height the fetcher will request; advances as fetches are enqueued */
|
|
83
|
+
private nextFetchHeight;
|
|
84
|
+
/** Whether a fetcher loop is active, and for which run */
|
|
85
|
+
private fetcherRunning;
|
|
86
|
+
private fetcherGeneration;
|
|
87
|
+
private fetcherToken;
|
|
88
|
+
/** Height of the block whose processing failed most recently, and how many times in a row */
|
|
89
|
+
private lastFailedHeight;
|
|
90
|
+
private sameHeightFailures;
|
|
66
91
|
/**
|
|
67
92
|
* Creates a new Eclesia indexer instance
|
|
68
93
|
* @param config - Indexer configuration options
|
|
69
94
|
*/
|
|
70
|
-
constructor(config:
|
|
95
|
+
constructor(config: EclesiaIndexerConfig);
|
|
71
96
|
private setStatus;
|
|
97
|
+
/**
|
|
98
|
+
* Marks the current run for recovery and wakes the main loop if it is parked waiting for a
|
|
99
|
+
* block. Callbacks left over from a previous run pass their generation and are ignored.
|
|
100
|
+
*/
|
|
101
|
+
private requestRecovery;
|
|
102
|
+
/** Rejects every wait parked in waitForBlockData() */
|
|
103
|
+
private wakeBlockWaiters;
|
|
104
|
+
/**
|
|
105
|
+
* Refuses to index a chain other than the configured one. An RPC pool that mixes networks, or
|
|
106
|
+
* a wrong URL, would otherwise write a different chain's blocks into the database.
|
|
107
|
+
*/
|
|
108
|
+
private assertChainId;
|
|
109
|
+
/** Counts consecutive processing failures per block height */
|
|
110
|
+
private noteBlockFailure;
|
|
111
|
+
/** True once one block has failed maxFailuresPerBlock times in a row */
|
|
112
|
+
private isStuck;
|
|
113
|
+
/**
|
|
114
|
+
* Waits for the next dequeued block but wakes early when recovery or stop is requested, so a
|
|
115
|
+
* loop parked on an empty queue never waits for a block that will not come.
|
|
116
|
+
*/
|
|
117
|
+
private waitForBlockData;
|
|
118
|
+
/** (Re)arms the idle check that runs when no block has been announced for a while */
|
|
119
|
+
private armIdleCheck;
|
|
120
|
+
/**
|
|
121
|
+
* Runs when no block has been announced for IDLE_CHECK_INTERVAL_MS. A chain that has stopped
|
|
122
|
+
* producing blocks (halt, upgrade, slow chain) is not an error: the indexer reports WAITING and
|
|
123
|
+
* checks again later. Recovery is requested only when the chain has moved on without us, which
|
|
124
|
+
* means the subscription is dead, or when the RPC cannot be reached at all.
|
|
125
|
+
*/
|
|
126
|
+
private checkLiveness;
|
|
72
127
|
private blockListener;
|
|
73
128
|
private isMinimal;
|
|
74
129
|
connect(): Promise<boolean>;
|
|
130
|
+
/**
|
|
131
|
+
* Opens one CometBFT client with its own timeout. If the timeout wins, the client
|
|
132
|
+
* that may still arrive is disconnected so a slow RPC never leaks a socket.
|
|
133
|
+
*/
|
|
134
|
+
private connectWithTimeout;
|
|
75
135
|
private initialize;
|
|
76
|
-
|
|
136
|
+
/**
|
|
137
|
+
* Stops the indexer and releases everything that would keep the process alive:
|
|
138
|
+
* the block subscription, polling and inactivity timers, both RPC clients and the
|
|
139
|
+
* health and metrics servers. Safe to call more than once.
|
|
140
|
+
*/
|
|
141
|
+
stop(): Promise<void>;
|
|
77
142
|
private clearBlockQueue;
|
|
78
143
|
private setupBlockListening;
|
|
144
|
+
/**
|
|
145
|
+
* Resolves once the indexer has stopped for good: stop() was called, endHeight was reached, or
|
|
146
|
+
* a fatal-error was emitted. Restarts with backoff do not resolve it. Use it to keep a caller
|
|
147
|
+
* waiting for the whole run rather than for the first loop exit.
|
|
148
|
+
*/
|
|
149
|
+
whenStopped(): Promise<void>;
|
|
79
150
|
start(): Promise<void>;
|
|
151
|
+
/**
|
|
152
|
+
* Emits an event and waits for its handlers. Handlers run one after another in registration
|
|
153
|
+
* order: they share one database connection and one transaction, so interleaving them at
|
|
154
|
+
* await points would let two handlers read and write the same rows in an unpredictable order,
|
|
155
|
+
* and a failure in one would leave the others mid-flight while the block is rolled back. The
|
|
156
|
+
* first rejection propagates and stops the remaining handlers.
|
|
157
|
+
*/
|
|
80
158
|
asyncEmit: EmitFunc<keyof WithHeightAndUUID<EventMap>>;
|
|
81
159
|
private processBlock;
|
|
160
|
+
/**
|
|
161
|
+
* Fetches every height from nextFetchHeight up to latestHeight, waiting for queue space
|
|
162
|
+
* before each fetch. Serves the initial catch-up and live blocks alike: a new announcement
|
|
163
|
+
* only moves latestHeight and starts this loop if it is not already running, so bursts and
|
|
164
|
+
* skipped announcements are handled by the same code and the queue can never overflow.
|
|
165
|
+
*/
|
|
82
166
|
private fetcher;
|
|
167
|
+
/**
|
|
168
|
+
* Runs an ABCI query. A transport failure (RPC down, timeout, empty reply) requests a recovery.
|
|
169
|
+
* A reply with a non-zero code is the chain answering "no" (pruned height, unknown path, bad
|
|
170
|
+
* key): it is thrown as an RPCError with the code and log, and no recovery is requested for
|
|
171
|
+
* ad-hoc queries, so modules can catch it. Block-pipeline queries reject into the fetcher,
|
|
172
|
+
* which requests recovery itself.
|
|
173
|
+
*/
|
|
83
174
|
callABCI(path: string, data: Uint8Array, height?: number, adHoc?: boolean): Promise<Uint8Array>;
|
|
175
|
+
/**
|
|
176
|
+
* Fetches the complete validator set at a height, following pagination, and returns it
|
|
177
|
+
* re-encoded as a single QueryValidatorsResponse so the block queue payload keeps its shape.
|
|
178
|
+
* Chains with more validators than one page (1000) were silently truncated before.
|
|
179
|
+
*/
|
|
180
|
+
private fetchValidatorSet;
|
|
84
181
|
private newBlockReceived;
|
|
182
|
+
/** Starts a single polling chain, retiring any chain left over from a previous run */
|
|
183
|
+
private startPolling;
|
|
184
|
+
private stopPolling;
|
|
85
185
|
private pollForBlock;
|
|
86
186
|
private readGenesis;
|
|
87
187
|
private setArrayReader;
|
|
88
188
|
private setValueReader;
|
|
89
189
|
private parseGenesis;
|
|
90
190
|
}
|
|
191
|
+
/** @deprecated Misspelling kept for compatibility, use EclesiaIndexer. Removed in 3.0. */
|
|
192
|
+
declare const EcleciaIndexer: typeof EclesiaIndexer;
|
|
193
|
+
/** @deprecated Misspelling kept for compatibility, use EclesiaIndexer. Removed in 3.0. */
|
|
194
|
+
type EcleciaIndexer = EclesiaIndexer;
|
|
91
195
|
//#endregion
|
|
92
|
-
export { EcleciaIndexer, defaultIndexerConfig };
|
|
196
|
+
export { EcleciaIndexer, EclesiaIndexer, defaultIndexerConfig };
|
|
93
197
|
//# sourceMappingURL=index.d.cts.map
|
|
@@ -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":";;;;;;;;cAmEa;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;EAMH,iBAAA,EAAA,OAAA;EAGK,eAAA,EAAA,MAAA;EAGT,gBAAQ,EAAA,OAAA;EA0DA,cAAA,EAAA,MAAA;EA0VA,IAAA,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;EAsGC,gBAAA,EAAA,GAAA,UAAA,CAAA,IAAA,CAAA;EAmGC,cAAA,EAAA,CAAA,OAAA,EAAA,OAAA,EAAA,GA1oBW,OA0oBX,CAAA,IAAA,CAAA;CAIJ;;;;;AAifqF,cAxnC5F,cAAA,SAAuB,cAAA,CAwnCqE;EAAR;EAxnC7D,MAAA,EAEnB,oBAFmB;EAAc;EA+7CrC,QAAA,OAAA;EAED;;;;;;;;;;;;;cAv6CS;;;;UAMH;;eAGK;;OAGT,OAAA,CAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA0DA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;aA0VA;;;;;;;;;;;;UAsGC;;;;;;;;iBAmGC;WAIJ;;;;;;;;aAkNA,eAAe,kBAAkB;;;;;;;;;;;;;;;;+BA+RT,+CAAqD,QAAQ;;;;;;;;;;;;;;;;;;cAuU5F,uBAAc;;KAEf,cAAA,GAAiB"}
|