@devtion/devcli 0.0.0-3c7b092 → 0.0.0-3df1645
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +64 -33
- package/package.json +2 -2
- package/src/commands/auth.ts +20 -9
- package/src/commands/contribute.ts +4 -2
- package/src/commands/finalize.ts +5 -1
- package/src/commands/index.ts +1 -1
- package/src/commands/listCeremonies.ts +1 -2
- package/src/commands/observe.ts +1 -1
- package/src/commands/setup.ts +40 -19
- package/src/commands/validate.ts +1 -2
- package/src/index.ts +15 -8
- package/src/lib/prompts.ts +12 -11
- package/src/lib/services.ts +0 -2
- package/src/lib/utils.ts +37 -5
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
* @module @
|
|
5
|
-
* @version 1.0.
|
|
4
|
+
* @module @p0tion/phase2cli
|
|
5
|
+
* @version 1.0.9
|
|
6
6
|
* @file All-in-one interactive command-line for interfacing with zkSNARK Phase 2 Trusted Setup ceremonies
|
|
7
7
|
* @copyright Ethereum Foundation 2022
|
|
8
8
|
* @license MIT
|
|
@@ -585,8 +585,18 @@ const publishGist = async (token, content, ceremonyTitle, ceremonyPrefix) => {
|
|
|
585
585
|
* @returns <string> - the ready to share tweet url.
|
|
586
586
|
*/
|
|
587
587
|
const generateCustomUrlToTweetAboutParticipation = (ceremonyName, gistUrl, isFinalizing) => isFinalizing
|
|
588
|
-
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") ||
|
|
589
|
-
|
|
588
|
+
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") ||
|
|
589
|
+
ceremonyName.toLowerCase().includes("setup") ||
|
|
590
|
+
ceremonyName.toLowerCase().includes("phase2") ||
|
|
591
|
+
ceremonyName.toLowerCase().includes("ceremony")
|
|
592
|
+
? "!"
|
|
593
|
+
: "%20Phase%202%20Trusted%20Setup%20ceremony!"}%20You%20can%20view%20my%20final%20attestation%20here:%20${gistUrl}%20#Ethereum%20#ZKP%20#PSE`
|
|
594
|
+
: `https://twitter.com/intent/tweet?text=I%20contributed%20to%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") ||
|
|
595
|
+
ceremonyName.toLowerCase().includes("setup") ||
|
|
596
|
+
ceremonyName.toLowerCase().includes("phase2") ||
|
|
597
|
+
ceremonyName.toLowerCase().includes("ceremony")
|
|
598
|
+
? "!"
|
|
599
|
+
: "%20Phase%202%20Trusted%20Setup%20ceremony!"}%20You%20can%20view%20the%20steps%20to%20contribute%20here:%20https://ceremony.pse.dev%20You%20can%20view%20my%20attestation%20here:%20${gistUrl}%20#Ethereum%20#ZKP`;
|
|
590
600
|
/**
|
|
591
601
|
* Return a custom progress bar.
|
|
592
602
|
* @param type <ProgressBarType> - the type of the progress bar.
|
|
@@ -767,6 +777,7 @@ const handleStartOrResumeContribution = async (cloudFunctions, firestoreDatabase
|
|
|
767
777
|
// Download the latest contribution from bucket.
|
|
768
778
|
await downloadCeremonyArtifact(cloudFunctions, bucketName, lastZkeyStorageFilePath, lastZkeyLocalFilePath);
|
|
769
779
|
console.log(`${theme.symbols.success} Contribution ${theme.text.bold(`#${lastZkeyIndex}`)} correctly downloaded`);
|
|
780
|
+
await sleep(3000);
|
|
770
781
|
// Advance to next contribution step (COMPUTING) if not finalizing.
|
|
771
782
|
if (!isFinalizing) {
|
|
772
783
|
spinner.text = `Preparing for contribution computation...`;
|
|
@@ -794,11 +805,14 @@ const handleStartOrResumeContribution = async (cloudFunctions, firestoreDatabase
|
|
|
794
805
|
showError(COMMAND_ERRORS.COMMAND_CONTRIBUTE_FINALIZE_NO_TRANSCRIPT_CONTRIBUTION_HASH_MATCH, true);
|
|
795
806
|
// Format contribution hash.
|
|
796
807
|
const contributionHash = matchContributionHash?.at(0)?.replace("\n\t\t", "");
|
|
808
|
+
await sleep(500);
|
|
797
809
|
// Make request to cloud functions to permanently store the information.
|
|
798
810
|
await permanentlyStoreCurrentContributionTimeAndHash(cloudFunctions, ceremony.id, computingTime, contributionHash);
|
|
799
811
|
// Format computing time.
|
|
800
812
|
const { seconds: computationSeconds, minutes: computationMinutes, hours: computationHours } = getSecondsMinutesHoursFromMillis(computingTime);
|
|
801
813
|
spinner.succeed(`${isFinalizing ? "Contribution" : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}`} computation took ${theme.text.bold(`${convertToDoubleDigits(computationHours)}:${convertToDoubleDigits(computationMinutes)}:${convertToDoubleDigits(computationSeconds)}`)}`);
|
|
814
|
+
// ensure the previous step is completed
|
|
815
|
+
await sleep(5000);
|
|
802
816
|
// Advance to next contribution step (UPLOADING) if not finalizing.
|
|
803
817
|
if (!isFinalizing) {
|
|
804
818
|
spinner.text = `Preparing for uploading the contribution...`;
|
|
@@ -816,10 +830,15 @@ const handleStartOrResumeContribution = async (cloudFunctions, firestoreDatabase
|
|
|
816
830
|
if (isFinalizing || participantData.contributionStep === "UPLOADING" /* ParticipantContributionStep.UPLOADING */) {
|
|
817
831
|
spinner.text = `Uploading ${isFinalizing ? "final" : "your"} contribution ${!isFinalizing ? theme.text.bold(`#${nextZkeyIndex}`) : ""} to storage.\n${theme.symbols.warning} This step may take a while based on circuit size and your internet speed. Everything's fine, just be patient.`;
|
|
818
832
|
spinner.start();
|
|
819
|
-
|
|
820
|
-
|
|
833
|
+
const progressBar = customProgressBar(ProgressBarType.UPLOAD, `your contribution`);
|
|
834
|
+
if (!isFinalizing) {
|
|
835
|
+
await multiPartUpload(cloudFunctions, bucketName, nextZkeyStorageFilePath, nextZkeyLocalFilePath, Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB), ceremony.id, participantData.tempContributionData, progressBar);
|
|
836
|
+
progressBar.stop();
|
|
837
|
+
}
|
|
821
838
|
else
|
|
822
839
|
await multiPartUpload(cloudFunctions, bucketName, nextZkeyStorageFilePath, nextZkeyLocalFilePath, Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB));
|
|
840
|
+
// small sleep to ensure the previous step is completed
|
|
841
|
+
await sleep(5000);
|
|
823
842
|
spinner.succeed(`${isFinalizing ? `Contribution` : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}`} correctly saved to storage`);
|
|
824
843
|
// Advance to next contribution step (VERIFYING) if not finalizing.
|
|
825
844
|
if (!isFinalizing) {
|
|
@@ -1125,7 +1144,7 @@ const promptCircuitInputData = async (constraintSize, timeoutMechanismType, same
|
|
|
1125
1144
|
let circomVersion = "";
|
|
1126
1145
|
let circomCommitHash = "";
|
|
1127
1146
|
let circuitInputData;
|
|
1128
|
-
let
|
|
1147
|
+
let cfOrVm;
|
|
1129
1148
|
let vmDiskType;
|
|
1130
1149
|
let vmConfigurationType = "";
|
|
1131
1150
|
const questions = [
|
|
@@ -1185,13 +1204,16 @@ const promptCircuitInputData = async (constraintSize, timeoutMechanismType, same
|
|
|
1185
1204
|
const { confirmation } = await askForConfirmation(`The contribution verification can be performed using Cloud Functions (CF, cheaper for small contributions but limited to 1M constraints) or custom virtual machines (expensive but could scale up to 30M constraints). Be aware about VM costs and if you wanna learn more, please visit the documentation to have a complete overview about cost estimation of the two mechanisms.\nChoose the contribution verification mechanism`, `CF`, // eq. true.
|
|
1186
1205
|
`VM` // eq. false.
|
|
1187
1206
|
);
|
|
1188
|
-
|
|
1207
|
+
cfOrVm = confirmation
|
|
1208
|
+
? "CF" /* CircuitContributionVerificationMechanism.CF */
|
|
1209
|
+
: "VM" /* CircuitContributionVerificationMechanism.VM */;
|
|
1189
1210
|
}
|
|
1190
|
-
else
|
|
1191
|
-
|
|
1192
|
-
|
|
1211
|
+
else {
|
|
1212
|
+
cfOrVm = "VM" /* CircuitContributionVerificationMechanism.VM */;
|
|
1213
|
+
}
|
|
1214
|
+
if (cfOrVm === undefined)
|
|
1193
1215
|
showError(COMMAND_ERRORS.COMMAND_ABORT_PROMPT, true);
|
|
1194
|
-
if (
|
|
1216
|
+
if (cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */) {
|
|
1195
1217
|
// Ask for selecting the specific VM configuration type.
|
|
1196
1218
|
vmConfigurationType = await promptVMTypeSelector(constraintSize);
|
|
1197
1219
|
// Ask for selecting the specific VM disk (volume) type.
|
|
@@ -1225,9 +1247,7 @@ const promptCircuitInputData = async (constraintSize, timeoutMechanismType, same
|
|
|
1225
1247
|
paramsConfiguration: circuitConfigurationValues
|
|
1226
1248
|
},
|
|
1227
1249
|
verification: {
|
|
1228
|
-
cfOrVm
|
|
1229
|
-
? "CF" /* CircuitContributionVerificationMechanism.CF */
|
|
1230
|
-
: "VM" /* CircuitContributionVerificationMechanism.VM */,
|
|
1250
|
+
cfOrVm,
|
|
1231
1251
|
vm: {
|
|
1232
1252
|
vmConfigurationType,
|
|
1233
1253
|
vmDiskType
|
|
@@ -1263,9 +1283,7 @@ const promptCircuitInputData = async (constraintSize, timeoutMechanismType, same
|
|
|
1263
1283
|
paramsConfiguration: circuitConfigurationValues
|
|
1264
1284
|
},
|
|
1265
1285
|
verification: {
|
|
1266
|
-
cfOrVm
|
|
1267
|
-
? "CF" /* CircuitContributionVerificationMechanism.CF */
|
|
1268
|
-
: "VM" /* CircuitContributionVerificationMechanism.VM */,
|
|
1286
|
+
cfOrVm,
|
|
1269
1287
|
vm: {
|
|
1270
1288
|
vmConfigurationType,
|
|
1271
1289
|
vmDiskType
|
|
@@ -1831,7 +1849,9 @@ const setup = async (cmd) => {
|
|
|
1831
1849
|
let ceremonyId = ""; // The unique identifier of the ceremony.
|
|
1832
1850
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices();
|
|
1833
1851
|
// Check for authentication.
|
|
1834
|
-
const { user, providerUserId } = cmd.auth
|
|
1852
|
+
const { user, providerUserId } = cmd.auth
|
|
1853
|
+
? await authWithToken(firebaseApp, cmd.auth)
|
|
1854
|
+
: await checkAuth(firebaseApp);
|
|
1835
1855
|
// Preserve command execution only for coordinators.
|
|
1836
1856
|
if (!(await isCoordinator(user)))
|
|
1837
1857
|
showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true);
|
|
@@ -1848,7 +1868,7 @@ const setup = async (cmd) => {
|
|
|
1848
1868
|
// if there is the file option, then set up the non interactively
|
|
1849
1869
|
if (cmd.template) {
|
|
1850
1870
|
// 1. parse the file
|
|
1851
|
-
// tmp data - do not cleanup files as we need them
|
|
1871
|
+
// tmp data - do not cleanup files as we need them
|
|
1852
1872
|
const spinner = customSpinner(`Parsing ${theme.text.bold(cmd.template)} setup configuration file...`, `clock`);
|
|
1853
1873
|
spinner.start();
|
|
1854
1874
|
const setupCeremonyData = await parseCeremonyFile(cmd.template);
|
|
@@ -2104,17 +2124,29 @@ const expirationCountdownForGithubOAuth = (expirationInSeconds) => {
|
|
|
2104
2124
|
*/
|
|
2105
2125
|
const onVerification = async (verification) => {
|
|
2106
2126
|
// Copy code to clipboard.
|
|
2107
|
-
|
|
2108
|
-
|
|
2127
|
+
let noClipboard = false;
|
|
2128
|
+
try {
|
|
2129
|
+
clipboard.writeSync(verification.user_code);
|
|
2130
|
+
clipboard.readSync();
|
|
2131
|
+
}
|
|
2132
|
+
catch (error) {
|
|
2133
|
+
noClipboard = true;
|
|
2134
|
+
}
|
|
2109
2135
|
// Display data.
|
|
2110
2136
|
console.log(`${theme.symbols.warning} Visit ${theme.text.bold(theme.text.underlined(verification.verification_uri))} on this device to generate a new token and authenticate\n`);
|
|
2111
|
-
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })),
|
|
2112
|
-
|
|
2137
|
+
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })), "\n");
|
|
2138
|
+
const message = !noClipboard ? `has been copied to your clipboard (${theme.emojis.clipboard})` : ``;
|
|
2139
|
+
console.log(`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} ${message} ${theme.symbols.success})\n`);
|
|
2113
2140
|
const spinner = customSpinner(`Redirecting to Github...`, `clock`);
|
|
2114
2141
|
spinner.start();
|
|
2115
2142
|
await sleep(10000); // ~10s to make users able to read the CLI.
|
|
2116
|
-
|
|
2117
|
-
|
|
2143
|
+
try {
|
|
2144
|
+
// Automatically open the page (# Step 2).
|
|
2145
|
+
await open(verification.verification_uri);
|
|
2146
|
+
}
|
|
2147
|
+
catch (error) {
|
|
2148
|
+
console.log(`${theme.symbols.info} Please authenticate via GitHub at ${verification.verification_uri}`);
|
|
2149
|
+
}
|
|
2118
2150
|
spinner.stop();
|
|
2119
2151
|
// Countdown for time expiration.
|
|
2120
2152
|
expirationCountdownForGithubOAuth(verification.expires_in);
|
|
@@ -2610,7 +2642,9 @@ const listenToParticipantDocumentChanges = async (firestoreDatabase, cloudFuncti
|
|
|
2610
2642
|
// Get latest contribution verification result.
|
|
2611
2643
|
await getLatestVerificationResult(firestoreDatabase, ceremony.id, circuit.id, participant.id);
|
|
2612
2644
|
// Get next circuit for contribution.
|
|
2613
|
-
const nextCircuit = timeoutExpired
|
|
2645
|
+
const nextCircuit = timeoutExpired
|
|
2646
|
+
? getCircuitBySequencePosition(circuits, changedContributionProgress)
|
|
2647
|
+
: getCircuitBySequencePosition(circuits, changedContributionProgress + 1);
|
|
2614
2648
|
// Check disk space requirements for participant.
|
|
2615
2649
|
const wannaGenerateAttestation = await handleDiskSpaceRequirementForNextContribution(cloudFunctions, ceremony.id, nextCircuit.data.sequencePosition, nextCircuit.data.zKeySizeInBytes, timeoutExpired, providerUserId);
|
|
2616
2650
|
// Check if the participant would like to generate a new attestation.
|
|
@@ -3171,10 +3205,7 @@ program
|
|
|
3171
3205
|
.command("clean")
|
|
3172
3206
|
.description("clean up output generated by commands from the current working directory")
|
|
3173
3207
|
.action(clean);
|
|
3174
|
-
program
|
|
3175
|
-
.command("list")
|
|
3176
|
-
.description("List all ceremonies prefixes")
|
|
3177
|
-
.action(listCeremonies);
|
|
3208
|
+
program.command("list").description("List all ceremonies prefixes").action(listCeremonies);
|
|
3178
3209
|
program
|
|
3179
3210
|
.command("logout")
|
|
3180
3211
|
.description("sign out from Firebae Auth service and delete Github OAuth 2.0 token from local storage")
|
|
@@ -3190,8 +3221,8 @@ const ceremony = program.command("coordinate").description("commands for coordin
|
|
|
3190
3221
|
ceremony
|
|
3191
3222
|
.command("setup")
|
|
3192
3223
|
.description("setup a Groth16 Phase 2 Trusted Setup ceremony for zk-SNARK circuits")
|
|
3193
|
-
.option(
|
|
3194
|
-
.option(
|
|
3224
|
+
.option("-t, --template <path>", "The path to the ceremony setup template", "")
|
|
3225
|
+
.option("-a, --auth <string>", "The Github OAuth 2.0 token", "")
|
|
3195
3226
|
.action(setup);
|
|
3196
3227
|
ceremony
|
|
3197
3228
|
.command("observe")
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@devtion/devcli",
|
|
3
3
|
"type": "module",
|
|
4
|
-
"version": "0.0.0-
|
|
4
|
+
"version": "0.0.0-3df1645",
|
|
5
5
|
"description": "All-in-one interactive command-line for interfacing with zkSNARK Phase 2 Trusted Setup ceremonies",
|
|
6
6
|
"repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
|
|
7
7
|
"homepage": "https://github.com/privacy-scaling-explorations/p0tion",
|
|
@@ -97,5 +97,5 @@
|
|
|
97
97
|
"publishConfig": {
|
|
98
98
|
"access": "public"
|
|
99
99
|
},
|
|
100
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "6f9aa8c0097076db64ca825e5714f4e149012f03"
|
|
101
101
|
}
|
package/src/commands/auth.ts
CHANGED
|
@@ -63,8 +63,14 @@ export const expirationCountdownForGithubOAuth = (expirationInSeconds: number) =
|
|
|
63
63
|
*/
|
|
64
64
|
export const onVerification = async (verification: Verification): Promise<void> => {
|
|
65
65
|
// Copy code to clipboard.
|
|
66
|
-
|
|
67
|
-
|
|
66
|
+
let noClipboard = false
|
|
67
|
+
try {
|
|
68
|
+
clipboard.writeSync(verification.user_code)
|
|
69
|
+
clipboard.readSync()
|
|
70
|
+
} catch (error) {
|
|
71
|
+
noClipboard = true
|
|
72
|
+
}
|
|
73
|
+
|
|
68
74
|
|
|
69
75
|
// Display data.
|
|
70
76
|
console.log(
|
|
@@ -73,12 +79,13 @@ export const onVerification = async (verification: Verification): Promise<void>
|
|
|
73
79
|
)} on this device to generate a new token and authenticate\n`
|
|
74
80
|
)
|
|
75
81
|
|
|
76
|
-
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })),
|
|
77
|
-
|
|
82
|
+
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })), "\n")
|
|
83
|
+
|
|
84
|
+
const message = !noClipboard ? `has been copied to your clipboard (${theme.emojis.clipboard})` : ``
|
|
78
85
|
console.log(
|
|
79
|
-
`${theme.symbols.info} Your auth code: ${theme.text.bold(
|
|
80
|
-
|
|
81
|
-
})\n`
|
|
86
|
+
`${theme.symbols.info} Your auth code: ${theme.text.bold(
|
|
87
|
+
verification.user_code
|
|
88
|
+
)} ${message} ${theme.symbols.success})\n`
|
|
82
89
|
)
|
|
83
90
|
|
|
84
91
|
const spinner = customSpinner(`Redirecting to Github...`, `clock`)
|
|
@@ -86,8 +93,12 @@ export const onVerification = async (verification: Verification): Promise<void>
|
|
|
86
93
|
|
|
87
94
|
await sleep(10000) // ~10s to make users able to read the CLI.
|
|
88
95
|
|
|
89
|
-
|
|
90
|
-
|
|
96
|
+
try {
|
|
97
|
+
// Automatically open the page (# Step 2).
|
|
98
|
+
await open(verification.verification_uri)
|
|
99
|
+
} catch (error: any) {
|
|
100
|
+
console.log(`${theme.symbols.info} Please authenticate via GitHub at ${verification.verification_uri}`)
|
|
101
|
+
}
|
|
91
102
|
|
|
92
103
|
spinner.stop()
|
|
93
104
|
|
|
@@ -811,7 +811,9 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
811
811
|
await getLatestVerificationResult(firestoreDatabase, ceremony.id, circuit.id, participant.id)
|
|
812
812
|
|
|
813
813
|
// Get next circuit for contribution.
|
|
814
|
-
const nextCircuit = timeoutExpired
|
|
814
|
+
const nextCircuit = timeoutExpired
|
|
815
|
+
? getCircuitBySequencePosition(circuits, changedContributionProgress)
|
|
816
|
+
: getCircuitBySequencePosition(circuits, changedContributionProgress + 1)
|
|
815
817
|
|
|
816
818
|
// Check disk space requirements for participant.
|
|
817
819
|
const wannaGenerateAttestation = await handleDiskSpaceRequirementForNextContribution(
|
|
@@ -895,7 +897,7 @@ const contribute = async (opt: any) => {
|
|
|
895
897
|
// Get options.
|
|
896
898
|
const ceremonyOpt = opt.ceremony
|
|
897
899
|
const entropyOpt = opt.entropy
|
|
898
|
-
const auth = opt.auth
|
|
900
|
+
const auth = opt.auth
|
|
899
901
|
|
|
900
902
|
// Check for authentication.
|
|
901
903
|
const { user, providerUserId, token } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
package/src/commands/finalize.ts
CHANGED
|
@@ -249,7 +249,11 @@ const finalize = async (opt: any) => {
|
|
|
249
249
|
|
|
250
250
|
// Check for authentication.
|
|
251
251
|
const auth = opt.auth
|
|
252
|
-
const {
|
|
252
|
+
const {
|
|
253
|
+
user,
|
|
254
|
+
providerUserId,
|
|
255
|
+
token: coordinatorAccessToken
|
|
256
|
+
} = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
253
257
|
|
|
254
258
|
// Preserve command execution only for coordinators.
|
|
255
259
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
package/src/commands/index.ts
CHANGED
|
@@ -6,4 +6,4 @@ export { default as finalize } from "./finalize.js"
|
|
|
6
6
|
export { default as clean } from "./clean.js"
|
|
7
7
|
export { default as logout } from "./logout.js"
|
|
8
8
|
export { default as validate } from "./validate.js"
|
|
9
|
-
export { default as listCeremonies} from "./listCeremonies.js"
|
|
9
|
+
export { default as listCeremonies } from "./listCeremonies.js"
|
|
@@ -17,11 +17,10 @@ const listCeremonies = async () => {
|
|
|
17
17
|
|
|
18
18
|
// loop through all ceremonies
|
|
19
19
|
for (const ceremony of ceremonies) names.push(ceremony.data().prefix)
|
|
20
|
-
|
|
20
|
+
|
|
21
21
|
// print them to the console
|
|
22
22
|
console.log(names.join(", "))
|
|
23
23
|
process.exit(0)
|
|
24
|
-
|
|
25
24
|
} catch (err: any) {
|
|
26
25
|
showError(`${err.toString()}`, false)
|
|
27
26
|
// we want to exit with a non-zero exit code
|
package/src/commands/observe.ts
CHANGED
|
@@ -15,7 +15,7 @@ import { COMMAND_ERRORS, GENERIC_ERRORS, showError } from "../lib/errors.js"
|
|
|
15
15
|
import { promptForCeremonySelection } from "../lib/prompts.js"
|
|
16
16
|
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
17
17
|
import theme from "../lib/theme.js"
|
|
18
|
-
import {customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils.js"
|
|
18
|
+
import { customSpinner, getSecondsMinutesHoursFromMillis, sleep } from "../lib/utils.js"
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* Clean cursor lines from current position back to root (default: zero).
|
package/src/commands/setup.ts
CHANGED
|
@@ -466,7 +466,7 @@ export const handleCircuitArtifactUploadToStorage = async (
|
|
|
466
466
|
* from Hermez's ceremony Phase 1 Reliable Setup Ceremony.
|
|
467
467
|
* @param cmd? <any> - the path to the ceremony setup file.
|
|
468
468
|
*/
|
|
469
|
-
const setup = async (cmd: { template?: string
|
|
469
|
+
const setup = async (cmd: { template?: string; auth?: string }) => {
|
|
470
470
|
// Setup command state.
|
|
471
471
|
const circuits: Array<CircuitDocument> = [] // Circuits.
|
|
472
472
|
let ceremonyId: string = "" // The unique identifier of the ceremony.
|
|
@@ -474,8 +474,10 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
474
474
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
475
475
|
|
|
476
476
|
// Check for authentication.
|
|
477
|
-
const { user, providerUserId } = cmd.auth
|
|
478
|
-
|
|
477
|
+
const { user, providerUserId } = cmd.auth
|
|
478
|
+
? await authWithToken(firebaseApp, cmd.auth)
|
|
479
|
+
: await checkAuth(firebaseApp)
|
|
480
|
+
|
|
479
481
|
// Preserve command execution only for coordinators.
|
|
480
482
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
481
483
|
|
|
@@ -501,7 +503,7 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
501
503
|
// if there is the file option, then set up the non interactively
|
|
502
504
|
if (cmd.template) {
|
|
503
505
|
// 1. parse the file
|
|
504
|
-
// tmp data - do not cleanup files as we need them
|
|
506
|
+
// tmp data - do not cleanup files as we need them
|
|
505
507
|
const spinner = customSpinner(`Parsing ${theme.text.bold(cmd.template!)} setup configuration file...`, `clock`)
|
|
506
508
|
spinner.start()
|
|
507
509
|
const setupCeremonyData = await parseCeremonyFile(cmd.template!)
|
|
@@ -524,13 +526,26 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
524
526
|
const zkeyLocalPathAndFileName = getZkeyLocalFilePath(circuit.files.initialZkeyFilename)
|
|
525
527
|
|
|
526
528
|
// 2. download the pot and wasm files
|
|
527
|
-
await checkAndDownloadSmallestPowersOfTau(
|
|
528
|
-
|
|
529
|
+
await checkAndDownloadSmallestPowersOfTau(
|
|
530
|
+
convertToDoubleDigits(circuit.metadata?.pot!),
|
|
531
|
+
circuit.files.potFilename
|
|
532
|
+
)
|
|
533
|
+
|
|
529
534
|
// 3. generate the zKey
|
|
530
|
-
const spinner = customSpinner(
|
|
535
|
+
const spinner = customSpinner(
|
|
536
|
+
`Generating genesis zKey for circuit ${theme.text.bold(circuit.name)}...`,
|
|
537
|
+
`clock`
|
|
538
|
+
)
|
|
531
539
|
spinner.start()
|
|
532
|
-
await zKey.newZKey(
|
|
533
|
-
|
|
540
|
+
await zKey.newZKey(
|
|
541
|
+
r1csLocalPathAndFileName,
|
|
542
|
+
getPotLocalFilePath(circuit.files.potFilename),
|
|
543
|
+
zkeyLocalPathAndFileName,
|
|
544
|
+
undefined
|
|
545
|
+
)
|
|
546
|
+
spinner.succeed(
|
|
547
|
+
`Generation of the genesis zKey for citcui ${theme.text.bold(circuit.name)} completed successfully`
|
|
548
|
+
)
|
|
534
549
|
|
|
535
550
|
// 4. calculate the hashes
|
|
536
551
|
const wasmBlake2bHash = await blake512FromPath(wasmLocalPathAndFileName)
|
|
@@ -547,7 +562,7 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
547
562
|
zkeyLocalPathAndFileName,
|
|
548
563
|
circuit.files.initialZkeyFilename
|
|
549
564
|
)
|
|
550
|
-
|
|
565
|
+
|
|
551
566
|
// Check if PoT file has been already uploaded to storage.
|
|
552
567
|
const alreadyUploadedPot = await checkIfObjectExist(
|
|
553
568
|
firebaseFunctions,
|
|
@@ -595,18 +610,24 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
595
610
|
|
|
596
611
|
ceremonySetupData.circuits[index].zKeySizeInBytes = getFileStats(zkeyLocalPathAndFileName).size
|
|
597
612
|
}
|
|
598
|
-
|
|
599
613
|
|
|
600
614
|
// 7. setup the ceremony
|
|
601
|
-
const ceremonyId = await setupCeremony(
|
|
602
|
-
|
|
603
|
-
ceremonySetupData.ceremonyInputData
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
615
|
+
const ceremonyId = await setupCeremony(
|
|
616
|
+
firebaseFunctions,
|
|
617
|
+
ceremonySetupData.ceremonyInputData,
|
|
618
|
+
ceremonySetupData.ceremonyPrefix,
|
|
619
|
+
ceremonySetupData.circuits
|
|
620
|
+
)
|
|
621
|
+
console.log(
|
|
622
|
+
`Congratulations, the setup of ceremony ${theme.text.bold(
|
|
623
|
+
ceremonySetupData.ceremonyInputData.title
|
|
624
|
+
)} (${`UID: ${theme.text.bold(ceremonyId)}`}) has been successfully completed ${
|
|
625
|
+
theme.emojis.tada
|
|
626
|
+
}. You will be able to find all the files and info respectively in the ceremony bucket and database document.`
|
|
627
|
+
)
|
|
628
|
+
|
|
608
629
|
terminate(providerUserId)
|
|
609
|
-
}
|
|
630
|
+
}
|
|
610
631
|
|
|
611
632
|
// Look for R1CS files.
|
|
612
633
|
const r1csFilePaths = await filterDirectoryFilesByExtension(cwd, `.r1cs`)
|
package/src/commands/validate.ts
CHANGED
|
@@ -4,7 +4,7 @@ import { showError } from "../lib/errors.js"
|
|
|
4
4
|
/**
|
|
5
5
|
* Validate ceremony setup command.
|
|
6
6
|
*/
|
|
7
|
-
const validate = async (cmd: { template: string
|
|
7
|
+
const validate = async (cmd: { template: string; constraints?: number }) => {
|
|
8
8
|
try {
|
|
9
9
|
// parse the file and cleanup after
|
|
10
10
|
const parsedFile = await parseCeremonyFile(cmd.template, true)
|
|
@@ -18,7 +18,6 @@ const validate = async (cmd: { template: string, constraints?: number }) => {
|
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
console.log(true)
|
|
21
|
-
|
|
22
21
|
} catch (err: any) {
|
|
23
22
|
showError(`${err.toString()}`, false)
|
|
24
23
|
// we want to exit with a non-zero exit code
|
package/src/index.ts
CHANGED
|
@@ -4,7 +4,17 @@ import { createCommand } from "commander"
|
|
|
4
4
|
import { readFileSync } from "fs"
|
|
5
5
|
import { dirname } from "path"
|
|
6
6
|
import { fileURLToPath } from "url"
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
setup,
|
|
9
|
+
auth,
|
|
10
|
+
contribute,
|
|
11
|
+
observe,
|
|
12
|
+
finalize,
|
|
13
|
+
clean,
|
|
14
|
+
logout,
|
|
15
|
+
validate,
|
|
16
|
+
listCeremonies
|
|
17
|
+
} from "./commands/index.js"
|
|
8
18
|
|
|
9
19
|
// Get pkg info (e.g., name, version).
|
|
10
20
|
const packagePath = `${dirname(fileURLToPath(import.meta.url))}/..`
|
|
@@ -27,10 +37,7 @@ program
|
|
|
27
37
|
.command("clean")
|
|
28
38
|
.description("clean up output generated by commands from the current working directory")
|
|
29
39
|
.action(clean)
|
|
30
|
-
program
|
|
31
|
-
.command("list")
|
|
32
|
-
.description("List all ceremonies prefixes")
|
|
33
|
-
.action(listCeremonies)
|
|
40
|
+
program.command("list").description("List all ceremonies prefixes").action(listCeremonies)
|
|
34
41
|
program
|
|
35
42
|
.command("logout")
|
|
36
43
|
.description("sign out from Firebae Auth service and delete Github OAuth 2.0 token from local storage")
|
|
@@ -48,10 +55,10 @@ const ceremony = program.command("coordinate").description("commands for coordin
|
|
|
48
55
|
ceremony
|
|
49
56
|
.command("setup")
|
|
50
57
|
.description("setup a Groth16 Phase 2 Trusted Setup ceremony for zk-SNARK circuits")
|
|
51
|
-
.option(
|
|
52
|
-
.option(
|
|
58
|
+
.option("-t, --template <path>", "The path to the ceremony setup template", "")
|
|
59
|
+
.option("-a, --auth <string>", "The Github OAuth 2.0 token", "")
|
|
53
60
|
.action(setup)
|
|
54
|
-
|
|
61
|
+
|
|
55
62
|
ceremony
|
|
56
63
|
.command("observe")
|
|
57
64
|
.description("observe in real-time the waiting queue of each ceremony circuit")
|
package/src/lib/prompts.ts
CHANGED
|
@@ -343,7 +343,7 @@ export const promptCircuitInputData = async (
|
|
|
343
343
|
let circomVersion: string = ""
|
|
344
344
|
let circomCommitHash: string = ""
|
|
345
345
|
let circuitInputData: CircuitInputData
|
|
346
|
-
let
|
|
346
|
+
let cfOrVm: CircuitContributionVerificationMechanism
|
|
347
347
|
let vmDiskType: DiskTypeForVM
|
|
348
348
|
let vmConfigurationType: string = ""
|
|
349
349
|
|
|
@@ -429,12 +429,17 @@ export const promptCircuitInputData = async (
|
|
|
429
429
|
`CF`, // eq. true.
|
|
430
430
|
`VM` // eq. false.
|
|
431
431
|
)
|
|
432
|
-
|
|
433
|
-
|
|
432
|
+
cfOrVm = confirmation
|
|
433
|
+
? CircuitContributionVerificationMechanism.CF
|
|
434
|
+
: CircuitContributionVerificationMechanism.VM
|
|
434
435
|
|
|
435
|
-
|
|
436
|
+
} else {
|
|
437
|
+
cfOrVm = CircuitContributionVerificationMechanism.VM
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
if (cfOrVm === undefined) showError(COMMAND_ERRORS.COMMAND_ABORT_PROMPT, true)
|
|
436
441
|
|
|
437
|
-
if (
|
|
442
|
+
if (cfOrVm === CircuitContributionVerificationMechanism.VM) {
|
|
438
443
|
// Ask for selecting the specific VM configuration type.
|
|
439
444
|
vmConfigurationType = await promptVMTypeSelector(constraintSize)
|
|
440
445
|
|
|
@@ -478,9 +483,7 @@ export const promptCircuitInputData = async (
|
|
|
478
483
|
paramsConfiguration: circuitConfigurationValues
|
|
479
484
|
},
|
|
480
485
|
verification: {
|
|
481
|
-
cfOrVm
|
|
482
|
-
? CircuitContributionVerificationMechanism.CF
|
|
483
|
-
: CircuitContributionVerificationMechanism.VM,
|
|
486
|
+
cfOrVm,
|
|
484
487
|
vm: {
|
|
485
488
|
vmConfigurationType,
|
|
486
489
|
vmDiskType
|
|
@@ -520,9 +523,7 @@ export const promptCircuitInputData = async (
|
|
|
520
523
|
paramsConfiguration: circuitConfigurationValues
|
|
521
524
|
},
|
|
522
525
|
verification: {
|
|
523
|
-
cfOrVm
|
|
524
|
-
? CircuitContributionVerificationMechanism.CF
|
|
525
|
-
: CircuitContributionVerificationMechanism.VM,
|
|
526
|
+
cfOrVm,
|
|
526
527
|
vm: {
|
|
527
528
|
vmConfigurationType,
|
|
528
529
|
vmDiskType
|
package/src/lib/services.ts
CHANGED
package/src/lib/utils.ts
CHANGED
|
@@ -311,8 +311,22 @@ export const generateCustomUrlToTweetAboutParticipation = (
|
|
|
311
311
|
isFinalizing: boolean
|
|
312
312
|
) =>
|
|
313
313
|
isFinalizing
|
|
314
|
-
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}${
|
|
315
|
-
|
|
314
|
+
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}${
|
|
315
|
+
ceremonyName.toLowerCase().includes("trusted") ||
|
|
316
|
+
ceremonyName.toLowerCase().includes("setup") ||
|
|
317
|
+
ceremonyName.toLowerCase().includes("phase2") ||
|
|
318
|
+
ceremonyName.toLowerCase().includes("ceremony")
|
|
319
|
+
? "!"
|
|
320
|
+
: "%20Phase%202%20Trusted%20Setup%20ceremony!"
|
|
321
|
+
}%20You%20can%20view%20my%20final%20attestation%20here:%20${gistUrl}%20#Ethereum%20#ZKP%20#PSE`
|
|
322
|
+
: `https://twitter.com/intent/tweet?text=I%20contributed%20to%20the%20${ceremonyName}${
|
|
323
|
+
ceremonyName.toLowerCase().includes("trusted") ||
|
|
324
|
+
ceremonyName.toLowerCase().includes("setup") ||
|
|
325
|
+
ceremonyName.toLowerCase().includes("phase2") ||
|
|
326
|
+
ceremonyName.toLowerCase().includes("ceremony")
|
|
327
|
+
? "!"
|
|
328
|
+
: "%20Phase%202%20Trusted%20Setup%20ceremony!"
|
|
329
|
+
}%20You%20can%20view%20the%20steps%20to%20contribute%20here:%20https://ceremony.pse.dev%20You%20can%20view%20my%20attestation%20here:%20${gistUrl}%20#Ethereum%20#ZKP`
|
|
316
330
|
|
|
317
331
|
/**
|
|
318
332
|
* Return a custom progress bar.
|
|
@@ -540,7 +554,9 @@ export const handleStartOrResumeContribution = async (
|
|
|
540
554
|
const { completedContributions } = waitingQueue // = current progress.
|
|
541
555
|
|
|
542
556
|
console.log(
|
|
543
|
-
`${theme.text.bold(
|
|
557
|
+
`${theme.text.bold(
|
|
558
|
+
`\n- Circuit # ${theme.colors.magenta(`${sequencePosition}/${circuitsLength}`)}`
|
|
559
|
+
)} (Contribution Steps)`
|
|
544
560
|
)
|
|
545
561
|
|
|
546
562
|
// Get most up-to-date data from the participant document.
|
|
@@ -609,6 +625,8 @@ export const handleStartOrResumeContribution = async (
|
|
|
609
625
|
`${theme.symbols.success} Contribution ${theme.text.bold(`#${lastZkeyIndex}`)} correctly downloaded`
|
|
610
626
|
)
|
|
611
627
|
|
|
628
|
+
await sleep(3000)
|
|
629
|
+
|
|
612
630
|
// Advance to next contribution step (COMPUTING) if not finalizing.
|
|
613
631
|
if (!isFinalizing) {
|
|
614
632
|
spinner.text = `Preparing for contribution computation...`
|
|
@@ -652,6 +670,8 @@ export const handleStartOrResumeContribution = async (
|
|
|
652
670
|
// Format contribution hash.
|
|
653
671
|
const contributionHash = matchContributionHash?.at(0)?.replace("\n\t\t", "")!
|
|
654
672
|
|
|
673
|
+
await sleep(500)
|
|
674
|
+
|
|
655
675
|
// Make request to cloud functions to permanently store the information.
|
|
656
676
|
await permanentlyStoreCurrentContributionTimeAndHash(
|
|
657
677
|
cloudFunctions,
|
|
@@ -677,6 +697,9 @@ export const handleStartOrResumeContribution = async (
|
|
|
677
697
|
)}`
|
|
678
698
|
)
|
|
679
699
|
|
|
700
|
+
// ensure the previous step is completed
|
|
701
|
+
await sleep(5000)
|
|
702
|
+
|
|
680
703
|
// Advance to next contribution step (UPLOADING) if not finalizing.
|
|
681
704
|
if (!isFinalizing) {
|
|
682
705
|
spinner.text = `Preparing for uploading the contribution...`
|
|
@@ -701,7 +724,9 @@ export const handleStartOrResumeContribution = async (
|
|
|
701
724
|
} This step may take a while based on circuit size and your internet speed. Everything's fine, just be patient.`
|
|
702
725
|
spinner.start()
|
|
703
726
|
|
|
704
|
-
|
|
727
|
+
const progressBar = customProgressBar(ProgressBarType.UPLOAD, `your contribution`)
|
|
728
|
+
|
|
729
|
+
if (!isFinalizing) {
|
|
705
730
|
await multiPartUpload(
|
|
706
731
|
cloudFunctions,
|
|
707
732
|
bucketName,
|
|
@@ -709,8 +734,12 @@ export const handleStartOrResumeContribution = async (
|
|
|
709
734
|
nextZkeyLocalFilePath,
|
|
710
735
|
Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB),
|
|
711
736
|
ceremony.id,
|
|
712
|
-
participantData.tempContributionData
|
|
737
|
+
participantData.tempContributionData,
|
|
738
|
+
progressBar
|
|
713
739
|
)
|
|
740
|
+
|
|
741
|
+
progressBar.stop()
|
|
742
|
+
}
|
|
714
743
|
else
|
|
715
744
|
await multiPartUpload(
|
|
716
745
|
cloudFunctions,
|
|
@@ -720,6 +749,9 @@ export const handleStartOrResumeContribution = async (
|
|
|
720
749
|
Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB)
|
|
721
750
|
)
|
|
722
751
|
|
|
752
|
+
// small sleep to ensure the previous step is completed
|
|
753
|
+
await sleep(5000)
|
|
754
|
+
|
|
723
755
|
spinner.succeed(
|
|
724
756
|
`${
|
|
725
757
|
isFinalizing ? `Contribution` : `Contribution ${theme.text.bold(`#${nextZkeyIndex}`)}`
|