@devtion/backend 0.0.0-c1f4cbe → 0.0.0-e22d20d

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.
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @module @p0tion/backend
3
- * @version 1.1.1
3
+ * @version 1.2.4
4
4
  * @file MPC Phase 2 backend for Firebase services management
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
@@ -559,7 +559,7 @@ dotenv.config();
559
559
  const registerAuthUser = functions__namespace
560
560
  .region("europe-west1")
561
561
  .runWith({
562
- memory: "512MB"
562
+ memory: "1GB"
563
563
  })
564
564
  .auth.user()
565
565
  .onCreate(async (user) => {
@@ -646,7 +646,7 @@ const registerAuthUser = functions__namespace
646
646
  const processSignUpWithCustomClaims = functions__namespace
647
647
  .region("europe-west1")
648
648
  .runWith({
649
- memory: "512MB"
649
+ memory: "1GB"
650
650
  })
651
651
  .auth.user()
652
652
  .onCreate(async (user) => {
@@ -687,7 +687,7 @@ dotenv.config();
687
687
  const startCeremony = functions__namespace
688
688
  .region("europe-west1")
689
689
  .runWith({
690
- memory: "512MB"
690
+ memory: "1GB"
691
691
  })
692
692
  .pubsub.schedule(`every 30 minutes`)
693
693
  .onRun(async () => {
@@ -709,7 +709,7 @@ const startCeremony = functions__namespace
709
709
  const stopCeremony = functions__namespace
710
710
  .region("europe-west1")
711
711
  .runWith({
712
- memory: "512MB"
712
+ memory: "1GB"
713
713
  })
714
714
  .pubsub.schedule(`every 30 minutes`)
715
715
  .onRun(async () => {
@@ -731,7 +731,7 @@ const stopCeremony = functions__namespace
731
731
  const setupCeremony = functions__namespace
732
732
  .region("europe-west1")
733
733
  .runWith({
734
- memory: "512MB"
734
+ memory: "1GB"
735
735
  })
736
736
  .https.onCall(async (data, context) => {
737
737
  // Check if the user has the coordinator claim.
@@ -856,7 +856,7 @@ const initEmptyWaitingQueueForCircuit = functions__namespace
856
856
  const finalizeCeremony = functions__namespace
857
857
  .region("europe-west1")
858
858
  .runWith({
859
- memory: "512MB"
859
+ memory: "1GB"
860
860
  })
861
861
  .https.onCall(async (data, context) => {
862
862
  if (!context.auth || !context.auth.token.coordinator)
@@ -932,7 +932,7 @@ dotenv.config();
932
932
  const checkParticipantForCeremony = functions__namespace
933
933
  .region("europe-west1")
934
934
  .runWith({
935
- memory: "512MB"
935
+ memory: "1GB"
936
936
  })
937
937
  .https.onCall(async (data, context) => {
938
938
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -1036,7 +1036,7 @@ const checkParticipantForCeremony = functions__namespace
1036
1036
  const progressToNextCircuitForContribution = functions__namespace
1037
1037
  .region("europe-west1")
1038
1038
  .runWith({
1039
- memory: "512MB"
1039
+ memory: "1GB"
1040
1040
  })
1041
1041
  .https.onCall(async (data, context) => {
1042
1042
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -1083,7 +1083,7 @@ const progressToNextCircuitForContribution = functions__namespace
1083
1083
  const progressToNextContributionStep = functions__namespace
1084
1084
  .region("europe-west1")
1085
1085
  .runWith({
1086
- memory: "512MB"
1086
+ memory: "1GB"
1087
1087
  })
1088
1088
  .https.onCall(async (data, context) => {
1089
1089
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -1134,7 +1134,7 @@ const progressToNextContributionStep = functions__namespace
1134
1134
  const permanentlyStoreCurrentContributionTimeAndHash = functions__namespace
1135
1135
  .region("europe-west1")
1136
1136
  .runWith({
1137
- memory: "512MB"
1137
+ memory: "1GB"
1138
1138
  })
1139
1139
  .https.onCall(async (data, context) => {
1140
1140
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -1176,7 +1176,7 @@ const permanentlyStoreCurrentContributionTimeAndHash = functions__namespace
1176
1176
  const temporaryStoreCurrentContributionMultiPartUploadId = functions__namespace
1177
1177
  .region("europe-west1")
1178
1178
  .runWith({
1179
- memory: "512MB"
1179
+ memory: "1GB"
1180
1180
  })
1181
1181
  .https.onCall(async (data, context) => {
1182
1182
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -1214,7 +1214,7 @@ const temporaryStoreCurrentContributionMultiPartUploadId = functions__namespace
1214
1214
  const temporaryStoreCurrentContributionUploadedChunkData = functions__namespace
1215
1215
  .region("europe-west1")
1216
1216
  .runWith({
1217
- memory: "512MB"
1217
+ memory: "1GB"
1218
1218
  })
1219
1219
  .https.onCall(async (data, context) => {
1220
1220
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -1256,7 +1256,7 @@ const temporaryStoreCurrentContributionUploadedChunkData = functions__namespace
1256
1256
  const checkAndPrepareCoordinatorForFinalization = functions__namespace
1257
1257
  .region("europe-west1")
1258
1258
  .runWith({
1259
- memory: "512MB"
1259
+ memory: "1GB"
1260
1260
  })
1261
1261
  .https.onCall(async (data, context) => {
1262
1262
  if (!context.auth || !context.auth.token.coordinator)
@@ -1496,7 +1496,7 @@ const waitForVMCommandExecution = (ssm, vmInstanceId, commandId) => new Promise(
1496
1496
  const coordinateCeremonyParticipant = functionsV1__namespace
1497
1497
  .region("europe-west1")
1498
1498
  .runWith({
1499
- memory: "512MB"
1499
+ memory: "1GB"
1500
1500
  })
1501
1501
  .firestore.document(`${actions.commonTerms.collections.ceremonies.name}/{ceremonyId}/${actions.commonTerms.collections.participants.name}/{participantId}`)
1502
1502
  .onUpdate(async (participantChanges) => {
@@ -1596,296 +1596,301 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
1596
1596
  * 2) Send all updates atomically to the Firestore database.
1597
1597
  */
1598
1598
  const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" }, async (request) => {
1599
- if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1600
- logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1601
- if (!request.data.ceremonyId ||
1602
- !request.data.circuitId ||
1603
- !request.data.contributorOrCoordinatorIdentifier ||
1604
- !request.data.bucketName)
1605
- logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA);
1606
- if (!process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
1607
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
1608
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1609
- logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
1610
- // Step (0).
1611
- // Prepare and start timer.
1612
- const verifyContributionTimer = new timerNode.Timer({ label: actions.commonTerms.cloudFunctionsNames.verifyContribution });
1613
- verifyContributionTimer.start();
1614
- // Get DB.
1615
- const firestore = admin.firestore();
1616
- // Prepare batch of txs.
1617
- const batch = firestore.batch();
1618
- // Extract data.
1619
- const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data;
1620
- const userId = request.auth?.uid;
1621
- // Look for the ceremony, circuit and participant document.
1622
- const ceremonyDoc = await getDocumentById(actions.commonTerms.collections.ceremonies.name, ceremonyId);
1623
- const circuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1624
- const participantDoc = await getDocumentById(actions.getParticipantsCollectionPath(ceremonyId), userId);
1625
- if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
1626
- logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA);
1627
- // Extract documents data.
1628
- const { state } = ceremonyDoc.data();
1629
- const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data();
1630
- const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data();
1631
- const { completedContributions, failedContributions } = waitingQueue;
1632
- const { contributionComputation: avgContributionComputationTime, fullContribution: avgFullContributionTime, verifyCloudFunction: avgVerifyCloudFunctionTime } = avgTimings;
1633
- const { cfOrVm, vm } = verification;
1634
- // we might not have it if the circuit is not using VM.
1635
- let vmInstanceId = "";
1636
- if (vm)
1637
- vmInstanceId = vm.vmInstanceId;
1638
- // Define pre-conditions.
1639
- const isFinalizing = state === "CLOSED" /* CeremonyState.CLOSED */ && request.auth && request.auth.token.coordinator; // true only when the coordinator verifies the final contributions.
1640
- const isContributing = status === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1641
- const isUsingVM = cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */ && !!vmInstanceId;
1642
- // Prepare state.
1643
- let isContributionValid = false;
1644
- let verifyCloudFunctionExecutionTime = 0; // time spent while executing the verify contribution cloud function.
1645
- let verifyCloudFunctionTime = 0; // time spent while executing the core business logic of this cloud function.
1646
- let fullContributionTime = 0; // time spent while doing non-verification contributions tasks (download, compute, upload).
1647
- let contributionComputationTime = 0; // time spent while computing the contribution.
1648
- let lastZkeyBlake2bHash = ""; // the Blake2B hash of the last zKey.
1649
- let verificationTranscriptTemporaryLocalPath = ""; // the local temporary path for the verification transcript.
1650
- let transcriptBlake2bHash = ""; // the Blake2B hash of the verification transcript.
1651
- let commandId = ""; // the unique identifier of the VM command.
1652
- // Derive necessary data.
1653
- const lastZkeyIndex = actions.formatZkeyIndex(completedContributions + 1);
1654
- const verificationTranscriptCompleteFilename = `${prefix}_${isFinalizing
1655
- ? `${contributorOrCoordinatorIdentifier}_${actions.finalContributionIndex}_verification_transcript.log`
1656
- : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`}`;
1657
- const lastZkeyFilename = `${prefix}_${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex}.zkey`;
1658
- // Prepare state for VM verification (if needed).
1659
- const ec2 = await createEC2Client();
1660
- const ssm = await createSSMClient();
1661
- // Step (1.A.1).
1662
- // Get storage paths.
1663
- const verificationTranscriptStoragePathAndFilename = actions.getTranscriptStorageFilePath(prefix, verificationTranscriptCompleteFilename);
1664
- // the zKey storage path is required to be sent to the VM api
1665
- const lastZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex}.zkey`);
1666
- const verificationTaskTimer = new timerNode.Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` });
1667
- const completeVerification = async () => {
1668
- // Stop verification task timer.
1669
- printLog("Completing verification", LogLevel.DEBUG);
1670
- verificationTaskTimer.stop();
1671
- verifyCloudFunctionExecutionTime = verificationTaskTimer.ms();
1672
- if (isUsingVM) {
1673
- // Create temporary path.
1674
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.log`);
1675
- await sleep(1000); // wait 1s for file creation.
1676
- // Download from bucket.
1677
- // nb. the transcript MUST be uploaded from the VM by verification commands.
1678
- await downloadArtifactFromS3Bucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath);
1679
- // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
1680
- const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8");
1681
- if (content.includes("ZKey Ok!"))
1682
- isContributionValid = true;
1683
- // If the contribution is valid, then format and store the trascript.
1599
+ try {
1600
+ if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1601
+ logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1602
+ if (!request.data.ceremonyId ||
1603
+ !request.data.circuitId ||
1604
+ !request.data.contributorOrCoordinatorIdentifier ||
1605
+ !request.data.bucketName)
1606
+ logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA);
1607
+ if (!process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
1608
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
1609
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1610
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
1611
+ // Step (0).
1612
+ // Prepare and start timer.
1613
+ const verifyContributionTimer = new timerNode.Timer({ label: actions.commonTerms.cloudFunctionsNames.verifyContribution });
1614
+ verifyContributionTimer.start();
1615
+ // Get DB.
1616
+ const firestore = admin.firestore();
1617
+ // Prepare batch of txs.
1618
+ const batch = firestore.batch();
1619
+ // Extract data.
1620
+ const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data;
1621
+ const userId = request.auth?.uid;
1622
+ // Look for the ceremony, circuit and participant document.
1623
+ const ceremonyDoc = await getDocumentById(actions.commonTerms.collections.ceremonies.name, ceremonyId);
1624
+ const circuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1625
+ const participantDoc = await getDocumentById(actions.getParticipantsCollectionPath(ceremonyId), userId);
1626
+ if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
1627
+ logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA);
1628
+ // Extract documents data.
1629
+ const { state } = ceremonyDoc.data();
1630
+ const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data();
1631
+ const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data();
1632
+ const { completedContributions, failedContributions } = waitingQueue;
1633
+ const { contributionComputation: avgContributionComputationTime, fullContribution: avgFullContributionTime, verifyCloudFunction: avgVerifyCloudFunctionTime } = avgTimings;
1634
+ const { cfOrVm, vm } = verification;
1635
+ // we might not have it if the circuit is not using VM.
1636
+ let vmInstanceId = "";
1637
+ if (vm)
1638
+ vmInstanceId = vm.vmInstanceId;
1639
+ // Define pre-conditions.
1640
+ const isFinalizing = state === "CLOSED" /* CeremonyState.CLOSED */ && request.auth && request.auth.token.coordinator; // true only when the coordinator verifies the final contributions.
1641
+ const isContributing = status === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1642
+ const isUsingVM = cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */ && !!vmInstanceId;
1643
+ // Prepare state.
1644
+ let isContributionValid = false;
1645
+ let verifyCloudFunctionExecutionTime = 0; // time spent while executing the verify contribution cloud function.
1646
+ let verifyCloudFunctionTime = 0; // time spent while executing the core business logic of this cloud function.
1647
+ let fullContributionTime = 0; // time spent while doing non-verification contributions tasks (download, compute, upload).
1648
+ let contributionComputationTime = 0; // time spent while computing the contribution.
1649
+ let lastZkeyBlake2bHash = ""; // the Blake2B hash of the last zKey.
1650
+ let verificationTranscriptTemporaryLocalPath = ""; // the local temporary path for the verification transcript.
1651
+ let transcriptBlake2bHash = ""; // the Blake2B hash of the verification transcript.
1652
+ let commandId = ""; // the unique identifier of the VM command.
1653
+ // Derive necessary data.
1654
+ const lastZkeyIndex = actions.formatZkeyIndex(completedContributions + 1);
1655
+ const verificationTranscriptCompleteFilename = `${prefix}_${isFinalizing
1656
+ ? `${contributorOrCoordinatorIdentifier}_${actions.finalContributionIndex}_verification_transcript.log`
1657
+ : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`}`;
1658
+ const lastZkeyFilename = `${prefix}_${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex}.zkey`;
1659
+ // Prepare state for VM verification (if needed).
1660
+ const ec2 = await createEC2Client();
1661
+ const ssm = await createSSMClient();
1662
+ // Step (1.A.1).
1663
+ // Get storage paths.
1664
+ const verificationTranscriptStoragePathAndFilename = actions.getTranscriptStorageFilePath(prefix, verificationTranscriptCompleteFilename);
1665
+ // the zKey storage path is required to be sent to the VM api
1666
+ const lastZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex}.zkey`);
1667
+ const verificationTaskTimer = new timerNode.Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` });
1668
+ const completeVerification = async () => {
1669
+ // Stop verification task timer.
1670
+ printLog("Completing verification", LogLevel.DEBUG);
1671
+ verificationTaskTimer.stop();
1672
+ verifyCloudFunctionExecutionTime = verificationTaskTimer.ms();
1673
+ if (isUsingVM) {
1674
+ // Create temporary path.
1675
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.log`);
1676
+ await sleep(1000); // wait 1s for file creation.
1677
+ // Download from bucket.
1678
+ // nb. the transcript MUST be uploaded from the VM by verification commands.
1679
+ await downloadArtifactFromS3Bucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath);
1680
+ // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
1681
+ const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8");
1682
+ if (content.includes("ZKey Ok!"))
1683
+ isContributionValid = true;
1684
+ // If the contribution is valid, then format and store the trascript.
1685
+ if (isContributionValid) {
1686
+ // eslint-disable-next-line no-control-regex
1687
+ const updated = content.replace(/\x1b[[0-9;]*m/g, "");
1688
+ fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated);
1689
+ }
1690
+ }
1691
+ printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG);
1692
+ // Create a new contribution document.
1693
+ const contributionDoc = await firestore
1694
+ .collection(actions.getContributionsCollectionPath(ceremonyId, circuitId))
1695
+ .doc()
1696
+ .get();
1697
+ // Step (1.A.4).
1684
1698
  if (isContributionValid) {
1685
- // eslint-disable-next-line no-control-regex
1686
- const updated = content.replace(/\x1b[[0-9;]*m/g, "");
1687
- fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated);
1699
+ // Sleep ~3 seconds to wait for verification transcription.
1700
+ await sleep(3000);
1701
+ // Step (1.A.4.A.1).
1702
+ if (isUsingVM) {
1703
+ // Retrieve the contribution hash from the command output.
1704
+ lastZkeyBlake2bHash = await actions.retrieveCommandOutput(ssm, vmInstanceId, commandId);
1705
+ const hashRegex = /[a-fA-F0-9]{64}/;
1706
+ const match = lastZkeyBlake2bHash.match(hashRegex);
1707
+ lastZkeyBlake2bHash = match.at(0);
1708
+ // re upload the formatted verification transcript
1709
+ await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1710
+ }
1711
+ else {
1712
+ // Upload verification transcript.
1713
+ /// nb. do not use multi-part upload here due to small file size.
1714
+ await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1715
+ }
1716
+ // Compute verification transcript hash.
1717
+ transcriptBlake2bHash = await actions.blake512FromPath(verificationTranscriptTemporaryLocalPath);
1718
+ // Free resources by unlinking transcript temporary file.
1719
+ fs.unlinkSync(verificationTranscriptTemporaryLocalPath);
1720
+ // Filter participant contributions to find the data related to the one verified.
1721
+ const participantContributions = contributions.filter((contribution) => !!contribution.hash && !!contribution.computationTime && !contribution.doc);
1722
+ /// @dev (there must be only one contribution with an empty 'doc' field).
1723
+ if (participantContributions.length !== 1)
1724
+ logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA);
1725
+ // Get contribution computation time.
1726
+ contributionComputationTime = contributions.at(0).computationTime;
1727
+ // Step (1.A.4.A.2).
1728
+ batch.create(contributionDoc.ref, {
1729
+ participantId: participantDoc.id,
1730
+ contributionComputationTime,
1731
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
1732
+ zkeyIndex: isFinalizing ? actions.finalContributionIndex : lastZkeyIndex,
1733
+ files: {
1734
+ transcriptFilename: verificationTranscriptCompleteFilename,
1735
+ lastZkeyFilename,
1736
+ transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
1737
+ lastZkeyStoragePath,
1738
+ transcriptBlake2bHash,
1739
+ lastZkeyBlake2bHash
1740
+ },
1741
+ verificationSoftware: {
1742
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1743
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1744
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1745
+ },
1746
+ valid: isContributionValid,
1747
+ lastUpdated: getCurrentServerTimestampInMillis()
1748
+ });
1749
+ verifyContributionTimer.stop();
1750
+ verifyCloudFunctionTime = verifyContributionTimer.ms();
1688
1751
  }
1689
- }
1690
- printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG);
1691
- // Create a new contribution document.
1692
- const contributionDoc = await firestore
1693
- .collection(actions.getContributionsCollectionPath(ceremonyId, circuitId))
1694
- .doc()
1695
- .get();
1696
- // Step (1.A.4).
1697
- if (isContributionValid) {
1698
- // Sleep ~3 seconds to wait for verification transcription.
1699
- await sleep(3000);
1700
- // Step (1.A.4.A.1).
1752
+ else {
1753
+ // Step (1.A.4.B).
1754
+ // Free-up storage by deleting invalid contribution.
1755
+ await deleteObject(bucketName, lastZkeyStoragePath);
1756
+ // Step (1.A.4.B.1).
1757
+ batch.create(contributionDoc.ref, {
1758
+ participantId: participantDoc.id,
1759
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
1760
+ zkeyIndex: isFinalizing ? actions.finalContributionIndex : lastZkeyIndex,
1761
+ verificationSoftware: {
1762
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1763
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1764
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1765
+ },
1766
+ valid: isContributionValid,
1767
+ lastUpdated: getCurrentServerTimestampInMillis()
1768
+ });
1769
+ }
1770
+ // Stop VM instance
1701
1771
  if (isUsingVM) {
1702
- // Retrieve the contribution hash from the command output.
1703
- lastZkeyBlake2bHash = await actions.retrieveCommandOutput(ssm, vmInstanceId, commandId);
1704
- const hashRegex = /[a-fA-F0-9]{64}/;
1705
- const match = lastZkeyBlake2bHash.match(hashRegex);
1706
- lastZkeyBlake2bHash = match.at(0);
1707
- // re upload the formatted verification transcript
1708
- await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1772
+ // using try and catch as the VM stopping function can throw
1773
+ // however we want to continue without stopping as the
1774
+ // verification was valid, and inform the coordinator
1775
+ try {
1776
+ await actions.stopEC2Instance(ec2, vmInstanceId);
1777
+ }
1778
+ catch (error) {
1779
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1780
+ }
1709
1781
  }
1710
- else {
1711
- // Upload verification transcript.
1712
- /// nb. do not use multi-part upload here due to small file size.
1713
- await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1782
+ // Step (1.A.4.C)
1783
+ if (!isFinalizing) {
1784
+ // Step (1.A.4.C.1)
1785
+ // Compute new average contribution/verification time.
1786
+ fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt);
1787
+ const newAvgContributionComputationTime = avgContributionComputationTime > 0
1788
+ ? (avgContributionComputationTime + contributionComputationTime) / 2
1789
+ : contributionComputationTime;
1790
+ const newAvgFullContributionTime = avgFullContributionTime > 0
1791
+ ? (avgFullContributionTime + fullContributionTime) / 2
1792
+ : fullContributionTime;
1793
+ const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1794
+ ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1795
+ : verifyCloudFunctionTime;
1796
+ // Prepare tx to update circuit average contribution/verification time.
1797
+ const updatedCircuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1798
+ const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1799
+ /// @dev this must happen only for valid contributions.
1800
+ batch.update(circuitDoc.ref, {
1801
+ avgTimings: {
1802
+ contributionComputation: isContributionValid
1803
+ ? newAvgContributionComputationTime
1804
+ : avgContributionComputationTime,
1805
+ fullContribution: isContributionValid ? newAvgFullContributionTime : avgFullContributionTime,
1806
+ verifyCloudFunction: isContributionValid
1807
+ ? newAvgVerifyCloudFunctionTime
1808
+ : avgVerifyCloudFunctionTime
1809
+ },
1810
+ waitingQueue: {
1811
+ ...updatedWaitingQueue,
1812
+ completedContributions: isContributionValid
1813
+ ? completedContributions + 1
1814
+ : completedContributions,
1815
+ failedContributions: isContributionValid ? failedContributions : failedContributions + 1
1816
+ },
1817
+ lastUpdated: getCurrentServerTimestampInMillis()
1818
+ });
1714
1819
  }
1715
- // Compute verification transcript hash.
1716
- transcriptBlake2bHash = await actions.blake512FromPath(verificationTranscriptTemporaryLocalPath);
1717
- // Free resources by unlinking transcript temporary file.
1718
- fs.unlinkSync(verificationTranscriptTemporaryLocalPath);
1719
- // Filter participant contributions to find the data related to the one verified.
1720
- const participantContributions = contributions.filter((contribution) => !!contribution.hash && !!contribution.computationTime && !contribution.doc);
1721
- /// @dev (there must be only one contribution with an empty 'doc' field).
1722
- if (participantContributions.length !== 1)
1723
- logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA);
1724
- // Get contribution computation time.
1725
- contributionComputationTime = contributions.at(0).computationTime;
1726
- // Step (1.A.4.A.2).
1727
- batch.create(contributionDoc.ref, {
1728
- participantId: participantDoc.id,
1729
- contributionComputationTime,
1730
- verificationComputationTime: verifyCloudFunctionExecutionTime,
1731
- zkeyIndex: isFinalizing ? actions.finalContributionIndex : lastZkeyIndex,
1732
- files: {
1733
- transcriptFilename: verificationTranscriptCompleteFilename,
1734
- lastZkeyFilename,
1735
- transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
1736
- lastZkeyStoragePath,
1737
- transcriptBlake2bHash,
1738
- lastZkeyBlake2bHash
1739
- },
1740
- verificationSoftware: {
1741
- name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1742
- version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1743
- commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1744
- },
1745
- valid: isContributionValid,
1746
- lastUpdated: getCurrentServerTimestampInMillis()
1747
- });
1748
- verifyContributionTimer.stop();
1749
- verifyCloudFunctionTime = verifyContributionTimer.ms();
1750
- }
1751
- else {
1752
- // Step (1.A.4.B).
1753
- // Free-up storage by deleting invalid contribution.
1754
- await deleteObject(bucketName, lastZkeyStoragePath);
1755
- // Step (1.A.4.B.1).
1756
- batch.create(contributionDoc.ref, {
1757
- participantId: participantDoc.id,
1758
- verificationComputationTime: verifyCloudFunctionExecutionTime,
1759
- zkeyIndex: isFinalizing ? actions.finalContributionIndex : lastZkeyIndex,
1760
- verificationSoftware: {
1761
- name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1762
- version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1763
- commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1764
- },
1765
- valid: isContributionValid,
1766
- lastUpdated: getCurrentServerTimestampInMillis()
1767
- });
1768
- }
1769
- // Stop VM instance
1770
- if (isUsingVM) {
1771
- // using try and catch as the VM stopping function can throw
1772
- // however we want to continue without stopping as the
1773
- // verification was valid, and inform the coordinator
1820
+ // Step (2).
1821
+ await batch.commit();
1822
+ printLog(`The contribution #${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex} of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${isContributionValid ? "valid" : "invalid"} for the participant ${participantDoc.id}`, LogLevel.DEBUG);
1823
+ };
1824
+ // Step (1).
1825
+ if (isContributing || isFinalizing) {
1826
+ // Prepare timer.
1827
+ verificationTaskTimer.start();
1828
+ // Step (1.A.3.0).
1829
+ if (isUsingVM) {
1830
+ printLog(`Starting the VM mechanism`, LogLevel.DEBUG);
1831
+ // Prepare for VM execution.
1832
+ let isVMRunning = false; // true when the VM is up, otherwise false.
1833
+ // Step (1.A.3.1).
1834
+ await actions.startEC2Instance(ec2, vmInstanceId);
1835
+ await sleep(60000); // nb. wait for VM startup (1 mins + retry).
1836
+ // Check if the startup is running.
1837
+ isVMRunning = await checkIfVMRunning(ec2, vmInstanceId);
1838
+ printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG);
1839
+ // Step (1.A.3.2).
1840
+ // Prepare.
1841
+ const verificationCommand = actions.vmContributionVerificationCommand(bucketName, lastZkeyStoragePath, verificationTranscriptStoragePathAndFilename);
1842
+ // Run.
1843
+ commandId = await actions.runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1844
+ printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1845
+ // Step (1.A.3.3).
1846
+ return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1847
+ .then(async () => {
1848
+ // Command execution successfully completed.
1849
+ printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
1850
+ await completeVerification();
1851
+ })
1852
+ .catch((error) => {
1853
+ // Command execution aborted.
1854
+ printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.DEBUG);
1855
+ logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1856
+ });
1857
+ }
1858
+ // CF approach.
1859
+ printLog(`CF mechanism`, LogLevel.DEBUG);
1860
+ const potStoragePath = actions.getPotStorageFilePath(files.potFilename);
1861
+ const firstZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${actions.genesisZkeyIndex}.zkey`);
1862
+ // Prepare temporary file paths.
1863
+ // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1864
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1865
+ const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1866
+ const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1867
+ const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1868
+ // Create and populate transcript.
1869
+ const transcriptLogger = actions.createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1870
+ transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1871
+ // Step (1.A.2).
1872
+ await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1873
+ await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1874
+ await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1875
+ // Step (1.A.4).
1876
+ isContributionValid = await snarkjs.zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1877
+ // Compute contribution hash.
1878
+ lastZkeyBlake2bHash = await actions.blake512FromPath(lastZkeyTempFilePath);
1879
+ // Free resources by unlinking temporary folders.
1880
+ // Do not free-up verification transcript path here.
1774
1881
  try {
1775
- await actions.stopEC2Instance(ec2, vmInstanceId);
1882
+ fs.unlinkSync(potTempFilePath);
1883
+ fs.unlinkSync(firstZkeyTempFilePath);
1884
+ fs.unlinkSync(lastZkeyTempFilePath);
1776
1885
  }
1777
1886
  catch (error) {
1778
- printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1887
+ printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1779
1888
  }
1889
+ await completeVerification();
1780
1890
  }
1781
- // Step (1.A.4.C)
1782
- if (!isFinalizing) {
1783
- // Step (1.A.4.C.1)
1784
- // Compute new average contribution/verification time.
1785
- fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt);
1786
- const newAvgContributionComputationTime = avgContributionComputationTime > 0
1787
- ? (avgContributionComputationTime + contributionComputationTime) / 2
1788
- : contributionComputationTime;
1789
- const newAvgFullContributionTime = avgFullContributionTime > 0
1790
- ? (avgFullContributionTime + fullContributionTime) / 2
1791
- : fullContributionTime;
1792
- const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1793
- ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1794
- : verifyCloudFunctionTime;
1795
- // Prepare tx to update circuit average contribution/verification time.
1796
- const updatedCircuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1797
- const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1798
- /// @dev this must happen only for valid contributions.
1799
- batch.update(circuitDoc.ref, {
1800
- avgTimings: {
1801
- contributionComputation: isContributionValid
1802
- ? newAvgContributionComputationTime
1803
- : avgContributionComputationTime,
1804
- fullContribution: isContributionValid ? newAvgFullContributionTime : avgFullContributionTime,
1805
- verifyCloudFunction: isContributionValid
1806
- ? newAvgVerifyCloudFunctionTime
1807
- : avgVerifyCloudFunctionTime
1808
- },
1809
- waitingQueue: {
1810
- ...updatedWaitingQueue,
1811
- completedContributions: isContributionValid
1812
- ? completedContributions + 1
1813
- : completedContributions,
1814
- failedContributions: isContributionValid ? failedContributions : failedContributions + 1
1815
- },
1816
- lastUpdated: getCurrentServerTimestampInMillis()
1817
- });
1818
- }
1819
- // Step (2).
1820
- await batch.commit();
1821
- printLog(`The contribution #${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex} of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${isContributionValid ? "valid" : "invalid"} for the participant ${participantDoc.id}`, LogLevel.DEBUG);
1822
- };
1823
- // Step (1).
1824
- if (isContributing || isFinalizing) {
1825
- // Prepare timer.
1826
- verificationTaskTimer.start();
1827
- // Step (1.A.3.0).
1828
- if (isUsingVM) {
1829
- printLog(`Starting the VM mechanism`, LogLevel.DEBUG);
1830
- // Prepare for VM execution.
1831
- let isVMRunning = false; // true when the VM is up, otherwise false.
1832
- // Step (1.A.3.1).
1833
- await actions.startEC2Instance(ec2, vmInstanceId);
1834
- await sleep(60000); // nb. wait for VM startup (1 mins + retry).
1835
- // Check if the startup is running.
1836
- isVMRunning = await checkIfVMRunning(ec2, vmInstanceId);
1837
- printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG);
1838
- // Step (1.A.3.2).
1839
- // Prepare.
1840
- const verificationCommand = actions.vmContributionVerificationCommand(bucketName, lastZkeyStoragePath, verificationTranscriptStoragePathAndFilename);
1841
- // Run.
1842
- commandId = await actions.runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1843
- printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1844
- // Step (1.A.3.3).
1845
- return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1846
- .then(async () => {
1847
- // Command execution successfully completed.
1848
- printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
1849
- await completeVerification();
1850
- })
1851
- .catch((error) => {
1852
- // Command execution aborted.
1853
- printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.DEBUG);
1854
- logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1855
- });
1856
- }
1857
- // CF approach.
1858
- printLog(`CF mechanism`, LogLevel.DEBUG);
1859
- const potStoragePath = actions.getPotStorageFilePath(files.potFilename);
1860
- const firstZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${actions.genesisZkeyIndex}.zkey`);
1861
- // Prepare temporary file paths.
1862
- // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1863
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1864
- const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1865
- const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1866
- const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1867
- // Create and populate transcript.
1868
- const transcriptLogger = actions.createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1869
- transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1870
- // Step (1.A.2).
1871
- await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1872
- await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1873
- await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1874
- // Step (1.A.4).
1875
- isContributionValid = await snarkjs.zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1876
- // Compute contribution hash.
1877
- lastZkeyBlake2bHash = await actions.blake512FromPath(lastZkeyTempFilePath);
1878
- // Free resources by unlinking temporary folders.
1879
- // Do not free-up verification transcript path here.
1880
- try {
1881
- fs.unlinkSync(potTempFilePath);
1882
- fs.unlinkSync(firstZkeyTempFilePath);
1883
- fs.unlinkSync(lastZkeyTempFilePath);
1884
- }
1885
- catch (error) {
1886
- printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1887
- }
1888
- await completeVerification();
1891
+ }
1892
+ catch (error) {
1893
+ logAndThrowError(makeError("unknown", error));
1889
1894
  }
1890
1895
  });
1891
1896
  /**
@@ -1896,7 +1901,7 @@ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "16GiB"
1896
1901
  const refreshParticipantAfterContributionVerification = functionsV1__namespace
1897
1902
  .region("europe-west1")
1898
1903
  .runWith({
1899
- memory: "512MB"
1904
+ memory: "1GB"
1900
1905
  })
1901
1906
  .firestore.document(`/${actions.commonTerms.collections.ceremonies.name}/{ceremony}/${actions.commonTerms.collections.circuits.name}/{circuit}/${actions.commonTerms.collections.contributions.name}/{contributions}`)
1902
1907
  .onCreate(async (createdContribution) => {
@@ -1957,7 +1962,7 @@ const refreshParticipantAfterContributionVerification = functionsV1__namespace
1957
1962
  const finalizeCircuit = functionsV1__namespace
1958
1963
  .region("europe-west1")
1959
1964
  .runWith({
1960
- memory: "512MB"
1965
+ memory: "1GB"
1961
1966
  })
1962
1967
  .https.onCall(async (data, context) => {
1963
1968
  if (!context.auth || !context.auth.token.coordinator)
@@ -2101,7 +2106,7 @@ const checkIfBucketIsDedicatedToCeremony = async (bucketName) => {
2101
2106
  const createBucket = functions__namespace
2102
2107
  .region("europe-west1")
2103
2108
  .runWith({
2104
- memory: "512MB"
2109
+ memory: "1GB"
2105
2110
  })
2106
2111
  .https.onCall(async (data, context) => {
2107
2112
  // Check if the user has the coordinator claim.
@@ -2191,7 +2196,7 @@ const createBucket = functions__namespace
2191
2196
  const checkIfObjectExist = functions__namespace
2192
2197
  .region("europe-west1")
2193
2198
  .runWith({
2194
- memory: "512MB"
2199
+ memory: "1GB"
2195
2200
  })
2196
2201
  .https.onCall(async (data, context) => {
2197
2202
  // Check if the user has the coordinator claim.
@@ -2237,7 +2242,7 @@ const checkIfObjectExist = functions__namespace
2237
2242
  const generateGetObjectPreSignedUrl = functions__namespace
2238
2243
  .region("europe-west1")
2239
2244
  .runWith({
2240
- memory: "512MB"
2245
+ memory: "1GB"
2241
2246
  })
2242
2247
  .https.onCall(async (data, context) => {
2243
2248
  if (!context.auth)
@@ -2277,7 +2282,7 @@ const generateGetObjectPreSignedUrl = functions__namespace
2277
2282
  const startMultiPartUpload = functions__namespace
2278
2283
  .region("europe-west1")
2279
2284
  .runWith({
2280
- memory: "512MB"
2285
+ memory: "2GB"
2281
2286
  })
2282
2287
  .https.onCall(async (data, context) => {
2283
2288
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -2332,7 +2337,7 @@ const startMultiPartUpload = functions__namespace
2332
2337
  const generatePreSignedUrlsParts = functions__namespace
2333
2338
  .region("europe-west1")
2334
2339
  .runWith({
2335
- memory: "512MB",
2340
+ memory: "1GB",
2336
2341
  timeoutSeconds: 300
2337
2342
  })
2338
2343
  .https.onCall(async (data, context) => {
@@ -2393,7 +2398,7 @@ const generatePreSignedUrlsParts = functions__namespace
2393
2398
  const completeMultiPartUpload = functions__namespace
2394
2399
  .region("europe-west1")
2395
2400
  .runWith({
2396
- memory: "512MB"
2401
+ memory: "2GB"
2397
2402
  })
2398
2403
  .https.onCall(async (data, context) => {
2399
2404
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -2607,7 +2612,7 @@ const checkNonceOfSIWEAddress = functions__namespace
2607
2612
  const auth$1 = auth.getAuth();
2608
2613
  // check nonce
2609
2614
  const parts = result.sub.split("|");
2610
- const address = decodeURIComponent(parts[2]).split("eip155:534352:")[1];
2615
+ const address = decodeURIComponent(parts[2]).split(":")[2];
2611
2616
  const minimumNonce = Number(process.env.ETH_MINIMUM_NONCE);
2612
2617
  const nonceBlockHeight = "latest"; // process.env.ETH_NONCE_BLOCK_HEIGHT
2613
2618
  // look up nonce for address @block
@@ -2674,7 +2679,7 @@ dotenv.config();
2674
2679
  const checkAndRemoveBlockingContributor = functions__namespace
2675
2680
  .region("europe-west1")
2676
2681
  .runWith({
2677
- memory: "512MB"
2682
+ memory: "1GB"
2678
2683
  })
2679
2684
  .pubsub.schedule("every 1 minutes")
2680
2685
  .onRun(async () => {
@@ -2743,7 +2748,8 @@ const checkAndRemoveBlockingContributor = functions__namespace
2743
2748
  if (timeoutExpirationDateInMsForBlockingContributor < currentServerTimestamp &&
2744
2749
  (contributionStep === "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */ ||
2745
2750
  contributionStep === "COMPUTING" /* ParticipantContributionStep.COMPUTING */ ||
2746
- contributionStep === "UPLOADING" /* ParticipantContributionStep.UPLOADING */))
2751
+ contributionStep === "UPLOADING" /* ParticipantContributionStep.UPLOADING */ ||
2752
+ contributionStep === "COMPLETED" /* ParticipantContributionStep.COMPLETED */))
2747
2753
  timeoutType = "BLOCKING_CONTRIBUTION" /* TimeoutType.BLOCKING_CONTRIBUTION */;
2748
2754
  if (timeoutExpirationDateInMsForVerificationCloudFunction > 0 &&
2749
2755
  timeoutExpirationDateInMsForVerificationCloudFunction < currentServerTimestamp &&
@@ -2820,7 +2826,7 @@ const checkAndRemoveBlockingContributor = functions__namespace
2820
2826
  const resumeContributionAfterTimeoutExpiration = functions__namespace
2821
2827
  .region("europe-west1")
2822
2828
  .runWith({
2823
- memory: "512MB"
2829
+ memory: "1GB"
2824
2830
  })
2825
2831
  .https.onCall(async (data, context) => {
2826
2832
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))