@@ -58,6 +58,7 @@ import {
58
58
uploadFileToBucket
59
59
} from "../lib/utils"
60
60
import { EC2Client } from "@aws-sdk/client-ec2"
61
+ import { HttpsError } from "firebase-functions/v2/https"
61
62
62
63
dotenv . config ( )
63
64
@@ -214,57 +215,71 @@ 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 )
236
-
237
- if ( cmdStatus === CommandInvocationStatus . SUCCESS ) {
238
- printLog ( `Command ${ commandId } successfully completed` , LogLevel . DEBUG )
239
-
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 )
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
+ }
257
267
258
- if ( ! error . toString ( ) . includes ( commandId ) ) logAndThrowError ( COMMON_ERRORS . CM_INVALID_COMMAND_EXECUTION )
268
+ if ( error ) {
269
+ logAndThrowError ( error )
270
+ }
271
+ } catch ( error : any ) {
272
+ printLog ( `Invalid command ${ commandId } execution` , LogLevel . DEBUG )
273
+
274
+ if ( ! error . toString ( ) . includes ( commandId ) ) logAndThrowError ( COMMON_ERRORS . CM_INVALID_COMMAND_EXECUTION )
259
275
260
- // Reject the promise.
261
- reject ( )
262
- } finally {
263
- // Clear the interval.
264
- clearInterval ( interval )
276
+ // Reject the promise.
277
+ reject ( )
278
+ }
265
279
}
266
- } , 60000 ) // 1 minute.
267
- }
280
+
281
+ setTimeout ( poll , 60000 ) ;
282
+ } )
268
283
269
284
/**
270
285
* This method is used to coordinate the waiting queues of ceremony circuits.
@@ -783,9 +798,7 @@ export const verifycontribution = functionsV2.https.onCall(
783
798
printLog ( `Starting the execution of command ${ commandId } ` , LogLevel . DEBUG )
784
799
785
800
// Step (1.A.3.3).
786
- return new Promise < void > ( ( resolve , reject ) =>
787
- waitForVMCommandExecution ( resolve , reject , ssm , vmInstanceId , commandId )
788
- )
801
+ return waitForVMCommandExecution ( ssm , vmInstanceId , commandId )
789
802
. then ( async ( ) => {
790
803
// Command execution successfully completed.
791
804
printLog ( `Command ${ commandId } execution has been successfully completed` , LogLevel . DEBUG )
@@ -797,59 +810,59 @@ export const verifycontribution = functionsV2.https.onCall(
797
810
798
811
logAndThrowError ( COMMON_ERRORS . CM_INVALID_COMMAND_EXECUTION )
799
812
} )
800
- } else {
801
- // CF approach.
802
- printLog ( `CF mechanism` , LogLevel . DEBUG )
813
+ }
803
814
804
- const potStoragePath = getPotStorageFilePath ( files . potFilename )
805
- const firstZkeyStoragePath = getZkeyStorageFilePath ( prefix , `${ prefix } _${ genesisZkeyIndex } .zkey` )
806
- // Prepare temporary file paths.
807
- // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
808
- verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath (
809
- verificationTranscriptCompleteFilename
810
- )
811
- const potTempFilePath = createTemporaryLocalPath ( `${ circuitId } _${ participantDoc . id } .pot` )
812
- const firstZkeyTempFilePath = createTemporaryLocalPath ( `${ circuitId } _${ participantDoc . id } _genesis.zkey` )
813
- const lastZkeyTempFilePath = createTemporaryLocalPath ( `${ circuitId } _${ participantDoc . id } _last.zkey` )
814
-
815
- // Create and populate transcript.
816
- const transcriptLogger = createCustomLoggerForFile ( verificationTranscriptTemporaryLocalPath )
817
- transcriptLogger . info (
818
- `${
819
- isFinalizing ? `Final verification` : `Verification`
820
- } transcript for ${ prefix } circuit Phase 2 contribution.\n${
821
- isFinalizing ? `Coordinator ` : `Contributor # ${ Number ( lastZkeyIndex ) } `
822
- } (${ contributorOrCoordinatorIdentifier } )\n`
823
- )
815
+ // CF approach.
816
+ printLog ( `CF mechanism` , LogLevel . DEBUG )
824
817
825
- // Step (1.A.2).
826
- await downloadArtifactFromS3Bucket ( bucketName , potStoragePath , potTempFilePath )
827
- await downloadArtifactFromS3Bucket ( bucketName , firstZkeyStoragePath , firstZkeyTempFilePath )
828
- await downloadArtifactFromS3Bucket ( bucketName , lastZkeyStoragePath , lastZkeyTempFilePath )
829
-
830
- // Step (1.A.4).
831
- isContributionValid = await zKey . verifyFromInit (
832
- firstZkeyTempFilePath ,
833
- potTempFilePath ,
834
- lastZkeyTempFilePath ,
835
- transcriptLogger
836
- )
837
-
838
- // Compute contribution hash.
839
- lastZkeyBlake2bHash = await blake512FromPath ( lastZkeyTempFilePath )
840
-
841
- // Free resources by unlinking temporary folders.
842
- // Do not free-up verification transcript path here.
843
- try {
844
- fs . unlinkSync ( potTempFilePath )
845
- fs . unlinkSync ( firstZkeyTempFilePath )
846
- fs . unlinkSync ( lastZkeyTempFilePath )
847
- } catch ( error : any ) {
848
- printLog ( `Error while unlinking temporary files - Error ${ error } ` , LogLevel . WARN )
849
- }
850
-
851
- await completeVerification ( )
852
- }
818
+ const potStoragePath = getPotStorageFilePath ( files . potFilename )
819
+ const firstZkeyStoragePath = getZkeyStorageFilePath ( prefix , `${ prefix } _${ genesisZkeyIndex } .zkey` )
820
+ // Prepare temporary file paths.
821
+ // (nb. these are needed to download the necessary artifacts for verification from AWS S3).
822
+ verificationTranscriptTemporaryLocalPath = createTemporaryLocalPath (
823
+ verificationTranscriptCompleteFilename
824
+ )
825
+ const potTempFilePath = createTemporaryLocalPath ( `${ circuitId } _${ participantDoc . id } .pot` )
826
+ const firstZkeyTempFilePath = createTemporaryLocalPath ( `${ circuitId } _${ participantDoc . id } _genesis.zkey` )
827
+ const lastZkeyTempFilePath = createTemporaryLocalPath ( `${ circuitId } _${ participantDoc . id } _last.zkey` )
828
+
829
+ // Create and populate transcript.
830
+ const transcriptLogger = createCustomLoggerForFile ( verificationTranscriptTemporaryLocalPath )
831
+ transcriptLogger . info (
832
+ `${
833
+ isFinalizing ? `Final verification` : `Verification`
834
+ } transcript for ${ prefix } circuit Phase 2 contribution.\n${
835
+ isFinalizing ? `Coordinator ` : `Contributor # ${ Number ( lastZkeyIndex ) } `
836
+ } (${ contributorOrCoordinatorIdentifier } )\n`
837
+ )
838
+
839
+ // Step (1.A.2).
840
+ await downloadArtifactFromS3Bucket ( bucketName , potStoragePath , potTempFilePath )
841
+ await downloadArtifactFromS3Bucket ( bucketName , firstZkeyStoragePath , firstZkeyTempFilePath )
842
+ await downloadArtifactFromS3Bucket ( bucketName , lastZkeyStoragePath , lastZkeyTempFilePath )
843
+
844
+ // Step (1.A.4).
845
+ isContributionValid = await zKey . verifyFromInit (
846
+ firstZkeyTempFilePath ,
847
+ potTempFilePath ,
848
+ lastZkeyTempFilePath ,
849
+ transcriptLogger
850
+ )
851
+
852
+ // Compute contribution hash.
853
+ lastZkeyBlake2bHash = await blake512FromPath ( lastZkeyTempFilePath )
854
+
855
+ // Free resources by unlinking temporary folders.
856
+ // Do not free-up verification transcript path here.
857
+ try {
858
+ fs . unlinkSync ( potTempFilePath )
859
+ fs . unlinkSync ( firstZkeyTempFilePath )
860
+ fs . unlinkSync ( lastZkeyTempFilePath )
861
+ } catch ( error : any ) {
862
+ printLog ( `Error while unlinking temporary files - Error ${ error } ` , LogLevel . WARN )
863
+ }
864
+
865
+ await completeVerification ( )
853
866
}
854
867
}
855
868
)
0 commit comments