Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixes CR 2024-05-10 #78

Merged
merged 5 commits into from
May 10, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion packages/apps/human-app/server/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,5 @@ E2E_TESTING_ESCROW_CHAIN_ID= # number
RPC_URL= # string
CORS_ENABLED= # boolean, example: true
CORS_ALLOWED_ORIGIN= # string example: http://localhost:5173
CORS_ALLOWED_HEADERS= # string, example: 'Content-Type,Accept'
CORS_ALLOWED_HEADERS= # string, example: 'Content-Type,Accept'
CHAIN_IDS_ENABLED= # number array, example: 80002,80001
5 changes: 4 additions & 1 deletion packages/apps/human-app/server/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -32,4 +32,7 @@ lerna-debug.log*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
!.vscode/extensions.json

# Redis Data
./redis_data
2 changes: 1 addition & 1 deletion packages/apps/human-app/server/docker-compose.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,4 @@ services:
ports:
- '${REDIS_PORT}:6379'
volumes:
- redis_data:/data
- ./redis_data:/data
14 changes: 14 additions & 0 deletions packages/apps/human-app/server/src/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import { ExchangeOracleModule } from './integrations/exchange-oracle/exchange-or
import { KvStoreModule } from './integrations/kv-store/kv-store.module';
import { EscrowUtilsModule } from './integrations/escrow/escrow-utils.module';
import Joi from 'joi';
import { ChainId } from '@human-protocol/sdk';

@Module({
imports: [
Expand All @@ -38,6 +39,19 @@ import Joi from 'joi';
REDIS_PORT: Joi.number().required(),
REDIS_HOST: Joi.string().required(),
RPC_URL: Joi.string().required(),
CHAIN_IDS_ENABLED: Joi.string()
.custom((value) => {
const chainIds = value.split(',');
for (const id of chainIds) {
if (!Object.values(ChainId).includes(Number(id.trim()))) {
throw new Error(
`Invalid chain ID: Chain ID ${id} is not included in the HUMAN SDK.`,
);
}
}
return value;
})
.required(),
}),
}),
AutomapperModule.forRoot({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -64,4 +64,8 @@ export class EnvironmentConfigService {
DEFAULT_CORS_ALLOWED_HEADERS,
);
}
get chainIdsEnabled(): string[] {
const chainIds = this.configService.getOrThrow<string>('CHAIN_IDS_ENABLED');
return chainIds.split(',').map((id) => id.trim());
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ import { KVStoreClient, KVStoreKeys } from '@human-protocol/sdk';

@Injectable()
export class KvStoreGateway {
private URL_KEY = KVStoreKeys.url;
private kvStoreClient: KVStoreClient;
constructor(private environmentConfig: EnvironmentConfigService) {}
async onModuleInit(): Promise<void> {
Expand All @@ -14,6 +13,6 @@ export class KvStoreGateway {
);
}
async getExchangeOracleUrlByAddress(address: string): Promise<string> {
return this.kvStoreClient.get(address, this.URL_KEY);
return this.kvStoreClient.get(address, KVStoreKeys.url);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ export class JobsDiscoveryService {
command: JobsDiscoveryParamsCommand,
): Promise<JobsDiscoveryResponse> {
const exchangeOracleUrl =
await this.kvStoreGateway.getExchangeOracleUrlByAddress(command.address);
await this.kvStoreGateway.getExchangeOracleUrlByAddress(command.oracleAddress);
const details = this.mapper.map(
command,
JobsDiscoveryParamsCommand,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ export class JobsDiscoveryParamsDto extends PageableDto {
@AutoMap()
@IsString()
@ApiProperty()
address?: string;
oracle_address?: string;
@AutoMap()
@IsOptional()
@IsString()
Expand Down Expand Up @@ -79,7 +79,7 @@ export class JobsDiscoveryParamsData extends PageableData {
}
export class JobsDiscoveryParamsCommand {
@AutoMap()
address: string;
oracleAddress: string;
@AutoMap()
token: string;
@AutoMap()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
} from '../model/jobs-discovery.model';
import {
JobDiscoveryFieldName,
JobDiscoverySortField, JobStatus,
JobDiscoverySortField,
JobStatus,
SortOrder,
} from '../../../common/enums/global-common';
const EXCHANGE_ORACLE_URL = 'https://www.test_url.org';
Expand All @@ -34,7 +35,7 @@ const STATUS = JobStatus.ACTIVE;
export const jobsDiscoveryOracleUrlFixture = EXCHANGE_ORACLE_URL;
export const jobDiscoveryToken = TOKEN;
export const dtoFixture: JobsDiscoveryParamsDto = {
address: EXCHANGE_ORACLE_ADDRESS,
oracle_address: EXCHANGE_ORACLE_ADDRESS,
escrow_address: ESCROW_ADDRESS,
chain_id: CHAIN_ID,
page_size: PAGE_SIZE,
Expand Down Expand Up @@ -71,7 +72,7 @@ const paramsDataFixture: JobsDiscoveryParamsData = {
export const paramsDataFixtureAsString = `?escrow_address=${paramsDataFixture.escrow_address}&chain_id=${paramsDataFixture.chain_id}&page_size=${paramsDataFixture.page_size}&page=${paramsDataFixture.page}&sort=${paramsDataFixture.sort}&sort_field=${paramsDataFixture.sort_field}&job_type=${paramsDataFixture.job_type}&fields=${paramsDataFixture.fields.join(',')}`;
export const jobsDiscoveryParamsCommandFixture: JobsDiscoveryParamsCommand = {
data: dataFixture,
address: EXCHANGE_ORACLE_ADDRESS,
oracleAddress: EXCHANGE_ORACLE_ADDRESS,
token: TOKEN,
};
export const jobsDiscoveryParamsDetailsFixture: JobsDiscoveryParamsDetails = {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ describe('JobsDiscoveryService', () => {
const result = await service.processJobsDiscovery(command);
expect(
kvStoreGatewayMock.getExchangeOracleUrlByAddress,
).toHaveBeenCalledWith(command.address);
).toHaveBeenCalledWith(command.oracleAddress);
expect(exchangeOracleGatewayMock.fetchJobs).toHaveBeenCalledWith(details);
expect(result).toEqual(responseFixture);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,4 @@
import { IOperator } from '@human-protocol/sdk';
import { AutoMap } from '@automapper/classes';
import { ApiProperty } from '@nestjs/swagger';
import { IsNumber } from 'class-validator';
import { Type } from 'class-transformer';

export class OracleDiscoveryDto {
@AutoMap()
@IsNumber()
@Type(() => Number)
@ApiProperty({ example: 80002 })
chainId: number;
}
export class OracleDiscoveryCommand {
@AutoMap()
chainId: number;
}

export class OracleDiscoveryResponse implements IOperator {
address: string;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,38 +1,16 @@
import {
Controller,
Get,
Query,
UsePipes,
ValidationPipe,
} from '@nestjs/common';
import { Mapper } from '@automapper/core';
import { InjectMapper } from '@automapper/nestjs';
import { Controller, Get, UsePipes, ValidationPipe } from '@nestjs/common';
import { ApiOperation, ApiTags } from '@nestjs/swagger';
import { OracleDiscoveryService } from './oracle-discovery.serivce';
import {
OracleDiscoveryCommand,
OracleDiscoveryResponse,
OracleDiscoveryDto,
} from './model/oracle-discovery.model';
import { OracleDiscoveryResponse } from './model/oracle-discovery.model';

@Controller()
export class OracleDiscoveryController {
constructor(
private readonly service: OracleDiscoveryService,
@InjectMapper() private readonly mapper: Mapper,
) {}
constructor(private readonly service: OracleDiscoveryService) {}
@ApiTags('Oracle-Discovery')
@Get('/oracles')
@ApiOperation({ summary: 'Oracles discovery' })
@UsePipes(new ValidationPipe())
public getOracles(
@Query() oracleDiscoveryDto: OracleDiscoveryDto,
): Promise<OracleDiscoveryResponse[]> {
const oracleDiscoveryCommand = this.mapper.map(
oracleDiscoveryDto,
OracleDiscoveryDto,
OracleDiscoveryCommand,
);
return this.service.processOracleDiscovery(oracleDiscoveryCommand);
public getOracles(): Promise<OracleDiscoveryResponse[]> {
return this.service.processOracleDiscovery();
}
}

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,9 +1,8 @@
import { Module } from '@nestjs/common';
import { OracleDiscoveryService } from './oracle-discovery.serivce';
import { OracleDiscoveryProfile } from './oracle-discovery.mapper';

@Module({
providers: [OracleDiscoveryService, OracleDiscoveryProfile],
providers: [OracleDiscoveryService],
exports: [OracleDiscoveryService],
})
export class OracleDiscoveryModule {}
Original file line number Diff line number Diff line change
@@ -1,38 +1,47 @@
import { Inject, Injectable } from '@nestjs/common';
import {
OracleDiscoveryCommand,
OracleDiscoveryResponse,
} from './model/oracle-discovery.model';
import { Inject, Injectable, Logger } from '@nestjs/common';
import { OracleDiscoveryResponse } from './model/oracle-discovery.model';
import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Cache } from 'cache-manager';
import { OperatorUtils } from '@human-protocol/sdk';
import { EnvironmentConfigService } from '../../common/config/environment-config.service';

@Injectable()
export class OracleDiscoveryService {
logger = new Logger('OracleDiscoveryService');
EXCHANGE_ORACLE = 'Exchange Oracle';
constructor(
@Inject(CACHE_MANAGER) private cacheManager: Cache,
private configService: EnvironmentConfigService,
) {}

async processOracleDiscovery(
command: OracleDiscoveryCommand,
): Promise<OracleDiscoveryResponse[]> {
async processOracleDiscovery(): Promise<OracleDiscoveryResponse[]> {
const address = this.configService.reputationOracleAddress.toLowerCase();
let data: OracleDiscoveryResponse[] | undefined =
await this.cacheManager.get(command.chainId.toString());
if (!data) {
data = await OperatorUtils.getReputationNetworkOperators(
command.chainId,
address,
this.EXCHANGE_ORACLE,
);
await this.cacheManager.set(
command.chainId.toString(),
data,
this.configService.cacheTtlOracleDiscovery,
);
}
return data;
const chainIds = this.configService.chainIdsEnabled;

const allData = await Promise.all(
chainIds.map(async (chainId) => {
let data: OracleDiscoveryResponse[] | undefined =
await this.cacheManager.get(chainId);
if (!data) {
try {
data = await OperatorUtils.getReputationNetworkOperators(
Number(chainId),
address,
this.EXCHANGE_ORACLE,
);
await this.cacheManager.set(
chainId,
data,
this.configService.cacheTtlOracleDiscovery,
);
} catch (error) {
this.logger.error(`Error processing chainId ${chainId}:`, error);
}
}
return data;
}),
);

return allData.flat().filter(Boolean) as OracleDiscoveryResponse[];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -4,18 +4,11 @@ import { classes } from '@automapper/classes';
import { OracleDiscoveryController } from '../oracle-discovery.controller';
import { OracleDiscoveryService } from '../oracle-discovery.serivce';
import { oracleDiscoveryServiceMock } from './oracle-discovery.service.mock';
import { OracleDiscoveryProfile } from '../oracle-discovery.mapper';
import {
OracleDiscoveryCommand,
OracleDiscoveryResponse,
OracleDiscoveryDto,
} from '../model/oracle-discovery.model';
import { ChainId } from '@human-protocol/sdk';
import { OracleDiscoveryResponse } from '../model/oracle-discovery.model';
import { generateOracleDiscoveryResponseBody } from './oracle-discovery.fixture';

describe('OracleDiscoveryController', () => {
let controller: OracleDiscoveryController;
let service: OracleDiscoveryService;

beforeEach(async () => {
const module: TestingModule = await Test.createTestingModule({
Expand All @@ -25,7 +18,7 @@ describe('OracleDiscoveryController', () => {
strategyInitializer: classes(),
}),
],
providers: [OracleDiscoveryService, OracleDiscoveryProfile],
providers: [OracleDiscoveryService],
})
.overrideProvider(OracleDiscoveryService)
.useValue(oracleDiscoveryServiceMock)
Expand All @@ -34,26 +27,15 @@ describe('OracleDiscoveryController', () => {
controller = module.get<OracleDiscoveryController>(
OracleDiscoveryController,
);
service = module.get<OracleDiscoveryService>(OracleDiscoveryService);
});

it('should be defined', () => {
expect(controller).toBeDefined();
});

describe('oracle discovery', () => {
it('oracle discovery should be called with input in OracleDiscoveryDto format and return OracleDiscoveryData', async () => {
const dto: OracleDiscoveryDto = {
chainId: 80001,
};
const result: OracleDiscoveryResponse[] =
await controller.getOracles(dto);
const expectedCommand = {
chainId: ChainId.POLYGON_MUMBAI,
} as OracleDiscoveryCommand;
expect(service.processOracleDiscovery).toHaveBeenCalledWith(
expectedCommand,
);
it('oracle discovery should be return OracleDiscoveryData', async () => {
const result: OracleDiscoveryResponse[] = await controller.getOracles();
const expectedResponse = generateOracleDiscoveryResponseBody();
expect(result).toEqual(expectedResponse);
});
Expand Down
Loading
Loading