@devtion/backend 0.0.0-f784f3a → 0.0.0-f7df5e1

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 CHANGED
@@ -102,10 +102,10 @@ yarn firebase:init
102
102
 
103
103
  #### AWS Infrastructure
104
104
 
105
- 0. Login or create a [new AWS Account](https://portal.aws.amazon.com/billing/signup?nc2=h_ct&src=header_signup&redirect_url=https%3A%2F%2Faws.amazon.com%2Fregistration-confirmation#/start/email).
105
+ 0. Login or create a [new AWS Account](https://portal.aws.amazon.com/billing/signup?nc2=h_ct&src=header_signup&redirect_url=https%3A%2F%2Faws.amazon.com%2Fregistration-confirmation#/start/email).
106
106
  - The AWS free tier account will cover a good number of requests for ceremonies but there could be some costs based on your ceremony circuits size.
107
- 1. Create an access key for a user with Admin privileges (__NOT ROOT USER__)
108
- 2. Setup the `awscli` ([docs](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)) and add the keys for this user.
107
+ 1. Create an access key for a user with Admin privileges (**NOT ROOT USER**)
108
+ 2. Setup the `awscli` ([docs](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-configure.html)) and add the keys for this user.
109
109
  3. Install `terraform` ([docs](https://developer.hashicorp.com/terraform/tutorials/aws-get-started/install-cli))
110
110
  4. Decide on an AWS region (by default this is **us-east-1**) - if you want to change you will need to do the following:
111
111
  1. update **aws/lambda/index.mjs** ([exact line](https://github.com/privacy-scaling-explorations/p0tion/blob/dev/packages/backend/aws/lambda/index.mjs#L3)) to the new region
@@ -117,9 +117,9 @@ yarn firebase:init
117
117
  1. `terraform init`
118
118
  2. `terraform plan`
119
119
  3. `terraform apply`
120
- 4. `terraform output secret_key`
120
+ 4. `terraform output secret_key`
121
121
  - To print the secret access key for the IAM user
122
- 6. Store the other values (sns_topic_arn etc.)
122
+ 5. Store the other values (sns_topic_arn etc.)
123
123
  - These will be needed for the .env file configuration
124
124
 
125
125
  The IAM user created with the steps above can be used for all p0tion's features.
@@ -1,6 +1,6 @@
1
1
  /**
2
- * @module @p0tion/backend
3
- * @version 1.0.5
2
+ * @module @devtion/backend
3
+ * @version 1.0.8
4
4
  * @file MPC Phase 2 backend for Firebase services management
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
@@ -11,7 +11,7 @@
11
11
  var admin = require('firebase-admin');
12
12
  var functions = require('firebase-functions');
13
13
  var dotenv = require('dotenv');
14
- var actions = require('@p0tion/actions');
14
+ var actions = require('@devtion/actions');
15
15
  var htmlEntities = require('html-entities');
16
16
  var firestore = require('firebase-admin/firestore');
17
17
  var clientS3 = require('@aws-sdk/client-s3');
@@ -144,7 +144,8 @@ const SPECIFIC_ERRORS = {
144
144
  SE_VM_FAILED_COMMAND_EXECUTION: makeError("failed-precondition", "VM command execution failed", "Please, contact the coordinator if this error persists."),
145
145
  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."),
146
146
  SE_VM_CANCELLED_COMMAND_EXECUTION: makeError("cancelled", "VM command execution has been cancelled", "Please, contact the coordinator if this error persists."),
147
- 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.")
147
+ 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."),
148
+ 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.")
148
149
  };
149
150
  /**
150
151
  * A set of common errors.
@@ -328,7 +329,7 @@ const downloadArtifactFromS3Bucket = async (bucketName, objectKey, localFilePath
328
329
  const writeStream = node_fs.createWriteStream(localFilePath);
329
330
  const streamPipeline = node_util.promisify(node_stream.pipeline);
330
331
  await streamPipeline(response.body, writeStream);
331
- writeStream.on('finish', () => {
332
+ writeStream.on("finish", () => {
332
333
  writeStream.end();
333
334
  });
334
335
  };
@@ -544,8 +545,10 @@ const registerAuthUser = functions__namespace
544
545
  const { uid } = user;
545
546
  // Reference to a document using uid.
546
547
  const userRef = firestore.collection(actions.commonTerms.collections.users.name).doc(uid);
547
- // html encode the display name
548
- const encodedDisplayName = htmlEntities.encode(displayName);
548
+ // html encode the display name (or put the ID if the name is not displayed)
549
+ const encodedDisplayName = user.displayName === "Null" || user.displayName === null ? user.uid : htmlEntities.encode(displayName);
550
+ // store the avatar URL of a contributor
551
+ let avatarUrl = "";
549
552
  // we only do reputation check if the user is not a coordinator
550
553
  if (!(email?.endsWith(`@${process.env.CUSTOM_CLAIMS_COORDINATOR_EMAIL_ADDRESS_OR_DOMAIN}`) ||
551
554
  email === process.env.CUSTOM_CLAIMS_COORDINATOR_EMAIL_ADDRESS_OR_DOMAIN)) {
@@ -555,14 +558,18 @@ const registerAuthUser = functions__namespace
555
558
  const vars = getGitHubVariables();
556
559
  // this return true or false
557
560
  try {
558
- const res = await actions.githubReputation(user.providerData[0].uid, vars.minimumFollowing, vars.minimumFollowers, vars.minimumPublicRepos);
559
- if (!res) {
561
+ const { reputable, avatarUrl: avatarURL } = await actions.githubReputation(user.providerData[0].uid, vars.minimumFollowing, vars.minimumFollowers, vars.minimumPublicRepos);
562
+ if (!reputable) {
560
563
  // Delete user
561
564
  await auth.deleteUser(user.uid);
562
565
  // Throw error
563
- logAndThrowError(makeError("permission-denied", "The user is not allowed to sign up because their Github reputation is not high enough.", `The user ${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.`));
566
+ 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
567
+ ? user.uid
568
+ : 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.`));
564
569
  }
565
- printLog(`Github reputation check passed for user ${user.displayName}`, LogLevel.DEBUG);
570
+ // store locally
571
+ avatarUrl = avatarURL;
572
+ printLog(`Github reputation check passed for user ${user.displayName === "Null" || user.displayName === null ? user.uid : user.displayName}`, LogLevel.DEBUG);
566
573
  }
567
574
  catch (error) {
568
575
  // Delete user
@@ -572,6 +579,8 @@ const registerAuthUser = functions__namespace
572
579
  }
573
580
  }
574
581
  // Set document (nb. we refer to providerData[0] because we use Github OAuth provider only).
582
+ // In future releases we might want to loop through the providerData array as we support
583
+ // more providers.
575
584
  await userRef.set({
576
585
  name: encodedDisplayName,
577
586
  encodedDisplayName,
@@ -584,7 +593,13 @@ const registerAuthUser = functions__namespace
584
593
  photoURL: photoURL || "",
585
594
  lastUpdated: getCurrentServerTimestampInMillis()
586
595
  });
596
+ // we want to create a new collection for the users to store the avatars
597
+ const avatarRef = firestore.collection(actions.commonTerms.collections.avatars.name).doc(uid);
598
+ await avatarRef.set({
599
+ avatarUrl: avatarUrl || ""
600
+ });
587
601
  printLog(`Authenticated user document with identifier ${uid} has been correctly stored`, LogLevel.DEBUG);
602
+ printLog(`Authenticated user avatar with identifier ${uid} has been correctly stored`, LogLevel.DEBUG);
588
603
  });
589
604
  /**
590
605
  * Set custom claims for role-based access control on the newly created user.
@@ -721,7 +736,7 @@ const setupCeremony = functions__namespace
721
736
  // Check if using the VM approach for contribution verification.
722
737
  if (circuit.verification.cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */) {
723
738
  // VM command to be run at the startup.
724
- const startupCommand = actions.vmBootstrapCommand(bucketName);
739
+ const startupCommand = actions.vmBootstrapCommand(`${bucketName}/circuits/${circuit.name}`);
725
740
  // Get EC2 client.
726
741
  const ec2Client = await createEC2Client();
727
742
  // Get AWS variables.
@@ -730,7 +745,8 @@ const setupCeremony = functions__namespace
730
745
  const vmCommands = actions.vmDependenciesAndCacheArtifactsCommand(`${bucketName}/${circuit.files?.initialZkeyStoragePath}`, `${bucketName}/${circuit.files?.potStoragePath}`, snsTopic, region);
731
746
  printLog(`Check VM dependencies and cache artifacts commands ${vmCommands.join("\n")}`, LogLevel.DEBUG);
732
747
  // Upload the post-startup commands script file.
733
- await uploadFileToBucketNoFile(bucketName, actions.vmBootstrapScriptFilename, vmCommands.join("\n"));
748
+ printLog(`Uploading VM post-startup commands script file ${actions.vmBootstrapScriptFilename}`, LogLevel.DEBUG);
749
+ await uploadFileToBucketNoFile(bucketName, `circuits/${circuit.name}/${actions.vmBootstrapScriptFilename}`, vmCommands.join("\n"));
734
750
  // Compute the VM disk space requirement (in GB).
735
751
  const vmDiskSize = actions.computeDiskSizeForVM(circuit.zKeySizeInBytes, circuit.metadata?.pot);
736
752
  printLog(`Check VM startup commands ${startupCommand.join("\n")}`, LogLevel.DEBUG);
@@ -877,7 +893,7 @@ dotenv.config();
877
893
  * @dev true when the participant can participate (1.A, 3.B, 1.D); otherwise false.
878
894
  */
879
895
  const checkParticipantForCeremony = functions__namespace
880
- .region('europe-west1')
896
+ .region("europe-west1")
881
897
  .runWith({
882
898
  memory: "512MB"
883
899
  })
@@ -981,7 +997,7 @@ const checkParticipantForCeremony = functions__namespace
981
997
  * 2) the participant has just finished the contribution for a circuit (contributionProgress != 0 && status = CONTRIBUTED && contributionStep = COMPLETED).
982
998
  */
983
999
  const progressToNextCircuitForContribution = functions__namespace
984
- .region('europe-west1')
1000
+ .region("europe-west1")
985
1001
  .runWith({
986
1002
  memory: "512MB"
987
1003
  })
@@ -1028,7 +1044,7 @@ const progressToNextCircuitForContribution = functions__namespace
1028
1044
  * 5) Completed contribution computation and verification.
1029
1045
  */
1030
1046
  const progressToNextContributionStep = functions__namespace
1031
- .region('europe-west1')
1047
+ .region("europe-west1")
1032
1048
  .runWith({
1033
1049
  memory: "512MB"
1034
1050
  })
@@ -1079,7 +1095,7 @@ const progressToNextContributionStep = functions__namespace
1079
1095
  * @dev enable the current contributor to resume a contribution from where it had left off.
1080
1096
  */
1081
1097
  const permanentlyStoreCurrentContributionTimeAndHash = functions__namespace
1082
- .region('europe-west1')
1098
+ .region("europe-west1")
1083
1099
  .runWith({
1084
1100
  memory: "512MB"
1085
1101
  })
@@ -1121,7 +1137,7 @@ const permanentlyStoreCurrentContributionTimeAndHash = functions__namespace
1121
1137
  * @dev enable the current contributor to resume a multi-part upload from where it had left off.
1122
1138
  */
1123
1139
  const temporaryStoreCurrentContributionMultiPartUploadId = functions__namespace
1124
- .region('europe-west1')
1140
+ .region("europe-west1")
1125
1141
  .runWith({
1126
1142
  memory: "512MB"
1127
1143
  })
@@ -1159,7 +1175,7 @@ const temporaryStoreCurrentContributionMultiPartUploadId = functions__namespace
1159
1175
  * @dev enable the current contributor to resume a multi-part upload from where it had left off.
1160
1176
  */
1161
1177
  const temporaryStoreCurrentContributionUploadedChunkData = functions__namespace
1162
- .region('europe-west1')
1178
+ .region("europe-west1")
1163
1179
  .runWith({
1164
1180
  memory: "512MB"
1165
1181
  })
@@ -1201,7 +1217,7 @@ const temporaryStoreCurrentContributionUploadedChunkData = functions__namespace
1201
1217
  * contributed to every selected ceremony circuits (= DONE).
1202
1218
  */
1203
1219
  const checkAndPrepareCoordinatorForFinalization = functions__namespace
1204
- .region('europe-west1')
1220
+ .region("europe-west1")
1205
1221
  .runWith({
1206
1222
  memory: "512MB"
1207
1223
  })
@@ -1353,39 +1369,54 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1353
1369
  * Wait until the command has completed its execution inside the VM.
1354
1370
  * @dev this method implements a custom interval to check 5 times after 1 minute if the command execution
1355
1371
  * has been completed or not by calling the `retrieveCommandStatus` method.
1356
- * @param {any} resolve the promise.
1357
- * @param {any} reject the promise.
1358
1372
  * @param {SSMClient} ssm the SSM client.
1359
1373
  * @param {string} vmInstanceId the unique identifier of the VM instance.
1360
1374
  * @param {string} commandId the unique identifier of the VM command.
1361
1375
  * @returns <Promise<void>> true when the command execution succeed; otherwise false.
1362
1376
  */
1363
- const waitForVMCommandExecution = (resolve, reject, ssm, vmInstanceId, commandId) => {
1364
- const interval = setInterval(async () => {
1377
+ const waitForVMCommandExecution = (ssm, vmInstanceId, commandId) => new Promise((resolve, reject) => {
1378
+ const poll = async () => {
1365
1379
  try {
1366
1380
  // Get command status.
1367
1381
  const cmdStatus = await actions.retrieveCommandStatus(ssm, vmInstanceId, commandId);
1368
1382
  printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG);
1369
- if (cmdStatus === clientSsm.CommandInvocationStatus.SUCCESS) {
1370
- printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG);
1371
- // Resolve the promise.
1372
- resolve();
1373
- }
1374
- else if (cmdStatus === clientSsm.CommandInvocationStatus.FAILED) {
1375
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION);
1376
- reject();
1377
- }
1378
- else if (cmdStatus === clientSsm.CommandInvocationStatus.TIMED_OUT) {
1379
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION);
1380
- reject();
1381
- }
1382
- else if (cmdStatus === clientSsm.CommandInvocationStatus.CANCELLED) {
1383
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION);
1384
- reject();
1383
+ let error;
1384
+ switch (cmdStatus) {
1385
+ case clientSsm.CommandInvocationStatus.CANCELLING:
1386
+ case clientSsm.CommandInvocationStatus.CANCELLED: {
1387
+ error = SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION;
1388
+ break;
1389
+ }
1390
+ case clientSsm.CommandInvocationStatus.DELAYED: {
1391
+ error = SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION;
1392
+ break;
1393
+ }
1394
+ case clientSsm.CommandInvocationStatus.FAILED: {
1395
+ error = SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION;
1396
+ break;
1397
+ }
1398
+ case clientSsm.CommandInvocationStatus.TIMED_OUT: {
1399
+ error = SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION;
1400
+ break;
1401
+ }
1402
+ case clientSsm.CommandInvocationStatus.IN_PROGRESS:
1403
+ case clientSsm.CommandInvocationStatus.PENDING: {
1404
+ // wait a minute and poll again
1405
+ setTimeout(poll, 60000);
1406
+ return;
1407
+ }
1408
+ case clientSsm.CommandInvocationStatus.SUCCESS: {
1409
+ printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG);
1410
+ // Resolve the promise.
1411
+ resolve();
1412
+ return;
1413
+ }
1414
+ default: {
1415
+ logAndThrowError(SPECIFIC_ERRORS.SE_VM_UNKNOWN_COMMAND_STATUS);
1416
+ }
1385
1417
  }
1386
- else if (cmdStatus === clientSsm.CommandInvocationStatus.DELAYED) {
1387
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION);
1388
- reject();
1418
+ if (error) {
1419
+ logAndThrowError(error);
1389
1420
  }
1390
1421
  }
1391
1422
  catch (error) {
@@ -1395,12 +1426,9 @@ const waitForVMCommandExecution = (resolve, reject, ssm, vmInstanceId, commandId
1395
1426
  // Reject the promise.
1396
1427
  reject();
1397
1428
  }
1398
- finally {
1399
- // Clear the interval.
1400
- clearInterval(interval);
1401
- }
1402
- }, 60000); // 1 minute.
1403
- };
1429
+ };
1430
+ setTimeout(poll, 60000);
1431
+ });
1404
1432
  /**
1405
1433
  * This method is used to coordinate the waiting queues of ceremony circuits.
1406
1434
  * @dev this cloud function is triggered whenever an update of a document related to a participant of a ceremony occurs.
@@ -1421,7 +1449,7 @@ const waitForVMCommandExecution = (resolve, reject, ssm, vmInstanceId, commandId
1421
1449
  * - Just completed a contribution or all contributions for each circuit. If yes, coordinate (multi-participant scenario).
1422
1450
  */
1423
1451
  const coordinateCeremonyParticipant = functionsV1__namespace
1424
- .region('europe-west1')
1452
+ .region("europe-west1")
1425
1453
  .runWith({
1426
1454
  memory: "512MB"
1427
1455
  })
@@ -1524,7 +1552,7 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
1524
1552
  * 1.A.4.C.1) If true, update circuit waiting for queue and average timings accordingly to contribution verification results;
1525
1553
  * 2) Send all updates atomically to the Firestore database.
1526
1554
  */
1527
- const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: 'europe-west1' }, async (request) => {
1555
+ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" }, async (request) => {
1528
1556
  if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1529
1557
  logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1530
1558
  if (!request.data.ceremonyId ||
@@ -1635,8 +1663,6 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1635
1663
  lastZkeyBlake2bHash = match.at(0);
1636
1664
  // re upload the formatted verification transcript
1637
1665
  await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1638
- // Stop VM instance.
1639
- await actions.stopEC2Instance(ec2, vmInstanceId);
1640
1666
  }
1641
1667
  else {
1642
1668
  // Upload verification transcript.
@@ -1697,6 +1723,9 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1697
1723
  lastUpdated: getCurrentServerTimestampInMillis()
1698
1724
  });
1699
1725
  }
1726
+ // Stop VM instance
1727
+ if (isUsingVM)
1728
+ await actions.stopEC2Instance(ec2, vmInstanceId);
1700
1729
  // Step (1.A.4.C)
1701
1730
  if (!isFinalizing) {
1702
1731
  // Step (1.A.4.C.1)
@@ -1711,7 +1740,7 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1711
1740
  const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1712
1741
  ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1713
1742
  : verifyCloudFunctionTime;
1714
- // Prepare tx to update circuit average contribution/verification time.
1743
+ // Prepare tx to update circuit average contribution/verification time.
1715
1744
  const updatedCircuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1716
1745
  const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1717
1746
  /// @dev this must happen only for valid contributions.
@@ -1761,7 +1790,7 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1761
1790
  commandId = await actions.runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1762
1791
  printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1763
1792
  // Step (1.A.3.3).
1764
- return new Promise((resolve, reject) => waitForVMCommandExecution(resolve, reject, ssm, vmInstanceId, commandId))
1793
+ return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1765
1794
  .then(async () => {
1766
1795
  // Command execution successfully completed.
1767
1796
  printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
@@ -1773,40 +1802,38 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1773
1802
  logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1774
1803
  });
1775
1804
  }
1776
- else {
1777
- // CF approach.
1778
- printLog(`CF mechanism`, LogLevel.DEBUG);
1779
- const potStoragePath = actions.getPotStorageFilePath(files.potFilename);
1780
- const firstZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${actions.genesisZkeyIndex}.zkey`);
1781
- // Prepare temporary file paths.
1782
- // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1783
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1784
- const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1785
- const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1786
- const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1787
- // Create and populate transcript.
1788
- const transcriptLogger = actions.createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1789
- transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1790
- // Step (1.A.2).
1791
- await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1792
- await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1793
- await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1794
- // Step (1.A.4).
1795
- isContributionValid = await snarkjs.zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1796
- // Compute contribution hash.
1797
- lastZkeyBlake2bHash = await actions.blake512FromPath(lastZkeyTempFilePath);
1798
- // Free resources by unlinking temporary folders.
1799
- // Do not free-up verification transcript path here.
1800
- try {
1801
- fs.unlinkSync(potTempFilePath);
1802
- fs.unlinkSync(firstZkeyTempFilePath);
1803
- fs.unlinkSync(lastZkeyTempFilePath);
1804
- }
1805
- catch (error) {
1806
- printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1807
- }
1808
- await completeVerification();
1805
+ // CF approach.
1806
+ printLog(`CF mechanism`, LogLevel.DEBUG);
1807
+ const potStoragePath = actions.getPotStorageFilePath(files.potFilename);
1808
+ const firstZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${actions.genesisZkeyIndex}.zkey`);
1809
+ // Prepare temporary file paths.
1810
+ // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1811
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1812
+ const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1813
+ const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1814
+ const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1815
+ // Create and populate transcript.
1816
+ const transcriptLogger = actions.createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1817
+ transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1818
+ // Step (1.A.2).
1819
+ await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1820
+ await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1821
+ await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1822
+ // Step (1.A.4).
1823
+ isContributionValid = await snarkjs.zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1824
+ // Compute contribution hash.
1825
+ lastZkeyBlake2bHash = await actions.blake512FromPath(lastZkeyTempFilePath);
1826
+ // Free resources by unlinking temporary folders.
1827
+ // Do not free-up verification transcript path here.
1828
+ try {
1829
+ fs.unlinkSync(potTempFilePath);
1830
+ fs.unlinkSync(firstZkeyTempFilePath);
1831
+ fs.unlinkSync(lastZkeyTempFilePath);
1832
+ }
1833
+ catch (error) {
1834
+ printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1809
1835
  }
1836
+ await completeVerification();
1810
1837
  }
1811
1838
  });
1812
1839
  /**
@@ -1815,7 +1842,7 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1815
1842
  * this does not happen if the participant is actually the coordinator who is finalizing the ceremony.
1816
1843
  */
1817
1844
  const refreshParticipantAfterContributionVerification = functionsV1__namespace
1818
- .region('europe-west1')
1845
+ .region("europe-west1")
1819
1846
  .runWith({
1820
1847
  memory: "512MB"
1821
1848
  })
@@ -1876,7 +1903,7 @@ const refreshParticipantAfterContributionVerification = functionsV1__namespace
1876
1903
  * and verification key extracted from the circuit final contribution (as part of the ceremony finalization process).
1877
1904
  */
1878
1905
  const finalizeCircuit = functionsV1__namespace
1879
- .region('europe-west1')
1906
+ .region("europe-west1")
1880
1907
  .runWith({
1881
1908
  memory: "512MB"
1882
1909
  })
@@ -2073,8 +2100,10 @@ const createBucket = functions__namespace
2073
2100
  CORSConfiguration: {
2074
2101
  CORSRules: [
2075
2102
  {
2076
- AllowedMethods: ["GET"],
2077
- AllowedOrigins: ["*"]
2103
+ AllowedMethods: ["GET", "PUT"],
2104
+ AllowedOrigins: ["*"],
2105
+ ExposeHeaders: ["ETag", "Content-Length"],
2106
+ AllowedHeaders: ["*"]
2078
2107
  }
2079
2108
  ]
2080
2109
  }
@@ -2551,7 +2580,8 @@ const resumeContributionAfterTimeoutExpiration = functions__namespace
2551
2580
  if (status === "EXHUMED" /* ParticipantStatus.EXHUMED */)
2552
2581
  await participantDoc.ref.update({
2553
2582
  status: "READY" /* ParticipantStatus.READY */,
2554
- lastUpdated: getCurrentServerTimestampInMillis()
2583
+ lastUpdated: getCurrentServerTimestampInMillis(),
2584
+ tempContributionData: {}
2555
2585
  });
2556
2586
  else
2557
2587
  logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_CANNOT_PROGRESS_TO_NEXT_CIRCUIT);