@devtion/backend 0.0.0-270e9e0 → 0.0.0-2e5a17d
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 +28 -2
- package/dist/src/functions/index.js +305 -168
- package/dist/src/functions/index.mjs +306 -170
- package/dist/types/functions/bandada.d.ts +4 -0
- package/dist/types/functions/bandada.d.ts.map +1 -0
- package/dist/types/functions/ceremony.d.ts.map +1 -1
- package/dist/types/functions/circuit.d.ts.map +1 -1
- package/dist/types/functions/index.d.ts +1 -0
- package/dist/types/functions/index.d.ts.map +1 -1
- package/dist/types/functions/storage.d.ts.map +1 -1
- package/dist/types/functions/timeout.d.ts.map +1 -1
- package/dist/types/functions/user.d.ts.map +1 -1
- package/dist/types/lib/errors.d.ts +2 -1
- package/dist/types/lib/errors.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts +1 -1
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +26 -1
- package/dist/types/types/index.d.ts.map +1 -1
- package/package.json +5 -4
- package/src/functions/bandada.ts +156 -0
- package/src/functions/ceremony.ts +9 -4
- package/src/functions/circuit.ts +137 -185
- package/src/functions/index.ts +1 -0
- package/src/functions/participant.ts +9 -9
- package/src/functions/storage.ts +7 -4
- package/src/functions/timeout.ts +5 -4
- package/src/functions/user.ts +35 -10
- package/src/lib/errors.ts +6 -1
- package/src/lib/utils.ts +11 -9
- package/src/types/declarations.d.ts +1 -0
- package/src/types/index.ts +28 -1
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @module @p0tion/backend
|
|
3
|
-
* @version 1.
|
|
3
|
+
* @version 1.1.1
|
|
4
4
|
* @file MPC Phase 2 backend for Firebase services management
|
|
5
5
|
* @copyright Ethereum Foundation 2022
|
|
6
6
|
* @license MIT
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import admin from 'firebase-admin';
|
|
10
10
|
import * as functions from 'firebase-functions';
|
|
11
11
|
import dotenv from 'dotenv';
|
|
12
|
-
import { getCircuitsCollectionPath, getTimeoutsCollectionPath, commonTerms, finalContributionIndex, getContributionsCollectionPath, githubReputation, getBucketName, vmBootstrapCommand, vmDependenciesAndCacheArtifactsCommand, vmBootstrapScriptFilename, computeDiskSizeForVM, createEC2Instance, getParticipantsCollectionPath, terminateEC2Instance, formatZkeyIndex, getTranscriptStorageFilePath, getZkeyStorageFilePath, startEC2Instance, vmContributionVerificationCommand, runCommandUsingSSM, getPotStorageFilePath, genesisZkeyIndex, createCustomLoggerForFile, blake512FromPath, getVerificationKeyStorageFilePath, getVerifierContractStorageFilePath, computeSHA256ToHex,
|
|
12
|
+
import { getCircuitsCollectionPath, getTimeoutsCollectionPath, commonTerms, finalContributionIndex, getContributionsCollectionPath, githubReputation, getBucketName, vmBootstrapCommand, vmDependenciesAndCacheArtifactsCommand, vmBootstrapScriptFilename, computeDiskSizeForVM, createEC2Instance, getParticipantsCollectionPath, terminateEC2Instance, formatZkeyIndex, getTranscriptStorageFilePath, getZkeyStorageFilePath, startEC2Instance, vmContributionVerificationCommand, runCommandUsingSSM, getPotStorageFilePath, genesisZkeyIndex, createCustomLoggerForFile, blake512FromPath, getVerificationKeyStorageFilePath, getVerifierContractStorageFilePath, computeSHA256ToHex, checkIfRunning, retrieveCommandOutput, stopEC2Instance, verificationKeyAcronym, verifierSmartContractAcronym, retrieveCommandStatus } from '@p0tion/actions';
|
|
13
13
|
import { encode } from 'html-entities';
|
|
14
14
|
import { Timestamp, FieldValue } from 'firebase-admin/firestore';
|
|
15
15
|
import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadBucketCommand, CreateBucketCommand, PutPublicAccessBlockCommand, PutBucketCorsCommand, HeadObjectCommand, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3';
|
|
@@ -28,7 +28,9 @@ import { EC2Client } from '@aws-sdk/client-ec2';
|
|
|
28
28
|
import * as functionsV1 from 'firebase-functions/v1';
|
|
29
29
|
import * as functionsV2 from 'firebase-functions/v2';
|
|
30
30
|
import { Timer } from 'timer-node';
|
|
31
|
-
import { zKey } from 'snarkjs';
|
|
31
|
+
import { zKey, groth16 } from 'snarkjs';
|
|
32
|
+
import { ApiSdk } from '@bandada/api-sdk';
|
|
33
|
+
import { getAuth } from 'firebase-admin/auth';
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Log levels.
|
|
@@ -49,7 +51,7 @@ var LogLevel;
|
|
|
49
51
|
* @notice the set of Firebase Functions status codes. The codes are the same at the
|
|
50
52
|
* ones exposed by {@link https://github.com/grpc/grpc/blob/master/doc/statuscodes.md | gRPC}.
|
|
51
53
|
* @param errorCode <FunctionsErrorCode> - the set of possible error codes.
|
|
52
|
-
* @param message <string> - the error
|
|
54
|
+
* @param message <string> - the error message.
|
|
53
55
|
* @param [details] <string> - the details of the error (optional).
|
|
54
56
|
* @returns <HttpsError>
|
|
55
57
|
*/
|
|
@@ -121,7 +123,8 @@ const SPECIFIC_ERRORS = {
|
|
|
121
123
|
SE_VM_FAILED_COMMAND_EXECUTION: makeError("failed-precondition", "VM command execution failed", "Please, contact the coordinator if this error persists."),
|
|
122
124
|
SE_VM_TIMEDOUT_COMMAND_EXECUTION: makeError("deadline-exceeded", "VM command execution took too long and has been timed-out", "Please, contact the coordinator if this error persists."),
|
|
123
125
|
SE_VM_CANCELLED_COMMAND_EXECUTION: makeError("cancelled", "VM command execution has been cancelled", "Please, contact the coordinator if this error persists."),
|
|
124
|
-
SE_VM_DELAYED_COMMAND_EXECUTION: makeError("unavailable", "VM command execution has been delayed since there were no available instance at the moment", "Please, contact the coordinator if this error persists.")
|
|
126
|
+
SE_VM_DELAYED_COMMAND_EXECUTION: makeError("unavailable", "VM command execution has been delayed since there were no available instance at the moment", "Please, contact the coordinator if this error persists."),
|
|
127
|
+
SE_VM_UNKNOWN_COMMAND_STATUS: makeError("unavailable", "VM command execution has failed due to an unknown status code", "Please, contact the coordinator if this error persists.")
|
|
125
128
|
};
|
|
126
129
|
/**
|
|
127
130
|
* A set of common errors.
|
|
@@ -264,7 +267,7 @@ const queryOpenedCeremonies = async () => {
|
|
|
264
267
|
const getCircuitDocumentByPosition = async (ceremonyId, sequencePosition) => {
|
|
265
268
|
// Query for all ceremony circuits.
|
|
266
269
|
const circuits = await getCeremonyCircuits(ceremonyId);
|
|
267
|
-
// Apply a filter using the sequence
|
|
270
|
+
// Apply a filter using the sequence position.
|
|
268
271
|
const matchedCircuits = circuits.filter((circuit) => circuit.data().sequencePosition === sequencePosition);
|
|
269
272
|
if (matchedCircuits.length !== 1)
|
|
270
273
|
logAndThrowError(COMMON_ERRORS.CM_NO_CIRCUIT_FOR_GIVEN_SEQUENCE_POSITION);
|
|
@@ -305,7 +308,7 @@ const downloadArtifactFromS3Bucket = async (bucketName, objectKey, localFilePath
|
|
|
305
308
|
const writeStream = createWriteStream(localFilePath);
|
|
306
309
|
const streamPipeline = promisify(pipeline);
|
|
307
310
|
await streamPipeline(response.body, writeStream);
|
|
308
|
-
writeStream.on(
|
|
311
|
+
writeStream.on("finish", () => {
|
|
309
312
|
writeStream.end();
|
|
310
313
|
});
|
|
311
314
|
};
|
|
@@ -429,12 +432,14 @@ const htmlEncodeCircuitData = (circuitDocument) => ({
|
|
|
429
432
|
const getGitHubVariables = () => {
|
|
430
433
|
if (!process.env.GITHUB_MINIMUM_FOLLOWERS ||
|
|
431
434
|
!process.env.GITHUB_MINIMUM_FOLLOWING ||
|
|
432
|
-
!process.env.GITHUB_MINIMUM_PUBLIC_REPOS
|
|
435
|
+
!process.env.GITHUB_MINIMUM_PUBLIC_REPOS ||
|
|
436
|
+
!process.env.GITHUB_MINIMUM_AGE)
|
|
433
437
|
logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
|
|
434
438
|
return {
|
|
435
439
|
minimumFollowers: Number(process.env.GITHUB_MINIMUM_FOLLOWERS),
|
|
436
440
|
minimumFollowing: Number(process.env.GITHUB_MINIMUM_FOLLOWING),
|
|
437
|
-
minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS)
|
|
441
|
+
minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS),
|
|
442
|
+
minimumAge: Number(process.env.GITHUB_MINIMUM_AGE)
|
|
438
443
|
};
|
|
439
444
|
};
|
|
440
445
|
/**
|
|
@@ -444,7 +449,7 @@ const getGitHubVariables = () => {
|
|
|
444
449
|
const getAWSVariables = () => {
|
|
445
450
|
if (!process.env.AWS_ACCESS_KEY_ID ||
|
|
446
451
|
!process.env.AWS_SECRET_ACCESS_KEY ||
|
|
447
|
-
!process.env.
|
|
452
|
+
!process.env.AWS_INSTANCE_PROFILE_ARN ||
|
|
448
453
|
!process.env.AWS_AMI_ID ||
|
|
449
454
|
!process.env.AWS_SNS_TOPIC_ARN)
|
|
450
455
|
logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
|
|
@@ -452,7 +457,7 @@ const getAWSVariables = () => {
|
|
|
452
457
|
accessKeyId: process.env.AWS_ACCESS_KEY_ID,
|
|
453
458
|
secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
|
|
454
459
|
region: process.env.AWS_REGION || "eu-central-1",
|
|
455
|
-
|
|
460
|
+
instanceProfileArn: process.env.AWS_INSTANCE_PROFILE_ARN,
|
|
456
461
|
amiId: process.env.AWS_AMI_ID,
|
|
457
462
|
snsTopic: process.env.AWS_SNS_TOPIC_ARN
|
|
458
463
|
};
|
|
@@ -521,25 +526,31 @@ const registerAuthUser = functions
|
|
|
521
526
|
const { uid } = user;
|
|
522
527
|
// Reference to a document using uid.
|
|
523
528
|
const userRef = firestore.collection(commonTerms.collections.users.name).doc(uid);
|
|
524
|
-
// html encode the display name
|
|
525
|
-
const encodedDisplayName = encode(displayName);
|
|
529
|
+
// html encode the display name (or put the ID if the name is not displayed)
|
|
530
|
+
const encodedDisplayName = user.displayName === "Null" || user.displayName === null ? user.uid : encode(displayName);
|
|
531
|
+
// store the avatar URL of a contributor
|
|
532
|
+
let avatarUrl = "";
|
|
526
533
|
// we only do reputation check if the user is not a coordinator
|
|
527
534
|
if (!(email?.endsWith(`@${process.env.CUSTOM_CLAIMS_COORDINATOR_EMAIL_ADDRESS_OR_DOMAIN}`) ||
|
|
528
535
|
email === process.env.CUSTOM_CLAIMS_COORDINATOR_EMAIL_ADDRESS_OR_DOMAIN)) {
|
|
529
536
|
const auth = admin.auth();
|
|
530
537
|
// if provider == github.com let's use our functions to check the user's reputation
|
|
531
|
-
if (user.providerData[0].providerId === "github.com") {
|
|
538
|
+
if (user.providerData.length > 0 && user.providerData[0].providerId === "github.com") {
|
|
532
539
|
const vars = getGitHubVariables();
|
|
533
540
|
// this return true or false
|
|
534
541
|
try {
|
|
535
|
-
const
|
|
536
|
-
if (!
|
|
542
|
+
const { reputable, avatarUrl: avatarURL } = await githubReputation(user.providerData[0].uid, vars.minimumFollowing, vars.minimumFollowers, vars.minimumPublicRepos, vars.minimumAge);
|
|
543
|
+
if (!reputable) {
|
|
537
544
|
// Delete user
|
|
538
545
|
await auth.deleteUser(user.uid);
|
|
539
546
|
// Throw error
|
|
540
|
-
logAndThrowError(makeError("permission-denied", "The user is not allowed to sign up because their Github reputation is not high enough.", `The user ${user.displayName
|
|
547
|
+
logAndThrowError(makeError("permission-denied", "The user is not allowed to sign up because their Github reputation is not high enough.", `The user ${user.displayName === "Null" || user.displayName === null
|
|
548
|
+
? user.uid
|
|
549
|
+
: user.displayName} is not allowed to sign up because their Github reputation is not high enough. Please contact the administrator if you think this is a mistake.`));
|
|
541
550
|
}
|
|
542
|
-
|
|
551
|
+
// store locally
|
|
552
|
+
avatarUrl = avatarURL;
|
|
553
|
+
printLog(`Github reputation check passed for user ${user.displayName === "Null" || user.displayName === null ? user.uid : user.displayName}`, LogLevel.DEBUG);
|
|
543
554
|
}
|
|
544
555
|
catch (error) {
|
|
545
556
|
// Delete user
|
|
@@ -549,19 +560,27 @@ const registerAuthUser = functions
|
|
|
549
560
|
}
|
|
550
561
|
}
|
|
551
562
|
// Set document (nb. we refer to providerData[0] because we use Github OAuth provider only).
|
|
563
|
+
// In future releases we might want to loop through the providerData array as we support
|
|
564
|
+
// more providers.
|
|
552
565
|
await userRef.set({
|
|
553
566
|
name: encodedDisplayName,
|
|
554
567
|
encodedDisplayName,
|
|
555
568
|
// Metadata.
|
|
556
569
|
creationTime,
|
|
557
|
-
lastSignInTime,
|
|
570
|
+
lastSignInTime: lastSignInTime || creationTime,
|
|
558
571
|
// Optional.
|
|
559
572
|
email: email || "",
|
|
560
573
|
emailVerified: emailVerified || false,
|
|
561
574
|
photoURL: photoURL || "",
|
|
562
575
|
lastUpdated: getCurrentServerTimestampInMillis()
|
|
563
576
|
});
|
|
577
|
+
// we want to create a new collection for the users to store the avatars
|
|
578
|
+
const avatarRef = firestore.collection(commonTerms.collections.avatars.name).doc(uid);
|
|
579
|
+
await avatarRef.set({
|
|
580
|
+
avatarUrl: avatarUrl || ""
|
|
581
|
+
});
|
|
564
582
|
printLog(`Authenticated user document with identifier ${uid} has been correctly stored`, LogLevel.DEBUG);
|
|
583
|
+
printLog(`Authenticated user avatar with identifier ${uid} has been correctly stored`, LogLevel.DEBUG);
|
|
565
584
|
});
|
|
566
585
|
/**
|
|
567
586
|
* Set custom claims for role-based access control on the newly created user.
|
|
@@ -698,7 +717,7 @@ const setupCeremony = functions
|
|
|
698
717
|
// Check if using the VM approach for contribution verification.
|
|
699
718
|
if (circuit.verification.cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */) {
|
|
700
719
|
// VM command to be run at the startup.
|
|
701
|
-
const startupCommand = vmBootstrapCommand(bucketName);
|
|
720
|
+
const startupCommand = vmBootstrapCommand(`${bucketName}/circuits/${circuit.name}`);
|
|
702
721
|
// Get EC2 client.
|
|
703
722
|
const ec2Client = await createEC2Client();
|
|
704
723
|
// Get AWS variables.
|
|
@@ -707,7 +726,8 @@ const setupCeremony = functions
|
|
|
707
726
|
const vmCommands = vmDependenciesAndCacheArtifactsCommand(`${bucketName}/${circuit.files?.initialZkeyStoragePath}`, `${bucketName}/${circuit.files?.potStoragePath}`, snsTopic, region);
|
|
708
727
|
printLog(`Check VM dependencies and cache artifacts commands ${vmCommands.join("\n")}`, LogLevel.DEBUG);
|
|
709
728
|
// Upload the post-startup commands script file.
|
|
710
|
-
|
|
729
|
+
printLog(`Uploading VM post-startup commands script file ${vmBootstrapScriptFilename}`, LogLevel.DEBUG);
|
|
730
|
+
await uploadFileToBucketNoFile(bucketName, `circuits/${circuit.name}/${vmBootstrapScriptFilename}`, vmCommands.join("\n"));
|
|
711
731
|
// Compute the VM disk space requirement (in GB).
|
|
712
732
|
const vmDiskSize = computeDiskSizeForVM(circuit.zKeySizeInBytes, circuit.metadata?.pot);
|
|
713
733
|
printLog(`Check VM startup commands ${startupCommand.join("\n")}`, LogLevel.DEBUG);
|
|
@@ -801,7 +821,7 @@ const finalizeCeremony = functions
|
|
|
801
821
|
// Get ceremony circuits.
|
|
802
822
|
const circuits = await getCeremonyCircuits(ceremonyId);
|
|
803
823
|
// Get final contribution for each circuit.
|
|
804
|
-
// nb. the `getFinalContributionDocument` checks the
|
|
824
|
+
// nb. the `getFinalContributionDocument` checks the existence of the final contribution document (if not present, throws).
|
|
805
825
|
// Therefore, we just need to call the method without taking any data to verify the pre-condition of having already computed
|
|
806
826
|
// the final contributions for each ceremony circuit.
|
|
807
827
|
for await (const circuit of circuits)
|
|
@@ -854,7 +874,7 @@ dotenv.config();
|
|
|
854
874
|
* @dev true when the participant can participate (1.A, 3.B, 1.D); otherwise false.
|
|
855
875
|
*/
|
|
856
876
|
const checkParticipantForCeremony = functions
|
|
857
|
-
.region(
|
|
877
|
+
.region("europe-west1")
|
|
858
878
|
.runWith({
|
|
859
879
|
memory: "512MB"
|
|
860
880
|
})
|
|
@@ -925,7 +945,7 @@ const checkParticipantForCeremony = functions
|
|
|
925
945
|
participantDoc.ref.update({
|
|
926
946
|
status: "EXHUMED" /* ParticipantStatus.EXHUMED */,
|
|
927
947
|
contributions,
|
|
928
|
-
tempContributionData: tempContributionData
|
|
948
|
+
tempContributionData: tempContributionData || FieldValue.delete(),
|
|
929
949
|
contributionStep: "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */,
|
|
930
950
|
contributionStartedAt: 0,
|
|
931
951
|
verificationStartedAt: FieldValue.delete(),
|
|
@@ -958,7 +978,7 @@ const checkParticipantForCeremony = functions
|
|
|
958
978
|
* 2) the participant has just finished the contribution for a circuit (contributionProgress != 0 && status = CONTRIBUTED && contributionStep = COMPLETED).
|
|
959
979
|
*/
|
|
960
980
|
const progressToNextCircuitForContribution = functions
|
|
961
|
-
.region(
|
|
981
|
+
.region("europe-west1")
|
|
962
982
|
.runWith({
|
|
963
983
|
memory: "512MB"
|
|
964
984
|
})
|
|
@@ -1005,7 +1025,7 @@ const progressToNextCircuitForContribution = functions
|
|
|
1005
1025
|
* 5) Completed contribution computation and verification.
|
|
1006
1026
|
*/
|
|
1007
1027
|
const progressToNextContributionStep = functions
|
|
1008
|
-
.region(
|
|
1028
|
+
.region("europe-west1")
|
|
1009
1029
|
.runWith({
|
|
1010
1030
|
memory: "512MB"
|
|
1011
1031
|
})
|
|
@@ -1056,7 +1076,7 @@ const progressToNextContributionStep = functions
|
|
|
1056
1076
|
* @dev enable the current contributor to resume a contribution from where it had left off.
|
|
1057
1077
|
*/
|
|
1058
1078
|
const permanentlyStoreCurrentContributionTimeAndHash = functions
|
|
1059
|
-
.region(
|
|
1079
|
+
.region("europe-west1")
|
|
1060
1080
|
.runWith({
|
|
1061
1081
|
memory: "512MB"
|
|
1062
1082
|
})
|
|
@@ -1098,7 +1118,7 @@ const permanentlyStoreCurrentContributionTimeAndHash = functions
|
|
|
1098
1118
|
* @dev enable the current contributor to resume a multi-part upload from where it had left off.
|
|
1099
1119
|
*/
|
|
1100
1120
|
const temporaryStoreCurrentContributionMultiPartUploadId = functions
|
|
1101
|
-
.region(
|
|
1121
|
+
.region("europe-west1")
|
|
1102
1122
|
.runWith({
|
|
1103
1123
|
memory: "512MB"
|
|
1104
1124
|
})
|
|
@@ -1136,7 +1156,7 @@ const temporaryStoreCurrentContributionMultiPartUploadId = functions
|
|
|
1136
1156
|
* @dev enable the current contributor to resume a multi-part upload from where it had left off.
|
|
1137
1157
|
*/
|
|
1138
1158
|
const temporaryStoreCurrentContributionUploadedChunkData = functions
|
|
1139
|
-
.region(
|
|
1159
|
+
.region("europe-west1")
|
|
1140
1160
|
.runWith({
|
|
1141
1161
|
memory: "512MB"
|
|
1142
1162
|
})
|
|
@@ -1178,7 +1198,7 @@ const temporaryStoreCurrentContributionUploadedChunkData = functions
|
|
|
1178
1198
|
* contributed to every selected ceremony circuits (= DONE).
|
|
1179
1199
|
*/
|
|
1180
1200
|
const checkAndPrepareCoordinatorForFinalization = functions
|
|
1181
|
-
.region(
|
|
1201
|
+
.region("europe-west1")
|
|
1182
1202
|
.runWith({
|
|
1183
1203
|
memory: "512MB"
|
|
1184
1204
|
})
|
|
@@ -1269,6 +1289,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
|
|
|
1269
1289
|
printLog(`Coordinate - executing scenario A - single - participantResumingAfterTimeoutExpiration`, LogLevel.DEBUG);
|
|
1270
1290
|
newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
|
|
1271
1291
|
newContributionStep = "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */;
|
|
1292
|
+
newCurrentContributorId = participant.id;
|
|
1272
1293
|
}
|
|
1273
1294
|
// Scenario (B).
|
|
1274
1295
|
else if (participantIsNotCurrentContributor) {
|
|
@@ -1329,101 +1350,74 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
|
|
|
1329
1350
|
* Wait until the command has completed its execution inside the VM.
|
|
1330
1351
|
* @dev this method implements a custom interval to check 5 times after 1 minute if the command execution
|
|
1331
1352
|
* has been completed or not by calling the `retrieveCommandStatus` method.
|
|
1332
|
-
* @param {any} resolve the promise.
|
|
1333
|
-
* @param {any} reject the promise.
|
|
1334
1353
|
* @param {SSMClient} ssm the SSM client.
|
|
1335
1354
|
* @param {string} vmInstanceId the unique identifier of the VM instance.
|
|
1336
1355
|
* @param {string} commandId the unique identifier of the VM command.
|
|
1337
1356
|
* @returns <Promise<void>> true when the command execution succeed; otherwise false.
|
|
1338
1357
|
*/
|
|
1339
|
-
const waitForVMCommandExecution = (
|
|
1340
|
-
const
|
|
1358
|
+
const waitForVMCommandExecution = (ssm, vmInstanceId, commandId) => new Promise((resolve, reject) => {
|
|
1359
|
+
const poll = async () => {
|
|
1341
1360
|
try {
|
|
1342
1361
|
// Get command status.
|
|
1343
1362
|
const cmdStatus = await retrieveCommandStatus(ssm, vmInstanceId, commandId);
|
|
1344
1363
|
printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG);
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1356
|
-
|
|
1357
|
-
|
|
1358
|
-
|
|
1359
|
-
|
|
1360
|
-
|
|
1364
|
+
let error;
|
|
1365
|
+
switch (cmdStatus) {
|
|
1366
|
+
case CommandInvocationStatus.CANCELLING:
|
|
1367
|
+
case CommandInvocationStatus.CANCELLED: {
|
|
1368
|
+
error = SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION;
|
|
1369
|
+
break;
|
|
1370
|
+
}
|
|
1371
|
+
case CommandInvocationStatus.DELAYED: {
|
|
1372
|
+
error = SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION;
|
|
1373
|
+
break;
|
|
1374
|
+
}
|
|
1375
|
+
case CommandInvocationStatus.FAILED: {
|
|
1376
|
+
error = SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION;
|
|
1377
|
+
break;
|
|
1378
|
+
}
|
|
1379
|
+
case CommandInvocationStatus.TIMED_OUT: {
|
|
1380
|
+
error = SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION;
|
|
1381
|
+
break;
|
|
1382
|
+
}
|
|
1383
|
+
case CommandInvocationStatus.IN_PROGRESS:
|
|
1384
|
+
case CommandInvocationStatus.PENDING: {
|
|
1385
|
+
// wait a minute and poll again
|
|
1386
|
+
setTimeout(poll, 60000);
|
|
1387
|
+
return;
|
|
1388
|
+
}
|
|
1389
|
+
case CommandInvocationStatus.SUCCESS: {
|
|
1390
|
+
printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG);
|
|
1391
|
+
// Resolve the promise.
|
|
1392
|
+
resolve();
|
|
1393
|
+
return;
|
|
1394
|
+
}
|
|
1395
|
+
default: {
|
|
1396
|
+
logAndThrowError(SPECIFIC_ERRORS.SE_VM_UNKNOWN_COMMAND_STATUS);
|
|
1397
|
+
}
|
|
1361
1398
|
}
|
|
1362
|
-
|
|
1363
|
-
logAndThrowError(
|
|
1364
|
-
reject();
|
|
1399
|
+
if (error) {
|
|
1400
|
+
logAndThrowError(error);
|
|
1365
1401
|
}
|
|
1366
1402
|
}
|
|
1367
1403
|
catch (error) {
|
|
1368
1404
|
printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG);
|
|
1405
|
+
const ec2 = await createEC2Client();
|
|
1406
|
+
// if it errors out, let's just log it as a warning so the coordinator is aware
|
|
1407
|
+
try {
|
|
1408
|
+
await stopEC2Instance(ec2, vmInstanceId);
|
|
1409
|
+
}
|
|
1410
|
+
catch (error) {
|
|
1411
|
+
printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
|
|
1412
|
+
}
|
|
1369
1413
|
if (!error.toString().includes(commandId))
|
|
1370
1414
|
logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
|
|
1371
1415
|
// Reject the promise.
|
|
1372
1416
|
reject();
|
|
1373
1417
|
}
|
|
1374
|
-
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
}
|
|
1378
|
-
}, 60000); // 1 minute.
|
|
1379
|
-
};
|
|
1380
|
-
/**
|
|
1381
|
-
* Wait until the artifacts have been downloaded.
|
|
1382
|
-
* @param {any} resolve the promise.
|
|
1383
|
-
* @param {any} reject the promise.
|
|
1384
|
-
* @param {string} potTempFilePath the tmp path to the locally downloaded pot file.
|
|
1385
|
-
* @param {string} firstZkeyTempFilePath the tmp path to the locally downloaded first zkey file.
|
|
1386
|
-
* @param {string} lastZkeyTempFilePath the tmp path to the locally downloaded last zkey file.
|
|
1387
|
-
*/
|
|
1388
|
-
const waitForFileDownload = (resolve, reject, potTempFilePath, firstZkeyTempFilePath, lastZkeyTempFilePath, circuitId, participantId) => {
|
|
1389
|
-
const maxWaitTime = 5 * 60 * 1000; // 5 minutes
|
|
1390
|
-
// every second check if the file download was completed
|
|
1391
|
-
const interval = setInterval(async () => {
|
|
1392
|
-
printLog(`Verifying that the artifacts were downloaded for circuit ${circuitId} and participant ${participantId}`, LogLevel.DEBUG);
|
|
1393
|
-
try {
|
|
1394
|
-
// check if files have been downloaded
|
|
1395
|
-
if (!fs.existsSync(potTempFilePath)) {
|
|
1396
|
-
printLog(`Pot file not found at ${potTempFilePath}`, LogLevel.DEBUG);
|
|
1397
|
-
}
|
|
1398
|
-
if (!fs.existsSync(firstZkeyTempFilePath)) {
|
|
1399
|
-
printLog(`First zkey file not found at ${firstZkeyTempFilePath}`, LogLevel.DEBUG);
|
|
1400
|
-
}
|
|
1401
|
-
if (!fs.existsSync(lastZkeyTempFilePath)) {
|
|
1402
|
-
printLog(`Last zkey file not found at ${lastZkeyTempFilePath}`, LogLevel.DEBUG);
|
|
1403
|
-
}
|
|
1404
|
-
// if all files were downloaded
|
|
1405
|
-
if (fs.existsSync(potTempFilePath) && fs.existsSync(firstZkeyTempFilePath) && fs.existsSync(lastZkeyTempFilePath)) {
|
|
1406
|
-
printLog(`All required files are present on disk.`, LogLevel.INFO);
|
|
1407
|
-
// resolve the promise
|
|
1408
|
-
resolve();
|
|
1409
|
-
}
|
|
1410
|
-
}
|
|
1411
|
-
catch (error) {
|
|
1412
|
-
// if we have an error then we print it as a warning and reject
|
|
1413
|
-
printLog(`Error while downloading files: ${error}`, LogLevel.WARN);
|
|
1414
|
-
reject();
|
|
1415
|
-
}
|
|
1416
|
-
finally {
|
|
1417
|
-
printLog(`Clearing the interval for file download. Circuit ${circuitId} and participant ${participantId}`, LogLevel.DEBUG);
|
|
1418
|
-
clearInterval(interval);
|
|
1419
|
-
}
|
|
1420
|
-
}, 5000);
|
|
1421
|
-
// we want to clean in 5 minutes in case
|
|
1422
|
-
setTimeout(() => {
|
|
1423
|
-
clearInterval(interval);
|
|
1424
|
-
reject(new Error('Timeout exceeded while waiting for files to be downloaded.'));
|
|
1425
|
-
}, maxWaitTime);
|
|
1426
|
-
};
|
|
1418
|
+
};
|
|
1419
|
+
setTimeout(poll, 60000);
|
|
1420
|
+
});
|
|
1427
1421
|
/**
|
|
1428
1422
|
* This method is used to coordinate the waiting queues of ceremony circuits.
|
|
1429
1423
|
* @dev this cloud function is triggered whenever an update of a document related to a participant of a ceremony occurs.
|
|
@@ -1444,7 +1438,7 @@ const waitForFileDownload = (resolve, reject, potTempFilePath, firstZkeyTempFile
|
|
|
1444
1438
|
* - Just completed a contribution or all contributions for each circuit. If yes, coordinate (multi-participant scenario).
|
|
1445
1439
|
*/
|
|
1446
1440
|
const coordinateCeremonyParticipant = functionsV1
|
|
1447
|
-
.region(
|
|
1441
|
+
.region("europe-west1")
|
|
1448
1442
|
.runWith({
|
|
1449
1443
|
memory: "512MB"
|
|
1450
1444
|
})
|
|
@@ -1515,11 +1509,9 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
|
|
|
1515
1509
|
const isVMRunning = await checkIfRunning(ec2, vmInstanceId);
|
|
1516
1510
|
if (!isVMRunning) {
|
|
1517
1511
|
printLog(`VM not running, ${attempts - 1} attempts remaining. Retrying in 1 minute...`, LogLevel.DEBUG);
|
|
1518
|
-
return
|
|
1519
|
-
}
|
|
1520
|
-
else {
|
|
1521
|
-
return true;
|
|
1512
|
+
return checkIfVMRunning(ec2, vmInstanceId, attempts - 1);
|
|
1522
1513
|
}
|
|
1514
|
+
return true;
|
|
1523
1515
|
};
|
|
1524
1516
|
/**
|
|
1525
1517
|
* Verify the contribution of a participant computed while contributing to a specific circuit of a ceremony.
|
|
@@ -1547,7 +1539,7 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
|
|
|
1547
1539
|
* 1.A.4.C.1) If true, update circuit waiting for queue and average timings accordingly to contribution verification results;
|
|
1548
1540
|
* 2) Send all updates atomically to the Firestore database.
|
|
1549
1541
|
*/
|
|
1550
|
-
const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region:
|
|
1542
|
+
const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" }, async (request) => {
|
|
1551
1543
|
if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
|
|
1552
1544
|
logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
|
|
1553
1545
|
if (!request.data.ceremonyId ||
|
|
@@ -1658,8 +1650,6 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1658
1650
|
lastZkeyBlake2bHash = match.at(0);
|
|
1659
1651
|
// re upload the formatted verification transcript
|
|
1660
1652
|
await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
|
|
1661
|
-
// Stop VM instance.
|
|
1662
|
-
await stopEC2Instance(ec2, vmInstanceId);
|
|
1663
1653
|
}
|
|
1664
1654
|
else {
|
|
1665
1655
|
// Upload verification transcript.
|
|
@@ -1720,6 +1710,18 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1720
1710
|
lastUpdated: getCurrentServerTimestampInMillis()
|
|
1721
1711
|
});
|
|
1722
1712
|
}
|
|
1713
|
+
// Stop VM instance
|
|
1714
|
+
if (isUsingVM) {
|
|
1715
|
+
// using try and catch as the VM stopping function can throw
|
|
1716
|
+
// however we want to continue without stopping as the
|
|
1717
|
+
// verification was valid, and inform the coordinator
|
|
1718
|
+
try {
|
|
1719
|
+
await stopEC2Instance(ec2, vmInstanceId);
|
|
1720
|
+
}
|
|
1721
|
+
catch (error) {
|
|
1722
|
+
printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
|
|
1723
|
+
}
|
|
1724
|
+
}
|
|
1723
1725
|
// Step (1.A.4.C)
|
|
1724
1726
|
if (!isFinalizing) {
|
|
1725
1727
|
// Step (1.A.4.C.1)
|
|
@@ -1735,6 +1737,8 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1735
1737
|
? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
|
|
1736
1738
|
: verifyCloudFunctionTime;
|
|
1737
1739
|
// Prepare tx to update circuit average contribution/verification time.
|
|
1740
|
+
const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId);
|
|
1741
|
+
const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
|
|
1738
1742
|
/// @dev this must happen only for valid contributions.
|
|
1739
1743
|
batch.update(circuitDoc.ref, {
|
|
1740
1744
|
avgTimings: {
|
|
@@ -1747,7 +1751,7 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1747
1751
|
: avgVerifyCloudFunctionTime
|
|
1748
1752
|
},
|
|
1749
1753
|
waitingQueue: {
|
|
1750
|
-
...
|
|
1754
|
+
...updatedWaitingQueue,
|
|
1751
1755
|
completedContributions: isContributionValid
|
|
1752
1756
|
? completedContributions + 1
|
|
1753
1757
|
: completedContributions,
|
|
@@ -1782,7 +1786,7 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1782
1786
|
commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
|
|
1783
1787
|
printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
|
|
1784
1788
|
// Step (1.A.3.3).
|
|
1785
|
-
return
|
|
1789
|
+
return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
|
|
1786
1790
|
.then(async () => {
|
|
1787
1791
|
// Command execution successfully completed.
|
|
1788
1792
|
printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
|
|
@@ -1794,52 +1798,38 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1794
1798
|
logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
|
|
1795
1799
|
});
|
|
1796
1800
|
}
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
|
|
1813
|
-
|
|
1814
|
-
|
|
1815
|
-
|
|
1816
|
-
|
|
1817
|
-
|
|
1818
|
-
|
|
1819
|
-
|
|
1820
|
-
|
|
1821
|
-
|
|
1822
|
-
|
|
1823
|
-
|
|
1824
|
-
// Free resources by unlinking temporary folders.
|
|
1825
|
-
// Do not free-up verification transcript path here.
|
|
1826
|
-
try {
|
|
1827
|
-
fs.unlinkSync(potTempFilePath);
|
|
1828
|
-
fs.unlinkSync(firstZkeyTempFilePath);
|
|
1829
|
-
fs.unlinkSync(lastZkeyTempFilePath);
|
|
1830
|
-
}
|
|
1831
|
-
catch (error) {
|
|
1832
|
-
printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
|
|
1833
|
-
}
|
|
1834
|
-
await completeVerification();
|
|
1835
|
-
})
|
|
1836
|
-
.catch((error) => {
|
|
1837
|
-
// Throw the new error
|
|
1838
|
-
const commonError = COMMON_ERRORS.CM_INVALID_REQUEST;
|
|
1839
|
-
const additionalDetails = error.toString();
|
|
1840
|
-
logAndThrowError(makeError(commonError.code, commonError.message, additionalDetails));
|
|
1841
|
-
});
|
|
1801
|
+
// CF approach.
|
|
1802
|
+
printLog(`CF mechanism`, LogLevel.DEBUG);
|
|
1803
|
+
const potStoragePath = getPotStorageFilePath(files.potFilename);
|
|
1804
|
+
const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`);
|
|
1805
|
+
// Prepare temporary file paths.
|
|
1806
|
+
// (nb. these are needed to download the necessary artifacts for verification from AWS S3).
|
|
1807
|
+
verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
|
|
1808
|
+
const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
|
|
1809
|
+
const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
|
|
1810
|
+
const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
|
|
1811
|
+
// Create and populate transcript.
|
|
1812
|
+
const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
|
|
1813
|
+
transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
|
|
1814
|
+
// Step (1.A.2).
|
|
1815
|
+
await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
|
|
1816
|
+
await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
|
|
1817
|
+
await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
|
|
1818
|
+
// Step (1.A.4).
|
|
1819
|
+
isContributionValid = await zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
|
|
1820
|
+
// Compute contribution hash.
|
|
1821
|
+
lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath);
|
|
1822
|
+
// Free resources by unlinking temporary folders.
|
|
1823
|
+
// Do not free-up verification transcript path here.
|
|
1824
|
+
try {
|
|
1825
|
+
fs.unlinkSync(potTempFilePath);
|
|
1826
|
+
fs.unlinkSync(firstZkeyTempFilePath);
|
|
1827
|
+
fs.unlinkSync(lastZkeyTempFilePath);
|
|
1842
1828
|
}
|
|
1829
|
+
catch (error) {
|
|
1830
|
+
printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
|
|
1831
|
+
}
|
|
1832
|
+
await completeVerification();
|
|
1843
1833
|
}
|
|
1844
1834
|
});
|
|
1845
1835
|
/**
|
|
@@ -1848,7 +1838,7 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
|
|
|
1848
1838
|
* this does not happen if the participant is actually the coordinator who is finalizing the ceremony.
|
|
1849
1839
|
*/
|
|
1850
1840
|
const refreshParticipantAfterContributionVerification = functionsV1
|
|
1851
|
-
.region(
|
|
1841
|
+
.region("europe-west1")
|
|
1852
1842
|
.runWith({
|
|
1853
1843
|
memory: "512MB"
|
|
1854
1844
|
})
|
|
@@ -1909,7 +1899,7 @@ const refreshParticipantAfterContributionVerification = functionsV1
|
|
|
1909
1899
|
* and verification key extracted from the circuit final contribution (as part of the ceremony finalization process).
|
|
1910
1900
|
*/
|
|
1911
1901
|
const finalizeCircuit = functionsV1
|
|
1912
|
-
.region(
|
|
1902
|
+
.region("europe-west1")
|
|
1913
1903
|
.runWith({
|
|
1914
1904
|
memory: "512MB"
|
|
1915
1905
|
})
|
|
@@ -2106,8 +2096,10 @@ const createBucket = functions
|
|
|
2106
2096
|
CORSConfiguration: {
|
|
2107
2097
|
CORSRules: [
|
|
2108
2098
|
{
|
|
2109
|
-
AllowedMethods: ["GET"],
|
|
2110
|
-
AllowedOrigins: ["*"]
|
|
2099
|
+
AllowedMethods: ["GET", "PUT"],
|
|
2100
|
+
AllowedOrigins: ["*"],
|
|
2101
|
+
ExposeHeaders: ["ETag", "Content-Length"],
|
|
2102
|
+
AllowedHeaders: ["*"]
|
|
2111
2103
|
}
|
|
2112
2104
|
]
|
|
2113
2105
|
}
|
|
@@ -2284,7 +2276,8 @@ const startMultiPartUpload = functions
|
|
|
2284
2276
|
const generatePreSignedUrlsParts = functions
|
|
2285
2277
|
.region("europe-west1")
|
|
2286
2278
|
.runWith({
|
|
2287
|
-
memory: "512MB"
|
|
2279
|
+
memory: "512MB",
|
|
2280
|
+
timeoutSeconds: 300
|
|
2288
2281
|
})
|
|
2289
2282
|
.https.onCall(async (data, context) => {
|
|
2290
2283
|
if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
|
|
@@ -2393,6 +2386,148 @@ const completeMultiPartUpload = functions
|
|
|
2393
2386
|
}
|
|
2394
2387
|
});
|
|
2395
2388
|
|
|
2389
|
+
const VKEY_DATA = {
|
|
2390
|
+
protocol: "groth16",
|
|
2391
|
+
curve: "bn128",
|
|
2392
|
+
nPublic: 3,
|
|
2393
|
+
vk_alpha_1: [
|
|
2394
|
+
"20491192805390485299153009773594534940189261866228447918068658471970481763042",
|
|
2395
|
+
"9383485363053290200918347156157836566562967994039712273449902621266178545958",
|
|
2396
|
+
"1"
|
|
2397
|
+
],
|
|
2398
|
+
vk_beta_2: [
|
|
2399
|
+
[
|
|
2400
|
+
"6375614351688725206403948262868962793625744043794305715222011528459656738731",
|
|
2401
|
+
"4252822878758300859123897981450591353533073413197771768651442665752259397132"
|
|
2402
|
+
],
|
|
2403
|
+
[
|
|
2404
|
+
"10505242626370262277552901082094356697409835680220590971873171140371331206856",
|
|
2405
|
+
"21847035105528745403288232691147584728191162732299865338377159692350059136679"
|
|
2406
|
+
],
|
|
2407
|
+
["1", "0"]
|
|
2408
|
+
],
|
|
2409
|
+
vk_gamma_2: [
|
|
2410
|
+
[
|
|
2411
|
+
"10857046999023057135944570762232829481370756359578518086990519993285655852781",
|
|
2412
|
+
"11559732032986387107991004021392285783925812861821192530917403151452391805634"
|
|
2413
|
+
],
|
|
2414
|
+
[
|
|
2415
|
+
"8495653923123431417604973247489272438418190587263600148770280649306958101930",
|
|
2416
|
+
"4082367875863433681332203403145435568316851327593401208105741076214120093531"
|
|
2417
|
+
],
|
|
2418
|
+
["1", "0"]
|
|
2419
|
+
],
|
|
2420
|
+
vk_delta_2: [
|
|
2421
|
+
[
|
|
2422
|
+
"3697618915467790705869942236922063775466274665053173890632463796679068973252",
|
|
2423
|
+
"14948341351907992175709156460547989243732741534604949238422596319735704165658"
|
|
2424
|
+
],
|
|
2425
|
+
[
|
|
2426
|
+
"3028459181652799888716942141752307629938889957960373621898607910203491239368",
|
|
2427
|
+
"11380736494786911280692284374675752681598754560757720296073023058533044108340"
|
|
2428
|
+
],
|
|
2429
|
+
["1", "0"]
|
|
2430
|
+
],
|
|
2431
|
+
vk_alphabeta_12: [
|
|
2432
|
+
[
|
|
2433
|
+
[
|
|
2434
|
+
"2029413683389138792403550203267699914886160938906632433982220835551125967885",
|
|
2435
|
+
"21072700047562757817161031222997517981543347628379360635925549008442030252106"
|
|
2436
|
+
],
|
|
2437
|
+
[
|
|
2438
|
+
"5940354580057074848093997050200682056184807770593307860589430076672439820312",
|
|
2439
|
+
"12156638873931618554171829126792193045421052652279363021382169897324752428276"
|
|
2440
|
+
],
|
|
2441
|
+
[
|
|
2442
|
+
"7898200236362823042373859371574133993780991612861777490112507062703164551277",
|
|
2443
|
+
"7074218545237549455313236346927434013100842096812539264420499035217050630853"
|
|
2444
|
+
]
|
|
2445
|
+
],
|
|
2446
|
+
[
|
|
2447
|
+
[
|
|
2448
|
+
"7077479683546002997211712695946002074877511277312570035766170199895071832130",
|
|
2449
|
+
"10093483419865920389913245021038182291233451549023025229112148274109565435465"
|
|
2450
|
+
],
|
|
2451
|
+
[
|
|
2452
|
+
"4595479056700221319381530156280926371456704509942304414423590385166031118820",
|
|
2453
|
+
"19831328484489333784475432780421641293929726139240675179672856274388269393268"
|
|
2454
|
+
],
|
|
2455
|
+
[
|
|
2456
|
+
"11934129596455521040620786944827826205713621633706285934057045369193958244500",
|
|
2457
|
+
"8037395052364110730298837004334506829870972346962140206007064471173334027475"
|
|
2458
|
+
]
|
|
2459
|
+
]
|
|
2460
|
+
],
|
|
2461
|
+
IC: [
|
|
2462
|
+
[
|
|
2463
|
+
"12951059800758687233303204819298121944551181861362200875212570257618182506154",
|
|
2464
|
+
"5751958719396509176593242305268064754837298673622815112953832050159760501392",
|
|
2465
|
+
"1"
|
|
2466
|
+
],
|
|
2467
|
+
[
|
|
2468
|
+
"9561588427935871983444704959674198910445823619407211599507208879011862515257",
|
|
2469
|
+
"14576201570478094842467636169770180675293504492823217349086195663150934064643",
|
|
2470
|
+
"1"
|
|
2471
|
+
],
|
|
2472
|
+
[
|
|
2473
|
+
"4811967233483727873912563574622036989372099129165459921963463310078093941559",
|
|
2474
|
+
"1874883809855039536107616044787862082553628089593740724610117059083415551067",
|
|
2475
|
+
"1"
|
|
2476
|
+
],
|
|
2477
|
+
[
|
|
2478
|
+
"12252730267779308452229639835051322390696643456253768618882001876621526827161",
|
|
2479
|
+
"7899194018737016222260328309937800777948677569409898603827268776967707173231",
|
|
2480
|
+
"1"
|
|
2481
|
+
]
|
|
2482
|
+
]
|
|
2483
|
+
};
|
|
2484
|
+
dotenv.config();
|
|
2485
|
+
const { BANDADA_API_URL, BANDADA_GROUP_ID } = process.env;
|
|
2486
|
+
const bandadaApi = new ApiSdk(BANDADA_API_URL);
|
|
2487
|
+
const bandadaValidateProof = functions
|
|
2488
|
+
.region("europe-west1")
|
|
2489
|
+
.runWith({
|
|
2490
|
+
memory: "512MB"
|
|
2491
|
+
})
|
|
2492
|
+
.https.onCall(async (data) => {
|
|
2493
|
+
if (!BANDADA_GROUP_ID)
|
|
2494
|
+
throw new Error("BANDADA_GROUP_ID is not defined in .env");
|
|
2495
|
+
const { proof, publicSignals } = data;
|
|
2496
|
+
const isCorrect = groth16.verify(VKEY_DATA, publicSignals, proof);
|
|
2497
|
+
if (!isCorrect)
|
|
2498
|
+
return {
|
|
2499
|
+
valid: false,
|
|
2500
|
+
message: "Invalid proof",
|
|
2501
|
+
token: ""
|
|
2502
|
+
};
|
|
2503
|
+
const commitment = data.publicSignals[1];
|
|
2504
|
+
const isMember = await bandadaApi.isGroupMember(BANDADA_GROUP_ID, commitment);
|
|
2505
|
+
if (!isMember)
|
|
2506
|
+
return {
|
|
2507
|
+
valid: false,
|
|
2508
|
+
message: "Not a member of the group",
|
|
2509
|
+
token: ""
|
|
2510
|
+
};
|
|
2511
|
+
const auth = getAuth();
|
|
2512
|
+
try {
|
|
2513
|
+
await admin.auth().createUser({
|
|
2514
|
+
uid: commitment
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
catch (error) {
|
|
2518
|
+
// if user already exist then just pass
|
|
2519
|
+
if (error.code !== "auth/uid-already-exists") {
|
|
2520
|
+
throw new Error(error);
|
|
2521
|
+
}
|
|
2522
|
+
}
|
|
2523
|
+
const token = await auth.createCustomToken(commitment);
|
|
2524
|
+
return {
|
|
2525
|
+
valid: true,
|
|
2526
|
+
message: "Valid proof and group member",
|
|
2527
|
+
token
|
|
2528
|
+
};
|
|
2529
|
+
});
|
|
2530
|
+
|
|
2396
2531
|
dotenv.config();
|
|
2397
2532
|
/**
|
|
2398
2533
|
* Check and remove the current contributor if it doesn't complete the contribution on the specified amount of time.
|
|
@@ -2434,7 +2569,7 @@ const checkAndRemoveBlockingContributor = functions
|
|
|
2434
2569
|
// Get ceremony circuits.
|
|
2435
2570
|
const circuits = await getCeremonyCircuits(ceremony.id);
|
|
2436
2571
|
// Extract ceremony data.
|
|
2437
|
-
const { timeoutMechanismType, penalty } = ceremony.data();
|
|
2572
|
+
const { timeoutType: timeoutMechanismType, penalty } = ceremony.data();
|
|
2438
2573
|
for (const circuit of circuits) {
|
|
2439
2574
|
if (!circuit.data())
|
|
2440
2575
|
// Do not use `logAndThrowError` method to avoid the function to exit before checking every ceremony.
|
|
@@ -2500,7 +2635,7 @@ const checkAndRemoveBlockingContributor = functions
|
|
|
2500
2635
|
// Prepare Firestore batch of txs.
|
|
2501
2636
|
const batch = firestore.batch();
|
|
2502
2637
|
// Remove current contributor from waiting queue.
|
|
2503
|
-
contributors.shift(
|
|
2638
|
+
contributors.shift();
|
|
2504
2639
|
// Check if someone else is ready to start the contribution.
|
|
2505
2640
|
if (contributors.length > 0) {
|
|
2506
2641
|
// Step (E.1).
|
|
@@ -2584,7 +2719,8 @@ const resumeContributionAfterTimeoutExpiration = functions
|
|
|
2584
2719
|
if (status === "EXHUMED" /* ParticipantStatus.EXHUMED */)
|
|
2585
2720
|
await participantDoc.ref.update({
|
|
2586
2721
|
status: "READY" /* ParticipantStatus.READY */,
|
|
2587
|
-
lastUpdated: getCurrentServerTimestampInMillis()
|
|
2722
|
+
lastUpdated: getCurrentServerTimestampInMillis(),
|
|
2723
|
+
tempContributionData: {}
|
|
2588
2724
|
});
|
|
2589
2725
|
else
|
|
2590
2726
|
logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_CANNOT_PROGRESS_TO_NEXT_CIRCUIT);
|
|
@@ -2593,4 +2729,4 @@ const resumeContributionAfterTimeoutExpiration = functions
|
|
|
2593
2729
|
|
|
2594
2730
|
admin.initializeApp();
|
|
2595
2731
|
|
|
2596
|
-
export { checkAndPrepareCoordinatorForFinalization, checkAndRemoveBlockingContributor, checkIfObjectExist, checkParticipantForCeremony, completeMultiPartUpload, coordinateCeremonyParticipant, createBucket, finalizeCeremony, finalizeCircuit, generateGetObjectPreSignedUrl, generatePreSignedUrlsParts, initEmptyWaitingQueueForCircuit, permanentlyStoreCurrentContributionTimeAndHash, processSignUpWithCustomClaims, progressToNextCircuitForContribution, progressToNextContributionStep, refreshParticipantAfterContributionVerification, registerAuthUser, resumeContributionAfterTimeoutExpiration, setupCeremony, startCeremony, startMultiPartUpload, stopCeremony, temporaryStoreCurrentContributionMultiPartUploadId, temporaryStoreCurrentContributionUploadedChunkData, verifycontribution };
|
|
2732
|
+
export { bandadaValidateProof, checkAndPrepareCoordinatorForFinalization, checkAndRemoveBlockingContributor, checkIfObjectExist, checkParticipantForCeremony, completeMultiPartUpload, coordinateCeremonyParticipant, createBucket, finalizeCeremony, finalizeCircuit, generateGetObjectPreSignedUrl, generatePreSignedUrlsParts, initEmptyWaitingQueueForCircuit, permanentlyStoreCurrentContributionTimeAndHash, processSignUpWithCustomClaims, progressToNextCircuitForContribution, progressToNextContributionStep, refreshParticipantAfterContributionVerification, registerAuthUser, resumeContributionAfterTimeoutExpiration, setupCeremony, startCeremony, startMultiPartUpload, stopCeremony, temporaryStoreCurrentContributionMultiPartUploadId, temporaryStoreCurrentContributionUploadedChunkData, verifycontribution };
|