From e1a98a8d4b33c589a4a32300e9ad03c9a647c05b Mon Sep 17 00:00:00 2001 From: Jeeiii Date: Mon, 30 Jan 2023 11:32:32 +0100 Subject: [PATCH] refactor: update and move constants to actions package BREAKING CHANGE: constants are now part of actions package --- packages/actions/src/core/lib/utils.ts | 4 +- packages/actions/src/helpers/constants.ts | 164 ++++++++++++------ packages/actions/src/helpers/query.ts | 27 ++- packages/actions/src/index.ts | 9 +- packages/phase2cli/src/commands/auth.ts | 6 +- packages/phase2cli/src/commands/clean.ts | 8 +- packages/phase2cli/src/commands/contribute.ts | 35 ++-- packages/phase2cli/src/commands/finalize.ts | 28 +-- packages/phase2cli/src/commands/logout.ts | 14 +- packages/phase2cli/src/commands/observe.ts | 24 +-- packages/phase2cli/src/commands/setup.ts | 122 +++++++------ packages/phase2cli/src/lib/authorization.ts | 18 +- packages/phase2cli/src/lib/commands.ts | 4 +- packages/phase2cli/src/lib/constants.ts | 103 ----------- packages/phase2cli/src/lib/errors.ts | 4 +- packages/phase2cli/src/lib/listeners.ts | 103 ++++++----- packages/phase2cli/src/lib/paths.ts | 42 ++--- packages/phase2cli/src/lib/prompts.ts | 106 ++++++----- packages/phase2cli/src/lib/queries.ts | 13 +- packages/phase2cli/src/lib/storage.ts | 6 +- packages/phase2cli/src/lib/theme.ts | 45 +++++ packages/phase2cli/src/lib/utils.ts | 102 ++++++----- 22 files changed, 527 insertions(+), 460 deletions(-) delete mode 100644 packages/phase2cli/src/lib/constants.ts create mode 100644 packages/phase2cli/src/lib/theme.ts diff --git a/packages/actions/src/core/lib/utils.ts b/packages/actions/src/core/lib/utils.ts index 1891c0e9..5c02005b 100644 --- a/packages/actions/src/core/lib/utils.ts +++ b/packages/actions/src/core/lib/utils.ts @@ -1,4 +1,4 @@ -import { firstZkeyIndex } from "../../helpers/constants" +import { genesisZkeyIndex } from "../../helpers/constants" /** * Get the powers from pot file name @@ -27,7 +27,7 @@ export const extractPrefix = (str: string): string => export const formatZkeyIndex = (progress: number): string => { let index = progress.toString() - while (index.length < firstZkeyIndex.length) { + while (index.length < genesisZkeyIndex.length) { index = `0${index}` } diff --git a/packages/actions/src/helpers/constants.ts b/packages/actions/src/helpers/constants.ts index 127abf46..3b772742 100644 --- a/packages/actions/src/helpers/constants.ts +++ b/packages/actions/src/helpers/constants.ts @@ -1,55 +1,115 @@ -export const terms = { - output: `output`, - setup: `setup`, - contribute: `contribute`, - finalize: `finalize`, - pot: `pot`, - zkeys: `zkeys`, - vkeys: `vkeys`, - metadata: `metadata`, - transcripts: `transcripts`, - attestation: `attestation`, - verifiers: `verifiers` -} - -export const potDownloadUrlTemplate = `https://hermez.s3-eu-west-1.amazonaws.com/` +/** + * Core constant values. + * @notice the theme currently supports a single color palette, which displays well on both dark and light terminal windows. + */ +// Main part for the Hermez Phase 1 Trusted Setup URLs to download PoT files. +export const potFileDownloadMainUrl = `https://hermez.s3-eu-west-1.amazonaws.com/` +// Main part for the Hermez Phase 1 Trusted Setup PoT files to be downloaded. export const potFilenameTemplate = `powersOfTau28_hez_final_` +// The genesis zKey index. +export const genesisZkeyIndex = `00000` +// The number of exponential iterations to be executed by SnarkJS when finalizing the ceremony. +export const numExpIterations = 10 +// The Solidity version of the Verifier Smart Contract generated with SnarkJS when finalizing the ceremony. +export const solidityVersion = "0.8.0" -/** Firebase */ -export const collections = { - users: "users", - participants: "participants", - ceremonies: "ceremonies", - circuits: "circuits", - contributions: "contributions", - timeouts: "timeouts" -} - -export const contributionsCollectionFields = { - contributionTime: "contributionTime", - files: "files", - lastUpdated: "lastUpdated", - participantId: "participantId", - valid: "valid", - verificationTime: "verificationTime", - zkeyIndex: "zKeyIndex" -} - -export const firstZkeyIndex = `00000` - -export const timeoutsCollectionFields = { - startDate: "startDate", - endDate: "endDate" -} - -export const ceremoniesCollectionFields = { - coordinatorId: "coordinatorId", - description: "description", - endDate: "endDate", - lastUpdated: "lastUpdated", - prefix: "prefix", - startDate: "startDate", - state: "state", - title: "title", - type: "type" +/** + * Commonly used terms. + * @dev useful for creating paths, references to collections and queries, object properties, folder names, and so on. + */ +export const commonTerms = { + collections: { + users: { + name: "users", + fields: { + creationTime: "creationTime", + displayName: "displayName", + email: "email", + emailVerified: "emailVerified", + lastSignInTime: "lastSignInTime", + lastUpdated: "lastUpdated", + name: "name", + photoURL: "photoURL" + } + }, + participants: { + name: "participants", + fields: { + contributionProgress: "contributionProgress", + contributionStartedAt: "contributionStartedAt", + contributionStep: "contributionStep", + contributions: "contributions", + lastUpdated: "lastUpdated", + status: "status", + verificationStartedAt: "verificationStartedAt" + } + }, + ceremonies: { + name: "ceremonies", + fields: { + coordinatorId: "coordinatorId", + description: "description", + endDate: "endDate", + lastUpdated: "lastUpdated", + penalty: "penalty", + prefix: "prefix", + startDate: "startDate", + state: "state", + timeoutType: "timeoutType", + title: "title", + type: "type" + } + }, + circuits: { + name: "circuits", + fields: { + avgTimings: "avgTimings", + compiler: "compiler", + description: "description", + files: "files", + lastUpdated: "lastUpdated", + metadata: "metadata", + name: "name", + prefix: "prefix", + sequencePosition: "sequencePosition", + template: "template", + timeoutMaxContributionWaitingTime: "timeoutMaxContributionWaitingTime", + waitingQueue: "waitingQueue", + zKeySizeInBytes: "zKeySizeInBytes" + } + }, + contributions: { + name: "contributions", + fields: { + contributionComputationTime: "contributionComputationTime", + files: "files", + lastUpdated: "lastUpdated", + participantId: "participantId", + valid: "valid", + verificationComputationTime: "verificationComputationTime", + zkeyIndex: "zKeyIndex" + } + }, + timeouts: { + name: "timeouts", + fields: { + type: "type", + startDate: "startDate", + endDate: "endDate" + } + } + }, + foldersAndPathsTerms: { + output: `output`, + setup: `setup`, + contribute: `contribute`, + finalize: `finalize`, + pot: `pot`, + zkeys: `zkeys`, + vkeys: `vkeys`, + metadata: `metadata`, + transcripts: `transcripts`, + attestation: `attestation`, + verifiers: `verifiers` + } } diff --git a/packages/actions/src/helpers/query.ts b/packages/actions/src/helpers/query.ts index 35d41c9d..f94206c9 100644 --- a/packages/actions/src/helpers/query.ts +++ b/packages/actions/src/helpers/query.ts @@ -14,12 +14,7 @@ import { where } from "firebase/firestore" import { CeremonyState, FirebaseDocumentInfo } from "../../types/index" -import { - ceremoniesCollectionFields, - collections, - contributionsCollectionFields, - timeoutsCollectionFields -} from "./constants" +import { commonTerms } from "./constants" /** * Helper for query a collection based on certain constraints. @@ -101,8 +96,8 @@ export const getCurrentContributorContribution = async ( ): Promise> => { const participantContributionQuerySnap = await queryCollection( firestoreDatabase, - `${collections.ceremonies}/${ceremonyId}/${collections.circuits}/${circuitId}/${collections.contributions}`, - [where(contributionsCollectionFields.participantId, "==", participantId)] + `${commonTerms.collections.ceremonies.name}/${ceremonyId}/${commonTerms.collections.circuits.name}/${circuitId}/${commonTerms.collections.contributions.name}`, + [where(commonTerms.collections.contributions.fields.participantId, "==", participantId)] ) return fromQueryToFirebaseDocumentInfo(participantContributionQuerySnap.docs) @@ -121,8 +116,8 @@ export const getCurrentActiveParticipantTimeout = async ( ): Promise> => { const participantTimeoutQuerySnap = await queryCollection( firestoreDatabase, - `${collections.ceremonies}/${ceremonyId}/${collections.participants}/${participantId}/${collections.timeouts}`, - [where(timeoutsCollectionFields.endDate, ">=", Timestamp.now().toMillis())] + `${commonTerms.collections.ceremonies.name}/${ceremonyId}/${commonTerms.collections.participants.name}/${participantId}/${commonTerms.collections.timeouts.name}`, + [where(commonTerms.collections.timeouts.fields.endDate, ">=", Timestamp.now().toMillis())] ) return fromQueryToFirebaseDocumentInfo(participantTimeoutQuerySnap.docs) @@ -137,10 +132,14 @@ export const getClosedCeremonies = async (firestoreDatabase: Firestore): Promise let closedStateCeremoniesQuerySnap: any try { - closedStateCeremoniesQuerySnap = await queryCollection(firestoreDatabase, collections.ceremonies, [ - where(ceremoniesCollectionFields.state, "==", CeremonyState.CLOSED), - where(ceremoniesCollectionFields.endDate, "<=", Date.now()) - ]) + closedStateCeremoniesQuerySnap = await queryCollection( + firestoreDatabase, + commonTerms.collections.ceremonies.name, + [ + where(commonTerms.collections.ceremonies.fields.state, "==", CeremonyState.CLOSED), + where(commonTerms.collections.ceremonies.fields.endDate, "<=", Date.now()) + ] + ) if (closedStateCeremoniesQuerySnap.empty && closedStateCeremoniesQuerySnap.size === 0) throw new Error("Queries-0001: There are no ceremonies ready to finalization") diff --git a/packages/actions/src/index.ts b/packages/actions/src/index.ts index f02e1df6..f64db003 100644 --- a/packages/actions/src/index.ts +++ b/packages/actions/src/index.ts @@ -56,4 +56,11 @@ export { getCurrentFirebaseAuthUser, isCoordinator } from "./helpers/firebase" -export { terms } from "./helpers/constants" +export { + commonTerms, + potFileDownloadMainUrl, + potFilenameTemplate, + genesisZkeyIndex, + numExpIterations, + solidityVersion +} from "./helpers/constants" diff --git a/packages/phase2cli/src/commands/auth.ts b/packages/phase2cli/src/commands/auth.ts index 5a2d3789..d3f3fb8d 100644 --- a/packages/phase2cli/src/commands/auth.ts +++ b/packages/phase2cli/src/commands/auth.ts @@ -1,10 +1,10 @@ #!/usr/bin/env node import dotenv from "dotenv" -import { symbols, theme } from "../lib/constants" import { exchangeGithubTokenForCredentials, getGithubUserHandle, terminate } from "../lib/utils" import { bootstrapCommandExecutionAndServices } from "../lib/commands" import { executeGithubDeviceFlow, signInToFirebase } from "../lib/authorization" import { checkLocalAccessToken, getLocalAccessToken, setLocalAccessToken } from "../lib/localStorage" +import theme from "../lib/theme" dotenv.config() @@ -39,9 +39,9 @@ const auth = async () => { // Get Github handle. const githubUserHandle = await getGithubUserHandle(String(token)) - console.log(`${symbols.success} You are authenticated as ${theme.bold(`@${githubUserHandle}`)}`) + console.log(`${theme.symbols.success} You are authenticated as ${theme.text.bold(`@${githubUserHandle}`)}`) console.log( - `${symbols.info} You are now able to compute contributions for zk-SNARK Phase2 Trusted Setup opened ceremonies` + `${theme.symbols.info} You are now able to compute contributions for zk-SNARK Phase2 Trusted Setup opened ceremonies` ) terminate(githubUserHandle) diff --git a/packages/phase2cli/src/commands/clean.ts b/packages/phase2cli/src/commands/clean.ts index a3ea31a1..202dcfbc 100644 --- a/packages/phase2cli/src/commands/clean.ts +++ b/packages/phase2cli/src/commands/clean.ts @@ -2,11 +2,11 @@ import { deleteDir, directoryExists } from "@zkmpc/actions" import { bootstrapCommandExecutionAndServices } from "../lib/commands" -import { emojis, symbols, theme } from "../lib/constants" import { showError } from "../lib/errors" import { askForConfirmation } from "../lib/prompts" import { outputLocalFolderPath } from "../lib/paths" import { customSpinner, sleep } from "../lib/utils" +import theme from "../lib/theme" /** * Clean command. @@ -19,7 +19,7 @@ const clean = async () => { const spinner = customSpinner(`Cleaning up...`, "clock") if (directoryExists(outputLocalFolderPath)) { - console.log(theme.bold(`${symbols.warning} Be careful, this action is irreversible!`)) + console.log(theme.text.bold(`${theme.symbols.warning} Be careful, this action is irreversible!`)) const { confirmation } = await askForConfirmation( "Are you sure you want to continue with the clean up?", @@ -36,10 +36,10 @@ const clean = async () => { // nb. simulate waiting time for 1s. await sleep(1000) - spinner.succeed(`Cleanup was successfully completed ${emojis.broom}`) + spinner.succeed(`Cleanup was successfully completed ${theme.emojis.broom}`) } } else { - console.log(`${symbols.info} There is nothing to clean ${emojis.eyes}`) + console.log(`${theme.symbols.info} There is nothing to clean ${theme.emojis.eyes}`) } } catch (err: any) { showError(`Something went wrong: ${err.toString()}`, true) diff --git a/packages/phase2cli/src/commands/contribute.ts b/packages/phase2cli/src/commands/contribute.ts index 3d78257e..8bd37fed 100644 --- a/packages/phase2cli/src/commands/contribute.ts +++ b/packages/phase2cli/src/commands/contribute.ts @@ -6,9 +6,9 @@ import { getContributorContributionsVerificationResults, getDocumentById, getOpenedCeremonies, - checkAndMakeNewDirectoryIfNonexistent + checkAndMakeNewDirectoryIfNonexistent, + commonTerms } from "@zkmpc/actions" -import { theme, emojis, collections, symbols } from "../lib/constants" import { askForCeremonySelection, getEntropyOrBeacon } from "../lib/prompts" import { ParticipantContributionStep, ParticipantStatus } from "../../types/index" import { terminate, handleTimedoutMessageForContributor, customSpinner, simpleLoader } from "../lib/utils" @@ -23,6 +23,7 @@ import { contributionTranscriptsLocalFolderPath, outputLocalFolderPath } from "../lib/paths" +import theme from "../lib/theme" /** * Contribute command. @@ -41,9 +42,9 @@ const contribute = async () => { if (runningCeremoniesDocs.length === 0) showError(FIREBASE_ERRORS.FIREBASE_CEREMONY_NOT_OPENED, true) console.log( - `${symbols.warning} ${theme.bold( - `The contribution process is based on a waiting queue mechanism (one contributor at a time) with an upper-bound time constraint per each contribution (does not restart if the process is halted for any reason).\n${symbols.info} Any contribution could take the bulk of your computational resources and memory based on the size of the circuit` - )} ${emojis.fire}\n` + `${theme.symbols.warning} ${theme.text.bold( + `The contribution process is based on a waiting queue mechanism (one contributor at a time) with an upper-bound time constraint per each contribution (does not restart if the process is halted for any reason).\n${theme.symbols.info} Any contribution could take the bulk of your computational resources and memory based on the size of the circuit` + )} ${theme.emojis.fire}\n` ) // Ask to select a ceremony. @@ -63,7 +64,7 @@ const contribute = async () => { // Get participant document. const participantDoc = await getDocumentById( firestoreDatabase, - `${collections.ceremonies}/${ceremony.id}/${collections.participants}`, + `${commonTerms.collections.ceremonies.name}/${ceremony.id}/${commonTerms.collections.participants.name}`, user.uid ) @@ -74,7 +75,7 @@ const contribute = async () => { // Check if the user can take part of the waiting queue for contributing. if (canParticipate) { - spinner.succeed(`You are eligible to contribute to the ceremony ${emojis.tada}\n`) + spinner.succeed(`You are eligible to contribute to the ceremony ${theme.emojis.tada}\n`) // Check for output directory. checkAndMakeNewDirectoryIfNonexistent(outputLocalFolderPath) @@ -139,32 +140,32 @@ const contribute = async () => { if (numberOfValidContributions) { console.log( - `Congrats, you have already contributed to ${theme.magenta( - theme.bold(numberOfValidContributions) - )} out of ${theme.magenta(theme.bold(numberOfCircuits))} circuits ${emojis.tada}` + `Congrats, you have already contributed to ${theme.colors.magenta( + theme.text.bold(numberOfValidContributions) + )} out of ${theme.colors.magenta(theme.text.bold(numberOfCircuits))} circuits ${theme.emojis.tada}` ) // Show valid/invalid contributions per each circuit. let idx = 0 for (const contributionValidity of contributionsValidity) { console.log( - `${contributionValidity ? symbols.success : symbols.error} ${theme.bold( + `${contributionValidity ? theme.symbols.success : theme.symbols.error} ${theme.text.bold( `Circuit` - )} ${theme.bold(theme.magenta(idx + 1))}` + )} ${theme.text.bold(theme.colors.magenta(idx + 1))}` ) idx += 1 } console.log( - `\nWe wanna thank you for your participation in preserving the security for ${theme.bold( + `\nWe wanna thank you for your participation in preserving the security for ${theme.text.bold( ceremony.data.title - )} Trusted Setup ceremony ${emojis.pray}` + )} Trusted Setup ceremony ${theme.emojis.pray}` ) } else console.log( - `\nYou have not successfully contributed to any of the ${theme.bold( - theme.magenta(circuits.length) - )} circuits ${emojis.upsideDown}` + `\nYou have not successfully contributed to any of the ${theme.text.bold( + theme.colors.magenta(circuits.length) + )} circuits ${theme.emojis.upsideDown}` ) // Graceful exit. diff --git a/packages/phase2cli/src/commands/finalize.ts b/packages/phase2cli/src/commands/finalize.ts index ddf203e4..a8973493 100644 --- a/packages/phase2cli/src/commands/finalize.ts +++ b/packages/phase2cli/src/commands/finalize.ts @@ -17,9 +17,10 @@ import { checkAndPrepareCoordinatorForFinalization, finalizeLastContribution, finalizeCeremony, - isCoordinator + isCoordinator, + commonTerms, + solidityVersion } from "@zkmpc/actions" -import { collections, emojis, solidityVersion, symbols, theme } from "../lib/constants" import { COMMAND_ERRORS, GENERIC_ERRORS, showError } from "../lib/errors" import { askForCeremonySelection, getEntropyOrBeacon } from "../lib/prompts" import { customSpinner, getLocalFilePath, makeContribution, publishGist, sleep, terminate } from "../lib/utils" @@ -34,6 +35,7 @@ import { verificationKeysLocalFolderPath, verifierContractsLocalFolderPath } from "../lib/paths" +import theme from "../lib/theme" /** * Finalize command. @@ -53,7 +55,7 @@ const finalize = async () => { const closedCeremoniesDocs = await getClosedCeremonies(firestoreDatabase) console.log( - `${symbols.warning} The computation of the final contribution could take the bulk of your computational resources and memory based on the size of the circuit ${emojis.fire}\n` + `${theme.symbols.warning} The computation of the final contribution could take the bulk of your computational resources and memory based on the size of the circuit ${theme.emojis.fire}\n` ) // Ask to select a ceremony. @@ -62,7 +64,7 @@ const finalize = async () => { // Get coordinator participant document. const participantDoc = await getDocumentById( firestoreDatabase, - `${collections.ceremonies}/${ceremony.id}/${collections.participants}`, + `${commonTerms.collections.ceremonies.name}/${ceremony.id}/${commonTerms.collections.participants.name}`, user.uid ) @@ -82,7 +84,7 @@ const finalize = async () => { // Handle random beacon request/generation. const beacon = await getEntropyOrBeacon(false) const beaconHashStr = crypto.createHash("sha256").update(beacon).digest("hex") - console.log(`${symbols.info} Your final beacon hash: ${theme.bold(beaconHashStr)}`) + console.log(`${theme.symbols.info} Your final beacon hash: ${theme.text.bold(beaconHashStr)}`) // Get ceremony circuits. const circuits = await getCeremonyCircuits(firestoreDatabase, ceremony.id) @@ -99,7 +101,7 @@ const finalize = async () => { // Paths config. const finalZkeyLocalPath = `${finalZkeysLocalFolderPath}/${circuit.data.prefix}_final.zkey` const verificationKeyLocalPath = `${verificationKeysLocalFolderPath}/${circuit.data.prefix}_vkey.json` - const verificationKeyStoragePath = `${collections.circuits}/${circuit.data.prefix}/${circuit.data.prefix}_vkey.json` + const verificationKeyStoragePath = `${commonTerms.collections.circuits.name}/${circuit.data.prefix}/${circuit.data.prefix}_vkey.json` const spinner = customSpinner(`Extracting verification key...`, "clock") spinner.start() @@ -131,7 +133,7 @@ const finalize = async () => { // 7. Turn the verifier into a smart contract. const verifierContractLocalPath = `${verifierContractsLocalFolderPath}/${circuit.data.name}_verifier.sol` - const verifierContractStoragePath = `${collections.circuits}/${circuit.data.prefix}/${circuit.data.prefix}_verifier.sol` + const verifierContractStoragePath = `${commonTerms.collections.circuits.name}/${circuit.data.prefix}/${circuit.data.prefix}_verifier.sol` spinner.text = `Extracting verifier contract...` spinner.start() @@ -190,7 +192,9 @@ const finalize = async () => { await finalizeCeremony(firebaseFunctions, ceremony.id) spinner.succeed( - `Congrats, you have correctly finalized the ${theme.bold(ceremony.data.title)} circuits ${emojis.tada}\n` + `Congrats, you have correctly finalized the ${theme.text.bold(ceremony.data.title)} circuits ${ + theme.emojis.tada + }\n` ) spinner.text = `Generating public finalization attestation...` @@ -239,8 +243,8 @@ const finalize = async () => { const gistUrl = await publishGist(token, attestation, ceremony.data.prefix, ceremony.data.title) spinner.succeed( - `Public finalization attestation successfully published as Github Gist at this link ${theme.bold( - theme.underlined(gistUrl) + `Public finalization attestation successfully published as Github Gist at this link ${theme.text.bold( + theme.text.underlined(gistUrl) )}` ) @@ -249,8 +253,8 @@ const finalize = async () => { console.log( `\nYou can tweet about the ceremony finalization if you'd like (click on the link below ${ - emojis.pointDown - }) \n\n${theme.underlined(attestationTweet)}` + theme.emojis.pointDown + }) \n\n${theme.text.underlined(attestationTweet)}` ) await open(attestationTweet) diff --git a/packages/phase2cli/src/commands/logout.ts b/packages/phase2cli/src/commands/logout.ts index a903ba6d..21fa2668 100644 --- a/packages/phase2cli/src/commands/logout.ts +++ b/packages/phase2cli/src/commands/logout.ts @@ -3,11 +3,11 @@ import { getAuth, signOut } from "firebase/auth" import { checkAuth } from "../lib/authorization" import { bootstrapCommandExecutionAndServices } from "../lib/commands" -import { emojis, symbols, theme } from "../lib/constants" import { showError } from "../lib/errors" import { deleteLocalAccessToken } from "../lib/localStorage" import { askForConfirmation } from "../lib/prompts" import { customSpinner } from "../lib/utils" +import theme from "../lib/theme" /** * Logout command. @@ -22,13 +22,13 @@ const logout = async () => { // Inform the user about deassociation in Github and re run auth console.log( - `${symbols.warning} We do not use any Github access token for authentication; thus we cannot revoke the authorization from your Github account for this CLI application` + `${theme.symbols.warning} We do not use any Github access token for authentication; thus we cannot revoke the authorization from your Github account for this CLI application` ) console.log( - `${symbols.info} You can do this manually as reported in the official Github documentation ${ - emojis.pointDown - }\n\n${theme.bold( - theme.underlined( + `${theme.symbols.info} You can do this manually as reported in the official Github documentation ${ + theme.emojis.pointDown + }\n\n${theme.text.bold( + theme.text.underlined( `https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/reviewing-your-authorized-applications-oauth` ) )}\n` @@ -49,7 +49,7 @@ const logout = async () => { deleteLocalAccessToken() spinner.stop() - console.log(`${symbols.success} Logout successfully completed ${emojis.wave}`) + console.log(`${theme.symbols.success} Logout successfully completed ${theme.emojis.wave}`) } } catch (err: any) { showError(`Something went wrong: ${err.toString()}`, true) diff --git a/packages/phase2cli/src/commands/observe.ts b/packages/phase2cli/src/commands/observe.ts index 132785a4..1d542c9a 100644 --- a/packages/phase2cli/src/commands/observe.ts +++ b/packages/phase2cli/src/commands/observe.ts @@ -13,9 +13,9 @@ import { FirebaseDocumentInfo } from "../../types/index" import { convertToDoubleDigits, customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils" import { askForCeremonySelection } from "../lib/prompts" import { COMMAND_ERRORS, GENERIC_ERRORS, showError } from "../lib/errors" -import { theme, emojis, symbols, observationWaitingTimeInMillis } from "../lib/constants" import { bootstrapCommandExecutionAndServices } from "../lib/commands" import { checkAuth } from "../lib/authorization" +import theme from "../lib/theme" /** * Clean cursor lines from current position back to root (default: zero). @@ -47,7 +47,7 @@ const displayLatestCircuitUpdates = async ( ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo ): Promise => { - let observation = theme.bold(`- Circuit # ${theme.magenta(circuit.data.sequencePosition)}`) // Observation output. + let observation = theme.text.bold(`- Circuit # ${theme.colors.magenta(circuit.data.sequencePosition)}`) // Observation output. let cursorPos = -1 // Current cursor position (nb. decrease every time there's a new line!). const { waitingQueue } = circuit.data @@ -57,7 +57,7 @@ const displayLatestCircuitUpdates = async ( const { completedContributions } = waitingQueue if (!currentContributor) { - observation += `\n> Nobody's currently waiting to contribute ${emojis.eyes}` + observation += `\n> Nobody's currently waiting to contribute ${theme.emojis.eyes}` cursorPos -= 1 } else { // Search for currentContributor' contribution. @@ -70,16 +70,16 @@ const displayLatestCircuitUpdates = async ( if (!contributions.length) { // The contributor is currently contributing. - observation += `\n> Participant ${theme.bold(`#${completedContributions + 1}`)} (${theme.bold( + observation += `\n> Participant ${theme.text.bold(`#${completedContributions + 1}`)} (${theme.text.bold( currentContributor - )}) is currently contributing ${emojis.fire}` + )}) is currently contributing ${theme.emojis.fire}` cursorPos -= 1 } else { // The contributor has contributed. - observation += `\n> Participant ${theme.bold(`#${completedContributions}`)} (${theme.bold( + observation += `\n> Participant ${theme.text.bold(`#${completedContributions}`)} (${theme.text.bold( currentContributor - )}) has completed the contribution ${emojis.tada}` + )}) has completed the contribution ${theme.emojis.tada}` cursorPos -= 1 @@ -100,20 +100,20 @@ const displayLatestCircuitUpdates = async ( hours: verificationTimeHours } = getSecondsMinutesHoursFromMillis(contributionData?.verificationComputationTime) - observation += `\n> The ${theme.bold("computation")} took ${theme.bold( + observation += `\n> The ${theme.text.bold("computation")} took ${theme.text.bold( `${convertToDoubleDigits(contributionTimeHours)}:${convertToDoubleDigits( contributionTimeMinutes )}:${convertToDoubleDigits(contributionTimeSeconds)}` )}` - observation += `\n> The ${theme.bold("verification")} took ${theme.bold( + observation += `\n> The ${theme.text.bold("verification")} took ${theme.text.bold( `${convertToDoubleDigits(verificationTimeHours)}:${convertToDoubleDigits( verificationTimeMinutes )}:${convertToDoubleDigits(verificationTimeSeconds)}` )}` observation += `\n> Contribution ${ contributionData?.valid - ? `${theme.bold("VALID")} ${symbols.success}` - : `${theme.bold("INVALID")} ${symbols.error}` + ? `${theme.text.bold("VALID")} ${theme.symbols.success}` + : `${theme.text.bold("INVALID")} ${theme.symbols.error}` }` cursorPos -= 3 @@ -131,6 +131,8 @@ const displayLatestCircuitUpdates = async ( * Observe command. */ const observe = async () => { + // @todo to be moved as command configuration parameter. + const observationWaitingTimeInMillis = 3000 try { // Initialize services. const { firebaseApp, firestoreDatabase } = await bootstrapCommandExecutionAndServices() diff --git a/packages/phase2cli/src/commands/setup.ts b/packages/phase2cli/src/commands/setup.ts index 8944ff3c..97c83f58 100644 --- a/packages/phase2cli/src/commands/setup.ts +++ b/packages/phase2cli/src/commands/setup.ts @@ -21,17 +21,12 @@ import { getFileStats, readFile, isCoordinator, - filterDirectoryFilesByExtension -} from "@zkmpc/actions" -import { - theme, - symbols, - emojis, + filterDirectoryFilesByExtension, + commonTerms, potFilenameTemplate, - potDownloadUrlTemplate, - names, - firstZkeyIndex -} from "../lib/constants" + genesisZkeyIndex, + potFileDownloadMainUrl +} from "@zkmpc/actions" import { convertToDoubleDigits, createCustomLoggerForFile, @@ -72,6 +67,7 @@ import { setupLocalFolderPath, zkeysLocalFolderPath } from "../lib/paths" +import theme from "../lib/theme" /** * Setup command. @@ -103,9 +99,13 @@ const setup = async () => { const cwd = process.cwd() console.log( - `${symbols.warning} To setup a zkSNARK Groth16 Phase 2 Trusted Setup ceremony you need to have the Rank-1 Constraint System (R1CS) file for each circuit in your working directory` + `${theme.symbols.warning} To setup a zkSNARK Groth16 Phase 2 Trusted Setup ceremony you need to have the Rank-1 Constraint System (R1CS) file for each circuit in your working directory` + ) + console.log( + `\n${theme.symbols.info} Your current working directory is ${theme.text.bold( + theme.text.underlined(process.cwd()) + )}\n` ) - console.log(`\n${symbols.info} Your current working directory is ${theme.bold(theme.underlined(process.cwd()))}\n`) // Look for R1CS files. const r1csFilePaths = await filterDirectoryFilesByExtension(cwd, `.r1cs`) @@ -148,7 +148,7 @@ const setup = async () => { while (wannaAddAnotherCircuit) { // Gather information about the ceremony circuits. - console.log(theme.bold(`\n- Circuit # ${theme.magenta(`${circuitSequencePosition}`)}\n`)) + console.log(theme.text.bold(`\n- Circuit # ${theme.colors.magenta(`${circuitSequencePosition}`)}\n`)) // Select one circuit among cwd circuits identified by R1CS files. const choosenCircuitFilename = await promptCircuitSelector(options) @@ -164,7 +164,9 @@ const setup = async () => { const circuitPrefix = extractPrefix(circuitName) // R1CS circuit file path. - const r1csMetadataLocalFilePath = getMetdataLocalFilePath(`${circuitPrefix}_${names.metadata}.log`) + const r1csMetadataLocalFilePath = getMetdataLocalFilePath( + `${circuitPrefix}_${commonTerms.foldersAndPathsTerms.metadata}.log` + ) const r1csCWDFilePath = getCWDFilePath(cwd, choosenCircuitFilename) // Prepare a custom logger for R1CS metadata store (from snarkjs console to file). @@ -219,13 +221,15 @@ const setup = async () => { await simpleLoader(`Summarizing your ceremony...`, `clock`, 2000) // Display ceremony summary. - let summary = `${`${theme.bold(ceremonyInputData.title)}\n${theme.italic(ceremonyInputData.description)}`} - \n${`Opening: ${theme.bold( - theme.underlined(ceremonyInputData.startDate.toUTCString().replace("GMT", "UTC")) - )}\nEnding: ${theme.bold(theme.underlined(ceremonyInputData.endDate.toUTCString().replace("GMT", "UTC")))}`} - \n${theme.bold( + let summary = `${`${theme.text.bold(ceremonyInputData.title)}\n${theme.text.italic(ceremonyInputData.description)}`} + \n${`Opening: ${theme.text.bold( + theme.text.underlined(ceremonyInputData.startDate.toUTCString().replace("GMT", "UTC")) + )}\nEnding: ${theme.text.bold( + theme.text.underlined(ceremonyInputData.endDate.toUTCString().replace("GMT", "UTC")) + )}`} + \n${theme.text.bold( ceremonyInputData.timeoutMechanismType === CeremonyTimeoutType.DYNAMIC ? `Dynamic` : `Fixed` - )} Timeout / ${theme.bold(ceremonyInputData.penalty)}m Penalty` + )} Timeout / ${theme.text.bold(ceremonyInputData.penalty)}m Penalty` for (let i = 0; i < circuitsInputData.length; i += 1) { const circuitInputData = circuitsInputData[i] @@ -261,30 +265,30 @@ const setup = async () => { }) // Append circuit summary. - summary += `\n\n${theme.bold( - `- CIRCUIT # ${theme.bold(theme.magenta(`${circuitInputData.sequencePosition}`))}` + summary += `\n\n${theme.text.bold( + `- CIRCUIT # ${theme.text.bold(theme.colors.magenta(`${circuitInputData.sequencePosition}`))}` )} - \n${`${theme.bold(circuitInputData.name)}\n${theme.italic(circuitInputData.description)} - \nCurve: ${theme.bold(curve)}\nCompiler: ${theme.bold(`${circuitInputData.compiler.version}`)} (${theme.bold( - circuitInputData.compiler.commitHash?.slice(0, 7) - )})\nSource: ${theme.bold(circuitInputData.template.externalReference.split(`/`).at(-1))}(${theme.bold( - circuitInputData.template.configuration - )})\n${ + \n${`${theme.text.bold(circuitInputData.name)}\n${theme.text.italic(circuitInputData.description)} + \nCurve: ${theme.text.bold(curve)}\nCompiler: ${theme.text.bold( + `${circuitInputData.compiler.version}` + )} (${theme.text.bold(circuitInputData.compiler.commitHash?.slice(0, 7))})\nSource: ${theme.text.bold( + circuitInputData.template.externalReference.split(`/`).at(-1) + )}(${theme.text.bold(circuitInputData.template.configuration)})\n${ ceremonyInputData.timeoutMechanismType === CeremonyTimeoutType.DYNAMIC - ? `Threshold: ${theme.bold(circuitInputData.dynamicThreshold)}%` - : `Max Contribution Time: ${theme.bold(circuitInputData.fixedTimeWindow)}m` + ? `Threshold: ${theme.text.bold(circuitInputData.dynamicThreshold)}%` + : `Max Contribution Time: ${theme.text.bold(circuitInputData.fixedTimeWindow)}m` } - \n# Wires: ${theme.bold(wires)}\n# Constraints: ${theme.bold(constraints)}\n# Private Inputs: ${theme.bold( - privateInputs - )}\n# Public Inputs: ${theme.bold(publicInputs)}\n# Labels: ${theme.bold(labels)}\n# Outputs: ${theme.bold( - outputs - )}\n# PoT: ${theme.bold(pot)}`}` + \n# Wires: ${theme.text.bold(wires)}\n# Constraints: ${theme.text.bold( + constraints + )}\n# Private Inputs: ${theme.text.bold(privateInputs)}\n# Public Inputs: ${theme.text.bold( + publicInputs + )}\n# Labels: ${theme.text.bold(labels)}\n# Outputs: ${theme.text.bold(outputs)}\n# PoT: ${theme.text.bold(pot)}`}` } // Show ceremony summary. console.log( boxen(summary, { - title: theme.magenta(`CEREMONY SUMMARY`), + title: theme.colors.magenta(`CEREMONY SUMMARY`), titleAlignment: "center", textAlignment: "left", margin: 1, @@ -305,7 +309,9 @@ const setup = async () => { for (let i = 0; i < circuits.length; i += 1) { const circuit = circuits[i] - console.log(theme.bold(`\n- Setup for Circuit # ${theme.magenta(`${circuit.sequencePosition}`)}\n`)) + console.log( + theme.text.bold(`\n- Setup for Circuit # ${theme.colors.magenta(`${circuit.sequencePosition}`)}\n`) + ) // Convert to double digits powers (e.g., 9 -> 09). let doubleDigitsPowers = convertToDoubleDigits(circuit.metadata.pot) @@ -313,7 +319,7 @@ const setup = async () => { // Rename R1Cs and zKey based on circuit name and prefix. const r1csCompleteFilename = `${circuit.name}.r1cs` - const firstZkeyCompleteFilename = `${circuit.prefix}_${firstZkeyIndex}.zkey` + const firstZkeyCompleteFilename = `${circuit.prefix}_${genesisZkeyIndex}.zkey` let preComputedZkeyCompleteFilename = `` // Local. @@ -328,7 +334,7 @@ const setup = async () => { if (leftPreComputedZkeys.length <= 0) console.log( - `${symbols.warning} No pre-computed zKey was found. Therefore, a new zKey from scratch will be generated.` + `${theme.symbols.warning} No pre-computed zKey was found. Therefore, a new zKey from scratch will be generated.` ) else { // Prompt if coordinator wanna use a pre-computed zKey for the circuit. @@ -395,28 +401,30 @@ const setup = async () => { .map((dirent: Dirent) => dirent.name) if (appropriatePotFiles.length <= 0 || !wannaUsePreDownloadedPoT) { - spinner.text = `Downloading the ${theme.bold( + spinner.text = `Downloading the ${theme.text.bold( `#${doubleDigitsPowers}` )} PoT from the Hermez Cryptography Phase 1 Trusted Setup...` spinner.start() // Prepare for downloading. - const potDownloadUrl = `${potDownloadUrlTemplate}${smallestPowersOfTauForCircuit}` + const potDownloadUrl = `${potFileDownloadMainUrl}${smallestPowersOfTauForCircuit}` const destFilePath = getPotLocalFilePath(smallestPowersOfTauForCircuit) // Download Powers of Tau file from remote server. await downloadFileFromUrl(destFilePath, potDownloadUrl) - spinner.succeed(`Powers of tau ${theme.bold(`#${doubleDigitsPowers}`)} downloaded successfully`) + spinner.succeed(`Powers of tau ${theme.text.bold(`#${doubleDigitsPowers}`)} downloaded successfully`) } else console.log( - `${symbols.success} Powers of Tau ${theme.bold(`#${doubleDigitsPowers}`)} already downloaded` + `${theme.symbols.success} Powers of Tau ${theme.text.bold( + `#${doubleDigitsPowers}` + )} already downloaded` ) // Check to avoid to upload a wrong combination of R1CS, PoT and pre-computed zKey file. if (!wannaGenerateNewZkey) { console.log( - `${symbols.info} Checking the pre-computed zKey locally on your machine (to avoid any R1CS, PoT, zKey combination errors)` + `${theme.symbols.info} Checking the pre-computed zKey locally on your machine (to avoid any R1CS, PoT, zKey combination errors)` ) // Verification. @@ -430,7 +438,7 @@ const setup = async () => { await sleep(3000) // workaround for unexpected file descriptor close. if (valid) { - console.log(`${symbols.success} The pre-computed zKey you have provided is valid`) + console.log(`${theme.symbols.success} The pre-computed zKey you have provided is valid`) // Update the pre-computed zKey list of options. leftPreComputedZkeys = leftPreComputedZkeys.filter( @@ -443,7 +451,7 @@ const setup = async () => { // Update local path. zkeyLocalPathAndFileName = getCWDFilePath(cwd, firstZkeyCompleteFilename) } else { - console.log(`${symbols.error} The pre-computed zKey you have provided is invalid`) + console.log(`${theme.symbols.error} The pre-computed zKey you have provided is invalid`) // Prompt to generate a new zKey from scratch. const newZkeyGeneration = await promptZkeyGeneration() @@ -456,8 +464,8 @@ const setup = async () => { // Generate a brand new zKey from scratch. if (wannaGenerateNewZkey) { console.log( - `${symbols.info} The computation of your brand new zKey is starting soon.\n${theme.bold( - `${symbols.warning} Be careful, stopping the process will result in the loss of all progress achieved so far.` + `${theme.symbols.info} The computation of your brand new zKey is starting soon.\n${theme.text.bold( + `${theme.symbols.warning} Be careful, stopping the process will result in the loss of all progress achieved so far.` )}` ) @@ -465,7 +473,7 @@ const setup = async () => { await zKey.newZKey(r1csLocalPathAndFileName, potLocalPathAndFileName, zkeyLocalPathAndFileName, console) console.log( - `\n${symbols.success} Generation of genesis zKey (${theme.bold( + `\n${theme.symbols.success} Generation of genesis zKey (${theme.text.bold( firstZkeyCompleteFilename )}) completed successfully` ) @@ -499,7 +507,7 @@ const setup = async () => { ) spinner.succeed( - `Upload of genesis zKey (${theme.bold(firstZkeyCompleteFilename)}) file completed successfully` + `Upload of genesis zKey (${theme.text.bold(firstZkeyCompleteFilename)}) file completed successfully` ) // PoT. @@ -507,7 +515,7 @@ const setup = async () => { const alreadyUploadedPot = await objectExist( firebaseFunctions, bucketName, - `${ceremonyPrefix}/${names.pot}/${smallestPowersOfTauForCircuit}` + `${ceremonyPrefix}/${commonTerms.foldersAndPathsTerms.pot}/${smallestPowersOfTauForCircuit}` ) if (!alreadyUploadedPot) { @@ -525,11 +533,13 @@ const setup = async () => { ) spinner.succeed( - `Upload of Powers of Tau (${theme.bold(smallestPowersOfTauForCircuit)}) file completed successfully` + `Upload of Powers of Tau (${theme.text.bold( + smallestPowersOfTauForCircuit + )}) file completed successfully` ) } else console.log( - `${symbols.success} The Powers of Tau (${theme.bold( + `${theme.symbols.success} The Powers of Tau (${theme.text.bold( smallestPowersOfTauForCircuit )}) file is already saved in the storage` ) @@ -547,7 +557,7 @@ const setup = async () => { process.env.CONFIG_PRESIGNED_URL_EXPIRATION_IN_SECONDS || 7200 ) - spinner.succeed(`Upload of R1CS (${theme.bold(r1csCompleteFilename)}) file completed successfully`) + spinner.succeed(`Upload of R1CS (${theme.text.bold(r1csCompleteFilename)}) file completed successfully`) /** FIRESTORE DB */ const circuitFiles: CircuitFiles = { @@ -596,10 +606,10 @@ const setup = async () => { await sleep(3000) // Cloud function termination workaround. spinner.succeed( - `Congratulations, the setup of ceremony ${theme.bold( + `Congratulations, the setup of ceremony ${theme.text.bold( ceremonyInputData.title )} has been successfully completed ${ - emojis.tada + theme.emojis.tada }. You will be able to find all the files and info respectively in the ceremony bucket and database document.` ) } diff --git a/packages/phase2cli/src/lib/authorization.ts b/packages/phase2cli/src/lib/authorization.ts index a131ce03..5bd17e64 100644 --- a/packages/phase2cli/src/lib/authorization.ts +++ b/packages/phase2cli/src/lib/authorization.ts @@ -6,10 +6,10 @@ import { OAuthCredential } from "firebase/auth" import open from "open" import clipboard from "clipboardy" import { AuthUser } from "../../types" -import { theme, emojis, symbols } from "./constants" import { showError, GENERIC_ERRORS, GITHUB_ERRORS, FIREBASE_ERRORS } from "./errors" import { checkLocalAccessToken, deleteLocalAccessToken, getLocalAccessToken } from "./localStorage" import { exchangeGithubTokenForCredentials, getGithubUserHandle } from "./utils" +import theme from "./theme" /** * Execute the sign in to Firebase using OAuth credentials. @@ -32,7 +32,7 @@ export const signInToFirebase = async (firebaseApp: FirebaseApp, credentials: OA // Inform user. console.log( - `${symbols.info} We have successfully removed your local token to make you able to repeat the authorization process once again. Please, run the auth command again whenever you are ready and complete the association with the CLI application.` + `${theme.symbols.info} We have successfully removed your local token to make you able to repeat the authorization process once again. Please, run the auth command again whenever you are ready and complete the association with the CLI application.` ) // Gracefully exit. @@ -85,8 +85,8 @@ const expirationCountdownForGithubOAuth = (expirationInSeconds: number) => { // Notify user. process.stdout.write( - `${symbols.warning} Expires in ${theme.bold( - theme.magenta(`00:${Math.floor(expirationInSeconds / 60)}:${secondsCounter}`) + `${theme.symbols.warning} Expires in ${theme.text.bold( + theme.colors.magenta(`00:${Math.floor(expirationInSeconds / 60)}:${secondsCounter}`) )}\r` ) } else { @@ -110,13 +110,13 @@ export const onVerification = async (verification: Verification): Promise // Display data. console.log( - `${symbols.warning} Visit ${theme.bold( - theme.underlined(verification.verification_uri) + `${theme.symbols.warning} Visit ${theme.text.bold( + theme.text.underlined(verification.verification_uri) )} on this device to authenticate` ) console.log( - `${symbols.info} Your auth code: ${theme.bold(verification.user_code)} (${emojis.clipboard} ${ - symbols.success + `${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} (${theme.emojis.clipboard} ${ + theme.symbols.success })\n` ) @@ -183,7 +183,7 @@ export const checkAuth = async (firebaseApp: FirebaseApp): Promise => const githubUserHandle = await getGithubUserHandle(String(token)) // Greet the user. - console.log(`Greetings, @${theme.bold(theme.bold(githubUserHandle))} ${emojis.wave}\n`) + console.log(`Greetings, @${theme.text.bold(githubUserHandle)} ${theme.emojis.wave}\n`) return { user, diff --git a/packages/phase2cli/src/lib/commands.ts b/packages/phase2cli/src/lib/commands.ts index 4d79f0e7..e6ac34fe 100644 --- a/packages/phase2cli/src/lib/commands.ts +++ b/packages/phase2cli/src/lib/commands.ts @@ -2,8 +2,8 @@ import { initializeFirebaseCoreServices } from "@zkmpc/actions" import figlet from "figlet" import { FirebaseServices } from "packages/actions/types" import clear from "clear" -import { theme } from "./constants" import { showError, CONFIG_ERRORS } from "./errors" +import theme from "./theme" /** * Bootstrap whatever is needed for a new command execution and related services. @@ -14,7 +14,7 @@ export const bootstrapCommandExecutionAndServices = async (): Promise { // Print the error. - console.error(`${symbols.error} ${err}`) + console.error(`${theme.symbols.error} ${err}`) // Terminate the process. if (doExit) process.exit(0) diff --git a/packages/phase2cli/src/lib/listeners.ts b/packages/phase2cli/src/lib/listeners.ts index d0b72420..2544084b 100644 --- a/packages/phase2cli/src/lib/listeners.ts +++ b/packages/phase2cli/src/lib/listeners.ts @@ -10,10 +10,10 @@ import { resumeContributionAfterTimeoutExpiration, formatZkeyIndex, getZkeysSpaceRequirementsForContributionInGB, - convertToGB + convertToGB, + commonTerms } from "@zkmpc/actions" import { FirebaseDocumentInfo, ParticipantContributionStep, ParticipantStatus } from "../../types/index" -import { collections, emojis, symbols, theme } from "./constants" import { convertToDoubleDigits, customSpinner, @@ -28,6 +28,7 @@ import { } from "./utils" import { GENERIC_ERRORS, showError } from "./errors" import { askForConfirmation } from "./prompts" +import theme from "./theme" /** * Return the available disk space of the current contributor in GB. @@ -61,20 +62,22 @@ const handleDiskSpaceRequirementForNextContribution = async ( // Check memory requirement. if (availableDiskSpaceInGB < zKeysSpaceRequirementsInGB) { - console.log(theme.bold(`- Circuit # ${theme.magenta(`${sequencePosition}`)}`)) + console.log(theme.text.bold(`- Circuit # ${theme.colors.magenta(`${sequencePosition}`)}`)) console.log( - `${symbols.error} You do not have enough memory to make a contribution (Required ${ - zKeysSpaceRequirementsInGB < 0.01 ? theme.bold(`< 0.01`) : theme.bold(zKeysSpaceRequirementsInGB) + `${theme.symbols.error} You do not have enough memory to make a contribution (Required ${ + zKeysSpaceRequirementsInGB < 0.01 + ? theme.text.bold(`< 0.01`) + : theme.text.bold(zKeysSpaceRequirementsInGB) } GB (available ${ - availableDiskSpaceInGB > 0 ? theme.bold(availableDiskSpaceInGB.toFixed(2)) : theme.bold(0) + availableDiskSpaceInGB > 0 ? theme.text.bold(availableDiskSpaceInGB.toFixed(2)) : theme.text.bold(0) } GB)\n` ) if (sequencePosition > 1) { // The user has computed at least one valid contribution. Therefore, can choose if free up memory and contrinue with next contribution or generate the final attestation. console.log( - `${symbols.info} You have time until ceremony ends to free up your memory, complete contributions and publish the attestation` + `${theme.symbols.info} You have time until ceremony ends to free up your memory, complete contributions and publish the attestation` ) const { confirmation } = await askForConfirmation( @@ -93,13 +96,13 @@ const handleDiskSpaceRequirementForNextContribution = async ( } } else { console.log( - `${symbols.success} You have enough memory for contributing to ${theme.bold( - `Circuit ${theme.magenta(sequencePosition)}` + `${theme.symbols.success} You have enough memory for contributing to ${theme.text.bold( + `Circuit ${theme.colors.magenta(sequencePosition)}` )}` ) const spinner = customSpinner( - `Joining ${theme.bold(`Circuit ${theme.magenta(sequencePosition)}`)} waiting queue...`, + `Joining ${theme.text.bold(`Circuit ${theme.colors.magenta(sequencePosition)}`)} waiting queue...`, `clock` ) spinner.start() @@ -108,7 +111,9 @@ const handleDiskSpaceRequirementForNextContribution = async ( await makeProgressToNextContribution(functions, ceremonyId) else await resumeContributionAfterTimeoutExpiration(functions, ceremonyId) - spinner.succeed(`All set for contribution to ${theme.bold(`Circuit ${theme.magenta(sequencePosition)}`)}`) + spinner.succeed( + `All set for contribution to ${theme.text.bold(`Circuit ${theme.colors.magenta(sequencePosition)}`)}` + ) return false } @@ -152,7 +157,7 @@ const listenToCircuitChanges = ( // Retrieve current contributor data. const currentContributorDoc = await getDocumentById( firestoreDatabase, - `${collections.ceremonies}/${ceremonyId}/${collections.participants}`, + `${commonTerms.collections.ceremonies.name}/${ceremonyId}/${commonTerms.collections.participants.name}`, currentContributor ) @@ -179,21 +184,21 @@ const listenToCircuitChanges = ( // Check if is the current contributor. if (newParticipantPositionInQueue === 1) { console.log( - `\n${symbols.success} Your turn has come ${emojis.tada}\n${symbols.info} Your contribution will begin soon` + `\n${theme.symbols.success} Your turn has come ${theme.emojis.tada}\n${theme.symbols.info} Your contribution will begin soon` ) unsubscriberForCircuitDocument() } else { // Position and time. console.log( - `\n${symbols.info} ${ + `\n${theme.symbols.info} ${ newParticipantPositionInQueue === 2 ? `You are the next contributor` - : `Your position in the waiting queue is ${theme.bold( - theme.magenta(newParticipantPositionInQueue - 1) + : `Your position in the waiting queue is ${theme.text.bold( + theme.colors.magenta(newParticipantPositionInQueue - 1) )}` } (${ newEstimatedWaitingTime > 0 - ? `${theme.bold( + ? `${theme.text.bold( `${convertToDoubleDigits(estHours)}:${convertToDoubleDigits( estMinutes )}:${convertToDoubleDigits(estSeconds)}` @@ -203,7 +208,7 @@ const listenToCircuitChanges = ( ) // Participant data. - console.log(` - Contributor # ${theme.bold(theme.magenta(completedContributions + 1))}`) + console.log(` - Contributor # ${theme.text.bold(theme.colors.magenta(completedContributions + 1))}`) // Data for displaying info about steps. const currentZkeyIndex = formatZkeyIndex(completedContributions) @@ -231,7 +236,7 @@ const listenToCircuitChanges = ( switch (contributionStep) { case ParticipantContributionStep.DOWNLOADING: { - const message = ` ${symbols.info} Downloading contribution ${theme.bold( + const message = ` ${theme.symbols.info} Downloading contribution ${theme.text.bold( `#${currentZkeyIndex}` )}` interval = simpleCountdown(remainingTime, message) @@ -240,12 +245,12 @@ const listenToCircuitChanges = ( } case ParticipantContributionStep.COMPUTING: { process.stdout.write( - ` ${symbols.success} Contribution ${theme.bold( + ` ${theme.symbols.success} Contribution ${theme.text.bold( `#${currentZkeyIndex}` )} correctly downloaded\n` ) - const message = ` ${symbols.info} Computing contribution ${theme.bold( + const message = ` ${theme.symbols.info} Computing contribution ${theme.text.bold( `#${nextZkeyIndex}` )}` interval = simpleCountdown(remainingTime, message) @@ -254,12 +259,12 @@ const listenToCircuitChanges = ( } case ParticipantContributionStep.UPLOADING: { process.stdout.write( - ` ${symbols.success} Contribution ${theme.bold( + ` ${theme.symbols.success} Contribution ${theme.text.bold( `#${nextZkeyIndex}` )} successfully computed\n` ) - const message = ` ${symbols.info} Uploading contribution ${theme.bold( + const message = ` ${theme.symbols.info} Uploading contribution ${theme.text.bold( `#${nextZkeyIndex}` )}` interval = simpleCountdown(remainingTime, message) @@ -268,12 +273,12 @@ const listenToCircuitChanges = ( } case ParticipantContributionStep.VERIFYING: { process.stdout.write( - ` ${symbols.success} Contribution ${theme.bold( + ` ${theme.symbols.success} Contribution ${theme.text.bold( `#${nextZkeyIndex}` )} successfully uploaded\n` ) - const message = ` ${symbols.info} Contribution verification ${theme.bold( + const message = ` ${theme.symbols.info} Contribution verification ${theme.text.bold( `#${nextZkeyIndex}` )}` interval = simpleCountdown(remainingTime, message) @@ -282,7 +287,7 @@ const listenToCircuitChanges = ( } case ParticipantContributionStep.COMPLETED: { process.stdout.write( - ` ${symbols.success} Contribution ${theme.bold( + ` ${theme.symbols.success} Contribution ${theme.text.bold( `#${nextZkeyIndex}` )} has been correctly verified\n` ) @@ -295,16 +300,20 @@ const listenToCircuitChanges = ( ) if (currentContributorContributions.length !== 1) - process.stdout.write(` ${symbols.error} We could not recover the contribution data`) + process.stdout.write( + ` ${theme.symbols.error} We could not recover the contribution data` + ) else { const contribution = currentContributorContributions.at(0) const data = contribution?.data console.log( - ` ${data?.valid ? symbols.success : symbols.error} Contribution ${theme.bold( - `#${nextZkeyIndex}` - )} is ${data?.valid ? `VALID` : `INVALID`}` + ` ${ + data?.valid ? theme.symbols.success : theme.symbols.error + } Contribution ${theme.text.bold(`#${nextZkeyIndex}`)} is ${ + data?.valid ? `VALID` : `INVALID` + }` ) } @@ -407,8 +416,8 @@ export default async ( // A.1 If the participant is in `waiting` status, he/she must receive updates from the circuit's waiting queue. if (status === ParticipantStatus.WAITING && oldStatus !== ParticipantStatus.TIMEDOUT) { console.log( - `${theme.bold( - `\n- Circuit # ${theme.magenta(`${circuit.data.sequencePosition}`)}` + `${theme.text.bold( + `\n- Circuit # ${theme.colors.magenta(`${circuit.data.sequencePosition}`)}` )} (Waiting Queue)` ) @@ -422,9 +431,9 @@ export default async ( isStepValidForStartingOrResumingContribution ) { console.log( - `\n${symbols.success} Your contribution will ${ + `\n${theme.symbols.success} Your contribution will ${ contributionStep === ParticipantContributionStep.DOWNLOADING ? `start` : `resume` - } soon ${emojis.clock}` + } soon ${theme.emojis.clock}` ) // Compute the contribution. @@ -460,22 +469,28 @@ export default async ( const estRemainingTimeInMillis = avgVerifyCloudFunctionTime - (Date.now() - verificationStartedAt) const { seconds, minutes, hours } = getSecondsMinutesHoursFromMillis(estRemainingTimeInMillis) - spinner.succeed(`Your contribution will resume soon ${emojis.clock}`) + spinner.succeed(`Your contribution will resume soon ${theme.emojis.clock}`) console.log( - `${theme.bold( - `\n- Circuit # ${theme.magenta(`${circuit.data.sequencePosition}`)}` + `${theme.text.bold( + `\n- Circuit # ${theme.colors.magenta(`${circuit.data.sequencePosition}`)}` )} (Contribution Steps)` ) console.log( - `${symbols.success} Contribution ${theme.bold(`#${currentZkeyIndex}`)} already downloaded` + `${theme.symbols.success} Contribution ${theme.text.bold( + `#${currentZkeyIndex}` + )} already downloaded` + ) + console.log( + `${theme.symbols.success} Contribution ${theme.text.bold(`#${nextZkeyIndex}`)} already computed` ) - console.log(`${symbols.success} Contribution ${theme.bold(`#${nextZkeyIndex}`)} already computed`) console.log( - `${symbols.success} Contribution ${theme.bold(`#${nextZkeyIndex}`)} already saved on storage` + `${theme.symbols.success} Contribution ${theme.text.bold( + `#${nextZkeyIndex}` + )} already saved on storage` ) console.log( - `${symbols.info} Contribution verification already started (est. time ${theme.bold( + `${theme.symbols.info} Contribution verification already started (est. time ${theme.text.bold( `${convertToDoubleDigits(hours)}:${convertToDoubleDigits(minutes)}:${convertToDoubleDigits( seconds )}` @@ -490,7 +505,7 @@ export default async ( oldContributionProgress === contributionProgress - 1 && contributionStep === ParticipantContributionStep.COMPLETED ) { - console.log(`\n${symbols.success} Contribute verification has been completed`) + console.log(`\n${theme.symbols.success} Contribute verification has been completed`) // Return true and false based on contribution verification. const contributionsValidity = await getContributorContributionsVerificationResults( @@ -505,8 +520,8 @@ export default async ( const isContributionValid = contributionsValidity[oldContributionProgress - 1] console.log( - `${isContributionValid ? symbols.success : symbols.error} Your contribution ${ - isContributionValid ? `is ${theme.bold("VALID")}` : `is ${theme.bold("INVALID")}` + `${isContributionValid ? theme.symbols.success : theme.symbols.error} Your contribution ${ + isContributionValid ? `is ${theme.text.bold("VALID")}` : `is ${theme.text.bold("INVALID")}` }` ) } diff --git a/packages/phase2cli/src/lib/paths.ts b/packages/phase2cli/src/lib/paths.ts index a7c7f1b7..7f277e20 100644 --- a/packages/phase2cli/src/lib/paths.ts +++ b/packages/phase2cli/src/lib/paths.ts @@ -1,23 +1,22 @@ -import { terms } from "@zkmpc/actions" -import { collections } from "./constants" +import { commonTerms } from "@zkmpc/actions" /** LOCAL PATHS */ -export const outputLocalFolderPath = `./${terms.output}` -export const setupLocalFolderPath = `${outputLocalFolderPath}/${terms.setup}` -export const contributeLocalFolderPath = `${outputLocalFolderPath}/${terms.contribute}` -export const finalizeLocalFolderPath = `${outputLocalFolderPath}/${terms.finalize}` -export const potLocalFolderPath = `${setupLocalFolderPath}/${terms.pot}` -export const zkeysLocalFolderPath = `${setupLocalFolderPath}/${terms.zkeys}` -export const metadataLocalFolderPath = `${setupLocalFolderPath}/${terms.metadata}` -export const contributionsLocalFolderPath = `${contributeLocalFolderPath}/${terms.zkeys}` -export const contributionTranscriptsLocalFolderPath = `${contributeLocalFolderPath}/${terms.transcripts}` -export const attestationLocalFolderPath = `${contributeLocalFolderPath}/${terms.attestation}` -export const finalZkeysLocalFolderPath = `${finalizeLocalFolderPath}/${terms.zkeys}` -export const finalPotLocalFolderPath = `${finalizeLocalFolderPath}/${terms.pot}` -export const finalTranscriptsLocalFolderPath = `${finalizeLocalFolderPath}/${terms.transcripts}` -export const finalAttestationsLocalFolderPath = `${finalizeLocalFolderPath}/${terms.attestation}` -export const verificationKeysLocalFolderPath = `${finalizeLocalFolderPath}/${terms.vkeys}` -export const verifierContractsLocalFolderPath = `${finalizeLocalFolderPath}/${terms.verifiers}` +export const outputLocalFolderPath = `./${commonTerms.output}` +export const setupLocalFolderPath = `${outputLocalFolderPath}/${commonTerms.setup}` +export const contributeLocalFolderPath = `${outputLocalFolderPath}/${commonTerms.contribute}` +export const finalizeLocalFolderPath = `${outputLocalFolderPath}/${commonTerms.finalize}` +export const potLocalFolderPath = `${setupLocalFolderPath}/${commonTerms.pot}` +export const zkeysLocalFolderPath = `${setupLocalFolderPath}/${commonTerms.zkeys}` +export const metadataLocalFolderPath = `${setupLocalFolderPath}/${commonTerms.metadata}` +export const contributionsLocalFolderPath = `${contributeLocalFolderPath}/${commonTerms.zkeys}` +export const contributionTranscriptsLocalFolderPath = `${contributeLocalFolderPath}/${commonTerms.transcripts}` +export const attestationLocalFolderPath = `${contributeLocalFolderPath}/${commonTerms.attestation}` +export const finalZkeysLocalFolderPath = `${finalizeLocalFolderPath}/${commonTerms.zkeys}` +export const finalPotLocalFolderPath = `${finalizeLocalFolderPath}/${commonTerms.pot}` +export const finalTranscriptsLocalFolderPath = `${finalizeLocalFolderPath}/${commonTerms.transcripts}` +export const finalAttestationsLocalFolderPath = `${finalizeLocalFolderPath}/${commonTerms.attestation}` +export const verificationKeysLocalFolderPath = `${finalizeLocalFolderPath}/${commonTerms.vkeys}` +export const verifierContractsLocalFolderPath = `${finalizeLocalFolderPath}/${commonTerms.verifiers}` export const getCWDFilePath = (cwd: string, completeFilename: string): string => `${cwd}/${completeFilename}` export const getMetdataLocalFilePath = (completeFilename: string): string => @@ -36,7 +35,7 @@ export const getZkeysLocalFilePath = (completeFilename: string): string => `${zk * @returns - the storage path of the R1CS file. */ export const getR1csStorageFilePath = (circuitPrefix: string, completeR1csFilename: string): string => - `${collections.circuits}/${circuitPrefix}/${completeR1csFilename}` + `${commonTerms.collections.circuits.name}/${circuitPrefix}/${completeR1csFilename}` /** * Get PoT file path in the storage. @@ -45,7 +44,8 @@ export const getR1csStorageFilePath = (circuitPrefix: string, completeR1csFilena * @param completePotFilename - the complete PoT filename (name + ext). * @returns - the storage path of the PoT file. */ -export const getPotStorageFilePath = (completePotFilename: string): string => `${terms.pot}/${completePotFilename}` +export const getPotStorageFilePath = (completePotFilename: string): string => + `${commonTerms.foldersAndPathsTerms.pot}/${completePotFilename}` /** * Get zKey file path tied to a particular circuit of a ceremony in the storage. @@ -55,4 +55,4 @@ export const getPotStorageFilePath = (completePotFilename: string): string => `$ * @returns - the storage path of the zKey file. */ export const getZkeyStorageFilePath = (circuitPrefix: string, completeZkeyFilename: string): string => - `${collections.circuits}/${circuitPrefix}/${collections.contributions}/${completeZkeyFilename}` + `${commonTerms.collections.circuits.name}/${circuitPrefix}/${commonTerms.collections.contributions.name}/${completeZkeyFilename}` diff --git a/packages/phase2cli/src/lib/prompts.ts b/packages/phase2cli/src/lib/prompts.ts index 55fa383c..24e4bdc3 100644 --- a/packages/phase2cli/src/lib/prompts.ts +++ b/packages/phase2cli/src/lib/prompts.ts @@ -8,10 +8,10 @@ import { CircuitInputData, FirebaseDocumentInfo } from "../../types/index" -import { symbols, theme } from "./constants" import { COMMAND_ERRORS, GENERIC_ERRORS, showError } from "./errors" import { customSpinner } from "./utils" import { getAllCeremoniesDocuments } from "./queries" +import theme from "./theme" /** * Ask a binary (yes/no or true/false) customizable question. @@ -24,7 +24,7 @@ export const askForConfirmation = async (question: string, active = "yes", inact prompts({ type: "toggle", name: "confirmation", - message: theme.bold(question), + message: theme.text.bold(question), initial: false, active, inactive @@ -46,14 +46,16 @@ export const promptCeremonyInputData = async (firestore: Firestore): Promise { if (title.length <= 0) - return theme.red(`${symbols.error} Please, enter a non-empty string as the name of the ceremony`) + return theme.colors.red( + `${theme.symbols.error} Please, enter a non-empty string as the name of the ceremony` + ) // Check if the current name matches one of the already used prefixes. if (prefixesAlreadyInUse.includes(extractPrefix(title))) - return theme.red(`${symbols.error} The name is already in use for another ceremony`) + return theme.colors.red(`${theme.symbols.error} The name is already in use for another ceremony`) return true } @@ -61,19 +63,21 @@ export const promptCeremonyInputData = async (firestore: Firestore): Promise title.length > 0 || - theme.red(`${symbols.error} Please, enter a non-empty string as the description of the ceremony`) + theme.colors.red( + `${theme.symbols.error} Please, enter a non-empty string as the description of the ceremony` + ) }, { type: "date", name: "startDate", - message: theme.bold(`When should the ceremony open for contributions?`), + message: theme.text.bold(`When should the ceremony open for contributions?`), validate: (d: any) => new Date(d).valueOf() > Date.now() ? true - : theme.red(`${symbols.error} Please, enter a date subsequent to current date`) + : theme.colors.red(`${theme.symbols.error} Please, enter a date subsequent to current date`) } ] // Prompt questions. @@ -85,11 +89,11 @@ export const promptCeremonyInputData = async (firestore: Firestore): Promise new Date(d).valueOf() > new Date(startDate).valueOf() ? true - : theme.red(`${symbols.error} Please, enter a date subsequent to starting date`) + : theme.colors.red(`${theme.symbols.error} Please, enter a date subsequent to starting date`) }) if (!endDate) showError(COMMAND_ERRORS.COMMAND_ABORT_PROMPT, true) @@ -100,7 +104,7 @@ export const promptCeremonyInputData = async (firestore: Firestore): Promise { - if (pnlt < 1) return theme.red(`${symbols.error} Please, enter a penalty at least one minute long`) + if (pnlt < 1) + return theme.colors.red(`${theme.symbols.error} Please, enter a penalty at least one minute long`) return true } @@ -154,10 +159,12 @@ export const promptCircomCompiler = async (): Promise => { { type: "text", name: "version", - message: theme.bold(`Circom compiler version (x.y.z)`), + message: theme.text.bold(`Circom compiler version (x.y.z)`), validate: (version: string) => { if (version.length <= 0 || !version.match(/^[0-9].[0-9.].[0-9]$/)) - return theme.red(`${symbols.error} Please, provide a valid Circom compiler version (e.g., 2.0.5)`) + return theme.colors.red( + `${theme.symbols.error} Please, provide a valid Circom compiler version (e.g., 2.0.5)` + ) return true } @@ -165,11 +172,11 @@ export const promptCircomCompiler = async (): Promise => { { type: "text", name: "commitHash", - message: theme.bold(`The hash of the Github commit linked to the version of the Circom compiler`), + message: theme.text.bold(`The hash of the Github commit linked to the version of the Circom compiler`), validate: (commitHash: string) => commitHash.length === 40 || - theme.red( - `${symbols.error} Please, provide a valid commit hash (e.g., b7ad01b11f9b4195e38ecc772291251260ab2c67)` + theme.colors.red( + `${theme.symbols.error} Please, provide a valid commit hash (e.g., b7ad01b11f9b4195e38ecc772291251260ab2c67)` ) } ] @@ -194,7 +201,7 @@ export const promptCircuitSelector = async (options: Array): Promise ({ title: option, value: option })), initial: 0 }) @@ -226,30 +233,32 @@ export const promptCircuitInputData = async ( { type: "text", name: "description", - message: theme.bold(`Short description`), + message: theme.text.bold(`Short description`), validate: (title: string) => title.length > 0 || - theme.red(`${symbols.error} Please, enter a non-empty string as the description of the circuit`) + theme.colors.red( + `${theme.symbols.error} Please, enter a non-empty string as the description of the circuit` + ) }, { name: "externalReference", type: "text", - message: theme.bold(`The external link to the circuit template`), + message: theme.text.bold(`The external link to the circuit template`), validate: (value) => value.length > 0 && value.match(/(https?:\/\/[^\s]+\.circom$)/g) ? true - : theme.red( - `${symbols.error} Please, provide a valid link to the circuit template (e.g., https://github.com/iden3/circomlib/blob/master/circuits/poseidon.circom)` + : theme.colors.red( + `${theme.symbols.error} Please, provide a valid link to the circuit template (e.g., https://github.com/iden3/circomlib/blob/master/circuits/poseidon.circom)` ) }, { name: "templateCommitHash", type: "text", - message: theme.bold(`The hash of the Github commit linked to the circuit template`), + message: theme.text.bold(`The hash of the Github commit linked to the circuit template`), validate: (commitHash: string) => commitHash.length === 40 || - theme.red( - `${symbols.error} Please, provide a valid commit hash (e.g., b7ad01b11f9b4195e38ecc772291251260ab2c67)` + theme.colors.red( + `${theme.symbols.error} Please, provide a valid commit hash (e.g., b7ad01b11f9b4195e38ecc772291251260ab2c67)` ) } ] @@ -273,11 +282,13 @@ export const promptCircuitInputData = async ( const { circuitTemplateValues } = await prompts({ name: "circuitTemplateValues", type: "text", - message: theme.bold(`Circuit template configuration in a comma-separated list of values`), + message: theme.text.bold(`Circuit template configuration in a comma-separated list of values`), validate: (value: string) => (value.split(",").length === 1 && !!value) || (value.split(`,`).length > 1 && value.includes(",")) || - theme.red(`${symbols.error} Please, provide a correct comma-separated list of values (e.g., 10,2,1,2)`) + theme.colors.red( + `${theme.symbols.error} Please, provide a correct comma-separated list of values (e.g., 10,2,1,2)` + ) }) if (circuitTemplateValues === undefined) showError(COMMAND_ERRORS.COMMAND_ABORT_PROMPT, true) @@ -298,13 +309,13 @@ export const promptCircuitInputData = async ( const { dynamicThreshold } = await prompts({ type: "number", name: "dynamicThreshold", - message: theme.bold( + message: theme.text.bold( `The dynamic timeout requires an acceptance threshold (expressed in %) to avoid disqualifying too many contributors for non-critical issues.\nFor example, suppose we set a threshold at 20%. If the average contribution is 10 minutes, the next contributor has 12 minutes to complete download, computation, and upload (verification is NOT included).\nTherefore, assuming it took 11:30 minutes, the next contributor will have (10 + 11:30) / 2 = 10:45 + 20% = 2:15 + 10:45 = 13 minutes total.\nPlease, set your threshold` ), validate: (value: number) => { if (value === undefined || value < 0 || value > 100) - return theme.red( - `${symbols.error} Please, provide a valid threshold selecting a value between [0-100]%. We suggest at least 25%.` + return theme.colors.red( + `${theme.symbols.error} Please, provide a valid threshold selecting a value between [0-100]%. We suggest at least 25%.` ) return true @@ -334,11 +345,12 @@ export const promptCircuitInputData = async ( const { fixedTimeWindow } = await prompts({ type: "number", name: `fixedTimeWindow`, - message: theme.bold( + message: theme.text.bold( `The fixed timeout requires a fixed time window for contribution. Your time window in minutes` ), validate: (value: number) => { - if (value <= 0) return theme.red(`${symbols.error} Please, provide a time window greater than zero`) + if (value <= 0) + return theme.colors.red(`${theme.symbols.error} Please, provide a time window greater than zero`) return true } @@ -424,7 +436,7 @@ export const promptPreComputedZkeySelector = async (options: Array): Pro const { preComputedZkeyFilename } = await prompts({ type: "select", name: "preComputedZkeyFilename", - message: theme.bold("Select the pre-computed zKey file related to the circuit"), + message: theme.text.bold("Select the pre-computed zKey file related to the circuit"), choices: options.map((option: string) => ({ title: option, value: option })), initial: 0 }) @@ -443,12 +455,12 @@ export const promptNeededPowersForCircuit = async (suggestedSmallestNeededPowers const question: PromptObject = { name: "choosenPowers", type: "number", - message: theme.bold(`Specify the amount of Powers of Tau used to generate the pre-computed zKey`), + message: theme.text.bold(`Specify the amount of Powers of Tau used to generate the pre-computed zKey`), validate: (value) => value >= suggestedSmallestNeededPowers && value <= 28 ? true - : theme.red( - `${symbols.error} Please, provide a valid amount of powers selecting a value between [${suggestedSmallestNeededPowers}-28]. ${suggestedSmallestNeededPowers}` + : theme.colors.red( + `${theme.symbols.error} Please, provide a valid amount of powers selecting a value between [${suggestedSmallestNeededPowers}-28]. ${suggestedSmallestNeededPowers}` ) } @@ -471,7 +483,7 @@ export const promptPotSelector = async (options: Array): Promise const { potFilename } = await prompts({ type: "select", name: "potFilename", - message: theme.bold("Select the Powers of Tau file choosen for the circuit"), + message: theme.text.bold("Select the Powers of Tau file choosen for the circuit"), choices: options.map((option: string) => { console.log(option) return { title: option, value: option } @@ -512,10 +524,12 @@ export const askForEntropyOrBeacon = async (askEntropy: boolean): Promise title.length > 0 || - theme.red(`${symbols.error} You must provide a valid value for the ${askEntropy ? `entropy` : `beacon`}!`) + theme.colors.red( + `${theme.symbols.error} You must provide a valid value for the ${askEntropy ? `entropy` : `beacon`}!` + ) }) if (!entropyOrBeacon) showError(GENERIC_ERRORS.GENERIC_DATA_INPUT, true) @@ -572,7 +586,7 @@ export const askForCeremonySelection = async ( choices.push({ title: ceremonyDoc.data.title, - description: `${ceremonyDoc.data.description} (${theme.magenta(daysLeft)} ${ + description: `${ceremonyDoc.data.description} (${theme.colors.magenta(daysLeft)} ${ now - ceremonyDoc.data.endDate < 0 ? `days left` : `days gone since closing` })`, value: ceremonyDoc @@ -583,7 +597,7 @@ export const askForCeremonySelection = async ( const { ceremony } = await prompts({ type: "select", name: "ceremony", - message: theme.bold("Select a ceremony"), + message: theme.text.bold("Select a ceremony"), choices, initial: 0 }) @@ -607,7 +621,7 @@ export const askForCircuitSelectionFromFirebase = async ( for (const circuitDoc of circuitsDocs) { choices.push({ title: `${circuitDoc.data.name}`, - description: `(#${theme.magenta(circuitDoc.data.sequencePosition)}) ${circuitDoc.data.description}`, + description: `(#${theme.colors.magenta(circuitDoc.data.sequencePosition)}) ${circuitDoc.data.description}`, value: circuitDoc }) } @@ -616,7 +630,7 @@ export const askForCircuitSelectionFromFirebase = async ( const { circuit } = await prompts({ type: "select", name: "circuit", - message: theme.bold("Select a circuit"), + message: theme.text.bold("Select a circuit"), choices, initial: 0 }) diff --git a/packages/phase2cli/src/lib/queries.ts b/packages/phase2cli/src/lib/queries.ts index 7b3c69e5..c8f91dbe 100644 --- a/packages/phase2cli/src/lib/queries.ts +++ b/packages/phase2cli/src/lib/queries.ts @@ -1,6 +1,5 @@ import { Firestore, where } from "firebase/firestore" -import { queryCollection, fromQueryToFirebaseDocumentInfo, getAllCollectionDocs } from "@zkmpc/actions" -import { collections, contributionsCollectionFields } from "./constants" +import { queryCollection, fromQueryToFirebaseDocumentInfo, getAllCollectionDocs, commonTerms } from "@zkmpc/actions" import { FirebaseDocumentInfo } from "../../types/index" /** @@ -9,9 +8,9 @@ import { FirebaseDocumentInfo } from "../../types/index" * @returns Promise> */ export const getAllCeremoniesDocuments = async (firestore: Firestore): Promise> => - fromQueryToFirebaseDocumentInfo(await getAllCollectionDocs(firestore, collections.ceremonies)).sort( - (a: FirebaseDocumentInfo, b: FirebaseDocumentInfo) => a.data.sequencePosition - b.data.sequencePosition - ) + fromQueryToFirebaseDocumentInfo( + await getAllCollectionDocs(firestore, commonTerms.collections.ceremonies.name) + ).sort((a: FirebaseDocumentInfo, b: FirebaseDocumentInfo) => a.data.sequencePosition - b.data.sequencePosition) /** * Query for circuits with a contribution from given participant. @@ -29,8 +28,8 @@ export const getCircuitsWithParticipantContribution = async ( for (const circuit of circuits) { const participantContributionQuerySnap = await queryCollection( - `${collections.ceremonies}/${ceremonyId}/${collections.circuits}/${circuit.id}/${collections.contributions}`, - [where(contributionsCollectionFields.participantId, "==", participantId)] + `${commonTerms.collections.ceremonies.name}/${ceremonyId}/${commonTerms.collections.circuits.name}/${circuit.id}/${commonTerms.collections.contributions.name}`, + [where(commonTerms.collections.contributions.fields.participantId, "==", participantId)] ) if (participantContributionQuerySnap.size === 1) circuitsWithContributionIds.push(circuit.id) diff --git a/packages/phase2cli/src/lib/storage.ts b/packages/phase2cli/src/lib/storage.ts index 584e4db2..8b6a2e8b 100644 --- a/packages/phase2cli/src/lib/storage.ts +++ b/packages/phase2cli/src/lib/storage.ts @@ -6,7 +6,7 @@ import { SingleBar, Presets } from "cli-progress" import { generateGetObjectPreSignedUrl, convertToGB } from "@zkmpc/actions" import { ProgressBarType } from "../../types/index" import { GENERIC_ERRORS, showError } from "./errors" -import { emojis, theme } from "./constants" +import theme from "./theme" dotenv.config() @@ -17,10 +17,10 @@ dotenv.config() */ export const customProgressBar = (type: ProgressBarType): SingleBar => { // Formats. - const uploadFormat = `${emojis.arrowUp} Uploading [${theme.magenta( + const uploadFormat = `${theme.emojis.arrowUp} Uploading [${theme.colors.magenta( "{bar}" )}] {percentage}% | {value}/{total} Chunks` - const downloadFormat = `${emojis.arrowDown} Downloading [${theme.magenta( + const downloadFormat = `${theme.emojis.arrowDown} Downloading [${theme.colors.magenta( "{bar}" )}] {percentage}% | {value}/{total} GB` diff --git a/packages/phase2cli/src/lib/theme.ts b/packages/phase2cli/src/lib/theme.ts new file mode 100644 index 00000000..d85b3621 --- /dev/null +++ b/packages/phase2cli/src/lib/theme.ts @@ -0,0 +1,45 @@ +import chalk from "chalk" +import logSymbols from "log-symbols" +import emoji from "node-emoji" + +/** + * Custom theme object. + */ +export default { + colors: { + yellow: chalk.yellow, + magenta: chalk.magenta, + red: chalk.red, + green: chalk.green + }, + text: { + underlined: chalk.underline, + bold: chalk.bold, + italic: chalk.italic + }, + symbols: { + success: logSymbols.success, + warning: logSymbols.warning, + error: logSymbols.error, + info: logSymbols.info + }, + emojis: { + tada: emoji.get("tada"), + key: emoji.get("key"), + broom: emoji.get("broom"), + pointDown: emoji.get("point_down"), + eyes: emoji.get("eyes"), + wave: emoji.get("wave"), + clipboard: emoji.get("clipboard"), + fire: emoji.get("fire"), + clock: emoji.get("hourglass"), + dizzy: emoji.get("dizzy_face"), + rocket: emoji.get("rocket"), + oldKey: emoji.get("old_key"), + pray: emoji.get("pray"), + moon: emoji.get("moon"), + upsideDown: emoji.get("upside_down_face"), + arrowUp: emoji.get("arrow_up"), + arrowDown: emoji.get("arrow_down") + } +} diff --git a/packages/phase2cli/src/lib/utils.ts b/packages/phase2cli/src/lib/utils.ts index 25da817e..db526923 100644 --- a/packages/phase2cli/src/lib/utils.ts +++ b/packages/phase2cli/src/lib/utils.ts @@ -23,7 +23,9 @@ import { readFile, writeFile, readJSONFile, - formatZkeyIndex + formatZkeyIndex, + numExpIterations, + commonTerms } from "@zkmpc/actions" import { fileURLToPath } from "url" import path from "path" @@ -35,7 +37,6 @@ import { Timing, VerifyContributionComputation } from "../../types/index" -import { collections, emojis, numIterationsExp, symbols, theme } from "./constants" import { GENERIC_ERRORS, GITHUB_ERRORS, showError } from "./errors" import { downloadLocalFileFromBucket } from "./storage" import { @@ -45,6 +46,7 @@ import { finalTranscriptsLocalFolderPath, finalZkeysLocalFolderPath } from "./paths" +import theme from "./theme" dotenv.config() @@ -253,7 +255,7 @@ export const convertMillisToSeconds = (millis: number): number => Number((millis * @params ghUsername - the Github username of the user. */ export const terminate = async (ghUsername: string) => { - console.log(`\nSee you, ${theme.bold(`@${ghUsername}`)} ${emojis.wave}`) + console.log(`\nSee you, ${theme.text.bold(`@${ghUsername}`)} ${theme.emojis.wave}`) process.exit(0) } @@ -276,8 +278,8 @@ export const createExpirationCountdown = (durationInSeconds: number, intervalInS if (seconds % 60 === 0) seconds = 0 process.stdout.write( - `${symbols.warning} Expires in ${theme.bold( - theme.magenta(`00:${Math.floor(durationInSeconds / 60)}:${seconds}`) + `${theme.symbols.warning} Expires in ${theme.text.bold( + theme.colors.magenta(`00:${Math.floor(durationInSeconds / 60)}:${seconds}`) )}\r` ) } else showError(GENERIC_ERRORS.GENERIC_COUNTDOWN_EXPIRED, true) @@ -306,7 +308,7 @@ export const simpleCountdown = (remainingTime: number, message: string): NodeJS. } = getSecondsMinutesHoursFromMillis(Math.abs(remainingTime)) process.stdout.write( - `${message} (${remainingTime < 0 ? theme.bold(`-`) : ``}${convertToDoubleDigits( + `${message} (${remainingTime < 0 ? theme.text.bold(`-`) : ``}${convertToDoubleDigits( cdHours )}:${convertToDoubleDigits(cdMinutes)}:${convertToDoubleDigits(cdSeconds)})\r` ) @@ -333,14 +335,14 @@ export const handleTimedoutMessageForContributor = async ( // Check if the contributor has been timedout. if (status === ParticipantStatus.TIMEDOUT && contributionStep !== ParticipantContributionStep.COMPLETED) { - if (!isContributing) console.log(theme.bold(`\n- Circuit # ${theme.magenta(contributionProgress)}`)) + if (!isContributing) console.log(theme.text.bold(`\n- Circuit # ${theme.colors.magenta(contributionProgress)}`)) else process.stdout.write(`\n`) console.log( - `${symbols.error} ${ + `${theme.symbols.error} ${ isContributing ? `You have been timedout while contributing` : `Timeout still in progress.` }\n\n${ - symbols.warning + theme.symbols.warning } This can happen due to network or memory issues, un/intentional crash, or contributions lasting for too long.` ) @@ -361,7 +363,7 @@ export const handleTimedoutMessageForContributor = async ( ) console.log( - `${symbols.info} You can retry your contribution in ${theme.bold( + `${theme.symbols.info} You can retry your contribution in ${theme.text.bold( `${convertToDoubleDigits(days)}:${convertToDoubleDigits(hours)}:${convertToDoubleDigits( minutes )}:${convertToDoubleDigits(seconds)}` @@ -397,7 +399,7 @@ export const computeContribution = async ( // Custom spinner for visual feedback. const text = `${finalize ? `Applying beacon...` : `Computing contribution...`} ${ contributionComputationTime > 0 - ? `(ETA ${theme.bold( + ? `(ETA ${theme.text.bold( `${convertToDoubleDigits(hours)}:${convertToDoubleDigits(minutes)}:${convertToDoubleDigits(seconds)}` )} |` : `` @@ -436,7 +438,7 @@ export const computeContribution = async ( if (finalize) // Finalize applying a random beacon. - await zKey.beacon(lastZkey, newZkey, name, entropyOrBeacon, numIterationsExp, logger) + await zKey.beacon(lastZkey, newZkey, name, entropyOrBeacon, numExpIterations, logger) // Compute the next contribution. else await zKey.contribute(lastZkey, newZkey, name, entropyOrBeacon, logger) @@ -523,9 +525,9 @@ export const generatePublicAttestation = async ( const numberOfValidContributions = contributionsValidity.filter(Boolean).length console.log( - `\nCongrats, you have successfully contributed to ${theme.magenta( - theme.bold(numberOfValidContributions) - )} out of ${theme.magenta(theme.bold(circuits.length))} circuits ${emojis.tada}` + `\nCongrats, you have successfully contributed to ${theme.colors.magenta( + theme.text.bold(numberOfValidContributions) + )} out of ${theme.colors.magenta(theme.text.bold(circuits.length))} circuits ${theme.emojis.tada}` ) // Show valid/invalid contributions per each circuit. @@ -533,9 +535,9 @@ export const generatePublicAttestation = async ( for (const contributionValidity of contributionsValidity) { console.log( - `${contributionValidity ? symbols.success : symbols.error} ${theme.bold(`Circuit`)} ${theme.bold( - theme.magenta(idx + 1) - )}` + `${contributionValidity ? theme.symbols.success : theme.symbols.error} ${theme.text.bold( + `Circuit` + )} ${theme.text.bold(theme.colors.magenta(idx + 1))}` ) idx += 1 } @@ -564,7 +566,9 @@ export const generatePublicAttestation = async ( const gistUrl = await publishGist(ghToken, attestation, ceremonyDoc.data.prefix, ceremonyDoc.data.title) spinner.succeed( - `Public attestation successfully published as Github Gist at this link ${theme.bold(theme.underlined(gistUrl))}` + `Public attestation successfully published as Github Gist at this link ${theme.text.bold( + theme.text.underlined(gistUrl) + )}` ) // Attestation link via Twitter. @@ -572,10 +576,10 @@ export const generatePublicAttestation = async ( console.log( `\nWe appreciate your contribution to preserving the ${ceremonyDoc.data.title} security! ${ - emojis.key + theme.emojis.key } You can tweet about your participation if you'd like (click on the link below ${ - emojis.pointDown - }) \n\n${theme.underlined(attestationTweet)}` + theme.emojis.pointDown + }) \n\n${theme.text.underlined(attestationTweet)}` ) await open(attestationTweet) @@ -653,7 +657,7 @@ export const computeVerification = async ( const spinner = customSpinner( `Verifying your contribution... ${ avgVerifyCloudFunctionTime > 0 - ? `(est. time ${theme.bold( + ? `(est. time ${theme.text.bold( `${convertToDoubleDigits(hours)}:${convertToDoubleDigits(minutes)}:${convertToDoubleDigits( seconds )}` @@ -734,7 +738,9 @@ export const makeContribution = async ( ) console.log( - `${theme.bold(`\n- Circuit # ${theme.magenta(`${circuit.data.sequencePosition}`)}`)} (Contribution Steps)` + `${theme.text.bold( + `\n- Circuit # ${theme.colors.magenta(`${circuit.data.sequencePosition}`)}` + )} (Contribution Steps)` ) if ( @@ -746,18 +752,23 @@ export const makeContribution = async ( spinner.start() // 1. Download last contribution. - const storagePath = `${collections.circuits}/${circuit.data.prefix}/${collections.contributions}/${circuit.data.prefix}_${currentZkeyIndex}.zkey` + const storagePath = `${commonTerms.collections.circuits.name}/${circuit.data.prefix}/${commonTerms.collections.contributions.name}/${circuit.data.prefix}_${currentZkeyIndex}.zkey` const localPath = `${contributionsPath}/${circuit.data.prefix}_${currentZkeyIndex}.zkey` spinner.stop() await downloadContribution(firebaseFunctions, bucketName, storagePath, localPath, false) - console.log(`${symbols.success} Contribution ${theme.bold(`#${currentZkeyIndex}`)} correctly downloaded`) + console.log( + `${theme.symbols.success} Contribution ${theme.text.bold(`#${currentZkeyIndex}`)} correctly downloaded` + ) // Make the step if not finalizing. if (!finalize) await makeContributionStepProgress(firebaseFunctions!, ceremony.id, true, "computation") - } else console.log(`${symbols.success} Contribution ${theme.bold(`#${currentZkeyIndex}`)} already downloaded`) + } else + console.log( + `${theme.symbols.success} Contribution ${theme.text.bold(`#${currentZkeyIndex}`)} already downloaded` + ) if ( finalize || @@ -814,8 +825,8 @@ export const makeContribution = async ( spinner.succeed( `${ - finalize ? "Contribution" : `Contribution ${theme.bold(`#${nextZkeyIndex}`)}` - } computation took ${theme.bold( + finalize ? "Contribution" : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}` + } computation took ${theme.text.bold( `${convertToDoubleDigits(computationHours)}:${convertToDoubleDigits( computationMinutes )}:${convertToDoubleDigits(computationSeconds)}` @@ -824,7 +835,7 @@ export const makeContribution = async ( // Make the step if not finalizing. if (!finalize) await makeContributionStepProgress(firebaseFunctions!, ceremony.id, true, "upload") - } else console.log(`${symbols.success} Contribution ${theme.bold(`#${nextZkeyIndex}`)} already computed`) + } else console.log(`${theme.symbols.success} Contribution ${theme.text.bold(`#${nextZkeyIndex}`)} already computed`) if ( finalize || @@ -834,12 +845,15 @@ export const makeContribution = async ( newParticipantData?.contributionStep === ParticipantContributionStep.UPLOADING ) { // 3. Store file. - const storagePath = `${collections.circuits}/${circuit.data.prefix}/${collections.contributions}/${ - circuit.data.prefix - }_${finalize ? `final` : nextZkeyIndex}.zkey` + const storagePath = `${commonTerms.collections.circuits.name}/${circuit.data.prefix}/${ + commonTerms.collections.contributions.name + }/${circuit.data.prefix}_${finalize ? `final` : nextZkeyIndex}.zkey` const localPath = `${contributionsPath}/${circuit.data.prefix}_${finalize ? `final` : nextZkeyIndex}.zkey` - const spinner = customSpinner(`Storing contribution ${theme.bold(`#${nextZkeyIndex}`)} to storage...`, `clock`) + const spinner = customSpinner( + `Storing contribution ${theme.text.bold(`#${nextZkeyIndex}`)} to storage...`, + `clock` + ) spinner.start() // Upload. @@ -866,7 +880,7 @@ export const makeContribution = async ( spinner.succeed( `${ - finalize ? `Contribution` : `Contribution ${theme.bold(`#${nextZkeyIndex}`)}` + finalize ? `Contribution` : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}` } correctly saved on storage` ) @@ -874,8 +888,8 @@ export const makeContribution = async ( if (!finalize) await makeContributionStepProgress(firebaseFunctions!, ceremony.id, true, "verification") } else console.log( - `${symbols.success} ${ - finalize ? `Contribution` : `Contribution ${theme.bold(`#${nextZkeyIndex}`)}` + `${theme.symbols.success} ${ + finalize ? `Contribution` : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}` } already saved on storage` ) @@ -903,14 +917,14 @@ export const makeContribution = async ( } = getSecondsMinutesHoursFromMillis(verifyCloudFunctionTime) console.log( - `${valid ? symbols.success : symbols.error} ${ - finalize ? `Contribution` : `Contribution ${theme.bold(`#${nextZkeyIndex}`)}` - } ${valid ? `is ${theme.bold("VALID")}` : `is ${theme.bold("INVALID")}`}` + `${valid ? theme.symbols.success : theme.symbols.error} ${ + finalize ? `Contribution` : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}` + } ${valid ? `is ${theme.text.bold("VALID")}` : `is ${theme.text.bold("INVALID")}`}` ) console.log( - `${symbols.success} ${ - finalize ? `Contribution` : `Contribution ${theme.bold(`#${nextZkeyIndex}`)}` - } verification took ${theme.bold( + `${theme.symbols.success} ${ + finalize ? `Contribution` : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}` + } verification took ${theme.text.bold( `${convertToDoubleDigits(verificationHours)}:${convertToDoubleDigits( verificationMinutes )}:${convertToDoubleDigits(verificationSeconds)}` @@ -923,7 +937,7 @@ export const makeContribution = async ( hours: contributionHours } = getSecondsMinutesHoursFromMillis(fullContributionTime + verifyCloudFunctionTime) console.log( - `${symbols.info} Your contribution took ${theme.bold( + `${theme.symbols.info} Your contribution took ${theme.text.bold( `${convertToDoubleDigits(contributionHours)}:${convertToDoubleDigits( contributionMinutes )}:${convertToDoubleDigits(contributionSeconds)}`