Skip to content

Commit

Permalink
feat(coordinator): deploy subgraph from coordinator service
Browse files Browse the repository at this point in the history
- [x] Add subgraph controller
- [x] Add subgraph deploy service
- [x] Remove app controller and use proof controller
- [x] Add env variables
  • Loading branch information
0xmad authored and ctrlc03 committed Jul 15, 2024
1 parent 45ed819 commit d04d82c
Show file tree
Hide file tree
Showing 27 changed files with 613 additions and 278 deletions.
4 changes: 4 additions & 0 deletions .github/workflows/coordinator-build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,10 @@ env:
COORDINATOR_MESSAGE_PROCESS_ZKEY_NAME: "ProcessMessages_10-2-1-2_test"
COORDINATOR_ZKEY_PATH: "./zkeys/"
COORDINATOR_RAPIDSNARK_EXE: "~/rapidsnark/build/prover"
SUBGRAPH_FOLDER: "../subgraph"
SUBGRAPH_NAME: ${{ vars.SUBGRAPH_NAME }}
SUBGRAPH_PROVIDER_URL: ${{ vars.SUBGRAPH_PROVIDER_URL }}
SUBGRAPH_DEPLOY_KEY: ${{ secrets.SUBGRAPH_DEPLOY_KEY }}

concurrency:
group: ${{ github.workflow }}-${{ github.head_ref || github.run_id }}
Expand Down
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@ circuit.json
input.json
*.proof.json
*.publicSignals.json
subgraph/config/*.json
!subgraph/config/network.json

.vscode/

Expand Down
2 changes: 1 addition & 1 deletion circuits/circom/utils/processMessagesInputHasher.circom
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ template ProcessMessagesInputHasher() {
// 2. Hash coordPubKey.
var computedPubKey = PoseidonHasher(2)(coordPubKey);

// 3. Hash the 6 inputs with SHA256.
// 3. Hash the 7 inputs with SHA256.
hash <== Sha256Hasher(7)([
packedVals,
computedPubKey,
Expand Down
14 changes: 14 additions & 0 deletions coordinator/.env.example
Original file line number Diff line number Diff line change
Expand Up @@ -32,3 +32,17 @@ COORDINATOR_ALLOWED_ORIGINS=

# Specify port for coordinator service (optional)
COORDINATOR_PORT=

# Subgraph name
SUBGRAPH_NAME="maci-subgraph"

# Subgraph provider url
SUBGRAPH_PROVIDER_URL=https://api.studio.thegraph.com/deploy/

# Subgraph deploy key
SUBGRAPH_DEPLOY_KEY=

# Subgraph project folder
SUBGRAPH_FOLDER=../subgraph


30 changes: 30 additions & 0 deletions coordinator/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,33 @@
Make sure you set `COORDINATOR_ADDRESSES` env variable and sign any message with the addresses from your application (see [AccountSignatureGuard](./ts/auth/AccountSignatureGuard.service.ts)).
7. Proofs can be generated with `POST v1/proof/generate` API method or with Websockets (see [dto spec](./ts/proof/dto.ts), [controller](./ts/app.controller.ts) and [wsgateway](./ts/events/events.gateway.ts)).
8. [Swagger documentation for API methods](https://maci-coordinator.pse.dev/api)

## Subgraph deployment

It is possible to deploy subgraph using coordinator service.

First, you need to setup subgraph and create a project. [Subgraph dashboard](https://thegraph.com/studio/).

Then, set env variables:

```
# Subgraph name
SUBGRAPH_NAME="maci-subgraph"
# Subgraph provider url
SUBGRAPH_PROVIDER_URL=https://api.studio.thegraph.com/deploy/
# Subgraph deploy key
SUBGRAPH_DEPLOY_KEY=*******
# Subgraph project folder
SUBGRAPH_FOLDER=../subgraph
```

After deployment, subgraph url will be available in studio dashboard and you can use this type of url to get latest deployed version in your application:

```
https://api.studio.thegraph.com/.../{SUBGRAPH_NAME}/version/latest
```

API method Details are available [here](https://maci-coordinator.pse.dev/api)
2 changes: 2 additions & 0 deletions coordinator/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"generate-keypair": "ts-node ./scripts/generateKeypair.ts"
},
"dependencies": {
"@graphprotocol/graph-cli": "^0.76.0",
"@nestjs/common": "^10.3.8",
"@nestjs/core": "^10.3.9",
"@nestjs/platform-express": "^10.3.8",
Expand All @@ -40,6 +41,7 @@
"maci-cli": "2.0.0-alpha",
"maci-contracts": "2.0.0-alpha",
"maci-domainobjs": "2.0.0-alpha",
"mustache": "^4.2.0",
"reflect-metadata": "^0.2.0",
"rxjs": "^7.8.1",
"socket.io": "^4.7.5",
Expand Down
2 changes: 1 addition & 1 deletion coordinator/tests/app.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ const MSG_TREE_DEPTH = 2;
const VOTE_OPTION_TREE_DEPTH = 2;
const MSG_BATCH_DEPTH = 1;

describe("AppController (e2e)", () => {
describe("e2e", () => {
const coordinatorKeypair = new Keypair();
let app: INestApplication;
let signer: Signer;
Expand Down
8 changes: 4 additions & 4 deletions coordinator/ts/app.module.ts
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import { Module } from "@nestjs/common";
import { ThrottlerModule } from "@nestjs/throttler";

import { AppController } from "./app.controller";
import { CryptoModule } from "./crypto/crypto.module";
import { EventsModule } from "./events/events.module";
import { FileModule } from "./file/file.module";
import { ProofGeneratorService } from "./proof/proof.service";
import { ProofModule } from "./proof/proof.module";
import { SubgraphModule } from "./subgraph/subgraph.module";

@Module({
imports: [
Expand All @@ -18,8 +18,8 @@ import { ProofGeneratorService } from "./proof/proof.service";
FileModule,
CryptoModule,
EventsModule,
SubgraphModule,
ProofModule,
],
controllers: [AppController],
providers: [ProofGeneratorService],
})
export class AppModule {}
1 change: 1 addition & 0 deletions coordinator/ts/common/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,5 @@ export enum ErrorCodes {
DECRYPTION = "4",
ENCRYPTION = "5",
FILE_NOT_FOUND = "6",
SUBGRAPH_DEPLOY = "7",
}
1 change: 1 addition & 0 deletions coordinator/ts/common/index.ts
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { ErrorCodes } from "./errors";
export { ESupportedNetworks } from "./networks";
64 changes: 64 additions & 0 deletions coordinator/ts/common/networks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
export enum ESupportedNetworks {
ETHEREUM = "mainnet",
OPTIMISM = "optimism",
OPTIMISM_SEPOLIA = "optimism-sepolia",
BSC = "bsc",
BSC_CHAPEL = "chapel",
GNOSIS_CHAIN = "gnosis",
FUSE = "fuse",
POLYGON = "matic",
FANTOM_OPERA = "fantom",
ZKSYNC_ERA_TESTNET = "zksync-era-testnet",
BOBA = "boba",
MOONBEAM = "moonbeam",
MOONRIVER = "moonriver",
MOONBASE_ALPHA = "mbase",
FANTOM_TESTNET = "fantom-testnet",
ARBITRUM_ONE = "arbitrum-one",
CELO = "celo",
AVALANCHE_FUJI = "fuji",
AVALANCHE = "avalanche",
CELO_ALFAJORES = "celo-alfajores",
HOLESKY = "holesky",
AURORA = "aurora",
AURORA_TESTNET = "aurora-testnet",
HARMONY = "harmony",
LINEA_SEPOLIA = "linea-sepolia",
GNOSIS_CHIADO = "gnosis-chiado",
MODE_SEPOLIA = "mode-sepolia",
MODE = "mode-mainnet",
BASE_SEPOLIA = "base-sepolia",
ZKSYNC_ERA_SEPOLIA = "zksync-era-sepolia",
POLYGON_ZKEVM = "polygon-zkevm",
ZKSYNC_ERA = "zksync-era",
ETHEREUM_SEPOLIA = "sepolia",
ARBITRUM_SEPOLIA = "arbitrum-sepolia",
LINEA = "linea",
BASE = "base",
SCROLL_SEPOLIA = "scroll-sepolia",
SCROLL = "scroll",
BLAST_MAINNET = "blast-mainnet",
ASTAR_ZKEVM_MAINNET = "astar-zkevm-mainnet",
SEI_TESTNET = "sei-testnet",
BLAST_TESTNET = "blast-testnet",
ETHERLINK_TESTNET = "etherlink-testnet",
XLAYER_SEPOLIA = "xlayer-sepolia",
XLAYER_MAINNET = "xlayer-mainnet",
POLYGON_AMOY = "polygon-amoy",
ZKYOTO_TESTNET = "zkyoto-testnet",
POLYGON_ZKEVM_CARDONA = "polygon-zkevm-cardona",
SEI_MAINNET = "sei-mainnet",
ROOTSTOCK_MAINNET = "rootstock",
IOTEX_MAINNET = "iotex",
NEAR_MAINNET = "near-mainnet",
NEAR_TESTNET = "near-testnet",
COSMOS = "cosmoshub-4",
COSMOS_HUB = "theta-testnet-001",
OSMOSIS = "osmosis-1",
OSMO_TESTNET = "osmo-test-4",
ARWEAVE = "arweave-mainnet",
BITCOIN = "btc",
SOLANA = "solana-mainnet-beta",
INJECTIVE_MAINNET = "injective-mainnet",
INJECTIVE_TESTNET = "injective-testnet",
}
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
import { HttpException, HttpStatus } from "@nestjs/common";
import { Test } from "@nestjs/testing";

import type { IGetPublicKeyData } from "./file/types";
import type { IGenerateArgs, IGenerateData } from "./proof/types";
import type { IGetPublicKeyData } from "../../file/types";
import type { IGenerateArgs, IGenerateData } from "../types";
import type { TallyData } from "maci-cli";

import { AppController } from "./app.controller";
import { FileService } from "./file/file.service";
import { ProofGeneratorService } from "./proof/proof.service";
import { FileService } from "../../file/file.service";
import { ProofController } from "../proof.controller";
import { ProofGeneratorService } from "../proof.service";

describe("AppController", () => {
let appController: AppController;
describe("ProofController", () => {
let proofController: ProofController;

const defaultProofGeneratorArgs: IGenerateArgs = {
poll: 0,
Expand Down Expand Up @@ -41,7 +41,7 @@ describe("AppController", () => {

beforeEach(async () => {
const app = await Test.createTestingModule({
controllers: [AppController],
controllers: [ProofController],
})
.useMocker((token) => {
if (token === ProofGeneratorService) {
Expand All @@ -60,7 +60,7 @@ describe("AppController", () => {
})
.compile();

appController = app.get<AppController>(AppController);
proofController = app.get<ProofController>(ProofController);
});

afterEach(() => {
Expand All @@ -69,31 +69,31 @@ describe("AppController", () => {

describe("v1/proof/generate", () => {
test("should return generated proof data", async () => {
const data = await appController.generate(defaultProofGeneratorArgs);
const data = await proofController.generate(defaultProofGeneratorArgs);
expect(data).toStrictEqual(defaultProofGeneratorData);
});

test("should throw an error if proof generation if failed", async () => {
test("should throw an error if proof generation is failed", async () => {
const error = new Error("error");
mockGeneratorService.generate.mockRejectedValue(error);

await expect(appController.generate(defaultProofGeneratorArgs)).rejects.toThrow(
await expect(proofController.generate(defaultProofGeneratorArgs)).rejects.toThrow(
new HttpException(error.message, HttpStatus.BAD_REQUEST),
);
});
});

describe("v1/proof/publicKey", () => {
test("should return public key properly", async () => {
const data = await appController.getPublicKey();
const data = await proofController.getPublicKey();
expect(data).toStrictEqual(defaultPublicKeyData);
});

test("should throw an error if file service throws an error", async () => {
const error = new Error("error");
mockFileService.getPublicKey.mockRejectedValue(error);

await expect(appController.getPublicKey()).rejects.toThrow(
await expect(proofController.getPublicKey()).rejects.toThrow(
new HttpException(error.message, HttpStatus.BAD_REQUEST),
);
});
Expand Down
Original file line number Diff line number Diff line change
@@ -1,26 +1,27 @@
import { Body, Controller, Get, HttpException, HttpStatus, Logger, Post, UseGuards } from "@nestjs/common";
import { ApiBearerAuth, ApiBody, ApiResponse, ApiTags } from "@nestjs/swagger";

import type { IGetPublicKeyData } from "./file/types";
import type { IGenerateData } from "./proof/types";
import type { IGenerateData } from "./types";
import type { IGetPublicKeyData } from "../file/types";

import { AccountSignatureGuard, Public } from "./auth/AccountSignatureGuard.service";
import { FileService } from "./file/file.service";
import { GenerateProofDto } from "./proof/dto";
import { ProofGeneratorService } from "./proof/proof.service";
import { AccountSignatureGuard, Public } from "../auth/AccountSignatureGuard.service";
import { FileService } from "../file/file.service";

import { GenerateProofDto } from "./dto";
import { ProofGeneratorService } from "./proof.service";

@ApiTags("v1/proof")
@ApiBearerAuth()
@Controller("v1/proof")
@UseGuards(AccountSignatureGuard)
export class AppController {
export class ProofController {
/**
* Logger
*/
private readonly logger = new Logger(AppController.name);
private readonly logger = new Logger(ProofController.name);

/**
* Initialize AppController
* Initialize ProofController
*
* @param proofGeneratorService - proof generator service
* @param fileService - file service
Expand Down
14 changes: 14 additions & 0 deletions coordinator/ts/proof/proof.module.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { Module } from "@nestjs/common";

import { CryptoModule } from "../crypto/crypto.module";
import { FileModule } from "../file/file.module";

import { ProofController } from "./proof.controller";
import { ProofGeneratorService } from "./proof.service";

@Module({
imports: [FileModule, CryptoModule],
controllers: [ProofController],
providers: [ProofGeneratorService],
})
export class ProofModule {}
Loading

0 comments on commit d04d82c

Please sign in to comment.