@devtion/backend 0.0.0-9843891 → 0.0.0-9d46256

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.2.3
3
+ * @version 1.2.8
4
4
  * @file MPC Phase 2 backend for Firebase services management
5
5
  * @copyright Ethereum Foundation 2022
6
6
  * @license MIT
@@ -148,7 +148,8 @@ const SPECIFIC_ERRORS = {
148
148
  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."),
149
149
  SE_VM_CANCELLED_COMMAND_EXECUTION: makeError("cancelled", "VM command execution has been cancelled", "Please, contact the coordinator if this error persists."),
150
150
  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."),
151
- 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.")
151
+ 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."),
152
+ WRONG_BUCKET_NAME: makeError("invalid-argument", "The provided bucket name is not valid.", "Bucket names must be between 3 and 63 characters long, can only contain lowercase letters, numbers, and hyphens, and must start and end with a letter or number.")
152
153
  };
153
154
  /**
154
155
  * A set of common errors.
@@ -769,7 +770,9 @@ const setupCeremony = functions__namespace
769
770
  // The VM unique identifier (if any).
770
771
  let vmInstanceId = "";
771
772
  // Get a new circuit document.
772
- const circuitDoc = await firestore.collection(actions.getCircuitsCollectionPath(ceremonyDoc.ref.id)).doc().get();
773
+ const ccp = actions.getCircuitsCollectionPath(ceremonyDoc.ref.id);
774
+ printLog(`CircuitsCollectionPath = ${ccp}`, LogLevel.DEBUG);
775
+ const circuitDoc = await firestore.collection(ccp).doc().get();
773
776
  // Check if using the VM approach for contribution verification.
774
777
  if (circuit.verification.cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */) {
775
778
  // VM command to be run at the startup.
@@ -806,12 +809,14 @@ const setupCeremony = functions__namespace
806
809
  }
807
810
  // Encode circuit data.
808
811
  const encodedCircuit = htmlEncodeCircuitData(circuit);
812
+ printLog(`writing circuit data...`, LogLevel.DEBUG);
809
813
  // Prepare tx to write circuit data.
810
814
  batch.create(circuitDoc.ref, {
811
815
  ...encodedCircuit,
812
816
  lastUpdated: getCurrentServerTimestampInMillis()
813
817
  });
814
818
  }
819
+ printLog(`Done handling circuits...`, LogLevel.DEBUG);
815
820
  // Send txs in a batch (to avoid race conditions).
816
821
  await batch.commit();
817
822
  printLog(`Setup completed for ceremony ${ceremonyDoc.id}`, LogLevel.DEBUG);
@@ -824,7 +829,7 @@ const setupCeremony = functions__namespace
824
829
  const initEmptyWaitingQueueForCircuit = functions__namespace
825
830
  .region("europe-west1")
826
831
  .runWith({
827
- memory: "512MB"
832
+ memory: "1GB"
828
833
  })
829
834
  .firestore.document(`/${actions.commonTerms.collections.ceremonies.name}/{ceremony}/${actions.commonTerms.collections.circuits.name}/{circuit}`)
830
835
  .onCreate(async (doc) => {
@@ -856,7 +861,7 @@ const initEmptyWaitingQueueForCircuit = functions__namespace
856
861
  const finalizeCeremony = functions__namespace
857
862
  .region("europe-west1")
858
863
  .runWith({
859
- memory: "512MB"
864
+ memory: "1GB"
860
865
  })
861
866
  .https.onCall(async (data, context) => {
862
867
  if (!context.auth || !context.auth.token.coordinator)
@@ -1333,7 +1338,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1333
1338
  if (isSingleParticipantCoordination) {
1334
1339
  // Scenario (A).
1335
1340
  if (emptyWaitingQueue) {
1336
- printLog(`Coordinate - executing scenario A - emptyWaitingQueue`, LogLevel.DEBUG);
1341
+ printLog(`Coordinate - executing scenario A - emptyWaitingQueue`, LogLevel.INFO);
1337
1342
  // Update.
1338
1343
  newCurrentContributorId = participant.id;
1339
1344
  newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
@@ -1342,14 +1347,14 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1342
1347
  }
1343
1348
  // Scenario (A).
1344
1349
  else if (participantResumingAfterTimeoutExpiration) {
1345
- printLog(`Coordinate - executing scenario A - single - participantResumingAfterTimeoutExpiration`, LogLevel.DEBUG);
1350
+ printLog(`Coordinate - executing scenario A - single - participantResumingAfterTimeoutExpiration`, LogLevel.INFO);
1346
1351
  newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1347
1352
  newContributionStep = "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */;
1348
1353
  newCurrentContributorId = participant.id;
1349
1354
  }
1350
1355
  // Scenario (B).
1351
1356
  else if (participantIsNotCurrentContributor) {
1352
- printLog(`Coordinate - executing scenario B - single - participantIsNotCurrentContributor`, LogLevel.DEBUG);
1357
+ printLog(`Coordinate - executing scenario B - single - participantIsNotCurrentContributor`, LogLevel.INFO);
1353
1358
  newCurrentContributorId = currentContributor;
1354
1359
  newParticipantStatus = "WAITING" /* ParticipantStatus.WAITING */;
1355
1360
  newContributors.push(participant.id);
@@ -1368,7 +1373,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1368
1373
  });
1369
1374
  }
1370
1375
  else if (participantIsCurrentContributor && participantCompletedOneOrAllContributions && !!ceremonyId) {
1371
- printLog(`Coordinate - executing scenario C - multi - participantIsCurrentContributor && participantCompletedOneOrAllContributions`, LogLevel.DEBUG);
1376
+ printLog(`Coordinate - executing scenario C - multi - participantIsCurrentContributor && participantCompletedOneOrAllContributions`, LogLevel.INFO);
1372
1377
  newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1373
1378
  newContributionStep = "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */;
1374
1379
  // Remove from waiting queue of circuit X.
@@ -1386,7 +1391,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1386
1391
  contributionStartedAt: getCurrentServerTimestampInMillis(),
1387
1392
  lastUpdated: getCurrentServerTimestampInMillis()
1388
1393
  });
1389
- printLog(`Participant ${newCurrentContributorId} is the new current contributor for circuit ${circuit.id}`, LogLevel.DEBUG);
1394
+ printLog(`Participant ${newCurrentContributorId} is the new current contributor for circuit ${circuit.id}`, LogLevel.INFO);
1390
1395
  }
1391
1396
  }
1392
1397
  // Prepare tx - must be done for all Scenarios.
@@ -1463,8 +1468,8 @@ const waitForVMCommandExecution = (ssm, vmInstanceId, commandId) => new Promise(
1463
1468
  try {
1464
1469
  await actions.stopEC2Instance(ec2, vmInstanceId);
1465
1470
  }
1466
- catch (error) {
1467
- printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1471
+ catch (stopError) {
1472
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${stopError}`, LogLevel.WARN);
1468
1473
  }
1469
1474
  if (!error.toString().includes(commandId))
1470
1475
  logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
@@ -1512,8 +1517,8 @@ const coordinateCeremonyParticipant = functionsV1__namespace
1512
1517
  // Extract data.
1513
1518
  const { contributionProgress: prevContributionProgress, status: prevStatus, contributionStep: prevContributionStep } = exParticipant.data();
1514
1519
  const { contributionProgress: changedContributionProgress, status: changedStatus, contributionStep: changedContributionStep } = changedParticipant.data();
1515
- printLog(`Coordinate participant ${exParticipant.id} for ceremony ${ceremonyId}`, LogLevel.DEBUG);
1516
- printLog(`Participant status: ${prevStatus} => ${changedStatus} - Participant contribution step: ${prevContributionStep} => ${changedContributionStep}`, LogLevel.DEBUG);
1520
+ printLog(`Coordinate participant ${exParticipant.id} for ceremony ${ceremonyId}`, LogLevel.INFO);
1521
+ printLog(`Participant status: ${prevStatus} => ${changedStatus} - Participant contribution step: ${prevContributionStep} => ${changedContributionStep}`, LogLevel.INFO);
1517
1522
  // Define pre-conditions.
1518
1523
  const participantReadyToContribute = changedStatus === "READY" /* ParticipantStatus.READY */;
1519
1524
  const participantReadyForFirstContribution = participantReadyToContribute && prevContributionProgress === 0;
@@ -1523,8 +1528,8 @@ const coordinateCeremonyParticipant = functionsV1__namespace
1523
1528
  prevContributionProgress !== 0;
1524
1529
  const participantCompletedEveryCircuitContribution = changedStatus === "DONE" /* ParticipantStatus.DONE */ && prevStatus !== "DONE" /* ParticipantStatus.DONE */;
1525
1530
  const participantCompletedContribution = prevContributionProgress === changedContributionProgress &&
1526
- prevStatus === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */ &&
1527
- prevContributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */ &&
1531
+ (prevStatus === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */ ||
1532
+ prevContributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */) &&
1528
1533
  changedStatus === "CONTRIBUTED" /* ParticipantStatus.CONTRIBUTED */ &&
1529
1534
  changedContributionStep === "COMPLETED" /* ParticipantContributionStep.COMPLETED */;
1530
1535
  // Step (2).
@@ -1532,7 +1537,7 @@ const coordinateCeremonyParticipant = functionsV1__namespace
1532
1537
  participantResumingContributionAfterTimeout ||
1533
1538
  participantReadyForNextContribution) {
1534
1539
  // Step (2.A).
1535
- printLog(`Participant is ready for first contribution (${participantReadyForFirstContribution}) or for the next contribution (${participantReadyForNextContribution}) or is resuming after a timeout expiration (${participantResumingContributionAfterTimeout})`, LogLevel.DEBUG);
1540
+ printLog(`Participant is ready for first contribution (${participantReadyForFirstContribution}) or for the next contribution (${participantReadyForNextContribution}) or is resuming after a timeout expiration (${participantResumingContributionAfterTimeout})`, LogLevel.INFO);
1536
1541
  // Get the circuit.
1537
1542
  const circuit = await getCircuitDocumentByPosition(ceremonyId, changedContributionProgress);
1538
1543
  // Coordinate.
@@ -1541,7 +1546,7 @@ const coordinateCeremonyParticipant = functionsV1__namespace
1541
1546
  }
1542
1547
  else if (participantCompletedContribution || participantCompletedEveryCircuitContribution) {
1543
1548
  // Step (2.B).
1544
- printLog(`Participant completed a contribution (${participantCompletedContribution}) or every contribution for each circuit (${participantCompletedEveryCircuitContribution})`, LogLevel.DEBUG);
1549
+ printLog(`Participant completed a contribution (${participantCompletedContribution}) or every contribution for each circuit (${participantCompletedEveryCircuitContribution})`, LogLevel.INFO);
1545
1550
  // Get the circuit.
1546
1551
  const circuit = await getCircuitDocumentByPosition(ceremonyId, prevContributionProgress);
1547
1552
  // Coordinate.
@@ -1595,297 +1600,325 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
1595
1600
  * 1.A.4.C.1) If true, update circuit waiting for queue and average timings accordingly to contribution verification results;
1596
1601
  * 2) Send all updates atomically to the Firestore database.
1597
1602
  */
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.
1684
- 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);
1603
+ const verifycontribution = functionsV2__namespace.https.onCall({ memory: "32GiB", timeoutSeconds: 3600, region: "europe-west1", cpu: 8 }, async (request) => {
1604
+ try {
1605
+ if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1606
+ logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1607
+ if (!request.data.ceremonyId ||
1608
+ !request.data.circuitId ||
1609
+ !request.data.contributorOrCoordinatorIdentifier ||
1610
+ !request.data.bucketName)
1611
+ logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA);
1612
+ if (!process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
1613
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
1614
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1615
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
1616
+ const BUCKET_NAME_REGEX = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
1617
+ if (!BUCKET_NAME_REGEX.test(request.data.bucketName))
1618
+ logAndThrowError(SPECIFIC_ERRORS.WRONG_BUCKET_NAME);
1619
+ // Step (0).
1620
+ // Prepare and start timer.
1621
+ const verifyContributionTimer = new timerNode.Timer({ label: actions.commonTerms.cloudFunctionsNames.verifyContribution });
1622
+ verifyContributionTimer.start();
1623
+ // Get DB.
1624
+ const firestore = admin.firestore();
1625
+ // Prepare batch of txs.
1626
+ const batch = firestore.batch();
1627
+ // Extract data.
1628
+ const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data;
1629
+ const userId = request.auth?.uid;
1630
+ // Look for the ceremony, circuit and participant document.
1631
+ const ceremonyDoc = await getDocumentById(actions.commonTerms.collections.ceremonies.name, ceremonyId);
1632
+ const circuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1633
+ const participantDoc = await getDocumentById(actions.getParticipantsCollectionPath(ceremonyId), userId);
1634
+ if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
1635
+ logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA);
1636
+ // Extract documents data.
1637
+ const { state } = ceremonyDoc.data();
1638
+ const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data();
1639
+ const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data();
1640
+ const { completedContributions, failedContributions } = waitingQueue;
1641
+ const { contributionComputation: avgContributionComputationTime, fullContribution: avgFullContributionTime, verifyCloudFunction: avgVerifyCloudFunctionTime } = avgTimings;
1642
+ const { cfOrVm, vm } = verification;
1643
+ // we might not have it if the circuit is not using VM.
1644
+ let vmInstanceId = "";
1645
+ if (vm)
1646
+ vmInstanceId = vm.vmInstanceId;
1647
+ // Define pre-conditions.
1648
+ const isFinalizing = state === "CLOSED" /* CeremonyState.CLOSED */ && request.auth && request.auth.token.coordinator; // true only when the coordinator verifies the final contributions.
1649
+ const isContributing = status === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1650
+ const isUsingVM = cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */ && !!vmInstanceId;
1651
+ // Prepare state.
1652
+ let isContributionValid = false;
1653
+ let verifyCloudFunctionExecutionTime = 0; // time spent while executing the verify contribution cloud function.
1654
+ let verifyCloudFunctionTime = 0; // time spent while executing the core business logic of this cloud function.
1655
+ let fullContributionTime = 0; // time spent while doing non-verification contributions tasks (download, compute, upload).
1656
+ let contributionComputationTime = 0; // time spent while computing the contribution.
1657
+ let lastZkeyBlake2bHash = ""; // the Blake2B hash of the last zKey.
1658
+ let verificationTranscriptTemporaryLocalPath = ""; // the local temporary path for the verification transcript.
1659
+ let transcriptBlake2bHash = ""; // the Blake2B hash of the verification transcript.
1660
+ let commandId = ""; // the unique identifier of the VM command.
1661
+ // Derive necessary data.
1662
+ const lastZkeyIndex = actions.formatZkeyIndex(completedContributions + 1);
1663
+ const verificationTranscriptCompleteFilename = `${prefix}_${isFinalizing
1664
+ ? `${contributorOrCoordinatorIdentifier}_${actions.finalContributionIndex}_verification_transcript.log`
1665
+ : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`}`;
1666
+ const lastZkeyFilename = `${prefix}_${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex}.zkey`;
1667
+ // Prepare state for VM verification (if needed).
1668
+ const ec2 = await createEC2Client();
1669
+ const ssm = await createSSMClient();
1670
+ // Step (1.A.1).
1671
+ // Get storage paths.
1672
+ const verificationTranscriptStoragePathAndFilename = actions.getTranscriptStorageFilePath(prefix, verificationTranscriptCompleteFilename);
1673
+ // the zKey storage path is required to be sent to the VM api
1674
+ const lastZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${isFinalizing ? actions.finalContributionIndex : lastZkeyIndex}.zkey`);
1675
+ const verificationTaskTimer = new timerNode.Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` });
1676
+ const dumpLog = async (path) => {
1677
+ printLog(`transcript >>>>>>`, LogLevel.DEBUG);
1678
+ try {
1679
+ const data = await fs.promises.readFile(path, "utf8");
1680
+ printLog(data, LogLevel.DEBUG);
1688
1681
  }
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).
1682
+ catch (readError) {
1683
+ printLog(readError, LogLevel.ERROR);
1684
+ }
1685
+ };
1686
+ const completeVerification = async () => {
1687
+ // Stop verification task timer.
1688
+ printLog("Completing verification", LogLevel.DEBUG);
1689
+ verificationTaskTimer.stop();
1690
+ verifyCloudFunctionExecutionTime = verificationTaskTimer.ms();
1701
1691
  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);
1692
+ // Create temporary path.
1693
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.log`);
1694
+ await sleep(1000); // wait 1s for file creation.
1695
+ // Download from bucket.
1696
+ // nb. the transcript MUST be uploaded from the VM by verification commands.
1697
+ await downloadArtifactFromS3Bucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath);
1698
+ // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
1699
+ const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8");
1700
+ if (content.includes("ZKey Ok!"))
1701
+ isContributionValid = true;
1702
+ // If the contribution is valid, then format and store the trascript.
1703
+ if (isContributionValid) {
1704
+ // eslint-disable-next-line no-control-regex
1705
+ const updated = content.replace(/\x1b[[0-9;]*m/g, "");
1706
+ fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated);
1707
+ }
1708
+ }
1709
+ printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG);
1710
+ // Create a new contribution document.
1711
+ const contributionDoc = await firestore
1712
+ .collection(actions.getContributionsCollectionPath(ceremonyId, circuitId))
1713
+ .doc()
1714
+ .get();
1715
+ // Step (1.A.4).
1716
+ if (isContributionValid) {
1717
+ // Sleep ~3 seconds to wait for verification transcription.
1718
+ await sleep(3000);
1719
+ // Step (1.A.4.A.1).
1720
+ if (isUsingVM) {
1721
+ // Retrieve the contribution hash from the command output.
1722
+ lastZkeyBlake2bHash = await actions.retrieveCommandOutput(ssm, vmInstanceId, commandId);
1723
+ const hashRegex = /[a-fA-F0-9]{64}/;
1724
+ const match = lastZkeyBlake2bHash.match(hashRegex);
1725
+ lastZkeyBlake2bHash = match.at(0);
1726
+ // re upload the formatted verification transcript
1727
+ await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1728
+ }
1729
+ else {
1730
+ // Upload verification transcript.
1731
+ /// nb. do not use multi-part upload here due to small file size.
1732
+ await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1733
+ }
1734
+ // Compute verification transcript hash.
1735
+ transcriptBlake2bHash = await actions.blake512FromPath(verificationTranscriptTemporaryLocalPath);
1736
+ // Free resources by unlinking transcript temporary file.
1737
+ fs.unlinkSync(verificationTranscriptTemporaryLocalPath);
1738
+ // Filter participant contributions to find the data related to the one verified.
1739
+ const participantContributions = contributions.filter((contribution) => !!contribution.hash && !!contribution.computationTime && !contribution.doc);
1740
+ /// @dev (there must be only one contribution with an empty 'doc' field).
1741
+ if (participantContributions.length !== 1)
1742
+ logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA);
1743
+ // Get contribution computation time.
1744
+ contributionComputationTime = contributions.at(0).computationTime;
1745
+ // Step (1.A.4.A.2).
1746
+ batch.create(contributionDoc.ref, {
1747
+ participantId: participantDoc.id,
1748
+ contributionComputationTime,
1749
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
1750
+ zkeyIndex: isFinalizing ? actions.finalContributionIndex : lastZkeyIndex,
1751
+ files: {
1752
+ transcriptFilename: verificationTranscriptCompleteFilename,
1753
+ lastZkeyFilename,
1754
+ transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
1755
+ lastZkeyStoragePath,
1756
+ transcriptBlake2bHash,
1757
+ lastZkeyBlake2bHash
1758
+ },
1759
+ verificationSoftware: {
1760
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1761
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1762
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1763
+ },
1764
+ valid: isContributionValid,
1765
+ lastUpdated: getCurrentServerTimestampInMillis()
1766
+ });
1767
+ verifyContributionTimer.stop();
1768
+ verifyCloudFunctionTime = verifyContributionTimer.ms();
1709
1769
  }
1710
1770
  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);
1771
+ // Step (1.A.4.B).
1772
+ // Free-up storage by deleting invalid contribution.
1773
+ await deleteObject(bucketName, lastZkeyStoragePath);
1774
+ // Step (1.A.4.B.1).
1775
+ batch.create(contributionDoc.ref, {
1776
+ participantId: participantDoc.id,
1777
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
1778
+ zkeyIndex: isFinalizing ? actions.finalContributionIndex : lastZkeyIndex,
1779
+ verificationSoftware: {
1780
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1781
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1782
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1783
+ },
1784
+ valid: isContributionValid,
1785
+ lastUpdated: getCurrentServerTimestampInMillis()
1786
+ });
1714
1787
  }
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
1788
+ // Stop VM instance
1789
+ if (isUsingVM) {
1790
+ // using try and catch as the VM stopping function can throw
1791
+ // however we want to continue without stopping as the
1792
+ // verification was valid, and inform the coordinator
1793
+ try {
1794
+ await actions.stopEC2Instance(ec2, vmInstanceId);
1795
+ }
1796
+ catch (error) {
1797
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1798
+ }
1799
+ }
1800
+ // Step (1.A.4.C)
1801
+ if (!isFinalizing) {
1802
+ // Step (1.A.4.C.1)
1803
+ // Compute new average contribution/verification time.
1804
+ fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt);
1805
+ const newAvgContributionComputationTime = avgContributionComputationTime > 0
1806
+ ? (avgContributionComputationTime + contributionComputationTime) / 2
1807
+ : contributionComputationTime;
1808
+ const newAvgFullContributionTime = avgFullContributionTime > 0
1809
+ ? (avgFullContributionTime + fullContributionTime) / 2
1810
+ : fullContributionTime;
1811
+ const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1812
+ ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1813
+ : verifyCloudFunctionTime;
1814
+ // Prepare tx to update circuit average contribution/verification time.
1815
+ const updatedCircuitDoc = await getDocumentById(actions.getCircuitsCollectionPath(ceremonyId), circuitId);
1816
+ const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1817
+ /// @dev this must happen only for valid contributions.
1818
+ batch.update(circuitDoc.ref, {
1819
+ avgTimings: {
1820
+ contributionComputation: isContributionValid
1821
+ ? newAvgContributionComputationTime
1822
+ : avgContributionComputationTime,
1823
+ fullContribution: isContributionValid
1824
+ ? newAvgFullContributionTime
1825
+ : avgFullContributionTime,
1826
+ verifyCloudFunction: isContributionValid
1827
+ ? newAvgVerifyCloudFunctionTime
1828
+ : avgVerifyCloudFunctionTime
1829
+ },
1830
+ waitingQueue: {
1831
+ ...updatedWaitingQueue,
1832
+ completedContributions: isContributionValid
1833
+ ? completedContributions + 1
1834
+ : completedContributions,
1835
+ failedContributions: isContributionValid ? failedContributions : failedContributions + 1
1836
+ },
1837
+ lastUpdated: getCurrentServerTimestampInMillis()
1838
+ });
1839
+ }
1840
+ // Step (2).
1841
+ await batch.commit();
1842
+ 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.INFO);
1843
+ };
1844
+ // Step (1).
1845
+ if (isContributing || isFinalizing) {
1846
+ // Prepare timer.
1847
+ verificationTaskTimer.start();
1848
+ // Step (1.A.3.0).
1849
+ if (isUsingVM) {
1850
+ printLog(`Starting the VM mechanism`, LogLevel.DEBUG);
1851
+ // Prepare for VM execution.
1852
+ let isVMRunning = false; // true when the VM is up, otherwise false.
1853
+ // Step (1.A.3.1).
1854
+ await actions.startEC2Instance(ec2, vmInstanceId);
1855
+ await sleep(60000); // nb. wait for VM startup (1 mins + retry).
1856
+ // Check if the startup is running.
1857
+ isVMRunning = await checkIfVMRunning(ec2, vmInstanceId);
1858
+ printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG);
1859
+ // Step (1.A.3.2).
1860
+ // Prepare.
1861
+ const verificationCommand = actions.vmContributionVerificationCommand(bucketName, lastZkeyStoragePath, verificationTranscriptStoragePathAndFilename);
1862
+ // Run.
1863
+ commandId = await actions.runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1864
+ printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1865
+ // Step (1.A.3.3).
1866
+ return await waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1867
+ .then(async () => {
1868
+ // Command execution successfully completed.
1869
+ printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
1870
+ await completeVerification();
1871
+ })
1872
+ .catch((error) => {
1873
+ // Command execution aborted.
1874
+ printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.WARN);
1875
+ logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1876
+ });
1877
+ }
1878
+ // CF approach.
1879
+ printLog(`CF mechanism`, LogLevel.DEBUG);
1880
+ const potStoragePath = actions.getPotStorageFilePath(files.potFilename);
1881
+ const firstZkeyStoragePath = actions.getZkeyStorageFilePath(prefix, `${prefix}_${actions.genesisZkeyIndex}.zkey`);
1882
+ printLog(`pot file: ${potStoragePath}`, LogLevel.DEBUG);
1883
+ printLog(`zkey file: ${firstZkeyStoragePath}`, LogLevel.DEBUG);
1884
+ // Prepare temporary file paths.
1885
+ // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1886
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1887
+ const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1888
+ const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1889
+ const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1890
+ printLog(`pot file: ${potTempFilePath}`, LogLevel.DEBUG);
1891
+ printLog(`firstZkey file: ${firstZkeyTempFilePath}`, LogLevel.DEBUG);
1892
+ printLog(`last zkey file: ${lastZkeyTempFilePath}`, LogLevel.DEBUG);
1893
+ // Create and populate transcript.
1894
+ const transcriptLogger = actions.createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1895
+ transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1896
+ // Step (1.A.2).
1897
+ await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1898
+ await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1899
+ await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1900
+ // Step (1.A.4).
1901
+ isContributionValid = await snarkjs.zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1902
+ await dumpLog(verificationTranscriptTemporaryLocalPath);
1903
+ // Compute contribution hash.
1904
+ lastZkeyBlake2bHash = await actions.blake512FromPath(lastZkeyTempFilePath);
1905
+ // Free resources by unlinking temporary folders.
1906
+ // Do not free-up verification transcript path here.
1774
1907
  try {
1775
- await actions.stopEC2Instance(ec2, vmInstanceId);
1908
+ fs.unlinkSync(potTempFilePath);
1909
+ fs.unlinkSync(firstZkeyTempFilePath);
1910
+ fs.unlinkSync(lastZkeyTempFilePath);
1776
1911
  }
1777
1912
  catch (error) {
1778
- printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1913
+ printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1779
1914
  }
1915
+ await completeVerification();
1780
1916
  }
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();
1917
+ return null;
1918
+ }
1919
+ catch (error) {
1920
+ logAndThrowError(makeError("unknown", error));
1921
+ return null;
1889
1922
  }
1890
1923
  });
1891
1924
  /**
@@ -1947,7 +1980,7 @@ const refreshParticipantAfterContributionVerification = functionsV1__namespace
1947
1980
  lastUpdated: getCurrentServerTimestampInMillis()
1948
1981
  });
1949
1982
  await batch.commit();
1950
- printLog(`Participant ${participantId} refreshed after contribution ${createdContribution.id} - The participant was finalizing the ceremony ${isFinalizing}`, LogLevel.DEBUG);
1983
+ printLog(`Participant ${participantId} refreshed after contribution ${createdContribution.id} - The participant was finalizing the ceremony? ${isFinalizing}`, LogLevel.INFO);
1951
1984
  });
1952
1985
  /**
1953
1986
  * Finalize the ceremony circuit.
@@ -2112,6 +2145,7 @@ const createBucket = functions__namespace
2112
2145
  // Connect to S3 client.
2113
2146
  const S3 = await getS3Client();
2114
2147
  try {
2148
+ printLog(`Creating AWS S3 bucket ${data.bucketName} ...`, LogLevel.LOG);
2115
2149
  // Try to get information about the bucket.
2116
2150
  await S3.send(new clientS3.HeadBucketCommand({ Bucket: data.bucketName }));
2117
2151
  // If the command succeeded, the bucket exists, throw an error.
@@ -2442,110 +2476,110 @@ const completeMultiPartUpload = functions__namespace
2442
2476
  }
2443
2477
  });
2444
2478
 
2445
- const VKEY_DATA = {
2446
- protocol: "groth16",
2447
- curve: "bn128",
2448
- nPublic: 3,
2449
- vk_alpha_1: [
2450
- "20491192805390485299153009773594534940189261866228447918068658471970481763042",
2451
- "9383485363053290200918347156157836566562967994039712273449902621266178545958",
2452
- "1"
2453
- ],
2454
- vk_beta_2: [
2455
- [
2456
- "6375614351688725206403948262868962793625744043794305715222011528459656738731",
2457
- "4252822878758300859123897981450591353533073413197771768651442665752259397132"
2458
- ],
2459
- [
2460
- "10505242626370262277552901082094356697409835680220590971873171140371331206856",
2461
- "21847035105528745403288232691147584728191162732299865338377159692350059136679"
2462
- ],
2463
- ["1", "0"]
2464
- ],
2465
- vk_gamma_2: [
2466
- [
2467
- "10857046999023057135944570762232829481370756359578518086990519993285655852781",
2468
- "11559732032986387107991004021392285783925812861821192530917403151452391805634"
2469
- ],
2470
- [
2471
- "8495653923123431417604973247489272438418190587263600148770280649306958101930",
2472
- "4082367875863433681332203403145435568316851327593401208105741076214120093531"
2479
+ dotenv.config();
2480
+ const { BANDADA_API_URL, BANDADA_GROUP_ID } = process.env;
2481
+ const bandadaApi = new apiSdk.ApiSdk(BANDADA_API_URL);
2482
+ const bandadaValidateProof = functions__namespace
2483
+ .region("europe-west1")
2484
+ .runWith({
2485
+ memory: "1GB"
2486
+ })
2487
+ .https.onCall(async (data) => {
2488
+ const VKEY_DATA = {
2489
+ protocol: "groth16",
2490
+ curve: "bn128",
2491
+ nPublic: 3,
2492
+ vk_alpha_1: [
2493
+ "20491192805390485299153009773594534940189261866228447918068658471970481763042",
2494
+ "9383485363053290200918347156157836566562967994039712273449902621266178545958",
2495
+ "1"
2473
2496
  ],
2474
- ["1", "0"]
2475
- ],
2476
- vk_delta_2: [
2477
- [
2478
- "3697618915467790705869942236922063775466274665053173890632463796679068973252",
2479
- "14948341351907992175709156460547989243732741534604949238422596319735704165658"
2497
+ vk_beta_2: [
2498
+ [
2499
+ "6375614351688725206403948262868962793625744043794305715222011528459656738731",
2500
+ "4252822878758300859123897981450591353533073413197771768651442665752259397132"
2501
+ ],
2502
+ [
2503
+ "10505242626370262277552901082094356697409835680220590971873171140371331206856",
2504
+ "21847035105528745403288232691147584728191162732299865338377159692350059136679"
2505
+ ],
2506
+ ["1", "0"]
2480
2507
  ],
2481
- [
2482
- "3028459181652799888716942141752307629938889957960373621898607910203491239368",
2483
- "11380736494786911280692284374675752681598754560757720296073023058533044108340"
2508
+ vk_gamma_2: [
2509
+ [
2510
+ "10857046999023057135944570762232829481370756359578518086990519993285655852781",
2511
+ "11559732032986387107991004021392285783925812861821192530917403151452391805634"
2512
+ ],
2513
+ [
2514
+ "8495653923123431417604973247489272438418190587263600148770280649306958101930",
2515
+ "4082367875863433681332203403145435568316851327593401208105741076214120093531"
2516
+ ],
2517
+ ["1", "0"]
2484
2518
  ],
2485
- ["1", "0"]
2486
- ],
2487
- vk_alphabeta_12: [
2488
- [
2519
+ vk_delta_2: [
2520
+ [
2521
+ "3697618915467790705869942236922063775466274665053173890632463796679068973252",
2522
+ "14948341351907992175709156460547989243732741534604949238422596319735704165658"
2523
+ ],
2489
2524
  [
2490
- "2029413683389138792403550203267699914886160938906632433982220835551125967885",
2491
- "21072700047562757817161031222997517981543347628379360635925549008442030252106"
2525
+ "3028459181652799888716942141752307629938889957960373621898607910203491239368",
2526
+ "11380736494786911280692284374675752681598754560757720296073023058533044108340"
2492
2527
  ],
2528
+ ["1", "0"]
2529
+ ],
2530
+ vk_alphabeta_12: [
2493
2531
  [
2494
- "5940354580057074848093997050200682056184807770593307860589430076672439820312",
2495
- "12156638873931618554171829126792193045421052652279363021382169897324752428276"
2532
+ [
2533
+ "2029413683389138792403550203267699914886160938906632433982220835551125967885",
2534
+ "21072700047562757817161031222997517981543347628379360635925549008442030252106"
2535
+ ],
2536
+ [
2537
+ "5940354580057074848093997050200682056184807770593307860589430076672439820312",
2538
+ "12156638873931618554171829126792193045421052652279363021382169897324752428276"
2539
+ ],
2540
+ [
2541
+ "7898200236362823042373859371574133993780991612861777490112507062703164551277",
2542
+ "7074218545237549455313236346927434013100842096812539264420499035217050630853"
2543
+ ]
2496
2544
  ],
2497
2545
  [
2498
- "7898200236362823042373859371574133993780991612861777490112507062703164551277",
2499
- "7074218545237549455313236346927434013100842096812539264420499035217050630853"
2546
+ [
2547
+ "7077479683546002997211712695946002074877511277312570035766170199895071832130",
2548
+ "10093483419865920389913245021038182291233451549023025229112148274109565435465"
2549
+ ],
2550
+ [
2551
+ "4595479056700221319381530156280926371456704509942304414423590385166031118820",
2552
+ "19831328484489333784475432780421641293929726139240675179672856274388269393268"
2553
+ ],
2554
+ [
2555
+ "11934129596455521040620786944827826205713621633706285934057045369193958244500",
2556
+ "8037395052364110730298837004334506829870972346962140206007064471173334027475"
2557
+ ]
2500
2558
  ]
2501
2559
  ],
2502
- [
2560
+ IC: [
2561
+ [
2562
+ "12951059800758687233303204819298121944551181861362200875212570257618182506154",
2563
+ "5751958719396509176593242305268064754837298673622815112953832050159760501392",
2564
+ "1"
2565
+ ],
2503
2566
  [
2504
- "7077479683546002997211712695946002074877511277312570035766170199895071832130",
2505
- "10093483419865920389913245021038182291233451549023025229112148274109565435465"
2567
+ "9561588427935871983444704959674198910445823619407211599507208879011862515257",
2568
+ "14576201570478094842467636169770180675293504492823217349086195663150934064643",
2569
+ "1"
2506
2570
  ],
2507
2571
  [
2508
- "4595479056700221319381530156280926371456704509942304414423590385166031118820",
2509
- "19831328484489333784475432780421641293929726139240675179672856274388269393268"
2572
+ "4811967233483727873912563574622036989372099129165459921963463310078093941559",
2573
+ "1874883809855039536107616044787862082553628089593740724610117059083415551067",
2574
+ "1"
2510
2575
  ],
2511
2576
  [
2512
- "11934129596455521040620786944827826205713621633706285934057045369193958244500",
2513
- "8037395052364110730298837004334506829870972346962140206007064471173334027475"
2577
+ "12252730267779308452229639835051322390696643456253768618882001876621526827161",
2578
+ "7899194018737016222260328309937800777948677569409898603827268776967707173231",
2579
+ "1"
2514
2580
  ]
2515
2581
  ]
2516
- ],
2517
- IC: [
2518
- [
2519
- "12951059800758687233303204819298121944551181861362200875212570257618182506154",
2520
- "5751958719396509176593242305268064754837298673622815112953832050159760501392",
2521
- "1"
2522
- ],
2523
- [
2524
- "9561588427935871983444704959674198910445823619407211599507208879011862515257",
2525
- "14576201570478094842467636169770180675293504492823217349086195663150934064643",
2526
- "1"
2527
- ],
2528
- [
2529
- "4811967233483727873912563574622036989372099129165459921963463310078093941559",
2530
- "1874883809855039536107616044787862082553628089593740724610117059083415551067",
2531
- "1"
2532
- ],
2533
- [
2534
- "12252730267779308452229639835051322390696643456253768618882001876621526827161",
2535
- "7899194018737016222260328309937800777948677569409898603827268776967707173231",
2536
- "1"
2537
- ]
2538
- ]
2539
- };
2540
- dotenv.config();
2541
- const { BANDADA_API_URL, BANDADA_GROUP_ID } = process.env;
2542
- const bandadaApi = new apiSdk.ApiSdk(BANDADA_API_URL);
2543
- const bandadaValidateProof = functions__namespace
2544
- .region("europe-west1")
2545
- .runWith({
2546
- memory: "512MB"
2547
- })
2548
- .https.onCall(async (data) => {
2582
+ };
2549
2583
  if (!BANDADA_GROUP_ID)
2550
2584
  throw new Error("BANDADA_GROUP_ID is not defined in .env");
2551
2585
  const { proof, publicSignals } = data;
@@ -2706,7 +2740,7 @@ const checkAndRemoveBlockingContributor = functions__namespace
2706
2740
  // Case (A).
2707
2741
  if (!currentContributor)
2708
2742
  // Do not use `logAndThrowError` method to avoid the function to exit before checking every ceremony.
2709
- printLog(`No current contributor for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.WARN);
2743
+ printLog(`No current contributor for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.DEBUG);
2710
2744
  else if (avgFullContribution === 0 &&
2711
2745
  avgContributionComputation === 0 &&
2712
2746
  avgVerifyCloudFunction === 0 &&
@@ -2732,7 +2766,7 @@ const checkAndRemoveBlockingContributor = functions__namespace
2732
2766
  ? Number(contributionStartedAt) +
2733
2767
  Number(avgFullContribution) +
2734
2768
  Number(timeoutDynamicThreshold)
2735
- : Number(contributionStartedAt) + Number(fixedTimeWindow) * 60000; // * 60000 = convert minutes to millis.
2769
+ : (Number(contributionStartedAt) + Number(fixedTimeWindow)) * 60000; // * 60000 = convert minutes to millis.
2736
2770
  // Case (D).
2737
2771
  const timeoutExpirationDateInMsForVerificationCloudFunction = contributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */ &&
2738
2772
  !!verificationStartedAt
@@ -2750,11 +2784,11 @@ const checkAndRemoveBlockingContributor = functions__namespace
2750
2784
  timeoutExpirationDateInMsForVerificationCloudFunction < currentServerTimestamp &&
2751
2785
  contributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */)
2752
2786
  timeoutType = "BLOCKING_CLOUD_FUNCTION" /* TimeoutType.BLOCKING_CLOUD_FUNCTION */;
2753
- printLog(`${timeoutType} detected for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.DEBUG);
2754
2787
  if (!timeoutType)
2755
2788
  // Do not use `logAndThrowError` method to avoid the function to exit before checking every ceremony.
2756
- printLog(`No timeout for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.WARN);
2789
+ printLog(`No timeout for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.DEBUG);
2757
2790
  else {
2791
+ printLog(`${timeoutType} detected for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.WARN);
2758
2792
  // Case (E).
2759
2793
  let nextCurrentContributorId = "";
2760
2794
  // Prepare Firestore batch of txs.
@@ -2805,7 +2839,7 @@ const checkAndRemoveBlockingContributor = functions__namespace
2805
2839
  });
2806
2840
  // Send atomic update for Firestore.
2807
2841
  await batch.commit();
2808
- printLog(`The contributor ${participant.id} has been identified as potential blocking contributor. A timeout of type ${timeoutType} has been triggered w/ a penalty of ${timeoutPenaltyInMs} ms`, LogLevel.DEBUG);
2842
+ printLog(`The contributor ${participant.id} has been identified as potential blocking contributor. A timeout of type ${timeoutType} has been triggered w/ a penalty of ${timeoutPenaltyInMs} ms`, LogLevel.WARN);
2809
2843
  }
2810
2844
  }
2811
2845
  }