Skip to content

Commit 684123a

Browse files
committed
feat(vms): implemented e2e test for contribution verification
1 parent 64f5019 commit 684123a

File tree

7 files changed

+144
-132
lines changed

7 files changed

+144
-132
lines changed

packages/actions/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@p0tion/actions",
3-
"version": "0.4.4",
3+
"version": "0.4.5",
44
"description": "A set of actions and helpers for CLI commands",
55
"repository": "git@github.com:privacy-scaling-explorations/p0tion.git",
66
"homepage": "https://github.com/privacy-scaling-explorations/p0tion",

packages/actions/test/unit/ec2.test.ts

+129-115
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import chai, { expect } from "chai"
22
import chaiAsPromised from "chai-as-promised"
33
import { EC2Client } from "@aws-sdk/client-ec2"
44
import fetch from "@adobe/node-fetch-retry"
5-
import { cleanUpMockUsers, cleanUpRecursively, createMockUser, deleteBucket, deleteObjectFromS3, envType, generateUserPasswords, getStorageConfiguration, getTranscriptLocalFilePath, initializeAdminServices, initializeUserServices, sleep } from "../utils"
5+
import { cleanUpMockUsers, cleanUpRecursively, createMockCeremony, createMockUser, deleteBucket, deleteObjectFromS3, envType, generateUserPasswords, getStorageConfiguration, getTranscriptLocalFilePath, initializeAdminServices, initializeUserServices, sleep } from "../utils"
66
import {
77
checkEC2Status,
88
createEC2Client,
@@ -39,105 +39,105 @@ describe("VMs", () => {
3939
ec2 = await createEC2Client()
4040
})
4141

42-
// describe("EC2", () => {
43-
// it("should create an instance", async () => {
44-
// instance = await createEC2Instance(ec2, [
45-
// "echo 'hello world' > hello.txt",
46-
// "aws s3 cp hello.txt s3://p0tion-test-bucket/hello.txt"
47-
// ], "t2.micro", amiId, keyName, roleArn, 8)
48-
// expect(instance).to.not.be.undefined
49-
// // give it time to actually spin up
50-
// await sleep(250000)
51-
// })
52-
53-
// it("checkEC2Status should return true for an instance that is running", async () => {
54-
// const response = await checkEC2Status(ec2, instance.InstanceId!)
55-
// expect(response).to.be.true
56-
// })
42+
describe("EC2", () => {
43+
it("should create an instance", async () => {
44+
instance = await createEC2Instance(ec2, [
45+
"echo 'hello world' > hello.txt",
46+
"aws s3 cp hello.txt s3://p0tion-test-bucket/hello.txt"
47+
], "t2.micro", amiId, keyName, roleArn, 8)
48+
expect(instance).to.not.be.undefined
49+
// give it time to actually spin up
50+
await sleep(250000)
51+
})
52+
53+
it("checkEC2Status should return true for an instance that is running", async () => {
54+
const response = await checkEC2Status(ec2, instance.InstanceId!)
55+
expect(response).to.be.true
56+
})
5757

58-
// it("getEC2Ip should return an ip", async () => {
59-
// const ip = await getEC2Ip(ec2, instance.InstanceId!)
60-
// expect(ip).to.not.be.undefined
61-
// previousIp = ip!
62-
// })
58+
it("getEC2Ip should return an ip", async () => {
59+
const ip = await getEC2Ip(ec2, instance.InstanceId!)
60+
expect(ip).to.not.be.undefined
61+
previousIp = ip!
62+
})
6363

64-
// it("stopEC2Instance should stop an instance", async () => {
65-
// await expect(stopEC2Instance(ec2, instance.InstanceId!)).to.be.fulfilled
66-
// await sleep(200000)
67-
// })
64+
it("stopEC2Instance should stop an instance", async () => {
65+
await expect(stopEC2Instance(ec2, instance.InstanceId!)).to.be.fulfilled
66+
await sleep(200000)
67+
})
6868

69-
// it("checkEC2Status should throw for an instance that is stopped", async () => {
70-
// await expect(checkEC2Status(ec2, instance.InstanceId!)).to.be.rejected
71-
// })
69+
it("checkEC2Status should throw for an instance that is stopped", async () => {
70+
await expect(checkEC2Status(ec2, instance.InstanceId!)).to.be.rejected
71+
})
7272

73-
// it("startEC2Instance should start an instance", async () => {
74-
// await expect(startEC2Instance(ec2, instance.InstanceId!)).to.be.fulfilled
75-
// await sleep(200000)
76-
// })
73+
it("startEC2Instance should start an instance", async () => {
74+
await expect(startEC2Instance(ec2, instance.InstanceId!)).to.be.fulfilled
75+
await sleep(200000)
76+
})
7777

78-
// it("should get a different ip address after a restart", async () => {
79-
// const ip = getEC2Ip(ec2, instance.InstanceId!)
80-
// expect(previousIp).to.not.equal(ip)
81-
// })
78+
it("should get a different ip address after a restart", async () => {
79+
const ip = getEC2Ip(ec2, instance.InstanceId!)
80+
expect(previousIp).to.not.equal(ip)
81+
})
8282

83-
// it("terminateEC2Instance should terminate an instance", async () => {
84-
// await expect(terminateEC2Instance(ec2, instance.InstanceId!)).to.be.fulfilled
85-
// })
86-
// })
87-
88-
// describe("SSM", () => {
89-
// let ssmClient: SSMClient
90-
// let commandId: string
91-
// let ssmTestInstance: P0tionEC2Instance
92-
// beforeAll(async () => {
93-
// ssmClient = await createSSMClient()
94-
// const userData = [
95-
// "#!/bin/bash",
96-
// "aws s3 cp s3://p0tion-test-bucket/script_test.sh script_test.sh",
97-
// "chmod +x script_test.sh && bash script_test.sh"
98-
// ]
99-
// ssmTestInstance = await createEC2Instance(ec2, userData, "t2.small", amiId, keyName, roleArn, 8)
100-
// await sleep(250000)
101-
// })
102-
// it("should run my commands", async () => {
103-
// await runCommandOnEC2(ssmClient, ssmTestInstance.InstanceId, [
104-
// `pwd`
105-
// ] )
83+
it("terminateEC2Instance should terminate an instance", async () => {
84+
await expect(terminateEC2Instance(ec2, instance.InstanceId!)).to.be.fulfilled
85+
})
86+
})
87+
88+
describe("SSM", () => {
89+
let ssmClient: SSMClient
90+
let commandId: string
91+
let ssmTestInstance: P0tionEC2Instance
92+
beforeAll(async () => {
93+
ssmClient = await createSSMClient()
94+
const userData = [
95+
"#!/bin/bash",
96+
"aws s3 cp s3://p0tion-test-bucket/script_test.sh script_test.sh",
97+
"chmod +x script_test.sh && bash script_test.sh"
98+
]
99+
ssmTestInstance = await createEC2Instance(ec2, userData, "t2.small", amiId, keyName, roleArn, 8)
100+
await sleep(250000)
101+
})
102+
it("should run my commands", async () => {
103+
await runCommandOnEC2(ssmClient, ssmTestInstance.InstanceId, [
104+
`pwd`
105+
] )
106106

107-
// })
108-
// it("run a command on a VM that is active", async () => {
109-
// commandId = await runCommandOnEC2(ssmClient, ssmTestInstance.InstanceId!, [
110-
// "echo $(whoami) >> hello.txt"
111-
// ])
112-
// expect(commandId).to.not.be.null
113-
// await sleep(500)
114-
// })
115-
// it("should run multiple commands", async () => {
116-
// await runCommandOnEC2(ssmClient, ssmTestInstance.InstanceId!, [
117-
// "su ubuntu", "whoami", "id", "pwd", "ls -la", "ls -la /root", "ls -la /home/ubuntu",
118-
// ])
119-
// })
120-
// it("should throw when trying to call a command on a VM that is not active", async () => {
121-
// await expect(runCommandOnEC2(ssmClient, "nonExistentOrOff", ["echo hello world"])).to.be.rejected
122-
// })
123-
// it("should retrieve the output of a command", async () => {
124-
// await sleep(20000)
125-
// const output = await retrieveCommandOutput(ssmClient, commandId, ssmTestInstance.InstanceId!)
126-
// expect(output.length).to.be.gt(0)
127-
// })
128-
// it("should throw when trying to retrieve the output of a non existent command", async () => {
129-
// await expect(retrieveCommandOutput(ssmClient, "nonExistentCommand", ssmTestInstance.InstanceId!)).to.be.rejected
130-
// })
131-
// afterAll(async () => {
132-
// await terminateEC2Instance(ec2, ssmTestInstance.InstanceId!)
133-
// })
134-
// })
135-
136-
// afterAll(async () => {
137-
// await terminateEC2Instance(ec2, instance.InstanceId!)
138-
// })
139-
140-
describe("Setup a ceremony that uses two VMs", () => {
107+
})
108+
it("run a command on a VM that is active", async () => {
109+
commandId = await runCommandOnEC2(ssmClient, ssmTestInstance.InstanceId!, [
110+
"echo $(whoami) >> hello.txt"
111+
])
112+
expect(commandId).to.not.be.null
113+
await sleep(500)
114+
})
115+
it("should run multiple commands", async () => {
116+
await runCommandOnEC2(ssmClient, ssmTestInstance.InstanceId!, [
117+
"su ubuntu", "whoami", "id", "pwd", "ls -la", "ls -la /root", "ls -la /home/ubuntu",
118+
])
119+
})
120+
it("should throw when trying to call a command on a VM that is not active", async () => {
121+
await expect(runCommandOnEC2(ssmClient, "nonExistentOrOff", ["echo hello world"])).to.be.rejected
122+
})
123+
it("should retrieve the output of a command", async () => {
124+
await sleep(20000)
125+
const output = await retrieveCommandOutput(ssmClient, commandId, ssmTestInstance.InstanceId!)
126+
expect(output.length).to.be.gt(0)
127+
})
128+
it("should throw when trying to retrieve the output of a non existent command", async () => {
129+
await expect(retrieveCommandOutput(ssmClient, "nonExistentCommand", ssmTestInstance.InstanceId!)).to.be.rejected
130+
})
131+
afterAll(async () => {
132+
await terminateEC2Instance(ec2, ssmTestInstance.InstanceId!)
133+
})
134+
})
135+
136+
afterAll(async () => {
137+
await terminateEC2Instance(ec2, instance.InstanceId!)
138+
})
139+
140+
describe("Setup and run a ceremony using VMs", () => {
141141
// Sample data for running the test.
142142
const users = [fakeUsersData.fakeUser1, fakeUsersData.fakeUser2]
143143
const passwords = generateUserPasswords(2)
@@ -149,7 +149,7 @@ describe("VMs", () => {
149149

150150
// Get configs for storage.
151151
const { ceremonyBucketPostfix, streamChunkSizeInMb } = getStorageConfiguration()
152-
const ceremony = fakeCeremoniesData.fakeCeremonyScheduledDynamic
152+
const ceremony = fakeCeremoniesData.fakeCeremonyOpenedFixed
153153
const ceremonyBucket = getBucketName(ceremony.data.prefix, ceremonyBucketPostfix)
154154
const circuit = fakeCircuitsData.fakeCircuitSmallNoContributors
155155

@@ -177,6 +177,8 @@ describe("VMs", () => {
177177
// s3 objects we have to delete
178178
const objectsToDelete = [potStoragePath, storagePath]
179179

180+
const secondCeremonyId = ceremony.uid
181+
180182
beforeAll(async () => {
181183
// create 2 users the second is the coordinator
182184
for (let i = 0; i < 2; i++) {
@@ -197,25 +199,29 @@ describe("VMs", () => {
197199
await multiPartUpload(userFunctions, ceremonyBucket, storagePath, zkeyPath, streamChunkSizeInMb)
198200
// pot upload
199201
await multiPartUpload(userFunctions, ceremonyBucket, potStoragePath, potPath, streamChunkSizeInMb)
202+
203+
204+
// create mock ceremony with circuit data
205+
await createMockCeremony(adminFirestore, ceremony, circuit)
200206
})
201207

202208
afterAll(async () => {
203-
// for (const instanceId of instancesToTerminate) {
204-
// await terminateEC2Instance(ec2, instanceId)
205-
// }
209+
for (const instanceId of instancesToTerminate) {
210+
await terminateEC2Instance(ec2, instanceId)
211+
}
206212

207-
// for (const objectToDelete of objectsToDelete) {
208-
// await deleteObjectFromS3(ceremonyBucket, objectToDelete)
209-
// }
210-
// await deleteBucket(ceremonyBucket)
213+
for (const objectToDelete of objectsToDelete) {
214+
await deleteObjectFromS3(ceremonyBucket, objectToDelete)
215+
}
216+
await deleteBucket(ceremonyBucket)
211217

212218
await cleanUpMockUsers(adminAuth, adminFirestore, users)
213219
await cleanUpRecursively(adminFirestore, ceremonyId)
214220

215221
fs.rmdirSync(`${outputDirectory}`, { recursive: true })
216222
})
217223

218-
it.only("should create a ceremony and two VMs should spin up", async () => {
224+
it("should create a ceremony and the VM should spin up", async () => {
219225
// 1. setup ceremony
220226
ceremonyId = await setupCeremony(userFunctions, ceremony.data, ceremony.data.prefix!, [circuit.data])
221227

@@ -240,11 +246,19 @@ describe("VMs", () => {
240246
await signInWithEmailAndPassword(userAuth, users[0].data.email, passwords[0])
241247
await sleep(500)
242248
// 2. get circuits for ceremony
243-
const circuits = await getCeremonyCircuits(userFirestore, ceremonyId)
249+
const circuits = await getCeremonyCircuits(userFirestore, secondCeremonyId)
244250
expect(circuits.length).to.be.gt(0)
245251

252+
// set the VM instance ID that we setup before
253+
for (const circuit of circuits) {
254+
await adminFirestore.collection(getCircuitsCollectionPath(secondCeremonyId)).doc(circuit.id).set({
255+
...circuit.data,
256+
vmInstanceId: instancesToTerminate[circuits.indexOf(circuit)]
257+
})
258+
}
259+
246260
// 3. register for cermeony
247-
const canParticipate = await checkParticipantForCeremony(userFunctions, ceremonyId)
261+
const canParticipate = await checkParticipantForCeremony(userFunctions, secondCeremonyId)
248262
expect(canParticipate).to.be.true
249263

250264
// 4. entropy
@@ -273,39 +287,39 @@ describe("VMs", () => {
273287
fs.writeFileSync(lastZkeyLocalFilePath, await getResponse.buffer())
274288
await sleep(500)
275289
// 9. progress to next step
276-
await progressToNextCircuitForContribution(userFunctions, ceremonyId)
290+
await progressToNextCircuitForContribution(userFunctions, secondCeremonyId)
277291
await sleep(1000)
278292

279293
const transcriptLocalFilePath = `${outputDirectory}/${getTranscriptLocalFilePath(
280294
`${circuit.data.prefix}_${nextZkeyIndex}.log`
281295
)}`
282296
const transcriptLogger = createCustomLoggerForFile(transcriptLocalFilePath)
283297
// 10. do contribution
284-
await zKey.contribute(lastZkeyLocalFilePath, nextZkeyLocalFilePath, users[2].uid, entropy, transcriptLogger)
298+
await zKey.contribute(lastZkeyLocalFilePath, nextZkeyLocalFilePath, users[0].uid, entropy, transcriptLogger)
285299
await sleep(1000)
286300

287301
// read the contribution hash
288302
const transcriptContents = fs.readFileSync(transcriptLocalFilePath, "utf-8").toString()
289303
const matchContributionHash = transcriptContents.match(/Contribution.+Hash.+\n\t\t.+\n\t\t.+\n.+\n\t\t.+\n/)
290304
const contributionHash = matchContributionHash?.at(0)?.replace("\n\t\t", "")!
291305

292-
await progressToNextContributionStep(userFunctions, ceremonyId)
306+
await progressToNextContributionStep(userFunctions, secondCeremonyId)
293307
await sleep(2000)
294308
await permanentlyStoreCurrentContributionTimeAndHash(
295309
userFunctions,
296-
ceremonyId,
310+
secondCeremonyId,
297311
new Date().valueOf(),
298312
contributionHash
299313
)
300314
await sleep(2000)
301315

302-
await progressToNextContributionStep(userFunctions, ceremonyId)
316+
await progressToNextContributionStep(userFunctions, secondCeremonyId)
303317
await sleep(1000)
304318

305319
const participant = await getDocumentById(
306320
userFirestore,
307-
getParticipantsCollectionPath(ceremonyId),
308-
users[2].uid
321+
getParticipantsCollectionPath(secondCeremonyId),
322+
users[0].uid
309323
)
310324

311325
// Upload
@@ -319,7 +333,7 @@ describe("VMs", () => {
319333
nextZkeyStoragePath,
320334
nextZkeyLocalFilePath,
321335
streamChunkSizeInMb,
322-
ceremony.uid,
336+
secondCeremonyId,
323337
participant.data()!.tempContributionData
324338
)
325339
await sleep(1000)
@@ -329,16 +343,16 @@ describe("VMs", () => {
329343
// Execute contribution verification.
330344
const tempCircuit = await getDocumentById(
331345
userFirestore,
332-
getCircuitsCollectionPath(ceremonyId),
346+
getCircuitsCollectionPath(secondCeremonyId),
333347
circuit.id
334348
)
335349

336350
await verifyContribution(
337351
userFunctions,
338-
ceremonyId,
352+
secondCeremonyId,
339353
tempCircuit,
340354
ceremonyBucket,
341-
users[2].uid,
355+
users[0].uid,
342356
String(process.env.FIREBASE_CF_URL_VERIFY_CONTRIBUTION)
343357
)
344358
})

packages/backend/package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@
6767
"@aws-sdk/client-ssm": "^3.357.0",
6868
"@aws-sdk/middleware-endpoint": "^3.329.0",
6969
"@aws-sdk/s3-request-presigner": "^3.329.0",
70-
"@p0tion/actions": "^0.4.4",
70+
"@p0tion/actions": "^0.4.5",
7171
"blakejs": "^1.2.1",
7272
"dotenv": "^16.0.3",
7373
"ethers": "5.7.2",

0 commit comments

Comments
 (0)