diff --git a/CHANGELOG.md b/CHANGELOG.md index e987a601..0765c7cc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,12 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [1.0.5](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.4...v1.0.5) (2023-07-24) + +**Note:** Version bump only for package p0tion + + + ## [1.0.4](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.2...v1.0.4) (2023-07-20) diff --git a/lerna.json b/lerna.json index d4be8ece..86e8e592 100644 --- a/lerna.json +++ b/lerna.json @@ -4,7 +4,7 @@ ], "npmClient": "yarn", "useWorkspaces": true, - "version": "1.0.4", + "version": "1.0.5", "changelogPreset": { "name": "conventionalcommits", "issuePrefixes": [ diff --git a/packages/actions/CHANGELOG.md b/packages/actions/CHANGELOG.md index 983c9d20..6e72a77d 100644 --- a/packages/actions/CHANGELOG.md +++ b/packages/actions/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.5](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.4...v1.0.5) (2023-07-24) + +**Note:** Version bump only for package @p0tion/actions + + + ## [1.0.4](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.2...v1.0.4) (2023-07-20) diff --git a/packages/actions/package.json b/packages/actions/package.json index b78377b8..d9e7cce3 100644 --- a/packages/actions/package.json +++ b/packages/actions/package.json @@ -1,6 +1,6 @@ { "name": "@p0tion/actions", - "version": "1.0.4", + "version": "1.0.5", "description": "A set of actions and helpers for CLI commands", "repository": "git@github.com:privacy-scaling-explorations/p0tion.git", "homepage": "https://github.com/privacy-scaling-explorations/p0tion", diff --git a/packages/actions/src/helpers/utils.ts b/packages/actions/src/helpers/utils.ts index 3e8803a7..b3c4e089 100644 --- a/packages/actions/src/helpers/utils.ts +++ b/packages/actions/src/helpers/utils.ts @@ -185,39 +185,63 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false): // check that the timeout is provided for the correct configuration let dynamicThreshold: number | undefined let fixedTimeWindow: number | undefined + + let circuit: CircuitDocument | CircuitInputData = {} as CircuitDocument | CircuitInputData + if (data.timeoutMechanismType === CeremonyTimeoutType.DYNAMIC) { if (circuitData.dynamicThreshold <= 0) throw new Error("The dynamic threshold should be > 0.") dynamicThreshold = circuitData.dynamicThreshold + + // the Circuit data for the ceremony setup + circuit = { + name: circuitData.name, + description: circuitData.description, + prefix: circuitPrefix, + sequencePosition: i+1, + metadata: metadata, + files: files, + template: template, + compiler: compiler, + verification: verification, + dynamicThreshold: dynamicThreshold, + avgTimings: { + contributionComputation: 0, + fullContribution: 0, + verifyCloudFunction: 0 + }, + + } } if (data.timeoutMechanismType === CeremonyTimeoutType.FIXED) { if (circuitData.fixedTimeWindow <= 0) throw new Error("The fixed time window threshold should be > 0.") fixedTimeWindow = circuitData.fixedTimeWindow - } - // the Circuit data for the ceremony setup - const circuit: CircuitDocument | CircuitInputData = { - name: circuitData.name, - description: circuitData.description, - prefix: circuitPrefix, - sequencePosition: i+1, - metadata: metadata, - files: files, - template: template, - compiler: compiler, - verification: verification, - fixedTimeWindow: fixedTimeWindow, - // dynamicThreshold: dynamicThreshold, - avgTimings: { - contributionComputation: 0, - fullContribution: 0, - verifyCloudFunction: 0 - }, - + + // the Circuit data for the ceremony setup + circuit = { + name: circuitData.name, + description: circuitData.description, + prefix: circuitPrefix, + sequencePosition: i+1, + metadata: metadata, + files: files, + template: template, + compiler: compiler, + verification: verification, + fixedTimeWindow: fixedTimeWindow, + avgTimings: { + contributionComputation: 0, + fullContribution: 0, + verifyCloudFunction: 0 + }, + + } } + circuits.push(circuit) // remove the local r1cs download (if used for verifying the config only vs setup) diff --git a/packages/backend/CHANGELOG.md b/packages/backend/CHANGELOG.md index 93648c54..c94234c8 100644 --- a/packages/backend/CHANGELOG.md +++ b/packages/backend/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.5](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.4...v1.0.5) (2023-07-24) + +**Note:** Version bump only for package @p0tion/backend + + + ## [1.0.4](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.2...v1.0.4) (2023-07-20) **Note:** Version bump only for package @p0tion/backend diff --git a/packages/backend/package.json b/packages/backend/package.json index 20234484..dbaf2fff 100644 --- a/packages/backend/package.json +++ b/packages/backend/package.json @@ -1,6 +1,6 @@ { "name": "@p0tion/backend", - "version": "1.0.4", + "version": "1.0.5", "description": "MPC Phase 2 backend for Firebase services management", "repository": "git@github.com:privacy-scaling-explorations/p0tion.git", "homepage": "https://github.com/privacy-scaling-explorations/p0tion", @@ -67,7 +67,7 @@ "@aws-sdk/client-ssm": "^3.357.0", "@aws-sdk/middleware-endpoint": "^3.329.0", "@aws-sdk/s3-request-presigner": "^3.329.0", - "@p0tion/actions": "^1.0.4", + "@p0tion/actions": "^1.0.5", "blakejs": "^1.2.1", "dotenv": "^16.0.3", "ethers": "5.7.2", diff --git a/packages/backend/src/functions/circuit.ts b/packages/backend/src/functions/circuit.ts index e2277f1e..31809acf 100644 --- a/packages/backend/src/functions/circuit.ts +++ b/packages/backend/src/functions/circuit.ts @@ -42,7 +42,7 @@ import { zKey } from "snarkjs" import { CommandInvocationStatus, SSMClient } from "@aws-sdk/client-ssm" import { FinalizeCircuitData, VerifyContributionData } from "../types/index" import { LogLevel } from "../types/enums" -import { COMMON_ERRORS, logAndThrowError, printLog, SPECIFIC_ERRORS } from "../lib/errors" +import { COMMON_ERRORS, logAndThrowError, makeError, printLog, SPECIFIC_ERRORS } from "../lib/errors" import { createEC2Client, createSSMClient, @@ -236,9 +236,6 @@ const waitForVMCommandExecution = ( if (cmdStatus === CommandInvocationStatus.SUCCESS) { printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG) - // Clear the interval. - clearInterval(interval) - // Resolve the promise. resolve() } else if (cmdStatus === CommandInvocationStatus.FAILED) { @@ -268,6 +265,62 @@ const waitForVMCommandExecution = ( }, 60000) // 1 minute. } +/** + * Wait until the artifacts have been downloaded. + * @param {any} resolve the promise. + * @param {any} reject the promise. + * @param {string} potTempFilePath the tmp path to the locally downloaded pot file. + * @param {string} firstZkeyTempFilePath the tmp path to the locally downloaded first zkey file. + * @param {string} lastZkeyTempFilePath the tmp path to the locally downloaded last zkey file. + */ +const waitForFileDownload = ( + resolve: any, + reject: any, + potTempFilePath: string, + firstZkeyTempFilePath: string, + lastZkeyTempFilePath: string, + circuitId: string, + participantId: string +) => { + const maxWaitTime = 5 * 60 * 1000 // 5 minutes + // every second check if the file download was completed + const interval = setInterval(async () => { + printLog(`Verifying that the artifacts were downloaded for circuit ${circuitId} and participant ${participantId}`, LogLevel.DEBUG) + try { + // check if files have been downloaded + if (!fs.existsSync(potTempFilePath)) { + printLog(`Pot file not found at ${potTempFilePath}`, LogLevel.DEBUG) + } + if (!fs.existsSync(firstZkeyTempFilePath)) { + printLog(`First zkey file not found at ${firstZkeyTempFilePath}`, LogLevel.DEBUG) + } + if (!fs.existsSync(lastZkeyTempFilePath)) { + printLog(`Last zkey file not found at ${lastZkeyTempFilePath}`, LogLevel.DEBUG) + } + + // if all files were downloaded + if (fs.existsSync(potTempFilePath) && fs.existsSync(firstZkeyTempFilePath) && fs.existsSync(lastZkeyTempFilePath)) { + printLog(`All required files are present on disk.`, LogLevel.INFO) + // resolve the promise + resolve() + } + } catch (error: any) { + // if we have an error then we print it as a warning and reject + printLog(`Error while downloading files: ${error}`, LogLevel.WARN) + reject() + } finally { + printLog(`Clearing the interval for file download. Circuit ${circuitId} and participant ${participantId}`, LogLevel.DEBUG) + clearInterval(interval) + } + }, 5000) + + // we want to clean in 5 minutes in case + setTimeout(() => { + clearInterval(interval) + reject(new Error('Timeout exceeded while waiting for files to be downloaded.')) + }, maxWaitTime) +} + /** * This method is used to coordinate the waiting queues of ceremony circuits. * @dev this cloud function is triggered whenever an update of a document related to a participant of a ceremony occurs. @@ -525,7 +578,7 @@ export const verifycontribution = functionsV2.https.onCall( ? `${contributorOrCoordinatorIdentifier}_${finalContributionIndex}_verification_transcript.log` : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log` }` - const firstZkeyFilename = `${prefix}_${genesisZkeyIndex}.zkey` + const lastZkeyFilename = `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey` // Prepare state for VM verification (if needed). @@ -555,7 +608,7 @@ export const verifycontribution = functionsV2.https.onCall( if (isUsingVM) { // Create temporary path. verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath( - verificationTranscriptCompleteFilename + `${circuitId}_${participantDoc.id}.log` ) await sleep(1000) // wait 1s for file creation. @@ -807,9 +860,9 @@ export const verifycontribution = functionsV2.https.onCall( verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath( verificationTranscriptCompleteFilename ) - const potTempFilePath = createTemporaryLocalPath(files.potFilename) - const firstZkeyTempFilePath = createTemporaryLocalPath(firstZkeyFilename) - const lastZkeyTempFilePath = createTemporaryLocalPath(lastZkeyFilename) + const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`) + const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`) + const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`) // Create and populate transcript. const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath) @@ -826,57 +879,45 @@ export const verifycontribution = functionsV2.https.onCall( await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath) await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath) - await sleep(10000) + await sleep(6000) - // check if files have been downloaded - if (!fs.existsSync(potTempFilePath)) { - printLog(`Pot file not found at ${potTempFilePath}`, LogLevel.DEBUG) - // retry once - printLog(`Retrying to download pot file from ${potStoragePath} to ${potTempFilePath}`, LogLevel.DEBUG) - await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath) - } - if (!fs.existsSync(firstZkeyTempFilePath)) { - printLog(`First zkey file not found at ${firstZkeyTempFilePath}`, LogLevel.DEBUG) - // retry once - printLog(`Retrying to download first zkey file from ${firstZkeyStoragePath} to ${firstZkeyTempFilePath}`, LogLevel.DEBUG) - await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath) - } - if (!fs.existsSync(lastZkeyTempFilePath)) { - printLog(`Last zkey file not found at ${lastZkeyTempFilePath}`, LogLevel.DEBUG) - // retry once - printLog(`Retrying to download last zkey file from ${lastZkeyStoragePath} to ${lastZkeyTempFilePath}`, LogLevel.DEBUG) - await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath) - } + // wait until the files are actually downloaded + return new Promise((resolve, reject) => + waitForFileDownload(resolve, reject, potTempFilePath, firstZkeyTempFilePath, lastZkeyTempFilePath, circuitId, participantDoc.id) + ) + .then(async () => { + printLog(`Downloads from AWS S3 bucket completed - ceremony ${ceremonyId} circuit ${circuitId}`, LogLevel.DEBUG) + + // Step (1.A.4). + isContributionValid = await zKey.verifyFromInit( + firstZkeyTempFilePath, + potTempFilePath, + lastZkeyTempFilePath, + transcriptLogger + ) + + // Compute contribution hash. + lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath) + + // Free resources by unlinking temporary folders. + // Do not free-up verification transcript path here. + try { + fs.unlinkSync(potTempFilePath) + fs.unlinkSync(firstZkeyTempFilePath) + fs.unlinkSync(lastZkeyTempFilePath) + } catch (error: any) { + printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN) + } - printLog(`Downloads from AWS S3 bucket completed - ceremony ${ceremonyId}`, LogLevel.DEBUG) + await completeVerification() + }) + .catch((error: any) => { + // Throw the new error + const commonError = COMMON_ERRORS.CM_INVALID_REQUEST + const additionalDetails = error.toString() - // Step (1.A.4). - try { - isContributionValid = await zKey.verifyFromInit( - firstZkeyTempFilePath, - potTempFilePath, - lastZkeyTempFilePath, - transcriptLogger - ) - } catch (error: any) { - printLog(`Error while verifying contribution - Error ${error}`, LogLevel.WARN) - isContributionValid = false - } - - // Compute contribution hash. - lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath) - - await completeVerification() - - // Free resources by unlinking temporary folders. - // Do not free-up verification transcript path here. - try { - fs.unlinkSync(potTempFilePath) - fs.unlinkSync(firstZkeyTempFilePath) - fs.unlinkSync(lastZkeyTempFilePath) - } catch (error: any) { - printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN) - } + logAndThrowError(makeError(commonError.code, commonError.message, additionalDetails)) + }) } } } diff --git a/packages/backend/src/functions/user.ts b/packages/backend/src/functions/user.ts index 9e7881d6..7f6d9628 100644 --- a/packages/backend/src/functions/user.ts +++ b/packages/backend/src/functions/user.ts @@ -109,6 +109,7 @@ export const registerAuthUser = functions * which uses the Firebase Authentication service. */ export const processSignUpWithCustomClaims = functions + .region("europe-west1") .runWith({ memory: "512MB" }) diff --git a/packages/backend/src/lib/utils.ts b/packages/backend/src/lib/utils.ts index 035bde28..a7fc6c0d 100644 --- a/packages/backend/src/lib/utils.ts +++ b/packages/backend/src/lib/utils.ts @@ -10,7 +10,7 @@ import admin from "firebase-admin" import dotenv from "dotenv" import { DeleteObjectCommand, GetObjectCommand, PutObjectCommand } from "@aws-sdk/client-s3" import { getSignedUrl } from "@aws-sdk/s3-request-presigner" -import { createWriteStream } from "node:fs" +import { createWriteStream, fstat } from "node:fs" import { pipeline } from "node:stream" import { promisify } from "node:util" import { readFileSync } from "fs" @@ -213,8 +213,13 @@ export const downloadArtifactFromS3Bucket = async (bucketName: string, objectKey if (response.status !== 200 || !response.ok) logAndThrowError(SPECIFIC_ERRORS.SE_STORAGE_DOWNLOAD_FAILED) // Write the file locally using streams. + const writeStream = createWriteStream(localFilePath) const streamPipeline = promisify(pipeline) - await streamPipeline(response.body, createWriteStream(localFilePath)) + await streamPipeline(response.body, writeStream) + + writeStream.on('finish', () => { + writeStream.end() + }) } /** diff --git a/packages/phase2cli/CHANGELOG.md b/packages/phase2cli/CHANGELOG.md index d056dae9..7c60d8ab 100644 --- a/packages/phase2cli/CHANGELOG.md +++ b/packages/phase2cli/CHANGELOG.md @@ -3,6 +3,13 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. + +## [1.0.5](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.4...v1.0.5) (2023-07-24) + +**Note:** Version bump only for package @p0tion/phase2cli + + + ## [1.0.4](https://github.com/privacy-scaling-explorations/p0tion/compare/v1.0.2...v1.0.4) (2023-07-20) **Note:** Version bump only for package @p0tion/phase2cli diff --git a/packages/phase2cli/package.json b/packages/phase2cli/package.json index 14ec4516..00c72f78 100644 --- a/packages/phase2cli/package.json +++ b/packages/phase2cli/package.json @@ -1,7 +1,7 @@ { "name": "@p0tion/phase2cli", "type": "module", - "version": "1.0.4", + "version": "1.0.5", "description": "All-in-one interactive command-line for interfacing with zkSNARK Phase 2 Trusted Setup ceremonies", "repository": "git@github.com:privacy-scaling-explorations/p0tion.git", "homepage": "https://github.com/privacy-scaling-explorations/p0tion", @@ -67,7 +67,7 @@ "@octokit/auth-oauth-app": "^5.0.5", "@octokit/auth-oauth-device": "^4.0.4", "@octokit/request": "^6.2.3", - "@p0tion/actions": "^1.0.4", + "@p0tion/actions": "^1.0.5", "blakejs": "^1.2.1", "boxen": "^7.1.0", "chalk": "^5.2.0", diff --git a/yarn.lock b/yarn.lock index 518a23ca..a37e9a2e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -6140,7 +6140,7 @@ __metadata: languageName: node linkType: hard -"@p0tion/actions@^1.0.4, @p0tion/actions@workspace:packages/actions": +"@p0tion/actions@^1.0.5, @p0tion/actions@workspace:packages/actions": version: 0.0.0-use.local resolution: "@p0tion/actions@workspace:packages/actions" dependencies: @@ -6195,7 +6195,7 @@ __metadata: "@aws-sdk/middleware-endpoint": ^3.329.0 "@aws-sdk/s3-request-presigner": ^3.329.0 "@firebase/rules-unit-testing": ^2.0.7 - "@p0tion/actions": ^1.0.4 + "@p0tion/actions": ^1.0.5 "@types/rollup-plugin-auto-external": ^2.0.2 "@types/uuid": ^9.0.1 blakejs: ^1.2.1 @@ -6228,7 +6228,7 @@ __metadata: "@octokit/auth-oauth-app": ^5.0.5 "@octokit/auth-oauth-device": ^4.0.4 "@octokit/request": ^6.2.3 - "@p0tion/actions": ^1.0.4 + "@p0tion/actions": ^1.0.5 "@types/clear": ^0.1.2 "@types/cli-progress": ^3.11.0 "@types/figlet": ^1.5.6