From 56d8add99b01496da5ebf3050812199ccfab7a1f Mon Sep 17 00:00:00 2001 From: Joel-David Wong Date: Mon, 4 Apr 2022 17:00:26 +0800 Subject: [PATCH 01/16] oracles status setup --- .../controllers/OraclesController.test.ts | 24 +++++++++++ .../src/controllers/OraclesController.ts | 42 +++++++++++++++++++ .../src/modules/ControllerModule.ts | 3 ++ .../whale/src/module.api/oracle.controller.ts | 4 +- 4 files changed, 71 insertions(+), 2 deletions(-) create mode 100644 apps/status-api/__tests__/controllers/OraclesController.test.ts create mode 100644 apps/status-api/src/controllers/OraclesController.ts diff --git a/apps/status-api/__tests__/controllers/OraclesController.test.ts b/apps/status-api/__tests__/controllers/OraclesController.test.ts new file mode 100644 index 0000000000..b70c4a5c84 --- /dev/null +++ b/apps/status-api/__tests__/controllers/OraclesController.test.ts @@ -0,0 +1,24 @@ +import { StatusApiTesting } from '../../testing/StatusApiTesting' + +const apiTesting = StatusApiTesting.create() + +beforeAll(async () => { + await apiTesting.start() +}) + +afterAll(async () => { + await apiTesting.stop() +}) + +describe('/oracles', () => { + it('/oracles?address=
- limited to 30', async () => { + const res = await apiTesting.app.inject({ + method: 'GET', + url: '/oracles?address=df1q02jh2rkymd6ncl75ql3f267u3guja9nzqj2qmn' + }) + expect(res.json()).toStrictEqual({ + status: 'operational' + }) + expect(res.statusCode).toStrictEqual(200) + }) +}) diff --git a/apps/status-api/src/controllers/OraclesController.ts b/apps/status-api/src/controllers/OraclesController.ts new file mode 100644 index 0000000000..99119cf2e4 --- /dev/null +++ b/apps/status-api/src/controllers/OraclesController.ts @@ -0,0 +1,42 @@ +import { Controller, Get, Query } from '@nestjs/common' +import { WhaleApiClient } from '@defichain/whale-api-client' +import { Oracle } from '@defichain/whale-api-client/dist/api/Oracles' +import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' + +@Controller('/status') +export class OraclesController { + constructor ( + private readonly client: WhaleApiClient, + protected readonly cache: SemaphoreCache + ) { + } + + @Get('oracles') + async getToken ( + @Query('address') oracleAddress: string + ): Promise<{ [key: string]: string }> { + const oracle: Oracle = await this.cachedGet('ORACLE', async () => { + return await this.client.oracles.getOracleByAddress(oracleAddress) + }, 1000) + + const nowEpoch = Date.now() + const latestPublishedTime = oracle.block.medianTime * 1000 + const timeDiff = nowEpoch - latestPublishedTime + + return { + status: timeDiff > (15 * 60 * 1000) ? 'operational' : 'outage' + } + } + + private async cachedGet (field: string, fetch: () => Promise, ttl: number): Promise { + const object = await this.cache.get(`OraclesController.${field}`, fetch, { ttl }) + return requireValue(object, field) + } +} + +function requireValue (value: T | undefined, name: string): T { + if (value === undefined) { + throw new Error(`failed to compute: ${name}`) + } + return value +} diff --git a/apps/status-api/src/modules/ControllerModule.ts b/apps/status-api/src/modules/ControllerModule.ts index 8f285a690d..fc8bc76568 100644 --- a/apps/status-api/src/modules/ControllerModule.ts +++ b/apps/status-api/src/modules/ControllerModule.ts @@ -3,6 +3,7 @@ import { ActuatorController } from '@defichain-apps/libs/actuator' import { BlockchainStatusController } from '../controllers/BlockchainStatusController' import { WhaleApiClient } from '@defichain/whale-api-client' import { ConfigService } from '@nestjs/config' +import { OracleController } from '../../../whale/src/module.api/oracle.controller' import { OverallStatusController } from '../controllers/OverallStatusController' /** @@ -13,8 +14,10 @@ import { OverallStatusController } from '../controllers/OverallStatusController' CacheModule.register() ], controllers: [ + ActuatorController, BlockchainStatusController, ActuatorController, + OracleController, OverallStatusController ], providers: [ diff --git a/apps/whale/src/module.api/oracle.controller.ts b/apps/whale/src/module.api/oracle.controller.ts index 18ad8f56be..98cb7f6dca 100644 --- a/apps/whale/src/module.api/oracle.controller.ts +++ b/apps/whale/src/module.api/oracle.controller.ts @@ -1,8 +1,8 @@ import { Controller, Get, NotFoundException, Param, Query } from '@nestjs/common' import { Oracle, OracleMapper } from '../module.model/oracle' import { OraclePriceFeed, OraclePriceFeedMapper } from '../module.model/oracle.price.feed' -import { ApiPagedResponse } from '../module.api/_core/api.paged.response' -import { PaginationQuery } from '../module.api/_core/api.query' +import { ApiPagedResponse } from './_core/api.paged.response' +import { PaginationQuery } from './_core/api.query' @Controller('/oracles') export class OracleController { From f8b2695ff1635a93072a3784e069523746a92834 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 4 Apr 2022 18:01:23 +0800 Subject: [PATCH 02/16] Refactor name to OracleStatusController and update tests for status --- .../controllers/OraclesController.test.ts | 47 +++++++++++++++++-- ...ontroller.ts => OracleStatusController.ts} | 8 ++-- .../src/modules/ControllerModule.ts | 8 ++-- 3 files changed, 53 insertions(+), 10 deletions(-) rename apps/status-api/src/controllers/{OraclesController.ts => OracleStatusController.ts} (84%) diff --git a/apps/status-api/__tests__/controllers/OraclesController.test.ts b/apps/status-api/__tests__/controllers/OraclesController.test.ts index b70c4a5c84..c275b7a554 100644 --- a/apps/status-api/__tests__/controllers/OraclesController.test.ts +++ b/apps/status-api/__tests__/controllers/OraclesController.test.ts @@ -1,4 +1,6 @@ import { StatusApiTesting } from '../../testing/StatusApiTesting' +import { WhaleApiClient } from '@defichain/whale-api-client' +import { Oracle } from '@defichain/whale-api-client/dist/api/Oracles' const apiTesting = StatusApiTesting.create() @@ -10,11 +12,30 @@ afterAll(async () => { await apiTesting.stop() }) -describe('/oracles', () => { - it('/oracles?address=
- limited to 30', async () => { +describe('OracleStatusController - Status test', () => { + it('/status/oracles?address=
- should get operational', async () => { + jest + .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') + .mockReturnValueOnce(getOracle(5)) + const res = await apiTesting.app.inject({ method: 'GET', - url: '/oracles?address=df1q02jh2rkymd6ncl75ql3f267u3guja9nzqj2qmn' + url: 'status/oracles?address=df1q02jh2rkymd6ncl75ql3f267u3guja9nzqj2qmn' + }) + expect(res.json()).toStrictEqual({ + status: 'operational' + }) + expect(res.statusCode).toStrictEqual(200) + }) + + it('/status/oracles?address=
-should get outage', async () => { + jest + .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') + .mockReturnValueOnce(getOracle(18)) + + const res = await apiTesting.app.inject({ + method: 'GET', + url: 'status/oracles?address=df1q02jh2rkymd6ncl75ql3f267u3guja9nzqj2qmn' }) expect(res.json()).toStrictEqual({ status: 'operational' @@ -22,3 +43,23 @@ describe('/oracles', () => { expect(res.statusCode).toStrictEqual(200) }) }) + +async function getOracle (minutesDiff: number): Promise { + const blockMedianTime = Date.now() / 1000 - (minutesDiff * 60) + + return { + id: '', + block: { + hash: '', + height: 0, + medianTime: blockMedianTime, + time: 0 + }, + ownerAddress: '', + priceFeeds: [{ + token: '', + currency: '' + }], + weightage: 0 + } +} diff --git a/apps/status-api/src/controllers/OraclesController.ts b/apps/status-api/src/controllers/OracleStatusController.ts similarity index 84% rename from apps/status-api/src/controllers/OraclesController.ts rename to apps/status-api/src/controllers/OracleStatusController.ts index 99119cf2e4..c7cc4223b8 100644 --- a/apps/status-api/src/controllers/OraclesController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -4,7 +4,7 @@ import { Oracle } from '@defichain/whale-api-client/dist/api/Oracles' import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' @Controller('/status') -export class OraclesController { +export class OracleStatusController { constructor ( private readonly client: WhaleApiClient, protected readonly cache: SemaphoreCache @@ -12,7 +12,7 @@ export class OraclesController { } @Get('oracles') - async getToken ( + async getOracleStatus ( @Query('address') oracleAddress: string ): Promise<{ [key: string]: string }> { const oracle: Oracle = await this.cachedGet('ORACLE', async () => { @@ -24,12 +24,12 @@ export class OraclesController { const timeDiff = nowEpoch - latestPublishedTime return { - status: timeDiff > (15 * 60 * 1000) ? 'operational' : 'outage' + status: timeDiff < (15 * 60 * 1000) ? 'operational' : 'outage' } } private async cachedGet (field: string, fetch: () => Promise, ttl: number): Promise { - const object = await this.cache.get(`OraclesController.${field}`, fetch, { ttl }) + const object = await this.cache.get(`OracleStatusController.${field}`, fetch, { ttl }) return requireValue(object, field) } } diff --git a/apps/status-api/src/modules/ControllerModule.ts b/apps/status-api/src/modules/ControllerModule.ts index fc8bc76568..9457512356 100644 --- a/apps/status-api/src/modules/ControllerModule.ts +++ b/apps/status-api/src/modules/ControllerModule.ts @@ -3,7 +3,8 @@ import { ActuatorController } from '@defichain-apps/libs/actuator' import { BlockchainStatusController } from '../controllers/BlockchainStatusController' import { WhaleApiClient } from '@defichain/whale-api-client' import { ConfigService } from '@nestjs/config' -import { OracleController } from '../../../whale/src/module.api/oracle.controller' +import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' +import { OracleStatusController } from '../controllers/OracleStatusController' import { OverallStatusController } from '../controllers/OverallStatusController' /** @@ -17,7 +18,7 @@ import { OverallStatusController } from '../controllers/OverallStatusController' ActuatorController, BlockchainStatusController, ActuatorController, - OracleController, + OracleStatusController, OverallStatusController ], providers: [ @@ -32,7 +33,8 @@ import { OverallStatusController } from '../controllers/OverallStatusController' }) }, inject: [ConfigService] - } + }, + SemaphoreCache ] }) export class ControllerModule { From 6242d416cf3d27b48928a6496d7378cdc3d41721 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 4 Apr 2022 18:10:37 +0800 Subject: [PATCH 03/16] Update logic for operational status to less than equals to 15 minutes --- apps/status-api/src/controllers/OracleStatusController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index c7cc4223b8..6d9939549b 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -24,7 +24,7 @@ export class OracleStatusController { const timeDiff = nowEpoch - latestPublishedTime return { - status: timeDiff < (15 * 60 * 1000) ? 'operational' : 'outage' + status: timeDiff <= (15 * 60 * 1000) ? 'operational' : 'outage' } } From 753cd0022023a988387139880c384ac555397adf Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 4 Apr 2022 21:19:17 +0800 Subject: [PATCH 04/16] Update Oracle status logic to outage if > 45 mins --- apps/status-api/src/controllers/OracleStatusController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index 6d9939549b..9171be7155 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -24,7 +24,7 @@ export class OracleStatusController { const timeDiff = nowEpoch - latestPublishedTime return { - status: timeDiff <= (15 * 60 * 1000) ? 'operational' : 'outage' + status: timeDiff <= (45 * 60 * 1000) ? 'operational' : 'outage' } } From 476d372dd9637f0e1efa01c6c67fda15adb19f00 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 4 Apr 2022 21:20:59 +0800 Subject: [PATCH 05/16] Update oracle status path --- .../__tests__/controllers/OraclesController.test.ts | 8 ++++---- apps/status-api/src/controllers/OracleStatusController.ts | 4 ++-- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/apps/status-api/__tests__/controllers/OraclesController.test.ts b/apps/status-api/__tests__/controllers/OraclesController.test.ts index c275b7a554..9fb4fcc912 100644 --- a/apps/status-api/__tests__/controllers/OraclesController.test.ts +++ b/apps/status-api/__tests__/controllers/OraclesController.test.ts @@ -13,14 +13,14 @@ afterAll(async () => { }) describe('OracleStatusController - Status test', () => { - it('/status/oracles?address=
- should get operational', async () => { + it('/oracles?address=
- should get operational', async () => { jest .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') .mockReturnValueOnce(getOracle(5)) const res = await apiTesting.app.inject({ method: 'GET', - url: 'status/oracles?address=df1q02jh2rkymd6ncl75ql3f267u3guja9nzqj2qmn' + url: 'oracles?address=df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw' }) expect(res.json()).toStrictEqual({ status: 'operational' @@ -35,10 +35,10 @@ describe('OracleStatusController - Status test', () => { const res = await apiTesting.app.inject({ method: 'GET', - url: 'status/oracles?address=df1q02jh2rkymd6ncl75ql3f267u3guja9nzqj2qmn' + url: 'oracles?address=df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4' }) expect(res.json()).toStrictEqual({ - status: 'operational' + status: 'outage' }) expect(res.statusCode).toStrictEqual(200) }) diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index 9171be7155..563377f0f3 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -3,7 +3,7 @@ import { WhaleApiClient } from '@defichain/whale-api-client' import { Oracle } from '@defichain/whale-api-client/dist/api/Oracles' import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' -@Controller('/status') +@Controller('oracles') export class OracleStatusController { constructor ( private readonly client: WhaleApiClient, @@ -11,7 +11,7 @@ export class OracleStatusController { ) { } - @Get('oracles') + @Get() async getOracleStatus ( @Query('address') oracleAddress: string ): Promise<{ [key: string]: string }> { From 24cdf048ec5b16e2f5be8e0b1610744c73fe1fe9 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 4 Apr 2022 21:21:56 +0800 Subject: [PATCH 06/16] Corrected to get last published time from price feed instead --- .../controllers/OraclesController.test.ts | 47 +++++++++++++++---- .../src/controllers/OracleStatusController.ts | 11 +++-- 2 files changed, 45 insertions(+), 13 deletions(-) diff --git a/apps/status-api/__tests__/controllers/OraclesController.test.ts b/apps/status-api/__tests__/controllers/OraclesController.test.ts index 9fb4fcc912..ecc053bc32 100644 --- a/apps/status-api/__tests__/controllers/OraclesController.test.ts +++ b/apps/status-api/__tests__/controllers/OraclesController.test.ts @@ -1,6 +1,6 @@ import { StatusApiTesting } from '../../testing/StatusApiTesting' -import { WhaleApiClient } from '@defichain/whale-api-client' -import { Oracle } from '@defichain/whale-api-client/dist/api/Oracles' +import { ApiPagedResponse, WhaleApiClient } from '@defichain/whale-api-client' +import { Oracle, OraclePriceFeed } from '@defichain/whale-api-client/dist/api/Oracles' const apiTesting = StatusApiTesting.create() @@ -16,7 +16,11 @@ describe('OracleStatusController - Status test', () => { it('/oracles?address=
- should get operational', async () => { jest .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') - .mockReturnValueOnce(getOracle(5)) + .mockReturnValueOnce(getOracle('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw')) + + jest + .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') + .mockReturnValueOnce(getOraclePriceFeed('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw', 5)) const res = await apiTesting.app.inject({ method: 'GET', @@ -28,10 +32,14 @@ describe('OracleStatusController - Status test', () => { expect(res.statusCode).toStrictEqual(200) }) - it('/status/oracles?address=
-should get outage', async () => { + it('/oracles?address=
-should get outage', async () => { jest .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') - .mockReturnValueOnce(getOracle(18)) + .mockReturnValueOnce(getOracle('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4')) + + jest + .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') + .mockReturnValueOnce(getOraclePriceFeed('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4', 46)) const res = await apiTesting.app.inject({ method: 'GET', @@ -44,18 +52,41 @@ describe('OracleStatusController - Status test', () => { }) }) -async function getOracle (minutesDiff: number): Promise { +async function getOraclePriceFeed (oracleAddress: string, minutesDiff: number): Promise> { const blockMedianTime = Date.now() / 1000 - (minutesDiff * 60) + return new ApiPagedResponse({ + data: [{ + id: '', + key: '', + sort: '', + token: '', + currency: '', + oracleId: '', + txid: '', + time: 0, + amount: '', + + block: { + hash: '', + height: 0, + medianTime: blockMedianTime, + time: 0 + } + }] + }, 'GET', `oracles/${oracleAddress}/AAPL-USD/feed`) +} + +async function getOracle (oracleAddress: string): Promise { return { id: '', block: { hash: '', height: 0, - medianTime: blockMedianTime, + medianTime: 0, time: 0 }, - ownerAddress: '', + ownerAddress: oracleAddress, priceFeeds: [{ token: '', currency: '' diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index 563377f0f3..f49625629d 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -1,6 +1,6 @@ import { Controller, Get, Query } from '@nestjs/common' import { WhaleApiClient } from '@defichain/whale-api-client' -import { Oracle } from '@defichain/whale-api-client/dist/api/Oracles' +import { OraclePriceFeed } from '@defichain/whale-api-client/dist/api/Oracles' import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' @Controller('oracles') @@ -15,12 +15,13 @@ export class OracleStatusController { async getOracleStatus ( @Query('address') oracleAddress: string ): Promise<{ [key: string]: string }> { - const oracle: Oracle = await this.cachedGet('ORACLE', async () => { - return await this.client.oracles.getOracleByAddress(oracleAddress) - }, 1000) + const oraclePriceFeed: OraclePriceFeed = await this.cachedGet(`oracle-${oracleAddress}`, async () => { + const oracle = await this.client.oracles.getOracleByAddress(oracleAddress) + return (await this.client.oracles.getPriceFeed(oracle.id, oracle.priceFeeds[0].token, oracle.priceFeeds[0].currency, 1))[0] + }, 5000) const nowEpoch = Date.now() - const latestPublishedTime = oracle.block.medianTime * 1000 + const latestPublishedTime = oraclePriceFeed.block.medianTime * 1000 const timeDiff = nowEpoch - latestPublishedTime return { From 8d25af510aede185dd0613f9fd9d46f660e00ab5 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 4 Apr 2022 21:36:13 +0800 Subject: [PATCH 07/16] Refactor oracle status test --- .../controllers/OraclesController.test.ts | 35 +++++++------------ 1 file changed, 13 insertions(+), 22 deletions(-) diff --git a/apps/status-api/__tests__/controllers/OraclesController.test.ts b/apps/status-api/__tests__/controllers/OraclesController.test.ts index ecc053bc32..71e19e4ea7 100644 --- a/apps/status-api/__tests__/controllers/OraclesController.test.ts +++ b/apps/status-api/__tests__/controllers/OraclesController.test.ts @@ -6,6 +6,8 @@ const apiTesting = StatusApiTesting.create() beforeAll(async () => { await apiTesting.start() + jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') + .mockReturnValue(getOracle()) }) afterAll(async () => { @@ -14,12 +16,7 @@ afterAll(async () => { describe('OracleStatusController - Status test', () => { it('/oracles?address=
- should get operational', async () => { - jest - .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') - .mockReturnValueOnce(getOracle('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw')) - - jest - .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') + jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') .mockReturnValueOnce(getOraclePriceFeed('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw', 5)) const res = await apiTesting.app.inject({ @@ -33,12 +30,7 @@ describe('OracleStatusController - Status test', () => { }) it('/oracles?address=
-should get outage', async () => { - jest - .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') - .mockReturnValueOnce(getOracle('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4')) - - jest - .spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') + jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') .mockReturnValueOnce(getOraclePriceFeed('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4', 46)) const res = await apiTesting.app.inject({ @@ -57,6 +49,12 @@ async function getOraclePriceFeed (oracleAddress: string, minutesDiff: number): return new ApiPagedResponse({ data: [{ + block: { + medianTime: blockMedianTime, + hash: '', + height: 0, + time: 0 + }, id: '', key: '', sort: '', @@ -65,19 +63,12 @@ async function getOraclePriceFeed (oracleAddress: string, minutesDiff: number): oracleId: '', txid: '', time: 0, - amount: '', - - block: { - hash: '', - height: 0, - medianTime: blockMedianTime, - time: 0 - } + amount: '' }] }, 'GET', `oracles/${oracleAddress}/AAPL-USD/feed`) } -async function getOracle (oracleAddress: string): Promise { +async function getOracle (): Promise { return { id: '', block: { @@ -86,7 +77,7 @@ async function getOracle (oracleAddress: string): Promise { medianTime: 0, time: 0 }, - ownerAddress: oracleAddress, + ownerAddress: '', priceFeeds: [{ token: '', currency: '' From e3f6debda57fb29650f13e2cd92e215498510829 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Wed, 6 Apr 2022 11:08:01 +0800 Subject: [PATCH 08/16] Update readme file with new /oracles status --- apps/status-api/README.md | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/apps/status-api/README.md b/apps/status-api/README.md index e53e95d142..0f86c671de 100644 --- a/apps/status-api/README.md +++ b/apps/status-api/README.md @@ -8,12 +8,29 @@ DeFiChain Status API, providing the statuses of different DeFiChain services. To decouple the DeFiChain products from the status page, the approach of having a centralised provider to determine each DeFiChain service status with a pre-defined logic will allow it to be maintained consistently throughout. This will allow other apps or services to share the status from the same Status APIs. -### `/blockchain/status` +### `/blockchain` >https://github.com/DeFiCh/jellyfish/issues/1271 -To provide the status of the blockchain based on the block creation time interval. +To provide the status of the blockchain based on the block creation time interval + +| Status | Threshold Time | +|--------------------|-------------------| +| `operational` | `< 30 minutes` | +| `degraded` | `30 - 45 minutes` | +| `outage` | `> 45 minutes` | + +### `/oracles?address=
` + +To provide the status of each oracle given the address based on the last published time for any given token + + +| Status | Threshold Time | +|--------------------|------------------| +| `operational` | `<= 45 minutes` | +| `outage` | `> 45 minutes` | + -### `/overall/status` +### `/overall` >https://github.com/DeFiCh/jellyfish/issues/1274 To provide the aggregated status of all services required by Light Wallet & Scan (Blockchain & Ocean). From f87e01d499b2b36364e5fe0c07906f3c8d3336e7 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Wed, 6 Apr 2022 16:41:50 +0800 Subject: [PATCH 09/16] Introduce OracleStatus for explicit API response --- ...ntroller.test.ts => OracleStatusController.test.ts} | 0 .../src/controllers/OracleStatusController.ts | 10 +++++++++- 2 files changed, 9 insertions(+), 1 deletion(-) rename apps/status-api/__tests__/controllers/{OraclesController.test.ts => OracleStatusController.test.ts} (100%) diff --git a/apps/status-api/__tests__/controllers/OraclesController.test.ts b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts similarity index 100% rename from apps/status-api/__tests__/controllers/OraclesController.test.ts rename to apps/status-api/__tests__/controllers/OracleStatusController.test.ts diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index f49625629d..e7bed5cbfa 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -11,10 +11,16 @@ export class OracleStatusController { ) { } + /** + * To provide the status of each oracle given the address based on the last published time for any given token + * + * @param oracleAddress + * @return {Promise} + */ @Get() async getOracleStatus ( @Query('address') oracleAddress: string - ): Promise<{ [key: string]: string }> { + ): Promise<{status: OracleStatus}> { const oraclePriceFeed: OraclePriceFeed = await this.cachedGet(`oracle-${oracleAddress}`, async () => { const oracle = await this.client.oracles.getOracleByAddress(oracleAddress) return (await this.client.oracles.getPriceFeed(oracle.id, oracle.priceFeeds[0].token, oracle.priceFeeds[0].currency, 1))[0] @@ -41,3 +47,5 @@ function requireValue (value: T | undefined, name: string): T { } return value } + +export type OracleStatus = 'outage' | 'operational' From 1f80ca1b5f4e923eb84d7a00b4a359abf2a589b1 Mon Sep 17 00:00:00 2001 From: Joel-David Wong Date: Thu, 7 Apr 2022 14:50:11 +0800 Subject: [PATCH 10/16] Updated mocked oracle function name --- .../controllers/OracleStatusController.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts index 71e19e4ea7..252ec91ae4 100644 --- a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts +++ b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts @@ -7,7 +7,7 @@ const apiTesting = StatusApiTesting.create() beforeAll(async () => { await apiTesting.start() jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getOracleByAddress') - .mockReturnValue(getOracle()) + .mockReturnValue(getMockedOracle()) }) afterAll(async () => { @@ -17,7 +17,7 @@ afterAll(async () => { describe('OracleStatusController - Status test', () => { it('/oracles?address=
- should get operational', async () => { jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') - .mockReturnValueOnce(getOraclePriceFeed('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw', 5)) + .mockReturnValueOnce(getMockedOraclePriceFeed('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw', 5)) const res = await apiTesting.app.inject({ method: 'GET', @@ -31,7 +31,7 @@ describe('OracleStatusController - Status test', () => { it('/oracles?address=
-should get outage', async () => { jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') - .mockReturnValueOnce(getOraclePriceFeed('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4', 46)) + .mockReturnValueOnce(getMockedOraclePriceFeed('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4', 46)) const res = await apiTesting.app.inject({ method: 'GET', @@ -44,7 +44,7 @@ describe('OracleStatusController - Status test', () => { }) }) -async function getOraclePriceFeed (oracleAddress: string, minutesDiff: number): Promise> { +async function getMockedOraclePriceFeed (oracleAddress: string, minutesDiff: number): Promise> { const blockMedianTime = Date.now() / 1000 - (minutesDiff * 60) return new ApiPagedResponse({ @@ -68,7 +68,7 @@ async function getOraclePriceFeed (oracleAddress: string, minutesDiff: number): }, 'GET', `oracles/${oracleAddress}/AAPL-USD/feed`) } -async function getOracle (): Promise { +async function getMockedOracle (): Promise { return { id: '', block: { From 234883ef8d6937bed48e5954366a2976558d3e0b Mon Sep 17 00:00:00 2001 From: Joel-David Wong Date: Thu, 7 Apr 2022 14:52:12 +0800 Subject: [PATCH 11/16] Refactored OracleStatus --- apps/status-api/src/controllers/OracleStatusController.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index e7bed5cbfa..c42fb0a2ef 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -3,6 +3,8 @@ import { WhaleApiClient } from '@defichain/whale-api-client' import { OraclePriceFeed } from '@defichain/whale-api-client/dist/api/Oracles' import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' +type OracleStatus = 'outage' | 'operational' + @Controller('oracles') export class OracleStatusController { constructor ( @@ -20,7 +22,7 @@ export class OracleStatusController { @Get() async getOracleStatus ( @Query('address') oracleAddress: string - ): Promise<{status: OracleStatus}> { + ): Promise<{ status: OracleStatus }> { const oraclePriceFeed: OraclePriceFeed = await this.cachedGet(`oracle-${oracleAddress}`, async () => { const oracle = await this.client.oracles.getOracleByAddress(oracleAddress) return (await this.client.oracles.getPriceFeed(oracle.id, oracle.priceFeeds[0].token, oracle.priceFeeds[0].currency, 1))[0] @@ -47,5 +49,3 @@ function requireValue (value: T | undefined, name: string): T { } return value } - -export type OracleStatus = 'outage' | 'operational' From ae9adf21d167035ef26b6c29569a76ee6470273e Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 11 Apr 2022 17:59:23 +0800 Subject: [PATCH 12/16] Refactor controller test dir --- .../controllers/OracleStatusController.test.ts | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename apps/status-api/{__tests__ => __test__}/controllers/OracleStatusController.test.ts (100%) diff --git a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts b/apps/status-api/__test__/controllers/OracleStatusController.test.ts similarity index 100% rename from apps/status-api/__tests__/controllers/OracleStatusController.test.ts rename to apps/status-api/__test__/controllers/OracleStatusController.test.ts From b313ddadbd0bb88aab18303721b1baa00260b9e8 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Mon, 11 Apr 2022 18:01:35 +0800 Subject: [PATCH 13/16] Refactor controller test dir --- .../controllers/BlockchainStatusController.test.ts | 0 .../controllers/OracleStatusController.test.ts | 0 .../controllers/OverallStatusController.test.ts | 0 3 files changed, 0 insertions(+), 0 deletions(-) rename apps/status-api/{__test__ => __tests__}/controllers/BlockchainStatusController.test.ts (100%) rename apps/status-api/{__test__ => __tests__}/controllers/OracleStatusController.test.ts (100%) rename apps/status-api/{__test__ => __tests__}/controllers/OverallStatusController.test.ts (100%) diff --git a/apps/status-api/__test__/controllers/BlockchainStatusController.test.ts b/apps/status-api/__tests__/controllers/BlockchainStatusController.test.ts similarity index 100% rename from apps/status-api/__test__/controllers/BlockchainStatusController.test.ts rename to apps/status-api/__tests__/controllers/BlockchainStatusController.test.ts diff --git a/apps/status-api/__test__/controllers/OracleStatusController.test.ts b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts similarity index 100% rename from apps/status-api/__test__/controllers/OracleStatusController.test.ts rename to apps/status-api/__tests__/controllers/OracleStatusController.test.ts diff --git a/apps/status-api/__test__/controllers/OverallStatusController.test.ts b/apps/status-api/__tests__/controllers/OverallStatusController.test.ts similarity index 100% rename from apps/status-api/__test__/controllers/OverallStatusController.test.ts rename to apps/status-api/__tests__/controllers/OverallStatusController.test.ts From 8484fd0eece483f8c0298850a4e0f1a5f6b6f36e Mon Sep 17 00:00:00 2001 From: Nichelle Date: Tue, 19 Apr 2022 22:46:58 +0800 Subject: [PATCH 14/16] Update oracle address to path param --- .../__tests__/controllers/OracleStatusController.test.ts | 8 ++++---- apps/status-api/src/controllers/OracleStatusController.ts | 6 +++--- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts index 252ec91ae4..473eb29c7b 100644 --- a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts +++ b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts @@ -15,13 +15,13 @@ afterAll(async () => { }) describe('OracleStatusController - Status test', () => { - it('/oracles?address=
- should get operational', async () => { + it('/oracles?address=
- should get operational as last published < 45 mins ago', async () => { jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') .mockReturnValueOnce(getMockedOraclePriceFeed('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw', 5)) const res = await apiTesting.app.inject({ method: 'GET', - url: 'oracles?address=df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw' + url: 'oracles/df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw' }) expect(res.json()).toStrictEqual({ status: 'operational' @@ -29,13 +29,13 @@ describe('OracleStatusController - Status test', () => { expect(res.statusCode).toStrictEqual(200) }) - it('/oracles?address=
-should get outage', async () => { + it('/oracles?address=
- should get outage as last published >= 45 mins ago', async () => { jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') .mockReturnValueOnce(getMockedOraclePriceFeed('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4', 46)) const res = await apiTesting.app.inject({ method: 'GET', - url: 'oracles?address=df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4' + url: 'oracles/df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4' }) expect(res.json()).toStrictEqual({ status: 'outage' diff --git a/apps/status-api/src/controllers/OracleStatusController.ts b/apps/status-api/src/controllers/OracleStatusController.ts index c42fb0a2ef..cd47cdf6d4 100644 --- a/apps/status-api/src/controllers/OracleStatusController.ts +++ b/apps/status-api/src/controllers/OracleStatusController.ts @@ -1,4 +1,4 @@ -import { Controller, Get, Query } from '@nestjs/common' +import { Controller, Get, Param } from '@nestjs/common' import { WhaleApiClient } from '@defichain/whale-api-client' import { OraclePriceFeed } from '@defichain/whale-api-client/dist/api/Oracles' import { SemaphoreCache } from '../../../whale/src/module.api/cache/semaphore.cache' @@ -19,9 +19,9 @@ export class OracleStatusController { * @param oracleAddress * @return {Promise} */ - @Get() + @Get('/:address') async getOracleStatus ( - @Query('address') oracleAddress: string + @Param('address') oracleAddress: string ): Promise<{ status: OracleStatus }> { const oraclePriceFeed: OraclePriceFeed = await this.cachedGet(`oracle-${oracleAddress}`, async () => { const oracle = await this.client.oracles.getOracleByAddress(oracleAddress) From 71f804419f991728e7df251153de0f026ce71a50 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Tue, 19 Apr 2022 22:48:11 +0800 Subject: [PATCH 15/16] Update oracle address to path param --- apps/status-api/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/apps/status-api/README.md b/apps/status-api/README.md index 0f86c671de..f42a445128 100644 --- a/apps/status-api/README.md +++ b/apps/status-api/README.md @@ -19,7 +19,7 @@ To provide the status of the blockchain based on the block creation time interva | `degraded` | `30 - 45 minutes` | | `outage` | `> 45 minutes` | -### `/oracles?address=
` +### `/oracles/:address` To provide the status of each oracle given the address based on the last published time for any given token From c020a924eee3078888887d48433572ca0020f6e9 Mon Sep 17 00:00:00 2001 From: Nichelle Date: Tue, 19 Apr 2022 23:13:28 +0800 Subject: [PATCH 16/16] Update OracleStatusController.test.ts --- .../__tests__/controllers/OracleStatusController.test.ts | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts index 473eb29c7b..c8658f79d9 100644 --- a/apps/status-api/__tests__/controllers/OracleStatusController.test.ts +++ b/apps/status-api/__tests__/controllers/OracleStatusController.test.ts @@ -15,7 +15,7 @@ afterAll(async () => { }) describe('OracleStatusController - Status test', () => { - it('/oracles?address=
- should get operational as last published < 45 mins ago', async () => { + it('/oracles/
- should get operational as last published < 45 mins ago', async () => { jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') .mockReturnValueOnce(getMockedOraclePriceFeed('df1qm7f2cx8vs9lqn8v43034nvckz6dxxpqezfh6dw', 5)) @@ -29,7 +29,7 @@ describe('OracleStatusController - Status test', () => { expect(res.statusCode).toStrictEqual(200) }) - it('/oracles?address=
- should get outage as last published >= 45 mins ago', async () => { + it('/oracles/
- should get outage as last published >= 45 mins ago', async () => { jest.spyOn(apiTesting.app.get(WhaleApiClient).oracles, 'getPriceFeed') .mockReturnValueOnce(getMockedOraclePriceFeed('df1qcpp3entq53tdyklm5v0lnvqer4verr4puxchq4', 46))