diff --git a/docker-compose.yml b/docker-compose.yml new file mode 100644 index 0000000..a0f2b8c --- /dev/null +++ b/docker-compose.yml @@ -0,0 +1,97 @@ +services: + admin: + build: + context: . + dockerfile: ops/docker/Dockerfile.admin + container_name: zkrand_admin_service + volumes: + - admin_volume:/data + environment: + - L2_NODE_WEB3_URL=https://sepolia.boba.network + - POLLING_INTERVAL=12000 + - RAND_GEN_INTERVAL=3600 + - RAND_GEN_START_DATE=2024-07-18T12:00:00Z + - ZK_RAND_ADDRESS=0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF + - ADMIN_PRIVATE_KEY=0x58936e48436d9764c0c09775444fe6700d0a8aa84d4d6c09e110f70fc87c7289 + - NODE_ONE_ADDRESS=0x85A6bCc74CB8570BEfF8526aec7d0Dfb6F128A60 + - NODE_TWO_ADDRESS=0x7D9e5627B650650Fa3E848364Cb5B0b696B885f2 + - NODE_THREE_ADDRESS=0xec21Cc95d30cc414922292790Bf2E9063bCEe94b + - NODE_FOUR_ADDRESS=0xE7a9aB7B20EFE5B450d7AcB5ABe169166a26DfAC + - NODE_FIVE_ADDRESS=0x5dbfFf2666C351b226cdCe7c1F82B9b0CEbb0bb9 + + node-one: + build: + context: . + dockerfile: ops/docker/Dockerfile.node + container_name: zkrand_node_1_service + volumes: + - node_1_volume:/data + environment: + - L2_NODE_WEB3_URL=https://sepolia.boba.network + - POLLING_INTERVAL=12000 + - ZK_RAND_ADDRESS=0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF + - NODE_PRIVATE_KEY=0x2e978a5709ac0dc3cbc2260519f8fcf5542af54dfaff489bcb4a69182be49429 + + + node-two: + build: + context: . + dockerfile: ops/docker/Dockerfile.node + container_name: zkrand_node_2_service + volumes: + - node_2_volume:/data + environment: + - L2_NODE_WEB3_URL=https://sepolia.boba.network + - POLLING_INTERVAL=12000 + - ZK_RAND_ADDRESS=0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF + - NODE_PRIVATE_KEY=0xa0a98d2341d78ed222b7a6314c026d8e85185203fd295f67b7146be956a05c58 + + node-three: + build: + context: . + dockerfile: ops/docker/Dockerfile.node + container_name: zkrand_node_3_service + volumes: + - node_3_volume:/data + environment: + - L2_NODE_WEB3_URL=https://sepolia.boba.network + - POLLING_INTERVAL=12000 + - ZK_RAND_ADDRESS=0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF + - NODE_PRIVATE_KEY=0x742e271d909d026b2b4dcc0384ec0b8df8f674f0773c354b57c24858419e89d3 + + + node-four: + build: + context: . + dockerfile: ops/docker/Dockerfile.node + container_name: zkrand_node_4_service + volumes: + - node_4_volume:/data + environment: + - L2_NODE_WEB3_URL=https://sepolia.boba.network + - POLLING_INTERVAL=12000 + - ZK_RAND_ADDRESS=0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF + - NODE_PRIVATE_KEY=0xeeb82181766c7d0fe45d2cb5b3399b1da17a1a432938ec8c4d73daca85eedaea + + + node-five: + build: + context: . + dockerfile: ops/docker/Dockerfile.node + container_name: zkrand_node_5_service + volumes: + - node_5_volume:/data + environment: + - L2_NODE_WEB3_URL=https://sepolia.boba.network + - POLLING_INTERVAL=12000 + - ZK_RAND_ADDRESS=0x1C2FfFeEee7d396597D60adAdAC63c2c48B829AF + - NODE_PRIVATE_KEY=0x88b68d7e8d96d8465cfe3dc4abf707e21aa49139189a784e2d50cc9ada9076c3 + + +volumes: + admin_volume: + node_1_volume: + node_2_volume: + node_3_volume: + node_4_volume: + node_5_volume: \ No newline at end of file diff --git a/ops/docker-compose.yml b/ops/docker-compose.yml deleted file mode 100644 index 021fbb2..0000000 --- a/ops/docker-compose.yml +++ /dev/null @@ -1,83 +0,0 @@ -version: '3' - -services: - admin: - build: - context: . - dockerfile: Dockerfile.admin - container_name: admin_service - environment: - - L2_NODE_WEB3_URL: "https://sepolia.boba.network" - - POLLING_INTERVAL: 12000 - - ZK_RAND_ADDRESS: "0xd688cFE3EC08d893E9A3b76f12113e1ef762f53A" - - ADMIN_PRIVATE_KEY: "0xac0974bec39a17e36ba4a6b4d238ff944bacb478cbed5efcae784d7bf4f2ff80" - - NODE_ONE_ADDRESS: "0x70997970c51812dc3a010c7d01b50e0d17dc79c8" - - NODE_TWO_ADDRESS: "0x3c44cdddb6a900fa2b585dd299e03d12fa4293bc" - - NODE_THREE_ADDRESS: "0x90f79bf6eb2c4f870365e785982e1f101e93b906" - - NODE_FOUR_ADDRESS: "0x15d34aaf54267db7d7c367839aaf71a00a2c6a65" - - NODE_FIVE_ADDRESS: "0x9965507d1a55bcc2695c58ba16fb37d819b0a4dc" - - nodeOne: - build: - context: . - dockerfile: Dockerfile.node - container_name: node_service - environment: - - L2_NODE_WEB3_URL: "https://sepolia.boba.network" - - POLLING_INTERVAL: 12000 - - ZK_RAND_ADDRESS: "0xd688cFE3EC08d893E9A3b76f12113e1ef762f53A" - - NODE_PRIVATE_KEY: "0x59c6995e998f97a5a0044966f0945389dc9e86dae88c7a8412f4603b6b78690d" - depends_on: - - admin - - nodeTwo: - build: - context: . - dockerfile: Dockerfile.node - container_name: node_service - environment: - - L2_NODE_WEB3_URL: "https://sepolia.boba.network" - - POLLING_INTERVAL: 12000 - - ZK_RAND_ADDRESS: "0xd688cFE3EC08d893E9A3b76f12113e1ef762f53A" - - NODE_PRIVATE_KEY: "0x5de4111afa1a4b94908f83103eb1f1706367c2e68ca870fc3fb9a804cdab365a" - depends_on: - - admin - - nodeThree: - build: - context: . - dockerfile: Dockerfile.node - container_name: node_service - environment: - - L2_NODE_WEB3_URL: "https://sepolia.boba.network" - - POLLING_INTERVAL: 12000 - - ZK_RAND_ADDRESS: "0xd688cFE3EC08d893E9A3b76f12113e1ef762f53A" - - NODE_PRIVATE_KEY: "0x7c852118294e51e653712a81e05800f419141751be58f605c371e15141b007a6" - depends_on: - - admin - - nodeFour: - build: - context: . - dockerfile: Dockerfile.node - container_name: node_service - environment: - - L2_NODE_WEB3_URL: "https://sepolia.boba.network" - - POLLING_INTERVAL: 12000 - - ZK_RAND_ADDRESS: "0xd688cFE3EC08d893E9A3b76f12113e1ef762f53A" - - NODE_PRIVATE_KEY: "0x47e179ec197488593b187f80a00eb0da91f1b9d0b13f8733639f19c30a34926a" - depends_on: - - admin - - nodeFive: - build: - context: . - dockerfile: Dockerfile.node - container_name: node_service - environment: - - L2_NODE_WEB3_URL: "https://sepolia.boba.network" - - POLLING_INTERVAL: 12000 - - ZK_RAND_ADDRESS: "0xd688cFE3EC08d893E9A3b76f12113e1ef762f53A" - - NODE_PRIVATE_KEY: "0x8b3a350cf5c34c9194ca85829a2df0ec3153be0318b5e2d3348e872092edffba" - depends_on: - - admin diff --git a/services/admin.ts b/services/admin.ts index 0025531..01a1e8e 100644 --- a/services/admin.ts +++ b/services/admin.ts @@ -7,7 +7,7 @@ import {exec} from "child_process"; import {sleep} from '@eth-optimism/core-utils' import {BaseService} from '@eth-optimism/common-ts' -import zkRandContractABI from '../artifacts/contracts/zkdvrf.sol/zkdvrf.json' +import zkRandContractABI from '../artifacts/contracts/zkdvrf_pre.sol/zkdvrf_pre.json' export const memberDir = `./data/members/` export const mpksPath = `./data/mpks.json` @@ -45,6 +45,7 @@ interface AdminZkRandOptions { nodeFiveAddress: string pollingInterval: number randGenInterval: number + randGenStartDate: string } const optionSettings = {} @@ -52,6 +53,8 @@ const optionSettings = {} const emptyAddress = '0x0000000000000000000000000000000000000000' // String representation of bytes32(0) const bytes32Zero = "0x" + "0".repeat(64); +const gasLimitLow = 500000 +const gasLimitHigh = 3000000 export class AdminZkRandService extends BaseService { constructor(options: AdminZkRandOptions) { @@ -62,6 +65,7 @@ export class AdminZkRandService extends BaseService { zkRandContract: Contract gasOverride: GasPriceOverride timeOfLastRound: number + startDate: number } = {} as any async _init(): Promise { @@ -87,6 +91,12 @@ export class AdminZkRandService extends BaseService { this.state.gasOverride = {gasLimit: 10000000} this.state.timeOfLastRound = 0 // 0 indicates no round has been initiated + + this.state.startDate = 0 + let startDate = new Date(this.options.randGenStartDate); + if (!isNaN(startDate.getTime())) { + this.state.startDate = startDate.getTime() + } } async _start(): Promise { @@ -110,35 +120,35 @@ export class AdminZkRandService extends BaseService { console.log("adding permissioned nodes") const nodeOne = await this.state.zkRandContract.addrToNode(this.options.nodeOneAddress) if (nodeOne.nodeAddress === emptyAddress) { - const retOne = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeOneAddress) + const retOne = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeOneAddress, {gasLimit: gasLimitLow}) console.log("transaction hash for addPermissionedNodes on node one:", retOne.hash) await retOne.wait() } const nodeTwo = await this.state.zkRandContract.addrToNode(this.options.nodeTwoAddress) if (nodeTwo.nodeAddress === emptyAddress) { - const retTwo = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeTwoAddress) + const retTwo = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeTwoAddress, {gasLimit: gasLimitLow}) console.log("transaction hash for addPermissionedNodes on node two:", retTwo.hash) await retTwo.wait() } const nodeThree = await this.state.zkRandContract.addrToNode(this.options.nodeThreeAddress) if (nodeThree.nodeAddress === emptyAddress) { - const retThree = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeThreeAddress) + const retThree = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeThreeAddress, {gasLimit: gasLimitLow}) console.log("transaction hash for addPermissionedNodes on node three:", retThree.hash) await retThree.wait() } const nodeFour = await this.state.zkRandContract.addrToNode(this.options.nodeFourAddress) if (nodeFour.nodeAddress === emptyAddress) { - const retFour = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeFourAddress) + const retFour = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeFourAddress, {gasLimit: gasLimitLow}) console.log("transaction hash for addPermissionedNodes on node four:", retFour.hash) await retFour.wait() } const nodeFive = await this.state.zkRandContract.addrToNode(this.options.nodeFiveAddress) if (nodeFive.nodeAddress === emptyAddress) { - const retFive = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeFiveAddress) + const retFive = await this.state.zkRandContract.addPermissionedNodes(this.options.nodeFiveAddress, {gasLimit: gasLimitLow}) console.log("transaction hash for addPermissionedNodes on node five:", retFive.hash) await retFive.wait() } @@ -149,8 +159,8 @@ export class AdminZkRandService extends BaseService { console.log("contractPhase", contractPhase) if (contractPhase == Status.Registered) { // all the nodes have registered; start nidkg - const ret = await this.state.zkRandContract.startNidkg() - console.log("transaction hash for startNiDkg: ", ret.hash) + const ret = await this.state.zkRandContract.startNidkg({gasLimit: gasLimitLow}) + console.log("transaction hash for startNiDkg:", ret.hash) await ret.wait() } else if (contractPhase == Status.NidkgComplete) { // nidkg has completed; calculate global public parameters @@ -158,25 +168,30 @@ export class AdminZkRandService extends BaseService { } else if (contractPhase == Status.Ready) { let currentRoundNum = await this.state.zkRandContract.currentRoundNum() console.log("currentRoundNum", currentRoundNum.toString()) - if (currentRoundNum == 0) { - // random generation starts from 1 - await this.initiateRand() + if (Date.now() < this.state.startDate) { + const begin = new Date(this.state.startDate); + console.log("randomness generation will begin at", begin.toUTCString()) } else { - let threshold = await this.state.zkRandContract.threshold() - let submissionCount = await this.state.zkRandContract.roundSubmissionCount(currentRoundNum) - let roundToRandom = await this.state.zkRandContract.roundToRandom(currentRoundNum) - - if (roundToRandom.value === bytes32Zero && submissionCount >= threshold) { - await this.createRandom(currentRoundNum) - } - - let secondsElapsed = Math.floor( - (Date.now() - this.state.timeOfLastRound) / 1000 - ) - console.log('Seconds elapsed since last random initiation:', secondsElapsed) - - if (secondsElapsed > this.options.randGenInterval) { - await this.initiateRand(); + if (currentRoundNum == 0) { + // random generation starts from 1 + await this.initiateRand() + } else { + let threshold = await this.state.zkRandContract.threshold() + let submissionCount = await this.state.zkRandContract.roundSubmissionCount(currentRoundNum) + let roundToRandom = await this.state.zkRandContract.roundToRandom(currentRoundNum) + + if (roundToRandom.value === bytes32Zero && submissionCount >= threshold) { + await this.createRandom(currentRoundNum) + } + + let secondsElapsed = Math.floor( + (Date.now() - this.state.timeOfLastRound) / 1000 + ) + console.log('Seconds elapsed since last random initiation:', secondsElapsed) + + if (secondsElapsed > this.options.randGenInterval) { + await this.initiateRand(); + } } } } @@ -191,15 +206,9 @@ export class AdminZkRandService extends BaseService { this.state.zkRandContract.on(eventReg, async (count, event) => { console.log("\nevent", eventReg, count); // Proceed to the next step here - const res = await this.state.zkRandContract.startNidkg() - const receipt = await this.options.l2RpcProvider.getTransactionReceipt(res.hash); - // Check if the transaction was successful - if (receipt.status === 1) { - console.log("Transaction startNidkg() successful!"); - } else { - console.log("Transaction startNidkg() failed!"); - } - console.log("NIDKG begins...") + const ret = await this.state.zkRandContract.startNidkg({gasLimit: gasLimitLow}) + console.log("transaction hash for startNiDkg: ", ret.hash) + await ret.wait() }); } @@ -229,14 +238,9 @@ export class AdminZkRandService extends BaseService { const filePath = dkgDir + "gpk.json" const gpk = readJsonFromFile(filePath); - const res = await this.state.zkRandContract.computeVk(gpk) - const receipt = await this.options.l2RpcProvider.getTransactionReceipt(res.hash); - // Check if the transaction was successful - if (receipt.status === 1) { - console.log("Transaction computeVk(..) successful!"); - } else { - console.log("Transaction computeVk(..) failed!"); - } + const res = await this.state.zkRandContract.computeVk(gpk, {gasLimit: gasLimitHigh}) + console.log("transaction hash for computeVk: ", res.hash) + await res.wait() // read global public parameters from the contract and compare them with the local version const gpkVal = await this.state.zkRandContract.getGpk() @@ -284,7 +288,7 @@ export class AdminZkRandService extends BaseService { const filePath = dkgDir + "gpk.json" const gpk = readJsonFromFile(filePath); - const res = await this.state.zkRandContract.computeVk(gpk) + const res = await this.state.zkRandContract.computeVk(gpk, {gasLimit: gasLimitHigh}) console.log("transaction hash for computeVk: ", res.hash) await res.wait() @@ -312,11 +316,12 @@ export class AdminZkRandService extends BaseService { async initiateRand() { // Proceed to the next step here - const res = await this.state.zkRandContract.initiateRandom() + const res = await this.state.zkRandContract.initiateRandom({gasLimit: gasLimitLow}) console.log("transaction hash for initiateRandom: ", res.hash) await res.wait() this.state.timeOfLastRound = Date.now() - console.log("******** new random round begins at:", this.state.timeOfLastRound.toString()) + const currentDate = new Date(this.state.timeOfLastRound); + console.log("******** new random round begins at:", currentDate.toUTCString(), "********") } async listenRandThreshold() { @@ -368,14 +373,9 @@ export class AdminZkRandService extends BaseService { const pseudo = readJsonFromFile(pseudoPath) console.log("pseudorandom computed", '0x' + Buffer.from(pseudo[`value`]).toString('hex')) - const res = await this.state.zkRandContract.submitRandom(pseudo) - const receipt = await this.options.l2RpcProvider.getTransactionReceipt(res.hash); - // Check if the transaction was successful - if (receipt.status === 1) { - console.log("Transaction submitRandom(..) successful!"); - } else { - console.log("Transaction submitRandom(..) failed!"); - } + const res = await this.state.zkRandContract.submitRandom(pseudo, {gasLimit: gasLimitLow}) + console.log("transaction hash for submitRandom:", res.hash) + await res.wait() const rand = await this.state.zkRandContract.getLatestRandom() console.log("✅ pseudorandom from contract", rand.value) @@ -429,7 +429,7 @@ export class AdminZkRandService extends BaseService { const pseudo = readJsonFromFile(pseudoPath) console.log("pseudorandom computed", '0x' + Buffer.from(pseudo[`value`]).toString('hex')) - const res = await this.state.zkRandContract.submitRandom(pseudo) + const res = await this.state.zkRandContract.submitRandom(pseudo, {gasLimit: gasLimitLow}) console.log("transaction hash for submitRandom:", res.hash) await res.wait() } diff --git a/services/exec/run.ts b/services/exec/run.ts index 547ff60..e57640d 100644 --- a/services/exec/run.ts +++ b/services/exec/run.ts @@ -31,6 +31,8 @@ const main = async () => { parseInt(env.RAND_GEN_INTERVAL, 10) || 3600 ) + const RAND_GEN_START_DATE = config.str('rand-gen-start-date', env.RAND_GEN_START_DATE) + const ZK_RAND_ADDRESS = config.str('zk-rand-address', env.ZK_RAND_ADDRESS) const NODE_ONE_ADDRESS = config.str('node-one-address', env.NODE_ONE_ADDRESS) const NODE_TWO_ADDRESS = config.str('node-two-address', env.NODE_TWO_ADDRESS) @@ -61,6 +63,7 @@ const main = async () => { nodeFiveAddress: NODE_FIVE_ADDRESS, pollingInterval: POLLING_INTERVAL, randGenInterval: RAND_GEN_INTERVAL, + randGenStartDate: RAND_GEN_START_DATE, }) await service.start() diff --git a/services/node.ts b/services/node.ts index faea052..2641418 100644 --- a/services/node.ts +++ b/services/node.ts @@ -7,7 +7,7 @@ import {exec} from "child_process"; import {sleep} from '@eth-optimism/core-utils' import {BaseService} from '@eth-optimism/common-ts' -import zkRandContractABI from '../artifacts/contracts/zkdvrf.sol/zkdvrf.json' +import zkRandContractABI from '../artifacts/contracts/zkdvrf_pre.sol/zkdvrf_pre.json' export const memberDir = `./data/members/` export const mpksPath = `./data/mpks.json` @@ -38,6 +38,8 @@ interface NodeZkRandOptions { } const optionSettings = {} +const gasLimitLow = 500000 +const gasLimitHigh = 3000000 export class NodeZkRandService extends BaseService { constructor(options: NodeZkRandOptions) { @@ -133,7 +135,7 @@ export class NodeZkRandService extends BaseService { const data = readJsonFromFile(filePath); const mpk = data[`pk`] - const res = await this.state.zkRandContract.registerNode(mpk) + const res = await this.state.zkRandContract.registerNode(mpk, {gasLimit: gasLimitLow}) console.log("transaction hash for registerNode", res.hash) await res.wait() console.log("member ", index, "registered\n") @@ -210,7 +212,7 @@ export class NodeZkRandService extends BaseService { const instance = readJsonFromFile(instancePath) // submit proof and instance to contract - const resPP = await this.state.zkRandContract.submitPublicParams(instance, proof) + const resPP = await this.state.zkRandContract.submitPublicParams(instance, proof, {gasLimit: gasLimitHigh}) console.log("transaction hash for submitPublicParams:", resPP.hash) resPP.wait() } @@ -260,7 +262,7 @@ export class NodeZkRandService extends BaseService { proof: evalJson[`proof`] } - const res = await this.state.zkRandContract.submitPartialEval(pEval) + const res = await this.state.zkRandContract.submitPartialEval(pEval, {gasLimit: gasLimitLow}) console.log("transaction hash for submitPartialEval", res.hash) await res.wait() }