Skip to content

Commit

Permalink
feat(relayer): add deploy scripts
Browse files Browse the repository at this point in the history
- [x] Update imports for using esm
- [x] Add docker support
- [x] Add health check endpoint
  • Loading branch information
0xmad committed Feb 7, 2025
1 parent 2d4c13a commit 1de4c4f
Show file tree
Hide file tree
Showing 44 changed files with 283 additions and 140 deletions.
6 changes: 6 additions & 0 deletions .dockerignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
node_modules
build
coverage
.git
zkeys

32 changes: 32 additions & 0 deletions apps/relayer/Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Copy source code and build the project
FROM node:20-alpine AS builder

WORKDIR /builder

COPY . .

RUN npm i -g pnpm@9
RUN pnpm install
RUN pnpm run build

# Create image by copying build artifacts
FROM node:20-alpine AS runner
RUN npm i -g pnpm@9

RUN mkdir -p ~/rapidsnark/build; \
wget -qO ~/rapidsnark/build/prover https://maci-devops-zkeys.s3.ap-northeast-2.amazonaws.com/rapidsnark-linux-amd64-1c137; \
chmod +x ~/rapidsnark/build/prover
RUN wget -qO ~/circom https://github.com/iden3/circom/releases/download/v2.1.6/circom-linux-amd64; \
chmod +x ~/circom; \
mv ~/circom /bin

USER node
ARG PORT=3000

WORKDIR /maci
COPY --chown=node:node --from=builder /builder/ ./
RUN pnpm run download-zkeys:test:relayer
WORKDIR /maci/apps/relayer

EXPOSE ${PORT}
CMD ["sh", "-c", "pnpm run hardhat & node build/ts/main.js"]
46 changes: 46 additions & 0 deletions apps/relayer/docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
version: "3.8"

services:
service:
build:
context: ../..
dockerfile: apps/relayer/Dockerfile
volumes:
- .:/app
ports:
- "3000:3000"
environment:
- RELAYER_RPC_URL=${RELAYER_RPC_URL}
- TTL=${TTL}
- LIMIT=${LIMIT}
- ALLOWED_ORIGINS=${ALLOWED_ORIGINS}
- MAX_MESSAGES=${MAX_MESSAGES}
- MONGO_DB_URI=mongodb://mongodb:27017
- MONGODB_USER=${MONGODB_USER}
- MONGODB_PASSWORD=${MONGODB_PASSWORD}
- MONGODB_DATABASE=${MONGODB_DATABASE}
- MNEMONIC=${MNEMONIC}
depends_on:
- mongodb
networks:
- mongo-net

mongodb:
image: mongo:latest
container_name: mongodb
environment:
- MONGO_INITDB_ROOT_USERNAME=${MONGODB_USER}
- MONGO_INITDB_ROOT_PASSWORD=${MONGODB_PASSWORD}
- MONGO_INITDB_DATABASE=${MONGODB_DATABASE}
volumes:
- mongodb-data:/data/db
networks:
- mongo-net

networks:
mongo-net:
driver: bridge

volumes:
mongodb-data:
driver: local
10 changes: 5 additions & 5 deletions apps/relayer/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
"hardhat": "hardhat node",
"build": "nest build",
"run:node": "node --import 'data:text/javascript,import { register } from \"node:module\"; import { pathToFileURL } from \"node:url\"; register(\"ts-node/esm\", pathToFileURL(\"./\"));'",
"start": "pnpm run run:node ./ts/main.ts",
"start": "nest start",
"start:prod": "pnpm run run:node build/ts/main.js",
"test": "NODE_OPTIONS=--experimental-vm-modules jest --forceExit",
"test:coverage": "pnpm run test --coverage",
Expand Down Expand Up @@ -45,10 +45,10 @@
"helia": "^5.2.0",
"helmet": "^8.0.0",
"lodash": "^4.17.21",
"maci-cli": "workspace:^2.5.0",
"maci-sdk": "workspace:^0.0.1",
"maci-domainobjs": "workspace:^2.5.0",
"maci-contracts": "workspace:^2.5.0",
"maci-cli": "^2.5.0",
"maci-sdk": "^0.0.1",
"maci-domainobjs": "^2.5.0",
"maci-contracts": "^2.5.0",
"mongoose": "^8.9.7",
"multiformats": "^13.3.1",
"mustache": "^4.2.0",
Expand Down
15 changes: 8 additions & 7 deletions apps/relayer/tests/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@ import { HttpStatus, ValidationPipe, type INestApplication } from "@nestjs/commo
import { Test } from "@nestjs/testing";
import request from "supertest";

import type { App } from "supertest/types";
import type { TApp } from "./constants.js";

import { AppModule } from "../ts/app.module";
import { AppModule } from "../ts/app.module.js";

describe("Integration", () => {
let app: INestApplication;
let app: INestApplication<TApp>;

beforeAll(async () => {
const moduleFixture = await Test.createTestingModule({
Expand All @@ -24,15 +24,16 @@ describe("Integration", () => {
});

test("should throw an error if api is not found", async () => {
const result = await request(app.getHttpServer() as App)
.get("/unknown")
.send()
.expect(404);
const result = await request(app.getHttpServer()).get("/unknown").send().expect(404);

expect(result.body).toStrictEqual({
error: "Not Found",
statusCode: HttpStatus.NOT_FOUND,
message: "Cannot GET /unknown",
});
});

test("should check health properly", async () => {
await request(app.getHttpServer()).get("/v1/health/check").send().expect(200);
});
});
4 changes: 4 additions & 0 deletions apps/relayer/tests/constants.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ import { homedir } from "os";
import path from "path";
import url from "url";

import type request from "supertest";

export const STATE_TREE_DEPTH = 10;
export const INT_STATE_TREE_DEPTH = 1;
export const VOTE_OPTION_TREE_DEPTH = 2;
Expand Down Expand Up @@ -36,3 +38,5 @@ export const tallyVotesZkeyPathNonQv = path.resolve(
dirname,
"../zkeys/TallyVotesNonQv_10-1-2_test/TallyVotesNonQv_10-1-2_test.0.zkey",
);

export type TApp = Parameters<typeof request>[0];
2 changes: 1 addition & 1 deletion apps/relayer/tests/deploy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import {
pollWasm,
pollWitgen,
rapidsnark,
} from "./constants";
} from "./constants.js";

interface IContractsData {
initialized: boolean;
Expand Down
18 changes: 8 additions & 10 deletions apps/relayer/tests/messageBatches.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ import { Keypair } from "maci-domainobjs";
import { formatProofForVerifierContract, genProofSnarkjs } from "maci-sdk";
import request from "supertest";

import type { App } from "supertest/types";
import { AppModule } from "../ts/app.module.js";

import { AppModule } from "../ts/app.module";
import { pollJoinedWasm, pollJoinedZkey, type TApp } from "./constants.js";

import { pollJoinedWasm, pollJoinedZkey } from "./constants";

jest.unmock("maci-contracts/typechain-types");
jest.unmock("maci-sdk");

describe("Integration message batches", () => {
let app: INestApplication;
let app: INestApplication<TApp>;
let stateLeafIndex: number;
let maciContractAddress: string;
let user: Keypair;

beforeAll(async () => {
const { TestDeploy } = await import("./deploy");
const { TestDeploy } = await import("./deploy.js");
await TestDeploy.sleep(1_000);
const testDeploy = await TestDeploy.getInstance();
const poll = testDeploy.contractsData.maciState!.polls.get(0n);
Expand Down Expand Up @@ -54,7 +52,7 @@ describe("Integration message batches", () => {

const keypair = new Keypair();

await request(app.getHttpServer() as App)
await request(app.getHttpServer())
.post("/v1/messages/publish")
.send({
messages: [
Expand All @@ -77,7 +75,7 @@ describe("Integration message batches", () => {

describe("/v1/messageBatches/get", () => {
test("should throw an error if dto is invalid", async () => {
const result = await request(app.getHttpServer() as App)
const result = await request(app.getHttpServer())
.get("/v1/messageBatches/get")
.send({
limit: 0,
Expand All @@ -104,7 +102,7 @@ describe("Integration message batches", () => {
});

test("should get message batches properly", async () => {
const result = await request(app.getHttpServer() as App)
const result = await request(app.getHttpServer())
.get("/v1/messageBatches/get")
.send({
limit: 10,
Expand Down
20 changes: 9 additions & 11 deletions apps/relayer/tests/messages.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,22 +5,20 @@ import { Keypair } from "maci-domainobjs";
import { formatProofForVerifierContract, genProofSnarkjs } from "maci-sdk";
import request from "supertest";

import type { App } from "supertest/types";
import { AppModule } from "../ts/app.module.js";

import { AppModule } from "../ts/app.module";
import { pollJoinedWasm, pollJoinedZkey, type TApp } from "./constants.js";

import { pollJoinedWasm, pollJoinedZkey } from "./constants";

jest.unmock("maci-contracts/typechain-types");
jest.unmock("maci-sdk");

describe("Integration messages", () => {
let app: INestApplication;
let app: INestApplication<TApp>;
let circuitInputs: Record<string, string>;
let stateLeafIndex: number;
let maciContractAddress: string;

beforeAll(async () => {
const { TestDeploy } = await import("./deploy");
const { TestDeploy } = await import("./deploy.js");
await TestDeploy.sleep(10_000);
const testDeploy = await TestDeploy.getInstance();
const poll = testDeploy.contractsData.maciState!.polls.get(0n);
Expand Down Expand Up @@ -67,7 +65,7 @@ describe("Integration messages", () => {
};

test("should throw an error if there is no valid proof", async () => {
const result = await request(app.getHttpServer() as App)
const result = await request(app.getHttpServer())
.post("/v1/messages/publish")
.send({
...defaultSaveMessagesArgs,
Expand All @@ -92,7 +90,7 @@ describe("Integration messages", () => {
wasmPath: pollJoinedWasm,
});

const result = await request(app.getHttpServer() as App)
const result = await request(app.getHttpServer())
.post("/v1/messages/publish")
.send({
stateLeafIndex,
Expand Down Expand Up @@ -122,7 +120,7 @@ describe("Integration messages", () => {
wasmPath: pollJoinedWasm,
});

const result = await request(app.getHttpServer() as App)
const result = await request(app.getHttpServer())
.post("/v1/messages/publish")
.send({
...defaultSaveMessagesArgs,
Expand All @@ -147,7 +145,7 @@ describe("Integration messages", () => {
wasmPath: pollJoinedWasm,
});

const result = await request(app.getHttpServer() as App)
const result = await request(app.getHttpServer())
.post("/v1/messages/publish")
.send({
...defaultSaveMessagesArgs,
Expand Down
10 changes: 6 additions & 4 deletions apps/relayer/ts/app.module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ import { MongooseModule } from "@nestjs/mongoose";
import { ScheduleModule } from "@nestjs/schedule";
import { ThrottlerModule } from "@nestjs/throttler";

import { IpfsModule } from "./ipfs/ipfs.module";
import { MessageModule } from "./message/message.module";
import { MessageBatchModule } from "./messageBatch/messageBatch.module";
import { HealthModule } from "./health/health.module.js";
import { IpfsModule } from "./ipfs/ipfs.module.js";
import { MessageModule } from "./message/message.module.js";
import { MessageBatchModule } from "./messageBatch/messageBatch.module.js";

@Module({
imports: [
Expand All @@ -19,7 +20,7 @@ import { MessageBatchModule } from "./messageBatch/messageBatch.module";
MongooseModule.forRootAsync({
useFactory: async () => {
if (process.env.NODE_ENV === "test") {
const { getTestMongooseModuleOptions } = await import("./jest/mongo");
const { getTestMongooseModuleOptions } = await import("./jest/mongo.js");

return getTestMongooseModuleOptions();
}
Expand All @@ -37,6 +38,7 @@ import { MessageBatchModule } from "./messageBatch/messageBatch.module";
IpfsModule,
MessageModule,
MessageBatchModule,
HealthModule,
],
})
export class AppModule {}
28 changes: 28 additions & 0 deletions apps/relayer/ts/health/__tests__/health.controller.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { jest } from "@jest/globals";
import { Test } from "@nestjs/testing";

import { HealthController } from "../health.controller.js";

describe("HealthController", () => {
let controller: HealthController;

beforeEach(async () => {
const app = await Test.createTestingModule({
controllers: [HealthController],
}).compile();

controller = app.get<HealthController>(HealthController);
});

afterEach(() => {
jest.clearAllMocks();
});

describe("v1/health/check", () => {
test("should check properly", () => {
const isRunning = controller.check();

expect(isRunning).toBe(true);
});
});
});
19 changes: 19 additions & 0 deletions apps/relayer/ts/health/health.controller.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/* eslint-disable @typescript-eslint/no-shadow */
import { Controller, Get, HttpStatus } from "@nestjs/common";
import { ApiResponse, ApiTags } from "@nestjs/swagger";

@ApiTags("v1/health")
@Controller("v1/health")
export class HealthController {
/**
* Health check api method.
*
* @param args fetch arguments
* @returns message batches
*/
@ApiResponse({ status: HttpStatus.OK, description: "The service is running" })
@Get("check")
check(): boolean {
return true;
}
}
8 changes: 8 additions & 0 deletions apps/relayer/ts/health/health.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
import { Module } from "@nestjs/common";

import { HealthController } from "./health.controller.js";

@Module({
controllers: [HealthController],
})
export class HealthModule {}
2 changes: 1 addition & 1 deletion apps/relayer/ts/ipfs/__tests__/ipfs.service.test.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IpfsService } from "../ipfs.service";
import { IpfsService } from "../ipfs.service.js";

describe("IpfsService", () => {
const defaultData = { hello: "world" };
Expand Down
2 changes: 1 addition & 1 deletion apps/relayer/ts/ipfs/ipfs.module.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { Module } from "@nestjs/common";

import { IpfsService } from "./ipfs.service";
import { IpfsService } from "./ipfs.service.js";

@Module({
exports: [IpfsService],
Expand Down
Loading

0 comments on commit 1de4c4f

Please sign in to comment.