@devtion/actions 0.0.0-270e9e0 → 0.0.0-2ed8e18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,18 +1,18 @@
1
1
  import { Firestore } from "firebase/firestore"
2
- import fs, { ReadPosition } from "fs"
2
+ import fs, { ReadPosition, createWriteStream } from "fs"
3
3
  import { utils as ffUtils } from "ffjavascript"
4
4
  import winston, { Logger } from "winston"
5
- import { S3Client, GetObjectCommand, HeadObjectCommand } from "@aws-sdk/client-s3"
6
- import {
7
- CircuitMetadata,
8
- Contribution,
9
- CircuitDocument,
5
+ import fetch from "@adobe/node-fetch-retry"
6
+ import {
7
+ CircuitMetadata,
8
+ Contribution,
9
+ CircuitDocument,
10
10
  CircuitInputData,
11
- ContributionValidity,
12
- FirebaseDocumentInfo,
13
- SetupCeremonyData,
11
+ ContributionValidity,
12
+ FirebaseDocumentInfo,
13
+ SetupCeremonyData,
14
14
  CeremonySetupTemplate,
15
- CeremonySetupTemplateCircuitArtifacts,
15
+ CeremonySetupTemplateCircuitArtifacts
16
16
  } from "../types/index"
17
17
  import { finalContributionIndex, genesisZkeyIndex, potFilenameTemplate } from "./constants"
18
18
  import {
@@ -22,14 +22,14 @@ import {
22
22
  getContributionsCollectionPath
23
23
  } from "./database"
24
24
  import { CeremonyTimeoutType } from "../types/enums"
25
- import {
26
- getPotStorageFilePath,
27
- getR1csStorageFilePath,
28
- getWasmStorageFilePath,
25
+ import {
26
+ getPotStorageFilePath,
27
+ getR1csStorageFilePath,
28
+ getWasmStorageFilePath,
29
29
  getZkeyStorageFilePath
30
30
  } from "./storage"
31
31
  import { blake512FromPath } from "./crypto"
32
- import { Readable, pipeline } from "stream"
32
+ import { pipeline } from "stream"
33
33
  import { promisify } from "util"
34
34
 
35
35
  /**
@@ -41,23 +41,29 @@ import { promisify } from "util"
41
41
  */
42
42
  export const parseCeremonyFile = async (path: string, cleanup: boolean = false): Promise<SetupCeremonyData> => {
43
43
  // check that the path exists
44
- if (!fs.existsSync(path)) throw new Error("The provided path to the configuration file does not exist. Please provide an absolute path and try again.")
45
-
44
+ if (!fs.existsSync(path))
45
+ throw new Error(
46
+ "The provided path to the configuration file does not exist. Please provide an absolute path and try again."
47
+ )
48
+
46
49
  try {
47
50
  // read the data
48
51
  const data: CeremonySetupTemplate = JSON.parse(fs.readFileSync(path).toString())
49
52
 
50
53
  // verify that the data is correct
51
- if (data['timeoutMechanismType'] !== CeremonyTimeoutType.DYNAMIC && data['timeoutMechanismType'] !== CeremonyTimeoutType.FIXED)
54
+ if (
55
+ data["timeoutMechanismType"] !== CeremonyTimeoutType.DYNAMIC &&
56
+ data["timeoutMechanismType"] !== CeremonyTimeoutType.FIXED
57
+ )
52
58
  throw new Error("Invalid timeout type. Please choose between DYNAMIC and FIXED.")
53
-
59
+
54
60
  // validate that we have at least 1 circuit input data
55
- if (!data.circuits || data.circuits.length === 0)
61
+ if (!data.circuits || data.circuits.length === 0)
56
62
  throw new Error("You need to provide the data for at least 1 circuit.")
57
63
 
58
64
  // validate that the end date is in the future
59
- let endDate: Date
60
- let startDate: Date
65
+ let endDate: Date
66
+ let startDate: Date
61
67
  try {
62
68
  endDate = new Date(data.endDate)
63
69
  startDate = new Date(data.startDate)
@@ -66,12 +72,12 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
66
72
  }
67
73
 
68
74
  if (endDate <= startDate) throw new Error("The end date should be greater than the start date.")
69
-
75
+
70
76
  const currentDate = new Date()
71
77
 
72
- if (endDate <= currentDate || startDate <= currentDate)
78
+ if (endDate <= currentDate || startDate <= currentDate)
73
79
  throw new Error("The start and end dates should be in the future.")
74
-
80
+
75
81
  // validate penalty
76
82
  if (data.penalty <= 0) throw new Error("The penalty should be greater than zero.")
77
83
 
@@ -87,58 +93,49 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
87
93
  circuitArtifacts.push({
88
94
  artifacts: artifacts
89
95
  })
90
- const r1csPath = artifacts.r1csStoragePath
91
- const wasmPath = artifacts.wasmStoragePath
92
96
 
93
97
  // where we storing the r1cs downloaded
94
98
  const localR1csPath = `./${circuitData.name}.r1cs`
95
-
96
- // check that the artifacts exist in S3
97
- // we don't need any privileges to download this
98
- // just the correct region
99
- const s3 = new S3Client({region: artifacts.region})
100
-
101
- try {
102
- await s3.send(new HeadObjectCommand({
103
- Bucket: artifacts.bucket,
104
- Key: r1csPath
105
- }))
106
- } catch (error: any) {
107
- throw new Error(`The r1cs file (${r1csPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`)
108
- }
109
-
110
- try {
111
- await s3.send(new HeadObjectCommand({
112
- Bucket: artifacts.bucket,
113
- Key: wasmPath
114
- }))
115
- } catch (error: any) {
116
- throw new Error(`The wasm file (${wasmPath}) seems to not exist. Please ensure this is correct and that the object is publicly available.`)
117
- }
99
+ // where we storing the wasm downloaded
100
+ const localWasmPath = `./${circuitData.name}.wasm`
118
101
 
119
102
  // download the r1cs to extract the metadata
120
- const command = new GetObjectCommand({ Bucket: artifacts.bucket, Key: artifacts.r1csStoragePath })
121
- const response = await s3.send(command)
122
103
  const streamPipeline = promisify(pipeline)
123
104
 
124
- if (response.$metadata.httpStatusCode !== 200)
125
- throw new Error("There was an error while trying to download the r1cs file. Please check that the file has the correct permissions (public) set.")
105
+ // Make the call.
106
+ const responseR1CS = await fetch(artifacts.r1csStoragePath)
107
+
108
+ // Handle errors.
109
+ if (!responseR1CS.ok && responseR1CS.status !== 200)
110
+ throw new Error(
111
+ `There was an error while trying to download the r1cs file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`
112
+ )
113
+
114
+ await streamPipeline(responseR1CS.body!, createWriteStream(localR1csPath))
115
+ // Write the file locally
126
116
 
127
- if (response.Body instanceof Readable)
128
- await streamPipeline(response.Body, fs.createWriteStream(localR1csPath))
129
-
130
117
  // extract the metadata from the r1cs
131
118
  const metadata = getR1CSInfo(localR1csPath)
132
119
 
120
+ // download wasm too to ensure it's available
121
+ const responseWASM = await fetch(artifacts.wasmStoragePath)
122
+ if (!responseWASM.ok && responseWASM.status !== 200)
123
+ throw new Error(
124
+ `There was an error while trying to download the WASM file for circuit ${circuitData.name}. Please check that the file has the correct permissions (public) set.`
125
+ )
126
+ await streamPipeline(responseWASM.body!, createWriteStream(localWasmPath))
127
+
133
128
  // validate that the circuit hash and template links are valid
134
129
  const template = circuitData.template
135
130
 
136
131
  const URLMatch = template.source.match(urlPattern)
137
- if (!URLMatch || URLMatch.length === 0 || URLMatch.length > 1) throw new Error("You should provide the URL to the circuits templates on GitHub.")
132
+ if (!URLMatch || URLMatch.length === 0 || URLMatch.length > 1)
133
+ throw new Error("You should provide the URL to the circuits templates on GitHub.")
138
134
 
139
135
  const hashMatch = template.commitHash.match(commitHashPattern)
140
- if (!hashMatch || hashMatch.length === 0 || hashMatch.length > 1) throw new Error("You should provide a valid commit hash of the circuit templates.")
141
-
136
+ if (!hashMatch || hashMatch.length === 0 || hashMatch.length > 1)
137
+ throw new Error("You should provide a valid commit hash of the circuit templates.")
138
+
142
139
  // calculate the hash of the r1cs file
143
140
  const r1csBlake2bHash = await blake512FromPath(localR1csPath)
144
141
 
@@ -151,12 +148,12 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
151
148
  const smallestPowersOfTauCompleteFilenameForCircuit = `${potFilenameTemplate}${doubleDigitsPowers}.ptau`
152
149
  const firstZkeyCompleteFilename = `${circuitPrefix}_${genesisZkeyIndex}.zkey`
153
150
 
154
- // storage paths
151
+ // storage paths
155
152
  const r1csStorageFilePath = getR1csStorageFilePath(circuitPrefix, r1csCompleteFilename)
156
153
  const wasmStorageFilePath = getWasmStorageFilePath(circuitPrefix, wasmCompleteFilename)
157
154
  const potStorageFilePath = getPotStorageFilePath(smallestPowersOfTauCompleteFilenameForCircuit)
158
155
  const zkeyStorageFilePath = getZkeyStorageFilePath(circuitPrefix, firstZkeyCompleteFilename)
159
-
156
+
160
157
  const files: any = {
161
158
  potFilename: smallestPowersOfTauCompleteFilenameForCircuit,
162
159
  r1csFilename: r1csCompleteFilename,
@@ -169,14 +166,15 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
169
166
  r1csBlake2bHash: r1csBlake2bHash
170
167
  }
171
168
 
172
- // validate that the compiler hash is a valid hash
169
+ // validate that the compiler hash is a valid hash
173
170
  const compiler = circuitData.compiler
174
171
  const compilerHashMatch = compiler.commitHash.match(commitHashPattern)
175
- if (!compilerHashMatch || compilerHashMatch.length === 0 || compilerHashMatch.length > 1) throw new Error("You should provide a valid commit hash of the circuit compiler.")
172
+ if (!compilerHashMatch || compilerHashMatch.length === 0 || compilerHashMatch.length > 1)
173
+ throw new Error("You should provide a valid commit hash of the circuit compiler.")
176
174
 
177
175
  // validate that the verification options are valid
178
176
  const verification = circuitData.verification
179
- if (verification.cfOrVm !== "CF" && verification.cfOrVm !== "VM")
177
+ if (verification.cfOrVm !== "CF" && verification.cfOrVm !== "VM")
180
178
  throw new Error("Please enter a valid verification mechanism: either CF or VM")
181
179
 
182
180
  // @todo VM parameters verification
@@ -189,8 +187,7 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
189
187
  let circuit: CircuitDocument | CircuitInputData = {} as CircuitDocument | CircuitInputData
190
188
 
191
189
  if (data.timeoutMechanismType === CeremonyTimeoutType.DYNAMIC) {
192
- if (circuitData.dynamicThreshold <= 0)
193
- throw new Error("The dynamic threshold should be > 0.")
190
+ if (circuitData.dynamicThreshold <= 0) throw new Error("The dynamic threshold should be > 0.")
194
191
  dynamicThreshold = circuitData.dynamicThreshold
195
192
 
196
193
  // the Circuit data for the ceremony setup
@@ -198,7 +195,7 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
198
195
  name: circuitData.name,
199
196
  description: circuitData.description,
200
197
  prefix: circuitPrefix,
201
- sequencePosition: i+1,
198
+ sequencePosition: i + 1,
202
199
  metadata: metadata,
203
200
  files: files,
204
201
  template: template,
@@ -209,23 +206,20 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
209
206
  contributionComputation: 0,
210
207
  fullContribution: 0,
211
208
  verifyCloudFunction: 0
212
- },
213
-
209
+ }
214
210
  }
215
211
  }
216
212
 
217
213
  if (data.timeoutMechanismType === CeremonyTimeoutType.FIXED) {
218
- if (circuitData.fixedTimeWindow <= 0)
219
- throw new Error("The fixed time window threshold should be > 0.")
214
+ if (circuitData.fixedTimeWindow <= 0) throw new Error("The fixed time window threshold should be > 0.")
220
215
  fixedTimeWindow = circuitData.fixedTimeWindow
221
216
 
222
-
223
217
  // the Circuit data for the ceremony setup
224
218
  circuit = {
225
219
  name: circuitData.name,
226
220
  description: circuitData.description,
227
221
  prefix: circuitPrefix,
228
- sequencePosition: i+1,
222
+ sequencePosition: i + 1,
229
223
  metadata: metadata,
230
224
  files: files,
231
225
  template: template,
@@ -236,16 +230,15 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
236
230
  contributionComputation: 0,
237
231
  fullContribution: 0,
238
232
  verifyCloudFunction: 0
239
- },
240
-
233
+ }
241
234
  }
242
235
  }
243
236
 
244
-
245
237
  circuits.push(circuit)
246
238
 
247
- // remove the local r1cs download (if used for verifying the config only vs setup)
239
+ // remove the local r1cs and wasm downloads (if used for verifying the config only vs setup)
248
240
  if (cleanup) fs.unlinkSync(localR1csPath)
241
+ fs.unlinkSync(localWasmPath)
249
242
  }
250
243
 
251
244
  const setupData: SetupCeremonyData = {
@@ -263,7 +256,6 @@ export const parseCeremonyFile = async (path: string, cleanup: boolean = false):
263
256
  }
264
257
 
265
258
  return setupData
266
-
267
259
  } catch (error: any) {
268
260
  throw new Error(`Error while parsing up the ceremony setup file. ${error.message}`)
269
261
  }
@@ -457,9 +449,11 @@ export const getPublicAttestationPreambleForContributor = (
457
449
  ceremonyName: string,
458
450
  isFinalizing: boolean
459
451
  ) =>
460
- `Hey, I'm ${contributorIdentifier} and I have ${
461
- isFinalizing ? "finalized" : "contributed to"
462
- } the ${ceremonyName} MPC Phase2 Trusted Setup ceremony.\nThe following are my contribution signatures:`
452
+ `Hey, I'm ${contributorIdentifier} and I have ${isFinalizing ? "finalized" : "contributed to"} the ${ceremonyName}${
453
+ ceremonyName.toLowerCase().includes("trusted setup") || ceremonyName.toLowerCase().includes("ceremony")
454
+ ? "."
455
+ : " MPC Phase2 Trusted Setup ceremony."
456
+ }\nThe following are my contribution signatures:`
463
457
 
464
458
  /**
465
459
  * Check and prepare public attestation for the contributor made only of its valid contributions.
@@ -740,4 +734,4 @@ export const getR1CSInfo = (localR1CSFilePath: string): CircuitMetadata => {
740
734
  * @param in <number> - the input number to be converted.
741
735
  * @returns <string> - the two digits stringified number derived from the conversion.
742
736
  */
743
- export const convertToDoubleDigits = (amount: number): string => (amount < 10 ? `0${amount}` : amount.toString())
737
+ export const convertToDoubleDigits = (amount: number): string => (amount < 10 ? `0${amount}` : amount.toString())
package/src/helpers/vm.ts CHANGED
@@ -82,7 +82,7 @@ export const vmDependenciesAndCacheArtifactsCommand = (
82
82
  zKeyPath: string,
83
83
  potPath: string,
84
84
  snsTopic: string,
85
- region: string
85
+ region: string
86
86
  ): Array<string> => [
87
87
  "#!/bin/bash",
88
88
  'MARKER_FILE="/var/run/my_script_ran"',
@@ -93,8 +93,13 @@ export const vmDependenciesAndCacheArtifactsCommand = (
93
93
  // eslint-disable-next-line no-template-curly-in-string
94
94
  "touch ${MARKER_FILE}",
95
95
  "sudo yum update -y",
96
- "curl -sL https://rpm.nodesource.com/setup_16.x | sudo bash - ",
97
- "sudo yum install -y nodejs",
96
+ "curl -O https://nodejs.org/dist/v16.13.0/node-v16.13.0-linux-x64.tar.xz",
97
+ "tar -xf node-v16.13.0-linux-x64.tar.xz",
98
+ "mv node-v16.13.0-linux-x64 nodejs",
99
+ "sudo mv nodejs /opt/",
100
+ "echo 'export NODEJS_HOME=/opt/nodejs' >> /etc/profile",
101
+ "echo 'export PATH=$NODEJS_HOME/bin:$PATH' >> /etc/profile",
102
+ "source /etc/profile",
98
103
  "npm install -g snarkjs",
99
104
  `aws s3 cp s3://${zKeyPath} /var/tmp/genesisZkey.zkey`,
100
105
  `aws s3 cp s3://${potPath} /var/tmp/pot.ptau`,
@@ -118,6 +123,7 @@ export const vmContributionVerificationCommand = (
118
123
  lastZkeyStoragePath: string,
119
124
  verificationTranscriptStoragePathAndFilename: string
120
125
  ): Array<string> => [
126
+ `source /etc/profile`,
121
127
  `aws s3 cp s3://${bucketName}/${lastZkeyStoragePath} /var/tmp/lastZKey.zkey > /var/tmp/log.txt`,
122
128
  `snarkjs zkvi /var/tmp/genesisZkey.zkey /var/tmp/pot.ptau /var/tmp/lastZKey.zkey > /var/tmp/verification_transcript.log`,
123
129
  `aws s3 cp /var/tmp/verification_transcript.log s3://${bucketName}/${verificationTranscriptStoragePathAndFilename} &>/dev/null`,
package/src/index.ts CHANGED
@@ -87,7 +87,7 @@ export {
87
87
  verifyContribution,
88
88
  checkAndPrepareCoordinatorForFinalization,
89
89
  finalizeCircuit,
90
- finalizeCeremony
90
+ finalizeCeremony
91
91
  } from "./helpers/functions"
92
92
  export { toHex, blake512FromPath, computeSHA256ToHex, compareHashes } from "./helpers/crypto"
93
93
  export {
@@ -159,4 +159,4 @@ export {
159
159
  createEC2Client,
160
160
  vmContributionVerificationCommand,
161
161
  retrieveCommandStatus
162
- } from "./helpers/vm"
162
+ } from "./helpers/vm"
@@ -620,7 +620,6 @@ export type SetupCeremonyData = {
620
620
  circuitArtifacts: Array<CeremonySetupTemplateCircuitArtifacts>
621
621
  }
622
622
 
623
-
624
623
  export type CeremonySetupTemplateCircuitArtifacts = {
625
624
  artifacts: {
626
625
  bucket: string
@@ -640,11 +639,16 @@ export type CeremonySetupTemplateCircuitName = {
640
639
  }
641
640
 
642
641
  export type CeremonySetupTemplate = {
643
- title: string
642
+ title: string
644
643
  description: string
645
644
  startDate: string
646
645
  endDate: string
647
646
  timeoutMechanismType: CeremonyTimeoutType
648
- penalty: number
649
- circuits: Array<CircuitDocument & CeremonySetupTemplateCircuitArtifacts & CeremonySetupTemplateCircuitTimeout & CeremonySetupTemplateCircuitName>
650
- }
647
+ penalty: number
648
+ circuits: Array<
649
+ CircuitDocument &
650
+ CeremonySetupTemplateCircuitArtifacts &
651
+ CeremonySetupTemplateCircuitTimeout &
652
+ CeremonySetupTemplateCircuitName
653
+ >
654
+ }