diff --git a/packages/indexer-common/src/errors.ts b/packages/indexer-common/src/errors.ts index 01af19fa2..f555d7523 100644 --- a/packages/indexer-common/src/errors.ts +++ b/packages/indexer-common/src/errors.ts @@ -85,6 +85,7 @@ export enum IndexerErrorCode { IE072 = 'IE072', IE073 = 'IE073', IE074 = 'IE074', + IE075 = 'IE075', } export const INDEXER_ERROR_MESSAGES: Record = { @@ -163,6 +164,7 @@ export const INDEXER_ERROR_MESSAGES: Record = { IE072: 'Failed to execute batch tx (contract: staking)', IE073: 'Failed to query subgraph features from indexing statuses endpoint', IE074: 'Failed to deploy subgraph: network not supported', + IE075: 'Failed to connect to network contracts', } export type IndexerErrorCause = unknown diff --git a/packages/indexer-service/src/commands/start.ts b/packages/indexer-service/src/commands/start.ts index 7e4e7c71d..4d97a868f 100644 --- a/packages/indexer-service/src/commands/start.ts +++ b/packages/indexer-service/src/commands/start.ts @@ -11,6 +11,7 @@ import { createLogger, createMetrics, createMetricsServer, + NetworkContracts, SubgraphDeploymentID, toAddress, } from '@graphprotocol/common-ts' @@ -32,6 +33,7 @@ import { createServer } from '../server' import { QueryProcessor } from '../queries' import { ensureAttestationSigners, monitorEligibleAllocations } from '../allocations' import { AllocationReceiptManager } from '../query-fees' +import pRetry from 'p-retry' export default { command: 'start', @@ -333,7 +335,7 @@ export default { chainId: networkIdentifier.chainId, }) - let contracts = undefined + let contracts: NetworkContracts | undefined = undefined try { contracts = await connectContracts( networkProvider, @@ -343,11 +345,8 @@ export default { } catch (error) { logger.error( `Failed to connect to contracts, please ensure you are using the intended Ethereum Network`, - { - error, - }, ) - throw error + throw indexerError(IndexerErrorCode.IE075, error) } logger.info('Successfully connected to contracts', { @@ -377,6 +376,44 @@ export default { operator: address.toString(), }) + // Validate the operator wallet matches the operator set for the indexer + const isOperator = await pRetry( + async () => + contracts!.staking.isOperator( + wallet.address.toString(), + indexerAddress.toString(), + ), + { + retries: 10, + maxTimeout: 10000, + onFailedAttempt: err => { + logger.warn( + `contracts.staking.isOperator(${wallet.address.toString()}, ${indexerAddress.toString()}) failed`, + { + attempt: err.attemptNumber, + retriesLeft: err.retriesLeft, + err: err.message, + }, + ) + }, + } as pRetry.Options, + ) + + if (isOperator == false) { + logger.error( + 'Operator wallet is not allowed for indexer, please see attached debug suggestions', + { + debugSuggestion1: 'verify that operator wallet is set for indexer account', + debugSuggestion2: + 'verify that service and agent are both using correct operator wallet mnemonic', + }, + ) + throw indexerError( + IndexerErrorCode.IE034, + `contracts.staking.isOperator returned 'False'`, + ) + } + // Monitor indexer allocations that we may receive traffic for const allocations = monitorEligibleAllocations({ indexer: indexerAddress,