@devtion/devcli 0.0.0-270e9e0 → 0.0.0-3c7b092
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/README.md +2 -0
- package/dist/.env +40 -39
- package/dist/index.js +38 -39
- package/dist/types/commands/contribute.d.ts +1 -1
- package/dist/types/commands/finalize.d.ts +4 -3
- package/dist/types/commands/observe.d.ts +1 -1
- package/dist/types/commands/setup.d.ts +1 -1
- package/dist/types/lib/prompts.d.ts +1 -1
- package/dist/types/lib/utils.d.ts +3 -2
- package/package.json +4 -3
- package/src/commands/auth.ts +6 -2
- package/src/commands/contribute.ts +10 -9
- package/src/commands/finalize.ts +15 -10
- package/src/commands/listCeremonies.ts +1 -1
- package/src/commands/observe.ts +1 -1
- package/src/commands/setup.ts +5 -28
- package/src/commands/validate.ts +1 -1
- package/src/index.ts +2 -0
- package/src/lib/localConfigs.ts +1 -1
- package/src/lib/prompts.ts +1 -1
- package/src/lib/services.ts +1 -1
- package/src/lib/utils.ts +8 -6
package/README.md
CHANGED
|
@@ -61,6 +61,8 @@ or run specific commands with `npx`:
|
|
|
61
61
|
npx @p0tion/phase2cli contribute
|
|
62
62
|
```
|
|
63
63
|
|
|
64
|
+
> Please note that phase2cli only runs on Linux or Mac systems. If a Windows user, please install [WSL2](https://learn.microsoft.com/en-us/windows/wsl/install) first.
|
|
65
|
+
|
|
64
66
|
## 📜 Usage
|
|
65
67
|
|
|
66
68
|
### Local Development
|
package/dist/.env
CHANGED
|
@@ -1,40 +1,41 @@
|
|
|
1
|
-
### FIREBASE ###
|
|
2
|
-
### These configs are related to the configuration of the Firebase services.
|
|
1
|
+
### FIREBASE ###
|
|
2
|
+
### These configs are related to the configuration of the Firebase services.
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
# The Firebase Application API key for making request against the services.
|
|
6
|
+
# nb. this is going to be auto-generated when creating a new application.
|
|
7
|
+
FIREBASE_API_KEY=AIzaSyDVAu8U4zBpM3FFLPyktSjZnCmg1IR73Cg
|
|
8
|
+
# The URL to Firebase Authentication service (should point to default).
|
|
9
|
+
# nb. this is going to be auto-generated when creating a new application.
|
|
10
|
+
FIREBASE_AUTH_DOMAIN=p0tion-ci-environment.firebaseapp.com
|
|
11
|
+
# The Firebase Application project id (should match with application name).
|
|
12
|
+
FIREBASE_PROJECT_ID=p0tion-ci-environment
|
|
13
|
+
# The Firebase unique message sender identifier (to recognize the application user).
|
|
14
|
+
# nb. this is going to be auto-generated when creating a new application.
|
|
15
|
+
FIREBASE_MESSAGING_SENDER_ID=22680510841
|
|
16
|
+
# The Firebase unique identifier for your application.
|
|
17
|
+
# nb. this is going to be auto-generated when creating a new application.
|
|
18
|
+
FIREBASE_APP_ID=1:22680510841:web:529a664e73dbabd1c7cfa8
|
|
19
|
+
FIREBASE_CF_URL_VERIFY_CONTRIBUTION=https://verifycontribution-mq4aqokliq-ew.a.run.app
|
|
20
|
+
|
|
21
|
+
### AUTHENTICATION ###
|
|
22
|
+
### These configs are related to the authentication of users.
|
|
23
|
+
|
|
24
|
+
# The unique identifier for the Github client associated to the OAuth Application.
|
|
25
|
+
AUTH_GITHUB_CLIENT_ID=e9f8a5fabdfe0d95618c
|
|
26
|
+
|
|
27
|
+
### AWS S3 STORAGE ###
|
|
28
|
+
### These configs are related to the configuration of the interaction with the
|
|
29
|
+
### AWS S3 bucket used as storage for ceremony artifacts.
|
|
30
|
+
|
|
31
|
+
# The chunk size to be used when executing multi-part upload or downloads.
|
|
32
|
+
# default 25 MBs.
|
|
33
|
+
# (e.g. a 200 MB file setting a stream chunk size of 25 MB is going to be splitted and uploaded/downloaded in 4 chunks).
|
|
34
|
+
CONFIG_STREAM_CHUNK_SIZE_IN_MB=25
|
|
35
|
+
# The postfix string for each ceremony bucket.
|
|
36
|
+
# default -ph2-ceremony
|
|
37
|
+
CONFIG_CEREMONY_BUCKET_POSTFIX=-p0tion-development-environment
|
|
38
|
+
# The amount of time in seconds which indicates the duration about the validity of a pre-signed URL.
|
|
39
|
+
# default: 7200 seconds = 2 hours.
|
|
40
|
+
CONFIG_PRESIGNED_URL_EXPIRATION_IN_SECONDS=7200
|
|
3
41
|
|
|
4
|
-
|
|
5
|
-
# The Firebase Application API key for making request against the services.
|
|
6
|
-
# nb. this is going to be auto-generated when creating a new application.
|
|
7
|
-
FIREBASE_API_KEY="AIzaSyCY_5a4TC3Hjxihwar2ssqG12QJ0k_HUjw"
|
|
8
|
-
# The URL to Firebase Authentication service (should point to default).
|
|
9
|
-
# nb. this is going to be auto-generated when creating a new application.
|
|
10
|
-
FIREBASE_AUTH_DOMAIN="pse-p0tion-staging.firebaseapp.com"
|
|
11
|
-
# The Firebase Application project id (should match with application name).
|
|
12
|
-
FIREBASE_PROJECT_ID="pse-p0tion-staging"
|
|
13
|
-
# The Firebase unique message sender identifier (to recognize the application user).
|
|
14
|
-
# nb. this is going to be auto-generated when creating a new application.
|
|
15
|
-
FIREBASE_MESSAGING_SENDER_ID="206432055346"
|
|
16
|
-
# The Firebase unique identifier for your application.
|
|
17
|
-
# nb. this is going to be auto-generated when creating a new application.
|
|
18
|
-
FIREBASE_APP_ID="1:206432055346:web:bde768fe8e7fd5ca660c2b"
|
|
19
|
-
FIREBASE_CF_URL_VERIFY_CONTRIBUTION="https://verifycontribution-bc7hurobjq-ew.a.run.app"
|
|
20
|
-
|
|
21
|
-
### AUTHENTICATION ###
|
|
22
|
-
### These configs are related to the authentication of users.
|
|
23
|
-
|
|
24
|
-
# The unique identifier for the Github client associated to the OAuth Application.
|
|
25
|
-
AUTH_GITHUB_CLIENT_ID="66302917ce8628103d33"
|
|
26
|
-
|
|
27
|
-
### AWS S3 STORAGE ###
|
|
28
|
-
### These configs are related to the configuration of the interaction with the
|
|
29
|
-
### AWS S3 bucket used as storage for ceremony artifacts.
|
|
30
|
-
|
|
31
|
-
# The chunk size to be used when executing multi-part upload or downloads.
|
|
32
|
-
# default 50 MBs.
|
|
33
|
-
# (e.g. a 200 MB file setting a stream chunk size of 50 MB is going to be splitted and uploaded/downloaded in 4 chunks).
|
|
34
|
-
CONFIG_STREAM_CHUNK_SIZE_IN_MB=50
|
|
35
|
-
# The postfix string for each ceremony bucket.
|
|
36
|
-
# default "-ph2-ceremony"
|
|
37
|
-
CONFIG_CEREMONY_BUCKET_POSTFIX="-pse-p0tion-staging"
|
|
38
|
-
# The amount of time in seconds which indicates the duration about the validity of a pre-signed URL.
|
|
39
|
-
# default: 7200 seconds = 2 hours.
|
|
40
|
-
CONFIG_PRESIGNED_URL_EXPIRATION_IN_SECONDS=7200
|
package/dist/index.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
4
|
* @module @devtion/devcli
|
|
5
|
-
* @version 1.0.
|
|
5
|
+
* @version 1.0.8
|
|
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
|
|
@@ -17,8 +17,7 @@ import boxen from 'boxen';
|
|
|
17
17
|
import { pipeline } from 'node:stream';
|
|
18
18
|
import { promisify } from 'node:util';
|
|
19
19
|
import fetch$1 from 'node-fetch';
|
|
20
|
-
import {
|
|
21
|
-
import { commonTerms, formatZkeyIndex, getZkeyStorageFilePath, finalContributionIndex, createCustomLoggerForFile, getBucketName, progressToNextContributionStep, permanentlyStoreCurrentContributionTimeAndHash, convertToDoubleDigits, multiPartUpload, verifyContribution, generateGetObjectPreSignedUrl, convertBytesOrKbToGb, numExpIterations, getDocumentById, getParticipantsCollectionPath, fromQueryToFirebaseDocumentInfo, getAllCollectionDocs, extractPrefix, autoGenerateEntropy, vmConfigurationTypes, initializeFirebaseCoreServices, signInToFirebaseWithCredentials, getCurrentFirebaseAuthUser, isCoordinator, parseCeremonyFile, blake512FromPath, checkIfObjectExist, setupCeremony, genesisZkeyIndex, getR1csStorageFilePath, getWasmStorageFilePath, getPotStorageFilePath, extractPoTFromFilename, potFileDownloadMainUrl, createS3Bucket, potFilenameTemplate, getR1CSInfo, getOpenedCeremonies, getCeremonyCircuits, checkParticipantForCeremony, getCurrentActiveParticipantTimeout, getCircuitBySequencePosition, getCircuitContributionsFromContributor, progressToNextCircuitForContribution, resumeContributionAfterTimeoutExpiration, generateValidContributionsAttestation, getContributionsValidityForContributor, getClosedCeremonies, checkAndPrepareCoordinatorForFinalization, computeSHA256ToHex, finalizeCeremony, getVerificationKeyStorageFilePath, verificationKeyAcronym, getVerifierContractStorageFilePath, verifierSmartContractAcronym, finalizeCircuit, exportVkey, exportVerifierContract } from '@p0tion/actions';
|
|
20
|
+
import { commonTerms, formatZkeyIndex, getZkeyStorageFilePath, finalContributionIndex, createCustomLoggerForFile, getBucketName, progressToNextContributionStep, permanentlyStoreCurrentContributionTimeAndHash, convertToDoubleDigits, multiPartUpload, verifyContribution, generateGetObjectPreSignedUrl, convertBytesOrKbToGb, numExpIterations, getDocumentById, getParticipantsCollectionPath, fromQueryToFirebaseDocumentInfo, getAllCollectionDocs, extractPrefix, autoGenerateEntropy, vmConfigurationTypes, initializeFirebaseCoreServices, signInToFirebaseWithCredentials, getCurrentFirebaseAuthUser, isCoordinator, parseCeremonyFile, blake512FromPath, checkIfObjectExist, setupCeremony, genesisZkeyIndex, getR1csStorageFilePath, getWasmStorageFilePath, getPotStorageFilePath, extractPoTFromFilename, potFileDownloadMainUrl, createS3Bucket, potFilenameTemplate, getR1CSInfo, getOpenedCeremonies, getCeremonyCircuits, checkParticipantForCeremony, getCurrentActiveParticipantTimeout, getCircuitBySequencePosition, getCircuitContributionsFromContributor, progressToNextCircuitForContribution, resumeContributionAfterTimeoutExpiration, generateValidContributionsAttestation, getContributionsValidityForContributor, getClosedCeremonies, checkAndPrepareCoordinatorForFinalization, computeSHA256ToHex, finalizeCeremony, getVerificationKeyStorageFilePath, verificationKeyAcronym, getVerifierContractStorageFilePath, verifierSmartContractAcronym, finalizeCircuit, exportVkey, exportVerifierContract } from '@devtion/actions';
|
|
22
21
|
import fetch from '@adobe/node-fetch-retry';
|
|
23
22
|
import { request } from '@octokit/request';
|
|
24
23
|
import { SingleBar, Presets } from 'cli-progress';
|
|
@@ -34,7 +33,6 @@ import Conf from 'conf';
|
|
|
34
33
|
import prompts from 'prompts';
|
|
35
34
|
import clear from 'clear';
|
|
36
35
|
import figlet from 'figlet';
|
|
37
|
-
import { Readable } from 'stream';
|
|
38
36
|
import { createOAuthDeviceAuth } from '@octokit/auth-oauth-device';
|
|
39
37
|
import clipboard from 'clipboardy';
|
|
40
38
|
import open from 'open';
|
|
@@ -367,6 +365,12 @@ const getVerificationKeyLocalFilePath = (completeFilename) => `${verificationKey
|
|
|
367
365
|
* @returns <string> - the complete final verifier contract path to the file.
|
|
368
366
|
*/
|
|
369
367
|
const getVerifierContractLocalFilePath = (completeFilename) => `${verifierContractsLocalFolderPath}/${completeFilename}`;
|
|
368
|
+
/**
|
|
369
|
+
* Get the complete final attestation file path.
|
|
370
|
+
* @param completeFilename <string> - the complete filename of the file (name.ext).
|
|
371
|
+
* @returns <string> - the complete final final attestation path to the file.
|
|
372
|
+
*/
|
|
373
|
+
const getFinalAttestationLocalFilePath = (completeFilename) => `${finalAttestationsLocalFolderPath}/${completeFilename}`;
|
|
370
374
|
/**
|
|
371
375
|
* Get the final transcript file path.
|
|
372
376
|
* @param completeFilename <string> - the complete filename of the file (name.ext).
|
|
@@ -581,8 +585,8 @@ const publishGist = async (token, content, ceremonyTitle, ceremonyPrefix) => {
|
|
|
581
585
|
* @returns <string> - the ready to share tweet url.
|
|
582
586
|
*/
|
|
583
587
|
const generateCustomUrlToTweetAboutParticipation = (ceremonyName, gistUrl, isFinalizing) => isFinalizing
|
|
584
|
-
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}%20Phase%202%20Trusted%20Setup%20ceremony
|
|
585
|
-
: `https://twitter.com/intent/tweet?text=I%20contributed%20to%20the%20${ceremonyName}%20Phase%202%20Trusted%20Setup%20ceremony
|
|
588
|
+
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") || ceremonyName.toLowerCase().includes("setup") || ceremonyName.toLowerCase().includes("phase2") || ceremonyName.toLowerCase().includes("ceremony") ? "!" : "%20Phase%202%20Trusted%20Setup%20ceremony!"}%20You%20can%20view%20my%20final%20attestation%20here:%20${gistUrl}%20#Ethereum%20#ZKP%20#PSE`
|
|
589
|
+
: `https://twitter.com/intent/tweet?text=I%20contributed%20to%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") || ceremonyName.toLowerCase().includes("setup") || ceremonyName.toLowerCase().includes("phase2") || ceremonyName.toLowerCase().includes("ceremony") ? "!" : "%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`;
|
|
586
590
|
/**
|
|
587
591
|
* Return a custom progress bar.
|
|
588
592
|
* @param type <ProgressBarType> - the type of the progress bar.
|
|
@@ -710,13 +714,14 @@ const getLatestUpdatesFromParticipant = async (firestoreDatabase, ceremonyId, pa
|
|
|
710
714
|
* @param entropyOrBeaconHash <string> - the entropy or beacon hash (only when finalizing) for the contribution.
|
|
711
715
|
* @param contributorOrCoordinatorIdentifier <string> - the identifier of the contributor or coordinator (only when finalizing).
|
|
712
716
|
* @param isFinalizing <boolean> - flag to discriminate between ceremony finalization (true) and contribution (false).
|
|
717
|
+
* @param circuitsLength <number> - the total number of circuits in the ceremony.
|
|
713
718
|
*/
|
|
714
|
-
const handleStartOrResumeContribution = async (cloudFunctions, firestoreDatabase, ceremony, circuit, participant, entropyOrBeaconHash, contributorOrCoordinatorIdentifier, isFinalizing) => {
|
|
719
|
+
const handleStartOrResumeContribution = async (cloudFunctions, firestoreDatabase, ceremony, circuit, participant, entropyOrBeaconHash, contributorOrCoordinatorIdentifier, isFinalizing, circuitsLength) => {
|
|
715
720
|
// Extract data.
|
|
716
721
|
const { prefix: ceremonyPrefix } = ceremony.data;
|
|
717
722
|
const { waitingQueue, avgTimings, prefix: circuitPrefix, sequencePosition } = circuit.data;
|
|
718
723
|
const { completedContributions } = waitingQueue; // = current progress.
|
|
719
|
-
console.log(`${theme.text.bold(`\n- Circuit # ${theme.colors.magenta(`${sequencePosition}`)}`)} (Contribution Steps)`);
|
|
724
|
+
console.log(`${theme.text.bold(`\n- Circuit # ${theme.colors.magenta(`${sequencePosition}/${circuitsLength}`)}`)} (Contribution Steps)`);
|
|
720
725
|
// Get most up-to-date data from the participant document.
|
|
721
726
|
let participantData = await getLatestUpdatesFromParticipant(firestoreDatabase, ceremony.id, participant.id);
|
|
722
727
|
const spinner = customSpinner(`${participantData.contributionStep === "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */
|
|
@@ -809,7 +814,7 @@ const handleStartOrResumeContribution = async (cloudFunctions, firestoreDatabase
|
|
|
809
814
|
console.log(`${theme.symbols.success} Contribution ${theme.text.bold(`#${nextZkeyIndex}`)} already computed`);
|
|
810
815
|
// Contribution step = UPLOADING.
|
|
811
816
|
if (isFinalizing || participantData.contributionStep === "UPLOADING" /* ParticipantContributionStep.UPLOADING */) {
|
|
812
|
-
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
|
|
817
|
+
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.`;
|
|
813
818
|
spinner.start();
|
|
814
819
|
if (!isFinalizing)
|
|
815
820
|
await multiPartUpload(cloudFunctions, bucketName, nextZkeyStorageFilePath, nextZkeyLocalFilePath, Number(process.env.CONFIG_STREAM_CHUNK_SIZE_IN_MB), ceremony.id, participantData.tempContributionData);
|
|
@@ -1853,8 +1858,6 @@ const setup = async (cmd) => {
|
|
|
1853
1858
|
// create a new bucket
|
|
1854
1859
|
const bucketName = await handleCeremonyBucketCreation(firebaseFunctions, ceremonySetupData.ceremonyPrefix);
|
|
1855
1860
|
console.log(`\n${theme.symbols.success} Ceremony bucket name: ${theme.text.bold(bucketName)}`);
|
|
1856
|
-
// create S3 clienbt
|
|
1857
|
-
const s3 = new S3Client({ region: 'us-east-1' });
|
|
1858
1861
|
// loop through each circuit
|
|
1859
1862
|
for await (const circuit of setupCeremonyData.circuits) {
|
|
1860
1863
|
// Local paths.
|
|
@@ -1864,21 +1867,12 @@ const setup = async (cmd) => {
|
|
|
1864
1867
|
const potLocalPathAndFileName = getPotLocalFilePath(circuit.files.potFilename);
|
|
1865
1868
|
const zkeyLocalPathAndFileName = getZkeyLocalFilePath(circuit.files.initialZkeyFilename);
|
|
1866
1869
|
// 2. download the pot and wasm files
|
|
1867
|
-
const streamPipeline = promisify(pipeline);
|
|
1868
1870
|
await checkAndDownloadSmallestPowersOfTau(convertToDoubleDigits(circuit.metadata?.pot), circuit.files.potFilename);
|
|
1869
|
-
// download the wasm to calculate the hash
|
|
1870
|
-
const spinner = customSpinner(`Downloading the ${theme.text.bold(`#${circuit.name}`)} WASM file from the project's bucket...`, `clock`);
|
|
1871
|
-
spinner.start();
|
|
1872
|
-
const command = new GetObjectCommand({ Bucket: ceremonySetupData.circuitArtifacts[index].artifacts.bucket, Key: ceremonySetupData.circuitArtifacts[index].artifacts.wasmStoragePath });
|
|
1873
|
-
const response = await s3.send(command);
|
|
1874
|
-
if (response.$metadata.httpStatusCode !== 200) {
|
|
1875
|
-
throw new Error("There was an error while trying to download the wasm file. Please check that the file has the correct permissions (public) set.");
|
|
1876
|
-
}
|
|
1877
|
-
if (response.Body instanceof Readable)
|
|
1878
|
-
await streamPipeline(response.Body, createWriteStream(wasmLocalPathAndFileName));
|
|
1879
|
-
spinner.stop();
|
|
1880
1871
|
// 3. generate the zKey
|
|
1872
|
+
const spinner = customSpinner(`Generating genesis zKey for circuit ${theme.text.bold(circuit.name)}...`, `clock`);
|
|
1873
|
+
spinner.start();
|
|
1881
1874
|
await zKey.newZKey(r1csLocalPathAndFileName, getPotLocalFilePath(circuit.files.potFilename), zkeyLocalPathAndFileName, undefined);
|
|
1875
|
+
spinner.succeed(`Generation of the genesis zKey for citcui ${theme.text.bold(circuit.name)} completed successfully`);
|
|
1882
1876
|
// 4. calculate the hashes
|
|
1883
1877
|
const wasmBlake2bHash = await blake512FromPath(wasmLocalPathAndFileName);
|
|
1884
1878
|
const potBlake2bHash = await blake512FromPath(getPotLocalFilePath(circuit.files.potFilename));
|
|
@@ -2113,8 +2107,9 @@ const onVerification = async (verification) => {
|
|
|
2113
2107
|
clipboard.writeSync(verification.user_code);
|
|
2114
2108
|
clipboard.readSync();
|
|
2115
2109
|
// Display data.
|
|
2116
|
-
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`);
|
|
2117
|
-
console.log(
|
|
2110
|
+
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" })), '\n');
|
|
2112
|
+
console.log(`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} has been copied to your clipboard (${theme.emojis.clipboard} ${theme.symbols.success})\n`);
|
|
2118
2113
|
const spinner = customSpinner(`Redirecting to Github...`, `clock`);
|
|
2119
2114
|
spinner.start();
|
|
2120
2115
|
await sleep(10000); // ~10s to make users able to read the CLI.
|
|
@@ -2407,7 +2402,6 @@ const listenToCeremonyCircuitDocumentChanges = (firestoreDatabase, ceremonyId, p
|
|
|
2407
2402
|
const { avgTimings, waitingQueue } = changedCircuit.data();
|
|
2408
2403
|
const { fullContribution, verifyCloudFunction } = avgTimings;
|
|
2409
2404
|
const { currentContributor } = waitingQueue;
|
|
2410
|
-
// Get circuit current contributor participant document.
|
|
2411
2405
|
const circuitCurrentContributor = await getDocumentById(firestoreDatabase, getParticipantsCollectionPath(ceremonyId), currentContributor);
|
|
2412
2406
|
// Check data.
|
|
2413
2407
|
if (!circuitCurrentContributor.data())
|
|
@@ -2566,8 +2560,8 @@ const listenToParticipantDocumentChanges = async (firestoreDatabase, cloudFuncti
|
|
|
2566
2560
|
// Communicate resume / start of the contribution to participant.
|
|
2567
2561
|
await simpleLoader(`${changedContributionStep === "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */ ? `Starting` : `Resuming`} your contribution...`, `clock`, 3000);
|
|
2568
2562
|
// Start / Resume the contribution for the participant.
|
|
2569
|
-
await handleStartOrResumeContribution(cloudFunctions, firestoreDatabase, ceremony, circuit, participant, entropy, providerUserId, false // not finalizing.
|
|
2570
|
-
);
|
|
2563
|
+
await handleStartOrResumeContribution(cloudFunctions, firestoreDatabase, ceremony, circuit, participant, entropy, providerUserId, false, // not finalizing.
|
|
2564
|
+
circuits.length);
|
|
2571
2565
|
}
|
|
2572
2566
|
// Scenario (3.A).
|
|
2573
2567
|
else if (isWaitingForContribution)
|
|
@@ -2616,7 +2610,7 @@ const listenToParticipantDocumentChanges = async (firestoreDatabase, cloudFuncti
|
|
|
2616
2610
|
// Get latest contribution verification result.
|
|
2617
2611
|
await getLatestVerificationResult(firestoreDatabase, ceremony.id, circuit.id, participant.id);
|
|
2618
2612
|
// Get next circuit for contribution.
|
|
2619
|
-
const nextCircuit = getCircuitBySequencePosition(circuits, changedContributionProgress + 1);
|
|
2613
|
+
const nextCircuit = timeoutExpired ? getCircuitBySequencePosition(circuits, changedContributionProgress) : getCircuitBySequencePosition(circuits, changedContributionProgress + 1);
|
|
2620
2614
|
// Check disk space requirements for participant.
|
|
2621
2615
|
const wannaGenerateAttestation = await handleDiskSpaceRequirementForNextContribution(cloudFunctions, ceremony.id, nextCircuit.data.sequencePosition, nextCircuit.data.zKeySizeInBytes, timeoutExpired, providerUserId);
|
|
2622
2616
|
// Check if the participant would like to generate a new attestation.
|
|
@@ -2654,11 +2648,12 @@ const listenToParticipantDocumentChanges = async (firestoreDatabase, cloudFuncti
|
|
|
2654
2648
|
*/
|
|
2655
2649
|
const contribute = async (opt) => {
|
|
2656
2650
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices();
|
|
2657
|
-
// Check for authentication.
|
|
2658
|
-
const { user, providerUserId, token } = await checkAuth(firebaseApp);
|
|
2659
2651
|
// Get options.
|
|
2660
2652
|
const ceremonyOpt = opt.ceremony;
|
|
2661
2653
|
const entropyOpt = opt.entropy;
|
|
2654
|
+
const auth = opt.auth;
|
|
2655
|
+
// Check for authentication.
|
|
2656
|
+
const { user, providerUserId, token } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp);
|
|
2662
2657
|
// Prepare data.
|
|
2663
2658
|
let selectedCeremony;
|
|
2664
2659
|
// Retrieve the opened ceremonies.
|
|
@@ -2694,7 +2689,7 @@ const contribute = async (opt) => {
|
|
|
2694
2689
|
const userDoc = await getDocumentById(firestoreDatabase, commonTerms.collections.users.name, user.uid);
|
|
2695
2690
|
const userData = userDoc.data();
|
|
2696
2691
|
if (!userData) {
|
|
2697
|
-
spinner.fail(`Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. Please contact the coordinator if you believe this to be an error.`);
|
|
2692
|
+
spinner.fail(`Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`);
|
|
2698
2693
|
process.exit(0);
|
|
2699
2694
|
}
|
|
2700
2695
|
// Check the user's current participant readiness for contribution status (eligible, already contributed, timed out).
|
|
@@ -2914,7 +2909,7 @@ const handleVerifierSmartContract = async (cloudFunctions, bucketName, finalZkey
|
|
|
2914
2909
|
const packagePath = `${dirname(fileURLToPath(import.meta.url))}`;
|
|
2915
2910
|
const verifierPath = packagePath.includes(`src/commands`)
|
|
2916
2911
|
? `${dirname(fileURLToPath(import.meta.url))}/../../../../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
2917
|
-
: `${dirname(fileURLToPath(import.meta.url))}
|
|
2912
|
+
: `${dirname(fileURLToPath(import.meta.url))}/../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`;
|
|
2918
2913
|
// Export the Solidity verifier smart contract.
|
|
2919
2914
|
const verifierCode = await exportVerifierContract(finalZkeyLocalFilePath, verifierPath);
|
|
2920
2915
|
spinner.text = `Writing verifier smart contract...`;
|
|
@@ -2941,10 +2936,11 @@ const handleVerifierSmartContract = async (cloudFunctions, bucketName, finalZkey
|
|
|
2941
2936
|
* @param participant <FirebaseDocumentInfo> - the Firestore document of the participant (coordinator).
|
|
2942
2937
|
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
2943
2938
|
* @param coordinatorIdentifier <string> - the identifier of the coordinator.
|
|
2939
|
+
* @param circuitsLength <number> - the number of circuits in the ceremony.
|
|
2944
2940
|
*/
|
|
2945
|
-
const handleCircuitFinalization = async (cloudFunctions, firestoreDatabase, ceremony, circuit, participant, beacon, coordinatorIdentifier) => {
|
|
2941
|
+
const handleCircuitFinalization = async (cloudFunctions, firestoreDatabase, ceremony, circuit, participant, beacon, coordinatorIdentifier, circuitsLength) => {
|
|
2946
2942
|
// Step (1).
|
|
2947
|
-
await handleStartOrResumeContribution(cloudFunctions, firestoreDatabase, ceremony, circuit, participant, computeSHA256ToHex(beacon), coordinatorIdentifier, true);
|
|
2943
|
+
await handleStartOrResumeContribution(cloudFunctions, firestoreDatabase, ceremony, circuit, participant, computeSHA256ToHex(beacon), coordinatorIdentifier, true, circuitsLength);
|
|
2948
2944
|
await sleep(2000); // workaound for descriptors.
|
|
2949
2945
|
// Extract data.
|
|
2950
2946
|
const { prefix: circuitPrefix } = circuit.data;
|
|
@@ -2979,10 +2975,11 @@ const handleCircuitFinalization = async (cloudFunctions, firestoreDatabase, cere
|
|
|
2979
2975
|
* @dev For proper execution, the command requires the coordinator to be authenticated with a GitHub account (run auth command first) in order to
|
|
2980
2976
|
* handle sybil-resistance and connect to GitHub APIs to publish the gist containing the final public attestation.
|
|
2981
2977
|
*/
|
|
2982
|
-
const finalize = async () => {
|
|
2978
|
+
const finalize = async (opt) => {
|
|
2983
2979
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices();
|
|
2984
2980
|
// Check for authentication.
|
|
2985
|
-
const
|
|
2981
|
+
const auth = opt.auth;
|
|
2982
|
+
const { user, providerUserId, token: coordinatorAccessToken } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp);
|
|
2986
2983
|
// Preserve command execution only for coordinators.
|
|
2987
2984
|
if (!(await isCoordinator(user)))
|
|
2988
2985
|
showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true);
|
|
@@ -3017,7 +3014,7 @@ const finalize = async () => {
|
|
|
3017
3014
|
const circuits = await getCeremonyCircuits(firestoreDatabase, selectedCeremony.id);
|
|
3018
3015
|
// Handle finalization for each ceremony circuit.
|
|
3019
3016
|
for await (const circuit of circuits)
|
|
3020
|
-
await handleCircuitFinalization(firebaseFunctions, firestoreDatabase, selectedCeremony, circuit, participant, beacon, providerUserId);
|
|
3017
|
+
await handleCircuitFinalization(firebaseFunctions, firestoreDatabase, selectedCeremony, circuit, participant, beacon, providerUserId, circuits.length);
|
|
3021
3018
|
process.stdout.write(`\n`);
|
|
3022
3019
|
const spinner = customSpinner(`Wrapping up the finalization of the ceremony...`, "clock");
|
|
3023
3020
|
spinner.start();
|
|
@@ -3032,7 +3029,7 @@ const finalize = async () => {
|
|
|
3032
3029
|
// Generate attestation with final contributions.
|
|
3033
3030
|
const publicAttestation = await generateValidContributionsAttestation(firestoreDatabase, circuits, selectedCeremony.id, participant.id, contributions, providerUserId, ceremonyName, true);
|
|
3034
3031
|
// Write public attestation locally.
|
|
3035
|
-
writeFile(
|
|
3032
|
+
writeFile(getFinalAttestationLocalFilePath(`${prefix}_${finalContributionIndex}_${commonTerms.foldersAndPathsTerms.attestation}.log`), Buffer.from(publicAttestation));
|
|
3036
3033
|
await sleep(3000); // workaround for file descriptor unexpected close.
|
|
3037
3034
|
const gistUrl = await publishGist(coordinatorAccessToken, publicAttestation, ceremonyName, prefix);
|
|
3038
3035
|
console.log(`\n${theme.symbols.info} Your public final attestation has been successfully posted as Github Gist (${theme.text.bold(theme.text.underlined(gistUrl))})`);
|
|
@@ -3168,6 +3165,7 @@ program
|
|
|
3168
3165
|
.description("compute contributions for a Phase2 Trusted Setup ceremony circuits")
|
|
3169
3166
|
.option("-c, --ceremony <string>", "the prefix of the ceremony you want to contribute for", "")
|
|
3170
3167
|
.option("-e, --entropy <string>", "the entropy (aka toxic waste) of your contribution", "")
|
|
3168
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
3171
3169
|
.action(contribute);
|
|
3172
3170
|
program
|
|
3173
3171
|
.command("clean")
|
|
@@ -3202,5 +3200,6 @@ ceremony
|
|
|
3202
3200
|
ceremony
|
|
3203
3201
|
.command("finalize")
|
|
3204
3202
|
.description("finalize a Phase2 Trusted Setup ceremony by applying a beacon, exporting verification key and verifier contract")
|
|
3203
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
3205
3204
|
.action(finalize);
|
|
3206
3205
|
program.parseAsync(process.argv);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { Contribution, ContributionValidity, FirebaseDocumentInfo } from "@
|
|
2
|
+
import { Contribution, ContributionValidity, FirebaseDocumentInfo } from "@devtion/actions";
|
|
3
3
|
import { DocumentSnapshot, DocumentData, Firestore } from "firebase/firestore";
|
|
4
4
|
import { Functions } from "firebase/functions";
|
|
5
5
|
/**
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import { FirebaseDocumentInfo } from "@
|
|
2
|
+
import { FirebaseDocumentInfo } from "@devtion/actions";
|
|
3
3
|
import { Functions } from "firebase/functions";
|
|
4
4
|
import { Firestore } from "firebase/firestore";
|
|
5
5
|
/**
|
|
@@ -36,8 +36,9 @@ export declare const handleVerifierSmartContract: (cloudFunctions: Functions, bu
|
|
|
36
36
|
* @param participant <FirebaseDocumentInfo> - the Firestore document of the participant (coordinator).
|
|
37
37
|
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
38
38
|
* @param coordinatorIdentifier <string> - the identifier of the coordinator.
|
|
39
|
+
* @param circuitsLength <number> - the number of circuits in the ceremony.
|
|
39
40
|
*/
|
|
40
|
-
export declare const handleCircuitFinalization: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, beacon: string, coordinatorIdentifier: string) => Promise<void>;
|
|
41
|
+
export declare const handleCircuitFinalization: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, beacon: string, coordinatorIdentifier: string, circuitsLength: number) => Promise<void>;
|
|
41
42
|
/**
|
|
42
43
|
* Finalize command.
|
|
43
44
|
* @notice The finalize command allows a coordinator to finalize a Trusted Setup Phase 2 ceremony by providing the final beacon,
|
|
@@ -47,5 +48,5 @@ export declare const handleCircuitFinalization: (cloudFunctions: Functions, fire
|
|
|
47
48
|
* @dev For proper execution, the command requires the coordinator to be authenticated with a GitHub account (run auth command first) in order to
|
|
48
49
|
* handle sybil-resistance and connect to GitHub APIs to publish the gist containing the final public attestation.
|
|
49
50
|
*/
|
|
50
|
-
declare const finalize: () => Promise<void>;
|
|
51
|
+
declare const finalize: (opt: any) => Promise<void>;
|
|
51
52
|
export default finalize;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { Functions } from "firebase/functions";
|
|
3
|
-
import { CeremonyTimeoutType, CircomCompilerData, CircuitInputData, CeremonyInputData, CircuitDocument } from "@
|
|
3
|
+
import { CeremonyTimeoutType, CircomCompilerData, CircuitInputData, CeremonyInputData, CircuitDocument } from "@devtion/actions";
|
|
4
4
|
/**
|
|
5
5
|
* Handle whatever is needed to obtain the input data for a circuit that the coordinator would like to add to the ceremony.
|
|
6
6
|
* @param choosenCircuitFilename <string> - the name of the circuit to add.
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { Answers } from "prompts";
|
|
2
2
|
import { Firestore } from "firebase/firestore";
|
|
3
|
-
import { CeremonyInputData, FirebaseDocumentInfo, CircomCompilerData, CircuitInputData, CeremonyTimeoutType, DiskTypeForVM } from "@
|
|
3
|
+
import { CeremonyInputData, FirebaseDocumentInfo, CircomCompilerData, CircuitInputData, CeremonyTimeoutType, DiskTypeForVM } from "@devtion/actions";
|
|
4
4
|
/**
|
|
5
5
|
* Ask a binary (yes/no or true/false) customizable question.
|
|
6
6
|
* @param question <string> - the question to be answered.
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { FirebaseDocumentInfo } from "@
|
|
1
|
+
import { FirebaseDocumentInfo } from "@devtion/actions";
|
|
2
2
|
import { OAuthCredential } from "firebase/auth";
|
|
3
3
|
import { DocumentData, Firestore } from "firebase/firestore";
|
|
4
4
|
import { Functions } from "firebase/functions";
|
|
@@ -154,5 +154,6 @@ export declare const getLatestUpdatesFromParticipant: (firestoreDatabase: Firest
|
|
|
154
154
|
* @param entropyOrBeaconHash <string> - the entropy or beacon hash (only when finalizing) for the contribution.
|
|
155
155
|
* @param contributorOrCoordinatorIdentifier <string> - the identifier of the contributor or coordinator (only when finalizing).
|
|
156
156
|
* @param isFinalizing <boolean> - flag to discriminate between ceremony finalization (true) and contribution (false).
|
|
157
|
+
* @param circuitsLength <number> - the total number of circuits in the ceremony.
|
|
157
158
|
*/
|
|
158
|
-
export declare const handleStartOrResumeContribution: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, entropyOrBeaconHash: any, contributorOrCoordinatorIdentifier: string, isFinalizing: boolean) => Promise<void>;
|
|
159
|
+
export declare const handleStartOrResumeContribution: (cloudFunctions: Functions, firestoreDatabase: Firestore, ceremony: FirebaseDocumentInfo, circuit: FirebaseDocumentInfo, participant: FirebaseDocumentInfo, entropyOrBeaconHash: any, contributorOrCoordinatorIdentifier: string, isFinalizing: boolean, circuitsLength: number) => Promise<void>;
|
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-3c7b092",
|
|
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",
|
|
@@ -64,10 +64,11 @@
|
|
|
64
64
|
},
|
|
65
65
|
"dependencies": {
|
|
66
66
|
"@adobe/node-fetch-retry": "^2.2.0",
|
|
67
|
+
"@aws-sdk/client-s3": "^3.329.0",
|
|
68
|
+
"@devtion/actions": "latest",
|
|
67
69
|
"@octokit/auth-oauth-app": "^5.0.5",
|
|
68
70
|
"@octokit/auth-oauth-device": "^4.0.4",
|
|
69
71
|
"@octokit/request": "^6.2.3",
|
|
70
|
-
"@p0tion/actions": "^1.0.5",
|
|
71
72
|
"blakejs": "^1.2.1",
|
|
72
73
|
"boxen": "^7.1.0",
|
|
73
74
|
"chalk": "^5.2.0",
|
|
@@ -96,5 +97,5 @@
|
|
|
96
97
|
"publishConfig": {
|
|
97
98
|
"access": "public"
|
|
98
99
|
},
|
|
99
|
-
"gitHead": "
|
|
100
|
+
"gitHead": "04a0a07eddaf6db530ae3ff3c4c61f8a12b98f91"
|
|
100
101
|
}
|
package/src/commands/auth.ts
CHANGED
|
@@ -4,6 +4,7 @@ import { Verification } from "@octokit/auth-oauth-device/dist-types/types.js"
|
|
|
4
4
|
import clipboard from "clipboardy"
|
|
5
5
|
import dotenv from "dotenv"
|
|
6
6
|
import open from "open"
|
|
7
|
+
import figlet from "figlet"
|
|
7
8
|
import { fileURLToPath } from "url"
|
|
8
9
|
import { dirname } from "path"
|
|
9
10
|
import { GENERIC_ERRORS, showError } from "../lib/errors.js"
|
|
@@ -69,10 +70,13 @@ export const onVerification = async (verification: Verification): Promise<void>
|
|
|
69
70
|
console.log(
|
|
70
71
|
`${theme.symbols.warning} Visit ${theme.text.bold(
|
|
71
72
|
theme.text.underlined(verification.verification_uri)
|
|
72
|
-
)} on this device to generate a new token and authenticate`
|
|
73
|
+
)} on this device to generate a new token and authenticate\n`
|
|
73
74
|
)
|
|
75
|
+
|
|
76
|
+
console.log(theme.colors.magenta(figlet.textSync("Code is Below", { font: "ANSI Shadow" })), '\n')
|
|
77
|
+
|
|
74
78
|
console.log(
|
|
75
|
-
`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} (${theme.emojis.clipboard} ${
|
|
79
|
+
`${theme.symbols.info} Your auth code: ${theme.text.bold(verification.user_code)} has been copied to your clipboard (${theme.emojis.clipboard} ${
|
|
76
80
|
theme.symbols.success
|
|
77
81
|
})\n`
|
|
78
82
|
)
|
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
generateValidContributionsAttestation,
|
|
23
23
|
commonTerms,
|
|
24
24
|
convertToDoubleDigits
|
|
25
|
-
} from "@
|
|
25
|
+
} from "@devtion/actions"
|
|
26
26
|
import { DocumentSnapshot, DocumentData, Firestore, onSnapshot, Timestamp } from "firebase/firestore"
|
|
27
27
|
import { Functions } from "firebase/functions"
|
|
28
28
|
import open from "open"
|
|
@@ -40,7 +40,7 @@ import {
|
|
|
40
40
|
estimateParticipantFreeGlobalDiskSpace
|
|
41
41
|
} from "../lib/utils.js"
|
|
42
42
|
import { COMMAND_ERRORS, showError } from "../lib/errors.js"
|
|
43
|
-
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
43
|
+
import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
44
44
|
import { getAttestationLocalFilePath, localPaths } from "../lib/localConfigs.js"
|
|
45
45
|
import theme from "../lib/theme.js"
|
|
46
46
|
import { checkAndMakeNewDirectoryIfNonexistent, writeFile } from "../lib/files.js"
|
|
@@ -464,7 +464,6 @@ export const listenToCeremonyCircuitDocumentChanges = (
|
|
|
464
464
|
const { fullContribution, verifyCloudFunction } = avgTimings
|
|
465
465
|
const { currentContributor } = waitingQueue
|
|
466
466
|
|
|
467
|
-
// Get circuit current contributor participant document.
|
|
468
467
|
const circuitCurrentContributor = await getDocumentById(
|
|
469
468
|
firestoreDatabase,
|
|
470
469
|
getParticipantsCollectionPath(ceremonyId),
|
|
@@ -725,7 +724,8 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
725
724
|
participant,
|
|
726
725
|
entropy,
|
|
727
726
|
providerUserId,
|
|
728
|
-
false // not finalizing.
|
|
727
|
+
false, // not finalizing.
|
|
728
|
+
circuits.length
|
|
729
729
|
)
|
|
730
730
|
}
|
|
731
731
|
// Scenario (3.A).
|
|
@@ -811,7 +811,7 @@ 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 = getCircuitBySequencePosition(circuits, changedContributionProgress + 1)
|
|
814
|
+
const nextCircuit = timeoutExpired ? getCircuitBySequencePosition(circuits, changedContributionProgress) : getCircuitBySequencePosition(circuits, changedContributionProgress + 1)
|
|
815
815
|
|
|
816
816
|
// Check disk space requirements for participant.
|
|
817
817
|
const wannaGenerateAttestation = await handleDiskSpaceRequirementForNextContribution(
|
|
@@ -892,12 +892,13 @@ export const listenToParticipantDocumentChanges = async (
|
|
|
892
892
|
const contribute = async (opt: any) => {
|
|
893
893
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
894
894
|
|
|
895
|
-
// Check for authentication.
|
|
896
|
-
const { user, providerUserId, token } = await checkAuth(firebaseApp)
|
|
897
|
-
|
|
898
895
|
// Get options.
|
|
899
896
|
const ceremonyOpt = opt.ceremony
|
|
900
897
|
const entropyOpt = opt.entropy
|
|
898
|
+
const auth = opt.auth
|
|
899
|
+
|
|
900
|
+
// Check for authentication.
|
|
901
|
+
const { user, providerUserId, token } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
901
902
|
|
|
902
903
|
// Prepare data.
|
|
903
904
|
let selectedCeremony: FirebaseDocumentInfo
|
|
@@ -949,7 +950,7 @@ const contribute = async (opt: any) => {
|
|
|
949
950
|
const userData = userDoc.data()
|
|
950
951
|
if (!userData) {
|
|
951
952
|
spinner.fail(
|
|
952
|
-
`Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. Please contact the coordinator if you believe this to be an error.`
|
|
953
|
+
`Unfortunately we could not find a user document with your information. This likely means that you did not pass the GitHub reputation checks and therefore are not elegible to contribute to any ceremony. If you believe you pass the requirements, it might be possible that your profile is private and we were not able to fetch your real statistics, in this case please consider making your profile public for the duration of the contribution. Please contact the coordinator if you believe this to be an error.`
|
|
953
954
|
)
|
|
954
955
|
process.exit(0)
|
|
955
956
|
}
|
package/src/commands/finalize.ts
CHANGED
|
@@ -22,7 +22,7 @@ import {
|
|
|
22
22
|
exportVerifierContract,
|
|
23
23
|
FirebaseDocumentInfo,
|
|
24
24
|
exportVkey
|
|
25
|
-
} from "@
|
|
25
|
+
} from "@devtion/actions"
|
|
26
26
|
import { Functions } from "firebase/functions"
|
|
27
27
|
import { Firestore } from "firebase/firestore"
|
|
28
28
|
import { dirname } from "path"
|
|
@@ -36,9 +36,9 @@ import {
|
|
|
36
36
|
sleep,
|
|
37
37
|
terminate
|
|
38
38
|
} from "../lib/utils.js"
|
|
39
|
-
import { bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
39
|
+
import { authWithToken, bootstrapCommandExecutionAndServices, checkAuth } from "../lib/services.js"
|
|
40
40
|
import {
|
|
41
|
-
|
|
41
|
+
getFinalAttestationLocalFilePath,
|
|
42
42
|
getFinalZkeyLocalFilePath,
|
|
43
43
|
getVerificationKeyLocalFilePath,
|
|
44
44
|
getVerifierContractLocalFilePath,
|
|
@@ -112,7 +112,7 @@ export const handleVerifierSmartContract = async (
|
|
|
112
112
|
? `${dirname(
|
|
113
113
|
fileURLToPath(import.meta.url)
|
|
114
114
|
)}/../../../../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
115
|
-
: `${dirname(fileURLToPath(import.meta.url))}
|
|
115
|
+
: `${dirname(fileURLToPath(import.meta.url))}/../node_modules/snarkjs/templates/verifier_groth16.sol.ejs`
|
|
116
116
|
|
|
117
117
|
// Export the Solidity verifier smart contract.
|
|
118
118
|
const verifierCode = await exportVerifierContract(finalZkeyLocalFilePath, verifierPath)
|
|
@@ -152,6 +152,7 @@ export const handleVerifierSmartContract = async (
|
|
|
152
152
|
* @param participant <FirebaseDocumentInfo> - the Firestore document of the participant (coordinator).
|
|
153
153
|
* @param beacon <string> - the value used to compute the final contribution while finalizing the ceremony.
|
|
154
154
|
* @param coordinatorIdentifier <string> - the identifier of the coordinator.
|
|
155
|
+
* @param circuitsLength <number> - the number of circuits in the ceremony.
|
|
155
156
|
*/
|
|
156
157
|
export const handleCircuitFinalization = async (
|
|
157
158
|
cloudFunctions: Functions,
|
|
@@ -160,7 +161,8 @@ export const handleCircuitFinalization = async (
|
|
|
160
161
|
circuit: FirebaseDocumentInfo,
|
|
161
162
|
participant: FirebaseDocumentInfo,
|
|
162
163
|
beacon: string,
|
|
163
|
-
coordinatorIdentifier: string
|
|
164
|
+
coordinatorIdentifier: string,
|
|
165
|
+
circuitsLength: number
|
|
164
166
|
) => {
|
|
165
167
|
// Step (1).
|
|
166
168
|
await handleStartOrResumeContribution(
|
|
@@ -171,7 +173,8 @@ export const handleCircuitFinalization = async (
|
|
|
171
173
|
participant,
|
|
172
174
|
computeSHA256ToHex(beacon),
|
|
173
175
|
coordinatorIdentifier,
|
|
174
|
-
true
|
|
176
|
+
true,
|
|
177
|
+
circuitsLength
|
|
175
178
|
)
|
|
176
179
|
|
|
177
180
|
await sleep(2000) // workaound for descriptors.
|
|
@@ -241,11 +244,12 @@ export const handleCircuitFinalization = async (
|
|
|
241
244
|
* @dev For proper execution, the command requires the coordinator to be authenticated with a GitHub account (run auth command first) in order to
|
|
242
245
|
* handle sybil-resistance and connect to GitHub APIs to publish the gist containing the final public attestation.
|
|
243
246
|
*/
|
|
244
|
-
const finalize = async () => {
|
|
247
|
+
const finalize = async (opt: any) => {
|
|
245
248
|
const { firebaseApp, firebaseFunctions, firestoreDatabase } = await bootstrapCommandExecutionAndServices()
|
|
246
249
|
|
|
247
250
|
// Check for authentication.
|
|
248
|
-
const
|
|
251
|
+
const auth = opt.auth
|
|
252
|
+
const { user, providerUserId, token: coordinatorAccessToken } = auth ? await authWithToken(firebaseApp, auth) : await checkAuth(firebaseApp)
|
|
249
253
|
|
|
250
254
|
// Preserve command execution only for coordinators.
|
|
251
255
|
if (!(await isCoordinator(user))) showError(COMMAND_ERRORS.COMMAND_NOT_COORDINATOR, true)
|
|
@@ -306,7 +310,8 @@ const finalize = async () => {
|
|
|
306
310
|
circuit,
|
|
307
311
|
participant,
|
|
308
312
|
beacon,
|
|
309
|
-
providerUserId
|
|
313
|
+
providerUserId,
|
|
314
|
+
circuits.length
|
|
310
315
|
)
|
|
311
316
|
|
|
312
317
|
process.stdout.write(`\n`)
|
|
@@ -344,7 +349,7 @@ const finalize = async () => {
|
|
|
344
349
|
|
|
345
350
|
// Write public attestation locally.
|
|
346
351
|
writeFile(
|
|
347
|
-
|
|
352
|
+
getFinalAttestationLocalFilePath(
|
|
348
353
|
`${prefix}_${finalContributionIndex}_${commonTerms.foldersAndPathsTerms.attestation}.log`
|
|
349
354
|
),
|
|
350
355
|
Buffer.from(publicAttestation)
|
package/src/commands/observe.ts
CHANGED
package/src/commands/setup.ts
CHANGED
|
@@ -7,7 +7,6 @@ import { pipeline } from "node:stream"
|
|
|
7
7
|
import { promisify } from "node:util"
|
|
8
8
|
import fetch from "node-fetch"
|
|
9
9
|
import { Functions } from "firebase/functions"
|
|
10
|
-
import { S3Client, GetObjectCommand } from "@aws-sdk/client-s3"
|
|
11
10
|
import {
|
|
12
11
|
CeremonyTimeoutType,
|
|
13
12
|
CircomCompilerData,
|
|
@@ -37,7 +36,7 @@ import {
|
|
|
37
36
|
setupCeremony,
|
|
38
37
|
parseCeremonyFile,
|
|
39
38
|
CircuitContributionVerificationMechanism
|
|
40
|
-
} from "@
|
|
39
|
+
} from "@devtion/actions"
|
|
41
40
|
import { customSpinner, simpleLoader, sleep, terminate } from "../lib/utils.js"
|
|
42
41
|
import {
|
|
43
42
|
promptCeremonyInputData,
|
|
@@ -63,7 +62,6 @@ import {
|
|
|
63
62
|
getFileStats,
|
|
64
63
|
checkAndMakeNewDirectoryIfNonexistent
|
|
65
64
|
} from "../lib/files.js"
|
|
66
|
-
import { Readable } from "stream"
|
|
67
65
|
|
|
68
66
|
/**
|
|
69
67
|
* Handle whatever is needed to obtain the input data for a circuit that the coordinator would like to add to the ceremony.
|
|
@@ -516,9 +514,6 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
516
514
|
const bucketName = await handleCeremonyBucketCreation(firebaseFunctions, ceremonySetupData.ceremonyPrefix)
|
|
517
515
|
console.log(`\n${theme.symbols.success} Ceremony bucket name: ${theme.text.bold(bucketName)}`)
|
|
518
516
|
|
|
519
|
-
// create S3 clienbt
|
|
520
|
-
const s3 = new S3Client({region: 'us-east-1'})
|
|
521
|
-
|
|
522
517
|
// loop through each circuit
|
|
523
518
|
for await (const circuit of setupCeremonyData.circuits) {
|
|
524
519
|
// Local paths.
|
|
@@ -529,32 +524,14 @@ const setup = async (cmd: { template?: string, auth?: string}) => {
|
|
|
529
524
|
const zkeyLocalPathAndFileName = getZkeyLocalFilePath(circuit.files.initialZkeyFilename)
|
|
530
525
|
|
|
531
526
|
// 2. download the pot and wasm files
|
|
532
|
-
const streamPipeline = promisify(pipeline)
|
|
533
527
|
await checkAndDownloadSmallestPowersOfTau(convertToDoubleDigits(circuit.metadata?.pot!), circuit.files.potFilename)
|
|
534
528
|
|
|
535
|
-
// download the wasm to calculate the hash
|
|
536
|
-
const spinner = customSpinner(
|
|
537
|
-
`Downloading the ${theme.text.bold(
|
|
538
|
-
`#${circuit.name}`
|
|
539
|
-
)} WASM file from the project's bucket...`,
|
|
540
|
-
`clock`
|
|
541
|
-
)
|
|
542
|
-
spinner.start()
|
|
543
|
-
const command = new GetObjectCommand({ Bucket: ceremonySetupData.circuitArtifacts[index].artifacts.bucket, Key: ceremonySetupData.circuitArtifacts[index].artifacts.wasmStoragePath })
|
|
544
|
-
|
|
545
|
-
const response = await s3.send(command)
|
|
546
|
-
|
|
547
|
-
if (response.$metadata.httpStatusCode !== 200) {
|
|
548
|
-
throw new Error("There was an error while trying to download the wasm file. Please check that the file has the correct permissions (public) set.")
|
|
549
|
-
}
|
|
550
|
-
|
|
551
|
-
if (response.Body instanceof Readable)
|
|
552
|
-
await streamPipeline(response.Body, createWriteStream(wasmLocalPathAndFileName))
|
|
553
|
-
|
|
554
|
-
spinner.stop()
|
|
555
529
|
// 3. generate the zKey
|
|
530
|
+
const spinner = customSpinner(`Generating genesis zKey for circuit ${theme.text.bold(circuit.name)}...`, `clock`)
|
|
531
|
+
spinner.start()
|
|
556
532
|
await zKey.newZKey(r1csLocalPathAndFileName, getPotLocalFilePath(circuit.files.potFilename), zkeyLocalPathAndFileName, undefined)
|
|
557
|
-
|
|
533
|
+
spinner.succeed(`Generation of the genesis zKey for citcui ${theme.text.bold(circuit.name)} completed successfully`)
|
|
534
|
+
|
|
558
535
|
// 4. calculate the hashes
|
|
559
536
|
const wasmBlake2bHash = await blake512FromPath(wasmLocalPathAndFileName)
|
|
560
537
|
const potBlake2bHash = await blake512FromPath(getPotLocalFilePath(circuit.files.potFilename))
|
package/src/commands/validate.ts
CHANGED
package/src/index.ts
CHANGED
|
@@ -21,6 +21,7 @@ program
|
|
|
21
21
|
.description("compute contributions for a Phase2 Trusted Setup ceremony circuits")
|
|
22
22
|
.option("-c, --ceremony <string>", "the prefix of the ceremony you want to contribute for", "")
|
|
23
23
|
.option("-e, --entropy <string>", "the entropy (aka toxic waste) of your contribution", "")
|
|
24
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
24
25
|
.action(contribute)
|
|
25
26
|
program
|
|
26
27
|
.command("clean")
|
|
@@ -61,6 +62,7 @@ ceremony
|
|
|
61
62
|
.description(
|
|
62
63
|
"finalize a Phase2 Trusted Setup ceremony by applying a beacon, exporting verification key and verifier contract"
|
|
63
64
|
)
|
|
65
|
+
.option("-a, --auth <string>", "the Github OAuth 2.0 token", "")
|
|
64
66
|
.action(finalize)
|
|
65
67
|
|
|
66
68
|
program.parseAsync(process.argv)
|
package/src/lib/localConfigs.ts
CHANGED
package/src/lib/prompts.ts
CHANGED
package/src/lib/services.ts
CHANGED
package/src/lib/utils.ts
CHANGED
|
@@ -19,7 +19,7 @@ import {
|
|
|
19
19
|
permanentlyStoreCurrentContributionTimeAndHash,
|
|
20
20
|
progressToNextContributionStep,
|
|
21
21
|
verifyContribution
|
|
22
|
-
} from "@
|
|
22
|
+
} from "@devtion/actions"
|
|
23
23
|
import { Presets, SingleBar } from "cli-progress"
|
|
24
24
|
import dotenv from "dotenv"
|
|
25
25
|
import { GithubAuthProvider, OAuthCredential } from "firebase/auth"
|
|
@@ -311,8 +311,8 @@ 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}%20Phase%202%20Trusted%20Setup%20ceremony
|
|
315
|
-
: `https://twitter.com/intent/tweet?text=I%20contributed%20to%20the%20${ceremonyName}%20Phase%202%20Trusted%20Setup%20ceremony
|
|
314
|
+
? `https://twitter.com/intent/tweet?text=I%20have%20finalized%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") || ceremonyName.toLowerCase().includes("setup") || ceremonyName.toLowerCase().includes("phase2") || ceremonyName.toLowerCase().includes("ceremony") ? "!" : "%20Phase%202%20Trusted%20Setup%20ceremony!"}%20You%20can%20view%20my%20final%20attestation%20here:%20${gistUrl}%20#Ethereum%20#ZKP%20#PSE`
|
|
315
|
+
: `https://twitter.com/intent/tweet?text=I%20contributed%20to%20the%20${ceremonyName}${ceremonyName.toLowerCase().includes("trusted") || ceremonyName.toLowerCase().includes("setup") || ceremonyName.toLowerCase().includes("phase2") || ceremonyName.toLowerCase().includes("ceremony") ? "!" : "%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`
|
|
316
316
|
|
|
317
317
|
/**
|
|
318
318
|
* Return a custom progress bar.
|
|
@@ -521,6 +521,7 @@ export const getLatestUpdatesFromParticipant = async (
|
|
|
521
521
|
* @param entropyOrBeaconHash <string> - the entropy or beacon hash (only when finalizing) for the contribution.
|
|
522
522
|
* @param contributorOrCoordinatorIdentifier <string> - the identifier of the contributor or coordinator (only when finalizing).
|
|
523
523
|
* @param isFinalizing <boolean> - flag to discriminate between ceremony finalization (true) and contribution (false).
|
|
524
|
+
* @param circuitsLength <number> - the total number of circuits in the ceremony.
|
|
524
525
|
*/
|
|
525
526
|
export const handleStartOrResumeContribution = async (
|
|
526
527
|
cloudFunctions: Functions,
|
|
@@ -530,7 +531,8 @@ export const handleStartOrResumeContribution = async (
|
|
|
530
531
|
participant: FirebaseDocumentInfo,
|
|
531
532
|
entropyOrBeaconHash: any,
|
|
532
533
|
contributorOrCoordinatorIdentifier: string,
|
|
533
|
-
isFinalizing: boolean
|
|
534
|
+
isFinalizing: boolean,
|
|
535
|
+
circuitsLength: number
|
|
534
536
|
): Promise<void> => {
|
|
535
537
|
// Extract data.
|
|
536
538
|
const { prefix: ceremonyPrefix } = ceremony.data
|
|
@@ -538,7 +540,7 @@ export const handleStartOrResumeContribution = async (
|
|
|
538
540
|
const { completedContributions } = waitingQueue // = current progress.
|
|
539
541
|
|
|
540
542
|
console.log(
|
|
541
|
-
`${theme.text.bold(`\n- Circuit # ${theme.colors.magenta(`${sequencePosition}`)}`)} (Contribution Steps)`
|
|
543
|
+
`${theme.text.bold(`\n- Circuit # ${theme.colors.magenta(`${sequencePosition}/${circuitsLength}`)}`)} (Contribution Steps)`
|
|
542
544
|
)
|
|
543
545
|
|
|
544
546
|
// Get most up-to-date data from the participant document.
|
|
@@ -696,7 +698,7 @@ export const handleStartOrResumeContribution = async (
|
|
|
696
698
|
!isFinalizing ? theme.text.bold(`#${nextZkeyIndex}`) : ""
|
|
697
699
|
} to storage.\n${
|
|
698
700
|
theme.symbols.warning
|
|
699
|
-
} This step may take a while based on circuit size and your
|
|
701
|
+
} This step may take a while based on circuit size and your internet speed. Everything's fine, just be patient.`
|
|
700
702
|
spinner.start()
|
|
701
703
|
|
|
702
704
|
if (!isFinalizing)
|