Skip to content

Commit

Permalink
Merge pull request #264 from lidofinance/develop
Browse files Browse the repository at this point in the history
Merge develop to main
  • Loading branch information
Tarens2 authored Jan 13, 2025
2 parents 01257a7 + e2440a6 commit 88f4ada
Show file tree
Hide file tree
Showing 2 changed files with 87 additions and 28 deletions.
106 changes: 78 additions & 28 deletions src/jobs/validators/validators.service.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { CronJob } from 'cron';
import { CronJob, CronTime } from 'cron';
import { Inject } from '@nestjs/common';
import { LOGGER_PROVIDER, LoggerService } from 'common/logger';
import { JobService } from 'common/job';
Expand Down Expand Up @@ -43,14 +43,21 @@ export class ValidatorsService {
*/
public async initialize(): Promise<void> {
await this.validatorsCacheService.initializeFromCache();
await this.updateValidators();

const envCronTime = this.configService.get('JOB_INTERVAL_VALIDATORS');
const chainId = this.configService.get('CHAIN_ID');
const cronByChainId = ORACLE_REPORTS_CRON_BY_CHAIN_ID[chainId] ?? CronExpression.EVERY_3_HOURS;
const cronTime = envCronTime ? envCronTime : cronByChainId;
const job = new CronJob(cronTime, () => this.updateValidators());
job.start();

await this.updateValidators();
const mainJob = new CronJob(cronTime, () => this.updateValidators());
mainJob.start();

await this.updateLidoWithdrawableValidators();
const lidoWithdrawableJob = new CronJob(CronExpression.EVERY_5_MINUTES, () =>
this.updateLidoWithdrawableValidators(),
);
lidoWithdrawableJob.start();

this.logger.log('Service initialized', { service: ValidatorsService.SERVICE_LOG_NAME, cronTime });
}
Expand Down Expand Up @@ -88,40 +95,21 @@ export class ValidatorsService {
this.validatorsStorageService.setActiveValidatorsCount(activeValidatorCount);
this.validatorsStorageService.setTotalValidatorsCount(data.length);
this.validatorsStorageService.setMaxExitEpoch(latestEpoch);

const frameBalances = await this.getLidoValidatorsWithdrawableBalances(data);
this.validatorsStorageService.setFrameBalances(frameBalances);
await this.findAndSetLidoValidatorsWithdrawableBalances(data);
await this.validatorsCacheService.saveDataToCache();

const currentFrame = this.genesisTimeService.getFrameOfEpoch(this.genesisTimeService.getCurrentEpoch());
this.logger.log('End update validators', {
service: ValidatorsService.SERVICE_LOG_NAME,
activeValidatorCount,
latestEpoch,
frameBalances: stringifyFrameBalances(frameBalances),
currentFrame,
});

Object.keys(frameBalances).forEach((frame) => {
this.prometheusService.validatorsState
.labels({
frame,
balance: frameBalances[frame],
})
.inc();
});

this.logAnalyticsAboutWithdrawableBalances(activeValidatorCount, latestEpoch);
this.validatorsStorageService.setLastUpdate(Math.floor(Date.now() / 1000));
},
);
}

protected async getLidoValidatorsWithdrawableBalances(validators: Validator[]) {
protected async findAndSetLidoValidatorsWithdrawableBalances(validators: Validator[]) {
const keysData = await this.lidoKeys.fetchLidoKeysData();
const lidoValidators = await this.lidoKeys.getLidoValidatorsByKeys(keysData.data, validators);
const lastWithdrawalValidatorIndex = await this.getLastWithdrawalValidatorIndex();
const frameBalances = {};

const withdrawableLidoValidatorIds: string[] = [];
for (const item of lidoValidators) {
if (item.validator.withdrawable_epoch !== FAR_FUTURE_EPOCH.toString() && BigNumber.from(item.balance).gt(0)) {
const withdrawalTimestamp = getValidatorWithdrawalTimestamp(
Expand All @@ -134,16 +122,78 @@ export class ValidatorsService {
const prevBalance = frameBalances[frame];
const balance = parseGweiToWei(item.balance);
frameBalances[frame] = prevBalance ? prevBalance.add(balance) : BigNumber.from(balance);
withdrawableLidoValidatorIds.push(item.index);
}

await unblock();
}

return frameBalances;
this.validatorsStorageService.setFrameBalances(frameBalances);
this.validatorsStorageService.setWithdrawableLidoValidatorIds(withdrawableLidoValidatorIds);
}

// updates withdrawable lido validators based on previously identified IDs
@OneAtTime()
protected async updateLidoWithdrawableValidators() {
await this.jobService.wrapJob(
{ name: 'update lido withdrawable validators', service: ValidatorsService.SERVICE_LOG_NAME },
async () => {
this.logger.log('Start update lido withdrawable validators', { service: ValidatorsService.SERVICE_LOG_NAME });

const validatorIds = this.validatorsStorageService.getWithdrawableLidoValidatorIds();
const lastWithdrawalValidatorIndex = await this.getLastWithdrawalValidatorIndex();
const frameBalances = {};

for (const validatorId of validatorIds) {
const stateValidator = await this.consensusProviderService.getStateValidator({
stateId: 'head',
validatorId,
});

const withdrawalTimestamp = getValidatorWithdrawalTimestamp(
BigNumber.from(stateValidator.data.index),
lastWithdrawalValidatorIndex,
this.validatorsStorageService.getActiveValidatorsCount(),
this.validatorsStorageService.getTotalValidatorsCount(),
);
const frame = this.genesisTimeService.getFrameByTimestamp(withdrawalTimestamp) + 1;
const prevBalance = frameBalances[frame];
const balance = parseGweiToWei(stateValidator.data.balance);
frameBalances[frame] = prevBalance ? prevBalance.add(balance) : BigNumber.from(balance);
}

this.validatorsStorageService.setFrameBalances(frameBalances);
this.logger.log('End update lido withdrawable validators', {
service: ValidatorsService.SERVICE_LOG_NAME,
frameBalances: stringifyFrameBalances(frameBalances),
});
},
);
}

protected async getLastWithdrawalValidatorIndex() {
const withdrawals = await this.executionProviderService.getLatestWithdrawals();
return BigNumber.from(withdrawals[withdrawals.length - 1].validatorIndex);
}

protected logAnalyticsAboutWithdrawableBalances(activeValidatorCount: number, latestEpoch: string) {
const currentFrame = this.genesisTimeService.getFrameOfEpoch(this.genesisTimeService.getCurrentEpoch());
const frameBalances = this.validatorsStorageService.getFrameBalances();
this.logger.log('End update validators', {
service: ValidatorsService.SERVICE_LOG_NAME,
activeValidatorCount,
latestEpoch,
frameBalances: stringifyFrameBalances(frameBalances),
currentFrame,
});

Object.keys(frameBalances).forEach((frame) => {
this.prometheusService.validatorsState
.labels({
frame,
balance: frameBalances[frame].toString(),
})
.inc();
});
}
}
9 changes: 9 additions & 0 deletions src/storage/validators/validators.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ export class ValidatorsStorageService {
protected totalValidatorsCount: number;
protected lastUpdate: number;
protected frameBalances: Record<string, BigNumber>;
protected withdrawableLidoValidatorIds: string[];

/**
* Get max exit epoch for all validators
Expand Down Expand Up @@ -80,4 +81,12 @@ export class ValidatorsStorageService {
public getTotalValidatorsCount() {
return this.totalValidatorsCount;
}

public setWithdrawableLidoValidatorIds(withdrawableLidoValidators: string[]) {
this.withdrawableLidoValidatorIds = withdrawableLidoValidators;
}

public getWithdrawableLidoValidatorIds() {
return this.withdrawableLidoValidatorIds;
}
}

0 comments on commit 88f4ada

Please sign in to comment.