Merge pull request #2075 from AleoHQ/example/vote

Commit vote example
This commit is contained in:
Collin Chin 2022-09-20 10:40:29 -07:00 committed by GitHub
commit 93307b1446
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 250 additions and 0 deletions

2
examples/vote/.gitignore vendored Normal file
View File

@ -0,0 +1,2 @@
outputs/
build/

94
examples/vote/README.md Normal file
View File

@ -0,0 +1,94 @@
# Leo Vote
## Summary
`vote.leo` is a general vote program.
Anyone can issue new proposals,
proposers can issue tickets to the voters,
and voters can vote without exposing their identity.
This example is inspired by the [aleo-vote](https://github.com/zkprivacy/aleo-vote) example written by the Aleo community.
## Noteworthy Features
Voter identity is concealed by privately passing a voter's ballot into a function.
Proposal information and voting results are revealed using the public `mapping` datatype in Leo.
## How to Run
To compile this Leo program, run:
```bash
leo build
```
Make changes to `vote/inputs/vote.in` before running each command.
### Propose
Anyone can issue a new proposal publicly by calling `propose` function.
Run `propose`:
```
leo run propose
```
Output sample:
```
{
owner: aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2.private,
gates: 0u64.private,
id: 2805252584833208809872967597325381727971256629741137995614832105537063464740field.private,
info: {
title: 2077160157502449938194577302446444field.private,
content: 1452374294790018907888397545906607852827800436field.private,
proposer: aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2.private
},
_nonce: 1639660347839832220966145410710039205878572956621820215177036061076060242021group.public
}
```
### Create Ticket
Proposers can create new tickets for proposed proposals.
Ticket is a record with `owner` and `pid`,
it can be used to vote for the specific proposal - `pid`,
and can only be used(voted) by the ticket `owner`.
Run `new_ticket`:
```
aleo run new_ticket
```
Output sample:
```
{
owner: aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2.private,
gates: 0u64.private,
pid: 2264670486490520844857553240576860973319410481267184439818180411609250173817field.private,
_nonce: 1637267040221574073903539416642641433705357302885235345311606754421919550724group.public
}
```
### Vote
A ticket owner can use their ticket record to vote `agree` / `disagree` with the specific proposal - `pid`.
Since the ticket record can be used as an input privately, the voter's privacy is protected.
Run `agree`:
```
leo run agree
```
Run `disagree`:
```
leo run disagree
```

View File

@ -0,0 +1,27 @@
// The program input for vote/src/main.leo
[propose]
info: ProposalInfo = ProposalInfo {
title: 2077160157502449938194577302446444field,
content: 1452374294790018907888397545906607852827800436field,
proposer: aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2,
};
[new_ticket]
pid: field = 2264670486490520844857553240576860973319410481267184439818180411609250173817field;
voter: address = aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2;
[agree]
ticket: Ticket = Ticket {
owner: aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2,
gates: 0u64,
pid: 2264670486490520844857553240576860973319410481267184439818180411609250173817field,
_nonce: 1637267040221574073903539416642641433705357302885235345311606754421919550724group
};
[disagree]
ticket: Ticket = Ticket {
owner: aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2,
gates: 0u64,
pid: 2264670486490520844857553240576860973319410481267184439818180411609250173817field,
_nonce: 1637267040221574073903539416642641433705357302885235345311606754421919550724group
};

View File

@ -0,0 +1,10 @@
{
"program": "vote.aleo",
"version": "0.0.0",
"description": "",
"development": {
"private_key": "APrivateKey1zkpBDEpwdFWqxe1NdB9fxZxiX9LahJ3CdqchSs7FGZVggNw",
"address": "aleo1kkk52quhnxgn2nfrcd9jqk7c9x27c23f2wvw7fyzcze56yahvcgszgttu2"
},
"license": "MIT"
}

21
examples/vote/run.sh Executable file
View File

@ -0,0 +1,21 @@
# Build the Leo vote program.
(
leo build || exit
)
# Run the `propose` program function
(
leo run propose || exit
)
# Run the `new_ticket` program function
(
leo run new_ticket || exit
)
# Run the `agree` or `disagree` program function
(
leo run agree || exit
# leo run disagree || exit
)

View File

@ -0,0 +1,96 @@
// The 'vote.leo' program.
// Proposal details
circuit ProposalInfo {
title: field,
content: field,
proposer: address,
}
// Proposal record records proposal info publicly
record Proposal {
owner: address,
gates: u64,
id: field,
info: ProposalInfo,
}
// Save proposal info in public storage.
mapping proposals: field => ProposalInfo;
// Privacy tickets to vote
record Ticket {
owner: address,
gates: u64,
pid: field,
}
// Count the total tickets issued for each proposal
mapping tickets: field => u64;
mapping agree_votes: field => u64;
mapping disagree_votes: field => u64;
// Propose a new proposal to vote on.
@program
function propose(public info: ProposalInfo) -> Proposal {
// Authenticate proposer.
console.assert_eq(self.caller, info.proposer);
// Generate a new proposal id.
let id: field = BHP256::hash(info.title);
// Finalize the proposal id.
finalize(id);
// Return a new record for the proposal.
return Proposal {
owner: self.caller,
gates: 0u64,
id,
info,
};
}
// Create a new proposal in the "tickets" mapping.
finalize propose(public id: field) {
increment(tickets, id, 0u64);
}
// Create a new ticket to vote with.
@program
function new_ticket(
public pid: field,
public voter: address,
) -> Ticket {
// Finalize the proposal id for the ticket.
finalize(pid);
return Ticket {
owner: voter,
gates: 0u64,
pid,
};
}
// Create a new ticket on a proposal in the "tickets" mapping.
finalize new_ticket(public pid: field) {
increment(tickets, pid, 1u64);
}
// Vote to agree with a proposal.
@program
function agree(ticket: Ticket) {// Privately cast the vote.
finalize(ticket.pid);
}
finalize agree(public pid: field) {// Publicly increment the number of agree votes.
increment(agree_votes, pid, 1u64);
}
// Vote to disagree with a proposal.
@program
function disagree(ticket: Ticket) {// Privately cast the vote.
finalize(ticket.pid);
}
finalize disagree(pid: field) {// Publicly increment the number of disagree votes.
increment(disagree_votes, pid, 1u64);
}