@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
@@ -9,7 +9,7 @@
9
9
  import admin from 'firebase-admin';
10
10
  import * as functions from 'firebase-functions';
11
11
  import dotenv from 'dotenv';
12
- import { getCircuitsCollectionPath, getTimeoutsCollectionPath, commonTerms, finalContributionIndex, getContributionsCollectionPath, githubReputation, getBucketName, vmBootstrapCommand, vmDependenciesAndCacheArtifactsCommand, vmBootstrapScriptFilename, computeDiskSizeForVM, createEC2Instance, getParticipantsCollectionPath, terminateEC2Instance, formatZkeyIndex, getTranscriptStorageFilePath, getZkeyStorageFilePath, startEC2Instance, vmContributionVerificationCommand, runCommandUsingSSM, getPotStorageFilePath, genesisZkeyIndex, createCustomLoggerForFile, blake512FromPath, getVerificationKeyStorageFilePath, getVerifierContractStorageFilePath, computeSHA256ToHex, checkIfRunning, retrieveCommandOutput, stopEC2Instance, verificationKeyAcronym, verifierSmartContractAcronym, retrieveCommandStatus } from '@p0tion/actions';
12
+ import { getCircuitsCollectionPath, getTimeoutsCollectionPath, commonTerms, finalContributionIndex, getContributionsCollectionPath, githubReputation, getBucketName, vmBootstrapCommand, vmDependenciesAndCacheArtifactsCommand, vmBootstrapScriptFilename, computeDiskSizeForVM, createEC2Instance, getParticipantsCollectionPath, terminateEC2Instance, formatZkeyIndex, getTranscriptStorageFilePath, getZkeyStorageFilePath, retrieveCommandOutput, blake512FromPath, stopEC2Instance, startEC2Instance, vmContributionVerificationCommand, runCommandUsingSSM, getPotStorageFilePath, genesisZkeyIndex, createCustomLoggerForFile, getVerificationKeyStorageFilePath, getVerifierContractStorageFilePath, computeSHA256ToHex, checkIfRunning, verificationKeyAcronym, verifierSmartContractAcronym, retrieveCommandStatus } from '@p0tion/actions';
13
13
  import { encode } from 'html-entities';
14
14
  import { Timestamp, FieldValue } from 'firebase-admin/firestore';
15
15
  import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadBucketCommand, CreateBucketCommand, PutPublicAccessBlockCommand, PutBucketCorsCommand, HeadObjectCommand, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3';
@@ -125,7 +125,8 @@ const SPECIFIC_ERRORS = {
125
125
  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."),
126
126
  SE_VM_CANCELLED_COMMAND_EXECUTION: makeError("cancelled", "VM command execution has been cancelled", "Please, contact the coordinator if this error persists."),
127
127
  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."),
128
- 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.")
128
+ 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."),
129
+ 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.")
129
130
  };
130
131
  /**
131
132
  * A set of common errors.
@@ -746,7 +747,9 @@ const setupCeremony = functions
746
747
  // The VM unique identifier (if any).
747
748
  let vmInstanceId = "";
748
749
  // Get a new circuit document.
749
- const circuitDoc = await firestore.collection(getCircuitsCollectionPath(ceremonyDoc.ref.id)).doc().get();
750
+ const ccp = getCircuitsCollectionPath(ceremonyDoc.ref.id);
751
+ printLog(`CircuitsCollectionPath = ${ccp}`, LogLevel.DEBUG);
752
+ const circuitDoc = await firestore.collection(ccp).doc().get();
750
753
  // Check if using the VM approach for contribution verification.
751
754
  if (circuit.verification.cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */) {
752
755
  // VM command to be run at the startup.
@@ -783,12 +786,14 @@ const setupCeremony = functions
783
786
  }
784
787
  // Encode circuit data.
785
788
  const encodedCircuit = htmlEncodeCircuitData(circuit);
789
+ printLog(`writing circuit data...`, LogLevel.DEBUG);
786
790
  // Prepare tx to write circuit data.
787
791
  batch.create(circuitDoc.ref, {
788
792
  ...encodedCircuit,
789
793
  lastUpdated: getCurrentServerTimestampInMillis()
790
794
  });
791
795
  }
796
+ printLog(`Done handling circuits...`, LogLevel.DEBUG);
792
797
  // Send txs in a batch (to avoid race conditions).
793
798
  await batch.commit();
794
799
  printLog(`Setup completed for ceremony ${ceremonyDoc.id}`, LogLevel.DEBUG);
@@ -801,7 +806,7 @@ const setupCeremony = functions
801
806
  const initEmptyWaitingQueueForCircuit = functions
802
807
  .region("europe-west1")
803
808
  .runWith({
804
- memory: "512MB"
809
+ memory: "1GB"
805
810
  })
806
811
  .firestore.document(`/${commonTerms.collections.ceremonies.name}/{ceremony}/${commonTerms.collections.circuits.name}/{circuit}`)
807
812
  .onCreate(async (doc) => {
@@ -833,7 +838,7 @@ const initEmptyWaitingQueueForCircuit = functions
833
838
  const finalizeCeremony = functions
834
839
  .region("europe-west1")
835
840
  .runWith({
836
- memory: "512MB"
841
+ memory: "1GB"
837
842
  })
838
843
  .https.onCall(async (data, context) => {
839
844
  if (!context.auth || !context.auth.token.coordinator)
@@ -1310,7 +1315,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1310
1315
  if (isSingleParticipantCoordination) {
1311
1316
  // Scenario (A).
1312
1317
  if (emptyWaitingQueue) {
1313
- printLog(`Coordinate - executing scenario A - emptyWaitingQueue`, LogLevel.DEBUG);
1318
+ printLog(`Coordinate - executing scenario A - emptyWaitingQueue`, LogLevel.INFO);
1314
1319
  // Update.
1315
1320
  newCurrentContributorId = participant.id;
1316
1321
  newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
@@ -1319,14 +1324,14 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1319
1324
  }
1320
1325
  // Scenario (A).
1321
1326
  else if (participantResumingAfterTimeoutExpiration) {
1322
- printLog(`Coordinate - executing scenario A - single - participantResumingAfterTimeoutExpiration`, LogLevel.DEBUG);
1327
+ printLog(`Coordinate - executing scenario A - single - participantResumingAfterTimeoutExpiration`, LogLevel.INFO);
1323
1328
  newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1324
1329
  newContributionStep = "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */;
1325
1330
  newCurrentContributorId = participant.id;
1326
1331
  }
1327
1332
  // Scenario (B).
1328
1333
  else if (participantIsNotCurrentContributor) {
1329
- printLog(`Coordinate - executing scenario B - single - participantIsNotCurrentContributor`, LogLevel.DEBUG);
1334
+ printLog(`Coordinate - executing scenario B - single - participantIsNotCurrentContributor`, LogLevel.INFO);
1330
1335
  newCurrentContributorId = currentContributor;
1331
1336
  newParticipantStatus = "WAITING" /* ParticipantStatus.WAITING */;
1332
1337
  newContributors.push(participant.id);
@@ -1345,7 +1350,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1345
1350
  });
1346
1351
  }
1347
1352
  else if (participantIsCurrentContributor && participantCompletedOneOrAllContributions && !!ceremonyId) {
1348
- printLog(`Coordinate - executing scenario C - multi - participantIsCurrentContributor && participantCompletedOneOrAllContributions`, LogLevel.DEBUG);
1353
+ printLog(`Coordinate - executing scenario C - multi - participantIsCurrentContributor && participantCompletedOneOrAllContributions`, LogLevel.INFO);
1349
1354
  newParticipantStatus = "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1350
1355
  newContributionStep = "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */;
1351
1356
  // Remove from waiting queue of circuit X.
@@ -1363,7 +1368,7 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1363
1368
  contributionStartedAt: getCurrentServerTimestampInMillis(),
1364
1369
  lastUpdated: getCurrentServerTimestampInMillis()
1365
1370
  });
1366
- printLog(`Participant ${newCurrentContributorId} is the new current contributor for circuit ${circuit.id}`, LogLevel.DEBUG);
1371
+ printLog(`Participant ${newCurrentContributorId} is the new current contributor for circuit ${circuit.id}`, LogLevel.INFO);
1367
1372
  }
1368
1373
  }
1369
1374
  // Prepare tx - must be done for all Scenarios.
@@ -1440,8 +1445,8 @@ const waitForVMCommandExecution = (ssm, vmInstanceId, commandId) => new Promise(
1440
1445
  try {
1441
1446
  await stopEC2Instance(ec2, vmInstanceId);
1442
1447
  }
1443
- catch (error) {
1444
- printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1448
+ catch (stopError) {
1449
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${stopError}`, LogLevel.WARN);
1445
1450
  }
1446
1451
  if (!error.toString().includes(commandId))
1447
1452
  logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
@@ -1489,8 +1494,8 @@ const coordinateCeremonyParticipant = functionsV1
1489
1494
  // Extract data.
1490
1495
  const { contributionProgress: prevContributionProgress, status: prevStatus, contributionStep: prevContributionStep } = exParticipant.data();
1491
1496
  const { contributionProgress: changedContributionProgress, status: changedStatus, contributionStep: changedContributionStep } = changedParticipant.data();
1492
- printLog(`Coordinate participant ${exParticipant.id} for ceremony ${ceremonyId}`, LogLevel.DEBUG);
1493
- printLog(`Participant status: ${prevStatus} => ${changedStatus} - Participant contribution step: ${prevContributionStep} => ${changedContributionStep}`, LogLevel.DEBUG);
1497
+ printLog(`Coordinate participant ${exParticipant.id} for ceremony ${ceremonyId}`, LogLevel.INFO);
1498
+ printLog(`Participant status: ${prevStatus} => ${changedStatus} - Participant contribution step: ${prevContributionStep} => ${changedContributionStep}`, LogLevel.INFO);
1494
1499
  // Define pre-conditions.
1495
1500
  const participantReadyToContribute = changedStatus === "READY" /* ParticipantStatus.READY */;
1496
1501
  const participantReadyForFirstContribution = participantReadyToContribute && prevContributionProgress === 0;
@@ -1500,8 +1505,8 @@ const coordinateCeremonyParticipant = functionsV1
1500
1505
  prevContributionProgress !== 0;
1501
1506
  const participantCompletedEveryCircuitContribution = changedStatus === "DONE" /* ParticipantStatus.DONE */ && prevStatus !== "DONE" /* ParticipantStatus.DONE */;
1502
1507
  const participantCompletedContribution = prevContributionProgress === changedContributionProgress &&
1503
- prevStatus === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */ &&
1504
- prevContributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */ &&
1508
+ (prevStatus === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */ ||
1509
+ prevContributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */) &&
1505
1510
  changedStatus === "CONTRIBUTED" /* ParticipantStatus.CONTRIBUTED */ &&
1506
1511
  changedContributionStep === "COMPLETED" /* ParticipantContributionStep.COMPLETED */;
1507
1512
  // Step (2).
@@ -1509,7 +1514,7 @@ const coordinateCeremonyParticipant = functionsV1
1509
1514
  participantResumingContributionAfterTimeout ||
1510
1515
  participantReadyForNextContribution) {
1511
1516
  // Step (2.A).
1512
- printLog(`Participant is ready for first contribution (${participantReadyForFirstContribution}) or for the next contribution (${participantReadyForNextContribution}) or is resuming after a timeout expiration (${participantResumingContributionAfterTimeout})`, LogLevel.DEBUG);
1517
+ printLog(`Participant is ready for first contribution (${participantReadyForFirstContribution}) or for the next contribution (${participantReadyForNextContribution}) or is resuming after a timeout expiration (${participantResumingContributionAfterTimeout})`, LogLevel.INFO);
1513
1518
  // Get the circuit.
1514
1519
  const circuit = await getCircuitDocumentByPosition(ceremonyId, changedContributionProgress);
1515
1520
  // Coordinate.
@@ -1518,7 +1523,7 @@ const coordinateCeremonyParticipant = functionsV1
1518
1523
  }
1519
1524
  else if (participantCompletedContribution || participantCompletedEveryCircuitContribution) {
1520
1525
  // Step (2.B).
1521
- printLog(`Participant completed a contribution (${participantCompletedContribution}) or every contribution for each circuit (${participantCompletedEveryCircuitContribution})`, LogLevel.DEBUG);
1526
+ printLog(`Participant completed a contribution (${participantCompletedContribution}) or every contribution for each circuit (${participantCompletedEveryCircuitContribution})`, LogLevel.INFO);
1522
1527
  // Get the circuit.
1523
1528
  const circuit = await getCircuitDocumentByPosition(ceremonyId, prevContributionProgress);
1524
1529
  // Coordinate.
@@ -1572,297 +1577,325 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
1572
1577
  * 1.A.4.C.1) If true, update circuit waiting for queue and average timings accordingly to contribution verification results;
1573
1578
  * 2) Send all updates atomically to the Firestore database.
1574
1579
  */
1575
- const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" }, async (request) => {
1576
- if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1577
- logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1578
- if (!request.data.ceremonyId ||
1579
- !request.data.circuitId ||
1580
- !request.data.contributorOrCoordinatorIdentifier ||
1581
- !request.data.bucketName)
1582
- logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA);
1583
- if (!process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
1584
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
1585
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1586
- logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
1587
- // Step (0).
1588
- // Prepare and start timer.
1589
- const verifyContributionTimer = new Timer({ label: commonTerms.cloudFunctionsNames.verifyContribution });
1590
- verifyContributionTimer.start();
1591
- // Get DB.
1592
- const firestore = admin.firestore();
1593
- // Prepare batch of txs.
1594
- const batch = firestore.batch();
1595
- // Extract data.
1596
- const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data;
1597
- const userId = request.auth?.uid;
1598
- // Look for the ceremony, circuit and participant document.
1599
- const ceremonyDoc = await getDocumentById(commonTerms.collections.ceremonies.name, ceremonyId);
1600
- const circuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId);
1601
- const participantDoc = await getDocumentById(getParticipantsCollectionPath(ceremonyId), userId);
1602
- if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
1603
- logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA);
1604
- // Extract documents data.
1605
- const { state } = ceremonyDoc.data();
1606
- const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data();
1607
- const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data();
1608
- const { completedContributions, failedContributions } = waitingQueue;
1609
- const { contributionComputation: avgContributionComputationTime, fullContribution: avgFullContributionTime, verifyCloudFunction: avgVerifyCloudFunctionTime } = avgTimings;
1610
- const { cfOrVm, vm } = verification;
1611
- // we might not have it if the circuit is not using VM.
1612
- let vmInstanceId = "";
1613
- if (vm)
1614
- vmInstanceId = vm.vmInstanceId;
1615
- // Define pre-conditions.
1616
- const isFinalizing = state === "CLOSED" /* CeremonyState.CLOSED */ && request.auth && request.auth.token.coordinator; // true only when the coordinator verifies the final contributions.
1617
- const isContributing = status === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1618
- const isUsingVM = cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */ && !!vmInstanceId;
1619
- // Prepare state.
1620
- let isContributionValid = false;
1621
- let verifyCloudFunctionExecutionTime = 0; // time spent while executing the verify contribution cloud function.
1622
- let verifyCloudFunctionTime = 0; // time spent while executing the core business logic of this cloud function.
1623
- let fullContributionTime = 0; // time spent while doing non-verification contributions tasks (download, compute, upload).
1624
- let contributionComputationTime = 0; // time spent while computing the contribution.
1625
- let lastZkeyBlake2bHash = ""; // the Blake2B hash of the last zKey.
1626
- let verificationTranscriptTemporaryLocalPath = ""; // the local temporary path for the verification transcript.
1627
- let transcriptBlake2bHash = ""; // the Blake2B hash of the verification transcript.
1628
- let commandId = ""; // the unique identifier of the VM command.
1629
- // Derive necessary data.
1630
- const lastZkeyIndex = formatZkeyIndex(completedContributions + 1);
1631
- const verificationTranscriptCompleteFilename = `${prefix}_${isFinalizing
1632
- ? `${contributorOrCoordinatorIdentifier}_${finalContributionIndex}_verification_transcript.log`
1633
- : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`}`;
1634
- const lastZkeyFilename = `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`;
1635
- // Prepare state for VM verification (if needed).
1636
- const ec2 = await createEC2Client();
1637
- const ssm = await createSSMClient();
1638
- // Step (1.A.1).
1639
- // Get storage paths.
1640
- const verificationTranscriptStoragePathAndFilename = getTranscriptStorageFilePath(prefix, verificationTranscriptCompleteFilename);
1641
- // the zKey storage path is required to be sent to the VM api
1642
- const lastZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`);
1643
- const verificationTaskTimer = new Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` });
1644
- const completeVerification = async () => {
1645
- // Stop verification task timer.
1646
- printLog("Completing verification", LogLevel.DEBUG);
1647
- verificationTaskTimer.stop();
1648
- verifyCloudFunctionExecutionTime = verificationTaskTimer.ms();
1649
- if (isUsingVM) {
1650
- // Create temporary path.
1651
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.log`);
1652
- await sleep(1000); // wait 1s for file creation.
1653
- // Download from bucket.
1654
- // nb. the transcript MUST be uploaded from the VM by verification commands.
1655
- await downloadArtifactFromS3Bucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath);
1656
- // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
1657
- const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8");
1658
- if (content.includes("ZKey Ok!"))
1659
- isContributionValid = true;
1660
- // If the contribution is valid, then format and store the trascript.
1661
- if (isContributionValid) {
1662
- // eslint-disable-next-line no-control-regex
1663
- const updated = content.replace(/\x1b[[0-9;]*m/g, "");
1664
- fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated);
1580
+ const verifycontribution = functionsV2.https.onCall({ memory: "32GiB", timeoutSeconds: 3600, region: "europe-west1", cpu: 8 }, async (request) => {
1581
+ try {
1582
+ if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1583
+ logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1584
+ if (!request.data.ceremonyId ||
1585
+ !request.data.circuitId ||
1586
+ !request.data.contributorOrCoordinatorIdentifier ||
1587
+ !request.data.bucketName)
1588
+ logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA);
1589
+ if (!process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
1590
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
1591
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1592
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
1593
+ const BUCKET_NAME_REGEX = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/;
1594
+ if (!BUCKET_NAME_REGEX.test(request.data.bucketName))
1595
+ logAndThrowError(SPECIFIC_ERRORS.WRONG_BUCKET_NAME);
1596
+ // Step (0).
1597
+ // Prepare and start timer.
1598
+ const verifyContributionTimer = new Timer({ label: commonTerms.cloudFunctionsNames.verifyContribution });
1599
+ verifyContributionTimer.start();
1600
+ // Get DB.
1601
+ const firestore = admin.firestore();
1602
+ // Prepare batch of txs.
1603
+ const batch = firestore.batch();
1604
+ // Extract data.
1605
+ const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data;
1606
+ const userId = request.auth?.uid;
1607
+ // Look for the ceremony, circuit and participant document.
1608
+ const ceremonyDoc = await getDocumentById(commonTerms.collections.ceremonies.name, ceremonyId);
1609
+ const circuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId);
1610
+ const participantDoc = await getDocumentById(getParticipantsCollectionPath(ceremonyId), userId);
1611
+ if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
1612
+ logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA);
1613
+ // Extract documents data.
1614
+ const { state } = ceremonyDoc.data();
1615
+ const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data();
1616
+ const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data();
1617
+ const { completedContributions, failedContributions } = waitingQueue;
1618
+ const { contributionComputation: avgContributionComputationTime, fullContribution: avgFullContributionTime, verifyCloudFunction: avgVerifyCloudFunctionTime } = avgTimings;
1619
+ const { cfOrVm, vm } = verification;
1620
+ // we might not have it if the circuit is not using VM.
1621
+ let vmInstanceId = "";
1622
+ if (vm)
1623
+ vmInstanceId = vm.vmInstanceId;
1624
+ // Define pre-conditions.
1625
+ const isFinalizing = state === "CLOSED" /* CeremonyState.CLOSED */ && request.auth && request.auth.token.coordinator; // true only when the coordinator verifies the final contributions.
1626
+ const isContributing = status === "CONTRIBUTING" /* ParticipantStatus.CONTRIBUTING */;
1627
+ const isUsingVM = cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */ && !!vmInstanceId;
1628
+ // Prepare state.
1629
+ let isContributionValid = false;
1630
+ let verifyCloudFunctionExecutionTime = 0; // time spent while executing the verify contribution cloud function.
1631
+ let verifyCloudFunctionTime = 0; // time spent while executing the core business logic of this cloud function.
1632
+ let fullContributionTime = 0; // time spent while doing non-verification contributions tasks (download, compute, upload).
1633
+ let contributionComputationTime = 0; // time spent while computing the contribution.
1634
+ let lastZkeyBlake2bHash = ""; // the Blake2B hash of the last zKey.
1635
+ let verificationTranscriptTemporaryLocalPath = ""; // the local temporary path for the verification transcript.
1636
+ let transcriptBlake2bHash = ""; // the Blake2B hash of the verification transcript.
1637
+ let commandId = ""; // the unique identifier of the VM command.
1638
+ // Derive necessary data.
1639
+ const lastZkeyIndex = formatZkeyIndex(completedContributions + 1);
1640
+ const verificationTranscriptCompleteFilename = `${prefix}_${isFinalizing
1641
+ ? `${contributorOrCoordinatorIdentifier}_${finalContributionIndex}_verification_transcript.log`
1642
+ : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`}`;
1643
+ const lastZkeyFilename = `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`;
1644
+ // Prepare state for VM verification (if needed).
1645
+ const ec2 = await createEC2Client();
1646
+ const ssm = await createSSMClient();
1647
+ // Step (1.A.1).
1648
+ // Get storage paths.
1649
+ const verificationTranscriptStoragePathAndFilename = getTranscriptStorageFilePath(prefix, verificationTranscriptCompleteFilename);
1650
+ // the zKey storage path is required to be sent to the VM api
1651
+ const lastZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`);
1652
+ const verificationTaskTimer = new Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` });
1653
+ const dumpLog = async (path) => {
1654
+ printLog(`transcript >>>>>>`, LogLevel.DEBUG);
1655
+ try {
1656
+ const data = await fs.promises.readFile(path, "utf8");
1657
+ printLog(data, LogLevel.DEBUG);
1665
1658
  }
1666
- }
1667
- printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG);
1668
- // Create a new contribution document.
1669
- const contributionDoc = await firestore
1670
- .collection(getContributionsCollectionPath(ceremonyId, circuitId))
1671
- .doc()
1672
- .get();
1673
- // Step (1.A.4).
1674
- if (isContributionValid) {
1675
- // Sleep ~3 seconds to wait for verification transcription.
1676
- await sleep(3000);
1677
- // Step (1.A.4.A.1).
1659
+ catch (readError) {
1660
+ printLog(readError, LogLevel.ERROR);
1661
+ }
1662
+ };
1663
+ const completeVerification = async () => {
1664
+ // Stop verification task timer.
1665
+ printLog("Completing verification", LogLevel.DEBUG);
1666
+ verificationTaskTimer.stop();
1667
+ verifyCloudFunctionExecutionTime = verificationTaskTimer.ms();
1678
1668
  if (isUsingVM) {
1679
- // Retrieve the contribution hash from the command output.
1680
- lastZkeyBlake2bHash = await retrieveCommandOutput(ssm, vmInstanceId, commandId);
1681
- const hashRegex = /[a-fA-F0-9]{64}/;
1682
- const match = lastZkeyBlake2bHash.match(hashRegex);
1683
- lastZkeyBlake2bHash = match.at(0);
1684
- // re upload the formatted verification transcript
1685
- await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1669
+ // Create temporary path.
1670
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.log`);
1671
+ await sleep(1000); // wait 1s for file creation.
1672
+ // Download from bucket.
1673
+ // nb. the transcript MUST be uploaded from the VM by verification commands.
1674
+ await downloadArtifactFromS3Bucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath);
1675
+ // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
1676
+ const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8");
1677
+ if (content.includes("ZKey Ok!"))
1678
+ isContributionValid = true;
1679
+ // If the contribution is valid, then format and store the trascript.
1680
+ if (isContributionValid) {
1681
+ // eslint-disable-next-line no-control-regex
1682
+ const updated = content.replace(/\x1b[[0-9;]*m/g, "");
1683
+ fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated);
1684
+ }
1685
+ }
1686
+ printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG);
1687
+ // Create a new contribution document.
1688
+ const contributionDoc = await firestore
1689
+ .collection(getContributionsCollectionPath(ceremonyId, circuitId))
1690
+ .doc()
1691
+ .get();
1692
+ // Step (1.A.4).
1693
+ if (isContributionValid) {
1694
+ // Sleep ~3 seconds to wait for verification transcription.
1695
+ await sleep(3000);
1696
+ // Step (1.A.4.A.1).
1697
+ if (isUsingVM) {
1698
+ // Retrieve the contribution hash from the command output.
1699
+ lastZkeyBlake2bHash = await retrieveCommandOutput(ssm, vmInstanceId, commandId);
1700
+ const hashRegex = /[a-fA-F0-9]{64}/;
1701
+ const match = lastZkeyBlake2bHash.match(hashRegex);
1702
+ lastZkeyBlake2bHash = match.at(0);
1703
+ // re upload the formatted verification transcript
1704
+ await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1705
+ }
1706
+ else {
1707
+ // Upload verification transcript.
1708
+ /// nb. do not use multi-part upload here due to small file size.
1709
+ await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1710
+ }
1711
+ // Compute verification transcript hash.
1712
+ transcriptBlake2bHash = await blake512FromPath(verificationTranscriptTemporaryLocalPath);
1713
+ // Free resources by unlinking transcript temporary file.
1714
+ fs.unlinkSync(verificationTranscriptTemporaryLocalPath);
1715
+ // Filter participant contributions to find the data related to the one verified.
1716
+ const participantContributions = contributions.filter((contribution) => !!contribution.hash && !!contribution.computationTime && !contribution.doc);
1717
+ /// @dev (there must be only one contribution with an empty 'doc' field).
1718
+ if (participantContributions.length !== 1)
1719
+ logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA);
1720
+ // Get contribution computation time.
1721
+ contributionComputationTime = contributions.at(0).computationTime;
1722
+ // Step (1.A.4.A.2).
1723
+ batch.create(contributionDoc.ref, {
1724
+ participantId: participantDoc.id,
1725
+ contributionComputationTime,
1726
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
1727
+ zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
1728
+ files: {
1729
+ transcriptFilename: verificationTranscriptCompleteFilename,
1730
+ lastZkeyFilename,
1731
+ transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
1732
+ lastZkeyStoragePath,
1733
+ transcriptBlake2bHash,
1734
+ lastZkeyBlake2bHash
1735
+ },
1736
+ verificationSoftware: {
1737
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1738
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1739
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1740
+ },
1741
+ valid: isContributionValid,
1742
+ lastUpdated: getCurrentServerTimestampInMillis()
1743
+ });
1744
+ verifyContributionTimer.stop();
1745
+ verifyCloudFunctionTime = verifyContributionTimer.ms();
1686
1746
  }
1687
1747
  else {
1688
- // Upload verification transcript.
1689
- /// nb. do not use multi-part upload here due to small file size.
1690
- await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1748
+ // Step (1.A.4.B).
1749
+ // Free-up storage by deleting invalid contribution.
1750
+ await deleteObject(bucketName, lastZkeyStoragePath);
1751
+ // Step (1.A.4.B.1).
1752
+ batch.create(contributionDoc.ref, {
1753
+ participantId: participantDoc.id,
1754
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
1755
+ zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
1756
+ verificationSoftware: {
1757
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1758
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1759
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1760
+ },
1761
+ valid: isContributionValid,
1762
+ lastUpdated: getCurrentServerTimestampInMillis()
1763
+ });
1691
1764
  }
1692
- // Compute verification transcript hash.
1693
- transcriptBlake2bHash = await blake512FromPath(verificationTranscriptTemporaryLocalPath);
1694
- // Free resources by unlinking transcript temporary file.
1695
- fs.unlinkSync(verificationTranscriptTemporaryLocalPath);
1696
- // Filter participant contributions to find the data related to the one verified.
1697
- const participantContributions = contributions.filter((contribution) => !!contribution.hash && !!contribution.computationTime && !contribution.doc);
1698
- /// @dev (there must be only one contribution with an empty 'doc' field).
1699
- if (participantContributions.length !== 1)
1700
- logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA);
1701
- // Get contribution computation time.
1702
- contributionComputationTime = contributions.at(0).computationTime;
1703
- // Step (1.A.4.A.2).
1704
- batch.create(contributionDoc.ref, {
1705
- participantId: participantDoc.id,
1706
- contributionComputationTime,
1707
- verificationComputationTime: verifyCloudFunctionExecutionTime,
1708
- zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
1709
- files: {
1710
- transcriptFilename: verificationTranscriptCompleteFilename,
1711
- lastZkeyFilename,
1712
- transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
1713
- lastZkeyStoragePath,
1714
- transcriptBlake2bHash,
1715
- lastZkeyBlake2bHash
1716
- },
1717
- verificationSoftware: {
1718
- name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1719
- version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1720
- commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1721
- },
1722
- valid: isContributionValid,
1723
- lastUpdated: getCurrentServerTimestampInMillis()
1724
- });
1725
- verifyContributionTimer.stop();
1726
- verifyCloudFunctionTime = verifyContributionTimer.ms();
1727
- }
1728
- else {
1729
- // Step (1.A.4.B).
1730
- // Free-up storage by deleting invalid contribution.
1731
- await deleteObject(bucketName, lastZkeyStoragePath);
1732
- // Step (1.A.4.B.1).
1733
- batch.create(contributionDoc.ref, {
1734
- participantId: participantDoc.id,
1735
- verificationComputationTime: verifyCloudFunctionExecutionTime,
1736
- zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
1737
- verificationSoftware: {
1738
- name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
1739
- version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
1740
- commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
1741
- },
1742
- valid: isContributionValid,
1743
- lastUpdated: getCurrentServerTimestampInMillis()
1744
- });
1745
- }
1746
- // Stop VM instance
1747
- if (isUsingVM) {
1748
- // using try and catch as the VM stopping function can throw
1749
- // however we want to continue without stopping as the
1750
- // verification was valid, and inform the coordinator
1765
+ // Stop VM instance
1766
+ if (isUsingVM) {
1767
+ // using try and catch as the VM stopping function can throw
1768
+ // however we want to continue without stopping as the
1769
+ // verification was valid, and inform the coordinator
1770
+ try {
1771
+ await stopEC2Instance(ec2, vmInstanceId);
1772
+ }
1773
+ catch (error) {
1774
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1775
+ }
1776
+ }
1777
+ // Step (1.A.4.C)
1778
+ if (!isFinalizing) {
1779
+ // Step (1.A.4.C.1)
1780
+ // Compute new average contribution/verification time.
1781
+ fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt);
1782
+ const newAvgContributionComputationTime = avgContributionComputationTime > 0
1783
+ ? (avgContributionComputationTime + contributionComputationTime) / 2
1784
+ : contributionComputationTime;
1785
+ const newAvgFullContributionTime = avgFullContributionTime > 0
1786
+ ? (avgFullContributionTime + fullContributionTime) / 2
1787
+ : fullContributionTime;
1788
+ const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1789
+ ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1790
+ : verifyCloudFunctionTime;
1791
+ // Prepare tx to update circuit average contribution/verification time.
1792
+ const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId);
1793
+ const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1794
+ /// @dev this must happen only for valid contributions.
1795
+ batch.update(circuitDoc.ref, {
1796
+ avgTimings: {
1797
+ contributionComputation: isContributionValid
1798
+ ? newAvgContributionComputationTime
1799
+ : avgContributionComputationTime,
1800
+ fullContribution: isContributionValid
1801
+ ? newAvgFullContributionTime
1802
+ : avgFullContributionTime,
1803
+ verifyCloudFunction: isContributionValid
1804
+ ? newAvgVerifyCloudFunctionTime
1805
+ : avgVerifyCloudFunctionTime
1806
+ },
1807
+ waitingQueue: {
1808
+ ...updatedWaitingQueue,
1809
+ completedContributions: isContributionValid
1810
+ ? completedContributions + 1
1811
+ : completedContributions,
1812
+ failedContributions: isContributionValid ? failedContributions : failedContributions + 1
1813
+ },
1814
+ lastUpdated: getCurrentServerTimestampInMillis()
1815
+ });
1816
+ }
1817
+ // Step (2).
1818
+ await batch.commit();
1819
+ printLog(`The contribution #${isFinalizing ? finalContributionIndex : lastZkeyIndex} of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${isContributionValid ? "valid" : "invalid"} for the participant ${participantDoc.id}`, LogLevel.INFO);
1820
+ };
1821
+ // Step (1).
1822
+ if (isContributing || isFinalizing) {
1823
+ // Prepare timer.
1824
+ verificationTaskTimer.start();
1825
+ // Step (1.A.3.0).
1826
+ if (isUsingVM) {
1827
+ printLog(`Starting the VM mechanism`, LogLevel.DEBUG);
1828
+ // Prepare for VM execution.
1829
+ let isVMRunning = false; // true when the VM is up, otherwise false.
1830
+ // Step (1.A.3.1).
1831
+ await startEC2Instance(ec2, vmInstanceId);
1832
+ await sleep(60000); // nb. wait for VM startup (1 mins + retry).
1833
+ // Check if the startup is running.
1834
+ isVMRunning = await checkIfVMRunning(ec2, vmInstanceId);
1835
+ printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG);
1836
+ // Step (1.A.3.2).
1837
+ // Prepare.
1838
+ const verificationCommand = vmContributionVerificationCommand(bucketName, lastZkeyStoragePath, verificationTranscriptStoragePathAndFilename);
1839
+ // Run.
1840
+ commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1841
+ printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1842
+ // Step (1.A.3.3).
1843
+ return await waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1844
+ .then(async () => {
1845
+ // Command execution successfully completed.
1846
+ printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
1847
+ await completeVerification();
1848
+ })
1849
+ .catch((error) => {
1850
+ // Command execution aborted.
1851
+ printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.WARN);
1852
+ logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1853
+ });
1854
+ }
1855
+ // CF approach.
1856
+ printLog(`CF mechanism`, LogLevel.DEBUG);
1857
+ const potStoragePath = getPotStorageFilePath(files.potFilename);
1858
+ const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`);
1859
+ printLog(`pot file: ${potStoragePath}`, LogLevel.DEBUG);
1860
+ printLog(`zkey file: ${firstZkeyStoragePath}`, LogLevel.DEBUG);
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
+ printLog(`pot file: ${potTempFilePath}`, LogLevel.DEBUG);
1868
+ printLog(`firstZkey file: ${firstZkeyTempFilePath}`, LogLevel.DEBUG);
1869
+ printLog(`last zkey file: ${lastZkeyTempFilePath}`, LogLevel.DEBUG);
1870
+ // Create and populate transcript.
1871
+ const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1872
+ transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1873
+ // Step (1.A.2).
1874
+ await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1875
+ await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1876
+ await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1877
+ // Step (1.A.4).
1878
+ isContributionValid = await zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1879
+ await dumpLog(verificationTranscriptTemporaryLocalPath);
1880
+ // Compute contribution hash.
1881
+ lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath);
1882
+ // Free resources by unlinking temporary folders.
1883
+ // Do not free-up verification transcript path here.
1751
1884
  try {
1752
- await stopEC2Instance(ec2, vmInstanceId);
1885
+ fs.unlinkSync(potTempFilePath);
1886
+ fs.unlinkSync(firstZkeyTempFilePath);
1887
+ fs.unlinkSync(lastZkeyTempFilePath);
1753
1888
  }
1754
1889
  catch (error) {
1755
- printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1890
+ printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1756
1891
  }
1892
+ await completeVerification();
1757
1893
  }
1758
- // Step (1.A.4.C)
1759
- if (!isFinalizing) {
1760
- // Step (1.A.4.C.1)
1761
- // Compute new average contribution/verification time.
1762
- fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt);
1763
- const newAvgContributionComputationTime = avgContributionComputationTime > 0
1764
- ? (avgContributionComputationTime + contributionComputationTime) / 2
1765
- : contributionComputationTime;
1766
- const newAvgFullContributionTime = avgFullContributionTime > 0
1767
- ? (avgFullContributionTime + fullContributionTime) / 2
1768
- : fullContributionTime;
1769
- const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1770
- ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1771
- : verifyCloudFunctionTime;
1772
- // Prepare tx to update circuit average contribution/verification time.
1773
- const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId);
1774
- const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1775
- /// @dev this must happen only for valid contributions.
1776
- batch.update(circuitDoc.ref, {
1777
- avgTimings: {
1778
- contributionComputation: isContributionValid
1779
- ? newAvgContributionComputationTime
1780
- : avgContributionComputationTime,
1781
- fullContribution: isContributionValid ? newAvgFullContributionTime : avgFullContributionTime,
1782
- verifyCloudFunction: isContributionValid
1783
- ? newAvgVerifyCloudFunctionTime
1784
- : avgVerifyCloudFunctionTime
1785
- },
1786
- waitingQueue: {
1787
- ...updatedWaitingQueue,
1788
- completedContributions: isContributionValid
1789
- ? completedContributions + 1
1790
- : completedContributions,
1791
- failedContributions: isContributionValid ? failedContributions : failedContributions + 1
1792
- },
1793
- lastUpdated: getCurrentServerTimestampInMillis()
1794
- });
1795
- }
1796
- // Step (2).
1797
- await batch.commit();
1798
- printLog(`The contribution #${isFinalizing ? finalContributionIndex : lastZkeyIndex} of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${isContributionValid ? "valid" : "invalid"} for the participant ${participantDoc.id}`, LogLevel.DEBUG);
1799
- };
1800
- // Step (1).
1801
- if (isContributing || isFinalizing) {
1802
- // Prepare timer.
1803
- verificationTaskTimer.start();
1804
- // Step (1.A.3.0).
1805
- if (isUsingVM) {
1806
- printLog(`Starting the VM mechanism`, LogLevel.DEBUG);
1807
- // Prepare for VM execution.
1808
- let isVMRunning = false; // true when the VM is up, otherwise false.
1809
- // Step (1.A.3.1).
1810
- await startEC2Instance(ec2, vmInstanceId);
1811
- await sleep(60000); // nb. wait for VM startup (1 mins + retry).
1812
- // Check if the startup is running.
1813
- isVMRunning = await checkIfVMRunning(ec2, vmInstanceId);
1814
- printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG);
1815
- // Step (1.A.3.2).
1816
- // Prepare.
1817
- const verificationCommand = vmContributionVerificationCommand(bucketName, lastZkeyStoragePath, verificationTranscriptStoragePathAndFilename);
1818
- // Run.
1819
- commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1820
- printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1821
- // Step (1.A.3.3).
1822
- return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1823
- .then(async () => {
1824
- // Command execution successfully completed.
1825
- printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
1826
- await completeVerification();
1827
- })
1828
- .catch((error) => {
1829
- // Command execution aborted.
1830
- printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.DEBUG);
1831
- logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1832
- });
1833
- }
1834
- // CF approach.
1835
- printLog(`CF mechanism`, LogLevel.DEBUG);
1836
- const potStoragePath = getPotStorageFilePath(files.potFilename);
1837
- const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`);
1838
- // Prepare temporary file paths.
1839
- // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1840
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1841
- const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1842
- const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1843
- const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1844
- // Create and populate transcript.
1845
- const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1846
- transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1847
- // Step (1.A.2).
1848
- await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1849
- await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1850
- await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1851
- // Step (1.A.4).
1852
- isContributionValid = await zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1853
- // Compute contribution hash.
1854
- lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath);
1855
- // Free resources by unlinking temporary folders.
1856
- // Do not free-up verification transcript path here.
1857
- try {
1858
- fs.unlinkSync(potTempFilePath);
1859
- fs.unlinkSync(firstZkeyTempFilePath);
1860
- fs.unlinkSync(lastZkeyTempFilePath);
1861
- }
1862
- catch (error) {
1863
- printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1864
- }
1865
- await completeVerification();
1894
+ return null;
1895
+ }
1896
+ catch (error) {
1897
+ logAndThrowError(makeError("unknown", error));
1898
+ return null;
1866
1899
  }
1867
1900
  });
1868
1901
  /**
@@ -1924,7 +1957,7 @@ const refreshParticipantAfterContributionVerification = functionsV1
1924
1957
  lastUpdated: getCurrentServerTimestampInMillis()
1925
1958
  });
1926
1959
  await batch.commit();
1927
- printLog(`Participant ${participantId} refreshed after contribution ${createdContribution.id} - The participant was finalizing the ceremony ${isFinalizing}`, LogLevel.DEBUG);
1960
+ printLog(`Participant ${participantId} refreshed after contribution ${createdContribution.id} - The participant was finalizing the ceremony? ${isFinalizing}`, LogLevel.INFO);
1928
1961
  });
1929
1962
  /**
1930
1963
  * Finalize the ceremony circuit.
@@ -2089,6 +2122,7 @@ const createBucket = functions
2089
2122
  // Connect to S3 client.
2090
2123
  const S3 = await getS3Client();
2091
2124
  try {
2125
+ printLog(`Creating AWS S3 bucket ${data.bucketName} ...`, LogLevel.LOG);
2092
2126
  // Try to get information about the bucket.
2093
2127
  await S3.send(new HeadBucketCommand({ Bucket: data.bucketName }));
2094
2128
  // If the command succeeded, the bucket exists, throw an error.
@@ -2419,110 +2453,110 @@ const completeMultiPartUpload = functions
2419
2453
  }
2420
2454
  });
2421
2455
 
2422
- const VKEY_DATA = {
2423
- protocol: "groth16",
2424
- curve: "bn128",
2425
- nPublic: 3,
2426
- vk_alpha_1: [
2427
- "20491192805390485299153009773594534940189261866228447918068658471970481763042",
2428
- "9383485363053290200918347156157836566562967994039712273449902621266178545958",
2429
- "1"
2430
- ],
2431
- vk_beta_2: [
2432
- [
2433
- "6375614351688725206403948262868962793625744043794305715222011528459656738731",
2434
- "4252822878758300859123897981450591353533073413197771768651442665752259397132"
2435
- ],
2436
- [
2437
- "10505242626370262277552901082094356697409835680220590971873171140371331206856",
2438
- "21847035105528745403288232691147584728191162732299865338377159692350059136679"
2439
- ],
2440
- ["1", "0"]
2441
- ],
2442
- vk_gamma_2: [
2443
- [
2444
- "10857046999023057135944570762232829481370756359578518086990519993285655852781",
2445
- "11559732032986387107991004021392285783925812861821192530917403151452391805634"
2446
- ],
2447
- [
2448
- "8495653923123431417604973247489272438418190587263600148770280649306958101930",
2449
- "4082367875863433681332203403145435568316851327593401208105741076214120093531"
2456
+ dotenv.config();
2457
+ const { BANDADA_API_URL, BANDADA_GROUP_ID } = process.env;
2458
+ const bandadaApi = new ApiSdk(BANDADA_API_URL);
2459
+ const bandadaValidateProof = functions
2460
+ .region("europe-west1")
2461
+ .runWith({
2462
+ memory: "1GB"
2463
+ })
2464
+ .https.onCall(async (data) => {
2465
+ const VKEY_DATA = {
2466
+ protocol: "groth16",
2467
+ curve: "bn128",
2468
+ nPublic: 3,
2469
+ vk_alpha_1: [
2470
+ "20491192805390485299153009773594534940189261866228447918068658471970481763042",
2471
+ "9383485363053290200918347156157836566562967994039712273449902621266178545958",
2472
+ "1"
2450
2473
  ],
2451
- ["1", "0"]
2452
- ],
2453
- vk_delta_2: [
2454
- [
2455
- "3697618915467790705869942236922063775466274665053173890632463796679068973252",
2456
- "14948341351907992175709156460547989243732741534604949238422596319735704165658"
2474
+ vk_beta_2: [
2475
+ [
2476
+ "6375614351688725206403948262868962793625744043794305715222011528459656738731",
2477
+ "4252822878758300859123897981450591353533073413197771768651442665752259397132"
2478
+ ],
2479
+ [
2480
+ "10505242626370262277552901082094356697409835680220590971873171140371331206856",
2481
+ "21847035105528745403288232691147584728191162732299865338377159692350059136679"
2482
+ ],
2483
+ ["1", "0"]
2457
2484
  ],
2458
- [
2459
- "3028459181652799888716942141752307629938889957960373621898607910203491239368",
2460
- "11380736494786911280692284374675752681598754560757720296073023058533044108340"
2485
+ vk_gamma_2: [
2486
+ [
2487
+ "10857046999023057135944570762232829481370756359578518086990519993285655852781",
2488
+ "11559732032986387107991004021392285783925812861821192530917403151452391805634"
2489
+ ],
2490
+ [
2491
+ "8495653923123431417604973247489272438418190587263600148770280649306958101930",
2492
+ "4082367875863433681332203403145435568316851327593401208105741076214120093531"
2493
+ ],
2494
+ ["1", "0"]
2461
2495
  ],
2462
- ["1", "0"]
2463
- ],
2464
- vk_alphabeta_12: [
2465
- [
2496
+ vk_delta_2: [
2497
+ [
2498
+ "3697618915467790705869942236922063775466274665053173890632463796679068973252",
2499
+ "14948341351907992175709156460547989243732741534604949238422596319735704165658"
2500
+ ],
2466
2501
  [
2467
- "2029413683389138792403550203267699914886160938906632433982220835551125967885",
2468
- "21072700047562757817161031222997517981543347628379360635925549008442030252106"
2502
+ "3028459181652799888716942141752307629938889957960373621898607910203491239368",
2503
+ "11380736494786911280692284374675752681598754560757720296073023058533044108340"
2469
2504
  ],
2505
+ ["1", "0"]
2506
+ ],
2507
+ vk_alphabeta_12: [
2470
2508
  [
2471
- "5940354580057074848093997050200682056184807770593307860589430076672439820312",
2472
- "12156638873931618554171829126792193045421052652279363021382169897324752428276"
2509
+ [
2510
+ "2029413683389138792403550203267699914886160938906632433982220835551125967885",
2511
+ "21072700047562757817161031222997517981543347628379360635925549008442030252106"
2512
+ ],
2513
+ [
2514
+ "5940354580057074848093997050200682056184807770593307860589430076672439820312",
2515
+ "12156638873931618554171829126792193045421052652279363021382169897324752428276"
2516
+ ],
2517
+ [
2518
+ "7898200236362823042373859371574133993780991612861777490112507062703164551277",
2519
+ "7074218545237549455313236346927434013100842096812539264420499035217050630853"
2520
+ ]
2473
2521
  ],
2474
2522
  [
2475
- "7898200236362823042373859371574133993780991612861777490112507062703164551277",
2476
- "7074218545237549455313236346927434013100842096812539264420499035217050630853"
2523
+ [
2524
+ "7077479683546002997211712695946002074877511277312570035766170199895071832130",
2525
+ "10093483419865920389913245021038182291233451549023025229112148274109565435465"
2526
+ ],
2527
+ [
2528
+ "4595479056700221319381530156280926371456704509942304414423590385166031118820",
2529
+ "19831328484489333784475432780421641293929726139240675179672856274388269393268"
2530
+ ],
2531
+ [
2532
+ "11934129596455521040620786944827826205713621633706285934057045369193958244500",
2533
+ "8037395052364110730298837004334506829870972346962140206007064471173334027475"
2534
+ ]
2477
2535
  ]
2478
2536
  ],
2479
- [
2537
+ IC: [
2538
+ [
2539
+ "12951059800758687233303204819298121944551181861362200875212570257618182506154",
2540
+ "5751958719396509176593242305268064754837298673622815112953832050159760501392",
2541
+ "1"
2542
+ ],
2480
2543
  [
2481
- "7077479683546002997211712695946002074877511277312570035766170199895071832130",
2482
- "10093483419865920389913245021038182291233451549023025229112148274109565435465"
2544
+ "9561588427935871983444704959674198910445823619407211599507208879011862515257",
2545
+ "14576201570478094842467636169770180675293504492823217349086195663150934064643",
2546
+ "1"
2483
2547
  ],
2484
2548
  [
2485
- "4595479056700221319381530156280926371456704509942304414423590385166031118820",
2486
- "19831328484489333784475432780421641293929726139240675179672856274388269393268"
2549
+ "4811967233483727873912563574622036989372099129165459921963463310078093941559",
2550
+ "1874883809855039536107616044787862082553628089593740724610117059083415551067",
2551
+ "1"
2487
2552
  ],
2488
2553
  [
2489
- "11934129596455521040620786944827826205713621633706285934057045369193958244500",
2490
- "8037395052364110730298837004334506829870972346962140206007064471173334027475"
2554
+ "12252730267779308452229639835051322390696643456253768618882001876621526827161",
2555
+ "7899194018737016222260328309937800777948677569409898603827268776967707173231",
2556
+ "1"
2491
2557
  ]
2492
2558
  ]
2493
- ],
2494
- IC: [
2495
- [
2496
- "12951059800758687233303204819298121944551181861362200875212570257618182506154",
2497
- "5751958719396509176593242305268064754837298673622815112953832050159760501392",
2498
- "1"
2499
- ],
2500
- [
2501
- "9561588427935871983444704959674198910445823619407211599507208879011862515257",
2502
- "14576201570478094842467636169770180675293504492823217349086195663150934064643",
2503
- "1"
2504
- ],
2505
- [
2506
- "4811967233483727873912563574622036989372099129165459921963463310078093941559",
2507
- "1874883809855039536107616044787862082553628089593740724610117059083415551067",
2508
- "1"
2509
- ],
2510
- [
2511
- "12252730267779308452229639835051322390696643456253768618882001876621526827161",
2512
- "7899194018737016222260328309937800777948677569409898603827268776967707173231",
2513
- "1"
2514
- ]
2515
- ]
2516
- };
2517
- dotenv.config();
2518
- const { BANDADA_API_URL, BANDADA_GROUP_ID } = process.env;
2519
- const bandadaApi = new ApiSdk(BANDADA_API_URL);
2520
- const bandadaValidateProof = functions
2521
- .region("europe-west1")
2522
- .runWith({
2523
- memory: "512MB"
2524
- })
2525
- .https.onCall(async (data) => {
2559
+ };
2526
2560
  if (!BANDADA_GROUP_ID)
2527
2561
  throw new Error("BANDADA_GROUP_ID is not defined in .env");
2528
2562
  const { proof, publicSignals } = data;
@@ -2683,7 +2717,7 @@ const checkAndRemoveBlockingContributor = functions
2683
2717
  // Case (A).
2684
2718
  if (!currentContributor)
2685
2719
  // Do not use `logAndThrowError` method to avoid the function to exit before checking every ceremony.
2686
- printLog(`No current contributor for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.WARN);
2720
+ printLog(`No current contributor for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.DEBUG);
2687
2721
  else if (avgFullContribution === 0 &&
2688
2722
  avgContributionComputation === 0 &&
2689
2723
  avgVerifyCloudFunction === 0 &&
@@ -2709,7 +2743,7 @@ const checkAndRemoveBlockingContributor = functions
2709
2743
  ? Number(contributionStartedAt) +
2710
2744
  Number(avgFullContribution) +
2711
2745
  Number(timeoutDynamicThreshold)
2712
- : Number(contributionStartedAt) + Number(fixedTimeWindow) * 60000; // * 60000 = convert minutes to millis.
2746
+ : (Number(contributionStartedAt) + Number(fixedTimeWindow)) * 60000; // * 60000 = convert minutes to millis.
2713
2747
  // Case (D).
2714
2748
  const timeoutExpirationDateInMsForVerificationCloudFunction = contributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */ &&
2715
2749
  !!verificationStartedAt
@@ -2727,11 +2761,11 @@ const checkAndRemoveBlockingContributor = functions
2727
2761
  timeoutExpirationDateInMsForVerificationCloudFunction < currentServerTimestamp &&
2728
2762
  contributionStep === "VERIFYING" /* ParticipantContributionStep.VERIFYING */)
2729
2763
  timeoutType = "BLOCKING_CLOUD_FUNCTION" /* TimeoutType.BLOCKING_CLOUD_FUNCTION */;
2730
- printLog(`${timeoutType} detected for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.DEBUG);
2731
2764
  if (!timeoutType)
2732
2765
  // Do not use `logAndThrowError` method to avoid the function to exit before checking every ceremony.
2733
- printLog(`No timeout for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.WARN);
2766
+ printLog(`No timeout for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.DEBUG);
2734
2767
  else {
2768
+ printLog(`${timeoutType} detected for circuit ${circuit.id} - ceremony ${ceremony.id}`, LogLevel.WARN);
2735
2769
  // Case (E).
2736
2770
  let nextCurrentContributorId = "";
2737
2771
  // Prepare Firestore batch of txs.
@@ -2782,7 +2816,7 @@ const checkAndRemoveBlockingContributor = functions
2782
2816
  });
2783
2817
  // Send atomic update for Firestore.
2784
2818
  await batch.commit();
2785
- 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);
2819
+ 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);
2786
2820
  }
2787
2821
  }
2788
2822
  }