Skip to content

Instantly share code, notes, and snippets.

@DustinWehr
Created October 10, 2017 15:29
Show Gist options
  • Save DustinWehr/98c9310afab793588aa8e031f1d79aec to your computer and use it in GitHub Desktop.
Save DustinWehr/98c9310afab793588aa8e031f1d79aec to your computer and use it in GitHub Desktop.
ballot.v.py fixed but still simple
# Voting with delegation.
# Information about voters
voters: public({
# weight is accumulated by delegation
weight: num,
# if true, that person already voted or delegated
voted: bool,
# person delegated to
delegate: address,
# index of the voted proposal. not meaningful unless `voted` is True.
vote: num
}[address])
# This is a type for a list of proposals.
proposals: public({
# short name (up to 32 bytes)
name: bytes32,
# number of accumulated votes
vote_count: num
}[num])
voter_count: public(num)
chairperson: public(address)
@constant
def delegated(addr: address) -> bool:
return self.voters[addr].delegate != 0x0000000000000000000000000000000000000000
@constant
def directly_voted(addr: address) -> bool:
return self.voters[addr].voted and self.voters[addr].delegate == 0x0000000000000000000000000000000000000000
# Setup global variables
def __init__(_proposalNames: bytes32[5]):
self.chairperson = msg.sender
self.voter_count = 0
for i in range(5):
self.proposals[i] = {
name: _proposalNames[i],
vote_count: 0
}
# Give `voter` the right to vote on this ballot.
# May only be called by `chairperson`.
def give_right_to_vote(voter: address):
# Throws if sender is not chairperson
assert msg.sender == self.chairperson
# Throws if voter has already voted
assert not self.voters[voter].voted
# Throws if voter's voting weight isn't 0
assert self.voters[voter].weight == 0
self.voters[voter].weight = 1
self.voter_count += 1
# Used by `delegate`. Can be called by anyone.
def forward_weight(delegate_with_weight_to_forward: address):
assert self.delegated(delegate_with_weight_to_forward)
# Throw if there is nothing to do:
assert self.voters[delegate_with_weight_to_forward].weight > 0
target = self.voters[delegate_with_weight_to_forward].delegate
for i in range(10):
if self.delegated(target):
target = self.voters[target].delegate
else:
# This effectively detects cycles of length <= 10.
# BUT cycles aren't actually problematic for correctness;
# they just result in spoiled votes.
# So, in the production version, this should instead be
# the responsibility of the contract's client, and this
# check should be removed.
assert target != delegate_with_weight_to_forward
# weight will be moved to someone who directly voted or
# hasn't voted
break
weight_to_forward = self.voters[delegate_with_weight_to_forward].weight
self.voters[delegate_with_weight_to_forward].weight = 0
self.voters[target].weight += weight_to_forward
if self.directly_voted(target):
self.proposals[self.voters[target].vote].vote_count += weight_to_forward
self.voters[target].weight = 0
# To reiterate: if target is also delegate, this function will need
# to be called again.
# Delegate your vote to the voter `to`.
def delegate(to: address):
# Throws if sender has already voted
assert not self.voters[msg.sender].voted
# Throws if sender tries to delegate their vote to themselves or to
# the default address valye of 0x0000000000000000000000000000000000000000
assert to != msg.sender and to != 0x0000000000000000000000000000000000000000
self.voters[msg.sender].delegate = to
self.voters[msg.sender].voted = True
# this call will throw iff this delegation would cause a loop
# of length <= 10
self.forward_weight(msg.sender)
# Give your vote (including votes delegated to you)
# to proposal `proposals[proposal].name`.
def vote(proposal: num):
assert not self.voters[msg.sender].voted
self.voters[msg.sender].voted = True
self.voters[msg.sender].vote = proposal
# If `proposal` is out of the range of the array,
# this will throw automatically and revert all
# changes.
self.proposals[proposal].vote_count += self.voters[msg.sender].weight
# Computes the winning proposal taking all
# previous votes into account.
@constant
def winning_proposal() -> num:
winning_vote_count = 0
for i in range(5):
if self.proposals[i].vote_count > winning_vote_count:
winning_vote_count = self.proposals[i].vote_count
winning_proposal = i
return winning_proposal
# Calls winning_proposal() function to get the index
# of the winner contained in the proposals array and then
# returns the name of the winner
@constant
def winner_name() -> bytes32:
return self.proposals[self.winning_proposal()].name
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment