From 75ccd459531648a1d47596997cbbe6514b7521c1 Mon Sep 17 00:00:00 2001 From: Eddort Date: Wed, 17 Jan 2024 18:46:47 +0100 Subject: [PATCH] feat: compare chainId and compare app version --- package.json | 7 ++++--- src/guardian/guardian.constants.ts | 1 + src/guardian/guardian.module.ts | 2 ++ src/guardian/guardian.service.ts | 30 ++++++++++++++++++++++++++++++ src/keys-api/interfaces/Status.ts | 6 ++++++ src/keys-api/interfaces/index.ts | 1 + src/keys-api/keys-api.service.ts | 12 +++++++++++- yarn.lock | 5 +++++ 8 files changed, 60 insertions(+), 4 deletions(-) create mode 100644 src/keys-api/interfaces/Status.ts diff --git a/package.json b/package.json index ff643b35..e3257fa0 100644 --- a/package.json +++ b/package.json @@ -33,6 +33,7 @@ "@chainsafe/ssz": "^0.9.2", "@ethersproject/providers": "^5.4.5", "@lido-nestjs/fetch": "^1.3.1", + "@lido-nestjs/key-validation": "^7.4.0", "@lido-nestjs/middleware": "^1.1.1", "@lido-sdk/constants": "^3.2.1", "@nestjs/common": "^8.0.0", @@ -41,15 +42,16 @@ "@nestjs/platform-express": "^8.1.1", "@nestjs/schedule": "^2.1.0", "@nestjs/terminus": "^8.0.1", - "@lido-nestjs/key-validation": "^7.4.0", "@willsoto/nestjs-prometheus": "^4.0.1", "app-root-path": "^3.0.0", "cache-manager": "^3.6.3", "class-transformer": "^0.5.1", "class-validator": "^0.14.0", + "compare-versions": "^6.1.0", "ethers": "^5.4.7", "glob": "^7.1.2", "kafkajs": "^1.15.0", + "lru-cache": "^9.1.1", "nest-winston": "^1.6.1", "node-abort-controller": "^3.0.1", "prom-client": "^14.0.0", @@ -57,8 +59,7 @@ "rimraf": "^3.0.2", "rxjs": "^7.2.0", "winston": "^3.3.3", - "ws": "^8.10.0", - "lru-cache": "^9.1.1" + "ws": "^8.10.0" }, "devDependencies": { "@nestjs/cli": "^8.2.5", diff --git a/src/guardian/guardian.constants.ts b/src/guardian/guardian.constants.ts index 490108bb..23fab3fa 100644 --- a/src/guardian/guardian.constants.ts +++ b/src/guardian/guardian.constants.ts @@ -3,3 +3,4 @@ import { CronExpression } from '@nestjs/schedule'; export const GUARDIAN_DEPOSIT_RESIGNING_BLOCKS = 10; export const GUARDIAN_DEPOSIT_JOB_NAME = 'guardian-deposit-job'; export const GUARDIAN_DEPOSIT_JOB_DURATION = CronExpression.EVERY_5_SECONDS; +export const MIN_KAPI_VERSION = '0.10.2'; diff --git a/src/guardian/guardian.module.ts b/src/guardian/guardian.module.ts index 15cefcad..dc129cc1 100644 --- a/src/guardian/guardian.module.ts +++ b/src/guardian/guardian.module.ts @@ -10,6 +10,7 @@ import { BlockGuardModule } from './block-guard/block-guard.module'; import { StakingModuleGuardModule } from './staking-module-guard'; import { GuardianMessageModule } from './guardian-message'; import { GuardianMetricsModule } from './guardian-metrics'; +import { KeysApiModule } from 'keys-api/keys-api.module'; @Module({ imports: [ @@ -23,6 +24,7 @@ import { GuardianMetricsModule } from './guardian-metrics'; StakingModuleGuardModule, GuardianMessageModule, GuardianMetricsModule, + KeysApiModule, ], providers: [GuardianService], exports: [GuardianService], diff --git a/src/guardian/guardian.service.ts b/src/guardian/guardian.service.ts index 2b0165a0..74eba84c 100644 --- a/src/guardian/guardian.service.ts +++ b/src/guardian/guardian.service.ts @@ -4,6 +4,7 @@ import { LoggerService, OnModuleInit, } from '@nestjs/common'; +import { compare } from 'compare-versions'; import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; import { SchedulerRegistry } from '@nestjs/schedule'; import { CronJob } from 'cron'; @@ -22,6 +23,9 @@ import { StakingModuleGuardService } from './staking-module-guard'; import { GuardianMessageService } from './guardian-message'; import { GuardianMetricsService } from './guardian-metrics'; import { StakingModuleData } from './interfaces'; +import { ProviderService } from 'provider'; +import { KeysApiService } from 'keys-api/keys-api.service'; +import { MIN_KAPI_VERSION } from './guardian.constants'; @Injectable() export class GuardianService implements OnModuleInit { @@ -42,6 +46,9 @@ export class GuardianService implements OnModuleInit { private stakingModuleGuardService: StakingModuleGuardService, private guardianMessageService: GuardianMessageService, private guardianMetricsService: GuardianMetricsService, + + private providerService: ProviderService, + private keysApiService: KeysApiService, ) {} public async onModuleInit(): Promise { @@ -57,6 +64,29 @@ export class GuardianService implements OnModuleInit { this.securityService.initialize({ blockHash }), ]); + const chainId = await this.providerService.getChainId(); + const keysApiStatus = await this.keysApiService.getKeysApiStatus(); + + if (chainId !== keysApiStatus.chainId) { + this.logger.warn('Wrong KAPI chainId', { + chainId, + keysApiChainId: keysApiStatus.chainId, + }); + throw new Error( + 'The ChainId in KeysAPI must match the ChainId in EL Node', + ); + } + + if (!compare(keysApiStatus.appVersion, MIN_KAPI_VERSION, '>=')) { + this.logger.warn('Wrong KAPI version', { + minKAPIVersion: MIN_KAPI_VERSION, + keysApiVersion: keysApiStatus.appVersion, + }); + throw new Error( + `The KAPI version must be greater than or equal to ${MIN_KAPI_VERSION}`, + ); + } + // The event cache is stored with an N block lag to avoid caching data from uncle blocks // so we don't worry about blockHash here await this.depositService.updateEventsCache(); diff --git a/src/keys-api/interfaces/Status.ts b/src/keys-api/interfaces/Status.ts new file mode 100644 index 00000000..9a48a010 --- /dev/null +++ b/src/keys-api/interfaces/Status.ts @@ -0,0 +1,6 @@ +export type Status = { + /** @description App version */ + appVersion: string; + /** @description Chain id */ + chainId: number; +}; diff --git a/src/keys-api/interfaces/index.ts b/src/keys-api/interfaces/index.ts index e5384860..ba0707c2 100644 --- a/src/keys-api/interfaces/index.ts +++ b/src/keys-api/interfaces/index.ts @@ -1,2 +1,3 @@ export type { SRModule } from './SRModule'; export type { KeyListResponse } from './KeyListResponse'; +export type { Status } from './Status'; diff --git a/src/keys-api/keys-api.service.ts b/src/keys-api/keys-api.service.ts index ae575df5..f69d67db 100644 --- a/src/keys-api/keys-api.service.ts +++ b/src/keys-api/keys-api.service.ts @@ -2,7 +2,7 @@ import { Injectable, LoggerService, Inject } from '@nestjs/common'; import { FetchService, RequestInit } from '@lido-nestjs/fetch'; import { AbortController } from 'node-abort-controller'; import { FETCH_REQUEST_TIMEOUT } from './keys-api.constants'; -import { KeyListResponse } from './interfaces'; +import { KeyListResponse, Status } from './interfaces'; import { WINSTON_MODULE_NEST_PROVIDER } from 'nest-winston'; import { Configuration } from 'common/config'; import { GroupedByModuleOperatorListResponse } from './interfaces/GroupedByModuleOperatorListResponse'; @@ -68,4 +68,14 @@ export class KeysApiService { ); return result; } + + /** + * + * @param The /v1/status API endpoint returns chainId, appVersion, El and Cl meta + * @returns + */ + public async getKeysApiStatus(): Promise { + const result = await this.fetch(`/v1/status`); + return result; + } } diff --git a/yarn.lock b/yarn.lock index e80121ca..09c2387a 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2909,6 +2909,11 @@ commander@^2.20.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== +compare-versions@^6.1.0: + version "6.1.0" + resolved "https://registry.yarnpkg.com/compare-versions/-/compare-versions-6.1.0.tgz#3f2131e3ae93577df111dba133e6db876ffe127a" + integrity sha512-LNZQXhqUvqUTotpZ00qLSaify3b4VFD588aRr8MKFw4CMUr98ytzCW5wDH5qx/DEY5kCDXcbcRuCqL0szEf2tg== + component-emitter@^1.3.0: version "1.3.0" resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0"