@devtion/backend 0.0.0-bfc9ee4 → 0.0.0-c749be4

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.0.5
3
+ * @version 1.1.0
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, retrieveCommandStatus, checkIfRunning, retrieveCommandOutput, stopEC2Instance, verificationKeyAcronym, verifierSmartContractAcronym } from '@p0tion/actions';
12
+ import { getCircuitsCollectionPath, getTimeoutsCollectionPath, commonTerms, finalContributionIndex, getContributionsCollectionPath, githubReputation, getBucketName, vmBootstrapCommand, vmDependenciesAndCacheArtifactsCommand, vmBootstrapScriptFilename, computeDiskSizeForVM, createEC2Instance, getParticipantsCollectionPath, terminateEC2Instance, formatZkeyIndex, getTranscriptStorageFilePath, getZkeyStorageFilePath, startEC2Instance, vmContributionVerificationCommand, runCommandUsingSSM, getPotStorageFilePath, genesisZkeyIndex, createCustomLoggerForFile, blake512FromPath, getVerificationKeyStorageFilePath, getVerifierContractStorageFilePath, computeSHA256ToHex, checkIfRunning, retrieveCommandOutput, stopEC2Instance, verificationKeyAcronym, verifierSmartContractAcronym, retrieveCommandStatus } from '@p0tion/actions';
13
13
  import { encode } from 'html-entities';
14
14
  import { Timestamp, FieldValue } from 'firebase-admin/firestore';
15
15
  import { S3Client, GetObjectCommand, PutObjectCommand, DeleteObjectCommand, HeadBucketCommand, CreateBucketCommand, PutPublicAccessBlockCommand, PutBucketCorsCommand, HeadObjectCommand, CreateMultipartUploadCommand, UploadPartCommand, CompleteMultipartUploadCommand } from '@aws-sdk/client-s3';
@@ -19,7 +19,7 @@ import { pipeline } from 'node:stream';
19
19
  import { promisify } from 'node:util';
20
20
  import fs, { readFileSync } from 'fs';
21
21
  import mime from 'mime-types';
22
- import { setTimeout } from 'timers/promises';
22
+ import { setTimeout as setTimeout$1 } from 'timers/promises';
23
23
  import fetch from '@adobe/node-fetch-retry';
24
24
  import path from 'path';
25
25
  import os from 'os';
@@ -121,7 +121,8 @@ const SPECIFIC_ERRORS = {
121
121
  SE_VM_FAILED_COMMAND_EXECUTION: makeError("failed-precondition", "VM command execution failed", "Please, contact the coordinator if this error persists."),
122
122
  SE_VM_TIMEDOUT_COMMAND_EXECUTION: makeError("deadline-exceeded", "VM command execution took too long and has been timed-out", "Please, contact the coordinator if this error persists."),
123
123
  SE_VM_CANCELLED_COMMAND_EXECUTION: makeError("cancelled", "VM command execution has been cancelled", "Please, contact the coordinator if this error persists."),
124
- SE_VM_DELAYED_COMMAND_EXECUTION: makeError("unavailable", "VM command execution has been delayed since there were no available instance at the moment", "Please, contact the coordinator if this error persists.")
124
+ SE_VM_DELAYED_COMMAND_EXECUTION: makeError("unavailable", "VM command execution has been delayed since there were no available instance at the moment", "Please, contact the coordinator if this error persists."),
125
+ SE_VM_UNKNOWN_COMMAND_STATUS: makeError("unavailable", "VM command execution has failed due to an unknown status code", "Please, contact the coordinator if this error persists.")
125
126
  };
126
127
  /**
127
128
  * A set of common errors.
@@ -191,7 +192,7 @@ const getCurrentServerTimestampInMillis = () => Timestamp.now().toMillis();
191
192
  * Interrupt the current execution for a specified amount of time.
192
193
  * @param ms <number> - the amount of time expressed in milliseconds.
193
194
  */
194
- const sleep = async (ms) => setTimeout(ms);
195
+ const sleep = async (ms) => setTimeout$1(ms);
195
196
  /**
196
197
  * Query for ceremony circuits.
197
198
  * @notice the order by sequence position is fundamental to maintain parallelism among contributions for different circuits.
@@ -264,7 +265,7 @@ const queryOpenedCeremonies = async () => {
264
265
  const getCircuitDocumentByPosition = async (ceremonyId, sequencePosition) => {
265
266
  // Query for all ceremony circuits.
266
267
  const circuits = await getCeremonyCircuits(ceremonyId);
267
- // Apply a filter using the sequence postion.
268
+ // Apply a filter using the sequence position.
268
269
  const matchedCircuits = circuits.filter((circuit) => circuit.data().sequencePosition === sequencePosition);
269
270
  if (matchedCircuits.length !== 1)
270
271
  logAndThrowError(COMMON_ERRORS.CM_NO_CIRCUIT_FOR_GIVEN_SEQUENCE_POSITION);
@@ -305,7 +306,7 @@ const downloadArtifactFromS3Bucket = async (bucketName, objectKey, localFilePath
305
306
  const writeStream = createWriteStream(localFilePath);
306
307
  const streamPipeline = promisify(pipeline);
307
308
  await streamPipeline(response.body, writeStream);
308
- writeStream.on('finish', () => {
309
+ writeStream.on("finish", () => {
309
310
  writeStream.end();
310
311
  });
311
312
  };
@@ -429,12 +430,14 @@ const htmlEncodeCircuitData = (circuitDocument) => ({
429
430
  const getGitHubVariables = () => {
430
431
  if (!process.env.GITHUB_MINIMUM_FOLLOWERS ||
431
432
  !process.env.GITHUB_MINIMUM_FOLLOWING ||
432
- !process.env.GITHUB_MINIMUM_PUBLIC_REPOS)
433
+ !process.env.GITHUB_MINIMUM_PUBLIC_REPOS ||
434
+ !process.env.GITHUB_MINIMUM_AGE)
433
435
  logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
434
436
  return {
435
437
  minimumFollowers: Number(process.env.GITHUB_MINIMUM_FOLLOWERS),
436
438
  minimumFollowing: Number(process.env.GITHUB_MINIMUM_FOLLOWING),
437
- minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS)
439
+ minimumPublicRepos: Number(process.env.GITHUB_MINIMUM_PUBLIC_REPOS),
440
+ minimumAge: Number(process.env.GITHUB_MINIMUM_AGE)
438
441
  };
439
442
  };
440
443
  /**
@@ -444,7 +447,7 @@ const getGitHubVariables = () => {
444
447
  const getAWSVariables = () => {
445
448
  if (!process.env.AWS_ACCESS_KEY_ID ||
446
449
  !process.env.AWS_SECRET_ACCESS_KEY ||
447
- !process.env.AWS_ROLE_ARN ||
450
+ !process.env.AWS_INSTANCE_PROFILE_ARN ||
448
451
  !process.env.AWS_AMI_ID ||
449
452
  !process.env.AWS_SNS_TOPIC_ARN)
450
453
  logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION);
@@ -452,7 +455,7 @@ const getAWSVariables = () => {
452
455
  accessKeyId: process.env.AWS_ACCESS_KEY_ID,
453
456
  secretAccessKey: process.env.AWS_SECRET_ACCESS_KEY,
454
457
  region: process.env.AWS_REGION || "eu-central-1",
455
- roleArn: process.env.AWS_ROLE_ARN,
458
+ instanceProfileArn: process.env.AWS_INSTANCE_PROFILE_ARN,
456
459
  amiId: process.env.AWS_AMI_ID,
457
460
  snsTopic: process.env.AWS_SNS_TOPIC_ARN
458
461
  };
@@ -521,8 +524,10 @@ const registerAuthUser = functions
521
524
  const { uid } = user;
522
525
  // Reference to a document using uid.
523
526
  const userRef = firestore.collection(commonTerms.collections.users.name).doc(uid);
524
- // html encode the display name
525
- const encodedDisplayName = encode(displayName);
527
+ // html encode the display name (or put the ID if the name is not displayed)
528
+ const encodedDisplayName = user.displayName === "Null" || user.displayName === null ? user.uid : encode(displayName);
529
+ // store the avatar URL of a contributor
530
+ let avatarUrl = "";
526
531
  // we only do reputation check if the user is not a coordinator
527
532
  if (!(email?.endsWith(`@${process.env.CUSTOM_CLAIMS_COORDINATOR_EMAIL_ADDRESS_OR_DOMAIN}`) ||
528
533
  email === process.env.CUSTOM_CLAIMS_COORDINATOR_EMAIL_ADDRESS_OR_DOMAIN)) {
@@ -532,14 +537,18 @@ const registerAuthUser = functions
532
537
  const vars = getGitHubVariables();
533
538
  // this return true or false
534
539
  try {
535
- const res = await githubReputation(user.providerData[0].uid, vars.minimumFollowing, vars.minimumFollowers, vars.minimumPublicRepos);
536
- if (!res) {
540
+ const { reputable, avatarUrl: avatarURL } = await githubReputation(user.providerData[0].uid, vars.minimumFollowing, vars.minimumFollowers, vars.minimumPublicRepos, vars.minimumAge);
541
+ if (!reputable) {
537
542
  // Delete user
538
543
  await auth.deleteUser(user.uid);
539
544
  // Throw error
540
- logAndThrowError(makeError("permission-denied", "The user is not allowed to sign up because their Github reputation is not high enough.", `The user ${user.displayName} is not allowed to sign up because their Github reputation is not high enough. Please contact the administrator if you think this is a mistake.`));
545
+ logAndThrowError(makeError("permission-denied", "The user is not allowed to sign up because their Github reputation is not high enough.", `The user ${user.displayName === "Null" || user.displayName === null
546
+ ? user.uid
547
+ : user.displayName} is not allowed to sign up because their Github reputation is not high enough. Please contact the administrator if you think this is a mistake.`));
541
548
  }
542
- printLog(`Github reputation check passed for user ${user.displayName}`, LogLevel.DEBUG);
549
+ // store locally
550
+ avatarUrl = avatarURL;
551
+ printLog(`Github reputation check passed for user ${user.displayName === "Null" || user.displayName === null ? user.uid : user.displayName}`, LogLevel.DEBUG);
543
552
  }
544
553
  catch (error) {
545
554
  // Delete user
@@ -549,6 +558,8 @@ const registerAuthUser = functions
549
558
  }
550
559
  }
551
560
  // Set document (nb. we refer to providerData[0] because we use Github OAuth provider only).
561
+ // In future releases we might want to loop through the providerData array as we support
562
+ // more providers.
552
563
  await userRef.set({
553
564
  name: encodedDisplayName,
554
565
  encodedDisplayName,
@@ -561,7 +572,13 @@ const registerAuthUser = functions
561
572
  photoURL: photoURL || "",
562
573
  lastUpdated: getCurrentServerTimestampInMillis()
563
574
  });
575
+ // we want to create a new collection for the users to store the avatars
576
+ const avatarRef = firestore.collection(commonTerms.collections.avatars.name).doc(uid);
577
+ await avatarRef.set({
578
+ avatarUrl: avatarUrl || ""
579
+ });
564
580
  printLog(`Authenticated user document with identifier ${uid} has been correctly stored`, LogLevel.DEBUG);
581
+ printLog(`Authenticated user avatar with identifier ${uid} has been correctly stored`, LogLevel.DEBUG);
565
582
  });
566
583
  /**
567
584
  * Set custom claims for role-based access control on the newly created user.
@@ -698,7 +715,7 @@ const setupCeremony = functions
698
715
  // Check if using the VM approach for contribution verification.
699
716
  if (circuit.verification.cfOrVm === "VM" /* CircuitContributionVerificationMechanism.VM */) {
700
717
  // VM command to be run at the startup.
701
- const startupCommand = vmBootstrapCommand(bucketName);
718
+ const startupCommand = vmBootstrapCommand(`${bucketName}/circuits/${circuit.name}`);
702
719
  // Get EC2 client.
703
720
  const ec2Client = await createEC2Client();
704
721
  // Get AWS variables.
@@ -707,7 +724,8 @@ const setupCeremony = functions
707
724
  const vmCommands = vmDependenciesAndCacheArtifactsCommand(`${bucketName}/${circuit.files?.initialZkeyStoragePath}`, `${bucketName}/${circuit.files?.potStoragePath}`, snsTopic, region);
708
725
  printLog(`Check VM dependencies and cache artifacts commands ${vmCommands.join("\n")}`, LogLevel.DEBUG);
709
726
  // Upload the post-startup commands script file.
710
- await uploadFileToBucketNoFile(bucketName, vmBootstrapScriptFilename, vmCommands.join("\n"));
727
+ printLog(`Uploading VM post-startup commands script file ${vmBootstrapScriptFilename}`, LogLevel.DEBUG);
728
+ await uploadFileToBucketNoFile(bucketName, `circuits/${circuit.name}/${vmBootstrapScriptFilename}`, vmCommands.join("\n"));
711
729
  // Compute the VM disk space requirement (in GB).
712
730
  const vmDiskSize = computeDiskSizeForVM(circuit.zKeySizeInBytes, circuit.metadata?.pot);
713
731
  printLog(`Check VM startup commands ${startupCommand.join("\n")}`, LogLevel.DEBUG);
@@ -854,7 +872,7 @@ dotenv.config();
854
872
  * @dev true when the participant can participate (1.A, 3.B, 1.D); otherwise false.
855
873
  */
856
874
  const checkParticipantForCeremony = functions
857
- .region('europe-west1')
875
+ .region("europe-west1")
858
876
  .runWith({
859
877
  memory: "512MB"
860
878
  })
@@ -925,7 +943,7 @@ const checkParticipantForCeremony = functions
925
943
  participantDoc.ref.update({
926
944
  status: "EXHUMED" /* ParticipantStatus.EXHUMED */,
927
945
  contributions,
928
- tempContributionData: tempContributionData ? tempContributionData : FieldValue.delete(),
946
+ tempContributionData: tempContributionData || FieldValue.delete(),
929
947
  contributionStep: "DOWNLOADING" /* ParticipantContributionStep.DOWNLOADING */,
930
948
  contributionStartedAt: 0,
931
949
  verificationStartedAt: FieldValue.delete(),
@@ -958,7 +976,7 @@ const checkParticipantForCeremony = functions
958
976
  * 2) the participant has just finished the contribution for a circuit (contributionProgress != 0 && status = CONTRIBUTED && contributionStep = COMPLETED).
959
977
  */
960
978
  const progressToNextCircuitForContribution = functions
961
- .region('europe-west1')
979
+ .region("europe-west1")
962
980
  .runWith({
963
981
  memory: "512MB"
964
982
  })
@@ -1005,7 +1023,7 @@ const progressToNextCircuitForContribution = functions
1005
1023
  * 5) Completed contribution computation and verification.
1006
1024
  */
1007
1025
  const progressToNextContributionStep = functions
1008
- .region('europe-west1')
1026
+ .region("europe-west1")
1009
1027
  .runWith({
1010
1028
  memory: "512MB"
1011
1029
  })
@@ -1056,7 +1074,7 @@ const progressToNextContributionStep = functions
1056
1074
  * @dev enable the current contributor to resume a contribution from where it had left off.
1057
1075
  */
1058
1076
  const permanentlyStoreCurrentContributionTimeAndHash = functions
1059
- .region('europe-west1')
1077
+ .region("europe-west1")
1060
1078
  .runWith({
1061
1079
  memory: "512MB"
1062
1080
  })
@@ -1098,7 +1116,7 @@ const permanentlyStoreCurrentContributionTimeAndHash = functions
1098
1116
  * @dev enable the current contributor to resume a multi-part upload from where it had left off.
1099
1117
  */
1100
1118
  const temporaryStoreCurrentContributionMultiPartUploadId = functions
1101
- .region('europe-west1')
1119
+ .region("europe-west1")
1102
1120
  .runWith({
1103
1121
  memory: "512MB"
1104
1122
  })
@@ -1136,7 +1154,7 @@ const temporaryStoreCurrentContributionMultiPartUploadId = functions
1136
1154
  * @dev enable the current contributor to resume a multi-part upload from where it had left off.
1137
1155
  */
1138
1156
  const temporaryStoreCurrentContributionUploadedChunkData = functions
1139
- .region('europe-west1')
1157
+ .region("europe-west1")
1140
1158
  .runWith({
1141
1159
  memory: "512MB"
1142
1160
  })
@@ -1178,7 +1196,7 @@ const temporaryStoreCurrentContributionUploadedChunkData = functions
1178
1196
  * contributed to every selected ceremony circuits (= DONE).
1179
1197
  */
1180
1198
  const checkAndPrepareCoordinatorForFinalization = functions
1181
- .region('europe-west1')
1199
+ .region("europe-west1")
1182
1200
  .runWith({
1183
1201
  memory: "512MB"
1184
1202
  })
@@ -1330,54 +1348,74 @@ const coordinate = async (participant, circuit, isSingleParticipantCoordination,
1330
1348
  * Wait until the command has completed its execution inside the VM.
1331
1349
  * @dev this method implements a custom interval to check 5 times after 1 minute if the command execution
1332
1350
  * has been completed or not by calling the `retrieveCommandStatus` method.
1333
- * @param {any} resolve the promise.
1334
- * @param {any} reject the promise.
1335
1351
  * @param {SSMClient} ssm the SSM client.
1336
1352
  * @param {string} vmInstanceId the unique identifier of the VM instance.
1337
1353
  * @param {string} commandId the unique identifier of the VM command.
1338
1354
  * @returns <Promise<void>> true when the command execution succeed; otherwise false.
1339
1355
  */
1340
- const waitForVMCommandExecution = (resolve, reject, ssm, vmInstanceId, commandId) => {
1341
- const interval = setInterval(async () => {
1356
+ const waitForVMCommandExecution = (ssm, vmInstanceId, commandId) => new Promise((resolve, reject) => {
1357
+ const poll = async () => {
1342
1358
  try {
1343
1359
  // Get command status.
1344
1360
  const cmdStatus = await retrieveCommandStatus(ssm, vmInstanceId, commandId);
1345
1361
  printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG);
1346
- if (cmdStatus === CommandInvocationStatus.SUCCESS) {
1347
- printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG);
1348
- // Resolve the promise.
1349
- resolve();
1350
- }
1351
- else if (cmdStatus === CommandInvocationStatus.FAILED) {
1352
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION);
1353
- reject();
1354
- }
1355
- else if (cmdStatus === CommandInvocationStatus.TIMED_OUT) {
1356
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION);
1357
- reject();
1358
- }
1359
- else if (cmdStatus === CommandInvocationStatus.CANCELLED) {
1360
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION);
1361
- reject();
1362
+ let error;
1363
+ switch (cmdStatus) {
1364
+ case CommandInvocationStatus.CANCELLING:
1365
+ case CommandInvocationStatus.CANCELLED: {
1366
+ error = SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION;
1367
+ break;
1368
+ }
1369
+ case CommandInvocationStatus.DELAYED: {
1370
+ error = SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION;
1371
+ break;
1372
+ }
1373
+ case CommandInvocationStatus.FAILED: {
1374
+ error = SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION;
1375
+ break;
1376
+ }
1377
+ case CommandInvocationStatus.TIMED_OUT: {
1378
+ error = SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION;
1379
+ break;
1380
+ }
1381
+ case CommandInvocationStatus.IN_PROGRESS:
1382
+ case CommandInvocationStatus.PENDING: {
1383
+ // wait a minute and poll again
1384
+ setTimeout(poll, 60000);
1385
+ return;
1386
+ }
1387
+ case CommandInvocationStatus.SUCCESS: {
1388
+ printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG);
1389
+ // Resolve the promise.
1390
+ resolve();
1391
+ return;
1392
+ }
1393
+ default: {
1394
+ logAndThrowError(SPECIFIC_ERRORS.SE_VM_UNKNOWN_COMMAND_STATUS);
1395
+ }
1362
1396
  }
1363
- else if (cmdStatus === CommandInvocationStatus.DELAYED) {
1364
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION);
1365
- reject();
1397
+ if (error) {
1398
+ logAndThrowError(error);
1366
1399
  }
1367
1400
  }
1368
1401
  catch (error) {
1369
1402
  printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG);
1403
+ const ec2 = await createEC2Client();
1404
+ // if it errors out, let's just log it as a warning so the coordinator is aware
1405
+ try {
1406
+ await stopEC2Instance(ec2, vmInstanceId);
1407
+ }
1408
+ catch (error) {
1409
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1410
+ }
1370
1411
  if (!error.toString().includes(commandId))
1371
1412
  logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1372
1413
  // Reject the promise.
1373
1414
  reject();
1374
1415
  }
1375
- finally {
1376
- // Clear the interval.
1377
- clearInterval(interval);
1378
- }
1379
- }, 60000); // 1 minute.
1380
- };
1416
+ };
1417
+ setTimeout(poll, 60000);
1418
+ });
1381
1419
  /**
1382
1420
  * This method is used to coordinate the waiting queues of ceremony circuits.
1383
1421
  * @dev this cloud function is triggered whenever an update of a document related to a participant of a ceremony occurs.
@@ -1398,7 +1436,7 @@ const waitForVMCommandExecution = (resolve, reject, ssm, vmInstanceId, commandId
1398
1436
  * - Just completed a contribution or all contributions for each circuit. If yes, coordinate (multi-participant scenario).
1399
1437
  */
1400
1438
  const coordinateCeremonyParticipant = functionsV1
1401
- .region('europe-west1')
1439
+ .region("europe-west1")
1402
1440
  .runWith({
1403
1441
  memory: "512MB"
1404
1442
  })
@@ -1469,11 +1507,9 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
1469
1507
  const isVMRunning = await checkIfRunning(ec2, vmInstanceId);
1470
1508
  if (!isVMRunning) {
1471
1509
  printLog(`VM not running, ${attempts - 1} attempts remaining. Retrying in 1 minute...`, LogLevel.DEBUG);
1472
- return await checkIfVMRunning(ec2, vmInstanceId, attempts - 1);
1473
- }
1474
- else {
1475
- return true;
1510
+ return checkIfVMRunning(ec2, vmInstanceId, attempts - 1);
1476
1511
  }
1512
+ return true;
1477
1513
  };
1478
1514
  /**
1479
1515
  * Verify the contribution of a participant computed while contributing to a specific circuit of a ceremony.
@@ -1501,7 +1537,7 @@ const checkIfVMRunning = async (ec2, vmInstanceId, attempts = 5) => {
1501
1537
  * 1.A.4.C.1) If true, update circuit waiting for queue and average timings accordingly to contribution verification results;
1502
1538
  * 2) Send all updates atomically to the Firestore database.
1503
1539
  */
1504
- const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: 'europe-west1' }, async (request) => {
1540
+ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" }, async (request) => {
1505
1541
  if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
1506
1542
  logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER);
1507
1543
  if (!request.data.ceremonyId ||
@@ -1612,8 +1648,6 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
1612
1648
  lastZkeyBlake2bHash = match.at(0);
1613
1649
  // re upload the formatted verification transcript
1614
1650
  await uploadFileToBucket(bucketName, verificationTranscriptStoragePathAndFilename, verificationTranscriptTemporaryLocalPath, true);
1615
- // Stop VM instance.
1616
- await stopEC2Instance(ec2, vmInstanceId);
1617
1651
  }
1618
1652
  else {
1619
1653
  // Upload verification transcript.
@@ -1674,6 +1708,18 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
1674
1708
  lastUpdated: getCurrentServerTimestampInMillis()
1675
1709
  });
1676
1710
  }
1711
+ // Stop VM instance
1712
+ if (isUsingVM) {
1713
+ // using try and catch as the VM stopping function can throw
1714
+ // however we want to continue without stopping as the
1715
+ // verification was valid, and inform the coordinator
1716
+ try {
1717
+ await stopEC2Instance(ec2, vmInstanceId);
1718
+ }
1719
+ catch (error) {
1720
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN);
1721
+ }
1722
+ }
1677
1723
  // Step (1.A.4.C)
1678
1724
  if (!isFinalizing) {
1679
1725
  // Step (1.A.4.C.1)
@@ -1688,7 +1734,7 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
1688
1734
  const newAvgVerifyCloudFunctionTime = avgVerifyCloudFunctionTime > 0
1689
1735
  ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
1690
1736
  : verifyCloudFunctionTime;
1691
- // Prepare tx to update circuit average contribution/verification time.
1737
+ // Prepare tx to update circuit average contribution/verification time.
1692
1738
  const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId);
1693
1739
  const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data();
1694
1740
  /// @dev this must happen only for valid contributions.
@@ -1738,7 +1784,7 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
1738
1784
  commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand);
1739
1785
  printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG);
1740
1786
  // Step (1.A.3.3).
1741
- return new Promise((resolve, reject) => waitForVMCommandExecution(resolve, reject, ssm, vmInstanceId, commandId))
1787
+ return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
1742
1788
  .then(async () => {
1743
1789
  // Command execution successfully completed.
1744
1790
  printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG);
@@ -1750,40 +1796,38 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
1750
1796
  logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION);
1751
1797
  });
1752
1798
  }
1753
- else {
1754
- // CF approach.
1755
- printLog(`CF mechanism`, LogLevel.DEBUG);
1756
- const potStoragePath = getPotStorageFilePath(files.potFilename);
1757
- const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`);
1758
- // Prepare temporary file paths.
1759
- // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1760
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1761
- const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1762
- const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1763
- const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1764
- // Create and populate transcript.
1765
- const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1766
- transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1767
- // Step (1.A.2).
1768
- await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1769
- await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1770
- await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1771
- // Step (1.A.4).
1772
- isContributionValid = await zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1773
- // Compute contribution hash.
1774
- lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath);
1775
- // Free resources by unlinking temporary folders.
1776
- // Do not free-up verification transcript path here.
1777
- try {
1778
- fs.unlinkSync(potTempFilePath);
1779
- fs.unlinkSync(firstZkeyTempFilePath);
1780
- fs.unlinkSync(lastZkeyTempFilePath);
1781
- }
1782
- catch (error) {
1783
- printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1784
- }
1785
- await completeVerification();
1799
+ // CF approach.
1800
+ printLog(`CF mechanism`, LogLevel.DEBUG);
1801
+ const potStoragePath = getPotStorageFilePath(files.potFilename);
1802
+ const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`);
1803
+ // Prepare temporary file paths.
1804
+ // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
1805
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename);
1806
+ const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`);
1807
+ const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`);
1808
+ const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`);
1809
+ // Create and populate transcript.
1810
+ const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath);
1811
+ transcriptLogger.info(`${isFinalizing ? `Final verification` : `Verification`} transcript for ${prefix} circuit Phase 2 contribution.\n${isFinalizing ? `Coordinator ` : `Contributor # ${Number(lastZkeyIndex)}`} (${contributorOrCoordinatorIdentifier})\n`);
1812
+ // Step (1.A.2).
1813
+ await downloadArtifactFromS3Bucket(bucketName, potStoragePath, potTempFilePath);
1814
+ await downloadArtifactFromS3Bucket(bucketName, firstZkeyStoragePath, firstZkeyTempFilePath);
1815
+ await downloadArtifactFromS3Bucket(bucketName, lastZkeyStoragePath, lastZkeyTempFilePath);
1816
+ // Step (1.A.4).
1817
+ isContributionValid = await zKey.verifyFromInit(firstZkeyTempFilePath, potTempFilePath, lastZkeyTempFilePath, transcriptLogger);
1818
+ // Compute contribution hash.
1819
+ lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath);
1820
+ // Free resources by unlinking temporary folders.
1821
+ // Do not free-up verification transcript path here.
1822
+ try {
1823
+ fs.unlinkSync(potTempFilePath);
1824
+ fs.unlinkSync(firstZkeyTempFilePath);
1825
+ fs.unlinkSync(lastZkeyTempFilePath);
1786
1826
  }
1827
+ catch (error) {
1828
+ printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN);
1829
+ }
1830
+ await completeVerification();
1787
1831
  }
1788
1832
  });
1789
1833
  /**
@@ -1792,7 +1836,7 @@ const verifycontribution = functionsV2.https.onCall({ memory: "16GiB", timeoutSe
1792
1836
  * this does not happen if the participant is actually the coordinator who is finalizing the ceremony.
1793
1837
  */
1794
1838
  const refreshParticipantAfterContributionVerification = functionsV1
1795
- .region('europe-west1')
1839
+ .region("europe-west1")
1796
1840
  .runWith({
1797
1841
  memory: "512MB"
1798
1842
  })
@@ -1853,7 +1897,7 @@ const refreshParticipantAfterContributionVerification = functionsV1
1853
1897
  * and verification key extracted from the circuit final contribution (as part of the ceremony finalization process).
1854
1898
  */
1855
1899
  const finalizeCircuit = functionsV1
1856
- .region('europe-west1')
1900
+ .region("europe-west1")
1857
1901
  .runWith({
1858
1902
  memory: "512MB"
1859
1903
  })
@@ -2050,8 +2094,10 @@ const createBucket = functions
2050
2094
  CORSConfiguration: {
2051
2095
  CORSRules: [
2052
2096
  {
2053
- AllowedMethods: ["GET"],
2054
- AllowedOrigins: ["*"]
2097
+ AllowedMethods: ["GET", "PUT"],
2098
+ AllowedOrigins: ["*"],
2099
+ ExposeHeaders: ["ETag", "Content-Length"],
2100
+ AllowedHeaders: ["*"]
2055
2101
  }
2056
2102
  ]
2057
2103
  }
@@ -2228,7 +2274,8 @@ const startMultiPartUpload = functions
2228
2274
  const generatePreSignedUrlsParts = functions
2229
2275
  .region("europe-west1")
2230
2276
  .runWith({
2231
- memory: "512MB"
2277
+ memory: "512MB",
2278
+ timeoutSeconds: 300
2232
2279
  })
2233
2280
  .https.onCall(async (data, context) => {
2234
2281
  if (!context.auth || (!context.auth.token.participant && !context.auth.token.coordinator))
@@ -2378,7 +2425,7 @@ const checkAndRemoveBlockingContributor = functions
2378
2425
  // Get ceremony circuits.
2379
2426
  const circuits = await getCeremonyCircuits(ceremony.id);
2380
2427
  // Extract ceremony data.
2381
- const { timeoutMechanismType, penalty } = ceremony.data();
2428
+ const { timeoutType: timeoutMechanismType, penalty } = ceremony.data();
2382
2429
  for (const circuit of circuits) {
2383
2430
  if (!circuit.data())
2384
2431
  // Do not use `logAndThrowError` method to avoid the function to exit before checking every ceremony.
@@ -2528,7 +2575,8 @@ const resumeContributionAfterTimeoutExpiration = functions
2528
2575
  if (status === "EXHUMED" /* ParticipantStatus.EXHUMED */)
2529
2576
  await participantDoc.ref.update({
2530
2577
  status: "READY" /* ParticipantStatus.READY */,
2531
- lastUpdated: getCurrentServerTimestampInMillis()
2578
+ lastUpdated: getCurrentServerTimestampInMillis(),
2579
+ tempContributionData: {}
2532
2580
  });
2533
2581
  else
2534
2582
  logAndThrowError(SPECIFIC_ERRORS.SE_CONTRIBUTE_CANNOT_PROGRESS_TO_NEXT_CIRCUIT);
@@ -1 +1 @@
1
- {"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../../src/functions/ceremony.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAuC/C;;;;;GAKG;AACH,eAAO,MAAM,aAAa,kCAiBpB,CAAA;AAEN;;;;;GAKG;AACH,eAAO,MAAM,YAAY,kCAkBnB,CAAA;AAEN;;;;GAIG;AACH,eAAO,MAAM,aAAa,mDAyHpB,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,+BAA+B,oEAsCtC,CAAA;AAEN;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,mDAiEvB,CAAA"}
1
+ {"version":3,"file":"ceremony.d.ts","sourceRoot":"","sources":["../../../src/functions/ceremony.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAuC/C;;;;;GAKG;AACH,eAAO,MAAM,aAAa,kCAiBpB,CAAA;AAEN;;;;;GAKG;AACH,eAAO,MAAM,YAAY,kCAkBnB,CAAA;AAEN;;;;GAIG;AACH,eAAO,MAAM,aAAa,mDA8HpB,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,+BAA+B,oEAsCtC,CAAA;AAEN;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,mDAiEvB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"circuit.d.ts","sourceRoot":"","sources":["../../../src/functions/circuit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,uBAAuB,CAAA;AACpD,OAAO,KAAK,WAAW,MAAM,uBAAuB,CAAA;AAyCpD,OAAO,EAAuB,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAkO5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,6BAA6B,4FAoGpC,CAAA;AA8BN;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,kBAAkB,0EA0Z9B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,+CAA+C,wEA4EtD,CAAA;AAEN;;;;GAIG;AACH,eAAO,MAAM,eAAe,uDA8EtB,CAAA"}
1
+ {"version":3,"file":"circuit.d.ts","sourceRoot":"","sources":["../../../src/functions/circuit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,uBAAuB,CAAA;AACpD,OAAO,KAAK,WAAW,MAAM,uBAAuB,CAAA;AA2CpD,OAAO,EAAuB,sBAAsB,EAAE,MAAM,gBAAgB,CAAA;AAwP5E;;;;;;;;;;;;;;;;;;GAkBG;AACH,eAAO,MAAM,6BAA6B,4FAoGpC,CAAA;AAwBN;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,eAAO,MAAM,kBAAkB,0EA8Z9B,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,+CAA+C,wEA4EtD,CAAA;AAEN;;;;GAIG;AACH,eAAO,MAAM,eAAe,uDA8EtB,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/functions/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAiI/C;;;GAGG;AACH,eAAO,MAAM,YAAY,mDAgGnB,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,kBAAkB,mDAgDzB,CAAA;AAEN;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,mDAyCpC,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mDA2D3B,CAAA;AAEN;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,mDAuElC,CAAA;AAEL;;;GAGG;AACH,eAAO,MAAM,uBAAuB,mDAgE9B,CAAA"}
1
+ {"version":3,"file":"storage.d.ts","sourceRoot":"","sources":["../../../src/functions/storage.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAiI/C;;;GAGG;AACH,eAAO,MAAM,YAAY,mDAkGnB,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,kBAAkB,mDAgDzB,CAAA;AAEN;;;;;GAKG;AACH,eAAO,MAAM,6BAA6B,mDAyCpC,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,oBAAoB,mDA2D3B,CAAA;AAEN;;;;;;GAMG;AACH,eAAO,MAAM,0BAA0B,mDAwElC,CAAA;AAEL;;;GAGG;AACH,eAAO,MAAM,uBAAuB,mDAgE9B,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../../../src/functions/timeout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAuB/C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iCAAiC,kCA6MxC,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,wCAAwC,mDAyC/C,CAAA"}
1
+ {"version":3,"file":"timeout.d.ts","sourceRoot":"","sources":["../../../src/functions/timeout.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAuB/C;;;;;;;;;;;;;;;;;GAiBG;AACH,eAAO,MAAM,iCAAiC,kCA6MxC,CAAA;AAEN;;;GAGG;AACH,eAAO,MAAM,wCAAwC,mDA0C/C,CAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/functions/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAW/C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,mEAuFvB,CAAA;AACN;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,mEA+BpC,CAAA"}
1
+ {"version":3,"file":"user.d.ts","sourceRoot":"","sources":["../../../src/functions/user.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAW/C;;;;;GAKG;AACH,eAAO,MAAM,gBAAgB,mEAgHvB,CAAA;AACN;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,mEA+BpC,CAAA"}
@@ -55,6 +55,7 @@ export declare const SPECIFIC_ERRORS: {
55
55
  SE_VM_TIMEDOUT_COMMAND_EXECUTION: functions.auth.HttpsError;
56
56
  SE_VM_CANCELLED_COMMAND_EXECUTION: functions.auth.HttpsError;
57
57
  SE_VM_DELAYED_COMMAND_EXECUTION: functions.auth.HttpsError;
58
+ SE_VM_UNKNOWN_COMMAND_STATUS: functions.auth.HttpsError;
58
59
  };
59
60
  /**
60
61
  * A set of common errors.
@@ -1 +1 @@
1
- {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,cAAe,kBAAkB,WAAW,MAAM,YAAY,MAAM,KAAG,UAC9B,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,QAAQ,YAAa,MAAM,YAAY,QAAQ,SAqB3D,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UAAW,UAAU,UAGjD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAkI3B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;CA2CzB,CAAA"}
1
+ {"version":3,"file":"errors.d.ts","sourceRoot":"","sources":["../../../src/lib/errors.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,SAAS,MAAM,oBAAoB,CAAA;AAC/C,OAAO,EAAE,kBAAkB,EAAE,UAAU,EAAE,MAAM,6BAA6B,CAAA;AAC5E,OAAO,EAAE,QAAQ,EAAE,MAAM,gBAAgB,CAAA;AAEzC;;;;;;;;GAQG;AACH,eAAO,MAAM,SAAS,cAAe,kBAAkB,WAAW,MAAM,YAAY,MAAM,KAAG,UAC9B,CAAA;AAE/D;;;;GAIG;AACH,eAAO,MAAM,QAAQ,YAAa,MAAM,YAAY,QAAQ,SAqB3D,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,gBAAgB,UAAW,UAAU,UAGjD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAuI3B,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;;CA2CzB,CAAA"}
@@ -1,6 +1,6 @@
1
1
  import { DocumentData, QuerySnapshot, DocumentSnapshot, QueryDocumentSnapshot, WhereFilterOp } from "firebase-admin/firestore";
2
2
  import admin from "firebase-admin";
3
- import { CircuitDocument } from "@p0tion/actions";
3
+ import { CircuitDocument } from "@devtion/actions";
4
4
  import { SSMClient } from "@aws-sdk/client-ssm";
5
5
  import { EC2Client } from "@aws-sdk/client-ec2";
6
6
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EAErB,aAAa,EAChB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,MAAM,gBAAgB,CAAA;AAWlC,OAAO,EAOH,eAAe,EAClB,MAAM,iBAAiB,CAAA;AAIxB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAM/C;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,eACZ,MAAM,cACN,MAAM,KACnB,QAAQ,iBAAiB,YAAY,CAAC,CASxC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAO,MAAoC,CAAA;AAEzF;;;GAGG;AACH,eAAO,MAAM,KAAK,OAAc,MAAM,KAAG,QAAQ,IAAI,CAAmB,CAAA;AAExE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,eAAsB,MAAM,KAAG,QAAQ,MAAM,sBAAsB,YAAY,CAAC,CAAC,CAYhH,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,eAC5B,MAAM,aACP,MAAM,KAClB,QAAQ,MAAM,sBAAsB,YAAY,CAAC,CAAC,CAUpD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,eACpB,MAAM,iBACH,MAAM,KACtB,QAAQ,cAAc,YAAY,CAAC,CASrC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAa,QAAQ,MAAM,sBAAsB,YAAY,CAAC,CAAC,CAWhG,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,eACzB,MAAM,oBACA,MAAM,KACzB,QAAQ,sBAAsB,YAAY,CAAC,CAY7C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,qBAAsB,MAAM,KAAG,MAAkD,CAAA;AAEtH;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,eAAsB,MAAM,aAAa,MAAM,iBAAiB,MAAM,kBA6B9G,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,eACf,MAAM,aACP,MAAM,iBACF,MAAM,aACX,OAAO,kBA4BpB,CAAA;AAED,eAAO,MAAM,wBAAwB,eACrB,MAAM,aACP,MAAM,QACX,MAAM,aACF,OAAO,kBAyBpB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,eAAsB,MAAM,aAAa,MAAM,kBAWvE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,UAC/B,MAAM,wBACS,OAAO,SACtB,aAAa,KACrB,QAAQ,MAAM,SAAS,cAAc,CAAC,MAAM,SAAS,aAAa,CAAC,CAYxD,CAAA;AAEd;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,eACjB,MAAM,aACP,MAAM,KAClB,QAAQ,sBAAsB,YAAY,CAAC,CAgB7C,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oBAAqB,eAAe,KAAG,eAKvE,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,GAarC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAO,GAkBlC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,QAAQ,SAAS,CAYzD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,QAAQ,SAAS,CAYzD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,cAAqB,MAAM,KAAG,QAAQ,MAAM,CAQxE,CAAA"}
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../../../src/lib/utils.ts"],"names":[],"mappings":"AAAA,OAAO,EACH,YAAY,EACZ,aAAa,EACb,gBAAgB,EAChB,qBAAqB,EAErB,aAAa,EAChB,MAAM,0BAA0B,CAAA;AACjC,OAAO,KAAK,MAAM,gBAAgB,CAAA;AAWlC,OAAO,EAOH,eAAe,EAClB,MAAM,iBAAiB,CAAA;AAIxB,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAC/C,OAAO,EAAE,SAAS,EAAE,MAAM,qBAAqB,CAAA;AAM/C;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,eACZ,MAAM,cACN,MAAM,KACnB,QAAQ,iBAAiB,YAAY,CAAC,CASxC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,iCAAiC,QAAO,MAAoC,CAAA;AAEzF;;;GAGG;AACH,eAAO,MAAM,KAAK,OAAc,MAAM,KAAG,QAAQ,IAAI,CAAmB,CAAA;AAExE;;;;;GAKG;AACH,eAAO,MAAM,mBAAmB,eAAsB,MAAM,KAAG,QAAQ,MAAM,sBAAsB,YAAY,CAAC,CAAC,CAYhH,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,+BAA+B,eAC5B,MAAM,aACP,MAAM,KAClB,QAAQ,MAAM,sBAAsB,YAAY,CAAC,CAAC,CAUpD,CAAA;AAED;;;;;;;GAOG;AACH,eAAO,MAAM,uBAAuB,eACpB,MAAM,iBACH,MAAM,KACtB,QAAQ,cAAc,YAAY,CAAC,CASrC,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,QAAa,QAAQ,MAAM,sBAAsB,YAAY,CAAC,CAAC,CAWhG,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,4BAA4B,eACzB,MAAM,oBACA,MAAM,KACzB,QAAQ,sBAAsB,YAAY,CAAC,CAY7C,CAAA;AAED;;;;;GAKG;AACH,eAAO,MAAM,wBAAwB,qBAAsB,MAAM,KAAG,MAAkD,CAAA;AAEtH;;;;;;GAMG;AACH,eAAO,MAAM,4BAA4B,eAAsB,MAAM,aAAa,MAAM,iBAAiB,MAAM,kBA6B9G,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,kBAAkB,eACf,MAAM,aACP,MAAM,iBACF,MAAM,aACX,OAAO,kBA4BpB,CAAA;AAED,eAAO,MAAM,wBAAwB,eACrB,MAAM,aACP,MAAM,QACX,MAAM,aACF,OAAO,kBAyBpB,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,YAAY,eAAsB,MAAM,aAAa,MAAM,kBAWvE,CAAA;AAED;;;;;;GAMG;AACH,eAAO,MAAM,6BAA6B,UAC/B,MAAM,wBACS,OAAO,SACtB,aAAa,KACrB,QAAQ,MAAM,SAAS,cAAc,CAAC,MAAM,SAAS,aAAa,CAAC,CAYxD,CAAA;AAEd;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,eACjB,MAAM,aACP,MAAM,KAClB,QAAQ,sBAAsB,YAAY,CAAC,CAgB7C,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,oBAAqB,eAAe,KAAG,eAKvE,CAAA;AAEF;;;GAGG;AACH,eAAO,MAAM,kBAAkB,QAAO,GAerC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAO,GAkBlC,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,QAAQ,SAAS,CAYzD,CAAA;AAED;;;GAGG;AACH,eAAO,MAAM,eAAe,QAAa,QAAQ,SAAS,CAYzD,CAAA;AAED;;;;GAIG;AACH,eAAO,MAAM,gBAAgB,cAAqB,MAAM,KAAG,QAAQ,MAAM,CAQxE,CAAA"}
@@ -1,4 +1,4 @@
1
- import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@p0tion/actions";
1
+ import { CeremonyInputData, CircuitDocument, ETagWithPartNumber } from "@devtion/actions";
2
2
  /**
3
3
  * Group all the necessary data needed for running the `setupCeremony` cloud function.
4
4
  * @typedef {Object} SetupCeremonyData