Skip to content

Commit

Permalink
fix: added more tests, fixed e2e
Browse files Browse the repository at this point in the history
  • Loading branch information
Amuhar committed Dec 6, 2023
1 parent c8b3d25 commit c14bc1e
Show file tree
Hide file tree
Showing 3 changed files with 272 additions and 7 deletions.
1 change: 0 additions & 1 deletion src/guardian/guardian.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,6 @@ export class GuardianService implements OnModuleInit {
this.logger.log('New staking router state cycle start');

try {
// TODO: rename
const { blockHash, blockNumber, vettedKeys, stakingModulesData } =
await this.stakingRouterService.getVettedAndUnusedKeys();

Expand Down
25 changes: 20 additions & 5 deletions src/guardian/staking-module-guard/staking-module-guard.service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,8 +152,10 @@ export class StakingModuleGuardService {
if (isFilteredIntersectionsFound) {
await this.handleKeysIntersections(stakingModuleData, blockData);
} else {
// it could throw error if kapi returned old data
const usedKeys = await this.getIntersectionBetweenUsedAndUnusedKeys(
keysIntersections,
blockData,
);

// if found used keys, Lido already made deposit on this keys
Expand Down Expand Up @@ -225,6 +227,7 @@ export class StakingModuleGuardService {

public async getIntersectionBetweenUsedAndUnusedKeys(
intersectionsWithLidoWC: VerifiedDepositEvent[],
blockData: BlockData,
) {
const depositedPubkeys = intersectionsWithLidoWC.map(
(deposit) => deposit.pubkey,
Expand All @@ -235,12 +238,24 @@ export class StakingModuleGuardService {
'Found intersections with lido credentials, need to check duplicated keys',
);

const keys = await this.stakingRouterService.getKeysWithDuplicates(
depositedPubkeys,
);
const { data, meta } =
await this.stakingRouterService.getKeysWithDuplicates(depositedPubkeys);

if (meta.elBlockSnapshot.blockNumber < blockData.blockNumber) {
// blockData.blockNumber we also read from kapi, so smth is wrong in kapi
this.logger.error(
'BlockNumber of the response older than previous response from KAPI',
{
previous: blockData.blockNumber,
current: meta.elBlockSnapshot.blockNumber,
},
);
throw Error(
'BlockNumber of the response older than previous response from KAPI',
);
}

// TODO: add block number check. keys blockNumber should be newer than we have in blockData because of used keys is not deleted
const usedKeys = keys.data.filter((key) => key.used);
const usedKeys = data.filter((key) => key.used);
return usedKeys;
}

Expand Down
253 changes: 252 additions & 1 deletion src/guardian/staking-module-guard/staking-module-guard.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { RepositoryModule } from 'contracts/repository';
import { LidoModule, LidoService } from 'contracts/lido';
import { MessageType } from 'messages';
import { StakingModuleGuardModule } from './staking-module-guard.module';
import { StakingRouterModule } from 'staking-router';
import { StakingRouterModule, StakingRouterService } from 'staking-router';
import { GuardianMetricsModule } from '../guardian-metrics';
import {
GuardianMessageModule,
Expand Down Expand Up @@ -52,6 +52,7 @@ describe('StakingModuleGuardService', () => {
let securityService: SecurityService;
let stakingModuleGuardService: StakingModuleGuardService;
let guardianMessageService: GuardianMessageService;
let stakingRouterService: StakingRouterService;

beforeEach(async () => {
const moduleRef = await Test.createTestingModule({
Expand All @@ -75,6 +76,7 @@ describe('StakingModuleGuardService', () => {
loggerService = moduleRef.get(WINSTON_MODULE_NEST_PROVIDER);
stakingModuleGuardService = moduleRef.get(StakingModuleGuardService);
guardianMessageService = moduleRef.get(GuardianMessageService);
stakingRouterService = moduleRef.get(StakingRouterService);

jest.spyOn(loggerService, 'log').mockImplementation(() => undefined);
jest.spyOn(loggerService, 'warn').mockImplementation(() => undefined);
Expand Down Expand Up @@ -661,4 +663,253 @@ describe('StakingModuleGuardService', () => {
expect(result.length).toEqual(0);
});
});

describe('getIntersectionBetweenUsedAndUnusedKeys', () => {
// function that return list from kapi that match keys in parameter
it('intersection is empty', async () => {
const intersectionsWithLidoWC = [];
// function that return list from kapi that match keys in parameter
const mockSendMessageFromGuardian = jest.spyOn(
stakingRouterService,
'getKeysWithDuplicates',
);

const result =
await stakingModuleGuardService.getIntersectionBetweenUsedAndUnusedKeys(
intersectionsWithLidoWC,
{
blockNumber: 1,
blockHash: '0x1234',
} as any,
);

expect(result).toEqual([]);
expect(mockSendMessageFromGuardian).toBeCalledTimes(0);
});

it('should return keys list if deposits with lido wx were made by lido', async () => {
const pubkeyWithUsedKey1 = '0x1234';
const pubkeyWithoutUsedKey = '0x56789';
const pubkeyWithUsedKey2 = '0x3478';
const lidoWC = '0x12';
const intersectionsWithLidoWC = [
{ pubkey: pubkeyWithUsedKey1, wc: lidoWC } as any,
{ pubkey: pubkeyWithoutUsedKey, wc: lidoWC } as any,
{ pubkey: pubkeyWithUsedKey2, wc: lidoWC } as any,
];
// function that return list from kapi that match keys in parameter
const mockSendMessageFromGuardian = jest
.spyOn(stakingRouterService, 'getKeysWithDuplicates')
.mockImplementation(async () => ({
data: [
{
key: pubkeyWithUsedKey1,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkeyWithUsedKey1,
depositSignature: 'signature',
operatorIndex: 0,
used: true,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkeyWithUsedKey2,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkeyWithUsedKey2,
depositSignature: 'signature',
operatorIndex: 0,
used: true,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkeyWithoutUsedKey,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
],
meta: {
elBlockSnapshot: {
blockNumber: 0,
blockHash: 'hash',
timestamp: 12345,
},
},
}));

const result =
await stakingModuleGuardService.getIntersectionBetweenUsedAndUnusedKeys(
intersectionsWithLidoWC,
{
blockNumber: 0,
blockHash: '0x1234',
} as any,
);

expect(result.length).toEqual(2);
expect(result).toEqual(
expect.arrayContaining([
{
key: pubkeyWithUsedKey1,
depositSignature: 'signature',
operatorIndex: 0,
used: true,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkeyWithUsedKey2,
depositSignature: 'signature',
operatorIndex: 0,
used: true,
index: 0,
moduleAddress: '0x0000',
},
]),
);
expect(mockSendMessageFromGuardian).toBeCalledTimes(1);
});

it('should return empty list if deposits with lido wc were made by someone else ', async () => {
const pubkey1 = '0x1234';
const pubkey2 = '0x56789';
const pubkey3 = '0x3478';
const lidoWC = '0x12';
const intersectionsWithLidoWC = [
{ pubkey: pubkey1, wc: lidoWC } as any,
{ pubkey: pubkey2, wc: lidoWC } as any,
{ pubkey: pubkey3, wc: lidoWC } as any,
];
// function that return list from kapi that match keys in parameter
const mockSendMessageFromGuardian = jest
.spyOn(stakingRouterService, 'getKeysWithDuplicates')
.mockImplementation(async () => ({
data: [
{
key: pubkey1,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkey2,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkey3,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
],
meta: {
elBlockSnapshot: {
blockNumber: 0,
blockHash: 'hash',
timestamp: 12345,
},
},
}));

const result =
await stakingModuleGuardService.getIntersectionBetweenUsedAndUnusedKeys(
intersectionsWithLidoWC,
{
blockNumber: 0,
blockHash: '0x1234',
} as any,
);

expect(result).toEqual([]);
expect(mockSendMessageFromGuardian).toBeCalledTimes(1);
});

it('should skip if blockNumber that kapi returned is smaller than in blockData ', async () => {
const pubkey1 = '0x1234';
const pubkey2 = '0x56789';
const pubkey3 = '0x3478';
const lidoWC = '0x12';
const intersectionsWithLidoWC = [
{ pubkey: pubkey1, wc: lidoWC } as any,
{ pubkey: pubkey2, wc: lidoWC } as any,
{ pubkey: pubkey3, wc: lidoWC } as any,
];
// function that return list from kapi that match keys in parameter
const mockSendMessageFromGuardian = jest
.spyOn(stakingRouterService, 'getKeysWithDuplicates')
.mockImplementation(async () => ({
data: [
{
key: pubkey1,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkey2,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
{
key: pubkey3,
depositSignature: 'signature',
operatorIndex: 0,
used: false,
index: 0,
moduleAddress: '0x0000',
},
],
meta: {
elBlockSnapshot: {
blockNumber: 0,
blockHash: 'hash',
timestamp: 12345,
},
},
}));

expect(
async () =>
await stakingModuleGuardService.getIntersectionBetweenUsedAndUnusedKeys(
intersectionsWithLidoWC,
{
blockNumber: 1,
blockHash: '0x1234',
} as any,
),
).rejects.toThrowError(
'BlockNumber of the response older than previous response from KAPI',
);

expect(mockSendMessageFromGuardian).toBeCalledTimes(1);
});
});
});

0 comments on commit c14bc1e

Please sign in to comment.