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

feat: base caching #55

Merged
merged 4 commits into from
Aug 23, 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
9 changes: 7 additions & 2 deletions apps/api/.env.example
Original file line number Diff line number Diff line change
@@ -1,6 +1,11 @@
PORT=3000 # Port to run the API server on
L1_RPC_URLS="" #CSV list of L2 RPC URLs
L2_RPC_URLS="" #CSV list of L1 RPC URLs

BRIDGE_HUB_ADDRESS=""
SHARED_BRIDGE_ADDRESS=""
STATE_MANAGER_ADDRESSES="" #CSV list of State managers addresses

L1_RPC_URLS="" #CSV list of L1 RPC URLs
L2_RPC_URLS="" #CSV list of L2 RPC URLs

COINGECKO_API_KEY='' # CoinGecko API key
COINGECKO_BASE_URL='' # CoinGecko API base URL for the API version you are using
Expand Down
3 changes: 2 additions & 1 deletion apps/api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,15 +17,16 @@
"test:cov": "vitest run --config vitest.config.ts --coverage"
},
"dependencies": {
"@zkchainhub/chain-providers": "workspace:*",
"@zkchainhub/metrics": "workspace:*",
"@zkchainhub/pricing": "workspace:*",
"@zkchainhub/chain-providers": "workspace:*",
"@zkchainhub/shared": "workspace:*",
"bignumber.js": "9.1.2",
"cache-manager": "5.7.6",
"cors": "2.8.5",
"dotenv": "16.4.5",
"express": "4.19.2",
"node-cache": "5.1.2",
"swagger-ui-express": "5.0.1",
"viem": "2.19.6",
"yaml": "2.5.0",
Expand Down
21 changes: 17 additions & 4 deletions apps/api/src/common/config/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import dotenv from "dotenv";
import { Address } from "viem";
import { Address, isAddress } from "viem";
import { mainnet, zksync } from "viem/chains";
import { z } from "zod";

Expand All @@ -9,6 +9,16 @@ dotenv.config();

const logger = Logger.getInstance();

const addressArraySchema = z
.string()
.transform((str) => str.split(","))
.refine((addresses) => addresses.every((address) => isAddress(address)), {
message: "Must be a comma-separated list of valid Addresses",
});
const addressSchema = z.string().refine((address) => isAddress(address), {
message: "Must be a valid Address",
});

const urlArraySchema = z
.string()
.transform((str) => str.split(","))
Expand All @@ -18,6 +28,9 @@ const urlArraySchema = z

const validationSchema = z.object({
PORT: z.coerce.number().positive().default(3000),
BRIDGE_HUB_ADDRESS: addressSchema,
SHARED_BRIDGE_ADDRESS: addressSchema,
STATE_MANAGER_ADDRESSES: addressArraySchema,
L1_RPC_URLS: urlArraySchema,
L2_RPC_URLS: z
.union([z.literal(""), urlArraySchema])
Expand Down Expand Up @@ -54,9 +67,9 @@ export const config = {
chain: zksync,
}
: undefined,
bridgeHubAddress: "0x303a465B659cBB0ab36eE643eA362c509EEb5213" as Address,
sharedBridgeAddress: "0xD7f9f54194C633F36CCD5F3da84ad4a1c38cB2cB" as Address,
stateTransitionManagerAddresses: ["0xc2eE6b6af7d616f6e27ce7F4A451Aedc2b0F5f5C"] as Address[],
bridgeHubAddress: envData.BRIDGE_HUB_ADDRESS as Address,
sharedBridgeAddress: envData.SHARED_BRIDGE_ADDRESS as Address,
stateTransitionManagerAddresses: envData.STATE_MANAGER_ADDRESSES as Address[],
pricing: {
cacheOptions: {
ttl: envData.CACHE_TTL,
Expand Down
36 changes: 36 additions & 0 deletions apps/api/src/common/middleware/cache.middleware.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { NextFunction, Request, Response } from "express";
import NodeCache from "node-cache";

const DEFAULT_TTL = 60; // 1 minute
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should we add this as env config too? maybe add it to tech debt to not forget

const cache = new NodeCache();

//FIXME: This is a temporary cache implementation. It is not recommended for production use.
// might be replaced with a more robust solution in the future.
/**
* A middleware that caches responses for a given time to live (TTL).
* @param args - The time to live (TTL) in seconds for the cached response.
* @returns A middleware function that caches responses for a given time to live (TTL).
*/
export function cacheMiddleware(args: { ttl: number } = { ttl: DEFAULT_TTL }) {
return async (req: Request, res: Response, next: NextFunction): Promise<void> => {
const key = req.originalUrl || req.url;
const cachedResponse = await cache.get(key);
if (cachedResponse) {
// Check if the cached response is a JSON object or plain text
res.json(cachedResponse);
} else {
// Store the original send and json functions
const originalJson = res.json.bind(res);
// Override the json function

res.json = (body): Response => {
// Cache the response body
cache.set(key, body, args.ttl);
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do NodeCache instances have some kind of limit on how many items it can cache? I understand this is a v0.1 solution so no worries if you've taken into account this potentially growing a lot.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is just a temporary solution, no idea how many items can NodeCache handle. In this case we are just gona have 2 items.

// Call the original json function with the response body
return originalJson(body);
};

next();
}
};
}
2 changes: 1 addition & 1 deletion apps/api/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { inspect } from "util";
import { caching } from "cache-manager";

import { EvmProvider } from "@zkchainhub/chain-providers/dist/src/index.js";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { EvmProvider } from "@zkchainhub/chain-providers/dist/src/index.js";
import { EvmProvider } from "@zkchainhub/chain-providers";

import { L1MetricsService } from "@zkchainhub/metrics";
import { CoingeckoProvider } from "@zkchainhub/pricing";
import { Logger } from "@zkchainhub/shared";

import { EvmProvider } from "../../../packages/chain-providers/dist/src/index.js";
import { App } from "./app.js";
import { config } from "./common/config/index.js";
import { MetricsController, MetricsRouter } from "./metrics/index.js";
Expand Down
5 changes: 3 additions & 2 deletions apps/api/src/metrics/routes/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { z } from "zod";

import { ILogger } from "@zkchainhub/shared";

import { cacheMiddleware } from "../../common/middleware/cache.middleware.js";
import { BaseRouter } from "../../common/routes/baseRouter.js";
import { ChainNotFound, MetricsController } from "../index.js";

Expand All @@ -27,7 +28,7 @@ export class MetricsRouter extends BaseRouter {
* Retrieves the ecosystem information.
* @returns {Promise<EcosystemInfo>} The ecosystem information.
*/
this.router.get("/ecosystem", async (_req, res, next) => {
this.router.get("/ecosystem", cacheMiddleware(), async (_req, res, next) => {
try {
const data = await this.metricsController.getEcosystem();
res.json(data);
Expand All @@ -42,7 +43,7 @@ export class MetricsRouter extends BaseRouter {
* @param {number} chainId - The ID of the chain.
* @returns {Promise<ZKChainInfo>} The chain information.
*/
this.router.get("/zkchain/:chainId", async (req, res, next) => {
this.router.get("/zkchain/:chainId", cacheMiddleware(), async (req, res, next) => {
try {
const { params } = ChainIdSchema.parse(req);

Expand Down
2 changes: 1 addition & 1 deletion packages/metrics/src/l1/l1MetricsService.ts
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import {
zeroAddress,
} from "viem";

import { EvmProvider } from "@zkchainhub/chain-providers/dist/src/index.js";
import { IPricingProvider } from "@zkchainhub/pricing";
import {
BatchesInfo,
Expand All @@ -27,7 +28,6 @@ import {
WETH,
} from "@zkchainhub/shared";

import { EvmProvider } from "../../../chain-providers/dist/src/index.js";
import {
AssetTvl,
bridgeHubAbi,
Expand Down
2 changes: 1 addition & 1 deletion packages/metrics/test/unit/l1/l1MetricsService.spec.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { Address, encodeFunctionData, erc20Abi, parseEther, zeroAddress } from "viem";
import { afterEach, describe, expect, it, Mocked, vi } from "vitest";

import { EvmProvider, MulticallNotFound } from "@zkchainhub/chain-providers/dist/src/index.js";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
import { EvmProvider, MulticallNotFound } from "@zkchainhub/chain-providers/dist/src/index.js";
import { EvmProvider, MulticallNotFound } from "@zkchainhub/chain-providers";

import { IPricingProvider } from "@zkchainhub/pricing";
import {
BatchesInfo,
Expand All @@ -15,7 +16,6 @@ import {
WETH,
} from "@zkchainhub/shared";

import { EvmProvider, MulticallNotFound } from "../../../../chain-providers/dist/src/index.js";
import {
bridgeHubAbi,
diamondProxyAbi,
Expand Down
23 changes: 23 additions & 0 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.