Problem Statement
You are tasked with creating a simple voting smart contract for an organization's general meeting. The contract should allow the chairperson to add voters, and each voter can cast one vote for one of two candidates. The contract must emit events whenever a voter is registered or votes. Additionally, the chairperson should be able to announce the winner after all votes have been cast. Ensure that only the chairperson can add voters or announce the winner, and that voters cannot vote more than once.
Requirements:
- Implement the contract in Solidity 0.8.x.
- Use events to log voter registration and voting actions.
- Utilize modifiers to restrict functions based on roles (chairperson, voter).
- Prevent reentrancy attacks.
Concepts
- Solidity
- Events
- Modifiers
Constraints
- Use only Solidity 0.8.x
- The chairperson can add voters at any time before the voting ends
- Voters can vote only once
Security Notes
- Ensure that the contract is resistant to reentrancy attacks
- Validate all inputs in functions to avoid unexpected behavior or vulnerabilities
Solutions
Python Solution
pragma solidity ^0.8.0;
contract Voting {
// Define the structure of a voter
struct Voter {
bool isRegistered;
bool hasVoted;
uint256 vote;
}
// Events for logging actions
event VoterRegistered(address indexed voter);
event Voted(address indexed voter, uint256 candidate);
event WinnerAnnounced(uint256 winner);
// State variables
address public chairperson;
mapping(address => Voter) public voters;
uint256 public totalVotesCandidate1;
uint256 public totalVotesCandidate2;
bool private votingEnded;
// Modifier to restrict functions to the chairperson only
modifier onlyChairperson() {
require(msg.sender == chairperson, "Only chairperson can perform this action");
_;
}
// Modifier to restrict functions to voters only
modifier onlyVoters() {
require(voters[msg.sender].isRegistered, "You are not a registered voter");
_;
}
// Constructor sets the chairperson when the contract is deployed
constructor() {
chairperson = msg.sender;
}
// Function to register a new voter
function addVoter(address voter) public onlyChairperson {
require(!voters[voter].isRegistered, "This address is already registered");
voters[voter] = Voter(true, false, 0);
emit VoterRegistered(voter);
}
// Function to cast a vote for a candidate (1 or 2)
function vote(uint256 candidate) public onlyVoters {
require(!voters[msg.sender].hasVoted, "You have already voted");
require(candidate == 1 || candidate == 2, "Invalid candidate number");
voters[msg.sender].hasVoted = true;
voters[msg.sender].vote = candidate;
if (candidate == 1) {
totalVotesCandidate1 += 1;
} else {
totalVotesCandidate2 += 1;
}
emit Voted(msg.sender, candidate);
}
// Function to announce the winner
function announceWinner() public onlyChairperson returns (uint256) {
require(!votingEnded, "Voting has already ended");
votingEnded = true;
uint256 winner = totalVotesCandidate1 > totalVotesCandidate2 ? 1 : 2;
emit WinnerAnnounced(winner);
return winner;
}
} This Solidity contract implements a simple voting system for an organization's general meeting. The chairperson can register voters, and each registered voter can cast one vote for either candidate 1 or candidate 2. Events are emitted whenever a voter is registered or votes, and the chairperson can announce the winner once all votes have been cast.
The contract uses modifiers to restrict certain functions to only the chairperson (such as adding voters and announcing the winner) and others to only registered voters (such as voting). This ensures that only authorized parties can perform specific actions. Additionally, the contract prevents reentrancy attacks by not allowing any external calls during critical operations.
The state variables include a mapping of voters' addresses to their respective Voter structures, which track whether they are registered, have voted, and for whom. The total votes for each candidate are also tracked using two separate counters. The voting process ends when the chairperson announces the winner, at which point further modifications to the vote counts are prevented.