From e99191926eb4276b0f0af8aac591c37d70da5441 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 29 Dec 2023 15:18:03 -0600 Subject: [PATCH 1/6] Update the API client. --- src/lib/api/core/OpenAPI.ts | 2 +- src/lib/api/index.ts | 1 - src/lib/api/models/CircuitCreateInput.ts | 11 ---------- src/lib/api/services/CircuitsService.ts | 27 +++++++++++++++++++++--- src/lib/api/services/ProofsService.ts | 24 +++++++++++++++++++++ src/lib/api/services/TokenService.ts | 6 +++--- 6 files changed, 52 insertions(+), 19 deletions(-) delete mode 100644 src/lib/api/models/CircuitCreateInput.ts diff --git a/src/lib/api/core/OpenAPI.ts b/src/lib/api/core/OpenAPI.ts index a26abea..8272043 100644 --- a/src/lib/api/core/OpenAPI.ts +++ b/src/lib/api/core/OpenAPI.ts @@ -21,7 +21,7 @@ export type OpenAPIConfig = { export const OpenAPI: OpenAPIConfig = { BASE: "https://sindri.app", - VERSION: "1.5.10", + VERSION: "1.5.25", WITH_CREDENTIALS: false, CREDENTIALS: "include", TOKEN: undefined, diff --git a/src/lib/api/index.ts b/src/lib/api/index.ts index a7d7278..e773a74 100644 --- a/src/lib/api/index.ts +++ b/src/lib/api/index.ts @@ -12,7 +12,6 @@ export type { APIKeyDoesNotExistResponse } from './models/APIKeyDoesNotExistResp export type { APIKeyErrorResponse } from './models/APIKeyErrorResponse'; export type { APIKeyResponse } from './models/APIKeyResponse'; export type { CircomCircuitInfoResponse } from './models/CircomCircuitInfoResponse'; -export type { CircuitCreateInput } from './models/CircuitCreateInput'; export type { CircuitDoesNotExistResponse } from './models/CircuitDoesNotExistResponse'; export { CircuitStatus } from './models/CircuitStatus'; export { CircuitType } from './models/CircuitType'; diff --git a/src/lib/api/models/CircuitCreateInput.ts b/src/lib/api/models/CircuitCreateInput.ts deleted file mode 100644 index e63d575..0000000 --- a/src/lib/api/models/CircuitCreateInput.ts +++ /dev/null @@ -1,11 +0,0 @@ -/* generated using openapi-typescript-codegen -- do no edit */ -/* istanbul ignore file */ -/* tslint:disable */ -/* eslint-disable */ - -/** - * Client input when creating a circuit. - */ -export type CircuitCreateInput = { - tags: Array; -}; diff --git a/src/lib/api/services/CircuitsService.ts b/src/lib/api/services/CircuitsService.ts index b3c023b..f9fcb63 100644 --- a/src/lib/api/services/CircuitsService.ts +++ b/src/lib/api/services/CircuitsService.ts @@ -2,10 +2,8 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ -import FormData from "form-data"; - +import type { ActionResponse } from "../models/ActionResponse"; import type { CircomCircuitInfoResponse } from "../models/CircomCircuitInfoResponse"; -import type { CircuitCreateInput } from "../models/CircuitCreateInput"; import type { GnarkCircuitInfoResponse } from "../models/GnarkCircuitInfoResponse"; import type { Halo2CircuitInfoResponse } from "../models/Halo2CircuitInfoResponse"; import type { NoirCircuitInfoResponse } from "../models/NoirCircuitInfoResponse"; @@ -112,6 +110,29 @@ export class CircuitsService { }); } + /** + * Delete Circuit + * Mark the specified circuit and any related proofs as deleted. + * @param circuitId + * @returns ActionResponse OK + * @throws ApiError + */ + public static circuitDelete( + circuitId: string, + ): CancelablePromise { + return __request(OpenAPI, { + method: "DELETE", + url: "/api/v1/circuit/{circuit_id}/delete", + path: { + circuit_id: circuitId, + }, + errors: { + 404: `Not Found`, + 500: `Internal Server Error`, + }, + }); + } + /** * Circuit Proofs * Return list of ProofInfoResponse for proofs of circuit_id related to team. diff --git a/src/lib/api/services/ProofsService.ts b/src/lib/api/services/ProofsService.ts index 92877ac..f3a07c0 100644 --- a/src/lib/api/services/ProofsService.ts +++ b/src/lib/api/services/ProofsService.ts @@ -2,6 +2,7 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +import type { ActionResponse } from "../models/ActionResponse"; import type { ProofInfoResponse } from "../models/ProofInfoResponse"; import type { CancelablePromise } from "../core/CancelablePromise"; @@ -76,4 +77,27 @@ export class ProofsService { }, }); } + + /** + * Delete Proof + * Mark the specified proof as deleted. + * @param proofId + * @returns ActionResponse OK + * @throws ApiError + */ + public static proofDelete( + proofId: string, + ): CancelablePromise { + return __request(OpenAPI, { + method: "DELETE", + url: "/api/v1/proof/{proof_id}/delete", + path: { + proof_id: proofId, + }, + errors: { + 404: `Not Found`, + 500: `Internal Server Error`, + }, + }); + } } diff --git a/src/lib/api/services/TokenService.ts b/src/lib/api/services/TokenService.ts index 1054238..9da01f6 100644 --- a/src/lib/api/services/TokenService.ts +++ b/src/lib/api/services/TokenService.ts @@ -20,7 +20,7 @@ export class TokenService { * @returns TokenObtainPairOutputSchema OK * @throws ApiError */ - public static bf740E1AControllerObtainToken( + public static aa5976D9ControllerObtainToken( requestBody: TokenObtainPairInputSchema, ): CancelablePromise { return __request(OpenAPI, { @@ -37,7 +37,7 @@ export class TokenService { * @returns TokenRefreshOutputSchema OK * @throws ApiError */ - public static db93F15ControllerRefreshToken( + public static a6E7B8BControllerRefreshToken( requestBody: TokenRefreshInputSchema, ): CancelablePromise { return __request(OpenAPI, { @@ -54,7 +54,7 @@ export class TokenService { * @returns Schema OK * @throws ApiError */ - public static abc17FbControllerVerifyToken( + public static f559BControllerVerifyToken( requestBody: TokenVerifyInputSchema, ): CancelablePromise { return __request(OpenAPI, { From 96d0cb3769e6e910fe7f889f1896a1d739a67811 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 29 Dec 2023 16:11:06 -0600 Subject: [PATCH 2/6] Add a rough cut of the proof create command. --- src/cli/index.ts | 2 + src/cli/proof.ts | 145 +++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 147 insertions(+) create mode 100644 src/cli/proof.ts diff --git a/src/cli/index.ts b/src/cli/index.ts index a123d5d..05ba986 100644 --- a/src/cli/index.ts +++ b/src/cli/index.ts @@ -10,6 +10,7 @@ import { lintCommand } from "cli/lint"; import { logger } from "cli/logging"; import { loginCommand } from "cli/login"; import { logoutCommand } from "cli/logout"; +import { proofCommand } from "cli/proof"; import { whoamiCommand } from "cli/whoami"; import { loadPackageJson } from "cli/utils"; @@ -29,6 +30,7 @@ export const program = new Command() .addCommand(lintCommand) .addCommand(loginCommand) .addCommand(logoutCommand) + .addCommand(proofCommand) .addCommand(whoamiCommand) // Parse the base command options and respond to them before invoking the subcommand. .hook("preAction", async (command) => { diff --git a/src/cli/proof.ts b/src/cli/proof.ts new file mode 100644 index 0000000..fd49ae5 --- /dev/null +++ b/src/cli/proof.ts @@ -0,0 +1,145 @@ +import fs from "fs"; +import path from "path"; +import process from "process"; + +import { Command } from "@commander-js/extra-typings"; + +import { Config } from "cli/config"; +import { logger, print } from "cli/logging"; +import { findFileUpwards } from "cli/utils"; +import { ApiError, CircuitsService } from "lib/api"; + +const readStdin = async (): Promise => { + let inputData = ""; + return new Promise((resolve) => { + process.stdin.on("data", (chunk) => (inputData += chunk)); + process.stdin.on("end", () => resolve(inputData)); + }); +}; + +const proofCreateCommand = new Command() + .name("create") + .description("Create a proof for the circuit.") + .option( + "-i, --input ", + "Input file for the proof (defaults to stdin).", + ) + .option("-t, --tag ", "Tag to generate the proof from.", "latest") + .action(async ({ input, tag }) => { + // Authorize the API client. + const config = new Config(); + const auth = config.auth; + if (!auth) { + logger.warn("You must login first with `sindri login`."); + return process.exit(1); + } + + // Find `sindri.json` and move into the root of the project directory. + const currentDirectoryPath = path.resolve("."); + if (!fs.existsSync(currentDirectoryPath)) { + logger.error( + `The "${currentDirectoryPath}" directory does not exist. Aborting.`, + ); + return process.exit(1); + } + const sindriJsonPath = findFileUpwards( + /^sindri.json$/i, + currentDirectoryPath, + ); + if (!sindriJsonPath) { + logger.error( + `No "sindri.json" file was found in or above "${currentDirectoryPath}". Aborting.`, + ); + return process.exit(1); + } + logger.debug(`Found "sindri.json" at "${sindriJsonPath}".`); + const rootDirectory = path.dirname(sindriJsonPath); + logger.debug(`Changing current directory to "${rootDirectory}".`); + process.chdir(rootDirectory); + + // Load `sindri.json` and find the circuit name. + let sindriJson: object = {}; + try { + const sindriJsonContent = fs.readFileSync(sindriJsonPath, { + encoding: "utf-8", + }); + sindriJson = JSON.parse(sindriJsonContent); + logger.debug( + `Successfully loaded "sindri.json" from "${sindriJsonPath}":`, + ); + logger.debug(sindriJson); + } catch (error) { + logger.fatal( + `Error loading "${sindriJsonPath}", perhaps it is not valid JSON?`, + ); + logger.error(error); + return process.exit(1); + } + if (!("name" in sindriJson)) { + logger.error('No "name" field found in "sindri.json". Aborting.'); + return process.exit(1); + } + const circuitName = sindriJson.name; + + // Reed in the proof input. + let proofInput: string | undefined; + if (input && fs.existsSync(input)) { + // Read from the specified input file. + proofInput = fs.readFileSync(input, "utf-8"); + } else if (!process.stdin.isTTY) { + // Read from stdin in a non-TTY context. + proofInput = await readStdin(); + } else { + // Try to load from common input filenames. + const defaultInputFiles = [ + "input.json", + "example-input.json", + "Prover.toml", + ]; + for (const file of defaultInputFiles) { + const qualifiedFile = path.join(rootDirectory, file); + if (fs.existsSync(file)) { + proofInput = fs.readFileSync(qualifiedFile, "utf-8"); + break; + } + } + + if (!proofInput) { + console.error( + "No input file specified, none of the default files found, and not in a non-TTY context.", + ); + process.exit(1); + } + } + + const circuitIdentifier = `${circuitName}:${tag}`; + try { + const response = await CircuitsService.proofCreate(circuitIdentifier, { + proof_input: proofInput, + }); + logger.debug(`/api/v1/circuit/${circuitIdentifier}/prove/ response:`); + logger.debug(response); + print({ + proofId: response.proof_id, + proof: response.proof, + public: response.public, + verificationKey: response.verification_key, + }); + } catch (error) { + // TODO: Better error handling. + if (error instanceof ApiError && error.status === 404) { + logger.error( + `No circuit found with the name "${circuitName}" and tag "${tag}".`, + ); + } else { + logger.fatal("An unknown error occurred."); + logger.error(error); + return process.exit(1); + } + } + }); + +export const proofCommand = new Command() + .name("proof") + .description("Commands related to proofs for the current circuit.") + .addCommand(proofCreateCommand); From a290983337fe48fb9d1d6d2ddb63825d13bb24b6 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 29 Dec 2023 16:19:08 -0600 Subject: [PATCH 3/6] Add back the form-date import. --- src/lib/api/services/CircuitsService.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/api/services/CircuitsService.ts b/src/lib/api/services/CircuitsService.ts index f9fcb63..0e62ac0 100644 --- a/src/lib/api/services/CircuitsService.ts +++ b/src/lib/api/services/CircuitsService.ts @@ -2,6 +2,9 @@ /* istanbul ignore file */ /* tslint:disable */ /* eslint-disable */ +// DO NOT REMOVE THIS! +import FormData from "form-data"; + import type { ActionResponse } from "../models/ActionResponse"; import type { CircomCircuitInfoResponse } from "../models/CircomCircuitInfoResponse"; import type { GnarkCircuitInfoResponse } from "../models/GnarkCircuitInfoResponse"; From 75c201047cf809679ad39a762587e59f28f2b35d Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 29 Dec 2023 16:21:56 -0600 Subject: [PATCH 4/6] Fix the token generation endpoint. --- src/cli/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/login.ts b/src/cli/login.ts index c3040fd..33d9b49 100644 --- a/src/cli/login.ts +++ b/src/cli/login.ts @@ -76,7 +76,7 @@ export const loginCommand = new Command() try { // Generate a JWT token to authenticate the user. OpenAPI.BASE = baseUrl; - const tokenResult = await TokenService.bf740E1AControllerObtainToken({ + const tokenResult = await TokenService.aa5976D9ControllerObtainToken( username, password, }); From 1ce5bcbfd877c43f95f3ee2bbaf181d7cd0a7449 Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 29 Dec 2023 16:43:30 -0600 Subject: [PATCH 5/6] Add the tags to the circuit create endpoint. --- src/lib/api/services/CircuitsService.ts | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/lib/api/services/CircuitsService.ts b/src/lib/api/services/CircuitsService.ts index 0e62ac0..b730b86 100644 --- a/src/lib/api/services/CircuitsService.ts +++ b/src/lib/api/services/CircuitsService.ts @@ -29,7 +29,10 @@ export class CircuitsService { | FormData // DO NOT REMOVE THIS! | { files: Array; - payload?: CircuitCreateInput; + /** + * Tags for a circuit. + */ + tags?: Array; }, ): CancelablePromise< | CircomCircuitInfoResponse From cc9703efd01bc16f62e7ead28f0070ffacd5ea7c Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Fri, 29 Dec 2023 16:51:47 -0600 Subject: [PATCH 6/6] Fix missing bracket. --- src/cli/login.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/cli/login.ts b/src/cli/login.ts index 33d9b49..fea7346 100644 --- a/src/cli/login.ts +++ b/src/cli/login.ts @@ -76,7 +76,7 @@ export const loginCommand = new Command() try { // Generate a JWT token to authenticate the user. OpenAPI.BASE = baseUrl; - const tokenResult = await TokenService.aa5976D9ControllerObtainToken( + const tokenResult = await TokenService.aa5976D9ControllerObtainToken({ username, password, });