블록체인 학습
0 XP

실습: 중복 투표 방지 (modifier)

지금까지 만든 vote 함수에는 치명적인 허점이 있습니다. 한 사람이 원하는 만큼 여러 번 투표할 수 있어 선거의 공정성이 무너집니다. 현실 선거에서 "1인 1표" 가 기본이듯, 이 컨트랙트도 한 주소는 한 번만 투표 하도록 강제해야 합니다.

투표 기록을 남기고, 검사한다

해법은 두 단계입니다. 첫째, 투표한 주소를 mapping(address => bool) public hasVoted 에 기록합니다. 둘째, 투표하기 전에 hasVoted[msg.sender] 가 이미 true 인지 검사해 이미 투표한 사람을 거부합니다. 여기서 msg.sender 는 함수를 호출한 주소, 즉 투표자 본인을 가리킵니다.

반복 검사는 modifier 로 묶는다

"이미 투표했는지 확인" 같은 검사는 여러 함수에서 재사용될 수 있고, 함수 본문과 검사 로직을 분리하면 코드가 훨씬 읽기 좋습니다. 그래서 검사를 modifier 로 빼냅니다. require 가 거짓이면 트랜잭션 전체가 되돌려지고(revert), 참이면 _; 위치에서 원래 함수 본문이 실행됩니다.

modifier notVotedYet() {
    require(!hasVoted[msg.sender], "already voted"); // 이미 투표함
    _;
}

조건 앞의 느낌표(!)는 "아직 투표하지 않았다면 통과" 라는 뜻입니다. 이걸 반대로 쓰면 투표한 사람만 통과시키는 정반대 동작이 되니 주의하세요.

해야 할 일:

  1. mapping(address => bool) public hasVoted 를 선언하세요.
  2. notVotedYet 라는 modifier 를 만들어 require(!hasVoted[msg.sender], "already voted") 로 검사하고 _; 를 두세요.
  3. vote(uint256 index) 함수에 notVotedYet modifier 를 적용하고, 투표 후 hasVoted[msg.sender] = true; 로 기록하세요.

_; 를 빠뜨리면 함수 본문이 아예 실행되지 않습니다. 또한 투표 후 hasVoted[msg.sender] = true; 기록을 잊으면 검사가 무의미해집니다.

완성 후 Run 으로 조건을 확인하세요.

Code Editor
에디터를 불러오는 중...
실행 결과

Run 버튼을 눌러 코드를 실행하세요.