@devtion/backend 0.0.0-4088679 → 0.0.0-477457c

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.
Files changed (50) hide show
  1. package/README.md +7 -7
  2. package/dist/src/functions/index.js +669 -354
  3. package/dist/src/functions/index.mjs +672 -359
  4. package/dist/src/functions/types/functions/bandada.d.ts +4 -0
  5. package/dist/src/functions/types/functions/bandada.d.ts.map +1 -0
  6. package/dist/{types → src/functions/types}/functions/ceremony.d.ts.map +1 -1
  7. package/dist/{types → src/functions/types}/functions/circuit.d.ts.map +1 -1
  8. package/dist/{types → src/functions/types}/functions/index.d.ts +2 -0
  9. package/dist/{types → src/functions/types}/functions/index.d.ts.map +1 -1
  10. package/dist/src/functions/types/functions/siwe.d.ts +4 -0
  11. package/dist/src/functions/types/functions/siwe.d.ts.map +1 -0
  12. package/dist/{types → src/functions/types}/functions/storage.d.ts.map +1 -1
  13. package/dist/{types → src/functions/types}/functions/timeout.d.ts.map +1 -1
  14. package/dist/{types → src/functions/types}/functions/user.d.ts.map +1 -1
  15. package/dist/{types → src/functions/types}/lib/errors.d.ts +3 -1
  16. package/dist/src/functions/types/lib/errors.d.ts.map +1 -0
  17. package/dist/{types → src/functions/types}/lib/services.d.ts +7 -0
  18. package/dist/src/functions/types/lib/services.d.ts.map +1 -0
  19. package/dist/src/functions/types/lib/utils.d.ts.map +1 -0
  20. package/dist/{types → src/functions/types}/types/index.d.ts +56 -0
  21. package/dist/src/functions/types/types/index.d.ts.map +1 -0
  22. package/package.json +8 -7
  23. package/src/functions/bandada.ts +154 -0
  24. package/src/functions/ceremony.ts +16 -8
  25. package/src/functions/circuit.ts +443 -391
  26. package/src/functions/index.ts +2 -0
  27. package/src/functions/participant.ts +15 -15
  28. package/src/functions/siwe.ts +77 -0
  29. package/src/functions/storage.ts +12 -8
  30. package/src/functions/timeout.ts +14 -13
  31. package/src/functions/user.ts +22 -11
  32. package/src/lib/errors.ts +11 -1
  33. package/src/lib/services.ts +36 -0
  34. package/src/lib/utils.ts +10 -8
  35. package/src/types/declarations.d.ts +1 -0
  36. package/src/types/index.ts +60 -0
  37. package/dist/types/lib/errors.d.ts.map +0 -1
  38. package/dist/types/lib/services.d.ts.map +0 -1
  39. package/dist/types/lib/utils.d.ts.map +0 -1
  40. package/dist/types/types/index.d.ts.map +0 -1
  41. /package/dist/{types → src/functions/types}/functions/ceremony.d.ts +0 -0
  42. /package/dist/{types → src/functions/types}/functions/circuit.d.ts +0 -0
  43. /package/dist/{types → src/functions/types}/functions/participant.d.ts +0 -0
  44. /package/dist/{types → src/functions/types}/functions/participant.d.ts.map +0 -0
  45. /package/dist/{types → src/functions/types}/functions/storage.d.ts +0 -0
  46. /package/dist/{types → src/functions/types}/functions/timeout.d.ts +0 -0
  47. /package/dist/{types → src/functions/types}/functions/user.d.ts +0 -0
  48. /package/dist/{types → src/functions/types}/lib/utils.d.ts +0 -0
  49. /package/dist/{types → src/functions/types}/types/enums.d.ts +0 -0
  50. /package/dist/{types → src/functions/types}/types/enums.d.ts.map +0 -0
@@ -40,6 +40,8 @@ import {
40
40
  } from "@devtion/actions"
41
41
  import { zKey } from "snarkjs"
42
42
  import { CommandInvocationStatus, SSMClient } from "@aws-sdk/client-ssm"
43
+ import { EC2Client } from "@aws-sdk/client-ec2"
44
+ import { HttpsError } from "firebase-functions/v2/https"
43
45
  import { FinalizeCircuitData, VerifyContributionData } from "../types/index"
44
46
  import { LogLevel } from "../types/enums"
45
47
  import { COMMON_ERRORS, logAndThrowError, makeError, printLog, SPECIFIC_ERRORS } from "../lib/errors"
@@ -57,7 +59,6 @@ import {
57
59
  sleep,
58
60
  uploadFileToBucket
59
61
  } from "../lib/utils"
60
- import { EC2Client } from "@aws-sdk/client-ec2"
61
62
 
62
63
  dotenv.config()
63
64
 
@@ -114,7 +115,7 @@ const coordinate = async (
114
115
  if (isSingleParticipantCoordination) {
115
116
  // Scenario (A).
116
117
  if (emptyWaitingQueue) {
117
- printLog(`Coordinate - executing scenario A - emptyWaitingQueue`, LogLevel.DEBUG)
118
+ printLog(`Coordinate - executing scenario A - emptyWaitingQueue`, LogLevel.INFO)
118
119
 
119
120
  // Update.
120
121
  newCurrentContributorId = participant.id
@@ -126,7 +127,7 @@ const coordinate = async (
126
127
  else if (participantResumingAfterTimeoutExpiration) {
127
128
  printLog(
128
129
  `Coordinate - executing scenario A - single - participantResumingAfterTimeoutExpiration`,
129
- LogLevel.DEBUG
130
+ LogLevel.INFO
130
131
  )
131
132
 
132
133
  newParticipantStatus = ParticipantStatus.CONTRIBUTING
@@ -135,7 +136,7 @@ const coordinate = async (
135
136
  }
136
137
  // Scenario (B).
137
138
  else if (participantIsNotCurrentContributor) {
138
- printLog(`Coordinate - executing scenario B - single - participantIsNotCurrentContributor`, LogLevel.DEBUG)
139
+ printLog(`Coordinate - executing scenario B - single - participantIsNotCurrentContributor`, LogLevel.INFO)
139
140
 
140
141
  newCurrentContributorId = currentContributor
141
142
  newParticipantStatus = ParticipantStatus.WAITING
@@ -159,7 +160,7 @@ const coordinate = async (
159
160
  } else if (participantIsCurrentContributor && participantCompletedOneOrAllContributions && !!ceremonyId) {
160
161
  printLog(
161
162
  `Coordinate - executing scenario C - multi - participantIsCurrentContributor && participantCompletedOneOrAllContributions`,
162
- LogLevel.DEBUG
163
+ LogLevel.INFO
163
164
  )
164
165
 
165
166
  newParticipantStatus = ParticipantStatus.CONTRIBUTING
@@ -189,7 +190,7 @@ const coordinate = async (
189
190
 
190
191
  printLog(
191
192
  `Participant ${newCurrentContributorId} is the new current contributor for circuit ${circuit.id}`,
192
- LogLevel.DEBUG
193
+ LogLevel.INFO
193
194
  )
194
195
  }
195
196
  }
@@ -214,57 +215,80 @@ const coordinate = async (
214
215
  * Wait until the command has completed its execution inside the VM.
215
216
  * @dev this method implements a custom interval to check 5 times after 1 minute if the command execution
216
217
  * has been completed or not by calling the `retrieveCommandStatus` method.
217
- * @param {any} resolve the promise.
218
- * @param {any} reject the promise.
219
218
  * @param {SSMClient} ssm the SSM client.
220
219
  * @param {string} vmInstanceId the unique identifier of the VM instance.
221
220
  * @param {string} commandId the unique identifier of the VM command.
222
221
  * @returns <Promise<void>> true when the command execution succeed; otherwise false.
223
222
  */
224
- const waitForVMCommandExecution = (
225
- resolve: any,
226
- reject: any,
227
- ssm: SSMClient,
228
- vmInstanceId: string,
229
- commandId: string
230
- ) => {
231
- const interval = setInterval(async () => {
232
- try {
233
- // Get command status.
234
- const cmdStatus = await retrieveCommandStatus(ssm, vmInstanceId, commandId)
235
- printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG)
223
+ const waitForVMCommandExecution = (ssm: SSMClient, vmInstanceId: string, commandId: string): Promise<void> =>
224
+ new Promise((resolve, reject) => {
225
+ const poll = async () => {
226
+ try {
227
+ // Get command status.
228
+ const cmdStatus = await retrieveCommandStatus(ssm, vmInstanceId, commandId)
229
+ printLog(`Checking command ${commandId} status => ${cmdStatus}`, LogLevel.DEBUG)
230
+
231
+ let error: HttpsError | undefined
232
+ switch (cmdStatus) {
233
+ case CommandInvocationStatus.CANCELLING:
234
+ case CommandInvocationStatus.CANCELLED: {
235
+ error = SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION
236
+ break
237
+ }
238
+ case CommandInvocationStatus.DELAYED: {
239
+ error = SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION
240
+ break
241
+ }
242
+ case CommandInvocationStatus.FAILED: {
243
+ error = SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION
244
+ break
245
+ }
246
+ case CommandInvocationStatus.TIMED_OUT: {
247
+ error = SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION
248
+ break
249
+ }
250
+ case CommandInvocationStatus.IN_PROGRESS:
251
+ case CommandInvocationStatus.PENDING: {
252
+ // wait a minute and poll again
253
+ setTimeout(poll, 60000)
254
+ return
255
+ }
256
+ case CommandInvocationStatus.SUCCESS: {
257
+ printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG)
258
+
259
+ // Resolve the promise.
260
+ resolve()
261
+ return
262
+ }
263
+ default: {
264
+ logAndThrowError(SPECIFIC_ERRORS.SE_VM_UNKNOWN_COMMAND_STATUS)
265
+ }
266
+ }
267
+
268
+ if (error) {
269
+ logAndThrowError(error)
270
+ }
271
+ } catch (error: any) {
272
+ printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG)
236
273
 
237
- if (cmdStatus === CommandInvocationStatus.SUCCESS) {
238
- printLog(`Command ${commandId} successfully completed`, LogLevel.DEBUG)
274
+ const ec2 = await createEC2Client()
239
275
 
240
- // Resolve the promise.
241
- resolve()
242
- } else if (cmdStatus === CommandInvocationStatus.FAILED) {
243
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_FAILED_COMMAND_EXECUTION)
244
- reject()
245
- } else if (cmdStatus === CommandInvocationStatus.TIMED_OUT) {
246
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_TIMEDOUT_COMMAND_EXECUTION)
247
- reject()
248
- } else if (cmdStatus === CommandInvocationStatus.CANCELLED) {
249
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_CANCELLED_COMMAND_EXECUTION)
250
- reject()
251
- } else if (cmdStatus === CommandInvocationStatus.DELAYED) {
252
- logAndThrowError(SPECIFIC_ERRORS.SE_VM_DELAYED_COMMAND_EXECUTION)
253
- reject()
254
- }
255
- } catch (error: any) {
256
- printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG)
276
+ // if it errors out, let's just log it as a warning so the coordinator is aware
277
+ try {
278
+ await stopEC2Instance(ec2, vmInstanceId)
279
+ } catch (stopError: any) {
280
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${stopError}`, LogLevel.WARN)
281
+ }
257
282
 
258
- if (!error.toString().includes(commandId)) logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
283
+ if (!error.toString().includes(commandId)) logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
259
284
 
260
- // Reject the promise.
261
- reject()
262
- } finally {
263
- // Clear the interval.
264
- clearInterval(interval)
285
+ // Reject the promise.
286
+ reject()
287
+ }
265
288
  }
266
- }, 60000) // 1 minute.
267
- }
289
+
290
+ setTimeout(poll, 60000)
291
+ })
268
292
 
269
293
  /**
270
294
  * This method is used to coordinate the waiting queues of ceremony circuits.
@@ -286,9 +310,9 @@ const waitForVMCommandExecution = (
286
310
  * - Just completed a contribution or all contributions for each circuit. If yes, coordinate (multi-participant scenario).
287
311
  */
288
312
  export const coordinateCeremonyParticipant = functionsV1
289
- .region('europe-west1')
313
+ .region("europe-west1")
290
314
  .runWith({
291
- memory: "512MB"
315
+ memory: "1GB"
292
316
  })
293
317
  .firestore.document(
294
318
  `${commonTerms.collections.ceremonies.name}/{ceremonyId}/${commonTerms.collections.participants.name}/{participantId}`
@@ -322,10 +346,10 @@ export const coordinateCeremonyParticipant = functionsV1
322
346
  contributionStep: changedContributionStep
323
347
  } = changedParticipant.data()!
324
348
 
325
- printLog(`Coordinate participant ${exParticipant.id} for ceremony ${ceremonyId}`, LogLevel.DEBUG)
349
+ printLog(`Coordinate participant ${exParticipant.id} for ceremony ${ceremonyId}`, LogLevel.INFO)
326
350
  printLog(
327
351
  `Participant status: ${prevStatus} => ${changedStatus} - Participant contribution step: ${prevContributionStep} => ${changedContributionStep}`,
328
- LogLevel.DEBUG
352
+ LogLevel.INFO
329
353
  )
330
354
 
331
355
  // Define pre-conditions.
@@ -346,8 +370,8 @@ export const coordinateCeremonyParticipant = functionsV1
346
370
 
347
371
  const participantCompletedContribution =
348
372
  prevContributionProgress === changedContributionProgress &&
349
- prevStatus === ParticipantStatus.CONTRIBUTING &&
350
- prevContributionStep === ParticipantContributionStep.VERIFYING &&
373
+ (prevStatus === ParticipantStatus.CONTRIBUTING ||
374
+ prevContributionStep === ParticipantContributionStep.VERIFYING) &&
351
375
  changedStatus === ParticipantStatus.CONTRIBUTED &&
352
376
  changedContributionStep === ParticipantContributionStep.COMPLETED
353
377
 
@@ -360,7 +384,7 @@ export const coordinateCeremonyParticipant = functionsV1
360
384
  // Step (2.A).
361
385
  printLog(
362
386
  `Participant is ready for first contribution (${participantReadyForFirstContribution}) or for the next contribution (${participantReadyForNextContribution}) or is resuming after a timeout expiration (${participantResumingContributionAfterTimeout})`,
363
- LogLevel.DEBUG
387
+ LogLevel.INFO
364
388
  )
365
389
 
366
390
  // Get the circuit.
@@ -374,7 +398,7 @@ export const coordinateCeremonyParticipant = functionsV1
374
398
  // Step (2.B).
375
399
  printLog(
376
400
  `Participant completed a contribution (${participantCompletedContribution}) or every contribution for each circuit (${participantCompletedEveryCircuitContribution})`,
377
- LogLevel.DEBUG
401
+ LogLevel.INFO
378
402
  )
379
403
 
380
404
  // Get the circuit.
@@ -387,7 +411,6 @@ export const coordinateCeremonyParticipant = functionsV1
387
411
  }
388
412
  })
389
413
 
390
-
391
414
  /**
392
415
  * Recursive function to check whether an EC2 is in a running state
393
416
  * @notice required step to run commands
@@ -396,23 +419,18 @@ export const coordinateCeremonyParticipant = functionsV1
396
419
  * @param attempts <number> - how many times to retry before failing
397
420
  * @returns <Promise<boolean>> - whether the VM was started
398
421
  */
399
- const checkIfVMRunning = async (
400
- ec2: EC2Client,
401
- vmInstanceId: string,
402
- attempts = 5
403
- ): Promise<boolean> => {
422
+ const checkIfVMRunning = async (ec2: EC2Client, vmInstanceId: string, attempts = 5): Promise<boolean> => {
404
423
  // if we tried 5 times, then throw an error
405
424
  if (attempts <= 0) logAndThrowError(SPECIFIC_ERRORS.SE_VM_NOT_RUNNING)
406
425
 
407
- await sleep(60000); // Wait for 1 min
408
- const isVMRunning = await checkIfRunning(ec2, vmInstanceId)
426
+ await sleep(60000) // Wait for 1 min
427
+ const isVMRunning = await checkIfRunning(ec2, vmInstanceId)
409
428
 
410
429
  if (!isVMRunning) {
411
430
  printLog(`VM not running, ${attempts - 1} attempts remaining. Retrying in 1 minute...`, LogLevel.DEBUG)
412
- return await checkIfVMRunning(ec2, vmInstanceId, attempts - 1)
413
- } else {
414
- return true
431
+ return checkIfVMRunning(ec2, vmInstanceId, attempts - 1)
415
432
  }
433
+ return true
416
434
  }
417
435
 
418
436
  /**
@@ -442,367 +460,391 @@ const checkIfVMRunning = async (
442
460
  * 2) Send all updates atomically to the Firestore database.
443
461
  */
444
462
  export const verifycontribution = functionsV2.https.onCall(
445
- { memory: "16GiB", timeoutSeconds: 3600, region: 'europe-west1' },
463
+ { memory: "32GiB", timeoutSeconds: 3600, region: "europe-west1", cpu: 8 },
446
464
  async (request: functionsV2.https.CallableRequest<VerifyContributionData>): Promise<any> => {
447
- if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
448
- logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER)
449
-
450
- if (
451
- !request.data.ceremonyId ||
452
- !request.data.circuitId ||
453
- !request.data.contributorOrCoordinatorIdentifier ||
454
- !request.data.bucketName
455
- )
456
- logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA)
457
-
458
- if (
459
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
460
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
461
- !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH
462
- )
463
- logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
464
-
465
- // Step (0).
466
-
467
- // Prepare and start timer.
468
- const verifyContributionTimer = new Timer({ label: commonTerms.cloudFunctionsNames.verifyContribution })
469
- verifyContributionTimer.start()
470
-
471
- // Get DB.
472
- const firestore = admin.firestore()
473
- // Prepare batch of txs.
474
- const batch = firestore.batch()
475
-
476
- // Extract data.
477
- const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data
478
- const userId = request.auth?.uid
479
-
480
- // Look for the ceremony, circuit and participant document.
481
- const ceremonyDoc = await getDocumentById(commonTerms.collections.ceremonies.name, ceremonyId)
482
- const circuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
483
- const participantDoc = await getDocumentById(getParticipantsCollectionPath(ceremonyId), userId!)
465
+ try {
466
+ if (!request.auth || (!request.auth.token.participant && !request.auth.token.coordinator))
467
+ logAndThrowError(SPECIFIC_ERRORS.SE_AUTH_NO_CURRENT_AUTH_USER)
468
+
469
+ if (
470
+ !request.data.ceremonyId ||
471
+ !request.data.circuitId ||
472
+ !request.data.contributorOrCoordinatorIdentifier ||
473
+ !request.data.bucketName
474
+ )
475
+ logAndThrowError(COMMON_ERRORS.CM_MISSING_OR_WRONG_INPUT_DATA)
484
476
 
485
- if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
486
- logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA)
477
+ if (
478
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME ||
479
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION ||
480
+ !process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH
481
+ )
482
+ logAndThrowError(COMMON_ERRORS.CM_WRONG_CONFIGURATION)
483
+
484
+ const BUCKET_NAME_REGEX = /^[a-z0-9][a-z0-9-]{1,61}[a-z0-9]$/
485
+ if (!BUCKET_NAME_REGEX.test(request.data.bucketName)) logAndThrowError(SPECIFIC_ERRORS.WRONG_BUCKET_NAME)
486
+
487
+ // Step (0).
488
+
489
+ // Prepare and start timer.
490
+ const verifyContributionTimer = new Timer({ label: commonTerms.cloudFunctionsNames.verifyContribution })
491
+ verifyContributionTimer.start()
492
+
493
+ // Get DB.
494
+ const firestore = admin.firestore()
495
+ // Prepare batch of txs.
496
+ const batch = firestore.batch()
497
+
498
+ // Extract data.
499
+ const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data
500
+ const userId = request.auth?.uid
501
+
502
+ // Look for the ceremony, circuit and participant document.
503
+ const ceremonyDoc = await getDocumentById(commonTerms.collections.ceremonies.name, ceremonyId)
504
+ const circuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
505
+ const participantDoc = await getDocumentById(getParticipantsCollectionPath(ceremonyId), userId!)
506
+
507
+ if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
508
+ logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA)
509
+
510
+ // Extract documents data.
511
+ const { state } = ceremonyDoc.data()!
512
+ const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data()!
513
+ const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data()!
514
+ const { completedContributions, failedContributions } = waitingQueue
515
+ const {
516
+ contributionComputation: avgContributionComputationTime,
517
+ fullContribution: avgFullContributionTime,
518
+ verifyCloudFunction: avgVerifyCloudFunctionTime
519
+ } = avgTimings
520
+ const { cfOrVm, vm } = verification
521
+ // we might not have it if the circuit is not using VM.
522
+ let vmInstanceId: string = ""
523
+ if (vm) vmInstanceId = vm.vmInstanceId
487
524
 
488
- // Extract documents data.
489
- const { state } = ceremonyDoc.data()!
490
- const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data()!
491
- const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data()!
492
- const { completedContributions, failedContributions } = waitingQueue
493
- const {
494
- contributionComputation: avgContributionComputationTime,
495
- fullContribution: avgFullContributionTime,
496
- verifyCloudFunction: avgVerifyCloudFunctionTime
497
- } = avgTimings
498
- const { cfOrVm, vm } = verification
499
- // we might not have it if the circuit is not using VM.
500
- let vmInstanceId: string = ""
501
- if (vm) vmInstanceId = vm.vmInstanceId
525
+ // Define pre-conditions.
526
+ const isFinalizing = state === CeremonyState.CLOSED && request.auth && request.auth.token.coordinator // true only when the coordinator verifies the final contributions.
527
+ const isContributing = status === ParticipantStatus.CONTRIBUTING
528
+ const isUsingVM = cfOrVm === CircuitContributionVerificationMechanism.VM && !!vmInstanceId
529
+
530
+ // Prepare state.
531
+ let isContributionValid = false
532
+ let verifyCloudFunctionExecutionTime = 0 // time spent while executing the verify contribution cloud function.
533
+ let verifyCloudFunctionTime = 0 // time spent while executing the core business logic of this cloud function.
534
+ let fullContributionTime = 0 // time spent while doing non-verification contributions tasks (download, compute, upload).
535
+ let contributionComputationTime = 0 // time spent while computing the contribution.
536
+ let lastZkeyBlake2bHash: string = "" // the Blake2B hash of the last zKey.
537
+ let verificationTranscriptTemporaryLocalPath: string = "" // the local temporary path for the verification transcript.
538
+ let transcriptBlake2bHash: string = "" // the Blake2B hash of the verification transcript.
539
+ let commandId: string = "" // the unique identifier of the VM command.
540
+
541
+ // Derive necessary data.
542
+ const lastZkeyIndex = formatZkeyIndex(completedContributions + 1)
543
+ const verificationTranscriptCompleteFilename = `${prefix}_${
544
+ isFinalizing
545
+ ? `${contributorOrCoordinatorIdentifier}_${finalContributionIndex}_verification_transcript.log`
546
+ : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`
547
+ }`
548
+
549
+ const lastZkeyFilename = `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`
550
+
551
+ // Prepare state for VM verification (if needed).
552
+ const ec2 = await createEC2Client()
553
+ const ssm = await createSSMClient()
554
+
555
+ // Step (1.A.1).
556
+ // Get storage paths.
557
+ const verificationTranscriptStoragePathAndFilename = getTranscriptStorageFilePath(
558
+ prefix,
559
+ verificationTranscriptCompleteFilename
560
+ )
561
+ // the zKey storage path is required to be sent to the VM api
562
+ const lastZkeyStoragePath = getZkeyStorageFilePath(
563
+ prefix,
564
+ `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`
565
+ )
502
566
 
503
- // Define pre-conditions.
504
- const isFinalizing = state === CeremonyState.CLOSED && request.auth && request.auth.token.coordinator // true only when the coordinator verifies the final contributions.
505
- const isContributing = status === ParticipantStatus.CONTRIBUTING
506
- const isUsingVM = cfOrVm === CircuitContributionVerificationMechanism.VM && !!vmInstanceId
507
-
508
- // Prepare state.
509
- let isContributionValid = false
510
- let verifyCloudFunctionExecutionTime = 0 // time spent while executing the verify contribution cloud function.
511
- let verifyCloudFunctionTime = 0 // time spent while executing the core business logic of this cloud function.
512
- let fullContributionTime = 0 // time spent while doing non-verification contributions tasks (download, compute, upload).
513
- let contributionComputationTime = 0 // time spent while computing the contribution.
514
- let lastZkeyBlake2bHash: string = "" // the Blake2B hash of the last zKey.
515
- let verificationTranscriptTemporaryLocalPath: string = "" // the local temporary path for the verification transcript.
516
- let transcriptBlake2bHash: string = "" // the Blake2B hash of the verification transcript.
517
- let commandId: string = "" // the unique identifier of the VM command.
518
-
519
- // Derive necessary data.
520
- const lastZkeyIndex = formatZkeyIndex(completedContributions + 1)
521
- const verificationTranscriptCompleteFilename = `${prefix}_${
522
- isFinalizing
523
- ? `${contributorOrCoordinatorIdentifier}_${finalContributionIndex}_verification_transcript.log`
524
- : `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`
525
- }`
526
-
527
- const lastZkeyFilename = `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`
528
-
529
- // Prepare state for VM verification (if needed).
530
- const ec2 = await createEC2Client()
531
- const ssm = await createSSMClient()
532
-
533
- // Step (1.A.1).
534
- // Get storage paths.
535
- const verificationTranscriptStoragePathAndFilename = getTranscriptStorageFilePath(
536
- prefix,
537
- verificationTranscriptCompleteFilename
538
- )
539
- // the zKey storage path is required to be sent to the VM api
540
- const lastZkeyStoragePath = getZkeyStorageFilePath(
541
- prefix,
542
- `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`
543
- )
567
+ const verificationTaskTimer = new Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` })
544
568
 
545
- const verificationTaskTimer = new Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` })
569
+ const dumpLog = async (path: string): Promise<void> => {
570
+ printLog(`transcript >>>>>>`, LogLevel.DEBUG)
571
+ try {
572
+ const data = await fs.promises.readFile(path, "utf8")
573
+ printLog(data, LogLevel.DEBUG)
574
+ } catch (readError: any) {
575
+ printLog(readError, LogLevel.ERROR)
576
+ }
577
+ }
546
578
 
547
- const completeVerification = async () => {
548
- // Stop verification task timer.
549
- printLog("Completing verification", LogLevel.DEBUG)
550
- verificationTaskTimer.stop()
551
- verifyCloudFunctionExecutionTime = verificationTaskTimer.ms()
579
+ const completeVerification = async () => {
580
+ // Stop verification task timer.
581
+ printLog("Completing verification", LogLevel.DEBUG)
582
+ verificationTaskTimer.stop()
583
+ verifyCloudFunctionExecutionTime = verificationTaskTimer.ms()
552
584
 
553
- if (isUsingVM) {
554
- // Create temporary path.
555
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(
556
- `${circuitId}_${participantDoc.id}.log`
557
- )
585
+ if (isUsingVM) {
586
+ // Create temporary path.
587
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(
588
+ `${circuitId}_${participantDoc.id}.log`
589
+ )
558
590
 
559
- await sleep(1000) // wait 1s for file creation.
591
+ await sleep(1000) // wait 1s for file creation.
560
592
 
561
- // Download from bucket.
562
- // nb. the transcript MUST be uploaded from the VM by verification commands.
563
- await downloadArtifactFromS3Bucket(
564
- bucketName,
565
- verificationTranscriptStoragePathAndFilename,
566
- verificationTranscriptTemporaryLocalPath
567
- )
593
+ // Download from bucket.
594
+ // nb. the transcript MUST be uploaded from the VM by verification commands.
595
+ await downloadArtifactFromS3Bucket(
596
+ bucketName,
597
+ verificationTranscriptStoragePathAndFilename,
598
+ verificationTranscriptTemporaryLocalPath
599
+ )
568
600
 
569
- // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
570
- const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8")
601
+ // Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
602
+ const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8")
571
603
 
572
- if (content.includes("ZKey Ok!")) isContributionValid = true
604
+ if (content.includes("ZKey Ok!")) isContributionValid = true
573
605
 
574
- // If the contribution is valid, then format and store the trascript.
575
- if (isContributionValid) {
576
- // eslint-disable-next-line no-control-regex
577
- const updated = content.replace(/\x1b[[0-9;]*m/g, "")
606
+ // If the contribution is valid, then format and store the trascript.
607
+ if (isContributionValid) {
608
+ // eslint-disable-next-line no-control-regex
609
+ const updated = content.replace(/\x1b[[0-9;]*m/g, "")
578
610
 
579
- fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated)
611
+ fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated)
612
+ }
580
613
  }
581
- }
582
-
583
- printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG)
584
-
585
- // Create a new contribution document.
586
- const contributionDoc = await firestore
587
- .collection(getContributionsCollectionPath(ceremonyId, circuitId))
588
- .doc()
589
- .get()
590
614
 
591
- // Step (1.A.4).
592
- if (isContributionValid) {
593
- // Sleep ~3 seconds to wait for verification transcription.
594
- await sleep(3000)
615
+ printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG)
595
616
 
596
- // Step (1.A.4.A.1).
597
- if (isUsingVM) {
598
- // Retrieve the contribution hash from the command output.
599
- lastZkeyBlake2bHash = await retrieveCommandOutput(ssm, vmInstanceId, commandId)
600
-
601
- const hashRegex = /[a-fA-F0-9]{64}/
602
- const match = lastZkeyBlake2bHash.match(hashRegex)!
617
+ // Create a new contribution document.
618
+ const contributionDoc = await firestore
619
+ .collection(getContributionsCollectionPath(ceremonyId, circuitId))
620
+ .doc()
621
+ .get()
603
622
 
604
- lastZkeyBlake2bHash = match.at(0)!
605
-
606
- // re upload the formatted verification transcript
607
- await uploadFileToBucket(
608
- bucketName,
609
- verificationTranscriptStoragePathAndFilename,
610
- verificationTranscriptTemporaryLocalPath,
611
- true
623
+ // Step (1.A.4).
624
+ if (isContributionValid) {
625
+ // Sleep ~3 seconds to wait for verification transcription.
626
+ await sleep(3000)
627
+
628
+ // Step (1.A.4.A.1).
629
+ if (isUsingVM) {
630
+ // Retrieve the contribution hash from the command output.
631
+ lastZkeyBlake2bHash = await retrieveCommandOutput(ssm, vmInstanceId, commandId)
632
+
633
+ const hashRegex = /[a-fA-F0-9]{64}/
634
+ const match = lastZkeyBlake2bHash.match(hashRegex)!
635
+
636
+ lastZkeyBlake2bHash = match.at(0)!
637
+
638
+ // re upload the formatted verification transcript
639
+ await uploadFileToBucket(
640
+ bucketName,
641
+ verificationTranscriptStoragePathAndFilename,
642
+ verificationTranscriptTemporaryLocalPath,
643
+ true
644
+ )
645
+ } else {
646
+ // Upload verification transcript.
647
+ /// nb. do not use multi-part upload here due to small file size.
648
+ await uploadFileToBucket(
649
+ bucketName,
650
+ verificationTranscriptStoragePathAndFilename,
651
+ verificationTranscriptTemporaryLocalPath,
652
+ true
653
+ )
654
+ }
655
+
656
+ // Compute verification transcript hash.
657
+ transcriptBlake2bHash = await blake512FromPath(verificationTranscriptTemporaryLocalPath)
658
+
659
+ // Free resources by unlinking transcript temporary file.
660
+ fs.unlinkSync(verificationTranscriptTemporaryLocalPath)
661
+
662
+ // Filter participant contributions to find the data related to the one verified.
663
+ const participantContributions = contributions.filter(
664
+ (contribution: Contribution) =>
665
+ !!contribution.hash && !!contribution.computationTime && !contribution.doc
612
666
  )
613
667
 
668
+ /// @dev (there must be only one contribution with an empty 'doc' field).
669
+ if (participantContributions.length !== 1)
670
+ logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA)
671
+
672
+ // Get contribution computation time.
673
+ contributionComputationTime = contributions.at(0).computationTime
674
+
675
+ // Step (1.A.4.A.2).
676
+ batch.create(contributionDoc.ref, {
677
+ participantId: participantDoc.id,
678
+ contributionComputationTime,
679
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
680
+ zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
681
+ files: {
682
+ transcriptFilename: verificationTranscriptCompleteFilename,
683
+ lastZkeyFilename,
684
+ transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
685
+ lastZkeyStoragePath,
686
+ transcriptBlake2bHash,
687
+ lastZkeyBlake2bHash
688
+ },
689
+ verificationSoftware: {
690
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
691
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
692
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
693
+ },
694
+ valid: isContributionValid,
695
+ lastUpdated: getCurrentServerTimestampInMillis()
696
+ })
697
+
698
+ verifyContributionTimer.stop()
699
+ verifyCloudFunctionTime = verifyContributionTimer.ms()
614
700
  } else {
615
- // Upload verification transcript.
616
- /// nb. do not use multi-part upload here due to small file size.
617
- await uploadFileToBucket(
618
- bucketName,
619
- verificationTranscriptStoragePathAndFilename,
620
- verificationTranscriptTemporaryLocalPath,
621
- true
622
- )
701
+ // Step (1.A.4.B).
702
+
703
+ // Free-up storage by deleting invalid contribution.
704
+ await deleteObject(bucketName, lastZkeyStoragePath)
705
+
706
+ // Step (1.A.4.B.1).
707
+ batch.create(contributionDoc.ref, {
708
+ participantId: participantDoc.id,
709
+ verificationComputationTime: verifyCloudFunctionExecutionTime,
710
+ zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
711
+ verificationSoftware: {
712
+ name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
713
+ version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
714
+ commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
715
+ },
716
+ valid: isContributionValid,
717
+ lastUpdated: getCurrentServerTimestampInMillis()
718
+ })
623
719
  }
624
720
 
625
- // Compute verification transcript hash.
626
- transcriptBlake2bHash = await blake512FromPath(verificationTranscriptTemporaryLocalPath)
721
+ // Stop VM instance
722
+ if (isUsingVM) {
723
+ // using try and catch as the VM stopping function can throw
724
+ // however we want to continue without stopping as the
725
+ // verification was valid, and inform the coordinator
726
+ try {
727
+ await stopEC2Instance(ec2, vmInstanceId)
728
+ } catch (error: any) {
729
+ printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN)
730
+ }
731
+ }
732
+ // Step (1.A.4.C)
733
+ if (!isFinalizing) {
734
+ // Step (1.A.4.C.1)
735
+ // Compute new average contribution/verification time.
736
+ fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt)
737
+
738
+ const newAvgContributionComputationTime =
739
+ avgContributionComputationTime > 0
740
+ ? (avgContributionComputationTime + contributionComputationTime) / 2
741
+ : contributionComputationTime
742
+ const newAvgFullContributionTime =
743
+ avgFullContributionTime > 0
744
+ ? (avgFullContributionTime + fullContributionTime) / 2
745
+ : fullContributionTime
746
+ const newAvgVerifyCloudFunctionTime =
747
+ avgVerifyCloudFunctionTime > 0
748
+ ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
749
+ : verifyCloudFunctionTime
750
+
751
+ // Prepare tx to update circuit average contribution/verification time.
752
+ const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
753
+ const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data()!
754
+ /// @dev this must happen only for valid contributions.
755
+ batch.update(circuitDoc.ref, {
756
+ avgTimings: {
757
+ contributionComputation: isContributionValid
758
+ ? newAvgContributionComputationTime
759
+ : avgContributionComputationTime,
760
+ fullContribution: isContributionValid
761
+ ? newAvgFullContributionTime
762
+ : avgFullContributionTime,
763
+ verifyCloudFunction: isContributionValid
764
+ ? newAvgVerifyCloudFunctionTime
765
+ : avgVerifyCloudFunctionTime
766
+ },
767
+ waitingQueue: {
768
+ ...updatedWaitingQueue,
769
+ completedContributions: isContributionValid
770
+ ? completedContributions + 1
771
+ : completedContributions,
772
+ failedContributions: isContributionValid ? failedContributions : failedContributions + 1
773
+ },
774
+ lastUpdated: getCurrentServerTimestampInMillis()
775
+ })
776
+ }
627
777
 
628
- // Free resources by unlinking transcript temporary file.
629
- fs.unlinkSync(verificationTranscriptTemporaryLocalPath)
778
+ // Step (2).
779
+ await batch.commit()
630
780
 
631
- // Filter participant contributions to find the data related to the one verified.
632
- const participantContributions = contributions.filter(
633
- (contribution: Contribution) =>
634
- !!contribution.hash && !!contribution.computationTime && !contribution.doc
781
+ printLog(
782
+ `The contribution #${
783
+ isFinalizing ? finalContributionIndex : lastZkeyIndex
784
+ } of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${
785
+ isContributionValid ? "valid" : "invalid"
786
+ } for the participant ${participantDoc.id}`,
787
+ LogLevel.INFO
635
788
  )
636
-
637
- /// @dev (there must be only one contribution with an empty 'doc' field).
638
- if (participantContributions.length !== 1)
639
- logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA)
640
-
641
- // Get contribution computation time.
642
- contributionComputationTime = contributions.at(0).computationTime
643
-
644
- // Step (1.A.4.A.2).
645
- batch.create(contributionDoc.ref, {
646
- participantId: participantDoc.id,
647
- contributionComputationTime,
648
- verificationComputationTime: verifyCloudFunctionExecutionTime,
649
- zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
650
- files: {
651
- transcriptFilename: verificationTranscriptCompleteFilename,
652
- lastZkeyFilename,
653
- transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
654
- lastZkeyStoragePath,
655
- transcriptBlake2bHash,
656
- lastZkeyBlake2bHash
657
- },
658
- verificationSoftware: {
659
- name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
660
- version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
661
- commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
662
- },
663
- valid: isContributionValid,
664
- lastUpdated: getCurrentServerTimestampInMillis()
665
- })
666
-
667
- verifyContributionTimer.stop()
668
- verifyCloudFunctionTime = verifyContributionTimer.ms()
669
- } else {
670
- // Step (1.A.4.B).
671
-
672
- // Free-up storage by deleting invalid contribution.
673
- await deleteObject(bucketName, lastZkeyStoragePath)
674
-
675
- // Step (1.A.4.B.1).
676
- batch.create(contributionDoc.ref, {
677
- participantId: participantDoc.id,
678
- verificationComputationTime: verifyCloudFunctionExecutionTime,
679
- zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
680
- verificationSoftware: {
681
- name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
682
- version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
683
- commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
684
- },
685
- valid: isContributionValid,
686
- lastUpdated: getCurrentServerTimestampInMillis()
687
- })
688
- }
689
-
690
- // Stop VM instance
691
- if (isUsingVM) await stopEC2Instance(ec2, vmInstanceId)
692
-
693
- // Step (1.A.4.C)
694
- if (!isFinalizing) {
695
- // Step (1.A.4.C.1)
696
- // Compute new average contribution/verification time.
697
- fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt)
698
-
699
- const newAvgContributionComputationTime =
700
- avgContributionComputationTime > 0
701
- ? (avgContributionComputationTime + contributionComputationTime) / 2
702
- : contributionComputationTime
703
- const newAvgFullContributionTime =
704
- avgFullContributionTime > 0
705
- ? (avgFullContributionTime + fullContributionTime) / 2
706
- : fullContributionTime
707
- const newAvgVerifyCloudFunctionTime =
708
- avgVerifyCloudFunctionTime > 0
709
- ? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
710
- : verifyCloudFunctionTime
711
-
712
- // Prepare tx to update circuit average contribution/verification time.
713
- const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
714
- const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data()!
715
- /// @dev this must happen only for valid contributions.
716
- batch.update(circuitDoc.ref, {
717
- avgTimings: {
718
- contributionComputation: isContributionValid
719
- ? newAvgContributionComputationTime
720
- : avgContributionComputationTime,
721
- fullContribution: isContributionValid ? newAvgFullContributionTime : avgFullContributionTime,
722
- verifyCloudFunction: isContributionValid
723
- ? newAvgVerifyCloudFunctionTime
724
- : avgVerifyCloudFunctionTime
725
- },
726
- waitingQueue: {
727
- ...updatedWaitingQueue,
728
- completedContributions: isContributionValid
729
- ? completedContributions + 1
730
- : completedContributions,
731
- failedContributions: isContributionValid ? failedContributions : failedContributions + 1
732
- },
733
- lastUpdated: getCurrentServerTimestampInMillis()
734
- })
735
789
  }
736
790
 
737
- // Step (2).
738
- await batch.commit()
791
+ // Step (1).
792
+ if (isContributing || isFinalizing) {
793
+ // Prepare timer.
794
+ verificationTaskTimer.start()
739
795
 
740
- printLog(
741
- `The contribution #${
742
- isFinalizing ? finalContributionIndex : lastZkeyIndex
743
- } of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${
744
- isContributionValid ? "valid" : "invalid"
745
- } for the participant ${participantDoc.id}`,
746
- LogLevel.DEBUG
747
- )
748
- }
749
-
750
- // Step (1).
751
- if (isContributing || isFinalizing) {
752
- // Prepare timer.
753
- verificationTaskTimer.start()
796
+ // Step (1.A.3.0).
797
+ if (isUsingVM) {
798
+ printLog(`Starting the VM mechanism`, LogLevel.DEBUG)
754
799
 
755
- // Step (1.A.3.0).
756
- if (isUsingVM) {
757
- printLog(`Starting the VM mechanism`, LogLevel.DEBUG)
800
+ // Prepare for VM execution.
801
+ let isVMRunning = false // true when the VM is up, otherwise false.
758
802
 
759
- // Prepare for VM execution.
760
- let isVMRunning = false // true when the VM is up, otherwise false.
803
+ // Step (1.A.3.1).
804
+ await startEC2Instance(ec2, vmInstanceId)
761
805
 
762
- // Step (1.A.3.1).
763
- await startEC2Instance(ec2, vmInstanceId)
806
+ await sleep(60000) // nb. wait for VM startup (1 mins + retry).
764
807
 
765
- await sleep(60000) // nb. wait for VM startup (1 mins + retry).
808
+ // Check if the startup is running.
809
+ isVMRunning = await checkIfVMRunning(ec2, vmInstanceId)
766
810
 
767
- // Check if the startup is running.
768
- isVMRunning = await checkIfVMRunning(ec2, vmInstanceId)
811
+ printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG)
769
812
 
770
- printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG)
813
+ // Step (1.A.3.2).
814
+ // Prepare.
815
+ const verificationCommand = vmContributionVerificationCommand(
816
+ bucketName,
817
+ lastZkeyStoragePath,
818
+ verificationTranscriptStoragePathAndFilename
819
+ )
771
820
 
772
- // Step (1.A.3.2).
773
- // Prepare.
774
- const verificationCommand = vmContributionVerificationCommand(
775
- bucketName,
776
- lastZkeyStoragePath,
777
- verificationTranscriptStoragePathAndFilename
778
- )
821
+ // Run.
822
+ commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand)
779
823
 
780
- // Run.
781
- commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand)
824
+ printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG)
782
825
 
783
- printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG)
826
+ // Step (1.A.3.3).
827
+ return await waitForVMCommandExecution(ssm, vmInstanceId, commandId)
828
+ .then(async () => {
829
+ // Command execution successfully completed.
830
+ printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG)
831
+ await completeVerification()
832
+ })
833
+ .catch((error: any) => {
834
+ // Command execution aborted.
835
+ printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.WARN)
784
836
 
785
- // Step (1.A.3.3).
786
- return new Promise<void>((resolve, reject) =>
787
- waitForVMCommandExecution(resolve, reject, ssm, vmInstanceId, commandId)
788
- )
789
- .then(async () => {
790
- // Command execution successfully completed.
791
- printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG)
792
- await completeVerification()
793
- })
794
- .catch((error: any) => {
795
- // Command execution aborted.
796
- printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.DEBUG)
837
+ logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
838
+ })
839
+ }
797
840
 
798
- logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
799
- })
800
- } else {
801
841
  // CF approach.
802
842
  printLog(`CF mechanism`, LogLevel.DEBUG)
803
843
 
804
844
  const potStoragePath = getPotStorageFilePath(files.potFilename)
805
845
  const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`)
846
+ printLog(`pot file: ${potStoragePath}`, LogLevel.DEBUG)
847
+ printLog(`zkey file: ${firstZkeyStoragePath}`, LogLevel.DEBUG)
806
848
  // Prepare temporary file paths.
807
849
  // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
808
850
  verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(
@@ -811,6 +853,9 @@ export const verifycontribution = functionsV2.https.onCall(
811
853
  const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`)
812
854
  const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`)
813
855
  const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`)
856
+ printLog(`pot file: ${potTempFilePath}`, LogLevel.DEBUG)
857
+ printLog(`firstZkey file: ${firstZkeyTempFilePath}`, LogLevel.DEBUG)
858
+ printLog(`last zkey file: ${lastZkeyTempFilePath}`, LogLevel.DEBUG)
814
859
 
815
860
  // Create and populate transcript.
816
861
  const transcriptLogger = createCustomLoggerForFile(verificationTranscriptTemporaryLocalPath)
@@ -834,7 +879,9 @@ export const verifycontribution = functionsV2.https.onCall(
834
879
  lastZkeyTempFilePath,
835
880
  transcriptLogger
836
881
  )
837
-
882
+
883
+ await dumpLog(verificationTranscriptTemporaryLocalPath)
884
+
838
885
  // Compute contribution hash.
839
886
  lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath)
840
887
 
@@ -846,10 +893,15 @@ export const verifycontribution = functionsV2.https.onCall(
846
893
  fs.unlinkSync(lastZkeyTempFilePath)
847
894
  } catch (error: any) {
848
895
  printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN)
849
- }
896
+ }
850
897
 
851
898
  await completeVerification()
852
899
  }
900
+
901
+ return null
902
+ } catch (error: any) {
903
+ logAndThrowError(makeError("unknown", error))
904
+ return null
853
905
  }
854
906
  }
855
907
  )
@@ -860,9 +912,9 @@ export const verifycontribution = functionsV2.https.onCall(
860
912
  * this does not happen if the participant is actually the coordinator who is finalizing the ceremony.
861
913
  */
862
914
  export const refreshParticipantAfterContributionVerification = functionsV1
863
- .region('europe-west1')
915
+ .region("europe-west1")
864
916
  .runWith({
865
- memory: "512MB"
917
+ memory: "1GB"
866
918
  })
867
919
  .firestore.document(
868
920
  `/${commonTerms.collections.ceremonies.name}/{ceremony}/${commonTerms.collections.circuits.name}/{circuit}/${commonTerms.collections.contributions.name}/{contributions}`
@@ -932,8 +984,8 @@ export const refreshParticipantAfterContributionVerification = functionsV1
932
984
  await batch.commit()
933
985
 
934
986
  printLog(
935
- `Participant ${participantId} refreshed after contribution ${createdContribution.id} - The participant was finalizing the ceremony ${isFinalizing}`,
936
- LogLevel.DEBUG
987
+ `Participant ${participantId} refreshed after contribution ${createdContribution.id} - The participant was finalizing the ceremony? ${isFinalizing}`,
988
+ LogLevel.INFO
937
989
  )
938
990
  })
939
991
 
@@ -943,9 +995,9 @@ export const refreshParticipantAfterContributionVerification = functionsV1
943
995
  * and verification key extracted from the circuit final contribution (as part of the ceremony finalization process).
944
996
  */
945
997
  export const finalizeCircuit = functionsV1
946
- .region('europe-west1')
998
+ .region("europe-west1")
947
999
  .runWith({
948
- memory: "512MB"
1000
+ memory: "1GB"
949
1001
  })
950
1002
  .https.onCall(async (data: FinalizeCircuitData, context: functionsV1.https.CallableContext) => {
951
1003
  if (!context.auth || !context.auth.token.coordinator) logAndThrowError(COMMON_ERRORS.CM_NOT_COORDINATOR_ROLE)