Skip to content

Commit 88f4ada

Browse files
authored
Merge pull request #264 from lidofinance/develop
Merge develop to main
2 parents 01257a7 + e2440a6 commit 88f4ada

File tree

2 files changed

+87
-28
lines changed

2 files changed

+87
-28
lines changed

src/jobs/validators/validators.service.ts

Lines changed: 78 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { CronJob } from 'cron';
1+
import { CronJob, CronTime } from 'cron';
22
import { Inject } from '@nestjs/common';
33
import { LOGGER_PROVIDER, LoggerService } from 'common/logger';
44
import { JobService } from 'common/job';
@@ -43,14 +43,21 @@ export class ValidatorsService {
4343
*/
4444
public async initialize(): Promise<void> {
4545
await this.validatorsCacheService.initializeFromCache();
46-
await this.updateValidators();
4746

4847
const envCronTime = this.configService.get('JOB_INTERVAL_VALIDATORS');
4948
const chainId = this.configService.get('CHAIN_ID');
5049
const cronByChainId = ORACLE_REPORTS_CRON_BY_CHAIN_ID[chainId] ?? CronExpression.EVERY_3_HOURS;
5150
const cronTime = envCronTime ? envCronTime : cronByChainId;
52-
const job = new CronJob(cronTime, () => this.updateValidators());
53-
job.start();
51+
52+
await this.updateValidators();
53+
const mainJob = new CronJob(cronTime, () => this.updateValidators());
54+
mainJob.start();
55+
56+
await this.updateLidoWithdrawableValidators();
57+
const lidoWithdrawableJob = new CronJob(CronExpression.EVERY_5_MINUTES, () =>
58+
this.updateLidoWithdrawableValidators(),
59+
);
60+
lidoWithdrawableJob.start();
5461

5562
this.logger.log('Service initialized', { service: ValidatorsService.SERVICE_LOG_NAME, cronTime });
5663
}
@@ -88,40 +95,21 @@ export class ValidatorsService {
8895
this.validatorsStorageService.setActiveValidatorsCount(activeValidatorCount);
8996
this.validatorsStorageService.setTotalValidatorsCount(data.length);
9097
this.validatorsStorageService.setMaxExitEpoch(latestEpoch);
91-
92-
const frameBalances = await this.getLidoValidatorsWithdrawableBalances(data);
93-
this.validatorsStorageService.setFrameBalances(frameBalances);
98+
await this.findAndSetLidoValidatorsWithdrawableBalances(data);
9499
await this.validatorsCacheService.saveDataToCache();
95-
96-
const currentFrame = this.genesisTimeService.getFrameOfEpoch(this.genesisTimeService.getCurrentEpoch());
97-
this.logger.log('End update validators', {
98-
service: ValidatorsService.SERVICE_LOG_NAME,
99-
activeValidatorCount,
100-
latestEpoch,
101-
frameBalances: stringifyFrameBalances(frameBalances),
102-
currentFrame,
103-
});
104-
105-
Object.keys(frameBalances).forEach((frame) => {
106-
this.prometheusService.validatorsState
107-
.labels({
108-
frame,
109-
balance: frameBalances[frame],
110-
})
111-
.inc();
112-
});
113-
100+
this.logAnalyticsAboutWithdrawableBalances(activeValidatorCount, latestEpoch);
114101
this.validatorsStorageService.setLastUpdate(Math.floor(Date.now() / 1000));
115102
},
116103
);
117104
}
118105

119-
protected async getLidoValidatorsWithdrawableBalances(validators: Validator[]) {
106+
protected async findAndSetLidoValidatorsWithdrawableBalances(validators: Validator[]) {
120107
const keysData = await this.lidoKeys.fetchLidoKeysData();
121108
const lidoValidators = await this.lidoKeys.getLidoValidatorsByKeys(keysData.data, validators);
122109
const lastWithdrawalValidatorIndex = await this.getLastWithdrawalValidatorIndex();
123110
const frameBalances = {};
124111

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

139128
await unblock();
140129
}
141130

142-
return frameBalances;
131+
this.validatorsStorageService.setFrameBalances(frameBalances);
132+
this.validatorsStorageService.setWithdrawableLidoValidatorIds(withdrawableLidoValidatorIds);
133+
}
134+
135+
// updates withdrawable lido validators based on previously identified IDs
136+
@OneAtTime()
137+
protected async updateLidoWithdrawableValidators() {
138+
await this.jobService.wrapJob(
139+
{ name: 'update lido withdrawable validators', service: ValidatorsService.SERVICE_LOG_NAME },
140+
async () => {
141+
this.logger.log('Start update lido withdrawable validators', { service: ValidatorsService.SERVICE_LOG_NAME });
142+
143+
const validatorIds = this.validatorsStorageService.getWithdrawableLidoValidatorIds();
144+
const lastWithdrawalValidatorIndex = await this.getLastWithdrawalValidatorIndex();
145+
const frameBalances = {};
146+
147+
for (const validatorId of validatorIds) {
148+
const stateValidator = await this.consensusProviderService.getStateValidator({
149+
stateId: 'head',
150+
validatorId,
151+
});
152+
153+
const withdrawalTimestamp = getValidatorWithdrawalTimestamp(
154+
BigNumber.from(stateValidator.data.index),
155+
lastWithdrawalValidatorIndex,
156+
this.validatorsStorageService.getActiveValidatorsCount(),
157+
this.validatorsStorageService.getTotalValidatorsCount(),
158+
);
159+
const frame = this.genesisTimeService.getFrameByTimestamp(withdrawalTimestamp) + 1;
160+
const prevBalance = frameBalances[frame];
161+
const balance = parseGweiToWei(stateValidator.data.balance);
162+
frameBalances[frame] = prevBalance ? prevBalance.add(balance) : BigNumber.from(balance);
163+
}
164+
165+
this.validatorsStorageService.setFrameBalances(frameBalances);
166+
this.logger.log('End update lido withdrawable validators', {
167+
service: ValidatorsService.SERVICE_LOG_NAME,
168+
frameBalances: stringifyFrameBalances(frameBalances),
169+
});
170+
},
171+
);
143172
}
144173

145174
protected async getLastWithdrawalValidatorIndex() {
146175
const withdrawals = await this.executionProviderService.getLatestWithdrawals();
147176
return BigNumber.from(withdrawals[withdrawals.length - 1].validatorIndex);
148177
}
178+
179+
protected logAnalyticsAboutWithdrawableBalances(activeValidatorCount: number, latestEpoch: string) {
180+
const currentFrame = this.genesisTimeService.getFrameOfEpoch(this.genesisTimeService.getCurrentEpoch());
181+
const frameBalances = this.validatorsStorageService.getFrameBalances();
182+
this.logger.log('End update validators', {
183+
service: ValidatorsService.SERVICE_LOG_NAME,
184+
activeValidatorCount,
185+
latestEpoch,
186+
frameBalances: stringifyFrameBalances(frameBalances),
187+
currentFrame,
188+
});
189+
190+
Object.keys(frameBalances).forEach((frame) => {
191+
this.prometheusService.validatorsState
192+
.labels({
193+
frame,
194+
balance: frameBalances[frame].toString(),
195+
})
196+
.inc();
197+
});
198+
}
149199
}

src/storage/validators/validators.service.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ export class ValidatorsStorageService {
88
protected totalValidatorsCount: number;
99
protected lastUpdate: number;
1010
protected frameBalances: Record<string, BigNumber>;
11+
protected withdrawableLidoValidatorIds: string[];
1112

1213
/**
1314
* Get max exit epoch for all validators
@@ -80,4 +81,12 @@ export class ValidatorsStorageService {
8081
public getTotalValidatorsCount() {
8182
return this.totalValidatorsCount;
8283
}
84+
85+
public setWithdrawableLidoValidatorIds(withdrawableLidoValidators: string[]) {
86+
this.withdrawableLidoValidatorIds = withdrawableLidoValidators;
87+
}
88+
89+
public getWithdrawableLidoValidatorIds() {
90+
return this.withdrawableLidoValidatorIds;
91+
}
8392
}

0 commit comments

Comments
 (0)