@devtion/backend 0.0.0-92056fa → 0.0.0-9239207
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.
- package/README.md +7 -7
- package/dist/src/functions/index.js +626 -337
- package/dist/src/functions/index.mjs +629 -342
- package/dist/types/functions/bandada.d.ts +4 -0
- package/dist/types/functions/bandada.d.ts.map +1 -0
- package/dist/types/functions/ceremony.d.ts.map +1 -1
- package/dist/types/functions/circuit.d.ts.map +1 -1
- package/dist/types/functions/index.d.ts +2 -0
- package/dist/types/functions/index.d.ts.map +1 -1
- package/dist/types/functions/siwe.d.ts +4 -0
- package/dist/types/functions/siwe.d.ts.map +1 -0
- package/dist/types/functions/storage.d.ts.map +1 -1
- package/dist/types/functions/timeout.d.ts.map +1 -1
- package/dist/types/functions/user.d.ts.map +1 -1
- package/dist/types/lib/errors.d.ts +2 -1
- package/dist/types/lib/errors.d.ts.map +1 -1
- package/dist/types/lib/services.d.ts +7 -0
- package/dist/types/lib/services.d.ts.map +1 -1
- package/dist/types/lib/utils.d.ts.map +1 -1
- package/dist/types/types/index.d.ts +56 -0
- package/dist/types/types/index.d.ts.map +1 -1
- package/package.json +4 -3
- package/src/functions/bandada.ts +155 -0
- package/src/functions/ceremony.ts +12 -7
- package/src/functions/circuit.ts +408 -382
- package/src/functions/index.ts +2 -0
- package/src/functions/participant.ts +15 -15
- package/src/functions/siwe.ts +77 -0
- package/src/functions/storage.ts +11 -8
- package/src/functions/timeout.ts +7 -5
- package/src/functions/user.ts +22 -12
- package/src/lib/errors.ts +6 -1
- package/src/lib/services.ts +36 -0
- package/src/lib/utils.ts +10 -8
- package/src/types/declarations.d.ts +1 -0
- package/src/types/index.ts +60 -0
package/src/functions/circuit.ts
CHANGED
|
@@ -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
|
|
|
@@ -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
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
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
|
+
}
|
|
236
267
|
|
|
237
|
-
|
|
238
|
-
|
|
268
|
+
if (error) {
|
|
269
|
+
logAndThrowError(error)
|
|
270
|
+
}
|
|
271
|
+
} catch (error: any) {
|
|
272
|
+
printLog(`Invalid command ${commandId} execution`, LogLevel.DEBUG)
|
|
239
273
|
|
|
240
|
-
|
|
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)
|
|
274
|
+
const ec2 = await createEC2Client()
|
|
257
275
|
|
|
258
|
-
|
|
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 (error: any) {
|
|
280
|
+
printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN)
|
|
281
|
+
}
|
|
259
282
|
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
283
|
+
if (!error.toString().includes(commandId)) logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
|
|
284
|
+
|
|
285
|
+
// Reject the promise.
|
|
286
|
+
reject()
|
|
287
|
+
}
|
|
265
288
|
}
|
|
266
|
-
|
|
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(
|
|
313
|
+
.region("europe-west1")
|
|
290
314
|
.runWith({
|
|
291
|
-
memory: "
|
|
315
|
+
memory: "1GB"
|
|
292
316
|
})
|
|
293
317
|
.firestore.document(
|
|
294
318
|
`${commonTerms.collections.ceremonies.name}/{ceremonyId}/${commonTerms.collections.participants.name}/{participantId}`
|
|
@@ -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)
|
|
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
|
|
413
|
-
} else {
|
|
414
|
-
return true
|
|
431
|
+
return checkIfVMRunning(ec2, vmInstanceId, attempts - 1)
|
|
415
432
|
}
|
|
433
|
+
return true
|
|
416
434
|
}
|
|
417
435
|
|
|
418
436
|
/**
|
|
@@ -442,361 +460,369 @@ 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:
|
|
463
|
+
{ memory: "16GiB", timeoutSeconds: 3600, region: "europe-west1" },
|
|
446
464
|
async (request: functionsV2.https.CallableRequest<VerifyContributionData>): Promise<any> => {
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
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!)
|
|
484
|
-
|
|
485
|
-
if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
|
|
486
|
-
logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA)
|
|
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)
|
|
487
476
|
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
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
|
+
// Step (0).
|
|
485
|
+
|
|
486
|
+
// Prepare and start timer.
|
|
487
|
+
const verifyContributionTimer = new Timer({ label: commonTerms.cloudFunctionsNames.verifyContribution })
|
|
488
|
+
verifyContributionTimer.start()
|
|
489
|
+
|
|
490
|
+
// Get DB.
|
|
491
|
+
const firestore = admin.firestore()
|
|
492
|
+
// Prepare batch of txs.
|
|
493
|
+
const batch = firestore.batch()
|
|
494
|
+
|
|
495
|
+
// Extract data.
|
|
496
|
+
const { ceremonyId, circuitId, contributorOrCoordinatorIdentifier, bucketName } = request.data
|
|
497
|
+
const userId = request.auth?.uid
|
|
498
|
+
|
|
499
|
+
// Look for the ceremony, circuit and participant document.
|
|
500
|
+
const ceremonyDoc = await getDocumentById(commonTerms.collections.ceremonies.name, ceremonyId)
|
|
501
|
+
const circuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
|
|
502
|
+
const participantDoc = await getDocumentById(getParticipantsCollectionPath(ceremonyId), userId!)
|
|
503
|
+
|
|
504
|
+
if (!ceremonyDoc.data() || !circuitDoc.data() || !participantDoc.data())
|
|
505
|
+
logAndThrowError(COMMON_ERRORS.CM_INEXISTENT_DOCUMENT_DATA)
|
|
506
|
+
|
|
507
|
+
// Extract documents data.
|
|
508
|
+
const { state } = ceremonyDoc.data()!
|
|
509
|
+
const { status, contributions, verificationStartedAt, contributionStartedAt } = participantDoc.data()!
|
|
510
|
+
const { waitingQueue, prefix, avgTimings, verification, files } = circuitDoc.data()!
|
|
511
|
+
const { completedContributions, failedContributions } = waitingQueue
|
|
512
|
+
const {
|
|
513
|
+
contributionComputation: avgContributionComputationTime,
|
|
514
|
+
fullContribution: avgFullContributionTime,
|
|
515
|
+
verifyCloudFunction: avgVerifyCloudFunctionTime
|
|
516
|
+
} = avgTimings
|
|
517
|
+
const { cfOrVm, vm } = verification
|
|
518
|
+
// we might not have it if the circuit is not using VM.
|
|
519
|
+
let vmInstanceId: string = ""
|
|
520
|
+
if (vm) vmInstanceId = vm.vmInstanceId
|
|
502
521
|
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
522
|
+
// Define pre-conditions.
|
|
523
|
+
const isFinalizing = state === CeremonyState.CLOSED && request.auth && request.auth.token.coordinator // true only when the coordinator verifies the final contributions.
|
|
524
|
+
const isContributing = status === ParticipantStatus.CONTRIBUTING
|
|
525
|
+
const isUsingVM = cfOrVm === CircuitContributionVerificationMechanism.VM && !!vmInstanceId
|
|
526
|
+
|
|
527
|
+
// Prepare state.
|
|
528
|
+
let isContributionValid = false
|
|
529
|
+
let verifyCloudFunctionExecutionTime = 0 // time spent while executing the verify contribution cloud function.
|
|
530
|
+
let verifyCloudFunctionTime = 0 // time spent while executing the core business logic of this cloud function.
|
|
531
|
+
let fullContributionTime = 0 // time spent while doing non-verification contributions tasks (download, compute, upload).
|
|
532
|
+
let contributionComputationTime = 0 // time spent while computing the contribution.
|
|
533
|
+
let lastZkeyBlake2bHash: string = "" // the Blake2B hash of the last zKey.
|
|
534
|
+
let verificationTranscriptTemporaryLocalPath: string = "" // the local temporary path for the verification transcript.
|
|
535
|
+
let transcriptBlake2bHash: string = "" // the Blake2B hash of the verification transcript.
|
|
536
|
+
let commandId: string = "" // the unique identifier of the VM command.
|
|
537
|
+
|
|
538
|
+
// Derive necessary data.
|
|
539
|
+
const lastZkeyIndex = formatZkeyIndex(completedContributions + 1)
|
|
540
|
+
const verificationTranscriptCompleteFilename = `${prefix}_${
|
|
541
|
+
isFinalizing
|
|
542
|
+
? `${contributorOrCoordinatorIdentifier}_${finalContributionIndex}_verification_transcript.log`
|
|
543
|
+
: `${lastZkeyIndex}_${contributorOrCoordinatorIdentifier}_verification_transcript.log`
|
|
544
|
+
}`
|
|
545
|
+
|
|
546
|
+
const lastZkeyFilename = `${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`
|
|
547
|
+
|
|
548
|
+
// Prepare state for VM verification (if needed).
|
|
549
|
+
const ec2 = await createEC2Client()
|
|
550
|
+
const ssm = await createSSMClient()
|
|
551
|
+
|
|
552
|
+
// Step (1.A.1).
|
|
553
|
+
// Get storage paths.
|
|
554
|
+
const verificationTranscriptStoragePathAndFilename = getTranscriptStorageFilePath(
|
|
555
|
+
prefix,
|
|
556
|
+
verificationTranscriptCompleteFilename
|
|
557
|
+
)
|
|
558
|
+
// the zKey storage path is required to be sent to the VM api
|
|
559
|
+
const lastZkeyStoragePath = getZkeyStorageFilePath(
|
|
560
|
+
prefix,
|
|
561
|
+
`${prefix}_${isFinalizing ? finalContributionIndex : lastZkeyIndex}.zkey`
|
|
562
|
+
)
|
|
544
563
|
|
|
545
|
-
|
|
564
|
+
const verificationTaskTimer = new Timer({ label: `${ceremonyId}-${circuitId}-${participantDoc.id}` })
|
|
546
565
|
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
566
|
+
const completeVerification = async () => {
|
|
567
|
+
// Stop verification task timer.
|
|
568
|
+
printLog("Completing verification", LogLevel.DEBUG)
|
|
569
|
+
verificationTaskTimer.stop()
|
|
570
|
+
verifyCloudFunctionExecutionTime = verificationTaskTimer.ms()
|
|
552
571
|
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
572
|
+
if (isUsingVM) {
|
|
573
|
+
// Create temporary path.
|
|
574
|
+
verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(
|
|
575
|
+
`${circuitId}_${participantDoc.id}.log`
|
|
576
|
+
)
|
|
558
577
|
|
|
559
|
-
|
|
578
|
+
await sleep(1000) // wait 1s for file creation.
|
|
560
579
|
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
580
|
+
// Download from bucket.
|
|
581
|
+
// nb. the transcript MUST be uploaded from the VM by verification commands.
|
|
582
|
+
await downloadArtifactFromS3Bucket(
|
|
583
|
+
bucketName,
|
|
584
|
+
verificationTranscriptStoragePathAndFilename,
|
|
585
|
+
verificationTranscriptTemporaryLocalPath
|
|
586
|
+
)
|
|
568
587
|
|
|
569
|
-
|
|
570
|
-
|
|
588
|
+
// Read the verification trascript and validate data by checking for core info ("ZKey Ok!").
|
|
589
|
+
const content = fs.readFileSync(verificationTranscriptTemporaryLocalPath, "utf-8")
|
|
571
590
|
|
|
572
|
-
|
|
591
|
+
if (content.includes("ZKey Ok!")) isContributionValid = true
|
|
573
592
|
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
593
|
+
// If the contribution is valid, then format and store the trascript.
|
|
594
|
+
if (isContributionValid) {
|
|
595
|
+
// eslint-disable-next-line no-control-regex
|
|
596
|
+
const updated = content.replace(/\x1b[[0-9;]*m/g, "")
|
|
578
597
|
|
|
579
|
-
|
|
598
|
+
fs.writeFileSync(verificationTranscriptTemporaryLocalPath, updated)
|
|
599
|
+
}
|
|
580
600
|
}
|
|
581
|
-
}
|
|
582
|
-
|
|
583
|
-
printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG)
|
|
584
601
|
|
|
585
|
-
|
|
586
|
-
const contributionDoc = await firestore
|
|
587
|
-
.collection(getContributionsCollectionPath(ceremonyId, circuitId))
|
|
588
|
-
.doc()
|
|
589
|
-
.get()
|
|
590
|
-
|
|
591
|
-
// Step (1.A.4).
|
|
592
|
-
if (isContributionValid) {
|
|
593
|
-
// Sleep ~3 seconds to wait for verification transcription.
|
|
594
|
-
await sleep(3000)
|
|
595
|
-
|
|
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)
|
|
602
|
+
printLog(`The contribution has been verified - Result ${isContributionValid}`, LogLevel.DEBUG)
|
|
600
603
|
|
|
601
|
-
|
|
602
|
-
|
|
604
|
+
// Create a new contribution document.
|
|
605
|
+
const contributionDoc = await firestore
|
|
606
|
+
.collection(getContributionsCollectionPath(ceremonyId, circuitId))
|
|
607
|
+
.doc()
|
|
608
|
+
.get()
|
|
603
609
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
//
|
|
607
|
-
await
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
610
|
+
// Step (1.A.4).
|
|
611
|
+
if (isContributionValid) {
|
|
612
|
+
// Sleep ~3 seconds to wait for verification transcription.
|
|
613
|
+
await sleep(3000)
|
|
614
|
+
|
|
615
|
+
// Step (1.A.4.A.1).
|
|
616
|
+
if (isUsingVM) {
|
|
617
|
+
// Retrieve the contribution hash from the command output.
|
|
618
|
+
lastZkeyBlake2bHash = await retrieveCommandOutput(ssm, vmInstanceId, commandId)
|
|
619
|
+
|
|
620
|
+
const hashRegex = /[a-fA-F0-9]{64}/
|
|
621
|
+
const match = lastZkeyBlake2bHash.match(hashRegex)!
|
|
622
|
+
|
|
623
|
+
lastZkeyBlake2bHash = match.at(0)!
|
|
624
|
+
|
|
625
|
+
// re upload the formatted verification transcript
|
|
626
|
+
await uploadFileToBucket(
|
|
627
|
+
bucketName,
|
|
628
|
+
verificationTranscriptStoragePathAndFilename,
|
|
629
|
+
verificationTranscriptTemporaryLocalPath,
|
|
630
|
+
true
|
|
631
|
+
)
|
|
632
|
+
} else {
|
|
633
|
+
// Upload verification transcript.
|
|
634
|
+
/// nb. do not use multi-part upload here due to small file size.
|
|
635
|
+
await uploadFileToBucket(
|
|
636
|
+
bucketName,
|
|
637
|
+
verificationTranscriptStoragePathAndFilename,
|
|
638
|
+
verificationTranscriptTemporaryLocalPath,
|
|
639
|
+
true
|
|
640
|
+
)
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
// Compute verification transcript hash.
|
|
644
|
+
transcriptBlake2bHash = await blake512FromPath(verificationTranscriptTemporaryLocalPath)
|
|
645
|
+
|
|
646
|
+
// Free resources by unlinking transcript temporary file.
|
|
647
|
+
fs.unlinkSync(verificationTranscriptTemporaryLocalPath)
|
|
648
|
+
|
|
649
|
+
// Filter participant contributions to find the data related to the one verified.
|
|
650
|
+
const participantContributions = contributions.filter(
|
|
651
|
+
(contribution: Contribution) =>
|
|
652
|
+
!!contribution.hash && !!contribution.computationTime && !contribution.doc
|
|
612
653
|
)
|
|
613
654
|
|
|
614
|
-
|
|
615
|
-
|
|
655
|
+
/// @dev (there must be only one contribution with an empty 'doc' field).
|
|
656
|
+
if (participantContributions.length !== 1)
|
|
657
|
+
logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA)
|
|
658
|
+
|
|
659
|
+
// Get contribution computation time.
|
|
660
|
+
contributionComputationTime = contributions.at(0).computationTime
|
|
661
|
+
|
|
662
|
+
// Step (1.A.4.A.2).
|
|
663
|
+
batch.create(contributionDoc.ref, {
|
|
664
|
+
participantId: participantDoc.id,
|
|
665
|
+
contributionComputationTime,
|
|
666
|
+
verificationComputationTime: verifyCloudFunctionExecutionTime,
|
|
667
|
+
zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
|
|
668
|
+
files: {
|
|
669
|
+
transcriptFilename: verificationTranscriptCompleteFilename,
|
|
670
|
+
lastZkeyFilename,
|
|
671
|
+
transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
|
|
672
|
+
lastZkeyStoragePath,
|
|
673
|
+
transcriptBlake2bHash,
|
|
674
|
+
lastZkeyBlake2bHash
|
|
675
|
+
},
|
|
676
|
+
verificationSoftware: {
|
|
677
|
+
name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
|
|
678
|
+
version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
|
|
679
|
+
commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
|
|
680
|
+
},
|
|
681
|
+
valid: isContributionValid,
|
|
682
|
+
lastUpdated: getCurrentServerTimestampInMillis()
|
|
683
|
+
})
|
|
684
|
+
|
|
685
|
+
verifyContributionTimer.stop()
|
|
686
|
+
verifyCloudFunctionTime = verifyContributionTimer.ms()
|
|
616
687
|
} else {
|
|
617
|
-
//
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
688
|
+
// Step (1.A.4.B).
|
|
689
|
+
|
|
690
|
+
// Free-up storage by deleting invalid contribution.
|
|
691
|
+
await deleteObject(bucketName, lastZkeyStoragePath)
|
|
692
|
+
|
|
693
|
+
// Step (1.A.4.B.1).
|
|
694
|
+
batch.create(contributionDoc.ref, {
|
|
695
|
+
participantId: participantDoc.id,
|
|
696
|
+
verificationComputationTime: verifyCloudFunctionExecutionTime,
|
|
697
|
+
zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
|
|
698
|
+
verificationSoftware: {
|
|
699
|
+
name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
|
|
700
|
+
version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
|
|
701
|
+
commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
|
|
702
|
+
},
|
|
703
|
+
valid: isContributionValid,
|
|
704
|
+
lastUpdated: getCurrentServerTimestampInMillis()
|
|
705
|
+
})
|
|
625
706
|
}
|
|
626
707
|
|
|
627
|
-
//
|
|
628
|
-
|
|
708
|
+
// Stop VM instance
|
|
709
|
+
if (isUsingVM) {
|
|
710
|
+
// using try and catch as the VM stopping function can throw
|
|
711
|
+
// however we want to continue without stopping as the
|
|
712
|
+
// verification was valid, and inform the coordinator
|
|
713
|
+
try {
|
|
714
|
+
await stopEC2Instance(ec2, vmInstanceId)
|
|
715
|
+
} catch (error: any) {
|
|
716
|
+
printLog(`Error while stopping VM instance ${vmInstanceId} - Error ${error}`, LogLevel.WARN)
|
|
717
|
+
}
|
|
718
|
+
}
|
|
719
|
+
// Step (1.A.4.C)
|
|
720
|
+
if (!isFinalizing) {
|
|
721
|
+
// Step (1.A.4.C.1)
|
|
722
|
+
// Compute new average contribution/verification time.
|
|
723
|
+
fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt)
|
|
724
|
+
|
|
725
|
+
const newAvgContributionComputationTime =
|
|
726
|
+
avgContributionComputationTime > 0
|
|
727
|
+
? (avgContributionComputationTime + contributionComputationTime) / 2
|
|
728
|
+
: contributionComputationTime
|
|
729
|
+
const newAvgFullContributionTime =
|
|
730
|
+
avgFullContributionTime > 0
|
|
731
|
+
? (avgFullContributionTime + fullContributionTime) / 2
|
|
732
|
+
: fullContributionTime
|
|
733
|
+
const newAvgVerifyCloudFunctionTime =
|
|
734
|
+
avgVerifyCloudFunctionTime > 0
|
|
735
|
+
? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
|
|
736
|
+
: verifyCloudFunctionTime
|
|
737
|
+
|
|
738
|
+
// Prepare tx to update circuit average contribution/verification time.
|
|
739
|
+
const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
|
|
740
|
+
const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data()!
|
|
741
|
+
/// @dev this must happen only for valid contributions.
|
|
742
|
+
batch.update(circuitDoc.ref, {
|
|
743
|
+
avgTimings: {
|
|
744
|
+
contributionComputation: isContributionValid
|
|
745
|
+
? newAvgContributionComputationTime
|
|
746
|
+
: avgContributionComputationTime,
|
|
747
|
+
fullContribution: isContributionValid ? newAvgFullContributionTime : avgFullContributionTime,
|
|
748
|
+
verifyCloudFunction: isContributionValid
|
|
749
|
+
? newAvgVerifyCloudFunctionTime
|
|
750
|
+
: avgVerifyCloudFunctionTime
|
|
751
|
+
},
|
|
752
|
+
waitingQueue: {
|
|
753
|
+
...updatedWaitingQueue,
|
|
754
|
+
completedContributions: isContributionValid
|
|
755
|
+
? completedContributions + 1
|
|
756
|
+
: completedContributions,
|
|
757
|
+
failedContributions: isContributionValid ? failedContributions : failedContributions + 1
|
|
758
|
+
},
|
|
759
|
+
lastUpdated: getCurrentServerTimestampInMillis()
|
|
760
|
+
})
|
|
761
|
+
}
|
|
629
762
|
|
|
630
|
-
//
|
|
631
|
-
|
|
763
|
+
// Step (2).
|
|
764
|
+
await batch.commit()
|
|
632
765
|
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
766
|
+
printLog(
|
|
767
|
+
`The contribution #${
|
|
768
|
+
isFinalizing ? finalContributionIndex : lastZkeyIndex
|
|
769
|
+
} of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${
|
|
770
|
+
isContributionValid ? "valid" : "invalid"
|
|
771
|
+
} for the participant ${participantDoc.id}`,
|
|
772
|
+
LogLevel.DEBUG
|
|
637
773
|
)
|
|
638
|
-
|
|
639
|
-
/// @dev (there must be only one contribution with an empty 'doc' field).
|
|
640
|
-
if (participantContributions.length !== 1)
|
|
641
|
-
logAndThrowError(SPECIFIC_ERRORS.SE_VERIFICATION_NO_PARTICIPANT_CONTRIBUTION_DATA)
|
|
642
|
-
|
|
643
|
-
// Get contribution computation time.
|
|
644
|
-
contributionComputationTime = contributions.at(0).computationTime
|
|
645
|
-
|
|
646
|
-
// Step (1.A.4.A.2).
|
|
647
|
-
batch.create(contributionDoc.ref, {
|
|
648
|
-
participantId: participantDoc.id,
|
|
649
|
-
contributionComputationTime,
|
|
650
|
-
verificationComputationTime: verifyCloudFunctionExecutionTime,
|
|
651
|
-
zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
|
|
652
|
-
files: {
|
|
653
|
-
transcriptFilename: verificationTranscriptCompleteFilename,
|
|
654
|
-
lastZkeyFilename,
|
|
655
|
-
transcriptStoragePath: verificationTranscriptStoragePathAndFilename,
|
|
656
|
-
lastZkeyStoragePath,
|
|
657
|
-
transcriptBlake2bHash,
|
|
658
|
-
lastZkeyBlake2bHash
|
|
659
|
-
},
|
|
660
|
-
verificationSoftware: {
|
|
661
|
-
name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
|
|
662
|
-
version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
|
|
663
|
-
commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
|
|
664
|
-
},
|
|
665
|
-
valid: isContributionValid,
|
|
666
|
-
lastUpdated: getCurrentServerTimestampInMillis()
|
|
667
|
-
})
|
|
668
|
-
|
|
669
|
-
verifyContributionTimer.stop()
|
|
670
|
-
verifyCloudFunctionTime = verifyContributionTimer.ms()
|
|
671
|
-
} else {
|
|
672
|
-
// Step (1.A.4.B).
|
|
673
|
-
|
|
674
|
-
// Free-up storage by deleting invalid contribution.
|
|
675
|
-
await deleteObject(bucketName, lastZkeyStoragePath)
|
|
676
|
-
|
|
677
|
-
// Step (1.A.4.B.1).
|
|
678
|
-
batch.create(contributionDoc.ref, {
|
|
679
|
-
participantId: participantDoc.id,
|
|
680
|
-
verificationComputationTime: verifyCloudFunctionExecutionTime,
|
|
681
|
-
zkeyIndex: isFinalizing ? finalContributionIndex : lastZkeyIndex,
|
|
682
|
-
verificationSoftware: {
|
|
683
|
-
name: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_NAME),
|
|
684
|
-
version: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_VERSION),
|
|
685
|
-
commitHash: String(process.env.CUSTOM_CONTRIBUTION_VERIFICATION_SOFTWARE_COMMIT_HASH)
|
|
686
|
-
},
|
|
687
|
-
valid: isContributionValid,
|
|
688
|
-
lastUpdated: getCurrentServerTimestampInMillis()
|
|
689
|
-
})
|
|
690
|
-
}
|
|
691
|
-
|
|
692
|
-
// Step (1.A.4.C)
|
|
693
|
-
if (!isFinalizing) {
|
|
694
|
-
// Step (1.A.4.C.1)
|
|
695
|
-
// Compute new average contribution/verification time.
|
|
696
|
-
fullContributionTime = Number(verificationStartedAt) - Number(contributionStartedAt)
|
|
697
|
-
|
|
698
|
-
const newAvgContributionComputationTime =
|
|
699
|
-
avgContributionComputationTime > 0
|
|
700
|
-
? (avgContributionComputationTime + contributionComputationTime) / 2
|
|
701
|
-
: contributionComputationTime
|
|
702
|
-
const newAvgFullContributionTime =
|
|
703
|
-
avgFullContributionTime > 0
|
|
704
|
-
? (avgFullContributionTime + fullContributionTime) / 2
|
|
705
|
-
: fullContributionTime
|
|
706
|
-
const newAvgVerifyCloudFunctionTime =
|
|
707
|
-
avgVerifyCloudFunctionTime > 0
|
|
708
|
-
? (avgVerifyCloudFunctionTime + verifyCloudFunctionTime) / 2
|
|
709
|
-
: verifyCloudFunctionTime
|
|
710
|
-
|
|
711
|
-
// Prepare tx to update circuit average contribution/verification time.
|
|
712
|
-
const updatedCircuitDoc = await getDocumentById(getCircuitsCollectionPath(ceremonyId), circuitId)
|
|
713
|
-
const { waitingQueue: updatedWaitingQueue } = updatedCircuitDoc.data()!
|
|
714
|
-
/// @dev this must happen only for valid contributions.
|
|
715
|
-
batch.update(circuitDoc.ref, {
|
|
716
|
-
avgTimings: {
|
|
717
|
-
contributionComputation: isContributionValid
|
|
718
|
-
? newAvgContributionComputationTime
|
|
719
|
-
: avgContributionComputationTime,
|
|
720
|
-
fullContribution: isContributionValid ? newAvgFullContributionTime : avgFullContributionTime,
|
|
721
|
-
verifyCloudFunction: isContributionValid
|
|
722
|
-
? newAvgVerifyCloudFunctionTime
|
|
723
|
-
: avgVerifyCloudFunctionTime
|
|
724
|
-
},
|
|
725
|
-
waitingQueue: {
|
|
726
|
-
...updatedWaitingQueue,
|
|
727
|
-
completedContributions: isContributionValid
|
|
728
|
-
? completedContributions + 1
|
|
729
|
-
: completedContributions,
|
|
730
|
-
failedContributions: isContributionValid ? failedContributions : failedContributions + 1
|
|
731
|
-
},
|
|
732
|
-
lastUpdated: getCurrentServerTimestampInMillis()
|
|
733
|
-
})
|
|
734
774
|
}
|
|
735
775
|
|
|
736
|
-
// Step (
|
|
737
|
-
|
|
776
|
+
// Step (1).
|
|
777
|
+
if (isContributing || isFinalizing) {
|
|
778
|
+
// Prepare timer.
|
|
779
|
+
verificationTaskTimer.start()
|
|
738
780
|
|
|
739
|
-
|
|
740
|
-
|
|
741
|
-
|
|
742
|
-
} of circuit ${circuitId} (ceremony ${ceremonyId}) has been verified as ${
|
|
743
|
-
isContributionValid ? "valid" : "invalid"
|
|
744
|
-
} for the participant ${participantDoc.id}`,
|
|
745
|
-
LogLevel.DEBUG
|
|
746
|
-
)
|
|
747
|
-
}
|
|
748
|
-
|
|
749
|
-
// Step (1).
|
|
750
|
-
if (isContributing || isFinalizing) {
|
|
751
|
-
// Prepare timer.
|
|
752
|
-
verificationTaskTimer.start()
|
|
781
|
+
// Step (1.A.3.0).
|
|
782
|
+
if (isUsingVM) {
|
|
783
|
+
printLog(`Starting the VM mechanism`, LogLevel.DEBUG)
|
|
753
784
|
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
printLog(`Starting the VM mechanism`, LogLevel.DEBUG)
|
|
785
|
+
// Prepare for VM execution.
|
|
786
|
+
let isVMRunning = false // true when the VM is up, otherwise false.
|
|
757
787
|
|
|
758
|
-
|
|
759
|
-
|
|
788
|
+
// Step (1.A.3.1).
|
|
789
|
+
await startEC2Instance(ec2, vmInstanceId)
|
|
760
790
|
|
|
761
|
-
|
|
762
|
-
await startEC2Instance(ec2, vmInstanceId)
|
|
791
|
+
await sleep(60000) // nb. wait for VM startup (1 mins + retry).
|
|
763
792
|
|
|
764
|
-
|
|
793
|
+
// Check if the startup is running.
|
|
794
|
+
isVMRunning = await checkIfVMRunning(ec2, vmInstanceId)
|
|
765
795
|
|
|
766
|
-
|
|
767
|
-
isVMRunning = await checkIfVMRunning(ec2, vmInstanceId)
|
|
796
|
+
printLog(`VM running: ${isVMRunning}`, LogLevel.DEBUG)
|
|
768
797
|
|
|
769
|
-
|
|
798
|
+
// Step (1.A.3.2).
|
|
799
|
+
// Prepare.
|
|
800
|
+
const verificationCommand = vmContributionVerificationCommand(
|
|
801
|
+
bucketName,
|
|
802
|
+
lastZkeyStoragePath,
|
|
803
|
+
verificationTranscriptStoragePathAndFilename
|
|
804
|
+
)
|
|
770
805
|
|
|
771
|
-
|
|
772
|
-
|
|
773
|
-
const verificationCommand = vmContributionVerificationCommand(
|
|
774
|
-
bucketName,
|
|
775
|
-
lastZkeyStoragePath,
|
|
776
|
-
verificationTranscriptStoragePathAndFilename
|
|
777
|
-
)
|
|
806
|
+
// Run.
|
|
807
|
+
commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand)
|
|
778
808
|
|
|
779
|
-
|
|
780
|
-
commandId = await runCommandUsingSSM(ssm, vmInstanceId, verificationCommand)
|
|
809
|
+
printLog(`Starting the execution of command ${commandId}`, LogLevel.DEBUG)
|
|
781
810
|
|
|
782
|
-
|
|
811
|
+
// Step (1.A.3.3).
|
|
812
|
+
return waitForVMCommandExecution(ssm, vmInstanceId, commandId)
|
|
813
|
+
.then(async () => {
|
|
814
|
+
// Command execution successfully completed.
|
|
815
|
+
printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG)
|
|
816
|
+
await completeVerification()
|
|
817
|
+
})
|
|
818
|
+
.catch((error: any) => {
|
|
819
|
+
// Command execution aborted.
|
|
820
|
+
printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.DEBUG)
|
|
783
821
|
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
)
|
|
788
|
-
.then(async () => {
|
|
789
|
-
// Command execution successfully completed.
|
|
790
|
-
printLog(`Command ${commandId} execution has been successfully completed`, LogLevel.DEBUG)
|
|
791
|
-
await completeVerification()
|
|
792
|
-
})
|
|
793
|
-
.catch((error: any) => {
|
|
794
|
-
// Command execution aborted.
|
|
795
|
-
printLog(`Command ${commandId} execution has been aborted - Error ${error}`, LogLevel.DEBUG)
|
|
822
|
+
logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
|
|
823
|
+
})
|
|
824
|
+
}
|
|
796
825
|
|
|
797
|
-
logAndThrowError(COMMON_ERRORS.CM_INVALID_COMMAND_EXECUTION)
|
|
798
|
-
})
|
|
799
|
-
} else {
|
|
800
826
|
// CF approach.
|
|
801
827
|
printLog(`CF mechanism`, LogLevel.DEBUG)
|
|
802
828
|
|
|
@@ -804,9 +830,7 @@ export const verifycontribution = functionsV2.https.onCall(
|
|
|
804
830
|
const firstZkeyStoragePath = getZkeyStorageFilePath(prefix, `${prefix}_${genesisZkeyIndex}.zkey`)
|
|
805
831
|
// Prepare temporary file paths.
|
|
806
832
|
// (nb. these are needed to download the necessary artifacts for verification from AWS S3).
|
|
807
|
-
verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(
|
|
808
|
-
verificationTranscriptCompleteFilename
|
|
809
|
-
)
|
|
833
|
+
verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath(verificationTranscriptCompleteFilename)
|
|
810
834
|
const potTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}.pot`)
|
|
811
835
|
const firstZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_genesis.zkey`)
|
|
812
836
|
const lastZkeyTempFilePath = createTemporaryLocalPath(`${circuitId}_${participantDoc.id}_last.zkey`)
|
|
@@ -833,7 +857,7 @@ export const verifycontribution = functionsV2.https.onCall(
|
|
|
833
857
|
lastZkeyTempFilePath,
|
|
834
858
|
transcriptLogger
|
|
835
859
|
)
|
|
836
|
-
|
|
860
|
+
|
|
837
861
|
// Compute contribution hash.
|
|
838
862
|
lastZkeyBlake2bHash = await blake512FromPath(lastZkeyTempFilePath)
|
|
839
863
|
|
|
@@ -845,11 +869,13 @@ export const verifycontribution = functionsV2.https.onCall(
|
|
|
845
869
|
fs.unlinkSync(lastZkeyTempFilePath)
|
|
846
870
|
} catch (error: any) {
|
|
847
871
|
printLog(`Error while unlinking temporary files - Error ${error}`, LogLevel.WARN)
|
|
848
|
-
}
|
|
872
|
+
}
|
|
849
873
|
|
|
850
874
|
await completeVerification()
|
|
851
875
|
}
|
|
852
|
-
}
|
|
876
|
+
} catch (error: any) {
|
|
877
|
+
logAndThrowError(makeError("unknown", error))
|
|
878
|
+
}
|
|
853
879
|
}
|
|
854
880
|
)
|
|
855
881
|
|
|
@@ -859,9 +885,9 @@ export const verifycontribution = functionsV2.https.onCall(
|
|
|
859
885
|
* this does not happen if the participant is actually the coordinator who is finalizing the ceremony.
|
|
860
886
|
*/
|
|
861
887
|
export const refreshParticipantAfterContributionVerification = functionsV1
|
|
862
|
-
.region(
|
|
888
|
+
.region("europe-west1")
|
|
863
889
|
.runWith({
|
|
864
|
-
memory: "
|
|
890
|
+
memory: "1GB"
|
|
865
891
|
})
|
|
866
892
|
.firestore.document(
|
|
867
893
|
`/${commonTerms.collections.ceremonies.name}/{ceremony}/${commonTerms.collections.circuits.name}/{circuit}/${commonTerms.collections.contributions.name}/{contributions}`
|
|
@@ -942,9 +968,9 @@ export const refreshParticipantAfterContributionVerification = functionsV1
|
|
|
942
968
|
* and verification key extracted from the circuit final contribution (as part of the ceremony finalization process).
|
|
943
969
|
*/
|
|
944
970
|
export const finalizeCircuit = functionsV1
|
|
945
|
-
.region(
|
|
971
|
+
.region("europe-west1")
|
|
946
972
|
.runWith({
|
|
947
|
-
memory: "
|
|
973
|
+
memory: "1GB"
|
|
948
974
|
})
|
|
949
975
|
.https.onCall(async (data: FinalizeCircuitData, context: functionsV1.https.CallableContext) => {
|
|
950
976
|
if (!context.auth || !context.auth.token.coordinator) logAndThrowError(COMMON_ERRORS.CM_NOT_COORDINATOR_ROLE)
|