Solidity中结构体数组for循环失效导致投票函数回滚问题
投票合约问题修复方案
核心问题分析
你的voterRules修饰器存在两处逻辑错误,导致已注册选民调用vote函数时触发回滚:
1. 选民身份验证逻辑错误
原代码遍历voterList时,只要有一个选民地址与调用者不匹配就触发回滚,这意味着只有当列表中所有地址都等于调用者时才通过验证,完全违背了"检查调用者是否在选民列表中"的需求。正确逻辑应该是遍历列表寻找匹配地址,若全程未找到则回滚。
2. 重复投票验证逻辑错误
原代码遍历candidateList检查voterToCandidate[msg.sender]是否等于任何候选人地址,会导致两种错误:
- 若存在候选人地址为
0x0,未投票的调用者(映射默认值为0x0)会被误判为已投票 - 已投票的调用者会触发所有候选人的检查,只要匹配就回滚,逻辑冗余且错误
修复后的完整合约代码
//SPDX-License-Identifier:UNLICENSED pragma solidity ^0.8.0; contract Ballot{ // VARIABLES address private chairperson; // MODIFIERS modifier isOwner(){ require(msg.sender == chairperson); _; } modifier isVoter(address voterAddress_){ require(voterAddress_ == msg.sender,"The voter must register by itself..."); _; } modifier voterRules(){ require(msg.sender != chairperson,"Chairperson cannot vote!!"); // 修复:验证调用者是否在选民列表中 bool isRegistered = false; for(uint m=0;m<voterList.length;m++){ if(msg.sender == voterList[m]._voterAddress){ isRegistered = true; break; } } require(isRegistered, "You must register yourself first..."); // 修复:验证是否已投票(使用Voter结构体的_isVoted字段更可靠) bool hasVoted = false; for(uint n=0;n<voterList.length;n++){ if(msg.sender == voterList[n]._voterAddress && voterList[n]._isVoted){ hasVoted = true; break; } } require(!hasVoted, "You cannot vote twice..."); _; } // CONSTRUCTOR constructor(){ chairperson = msg.sender; } // STRUCTS struct Candidate{ address _address; uint256 _noOfVotes; } struct Voter{ address _voterAddress; bool _isVoted; } // ARRAYS Candidate[] public candidateList; Voter[] public voterList; // MAPPINGS mapping(address=>address) private voterToCandidate; // FUNCTIONS function addCandidate(address address_) public isOwner{ for(uint i=0;i<candidateList.length;i++){ require(address_ != candidateList[i]._address, "Same Candidate cannot be added twice"); } candidateList.push(Candidate(address_,0)); } function registerVoter(address voterAddress_) external isVoter(voterAddress_){ for(uint j=0;j<voterList.length;j++){ require(voterAddress_ != voterList[j]._voterAddress,"Voter already registered"); } voterList.push(Voter(voterAddress_,false)); } function vote(uint256 _candId) public voterRules() { // 额外添加:验证候选人ID是否合法,防止越界访问 require(_candId < candidateList.length, "Invalid candidate ID"); voterToCandidate[msg.sender] = candidateList[_candId]._address; candidateList[_candId]._noOfVotes++; // 更新Voter结构体的_isVoted状态 for(uint p=0;p<voterList.length;p++){ if(msg.sender == voterList[p]._voterAddress){ voterList[p]._isVoted = true; break; } } } }
额外优化说明
- 为
vote函数添加候选人ID合法性检查,避免数组越界访问 - 改用
Voter结构体中的_isVoted字段验证重复投票,比依赖映射更可靠,规避了候选人地址为0x0的误判风险 - 优化注册函数的错误提示信息,表述更清晰明确
内容的提问来源于stack exchange,提问作者VIVEK T
相关产品推荐
相关产品推荐

