From 4f2c9689612c0a00db95978507e2005a542b293f Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Thu, 19 Feb 2026 14:50:28 +0200 Subject: [PATCH 01/19] retry connection lost --- src/components/Indexer/index.ts | 60 +++++- .../database/ElasticsearchConfigHelper.ts | 174 ++++++++---------- 2 files changed, 132 insertions(+), 102 deletions(-) diff --git a/src/components/Indexer/index.ts b/src/components/Indexer/index.ts index e261bb453..3c4f2a514 100644 --- a/src/components/Indexer/index.ts +++ b/src/components/Indexer/index.ts @@ -35,9 +35,10 @@ import { BlockchainRegistry } from '../BlockchainRegistry/index.js' import { CommandStatus, JobStatus } from '../../@types/commands.js' import { buildJobIdentifier, getDeployedContractBlock } from './utils.js' import { create256Hash } from '../../utils/crypt.js' -import { isReachableConnection } from '../../utils/database.js' +import { getDatabase, isReachableConnection } from '../../utils/database.js' import { sleep } from '../../utils/util.js' import { isReindexingNeeded } from './version.js' +import { DB_EVENTS, ES_CONNECTION_EVENTS } from '../database/ElasticsearchConfigHelper.js' /** * Event emitter for DDO (Data Descriptor Object) events @@ -82,6 +83,8 @@ export class OceanIndexer { private supportedChains: string[] private indexers: Map = new Map() private MIN_REQUIRED_VERSION = '0.2.2' + private isDbConnected: boolean = true + private reconnectTimer: NodeJS.Timeout | null = null constructor( db: Database, @@ -93,9 +96,64 @@ export class OceanIndexer { this.blockchainRegistry = blockchainRegistry this.supportedChains = Object.keys(supportedNetworks) INDEXING_QUEUE = [] + this.setupDbConnectionListeners() this.startAllChainIndexers() } + /** + * Listen for Elasticsearch connection events. + * + * CONNECTION_LOST → cancel any pending restart, stop all indexers once. + * CONNECTION_RESTORED → debounce restart by 5 s so rapid LOST/RESTORED cycles are a single restart. + */ + private setupDbConnectionListeners(): void { + ES_CONNECTION_EVENTS.on(DB_EVENTS.CONNECTION_LOST, async () => { + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer) + this.reconnectTimer = null + } + + if (!this.isDbConnected) { + return + } + + this.isDbConnected = false + INDEXER_LOGGER.error( + 'Database connection lost - stopping all chain indexers until DB is back' + ) + await this.stopAllChainIndexers() + }) + + ES_CONNECTION_EVENTS.on(DB_EVENTS.CONNECTION_RESTORED, () => { + if (this.isDbConnected) { + return + } + + if (this.reconnectTimer) { + clearTimeout(this.reconnectTimer) + } + + this.reconnectTimer = setTimeout(async () => { + this.reconnectTimer = null + if (this.isDbConnected) { + return + } + + this.isDbConnected = true + numCrawlAttempts = 0 + INDEXER_LOGGER.info( + 'Database connection stable - reinitialising DB and restarting all chain indexers' + ) + const freshDb = await getDatabase(true) + if (freshDb) { + this.db = freshDb + } + + await this.startAllChainIndexers() + }, 5000) + }) + } + public getSupportedNetworks(): RPCS { return this.networks } diff --git a/src/components/database/ElasticsearchConfigHelper.ts b/src/components/database/ElasticsearchConfigHelper.ts index 9838e4ff1..7cd81a5a5 100644 --- a/src/components/database/ElasticsearchConfigHelper.ts +++ b/src/components/database/ElasticsearchConfigHelper.ts @@ -1,9 +1,16 @@ +import EventEmitter from 'node:events' import { Client } from '@elastic/elasticsearch' import { OceanNodeDBConfig } from '../../@types' import { DATABASE_LOGGER } from '../../utils/logging/common.js' import { GENERIC_EMOJIS, LOG_LEVELS_STR } from '../../utils/logging/Logger.js' import { DB_TYPES } from '../../utils/constants.js' +export const DB_EVENTS = { + CONNECTION_LOST: 'db:connection:lost', + CONNECTION_RESTORED: 'db:connection:restored' +} as const +export const ES_CONNECTION_EVENTS = new EventEmitter() + export interface ElasticsearchRetryConfig { requestTimeout?: number pingTimeout?: number @@ -16,20 +23,17 @@ export interface ElasticsearchRetryConfig { } export const DEFAULT_ELASTICSEARCH_CONFIG: Required = { - requestTimeout: parseInt(process.env.ELASTICSEARCH_REQUEST_TIMEOUT || '60000'), - pingTimeout: parseInt(process.env.ELASTICSEARCH_PING_TIMEOUT || '5000'), + requestTimeout: parseInt(process.env.ELASTICSEARCH_REQUEST_TIMEOUT || '30000'), + pingTimeout: parseInt(process.env.ELASTICSEARCH_PING_TIMEOUT || '3000'), resurrectStrategy: (process.env.ELASTICSEARCH_RESURRECT_STRATEGY as 'ping' | 'optimistic' | 'none') || 'ping', - maxRetries: parseInt(process.env.ELASTICSEARCH_MAX_RETRIES || '5'), - sniffOnStart: process.env.ELASTICSEARCH_SNIFF_ON_START !== 'false', - sniffInterval: - process.env.ELASTICSEARCH_SNIFF_INTERVAL === 'false' - ? false - : parseInt(process.env.ELASTICSEARCH_SNIFF_INTERVAL || '30000'), + maxRetries: parseInt(process.env.ELASTICSEARCH_MAX_RETRIES || '3'), + sniffOnStart: process.env.ELASTICSEARCH_SNIFF_ON_START === 'false', + sniffInterval: process.env.ELASTICSEARCH_SNIFF_INTERVAL === 'true' ? 30000 : false, sniffOnConnectionFault: process.env.ELASTICSEARCH_SNIFF_ON_CONNECTION_FAULT !== 'false', healthCheckInterval: parseInt( - process.env.ELASTICSEARCH_HEALTH_CHECK_INTERVAL || '60000' + process.env.ELASTICSEARCH_HEALTH_CHECK_INTERVAL || '15000' ) } @@ -42,6 +46,7 @@ class ElasticsearchClientSingleton { private isRetrying: boolean = false private healthCheckTimer: NodeJS.Timeout | null = null private isMonitoring: boolean = false + private connectionLostEmitted: boolean = false private constructor() {} @@ -73,21 +78,27 @@ class ElasticsearchClientSingleton { } if (this.client && this.config) { + // Skip the extra ping here: 5 DB-class constructors all call getClient() + // during reconnect reinit, and concurrent pings cause false errors that trigger another LOST/RESTORED cycle. + if (this.isMonitoring) { + return this.client + } + const isHealthy = await this.checkConnectionHealth() if (isHealthy) { this.startHealthMonitoring(config, customConfig) return this.client } else { DATABASE_LOGGER.logMessageWithEmoji( - `Elasticsearch connection interrupted or failed to ${this.maskUrl( + `Elasticsearch connection unhealthy at ${this.maskUrl( this.config.url - )} - starting retry phase`, + )} - health monitoring will handle reconnection`, true, GENERIC_EMOJIS.EMOJI_CROSS_MARK, LOG_LEVELS_STR.LEVEL_WARN ) - this.closeConnectionSync() - return this.startRetryConnection(config, customConfig) + this.startHealthMonitoring(config, customConfig) + throw new Error('Elasticsearch connection is not healthy') } } @@ -109,33 +120,62 @@ class ElasticsearchClientSingleton { this.isMonitoring = true DATABASE_LOGGER.logMessageWithEmoji( - `Starting Elasticsearch connection monitoring (health check every ${finalConfig.healthCheckInterval}ms)`, + `Starting Elasticsearch health monitoring (interval: ${finalConfig.healthCheckInterval}ms)`, true, GENERIC_EMOJIS.EMOJI_OCEAN_WAVE, LOG_LEVELS_STR.LEVEL_DEBUG ) this.healthCheckTimer = setInterval(async () => { - if (this.client && !this.isRetrying) { - const isHealthy = await this.checkConnectionHealth() - if (!isHealthy) { + if (this.isRetrying) { + return + } + + const isHealthy = await this.checkConnectionHealth() + if (!isHealthy) { + if (this.client) { + try { + this.client.close() + } catch {} + this.client = null + this.config = null + } + + // Emit CONNECTION_LOST + if (!this.connectionLostEmitted) { + this.connectionLostEmitted = true DATABASE_LOGGER.logMessageWithEmoji( - `Elasticsearch connection lost during monitoring - triggering automatic reconnection`, + `Elasticsearch connection lost to ${this.maskUrl( + config.url + )} - starting reconnection attempts every ${finalConfig.healthCheckInterval}ms`, true, GENERIC_EMOJIS.EMOJI_CROSS_MARK, LOG_LEVELS_STR.LEVEL_WARN ) - this.closeConnectionSync() - try { - await this.startRetryConnection(config, customConfig) - } catch (error) { - DATABASE_LOGGER.logMessageWithEmoji( - `Automatic reconnection failed: ${error.message}`, - true, - GENERIC_EMOJIS.EMOJI_CROSS_MARK, - LOG_LEVELS_STR.LEVEL_ERROR - ) - } + ES_CONNECTION_EVENTS.emit(DB_EVENTS.CONNECTION_LOST) + } + + // Single reconnection attempt + this.isRetrying = true + try { + DATABASE_LOGGER.logMessageWithEmoji( + `Attempting Elasticsearch reconnection to ${this.maskUrl(config.url)}`, + true, + GENERIC_EMOJIS.EMOJI_OCEAN_WAVE, + LOG_LEVELS_STR.LEVEL_INFO + ) + await this.createNewConnection(config, customConfig) + this.isRetrying = false + this.connectionLostEmitted = false + DATABASE_LOGGER.logMessageWithEmoji( + `Elasticsearch connection restored to ${this.maskUrl(config.url)}`, + true, + GENERIC_EMOJIS.EMOJI_CHECK_MARK, + LOG_LEVELS_STR.LEVEL_INFO + ) + ES_CONNECTION_EVENTS.emit(DB_EVENTS.CONNECTION_RESTORED) + } catch { + this.isRetrying = false } } }, finalConfig.healthCheckInterval) @@ -155,71 +195,6 @@ class ElasticsearchClientSingleton { } } - private async startRetryConnection( - config: OceanNodeDBConfig, - customConfig: Partial = {} - ): Promise { - if (!this.isElasticsearchDatabase(config)) { - throw new Error(`Database type '${config.dbType}' is not Elasticsearch`) - } - - this.isRetrying = true - const finalConfig = { - ...DEFAULT_ELASTICSEARCH_CONFIG, - ...customConfig - } - - DATABASE_LOGGER.logMessageWithEmoji( - `Starting Elasticsearch retry connection phase to ${this.maskUrl( - config.url - )} (max retries: ${finalConfig.maxRetries})`, - true, - GENERIC_EMOJIS.EMOJI_OCEAN_WAVE, - LOG_LEVELS_STR.LEVEL_INFO - ) - - for (let attempt = 1; attempt <= finalConfig.maxRetries; attempt++) { - try { - DATABASE_LOGGER.logMessageWithEmoji( - `Elasticsearch reconnection attempt ${attempt}/${ - finalConfig.maxRetries - } to ${this.maskUrl(config.url)}`, - true, - GENERIC_EMOJIS.EMOJI_OCEAN_WAVE, - LOG_LEVELS_STR.LEVEL_INFO - ) - - const client = await this.createNewConnection(config, customConfig) - this.isRetrying = false - return client - } catch (error) { - if (attempt === finalConfig.maxRetries) { - this.isRetrying = false - DATABASE_LOGGER.logMessageWithEmoji( - `Elasticsearch retry connection failed after ${ - finalConfig.maxRetries - } attempts to ${this.maskUrl(config.url)}: ${error.message}`, - true, - GENERIC_EMOJIS.EMOJI_CROSS_MARK, - LOG_LEVELS_STR.LEVEL_ERROR - ) - throw error - } - - const delay = Math.min(1000 * Math.pow(2, attempt - 1), 30000) - DATABASE_LOGGER.logMessageWithEmoji( - `Elasticsearch retry attempt ${attempt}/${finalConfig.maxRetries} failed, waiting ${delay}ms before next attempt: ${error.message}`, - true, - GENERIC_EMOJIS.EMOJI_CROSS_MARK, - LOG_LEVELS_STR.LEVEL_WARN - ) - await new Promise((resolve) => setTimeout(resolve, delay)) - } - } - - throw new Error('Maximum retry attempts reached') - } - private async checkConnectionHealth(): Promise { if (!this.client) return false @@ -228,7 +203,7 @@ class ElasticsearchClientSingleton { return true } catch (error) { DATABASE_LOGGER.logMessageWithEmoji( - `Elasticsearch connection health check failed: ${error.message}`, + `Elasticsearch health check failed: ${error.message}`, true, GENERIC_EMOJIS.EMOJI_CROSS_MARK, LOG_LEVELS_STR.LEVEL_DEBUG @@ -277,9 +252,7 @@ class ElasticsearchClientSingleton { DATABASE_LOGGER.logMessageWithEmoji( `Elasticsearch connection established successfully to ${this.maskUrl( config.url - )} (attempt ${this.connectionAttempts}/${ - finalConfig.maxRetries - }) last successful connection ${this.lastConnectionTime}`, + )} (attempt ${this.connectionAttempts}) last successful connection ${this.lastConnectionTime}`, true, GENERIC_EMOJIS.EMOJI_CHECK_MARK, LOG_LEVELS_STR.LEVEL_INFO @@ -290,9 +263,7 @@ class ElasticsearchClientSingleton { DATABASE_LOGGER.logMessageWithEmoji( `Failed to connect to Elasticsearch at ${this.maskUrl(config.url)} (attempt ${ this.connectionAttempts - }/${finalConfig.maxRetries}) last successful connection ${ - this.lastConnectionTime - }: ${error.message}`, + }) last successful connection ${this.lastConnectionTime}: ${error.message}`, true, GENERIC_EMOJIS.EMOJI_CROSS_MARK, LOG_LEVELS_STR.LEVEL_ERROR @@ -323,6 +294,7 @@ class ElasticsearchClientSingleton { this.client = null this.config = null } + this.connectionLostEmitted = false } public getConnectionStats(): { From 4394210b2a17c78ac21ce50f246490a44186d4ad Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Thu, 19 Feb 2026 18:12:32 +0200 Subject: [PATCH 02/19] temporary debug check --- src/components/core/utils/nonceHandler.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/core/utils/nonceHandler.ts b/src/components/core/utils/nonceHandler.ts index 9fdd86a98..48b925106 100644 --- a/src/components/core/utils/nonceHandler.ts +++ b/src/components/core/utils/nonceHandler.ts @@ -187,12 +187,12 @@ async function validateNonceAndSignature( message: string = null, chainId?: string | null ): Promise { - if (nonce <= existingNonce) { - return { - valid: false, - error: 'nonce: ' + nonce + ' is not a valid nonce' - } - } + // if (nonce <= existingNonce) { + // return { + // valid: false, + // error: 'nonce: ' + nonce + ' is not a valid nonce' + // } + // } if (!message) message = String(nonce) const consumerMessage = ethers.solidityPackedKeccak256( From 6b84b8d57e62f305091e75e12ac2e2e904e8e8cc Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Fri, 20 Feb 2026 10:46:23 +0200 Subject: [PATCH 03/19] revert nonce comment --- src/components/core/utils/nonceHandler.ts | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/components/core/utils/nonceHandler.ts b/src/components/core/utils/nonceHandler.ts index 48b925106..9fdd86a98 100644 --- a/src/components/core/utils/nonceHandler.ts +++ b/src/components/core/utils/nonceHandler.ts @@ -187,12 +187,12 @@ async function validateNonceAndSignature( message: string = null, chainId?: string | null ): Promise { - // if (nonce <= existingNonce) { - // return { - // valid: false, - // error: 'nonce: ' + nonce + ' is not a valid nonce' - // } - // } + if (nonce <= existingNonce) { + return { + valid: false, + error: 'nonce: ' + nonce + ' is not a valid nonce' + } + } if (!message) message = String(nonce) const consumerMessage = ethers.solidityPackedKeccak256( From b64ed20a826ddf82dc6bf5a742cc7cd75a632f4b Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Fri, 20 Feb 2026 14:47:31 +0200 Subject: [PATCH 04/19] revert sniff on start logic and log err --- .../database/ElasticsearchConfigHelper.ts | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/components/database/ElasticsearchConfigHelper.ts b/src/components/database/ElasticsearchConfigHelper.ts index 7cd81a5a5..072ccfc2a 100644 --- a/src/components/database/ElasticsearchConfigHelper.ts +++ b/src/components/database/ElasticsearchConfigHelper.ts @@ -29,8 +29,11 @@ export const DEFAULT_ELASTICSEARCH_CONFIG: Required = (process.env.ELASTICSEARCH_RESURRECT_STRATEGY as 'ping' | 'optimistic' | 'none') || 'ping', maxRetries: parseInt(process.env.ELASTICSEARCH_MAX_RETRIES || '3'), - sniffOnStart: process.env.ELASTICSEARCH_SNIFF_ON_START === 'false', - sniffInterval: process.env.ELASTICSEARCH_SNIFF_INTERVAL === 'true' ? 30000 : false, + sniffOnStart: process.env.ELASTICSEARCH_SNIFF_ON_START !== 'false', + sniffInterval: + process.env.ELASTICSEARCH_SNIFF_INTERVAL === 'false' + ? false + : parseInt(process.env.ELASTICSEARCH_SNIFF_INTERVAL || '30000', 10) || 30000, sniffOnConnectionFault: process.env.ELASTICSEARCH_SNIFF_ON_CONNECTION_FAULT !== 'false', healthCheckInterval: parseInt( process.env.ELASTICSEARCH_HEALTH_CHECK_INTERVAL || '15000' @@ -136,7 +139,14 @@ class ElasticsearchClientSingleton { if (this.client) { try { this.client.close() - } catch {} + } catch (err) { + DATABASE_LOGGER.logMessageWithEmoji( + `Error closing Elasticsearch client during health check: ${err instanceof Error ? err.message : String(err)}`, + true, + GENERIC_EMOJIS.EMOJI_CROSS_MARK, + LOG_LEVELS_STR.LEVEL_DEBUG + ) + } this.client = null this.config = null } From 47ac976a02fd38724cc015e44b07c13b18086d03 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 12:37:44 +0200 Subject: [PATCH 05/19] log errs --- src/index.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/index.ts b/src/index.ts index 532dc363d..1e5109e72 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,6 +24,17 @@ import { scheduleCronJobs } from './utils/cronjobs/scheduleCronJobs.js' import { requestValidator } from './components/httpRoutes/requestValidator.js' import { hasValidDBConfiguration } from './utils/database.js' +process.on('uncaughtException', (err) => { + OCEAN_NODE_LOGGER.error(`Uncaught exception: ${err.message}`) + process.exit(1) +}) +process.on('unhandledRejection', (err) => { + OCEAN_NODE_LOGGER.error( + `Unhandled rejection: ${err instanceof Error ? err.message : String(err)}` + ) + process.exit(1) +}) + const app: Express = express() // const port = getRandomInt(6000,6500) From 36bbd8c3b1f1097edbadc0dbdf39df59dfc265fc Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 12:56:26 +0200 Subject: [PATCH 06/19] free only env and allow no fees object --- src/components/c2d/compute_engine_docker.ts | 6 ++++-- src/utils/config/schemas.ts | 14 ++++++++++---- src/utils/cronjobs/p2pAnnounceC2D.ts | 5 +++-- 3 files changed, 17 insertions(+), 8 deletions(-) diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 2f20300c6..853603d53 100644 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -135,7 +135,8 @@ export class C2DEngineDocker extends C2DEngine { supportedChains.push(parseInt(chain)) } } - for (const feeChain of Object.keys(envConfig.fees)) { + if (envConfig.fees && Object.keys(envConfig.fees).length > 0) { + for (const feeChain of Object.keys(envConfig.fees)) { // for (const feeConfig of envConfig.fees) { if (supportedChains.includes(parseInt(feeChain))) { if (fees === null) fees = {} @@ -169,6 +170,7 @@ export class C2DEngineDocker extends C2DEngine { } fees[feeChain] = tmpFees } + } /* for (const chain of Object.keys(config.supportedNetworks)) { const chainId = parseInt(chain) @@ -436,7 +438,7 @@ export class C2DEngineDocker extends C2DEngine { if (minDuration > 0) { // We need to claim payment - const fee = env.fees[job.payment.chainId]?.find( + const fee = env.fees?.[job.payment.chainId]?.find( (fee) => fee.feeToken === job.payment.token ) diff --git a/src/utils/config/schemas.ts b/src/utils/config/schemas.ts index 4e905871a..87b62d683 100644 --- a/src/utils/config/schemas.ts +++ b/src/utils/config/schemas.ts @@ -163,14 +163,20 @@ export const C2DDockerConfigSchema = z.array( accessLists: z.array(z.string()) }) .optional(), - fees: z.record(z.string(), z.array(ComputeEnvFeesSchema)), + fees: z.record(z.string(), z.array(ComputeEnvFeesSchema)).optional(), free: ComputeEnvironmentFreeOptionsSchema.optional(), imageRetentionDays: z.number().int().min(1).optional().default(7), imageCleanupInterval: z.number().int().min(3600).optional().default(86400) // min 1 hour, default 24 hours }) - .refine((data) => data.fees !== undefined && Object.keys(data.fees).length > 0, { - message: 'There is no fees configuration!' - }) + .refine( + (data) => + (data.fees !== undefined && Object.keys(data.fees).length > 0) || + (data.free !== undefined && data.free !== null), + { + message: + 'Each docker compute environment must have either a non-empty "fees" configuration or a "free" configuration' + } + ) .refine((data) => data.storageExpiry >= data.maxJobDuration, { message: '"storageExpiry" should be greater than "maxJobDuration"' }) diff --git a/src/utils/cronjobs/p2pAnnounceC2D.ts b/src/utils/cronjobs/p2pAnnounceC2D.ts index b1142b6b0..17daf0f57 100644 --- a/src/utils/cronjobs/p2pAnnounceC2D.ts +++ b/src/utils/cronjobs/p2pAnnounceC2D.ts @@ -41,7 +41,8 @@ export async function p2pAnnounceC2D(node: OceanNode) { break } } - for (const resource of env.free.resources) { + if (env.free?.resources) { + for (const resource of env.free.resources) { let min = 0 let kind = null let type = null @@ -89,8 +90,8 @@ export async function p2pAnnounceC2D(node: OceanNode) { break } } + } } - // now announce all resources to p2p network for (const obj of announce) { const res = { c2d: obj From 104a1d2ac6e9db432ef79c9bf31f8f2ea1833662 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 14:48:07 +0200 Subject: [PATCH 07/19] rpc err log --- src/components/Indexer/utils.ts | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/src/components/Indexer/utils.ts b/src/components/Indexer/utils.ts index 84445dfed..54f109c20 100644 --- a/src/components/Indexer/utils.ts +++ b/src/components/Indexer/utils.ts @@ -62,9 +62,17 @@ export const getDeployedContractBlock = (network: number) => { } export const getNetworkHeight = async (provider: FallbackProvider) => { - const networkHeight = await provider.getBlockNumber() - - return networkHeight + try { + const result = await withRetrial(() => provider.getBlockNumber(), 3, 2000) + console.log(`----------> RPC NETWORK HEIGHT: ${result}`) + return result + } catch (error: unknown) { + const msg = (error as Error)?.message ?? String(error) + if (msg.includes('invalid numeric value') || msg.includes('timeout')) { + throw new Error(`RPC timeout fetching block number: ${msg}`) + } + throw error + } } export const retrieveChunkEvents = async ( From 325a29f505c0f4b537b7a920797970361ba0058c Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 14:54:38 +0200 Subject: [PATCH 08/19] timeout rpc --- src/utils/blockchain.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index 11edf4473..fd1b455bc 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -144,12 +144,12 @@ export class Blockchain { private async detectNetwork(): Promise { const provider = await this.getProvider() + const timeoutMs = 10000 // 10s for slow RPCs return new Promise((resolve) => { const timeout = setTimeout(() => { - // timeout, hanging or invalid connection - CORE_LOGGER.error(`Unable to detect provider network: (TIMEOUT)`) + CORE_LOGGER.warn(`Unable to detect provider network: RPC timeout (${timeoutMs}ms)`) resolve({ ready: false, error: 'TIMEOUT' }) - }, 3000) + }, timeoutMs) provider .getBlock('latest') .then((block) => { From 687200dd92849802edb3b49f79bfb912b00a7689 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 15:04:09 +0200 Subject: [PATCH 09/19] Revert "timeout rpc" This reverts commit 325a29f505c0f4b537b7a920797970361ba0058c. --- src/utils/blockchain.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index fd1b455bc..11edf4473 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -144,12 +144,12 @@ export class Blockchain { private async detectNetwork(): Promise { const provider = await this.getProvider() - const timeoutMs = 10000 // 10s for slow RPCs return new Promise((resolve) => { const timeout = setTimeout(() => { - CORE_LOGGER.warn(`Unable to detect provider network: RPC timeout (${timeoutMs}ms)`) + // timeout, hanging or invalid connection + CORE_LOGGER.error(`Unable to detect provider network: (TIMEOUT)`) resolve({ ready: false, error: 'TIMEOUT' }) - }, timeoutMs) + }, 3000) provider .getBlock('latest') .then((block) => { From f90c3c830c2eb61fe82b66aeaa16cbe22ae237ef Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 15:34:41 +0200 Subject: [PATCH 10/19] log provider --- src/utils/blockchain.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index 11edf4473..ccef63b68 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -144,6 +144,8 @@ export class Blockchain { private async detectNetwork(): Promise { const provider = await this.getProvider() + console.log(`----------> PROVIDER: ${provider}`) + console.log(`----------> PROVIDER: ${JSON.stringify(provider)}`) return new Promise((resolve) => { const timeout = setTimeout(() => { // timeout, hanging or invalid connection From 469f2ffbeda406c9be31801e3deb06e3b0193978 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 15:44:03 +0200 Subject: [PATCH 11/19] Revert "log provider" This reverts commit f90c3c830c2eb61fe82b66aeaa16cbe22ae237ef. --- src/utils/blockchain.ts | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index ccef63b68..11edf4473 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -144,8 +144,6 @@ export class Blockchain { private async detectNetwork(): Promise { const provider = await this.getProvider() - console.log(`----------> PROVIDER: ${provider}`) - console.log(`----------> PROVIDER: ${JSON.stringify(provider)}`) return new Promise((resolve) => { const timeout = setTimeout(() => { // timeout, hanging or invalid connection From e32aeefe16379031cb287e5942f605b9d414acee Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 16:17:37 +0200 Subject: [PATCH 12/19] start api before indexer --- src/index.ts | 81 +++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/src/index.ts b/src/index.ts index 1e5109e72..6e633fae2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,46 +120,6 @@ if (!hasValidDBConfiguration(config.dbConfig)) { const keyManager = new KeyManager(config) const blockchainRegistry = new BlockchainRegistry(keyManager, config) -if (config.hasP2P) { - if (dbconn) { - node = new OceanP2P(config, keyManager, dbconn) - } else { - node = new OceanP2P(config, keyManager) - } - await node.start() -} -if (config.hasIndexer && dbconn) { - indexer = new OceanIndexer(dbconn, config.indexingNetworks, blockchainRegistry) - // if we set this var - // it also loads initial data (useful for testing, or we might actually want to have a bootstrap list) - // store and advertise DDOs - if (process.env.LOAD_INITIAL_DDOS && config.hasP2P) { - const list = loadInitialDDOS() - if (list.length > 0) { - // we need a timeout here, otherwise we have no peers available - setTimeout(() => { - node.storeAndAdvertiseDDOS(list) - }, 3000) - } - } -} -if (dbconn) { - provider = new OceanProvider(dbconn) -} - -// Singleton instance across application -const oceanNode = OceanNode.getInstance( - config, - - dbconn, - node, - provider, - indexer, - keyManager, - blockchainRegistry -) -oceanNode.addC2DEngines() - function removeExtraSlashes(req: any, res: any, next: any) { req.url = req.url.replace(/\/{2,}/g, '/') next() @@ -225,7 +185,44 @@ if (config.hasHttp) { OCEAN_NODE_LOGGER.logMessage(`HTTP port: ${config.httpPort}`, true) }) } +} - // Call the function to schedule the cron job to delete old logs - scheduleCronJobs(oceanNode) +if (config.hasP2P) { + if (dbconn) { + node = new OceanP2P(config, keyManager, dbconn) + } else { + node = new OceanP2P(config, keyManager) + } + await node.start() } +if (config.hasIndexer && dbconn) { + indexer = new OceanIndexer(dbconn, config.indexingNetworks, blockchainRegistry) + // if we set this var + // it also loads initial data (useful for testing, or we might actually want to have a bootstrap list) + // store and advertise DDOs + if (process.env.LOAD_INITIAL_DDOS && config.hasP2P) { + const list = loadInitialDDOS() + if (list.length > 0) { + // we need a timeout here, otherwise we have no peers available + setTimeout(() => { + node.storeAndAdvertiseDDOS(list) + }, 3000) + } + } +} +if (dbconn) { + provider = new OceanProvider(dbconn) +} + +// Singleton instance across application +const oceanNode = OceanNode.getInstance( + config, + dbconn, + node, + provider, + indexer, + keyManager, + blockchainRegistry +) +oceanNode.addC2DEngines() +scheduleCronJobs(oceanNode) From fabc740c18ec051cecd7ae4ba702b14598d942b0 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 16:47:12 +0200 Subject: [PATCH 13/19] start indexer later --- src/components/Indexer/index.ts | 7 ++- src/index.ts | 83 ++++++++++++++++++--------------- 2 files changed, 51 insertions(+), 39 deletions(-) diff --git a/src/components/Indexer/index.ts b/src/components/Indexer/index.ts index 3c4f2a514..78e2138f9 100644 --- a/src/components/Indexer/index.ts +++ b/src/components/Indexer/index.ts @@ -97,7 +97,12 @@ export class OceanIndexer { this.supportedChains = Object.keys(supportedNetworks) INDEXING_QUEUE = [] this.setupDbConnectionListeners() - this.startAllChainIndexers() + } + + public start(): void { + void this.startAllChainIndexers().catch((err) => { + INDEXER_LOGGER.error(`startAllChainIndexers failed: ${err?.message ?? err}`) + }) } /** diff --git a/src/index.ts b/src/index.ts index 6e633fae2..de6a141b1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -120,6 +120,46 @@ if (!hasValidDBConfiguration(config.dbConfig)) { const keyManager = new KeyManager(config) const blockchainRegistry = new BlockchainRegistry(keyManager, config) +if (config.hasP2P) { + if (dbconn) { + node = new OceanP2P(config, keyManager, dbconn) + } else { + node = new OceanP2P(config, keyManager) + } + await node.start() +} +if (config.hasIndexer && dbconn) { + indexer = new OceanIndexer(dbconn, config.indexingNetworks, blockchainRegistry) + // if we set this var + // it also loads initial data (useful for testing, or we might actually want to have a bootstrap list) + // store and advertise DDOs + if (process.env.LOAD_INITIAL_DDOS && config.hasP2P) { + const list = loadInitialDDOS() + if (list.length > 0) { + // we need a timeout here, otherwise we have no peers available + setTimeout(() => { + node.storeAndAdvertiseDDOS(list) + }, 3000) + } + } +} +if (dbconn) { + provider = new OceanProvider(dbconn) +} + +// Singleton instance across application +const oceanNode = OceanNode.getInstance( + config, + + dbconn, + node, + provider, + indexer, + keyManager, + blockchainRegistry +) +oceanNode.addC2DEngines() + function removeExtraSlashes(req: any, res: any, next: any) { req.url = req.url.replace(/\/{2,}/g, '/') next() @@ -185,44 +225,11 @@ if (config.hasHttp) { OCEAN_NODE_LOGGER.logMessage(`HTTP port: ${config.httpPort}`, true) }) } -} -if (config.hasP2P) { - if (dbconn) { - node = new OceanP2P(config, keyManager, dbconn) - } else { - node = new OceanP2P(config, keyManager) - } - await node.start() -} -if (config.hasIndexer && dbconn) { - indexer = new OceanIndexer(dbconn, config.indexingNetworks, blockchainRegistry) - // if we set this var - // it also loads initial data (useful for testing, or we might actually want to have a bootstrap list) - // store and advertise DDOs - if (process.env.LOAD_INITIAL_DDOS && config.hasP2P) { - const list = loadInitialDDOS() - if (list.length > 0) { - // we need a timeout here, otherwise we have no peers available - setTimeout(() => { - node.storeAndAdvertiseDDOS(list) - }, 3000) - } - } -} -if (dbconn) { - provider = new OceanProvider(dbconn) + // Call the function to schedule the cron job to delete old logs + scheduleCronJobs(oceanNode) } -// Singleton instance across application -const oceanNode = OceanNode.getInstance( - config, - dbconn, - node, - provider, - indexer, - keyManager, - blockchainRegistry -) -oceanNode.addC2DEngines() -scheduleCronJobs(oceanNode) +if (indexer) { + indexer.start() +} From 912c071c9eaaa3c7e96a72b98e4f7c6d0bedc76e Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 17:02:03 +0200 Subject: [PATCH 14/19] timeout rpc --- src/components/Indexer/index.ts | 5 ++--- src/utils/blockchain.ts | 16 +++++++++++++++- 2 files changed, 17 insertions(+), 4 deletions(-) diff --git a/src/components/Indexer/index.ts b/src/components/Indexer/index.ts index 78e2138f9..f53d87cd3 100644 --- a/src/components/Indexer/index.ts +++ b/src/components/Indexer/index.ts @@ -220,11 +220,10 @@ export class OceanIndexer { async retryCrawlerWithDelay( blockchain: Blockchain, - interval: number = 5000 // in milliseconds, default 5 secs + interval: number = 2000 // in milliseconds, default 2 secs ): Promise { try { - const retryInterval = Math.max(blockchain.getKnownRPCs().length * 3000, interval) // give 2 secs per each one - // try + const retryInterval = Math.max(blockchain.getKnownRPCs().length * 1500, interval) const result = await this.startCrawler(blockchain) const dbActive = this.getDatabase() if (!dbActive || !(await isReachableConnection(dbActive.getConfig().url))) { diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index 11edf4473..08731ccba 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -26,6 +26,16 @@ const POLYGON_NETWORK_ID = 137 const MUMBAI_NETWORK_ID = 80001 const SEPOLIA_NETWORK_ID = 11155111 +/** Max time to wait for RPC network check so we don't block the event loop when RPC is unreachable */ +const RPC_NETWORK_CHECK_TIMEOUT_MS = 5000 + +function withTimeout(promise: Promise, ms: number, message: string): Promise { + return Promise.race([ + promise, + new Promise((_, reject) => setTimeout(() => reject(new Error(message)), ms)) + ]) +} + export class Blockchain { private config?: OceanNodeConfig // Optional for new constructor private static signers: Map = new Map() @@ -77,7 +87,11 @@ export class Blockchain { // filter wrong chains or broken RPCs if (!force) { try { - const { chainId } = await rpcProvider.getNetwork() + const { chainId } = await withTimeout( + rpcProvider.getNetwork(), + RPC_NETWORK_CHECK_TIMEOUT_MS, + 'RPC network check timeout' + ) if (chainId.toString() === this.chainId.toString()) { this.providers.push(rpcProvider) break From 2f719d9540688c6e1a939c979e9e50a7fbedbf6e Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 17:14:40 +0200 Subject: [PATCH 15/19] catch no rpcs --- src/utils/blockchain.ts | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index 08731ccba..96ce602f7 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -103,6 +103,9 @@ export class Blockchain { this.providers.push(new JsonRpcProvider(rpc)) } } + if (this.providers.length === 0) { + throw new Error('No RPC provider available (all endpoints failed or timed out)') + } this.provider = new FallbackProvider(this.providers) } return this.provider @@ -157,7 +160,13 @@ export class Blockchain { } private async detectNetwork(): Promise { - const provider = await this.getProvider() + let provider: FallbackProvider + try { + provider = await this.getProvider() + } catch (err) { + CORE_LOGGER.error(`Unable to detect provider network: ${err.message}`) + return { ready: false, error: err.message } + } return new Promise((resolve) => { const timeout = setTimeout(() => { // timeout, hanging or invalid connection From d205ca1185ddb9cb39c607b1ebafb2da8ee9aa1a Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 17:44:33 +0200 Subject: [PATCH 16/19] update deps --- package-lock.json | 8 ++++---- package.json | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index e6e774f06..9f946198b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -44,7 +44,7 @@ "dotenv": "^16.3.1", "eciesjs": "^0.4.5", "eth-crypto": "^2.6.0", - "ethers": "^6.8.1", + "ethers": "^6.16.0", "express": "^4.21.1", "humanhash": "^1.0.4", "hyperdiff": "^2.0.16", @@ -9923,9 +9923,9 @@ "license": "MIT" }, "node_modules/ethers": { - "version": "6.15.0", - "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.15.0.tgz", - "integrity": "sha512-Kf/3ZW54L4UT0pZtsY/rf+EkBU7Qi5nnhonjUb8yTXcxH3cdcWrV2cRyk0Xk/4jK6OoHhxxZHriyhje20If2hQ==", + "version": "6.16.0", + "resolved": "https://registry.npmjs.org/ethers/-/ethers-6.16.0.tgz", + "integrity": "sha512-U1wulmetNymijEhpSEQ7Ct/P/Jw9/e7R1j5XIbPRydgV2DjLVMsULDlNksq3RQnFgKoLlZf88ijYtWEXcPa07A==", "funding": [ { "type": "individual", diff --git a/package.json b/package.json index 29b8ce2a7..9300287d3 100644 --- a/package.json +++ b/package.json @@ -83,7 +83,7 @@ "dotenv": "^16.3.1", "eciesjs": "^0.4.5", "eth-crypto": "^2.6.0", - "ethers": "^6.8.1", + "ethers": "^6.16.0", "express": "^4.21.1", "humanhash": "^1.0.4", "hyperdiff": "^2.0.16", From 4b727df1265f69b74a202f8b950bc9397a2119fa Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 17:59:38 +0200 Subject: [PATCH 17/19] start indexer in bg --- src/components/Indexer/index.ts | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/src/components/Indexer/index.ts b/src/components/Indexer/index.ts index f53d87cd3..3637ac727 100644 --- a/src/components/Indexer/index.ts +++ b/src/components/Indexer/index.ts @@ -312,24 +312,22 @@ export class OceanIndexer { return indexer } - // Start all chain indexers - public async startAllChainIndexers(): Promise { + // Start all chain indexers (fire-and-forget: returns once starts are kicked off, does not wait for each chain) + public async startAllChainIndexers(): Promise { await this.checkAndTriggerReindexing() // Setup event listeners for all chains (they all use the same event emitter) this.setupEventListeners() - // Start all indexers - they will run concurrently via async/await - let count = 0 + // Kick off all indexers in background; do not await so callers are not blocked for (const network of this.supportedChains) { const chainId = parseInt(network) - const indexer = await this.startChainIndexer(chainId) - if (indexer) { - count++ - } + this.startChainIndexer(chainId).catch((err) => { + INDEXER_LOGGER.error( + `Failed to start indexer for chain ${chainId}: ${err?.message ?? err}` + ) + }) } - - return count === this.supportedChains.length } private setupEventListeners() { From 0b5183db1c331205772fcf78c026bdf4bb0fd896 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 19:01:05 +0200 Subject: [PATCH 18/19] revert unused changes --- src/components/Indexer/index.ts | 29 ++++---- src/components/Indexer/utils.ts | 14 +--- src/components/c2d/compute_engine_docker.ts | 54 +++++++-------- src/index.ts | 15 ---- src/utils/blockchain.ts | 19 +----- src/utils/cronjobs/p2pAnnounceC2D.ts | 76 ++++++++++----------- 6 files changed, 82 insertions(+), 125 deletions(-) diff --git a/src/components/Indexer/index.ts b/src/components/Indexer/index.ts index 3637ac727..fd9e94476 100644 --- a/src/components/Indexer/index.ts +++ b/src/components/Indexer/index.ts @@ -97,12 +97,7 @@ export class OceanIndexer { this.supportedChains = Object.keys(supportedNetworks) INDEXING_QUEUE = [] this.setupDbConnectionListeners() - } - - public start(): void { - void this.startAllChainIndexers().catch((err) => { - INDEXER_LOGGER.error(`startAllChainIndexers failed: ${err?.message ?? err}`) - }) + this.startAllChainIndexers() } /** @@ -220,10 +215,10 @@ export class OceanIndexer { async retryCrawlerWithDelay( blockchain: Blockchain, - interval: number = 2000 // in milliseconds, default 2 secs + interval: number = 5000 // in milliseconds, default 2 secs ): Promise { try { - const retryInterval = Math.max(blockchain.getKnownRPCs().length * 1500, interval) + const retryInterval = Math.max(blockchain.getKnownRPCs().length * 3000, interval) // give 2 secs per each one const result = await this.startCrawler(blockchain) const dbActive = this.getDatabase() if (!dbActive || !(await isReachableConnection(dbActive.getConfig().url))) { @@ -312,22 +307,24 @@ export class OceanIndexer { return indexer } - // Start all chain indexers (fire-and-forget: returns once starts are kicked off, does not wait for each chain) - public async startAllChainIndexers(): Promise { + // Start all chain indexers + public async startAllChainIndexers(): Promise { await this.checkAndTriggerReindexing() // Setup event listeners for all chains (they all use the same event emitter) this.setupEventListeners() - // Kick off all indexers in background; do not await so callers are not blocked + // Start all indexers - they will run concurrently via async/await + let count = 0 for (const network of this.supportedChains) { const chainId = parseInt(network) - this.startChainIndexer(chainId).catch((err) => { - INDEXER_LOGGER.error( - `Failed to start indexer for chain ${chainId}: ${err?.message ?? err}` - ) - }) + const indexer = await this.startChainIndexer(chainId) + if (indexer) { + count++ + } } + + return count === this.supportedChains.length } private setupEventListeners() { diff --git a/src/components/Indexer/utils.ts b/src/components/Indexer/utils.ts index 54f109c20..84445dfed 100644 --- a/src/components/Indexer/utils.ts +++ b/src/components/Indexer/utils.ts @@ -62,17 +62,9 @@ export const getDeployedContractBlock = (network: number) => { } export const getNetworkHeight = async (provider: FallbackProvider) => { - try { - const result = await withRetrial(() => provider.getBlockNumber(), 3, 2000) - console.log(`----------> RPC NETWORK HEIGHT: ${result}`) - return result - } catch (error: unknown) { - const msg = (error as Error)?.message ?? String(error) - if (msg.includes('invalid numeric value') || msg.includes('timeout')) { - throw new Error(`RPC timeout fetching block number: ${msg}`) - } - throw error - } + const networkHeight = await provider.getBlockNumber() + + return networkHeight } export const retrieveChunkEvents = async ( diff --git a/src/components/c2d/compute_engine_docker.ts b/src/components/c2d/compute_engine_docker.ts index 853603d53..5d6222721 100644 --- a/src/components/c2d/compute_engine_docker.ts +++ b/src/components/c2d/compute_engine_docker.ts @@ -137,40 +137,40 @@ export class C2DEngineDocker extends C2DEngine { } if (envConfig.fees && Object.keys(envConfig.fees).length > 0) { for (const feeChain of Object.keys(envConfig.fees)) { - // for (const feeConfig of envConfig.fees) { - if (supportedChains.includes(parseInt(feeChain))) { - if (fees === null) fees = {} - if (!(feeChain in fees)) fees[feeChain] = [] - const tmpFees: ComputeEnvFees[] = [] - for (let i = 0; i < envConfig.fees[feeChain].length; i++) { - if ( - envConfig.fees[feeChain][i].prices && - envConfig.fees[feeChain][i].prices.length > 0 - ) { - if (!envConfig.fees[feeChain][i].feeToken) { - const tokenAddress = getOceanTokenAddressForChain(parseInt(feeChain)) - if (tokenAddress) { - envConfig.fees[feeChain][i].feeToken = tokenAddress - tmpFees.push(envConfig.fees[feeChain][i]) + // for (const feeConfig of envConfig.fees) { + if (supportedChains.includes(parseInt(feeChain))) { + if (fees === null) fees = {} + if (!(feeChain in fees)) fees[feeChain] = [] + const tmpFees: ComputeEnvFees[] = [] + for (let i = 0; i < envConfig.fees[feeChain].length; i++) { + if ( + envConfig.fees[feeChain][i].prices && + envConfig.fees[feeChain][i].prices.length > 0 + ) { + if (!envConfig.fees[feeChain][i].feeToken) { + const tokenAddress = getOceanTokenAddressForChain(parseInt(feeChain)) + if (tokenAddress) { + envConfig.fees[feeChain][i].feeToken = tokenAddress + tmpFees.push(envConfig.fees[feeChain][i]) + } else { + CORE_LOGGER.error( + `Unable to find Ocean token address for chain ${feeChain} and no custom token provided` + ) + } } else { - CORE_LOGGER.error( - `Unable to find Ocean token address for chain ${feeChain} and no custom token provided` - ) + tmpFees.push(envConfig.fees[feeChain][i]) } } else { - tmpFees.push(envConfig.fees[feeChain][i]) + CORE_LOGGER.error( + `Unable to find prices for fee ${JSON.stringify( + envConfig.fees[feeChain][i] + )} on chain ${feeChain}` + ) } - } else { - CORE_LOGGER.error( - `Unable to find prices for fee ${JSON.stringify( - envConfig.fees[feeChain][i] - )} on chain ${feeChain}` - ) } + fees[feeChain] = tmpFees } - fees[feeChain] = tmpFees } - } /* for (const chain of Object.keys(config.supportedNetworks)) { const chainId = parseInt(chain) diff --git a/src/index.ts b/src/index.ts index de6a141b1..532dc363d 100644 --- a/src/index.ts +++ b/src/index.ts @@ -24,17 +24,6 @@ import { scheduleCronJobs } from './utils/cronjobs/scheduleCronJobs.js' import { requestValidator } from './components/httpRoutes/requestValidator.js' import { hasValidDBConfiguration } from './utils/database.js' -process.on('uncaughtException', (err) => { - OCEAN_NODE_LOGGER.error(`Uncaught exception: ${err.message}`) - process.exit(1) -}) -process.on('unhandledRejection', (err) => { - OCEAN_NODE_LOGGER.error( - `Unhandled rejection: ${err instanceof Error ? err.message : String(err)}` - ) - process.exit(1) -}) - const app: Express = express() // const port = getRandomInt(6000,6500) @@ -229,7 +218,3 @@ if (config.hasHttp) { // Call the function to schedule the cron job to delete old logs scheduleCronJobs(oceanNode) } - -if (indexer) { - indexer.start() -} diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index 96ce602f7..ab971052c 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -26,16 +26,6 @@ const POLYGON_NETWORK_ID = 137 const MUMBAI_NETWORK_ID = 80001 const SEPOLIA_NETWORK_ID = 11155111 -/** Max time to wait for RPC network check so we don't block the event loop when RPC is unreachable */ -const RPC_NETWORK_CHECK_TIMEOUT_MS = 5000 - -function withTimeout(promise: Promise, ms: number, message: string): Promise { - return Promise.race([ - promise, - new Promise((_, reject) => setTimeout(() => reject(new Error(message)), ms)) - ]) -} - export class Blockchain { private config?: OceanNodeConfig // Optional for new constructor private static signers: Map = new Map() @@ -87,11 +77,7 @@ export class Blockchain { // filter wrong chains or broken RPCs if (!force) { try { - const { chainId } = await withTimeout( - rpcProvider.getNetwork(), - RPC_NETWORK_CHECK_TIMEOUT_MS, - 'RPC network check timeout' - ) + const { chainId } = await rpcProvider.getNetwork() if (chainId.toString() === this.chainId.toString()) { this.providers.push(rpcProvider) break @@ -103,9 +89,6 @@ export class Blockchain { this.providers.push(new JsonRpcProvider(rpc)) } } - if (this.providers.length === 0) { - throw new Error('No RPC provider available (all endpoints failed or timed out)') - } this.provider = new FallbackProvider(this.providers) } return this.provider diff --git a/src/utils/cronjobs/p2pAnnounceC2D.ts b/src/utils/cronjobs/p2pAnnounceC2D.ts index 17daf0f57..156a2ae80 100644 --- a/src/utils/cronjobs/p2pAnnounceC2D.ts +++ b/src/utils/cronjobs/p2pAnnounceC2D.ts @@ -43,54 +43,54 @@ export async function p2pAnnounceC2D(node: OceanNode) { } if (env.free?.resources) { for (const resource of env.free.resources) { - let min = 0 - let kind = null - let type = null - // we need to get the min from resources - for (const res of env.resources) { - if (res.id === resource.id) { - ;({ min } = res) - ;({ kind } = res) - ;({ type } = res) + let min = 0 + let kind = null + let type = null + // we need to get the min from resources + for (const res of env.resources) { + if (res.id === resource.id) { + ;({ min } = res) + ;({ kind } = res) + ;({ type } = res) + } } - } - switch (type) { - case 'cpu': - case 'gpu': - // For CPU and GPU, we assume the min and max are in terms of cores - // and we generate announcements for each core count in the range - // if min is not defined, we assume it is 1 - for (let i = min || 1; i <= resource.max; i++) { - const obj: Record = {} - obj.free = true - obj[type] = i - if (!announce.includes(obj)) { - announce.push(obj) - } - if (type === 'gpu' && kind) { - obj.kind = kind // add kind if available + switch (type) { + case 'cpu': + case 'gpu': + // For CPU and GPU, we assume the min and max are in terms of cores + // and we generate announcements for each core count in the range + // if min is not defined, we assume it is 1 + for (let i = min || 1; i <= resource.max; i++) { + const obj: Record = {} + obj.free = true + obj[type] = i if (!announce.includes(obj)) { announce.push(obj) } + if (type === 'gpu' && kind) { + obj.kind = kind // add kind if available + if (!announce.includes(obj)) { + announce.push(obj) + } + } } - } - break + break - case 'ram': - case 'disk': - for (let i = min; i <= resource.max; i += GB) { - const obj: Record = {} - obj.free = true - obj[type] = Math.round(i / GB) - if (!announce.includes(obj) && obj[type] > 0) { - announce.push(obj) + case 'ram': + case 'disk': + for (let i = min; i <= resource.max; i += GB) { + const obj: Record = {} + obj.free = true + obj[type] = Math.round(i / GB) + if (!announce.includes(obj) && obj[type] > 0) { + announce.push(obj) + } } - } - break + break + } } } - } } for (const obj of announce) { const res = { From e14a719f5ddf53585d2a05f16aa6e8170774e3a8 Mon Sep 17 00:00:00 2001 From: giurgiur99 Date: Tue, 24 Feb 2026 19:02:39 +0200 Subject: [PATCH 19/19] revert try catch network height --- src/utils/blockchain.ts | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/src/utils/blockchain.ts b/src/utils/blockchain.ts index ab971052c..11edf4473 100644 --- a/src/utils/blockchain.ts +++ b/src/utils/blockchain.ts @@ -143,13 +143,7 @@ export class Blockchain { } private async detectNetwork(): Promise { - let provider: FallbackProvider - try { - provider = await this.getProvider() - } catch (err) { - CORE_LOGGER.error(`Unable to detect provider network: ${err.message}`) - return { ready: false, error: err.message } - } + const provider = await this.getProvider() return new Promise((resolve) => { const timeout = setTimeout(() => { // timeout, hanging or invalid connection