From af9d4ae74a29aa5a76a810aac1dc980c6cf02ecb Mon Sep 17 00:00:00 2001 From: Evan Sangaline Date: Sun, 11 Feb 2024 11:03:17 -0600 Subject: [PATCH] Include all workspace files when creating circuits. --- .../src/script-templates/sindri/sindri.ts | 101 ++++++++++-------- 1 file changed, 57 insertions(+), 44 deletions(-) diff --git a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts index 0f9092201d..881699c329 100644 --- a/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts +++ b/libs/remix-ws-templates/src/script-templates/sindri/sindri.ts @@ -1,62 +1,75 @@ import client from 'sindri' +const getSindriManifest = async () => { + const sindriJson = await remix.call('fileManager', 'readFile', `sindri.json`) + return JSON.parse(sindriJson) +} + +const normalizePath = (path: string): string => { + while (path.startsWith('/') || path.startsWith('./')) { + path = path.replace(/^(\.\/|\/)/, '') + } + return path +} + /** * Compile the given circuit - * @param {string} entryPoint - path to the circuit to compile * @param {string} apiKey - sindri API key * @returns {Circuit} compiled circuit */ -export const createCircuit = async (entryPoint: string, apiKey: string) => { - client.authorize({ apiKey }) - - const sindriConf = await remix.call('fileManager', 'readFile', `sindri.json`) - const circuit = await remix.call('fileManager', 'readFile', entryPoint) - const deps = await remix.call('circuit-compiler' as any, 'resolveDependencies', entryPoint, circuit) - - const files = [] - files.push(new File([circuit], 'circuit.circom')) - files.push(new File([sindriConf], 'sindri.json')) - - for (const file in deps) { - if (file === entryPoint) continue - files.push(new File([deps[file]], file)) +export const createCircuit = async (apiKey: string) => { + const sindriManifest = await getSindriManifest() + client.authorize({apiKey}) + + // Create a map from file paths to `File` objects for all files in the workspace. + const filesByPath: {[path: string]: File} = {} + interface Workspace { + children?: Workspace + content?: string + } + const workspace: Workspace = await remix.call('fileManager', 'copyFolderToJson', '/') + const childQueue: Array<[string, Workspace]> = Object.entries(workspace) + while (childQueue.length > 0) { + const [path, child] = childQueue.pop() + if ('content' in child) { + filesByPath[path] = new File([child.content], path) } + if ('children' in child) { + childQueue.push(...Object.entries(child.children)) + } + } + + // Merge any of the circuit's resolved dependencies into the files at their expected import paths. + if (sindriManifest.circuitType === 'circom') { + const circuitPath = normalizePath(sindriManifest.circuitPath || 'circuit.circom') + const circuitContent = await remix.call('fileManager', 'readFile', circuitPath) + const dependencies: {[path: string]: string} = await remix.call('circuit-compiler' as any, 'resolveDependencies', circuitPath, circuitContent) + Object.entries(dependencies).forEach(([rawPath, content]) => { + const path = normalizePath(rawPath) + filesByPath[path] = new File([content], path) + }) + } - console.log(`creating circuit "${entryPoint}"...`) - const circuitProject = await client.createCircuit(files) - console.log(`circuit created ${circuitProject.circuit_id}`) - return circuitProject + console.log(`creating circuit "${entryPoint}"...`) + const files = Object.values(filesByPath) + const circuitProject = await client.createCircuit(files) + console.log(`circuit created ${circuitProject.circuit_id}`) + return circuitProject } /** * Generate a proof against the given circuit - * @param {string} circuitId - id of the circuit * @param {Object} signals - input signals + * @param {string} apiKey - sindri API key * @returns {Proof} generated proof */ -export const proveCircuit = async (circuitId: string, signals: { [id: string]: string }, apiKey: string) => { - client.authorize({ apiKey }) - console.log(`proving circuit ${circuitId}...`) - const proof = await client.proveCircuit(circuitId, JSON.stringify(signals)) - console.log(`proof id: ${proof.proof_id}`) - return proof -} - - -/** - * Save the circuit - * @param {Circuit} circuitProject - compiled circuit - */ -export const saveCircuit = async (circuitProject) => { - await remix.call('fileManager', 'writeFile', `.sindri/${circuitProject.circuit_id}.json`, JSON.stringify(circuitProject, null, '\t')) -} +export const proveCircuit = async (signals: {[id: string]: string}, apiKey: string) => { + const sindriManifest = await getSindriManifest() + client.authorize({apiKey}) -/** - * Load the circuit - * @param {string} circuitId - id of the circuit - * @param {Object} signals - input signals - * @returns {Proof} generated proof - */ -export const loadCircuit = async (circuitId: string) => { - return JSON.parse(await remix.call('fileManager', 'readFile', `.sindri/${circuitId}.json`)) + const circuitName = sindriManifest.name + console.log(`proving circuit "${circuitName}"...`) + const proof = await client.proveCircuit(circuitName, JSON.stringify(signals)) + console.log(`proof id: ${proof.proof_id}`) + return proof }