A funding round coordinator can tally votes using the MACI CLI, Docker or clrfund scripts.
Clone the MACI repo and switch to version v0.10.1:
git clone https://github.com/privacy-scaling-explorations/maci.git
cd maci/
git checkout v0.10.1
Follow instructions in README.md to install necessary dependencies.
Download the zkSNARK parameters for 'batch 64' circuits into the circuits/params/
directory.
Change the permission of the c binaries to be executable:
cd circuits/params
chmod u+x qvt32 batchUst32
Or, run the script monorepo/.github/scripts/download-batch64-params.sh to download the parameter files.
The contract deployment scripts, deploy*.ts
in the clrfund repository currently use the batch 64
circuits, if you want to use a smaller size circuits, you can find them here. You will need to update the deploy script to call deployMaciFactory()
with your circuit and redeploy the contracts.
// e.g. to use the x32 circuits
const circuit = 'x32' // defined in contracts/utils/deployment.ts
const maciFactory = await deployMaciFactory(deployer, circuit)
Compile the contracts to generate the ABI that the MACI command lines use in the next step.
cd ../contracts
npm run compileSol
Generate the coordinator key used to encrypt messages. The key will be used when deploying new round.
cd ../cli
node build/index.js genMaciKeypair
A single key can be used to coordinate multiple rounds.
Download the logs to be fed to the proveOnChain
step. This step is useful
especially to avoid hitting rating limiting from the node. Make sure to run this
step againts a node that has archiving enabled, e.g. could use the alchemy node:
cd ../cli
node build/index.js fetchLogs \
--eth-provider <ETH_HOSTNAME> \
--contract <MACI_CONTRACT_ADDR> \
--start-block <BLOCK_NUMBER> \
--num-blocks-per-request <BLOCKS_PER_REQ> \
--output logs
Decrypt messages, tally the votes and generate proofs:
node build/index.js genProofs \
--eth-provider <ETH_HOSTNAME> \
--contract <MACI_CONTRACT_ADDR> \
--privkey <COORDINATOR_PRIVKEY> \
--tally-file tally.json \
--logs-file logs \
--macistate macistate \
--output proofs.json
The coordinator private key (COORDINATOR_PRIVKEY
) must be in the MACI key format (starts with macisk
). It is used to decrypt messages.
The genProofs
command will create two files: proofs.json
and tally.json
. The proofs.json
file will be needed to run the next command, proveOnChain
, which submits proofs to the MACI contract:
node build/index.js proveOnChain \
--eth-provider <json-rpc-api-url> \
--contract <maci-address> \
--eth-privkey <eth-private-key> \
--proof-file proofs.json
The Ethereum private key (eth-private-key
) can be any private key that controls the necessary amount of ETH to pay for gas.
The process may take several hours. Results can be found in tally.json
file, which must then be published via IPFS.
Finally, the CID of tally file must be submitted to FundingRound
contract:
await fundingRound.publishTallyHash('<CID>')
In case you are in a different OS than Linux, you can run all the previous MACI CLI commands by running the Docker image located in the MACI repo.
Note: the batch 64 zkSNARK parameters have been tested using Ubuntu 22.04 + Node v16.13.2
First, install docker and docker-compose
Inside the maci repo, run:
docker-compose up
Once the container is built, in a different terminal, grab the container id:
docker container ls
Get inside the container and execute the scripts you want:
docker exec -it {CONTAINER_ID} bash
# inside the container
cd cli/
node build/index.js genProofs ...
cd contracts/
yarn ts-node scripts/generate-key.ts
A single key can be used to coordinate multiple rounds.
Install zkutil (see instructions in MACI readme).
Switch to contracts
directory:
cd contracts/
Download zkSNARK parameters for 'batch 64' circuits to snark-params
directory. Example:
ipfs get --output snark-params QmbVzVWqNTjEv5S3Vvyq7NkLVkpqWuA9DGMRibZYJXKJqy
Change the permission of the c binaries to be executable:
cd snark-params
chmod u+x qvt32 batchUst32
Or, run the script monorepo/.github/scripts/download-batch64-params.sh to download the parameter files.
Set the path to downloaded parameter files and also the path to zkutil
binary (if needed):
export NODE_CONFIG='{"snarkParamsPath": "path-to/snark-params/", "zkutil_bin": "/usr/bin/zkutil"}'
Set the following env vars in .env
:
# private key for decrypting messages
COORDINATOR_PK=<coordinator-private-key>
# private key for interacting with contracts
COORDINATOR_ETH_PK=<eth-private-key>
Decrypt messages and tally the votes:
yarn hardhat tally --network {network} --round-address {funding-round-address} --start-block {maci-contract-start-block}
If there's error and the tally task was stopped prematurely, it can be resumed by passing 2 additional parameters, '--maci-logs' and/or '--maci-state-file', if the files were generated.
Result will be saved to tally.json
file, which must then be published via IPFS.
Using command line
# start ipfs daemon in one terminal
ipfs daemon
# in a diff terminal, go to `/contracts` (or where you have the file) and publish the file
ipfs add tally.json
Make sure you have the following env vars in .env
. Ignore this if you are running a local test round in localhost
, the script will know these values itself.
FACTORY_ADDRESS=<funding-round-factory-address>
COORDINATOR_ETH_PK=<eth-private-key>
Once you have the tally.json
from the tally script, run:
yarn hardhat run --network {network} scripts/finalize.ts
Anyone can verify the tally results using the MACI cli or clrfund scripts.
Follow the steps in tallying votes to get the MACI cli, circuit parameters, and tally file, and verify using the following command:
node build/index.js verify -t tally.json
From the clrfund contracts folder, run the following command to verify the result:
yarn ts-node scripts/verify.ts tally.json
After finalizing the round, enable the leaderboard view in the vue-app by exporting the round information as follow:
- Set the etherscan API key in the hardhat.config.ts file in the contracts folder
- Export the round and tally result
cd contracts
yarn hardhat fetch-round --output-dir ../vue-app/src/rounds --network xdai --round-address <round address> --operator <operator>
- Build and deploy the app
If you encountered core dumped
while running the genProofs script as seen in this issue, make sure the files are not corrupted due to disk space issue, e.g. check file sizes, checksum, and missing files.