Skip to content

Commit

Permalink
feat(integration-test): add test scenarios
Browse files Browse the repository at this point in the history
  • Loading branch information
wanseob committed May 12, 2020
1 parent 039f420 commit 9e9f769
Show file tree
Hide file tree
Showing 11 changed files with 455 additions and 223 deletions.
22 changes: 22 additions & 0 deletions packages/contracts/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,8 @@ import { ContractOptions } from 'web3-eth-contract'

import { ICoordinatable } from './contracts/ICoordinatable'
import { IDepositChallenge } from './contracts/IDepositChallenge'
import { IERC20 } from './contracts/IERC20'
import { IERC721 } from './contracts/IERC721'
import { IHeaderChallenge } from './contracts/IHeaderChallenge'
import { IMigratable } from './contracts/IMigratable'
import { IMigrationChallenge } from './contracts/IMigrationChallenge'
Expand All @@ -19,6 +21,8 @@ import { ZkOptimisticRollUp } from './contracts/ZkOptimisticRollUp'

import { ICoordinatableABI } from './abis/ICoordinatable'
import { IDepositChallengeABI } from './abis/IDepositChallenge'
import { IERC20ABI } from './abis/IERC20'
import { IERC721ABI } from './abis/IERC721'
import { IHeaderChallengeABI } from './abis/IHeaderChallenge'
import { IMigratableABI } from './abis/IMigratable'
import { IMigrationChallengeABI } from './abis/IMigrationChallenge'
Expand Down Expand Up @@ -155,6 +159,24 @@ export default class ZkOPRUContract {
return new web3.eth.Contract(abi, address, option) as IUserInteractable
}

static asIERC20(
web3: Web3,
address: string,
option?: ContractOptions,
): IERC20 {
const abi: any[] = [...IERC20ABI]
return new web3.eth.Contract(abi, address, option) as IERC20
}

static asIERC721(
web3: Web3,
address: string,
option?: ContractOptions,
): IERC721 {
const abi: any[] = [...IERC721ABI]
return new web3.eth.Contract(abi, address, option) as IERC721
}

static asZkOptimisticRollUp(
web3: Web3,
address: string,
Expand Down
8 changes: 8 additions & 0 deletions packages/contracts/utils/ts-generator.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,8 @@ const importExportList = [
'ISetupWizard',
'ITxChallenge',
'IUserInteractable',
'IERC20',
'IERC721',
'ZkOptimisticRollUp',
]

Expand Down Expand Up @@ -56,6 +58,12 @@ const staticClasses = `${importExportList.reduce((prev, name) => {
`
}, '')}`

const exportInterfaces = `export {
${ts.reduce((prev, name) => {
if (!importExportList.includes(name)) return prev
return `${prev} ${name},\n`
}, '')}}\n`

const ZkOPRUContract = `export default class ZkOPRUContract {
upstream: ZkOptimisticRollUp
Expand Down
1 change: 1 addition & 0 deletions packages/core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,4 @@ export {
serializeHeader,
serializeBody,
} from './block'
export { L1Contract } from './layer1'
1 change: 1 addition & 0 deletions packages/integration-test/jest.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ const baseConfig = require('../../jest.config.base.js')

module.exports = {
...baseConfig,
moduleDirectories: ['node_modules'],
}
11 changes: 10 additions & 1 deletion packages/integration-test/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,16 @@
"dev": "ts-node-dev -r tsconfig-paths/register src/index.ts",
"start": "node dist/index.js"
},
"devDependencies": {
"dependencies": {
"@zkopru/account": "file:../account",
"@zkopru/babyjubjub": "file:../babyjubjub",
"@zkopru/contracts": "file:../contracts",
"@zkopru/core": "file:../core",
"@zkopru/coordinator": "file:../coordinator",
"@zkopru/database": "file:../database",
"@zkopru/transaction": "file:../transaction",
"@zkopru/utils": "file:../utils",
"@zkopru/zk-wizard": "file:../zk-wizard",
"@nano-sql/core": "^2.3.7",
"node-docker-api": "^1.1.22",
"web3": "^1.2.7",
Expand Down
26 changes: 26 additions & 0 deletions packages/integration-test/tests/helper/1_create_accounts.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
/* eslint-disable jest/no-export */
/* eslint-disable jest/no-hooks */
/* eslint-disable jest/require-top-level-describe */

import { toWei } from 'web3-utils'
import { Provider } from './context'

export const testAliceAccount = (ctx: Provider) => async () => {
const { web3, accounts } = ctx()
expect(
await web3.eth.getBalance(accounts.alice.ethAccount.address),
).toStrictEqual(toWei('100'))
}
export const testBobAccount = (ctx: Provider) => async () => {
const { web3, accounts } = ctx()
expect(
await web3.eth.getBalance(accounts.bob.ethAccount.address),
).toStrictEqual(toWei('100'))
}

export const testCarlAccount = (ctx: Provider) => async () => {
const { web3, accounts } = ctx()
expect(
await web3.eth.getBalance(accounts.carl.ethAccount.address),
).toStrictEqual(toWei('100'))
}
62 changes: 62 additions & 0 deletions packages/integration-test/tests/helper/2_register_vks.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/* eslint-disable jest/no-standalone-expect */
/* eslint-disable jest/require-tothrow-message */
/* eslint-disable jest/no-export */
/* eslint-disable jest/require-top-level-describe */

import { Provider } from './context'

export const testRegisterVKs = (ctx: Provider) => async () => {
const { contract, vks, accounts } = ctx()
const nIn = Object.keys(vks)
const nOut = Object.keys(vks[1])
const registerVKs: (() => Promise<void>)[] = []
let registeredNum = 0
nIn.forEach(i => {
nOut.forEach(j => {
registerVKs.push(async () => {
const tx = contract.setup.methods.registerVk(
i,
j,
vks[i][j].vk_alfa_1.slice(0, 2),
vks[i][j].vk_beta_2.slice(0, 2),
vks[i][j].vk_gamma_2.slice(0, 2),
vks[i][j].vk_delta_2.slice(0, 2),
vks[i][j].IC.map((arr: string[][]) => arr.slice(0, 2)),
)
const estimatedGas = await tx.estimateGas()
const receipt = await tx.send({
from: accounts.coordinator.address,
gas: estimatedGas,
})
registeredNum += 1
expect(receipt).toBeDefined()
})
})
})
await Promise.all(registerVKs.map(f => f()))
expect(registeredNum).toStrictEqual(16)
}

export const testRegisterVKFails = (ctx: Provider) => async () => {
const { contract, vks, accounts } = ctx()
const sampleVk = vks[4][4]
const tx = contract.setup.methods.registerVk(
5,
5,
sampleVk.vk_alfa_1.slice(0, 2),
sampleVk.vk_beta_2.slice(0, 2),
sampleVk.vk_gamma_2.slice(0, 2),
sampleVk.vk_delta_2.slice(0, 2),
sampleVk.IC.map((arr: string[][]) => arr.slice(0, 2)),
)
const estimatedGas = await tx.estimateGas()
await expect(
tx.send({ from: accounts.alice.address, gas: estimatedGas }),
).rejects.toThrow()
await expect(
tx.send({ from: accounts.bob.address, gas: estimatedGas }),
).rejects.toThrow()
await expect(
tx.send({ from: accounts.carl.address, gas: estimatedGas }),
).rejects.toThrow()
}
33 changes: 33 additions & 0 deletions packages/integration-test/tests/helper/3_complete_setup.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/* eslint-disable jest/no-expect-resolves */
/* eslint-disable jest/require-tothrow-message */
/* eslint-disable jest/no-export */
/* eslint-disable jest/require-top-level-describe */

import { Provider } from './context'

export const testCompleteSetup = (ctx: Provider) => async () => {
const { accounts, contract } = ctx()
const tx = contract.setup.methods.completeSetup()
const gas = await tx.estimateGas()
await expect(tx.send({ from: accounts.alice.address, gas })).rejects.toThrow()
await expect(tx.send({ from: accounts.bob.address, gas })).rejects.toThrow()
await expect(tx.send({ from: accounts.carl.address, gas })).rejects.toThrow()
await expect(
tx.send({ from: accounts.coordinator.address, gas }),
).resolves.toHaveProperty('transactionHash')
}

export const testRejectVkRegistration = (ctx: Provider) => async () => {
const { accounts, contract } = ctx()
const tx = contract.setup.methods.completeSetup()
await expect(
tx.estimateGas({ from: accounts.alice.address }),
).rejects.toThrow()
await expect(tx.estimateGas({ from: accounts.bob.address })).rejects.toThrow()
await expect(
tx.estimateGas({ from: accounts.carl.address }),
).rejects.toThrow()
await expect(
tx.estimateGas({ from: accounts.coordinator.address }),
).rejects.toThrow()
}
138 changes: 138 additions & 0 deletions packages/integration-test/tests/helper/context.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
import { ZkAccount, HDWallet } from '@zkopru/account'
import { schema } from '@zkopru/database'
import { sleep, readFromContainer } from '@zkopru/utils'
import { L1Contract } from '@zkopru/core'
import { Docker } from 'node-docker-api'
import { nSQL, InanoSQLInstance } from '@nano-sql/core'
import { Container } from 'node-docker-api/lib/container'
import Web3 from 'web3'

type VKs = { [nIn: number]: { [nOut: number]: any } }

export interface Context {
layer1Container: Container
circuitArtifactContainer: Container
accounts: {
coordinator: ZkAccount
alice: ZkAccount
bob: ZkAccount
carl: ZkAccount
}
web3: Web3
zkopruAddress: string
db: InanoSQLInstance
contract: L1Contract
vks: VKs
}

export type Provider = () => Context

export async function initContext() {
const docker = new Docker({ socketPath: '/var/run/docker.sock' })
const layer1Container = await docker.container.create({
Image: 'zkopru:contract',
name: Math.random()
.toString(36)
.substring(2, 16),
rm: true,
})
const circuitArtifactContainer = await docker.container.create({
Image: 'zkopru:circuits',
name: Math.random()
.toString(36)
.substring(2, 16),
rm: true,
})
await Promise.all([layer1Container.start(), circuitArtifactContainer.start()])
const deployed = await readFromContainer(
layer1Container,
'/proj/build/deployed/ZkOptimisticRollUp.json',
)
const zkopruAddress = JSON.parse(deployed.toString()).address
const status = await layer1Container.status()
const containerIP = (status.data as {
NetworkSettings: { IPAddress: string }
}).NetworkSettings.IPAddress
sleep(2000)
console.log('Running testnet on ', `${containerIP}:5000`)
const provider = new Web3.providers.WebsocketProvider(
`ws://${containerIP}:5000`,
{ reconnect: { auto: true } },
)
async function waitConnection() {
return new Promise<void>(res => {
if (provider.connected) res()
provider.on('connect', res)
})
}
await waitConnection()
console.log('Websocket connection with ', `${containerIP}:5000`)
const web3 = new Web3(provider)
const contract = new L1Contract(web3, zkopruAddress)
const dbName = 'zkopruFullNodeTester'
await nSQL().createDatabase({
id: dbName,
mode: 'TEMP',
tables: [
schema.utxo,
schema.utxoTree,
schema.withdrawal,
schema.withdrawalTree,
schema.nullifiers,
schema.nullifierTreeNode,
schema.migration,
schema.deposit,
schema.massDeposit,
schema.chain,
schema.keystore,
schema.hdWallet,
],
version: 3,
})
const db = nSQL().useDatabase(dbName)
const hdWallet = new HDWallet(db)
const mnemonic =
'myth like bonus scare over problem client lizard pioneer submit female collect'
await hdWallet.init(mnemonic, 'samplepassword')
const coordinator = await hdWallet.createAccount(0)
const alice = await hdWallet.createAccount(1)
const bob = await hdWallet.createAccount(2)
const carl = await hdWallet.createAccount(3)
const accounts = { coordinator, alice, bob, carl }
const vks: VKs = {
1: {},
2: {},
3: {},
4: {},
}
const nIn = [1, 2, 3, 4]
const nOut = [1, 2, 3, 4]
const readVKs: (() => Promise<void>)[] = []
nIn.forEach(i => {
nOut.forEach(j => {
const readVK = async () => {
const vk = JSON.parse(
(
await readFromContainer(
circuitArtifactContainer,
'/proj/build/vks/zk_transaction_1_1.vk.json',
)
).toString('utf8'),
)
vks[i][j] = vk
}
readVKs.push(readVK)
})
})
await Promise.all(readVKs.map(f => f()))
return {
layer1Container,
circuitArtifactContainer,
accounts,
web3,
zkopruAddress,
db,
contract,
vks,
}
}
Loading

0 comments on commit 9e9f769

Please sign in to comment.