diff --git a/src/helpers/rateLimit.ts b/src/helpers/rateLimit.ts index 5a51ed67..34dc2848 100644 --- a/src/helpers/rateLimit.ts +++ b/src/helpers/rateLimit.ts @@ -12,7 +12,9 @@ let client; client = createClient({ url: process.env.RATE_LIMIT_DATABASE_URL }); client.on('connect', () => console.log('[redis-rl] Redis connect')); client.on('ready', () => console.log('[redis-rl] Redis ready')); - client.on('reconnecting', err => console.log('[redis-rl] Redis reconnecting', err)); + client.on('reconnecting', err => + console.log('[redis-rl] Redis reconnecting', err) + ); client.on('error', err => console.log('[redis-rl] Redis error', err)); client.on('end', err => console.log('[redis-rl] Redis end', err)); await client.connect(); diff --git a/src/methods.test.ts b/src/methods.test.ts index c339074a..e0925541 100644 --- a/src/methods.test.ts +++ b/src/methods.test.ts @@ -96,7 +96,10 @@ describe('getVp function', () => { space: 'testSpace' }; - (snapshot.utils.getVp as jest.Mock).mockResolvedValue({ vp_state: 'pending', vp: 100 }); + (snapshot.utils.getVp as jest.Mock).mockResolvedValue({ + vp_state: 'pending', + vp: 100 + }); (getCurrentBlockNum as jest.Mock).mockResolvedValue(params.snapshot); const result = await getVp(params); @@ -161,13 +164,21 @@ describe('getVp function', () => { expect(mockRedis.multi).toHaveBeenCalled(); - expect(mockMulti.hSet).toHaveBeenCalledWith(`vp:${cacheKey}`, 'vp', votingPower.vp); + expect(mockMulti.hSet).toHaveBeenCalledWith( + `vp:${cacheKey}`, + 'vp', + votingPower.vp + ); expect(mockMulti.hSet).toHaveBeenCalledWith( `vp:${cacheKey}`, 'vp_by_strategy', JSON.stringify(votingPower.vp_by_strategy) ); - expect(mockMulti.hSet).toHaveBeenCalledWith(`vp:${cacheKey}`, 'vp_state', votingPower.vp_state); + expect(mockMulti.hSet).toHaveBeenCalledWith( + `vp:${cacheKey}`, + 'vp_state', + votingPower.vp_state + ); expect(mockMulti.exec).toHaveBeenCalled(); expect(result).toEqual({ @@ -210,12 +221,22 @@ describe('getVp function', () => { delegation: true }; - (snapshot.utils.getVp as jest.Mock).mockResolvedValue({ vp_state: 'pending', vp: 100 }); + (snapshot.utils.getVp as jest.Mock).mockResolvedValue({ + vp_state: 'pending', + vp: 100 + }); (getCurrentBlockNum as jest.Mock).mockResolvedValue(params.snapshot); await getVp(params); - expect(snapshot.utils.getVp).toHaveBeenCalledWith('0x123', '1', [], 1000, 'testSpace', true); + expect(snapshot.utils.getVp).toHaveBeenCalledWith( + '0x123', + '1', + [], + 1000, + 'testSpace', + true + ); }); }); diff --git a/src/methods.ts b/src/methods.ts index 3023a547..24e79cc1 100644 --- a/src/methods.ts +++ b/src/methods.ts @@ -21,19 +21,28 @@ interface ValidateRequestParams { params: any; } -const disableCachingForSpaces = ['magicappstore.eth', 'moonbeam-foundation.eth']; +const disableCachingForSpaces = [ + 'magicappstore.eth', + 'moonbeam-foundation.eth' +]; export async function getVp(params: GetVpRequestParams) { if (typeof params.snapshot !== 'number') params.snapshot = 'latest'; if (params.snapshot !== 'latest') { - const currentBlockNum = await getCurrentBlockNum(params.snapshot, params.network); - params.snapshot = currentBlockNum < params.snapshot ? 'latest' : params.snapshot; + const currentBlockNum = await getCurrentBlockNum( + params.snapshot, + params.network + ); + params.snapshot = + currentBlockNum < params.snapshot ? 'latest' : params.snapshot; } const key = sha256(JSON.stringify(params)); const useCache = - redis && params.snapshot !== 'latest' && !disableCachingForSpaces.includes(params.space); + redis && + params.snapshot !== 'latest' && + !disableCachingForSpaces.includes(params.space); if (useCache) { const cache = await redis.hGetAll(`vp:${key}`); @@ -60,7 +69,11 @@ export async function getVp(params: GetVpRequestParams) { if (useCache && result.vp_state === 'final') { const multi = redis.multi(); multi.hSet(`vp:${key}`, 'vp', result.vp); - multi.hSet(`vp:${key}`, 'vp_by_strategy', JSON.stringify(result.vp_by_strategy)); + multi.hSet( + `vp:${key}`, + 'vp_by_strategy', + JSON.stringify(result.vp_by_strategy) + ); multi.hSet(`vp:${key}`, 'vp_state', result.vp_state); multi.exec(); } diff --git a/src/metrics.ts b/src/metrics.ts index 10b0d90d..4c285515 100644 --- a/src/metrics.ts +++ b/src/metrics.ts @@ -13,7 +13,9 @@ const rateLimitedRequestsCount = new client.Counter({ function instrumentRateLimitedRequests(req, res, next) { res.on('finish', () => { if (whitelistedPath.some(path => path.test(req.path))) { - rateLimitedRequestsCount.inc({ rate_limited: res.statusCode === 429 ? 1 : 0 }); + rateLimitedRequestsCount.inc({ + rate_limited: res.statusCode === 429 ? 1 : 0 + }); } }); diff --git a/src/redis.ts b/src/redis.ts index de4fd536..e6960415 100644 --- a/src/redis.ts +++ b/src/redis.ts @@ -9,7 +9,9 @@ let client; client = createClient({ url: process.env.DATABASE_URL }); client.on('connect', () => console.log('[redis] Redis connect')); client.on('ready', () => console.log('[redis] Redis ready')); - client.on('reconnecting', err => console.log('[redis] Redis reconnecting', err)); + client.on('reconnecting', err => + console.log('[redis] Redis reconnecting', err) + ); client.on('error', err => console.log('[redis] Redis error', err)); client.on('end', err => console.log('[redis] Redis end', err)); await client.connect(); diff --git a/src/rpc.test.ts b/src/rpc.test.ts index 0a873144..25483912 100644 --- a/src/rpc.test.ts +++ b/src/rpc.test.ts @@ -14,7 +14,9 @@ jest.mock('./methods', () => ({ validate: jest.fn().mockResolvedValue(true), disabledNetworks: ['1319'] })); -jest.mock('./scores', () => jest.fn().mockResolvedValue({ result: {}, cache: false })); +jest.mock('./scores', () => + jest.fn().mockResolvedValue({ result: {}, cache: false }) +); jest.mock('./helpers/strategies', () => jest.fn()); jest.mock('./helpers/validations', () => jest.fn()); jest.mock('./requestDeduplicator', () => @@ -51,7 +53,12 @@ describe('API Routes', () => { const mockedRes = expect.anything(); const response = await request(app).post('/').send({}); - expect(utils.rpcError).toBeCalledWith(mockedRes, 400, 'missing method', null); + expect(utils.rpcError).toBeCalledWith( + mockedRes, + 400, + 'missing method', + null + ); expect(response.status).toBe(400); }); @@ -63,7 +70,12 @@ describe('API Routes', () => { method: 'get_vp', params: { address: '0x0000000000000000000000000000000000000000' } }); - expect(utils.rpcError).toBeCalledWith(mockedRes, 400, 'invalid address', null); + expect(utils.rpcError).toBeCalledWith( + mockedRes, + 400, + 'invalid address', + null + ); expect(response.status).toBe(400); }); @@ -75,9 +87,11 @@ describe('API Routes', () => { method: 'get_vp', params: { address: '0x123' } }); - expect(serve).toBeCalledWith(JSON.stringify({ address: '0x123' }), getVp, [ - { address: '0x123' } - ]); + expect(serve).toBeCalledWith( + JSON.stringify({ address: '0x123' }), + getVp, + [{ address: '0x123' }] + ); expect(response.status).toBe(200); }); @@ -103,9 +117,11 @@ describe('API Routes', () => { method: 'validate', params: { author: '0x123' } }); - expect(serve).toBeCalledWith(JSON.stringify({ author: '0x123' }), validate, [ - { author: '0x123' } - ]); + expect(serve).toBeCalledWith( + JSON.stringify({ author: '0x123' }), + validate, + [{ author: '0x123' }] + ); expect(response.status).toBe(200); }); @@ -131,7 +147,12 @@ describe('API Routes', () => { method: 'wrong_method', params: { address: '0x123' } }); - expect(utils.rpcError).toBeCalledWith(mockedRes, 400, 'wrong method', null); + expect(utils.rpcError).toBeCalledWith( + mockedRes, + 400, + 'wrong method', + null + ); expect(response.status).toBe(400); }); }); @@ -218,11 +239,17 @@ describe('API Routes', () => { describe('POST /api/scores', () => { it('should return error for disabled networks', async () => { const mockedRes = expect.anything(); - (utils.formatStrategies as jest.Mock).mockReturnValueOnce([{ name: 'test-strategy' }]); + (utils.formatStrategies as jest.Mock).mockReturnValueOnce([ + { name: 'test-strategy' } + ]); const response = await request(app) .post('/api/scores') .send({ - params: { network: '1319', strategies: [{ name: 'basic-strategy' }], space: '' } + params: { + network: '1319', + strategies: [{ name: 'basic-strategy' }], + space: '' + } }); expect(utils.rpcError).toBeCalledWith( @@ -236,7 +263,9 @@ describe('API Routes', () => { it('should return error for spaces with name that includes `pod-leader`', async () => { const mockedRes = expect.anything(); - (utils.formatStrategies as jest.Mock).mockReturnValueOnce([{ name: 'pod-leader' }]); + (utils.formatStrategies as jest.Mock).mockReturnValueOnce([ + { name: 'pod-leader' } + ]); const response = await request(app) .post('/api/scores') .send({ @@ -293,7 +322,9 @@ describe('API Routes', () => { cache: isCached, data: 'test data' }); - (utils.formatStrategies as jest.Mock).mockReturnValueOnce([{ name: 'test-strategy' }]); + (utils.formatStrategies as jest.Mock).mockReturnValueOnce([ + { name: 'test-strategy' } + ]); const response = await request(app) .post('/api/scores') @@ -301,14 +332,21 @@ describe('API Routes', () => { params: { network: '1', strategies: [{ name: 'test-strategy' }] } }); - expect(utils.rpcSuccess).toBeCalledWith(mockedRes, { data: 'test data' }, null, isCached); + expect(utils.rpcSuccess).toBeCalledWith( + mockedRes, + { data: 'test data' }, + null, + isCached + ); expect(response.status).toBe(200); }); it('should return error if score calculation fails', async () => { const mockedRes = expect.anything(); (scores as jest.Mock).mockRejectedValueOnce(new Error('Test error')); - (utils.formatStrategies as jest.Mock).mockReturnValueOnce([{ name: 'test-strategy' }]); + (utils.formatStrategies as jest.Mock).mockReturnValueOnce([ + { name: 'test-strategy' } + ]); const response = await request(app) .post('/api/scores') @@ -316,7 +354,12 @@ describe('API Routes', () => { params: { network: '1', strategies: [{ name: 'test-strategy' }] } }); - expect(utils.rpcError).toBeCalledWith(mockedRes, 500, new Error('Test error'), null); + expect(utils.rpcError).toBeCalledWith( + mockedRes, + 500, + new Error('Test error'), + null + ); expect(response.status).toBe(500); }); }); diff --git a/src/rpc.ts b/src/rpc.ts index d9114f92..e111335b 100644 --- a/src/rpc.ts +++ b/src/rpc.ts @@ -1,7 +1,12 @@ import express from 'express'; import { getAddress } from '@ethersproject/address'; import scores from './scores'; -import { formatStrategies, rpcSuccess, rpcError, blockNumByNetwork } from './utils'; +import { + formatStrategies, + rpcSuccess, + rpcError, + blockNumByNetwork +} from './utils'; import { version } from '../package.json'; import { getVp, validate } from './methods'; import getStrategies from './helpers/strategies'; @@ -37,11 +42,16 @@ router.post('/', async (req, res) => { return rpcError(res, 429, 'too many requests', null); try { - const response: any = await serve(JSON.stringify(params), getVp, [params]); + const response: any = await serve(JSON.stringify(params), getVp, [ + params + ]); return rpcSuccess(res, response.result, id, response.cache); } catch (e: any) { capture(e, { params, method }); - let error = JSON.stringify(e?.message || e || 'Unknown error').slice(0, 1000); + let error = JSON.stringify(e?.message || e || 'Unknown error').slice( + 0, + 1000 + ); // Detect provider error if (e?.reason && e?.error?.reason && e?.error?.url) { @@ -66,7 +76,10 @@ router.post('/', async (req, res) => { return rpcSuccess(res, result, id); } catch (e: any) { capture(e, { params, method }); - let error = JSON.stringify(e?.message || e || 'Unknown error').slice(0, 1000); + let error = JSON.stringify(e?.message || e || 'Unknown error').slice( + 0, + 1000 + ); // Detect provider error if (e?.reason && e?.error?.reason && e?.error?.url) { @@ -103,7 +116,13 @@ router.get('/api/validations', (req, res) => { router.post('/api/scores', async (req, res) => { const { params = {} } = req.body || {}; const requestId = req.headers['x-request-id']; - const { space = '', network = '1', snapshot = 'latest', addresses = [], force = false } = params; + const { + space = '', + network = '1', + snapshot = 'latest', + addresses = [], + force = false + } = params; let { strategies = [] } = params; strategies = formatStrategies(network, strategies); const strategyNames = strategies.map(strategy => strategy.name); diff --git a/src/scores.ts b/src/scores.ts index 66c55fb6..7c8151e8 100644 --- a/src/scores.ts +++ b/src/scores.ts @@ -12,7 +12,8 @@ async function calculateScores(parent, args, key) { if (args.snapshot !== 'latest') { const currentBlockNum = await getCurrentBlockNum(args.snapshot, network); - snapshotBlockNum = currentBlockNum < args.snapshot ? 'latest' : args.snapshot; + snapshotBlockNum = + currentBlockNum < args.snapshot ? 'latest' : args.snapshot; } const state = snapshotBlockNum === 'latest' ? 'pending' : 'final'; diff --git a/src/utils.test.ts b/src/utils.test.ts index 61d4546d..47f438c6 100644 --- a/src/utils.test.ts +++ b/src/utils.test.ts @@ -33,7 +33,9 @@ jest.mock('./utils', () => { describe('getCurrentBlockNum function', () => { beforeEach(() => { jest.clearAllMocks(); - Object.keys(blockNumByNetwork).forEach(key => delete blockNumByNetwork[key]); + Object.keys(blockNumByNetwork).forEach( + key => delete blockNumByNetwork[key] + ); }); afterAll(() => { diff --git a/test/e2e/index.test.ts b/test/e2e/index.test.ts index a7229e3c..bfb962a6 100644 --- a/test/e2e/index.test.ts +++ b/test/e2e/index.test.ts @@ -11,7 +11,9 @@ describe('/', () => { describe('when method params is invalid', () => { it('returns a 400 error', async () => { - const response = await request(process.env.HOST).post('/').send({ method: 'test' }); + const response = await request(process.env.HOST) + .post('/') + .send({ method: 'test' }); expect(response.status).toEqual(400); });