Skip to content

Commit 5d51010

Browse files
committed
Merge remote-tracking branch 'origin/main' into ph/txWorkerRedis
2 parents 4699307 + 8e97af5 commit 5d51010

File tree

8 files changed

+156
-50
lines changed

8 files changed

+156
-50
lines changed

Dockerfile

Lines changed: 17 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,10 @@
1-
FROM node:18.19-alpine AS base
2-
3-
# Install tini & build dependencies
4-
RUN apk add --no-cache tini && \
5-
apk --no-cache --virtual build-dependencies add g++ make py3-pip openssl
1+
FROM node:18.20-slim AS base
62

73
# Upgrade packages
8-
RUN apk update && apk upgrade
4+
RUN apt-get -y update && apt-get -y upgrade
5+
6+
# Install tini & build dependencies
7+
RUN apt-get install -y g++ make python3-pip openssl
98

109
# Set the working directory
1110
WORKDIR /app
@@ -30,7 +29,7 @@ RUN openssl req -x509 -newkey rsa:4096 -keyout key.pem -out cert.pem -days 365 \
3029
WORKDIR /app
3130

3231
# Clean up build dependencies
33-
RUN apk del build-dependencies
32+
# RUN apt del build-dependencies
3433

3534
##############################
3635
##############################
@@ -41,9 +40,6 @@ EXPOSE 3005
4140
ENV NODE_ENV="local"
4241
RUN npm install -g nodemon
4342

44-
# Use tini as entrypoint to handle killing processes
45-
ENTRYPOINT ["/sbin/tini", "--"]
46-
4743
CMD [ "sh", "-c","yarn prisma:setup:dev && yarn dev:run" ]
4844

4945
##############################
@@ -54,29 +50,32 @@ FROM base AS prod-dependencies
5450

5551
WORKDIR /app
5652

53+
# Upgrade packages
54+
RUN apt-get -y update && apt-get -y upgrade
55+
5756
# Build the project
58-
RUN apk --no-cache --virtual build-dependencies add g++ make py3-pip && \
57+
RUN apt-get install -y g++ make python3-pip && \
5958
yarn build && \
6059
yarn copy-files && \
6160
rm -rf node_modules && \
62-
yarn install --production=true --frozen-lockfile --network-timeout 1000000 && \
63-
apk del build-dependencies
61+
yarn install --production=true --frozen-lockfile --network-timeout 1000000
6462

65-
# Upgrade packages
66-
RUN apk update && apk upgrade
6763

6864
##############################
6965
##############################
7066

7167
# Production stage
72-
FROM node:18.19-alpine AS prod
68+
FROM node:18.20-slim AS prod
7369

7470
# Setting ENV variables for image information
7571
ARG ENGINE_VERSION
7672
ENV ENGINE_VERSION=${ENGINE_VERSION}
7773

78-
# Install tini
79-
RUN apk add --no-cache tini
74+
# Upgrade packages
75+
RUN apt-get -y update && apt-get -y upgrade
76+
77+
# Install openssl
78+
RUN apt-get install -y openssl
8079

8180
# Set the working directory
8281
WORKDIR /app
@@ -96,6 +95,4 @@ COPY --from=prod-dependencies /app/node_modules ./node_modules
9695
COPY --from=prod-dependencies /app/dist ./dist
9796
COPY --from=base /app/src/https ./dist/https
9897

99-
# Use tini as entrypoint to handle killing processes
100-
ENTRYPOINT ["/sbin/tini", "--"]
10198
CMD [ "yarn", "start"]

src/index.ts

Lines changed: 33 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,41 @@
11
import "./polyfill";
22
import { initServer } from "./server";
3+
import { env } from "./utils/env";
4+
import { logger } from "./utils/logger";
35
import { initWorker } from "./worker";
46

57
const main = async () => {
6-
initServer();
7-
initWorker();
8+
if (env.ENGINE_MODE === "server_only") {
9+
initServer();
10+
} else if (env.ENGINE_MODE === "worker_only") {
11+
initWorker();
12+
} else {
13+
initServer();
14+
initWorker();
15+
}
816
};
917

1018
main();
19+
20+
// Adding handlers for `uncaughtException` & `unhandledRejection`
21+
// Needs to be root level of your application to ensure it
22+
// catches any unhandledRejections or uncaughtException that occur throughout
23+
// entire codebase
24+
25+
process.on("uncaughtException", (err) => {
26+
logger({
27+
message: "Uncaught Exception",
28+
service: "server",
29+
level: "error",
30+
error: err,
31+
});
32+
});
33+
34+
process.on("unhandledRejection", (err) => {
35+
logger({
36+
message: "Unhandled Rejection",
37+
service: "server",
38+
level: "error",
39+
error: err,
40+
});
41+
});

src/server/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import { withErrorHandler } from "./middleware/error";
1515
import { withExpress } from "./middleware/express";
1616
import { withRequestLogs } from "./middleware/logs";
1717
import { withOpenApi } from "./middleware/open-api";
18+
import { withRateLimit } from "./middleware/rateLimit";
1819
import { withWebSocket } from "./middleware/websocket";
1920
import { withRoutes } from "./routes";
2021
import { writeOpenApiToFile } from "./utils/openapi";
@@ -62,6 +63,7 @@ export const initServer = async () => {
6263
await withRequestLogs(server);
6364
await withErrorHandler(server);
6465
await withEnforceEngineMode(server);
66+
await withRateLimit(server);
6567
await withWebSocket(server);
6668
await withAuth(server);
6769
await withExpress(server);

src/server/middleware/rateLimit.ts

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import { FastifyInstance } from "fastify";
2+
import { StatusCodes } from "http-status-codes";
3+
import { env } from "../../utils/env";
4+
import { redis } from "../../utils/redis/redis";
5+
import { createCustomError } from "./error";
6+
7+
export const withRateLimit = async (server: FastifyInstance) => {
8+
server.addHook("onRequest", async (request, reply) => {
9+
if (request.url === "/" || request.url === "/json") {
10+
return;
11+
}
12+
13+
const epochTimeInMinutes = Math.floor(new Date().getTime() / (1000 * 60));
14+
const key = `rate-limit:global:${epochTimeInMinutes}`;
15+
const count = await redis.incr(key);
16+
redis.expire(key, 2 * 60);
17+
18+
if (count > env.GLOBAL_RATE_LIMIT_PER_MIN) {
19+
throw createCustomError(
20+
`Too many requests. Please reduce your calls to ${env.GLOBAL_RATE_LIMIT_PER_MIN} requests/minute or update the "GLOBAL_RATE_LIMIT_PER_MIN" env var.`,
21+
StatusCodes.TOO_MANY_REQUESTS,
22+
"TOO_MANY_REQUESTS",
23+
);
24+
}
25+
});
26+
};

src/utils/env.ts

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,10 @@ export const env = createEnv({
8181
REDIS_URL: z.string(),
8282
SEND_TRANSACTION_QUEUE_CONCURRENCY: z.coerce.number().default(1500),
8383
CONFIRM_TRANSACTION_QUEUE_CONCURRENCY: z.coerce.number().default(1500),
84-
ENGINE_MODE: z.enum(["sandbox", "unrestricted"]).default("unrestricted"),
84+
ENGINE_MODE: z
85+
.enum(["default", "sandbox", "server_only", "worker_only"])
86+
.default("default"),
87+
GLOBAL_RATE_LIMIT_PER_MIN: z.coerce.number().default(400 * 60),
8588
},
8689
clientPrefix: "NEVER_USED",
8790
client: {},
@@ -112,6 +115,7 @@ export const env = createEnv({
112115
CONFIRM_TRANSACTION_QUEUE_CONCURRENCY:
113116
process.env.CONFIRM_TRANSACTION_QUEUE_CONCURRENCY,
114117
ENGINE_MODE: process.env.ENGINE_MODE,
118+
GLOBAL_RATE_LIMIT_PER_MIN: process.env.GLOBAL_RATE_LIMIT_PER_MIN,
115119
},
116120
onValidationError: (error: ZodError) => {
117121
console.error(

src/worker/tasks/processEventLogsWorker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,12 @@ import { logWorkerExceptions } from "../queues/queues";
3030
import { enqueueWebhook } from "../queues/sendWebhookQueue";
3131

3232
const handler: Processor<any, void, string> = async (job: Job<string>) => {
33-
const { chainId, filters, fromBlock, toBlock } =
34-
superjson.parse<EnqueueProcessEventLogsData>(job.data);
33+
const {
34+
chainId,
35+
filters = [],
36+
fromBlock,
37+
toBlock,
38+
} = superjson.parse<EnqueueProcessEventLogsData>(job.data);
3539

3640
const logs = await getLogs({
3741
chainId,

src/worker/tasks/processTransactionReceiptsWorker.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,12 @@ import { getContractId } from "../utils/contractId";
2828
import { getWebhooksByContractAddresses } from "./processEventLogsWorker";
2929

3030
const handler: Processor<any, void, string> = async (job: Job<string>) => {
31-
const { chainId, filters, fromBlock, toBlock } =
32-
superjson.parse<EnqueueProcessTransactionReceiptsData>(job.data);
31+
const {
32+
chainId,
33+
filters = [],
34+
fromBlock,
35+
toBlock,
36+
} = superjson.parse<EnqueueProcessTransactionReceiptsData>(job.data);
3337

3438
const receipts = await getFormattedTransactionReceipts({
3539
chainId,

yarn.lock

Lines changed: 61 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -642,18 +642,35 @@
642642
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.1.tgz#4ffb0055f7ef676ebc3a5a91fb621393294e2f43"
643643
integrity sha512-gJB6HLm5rYwSLI6PQa+X1t5CFGrv1J1TWG+sOyMCeKz2ojaj6Fnl/rZEspogG+cvqbt4AE/2eIyD2QfLKTBNlQ==
644644

645-
"@emotion/is-prop-valid@^1.2.1", "@emotion/is-prop-valid@^1.2.2":
645+
"@emotion/hash@^0.9.2":
646+
version "0.9.2"
647+
resolved "https://registry.yarnpkg.com/@emotion/hash/-/hash-0.9.2.tgz#ff9221b9f58b4dfe61e619a7788734bd63f6898b"
648+
integrity sha512-MyqliTZGuOm3+5ZRSaaBGP3USLw6+EGykkwZns2EPC5g8jJ4z9OrdZY9apkl3+UP9+sdz76YYkwCKP5gh8iY3g==
649+
650+
"@emotion/is-prop-valid@^1.2.1":
646651
version "1.2.2"
647652
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.2.2.tgz#d4175076679c6a26faa92b03bb786f9e52612337"
648653
integrity sha512-uNsoYd37AFmaCdXlg6EYD1KaPOaRWRByMCYzbKUX4+hhMfrxdVSelShywL4JVaAeM/eHUOSprYBQls+/neX3pw==
649654
dependencies:
650655
"@emotion/memoize" "^0.8.1"
651656

657+
"@emotion/is-prop-valid@^1.2.2":
658+
version "1.3.0"
659+
resolved "https://registry.yarnpkg.com/@emotion/is-prop-valid/-/is-prop-valid-1.3.0.tgz#bd84ba972195e8a2d42462387581560ef780e4e2"
660+
integrity sha512-SHetuSLvJDzuNbOdtPVbq6yMMMlLoW5Q94uDqJZqy50gcmAjxFkVqmzqSGEFq9gT2iMuIeKV1PXVWmvUhuZLlQ==
661+
dependencies:
662+
"@emotion/memoize" "^0.9.0"
663+
652664
"@emotion/memoize@^0.8.1":
653665
version "0.8.1"
654666
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.8.1.tgz#c1ddb040429c6d21d38cc945fe75c818cfb68e17"
655667
integrity sha512-W2P2c/VRW1/1tLox0mVUalvnWXxavmv/Oum2aPsRcoDJuob75FC3Y8FbpfLwUegRcxINtGUMPq0tFCvYNTBXNA==
656668

669+
"@emotion/memoize@^0.9.0":
670+
version "0.9.0"
671+
resolved "https://registry.yarnpkg.com/@emotion/memoize/-/memoize-0.9.0.tgz#745969d649977776b43fc7648c556aaa462b4102"
672+
integrity sha512-30FAj7/EoJ5mwVPOWhAyCX+FPfMDrVecJAM+Iw9NRoSl4BBAQeqj4cApHHUXOVvIPgLVDsCFoz/hGD+5QQD1GQ==
673+
657674
"@emotion/react@11.11.4":
658675
version "11.11.4"
659676
resolved "https://registry.yarnpkg.com/@emotion/react/-/react-11.11.4.tgz#3a829cac25c1f00e126408fab7f891f00ecc3c1d"
@@ -668,7 +685,7 @@
668685
"@emotion/weak-memoize" "^0.3.1"
669686
hoist-non-react-statics "^3.3.1"
670687

671-
"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3", "@emotion/serialize@^1.1.4":
688+
"@emotion/serialize@^1.1.2", "@emotion/serialize@^1.1.3":
672689
version "1.1.4"
673690
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.1.4.tgz#fc8f6d80c492cfa08801d544a05331d1cc7cd451"
674691
integrity sha512-RIN04MBT8g+FnDwgvIUi8czvr1LU1alUMI05LekWB5DGyTm8cCBMCRpq3GqaiyEDRptEXOyXnvZ58GZYu4kBxQ==
@@ -679,6 +696,17 @@
679696
"@emotion/utils" "^1.2.1"
680697
csstype "^3.0.2"
681698

699+
"@emotion/serialize@^1.1.4":
700+
version "1.3.0"
701+
resolved "https://registry.yarnpkg.com/@emotion/serialize/-/serialize-1.3.0.tgz#e07cadfc967a4e7816e0c3ffaff4c6ce05cb598d"
702+
integrity sha512-jACuBa9SlYajnpIVXB+XOXnfJHyckDfe6fOpORIM6yhBDlqGuExvDdZYHDQGoDf3bZXGv7tNr+LpLjJqiEQ6EA==
703+
dependencies:
704+
"@emotion/hash" "^0.9.2"
705+
"@emotion/memoize" "^0.9.0"
706+
"@emotion/unitless" "^0.9.0"
707+
"@emotion/utils" "^1.4.0"
708+
csstype "^3.0.2"
709+
682710
"@emotion/sheet@^1.2.2":
683711
version "1.2.2"
684712
resolved "https://registry.yarnpkg.com/@emotion/sheet/-/sheet-1.2.2.tgz#d58e788ee27267a14342303e1abb3d508b6d0fec"
@@ -713,6 +741,11 @@
713741
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.8.1.tgz#182b5a4704ef8ad91bde93f7a860a88fd92c79a3"
714742
integrity sha512-KOEGMu6dmJZtpadb476IsZBclKvILjopjUii3V+7MnXIQCYh8W3NgNcgwo21n9LXZX6EDIKvqfjYxXebDwxKmQ==
715743

744+
"@emotion/unitless@^0.9.0":
745+
version "0.9.0"
746+
resolved "https://registry.yarnpkg.com/@emotion/unitless/-/unitless-0.9.0.tgz#8e5548f072bd67b8271877e51c0f95c76a66cbe2"
747+
integrity sha512-TP6GgNZtmtFaFcsOgExdnfxLLpRDla4Q66tnenA9CktvVSdNKDvMVuUah4QvWPIpNjrWsGg3qeGo9a43QooGZQ==
748+
716749
"@emotion/use-insertion-effect-with-fallbacks@^1.0.1":
717750
version "1.0.1"
718751
resolved "https://registry.yarnpkg.com/@emotion/use-insertion-effect-with-fallbacks/-/use-insertion-effect-with-fallbacks-1.0.1.tgz#08de79f54eb3406f9daaf77c76e35313da963963"
@@ -723,6 +756,11 @@
723756
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.2.1.tgz#bbab58465738d31ae4cb3dbb6fc00a5991f755e4"
724757
integrity sha512-Y2tGf3I+XVnajdItskUCn6LX+VUDmP6lTL4fcqsXAv43dnlbZiuW4MWQW38rW/BVWSE7Q/7+XQocmpnRYILUmg==
725758

759+
"@emotion/utils@^1.4.0":
760+
version "1.4.0"
761+
resolved "https://registry.yarnpkg.com/@emotion/utils/-/utils-1.4.0.tgz#262f1d02aaedb2ec91c83a0955dd47822ad5fbdd"
762+
integrity sha512-spEnrA1b6hDR/C68lC2M7m6ALPUHZC0lIY7jAS/B/9DuuO1ZP04eov8SMv/6fwRd8pzmsn2AuJEznRREWlQrlQ==
763+
726764
"@emotion/weak-memoize@^0.3.1":
727765
version "0.3.1"
728766
resolved "https://registry.yarnpkg.com/@emotion/weak-memoize/-/weak-memoize-0.3.1.tgz#d0fce5d07b0620caa282b5131c297bb60f9d87e6"
@@ -4276,10 +4314,10 @@
42764314
lodash.isequal "4.5.0"
42774315
uint8arrays "3.1.0"
42784316

4279-
"@walletconnect/core@2.13.3":
4280-
version "2.13.3"
4281-
resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.13.3.tgz#d98fccefe36c6b365812fd0f7237a0f9634bafb6"
4282-
integrity sha512-TdF+rC6rONJGyOUtt/nLkbyQWjnkwbD3kXq3ZA0Q7+tYtmSjTDE4wbArlLbHIbtf69g+9/DpEVEQimWWcEOn2g==
4317+
"@walletconnect/core@2.14.0":
4318+
version "2.14.0"
4319+
resolved "https://registry.yarnpkg.com/@walletconnect/core/-/core-2.14.0.tgz#e8afb01455968b02aaf26c74f3bfcc9b82678a39"
4320+
integrity sha512-E/dgBM9q3judXnTfZQ5ILvDpeSdDpabBLsXtYXa3Nyc26cfNplfLJ2nXm9FgtTdhM1nZ7yx4+zDPiXawBRZl2g==
42834321
dependencies:
42844322
"@walletconnect/heartbeat" "1.2.2"
42854323
"@walletconnect/jsonrpc-provider" "1.0.14"
@@ -4292,8 +4330,8 @@
42924330
"@walletconnect/relay-auth" "1.0.4"
42934331
"@walletconnect/safe-json" "1.0.2"
42944332
"@walletconnect/time" "1.0.2"
4295-
"@walletconnect/types" "2.13.3"
4296-
"@walletconnect/utils" "2.13.3"
4333+
"@walletconnect/types" "2.14.0"
4334+
"@walletconnect/utils" "2.14.0"
42974335
events "3.3.0"
42984336
isomorphic-unfetch "3.1.0"
42994337
lodash.isequal "4.5.0"
@@ -4510,18 +4548,18 @@
45104548
events "3.3.0"
45114549

45124550
"@walletconnect/sign-client@^2.13.3":
4513-
version "2.13.3"
4514-
resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.13.3.tgz#9f8c826000bf3d6ea782f7325bc87e9f260e71ce"
4515-
integrity sha512-3Pcq6trHWdBZn5X0VUFQ3zJaaqyEbMW9WNVKcZ2SakIpQAwySd08Mztvq48G98jfucdgP3tjGPbBvzHX9vJX7w==
4551+
version "2.14.0"
4552+
resolved "https://registry.yarnpkg.com/@walletconnect/sign-client/-/sign-client-2.14.0.tgz#36533ef0976a869d815624217527482c90937fc8"
4553+
integrity sha512-UrB3S3eLjPYfBLCN3WJ5u7+WcZ8kFMe/QIDqLf76Jk6TaLwkSUy563LvnSw4KW/kA+/cY1KBSdUDfX1tzYJJXg==
45164554
dependencies:
4517-
"@walletconnect/core" "2.13.3"
4555+
"@walletconnect/core" "2.14.0"
45184556
"@walletconnect/events" "1.0.1"
45194557
"@walletconnect/heartbeat" "1.2.2"
45204558
"@walletconnect/jsonrpc-utils" "1.0.8"
45214559
"@walletconnect/logger" "2.1.2"
45224560
"@walletconnect/time" "1.0.2"
4523-
"@walletconnect/types" "2.13.3"
4524-
"@walletconnect/utils" "2.13.3"
4561+
"@walletconnect/types" "2.14.0"
4562+
"@walletconnect/utils" "2.14.0"
45254563
events "3.3.0"
45264564

45274565
"@walletconnect/time@1.0.2", "@walletconnect/time@^1.0.2":
@@ -4555,10 +4593,10 @@
45554593
"@walletconnect/logger" "2.1.2"
45564594
events "3.3.0"
45574595

4558-
"@walletconnect/types@2.13.3":
4559-
version "2.13.3"
4560-
resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.13.3.tgz#0280b5c64df9a2e07752c4121eeb81dc4a59b2c2"
4561-
integrity sha512-9UdtLoQqwGFfepCPprUAXeUbKg9zyDarPRmEJVco51OWXHCOpvRgroWk54fQHDhCUIfDELjObY6XNAzNrmNYUA==
4596+
"@walletconnect/types@2.14.0":
4597+
version "2.14.0"
4598+
resolved "https://registry.yarnpkg.com/@walletconnect/types/-/types-2.14.0.tgz#af3d4799b8ac5d166251af12bc024276f82f9b91"
4599+
integrity sha512-vevMi4jZLJ55vLuFOicQFmBBbLyb+S0sZS4IsaBdZkQflfGIq34HkN13c/KPl4Ye0aoR4/cUcUSitmGIzEQM5g==
45624600
dependencies:
45634601
"@walletconnect/events" "1.0.1"
45644602
"@walletconnect/heartbeat" "1.2.2"
@@ -4622,10 +4660,10 @@
46224660
query-string "7.1.3"
46234661
uint8arrays "3.1.0"
46244662

4625-
"@walletconnect/utils@2.13.3":
4626-
version "2.13.3"
4627-
resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.13.3.tgz#500d88342c193ce92ab9d2fae3bd343be71821b2"
4628-
integrity sha512-hjyyNhnhTCezGNr6OCfKRzqRsiak+p+YP57iRo1Tsf222fsj/9JD++MP97YiDwc4e4xXaZp/boiLB+8hJHsCog==
4663+
"@walletconnect/utils@2.14.0":
4664+
version "2.14.0"
4665+
resolved "https://registry.yarnpkg.com/@walletconnect/utils/-/utils-2.14.0.tgz#48493ffe1e902815fda3cbd5cc5409288a066d35"
4666+
integrity sha512-vRVomYQEtEAyCK2c5bzzEvtgxaGGITF8mWuIL+WYSAMyEJLY97mirP2urDucNwcUczwxUgI+no9RiNFbUHreQQ==
46294667
dependencies:
46304668
"@stablelib/chacha20poly1305" "1.0.1"
46314669
"@stablelib/hkdf" "1.0.1"
@@ -4635,7 +4673,7 @@
46354673
"@walletconnect/relay-api" "1.0.10"
46364674
"@walletconnect/safe-json" "1.0.2"
46374675
"@walletconnect/time" "1.0.2"
4638-
"@walletconnect/types" "2.13.3"
4676+
"@walletconnect/types" "2.14.0"
46394677
"@walletconnect/window-getters" "1.0.1"
46404678
"@walletconnect/window-metadata" "1.0.1"
46414679
detect-browser "5.3.0"

0 commit comments

Comments
 (0)