본문 바로가기

Ethereum/Solidity

Solidity _(1)Voting Program

투표 smart contract를 만들어 보겠습니다.  해당 컨트랙트의 설계는 다음과 같이 할 것입니다.

 

1. 투표 후보자는 byte형식으로 입력할 것입니다. 

2. 후보별 총 득표수를 볼 수 있습니다. 

3. 특정 후보에게 투표하면 특정 후보의 득표수가 1 증가합니다. 

4. 후보자 이외의 자에게 투표하면 함수가 실행되지 않도록 합니다. 

 

[Step1]

pragma solidity ^0.5.2;

contract Voting{
    mapping (bytes32 => uint256) public votesReceived;
    
    bytes32[] public candidateList;

 

1행 : 솔리디티 0.5.2 버전을 선언합니다. 

 

2행 : Voting이라는 이름을 갖은 컨트랙트를 만듭니다. 

 

3행 : 먼저 votesReceived라는 mapping을 정의합니다. mapping의 key는 byte32 이고 value는 uint256입니다. 

 

4행 : candidateList라는 이름의 public bytes32 동적배열을 만듭니다. 우리는 이 배열안에 투표에 참가할 후보자들을 넣을 것입니다. 

 

[Step 2]

pragma solidity ^0.5.2;

contract Voting{
    mapping (bytes32 => uint256) public votesReceived;
    
    bytes32[] public candidateList;
    
    constructor(bytes32[] memory candidateNames) public {
        candidateList = candidateNames;
    }

 

5행 : constructor를 생성합니다. constuructor은 컨트랙트가 배포될 때 호출됩니다. 우리는 컨트랙트가 배포될 때 배열 형식으로 후보자들의 이름을 bytes32형식으로 넣어줄 것입니다. 아래의 6행에서 우리가 입력한 배열을 condidateList에 넣어줄것이므로 굳이 storage로 저장하여 gas를 낭비할 필요가 없습니다. 따라서 memory형식으로 입력하여 우리가 입력한 배열을 함수가 실행되는 동안만 저장하고 함수가 다 동작한 후에는 지워지도록 합니다. 

 

6행 : 우리가 입력한 cadidateNames 배열은 candidateList에 저장합니다. candidateList.push( ) 형식을 쓰지 않는 이유는 우리가 입력한 배열 그대로 저장 할 것 이기 때문입니다. 우리가 입력한 cadidateNames 배열의 이름을 candidateList로 바꾼다고 생각하시면 이해하기 쉬울것입니다. 

 

[Step 3]

pragma solidity ^0.5.2;

contract Voting{
    mapping (bytes32 => uint256) public votesReceived;
    
    bytes32[] public candidateList;
    
    constructor(bytes32[] memory candidateNames) public {
        candidateList = candidateNames;
    }
    
    function totalVotesFor(bytes32 candidate) view public returns (uint256) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

 

8행 : totalVotesFor이라는 이름을 갖은 함수를 정의합니다. 이 함수는 byte32형식의 인수 candidate를 전달받는 함수입니다. 이 함수는 리턴값을 uint256형식으로 받게됩니다. 

 

9행 : 해당 함수를 실행하기 위한 조건을 설정합니다. validCandidate함수는 마지막에 정의할 것이므로 밑에서 설명하도록 하겠습니다. 

 

10행 : 해당 함수는 votesReceived(candidate)의 값을 반환합니다. 위에서 mapping한대로 투표 후보자의 이름을 byte32형식으로 넣어서 함수를 실행하게되면 투표 후보자의 이름을 key로하는 value(uint256형식)값이 반환될것입니다. 즉, 함수를 실행할기 전까지 특정 후보가 투표받은 수를 확인 할 수 있습니다. 

 

[Step 4]


contract Voting{
    mapping (bytes32 => uint256) public votesReceived;
    
    bytes32[] public candidateList;
    
    constructor(bytes32[] memory candidateNames) public {
        candidateList = candidateNames;
    }
    
    function totalVotesFor(bytes32 candidate) view public returns (uint256) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }
    
    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

12행 : voteForCandidate라는 이름을 갖는 public함수를 정의합니다. 이 함수는 byte32형식의 candidate를 인자로 받는 함수입니다. 

 

13행 : 해당함수를 실행하기 위한 조건입니다. 9행과 같으므로 밑에서 설명하도록 하겠습니다. 

 

14행 : 해당 함수를 실행하게되면 위에서 mapping한 uint256형태의 값이 반환됩니다. 함수가 실행되기 전의 값은 '0' 일것입니다. 우리가 특정 후보에 투표하기위해 그 사람의 이름을 bytes32형태로 넣어 함수를 실행하게 되면 mapping한 정의에 따라 최초 0이 반환될것이고 이 값에 1이 더해지게되여 최종적으로 1이 되게됩니다. 즉 우리가 선택한 후보가 1표를 받게 되는것입니다. 

 

[Step 5]

pragma solidity ^0.5.2;

contract Voting{
    mapping (bytes32 => uint256) public votesReceived;
    
    bytes32[] public candidateList;
    
    constructor(bytes32[] memory candidateNames) public {
        candidateList = candidateNames;
    }
    
    function totalVotesFor(bytes32 candidate) view public returns (uint256) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }
    
    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }
    
    function validCandidate(bytes32 candidate) view public returns (bool) {
        for(uint i = 0; i < candidateList.length; i++) {
            if(candidateList[i] == candidate) {
                return true;
            }
        }
        return false;
    }
}

15항 : validCandidate라는 이름을 갖은 함수를 정의합니다. 이 함수는 위에서 정의한 totalVotesFor함수와 voteForCandidate 함수를 실행하는 조건으로 사용될 것입니다.  해당 함수는 리턴값으로 boolean(참 또는 거짓)을 반환하게 됩니다. 

 

16항 : for문을 이용하여 반복작업을 처리합니다. 해당 반복문은 i가 0부터 시작하여 cadidasteList의 길이 전까지 실행될것입니다.  cadidasteList의 길이가 5라면 i = 0 부터 i = 4 까지 총 5번을 반복 할 것입니다. 

 

17항 : 조건문을 정의합니다. 해당 함수에 입력한 후보자의 이름의 bytes32값이 candidasteList에 있는지 리스트의 길이만큼 반복하여 찾게 됩니다. 반복하여 찾은 결과 해당 리스트에 후보자의 이름이 있는 경우에는 리턴값으로 true를 반환합니다. 반복하여 찾은 결과 후보자의 이름이 없는 경우 리턴값으로 false를 반환합니다. require는 ( ) 안의 값이 ture인 경우에만 require가 정의된 함수를 실행시키므로 입력한 후보자의 이름이  candidasteList에 있는 경우에만 8행의 totalVotesFor함수와 12행의 voteForCandidate 함수가 실행 될 것입니다. 

'Ethereum > Solidity' 카테고리의 다른 글

CrytoZombies_Lesson3_고급 솔리디티 개념  (0) 2019.07.23
CrytoZombies_Lesson2_심화문법  (0) 2019.07.23
CrytoZombies_Lesson1_기본문법  (0) 2019.07.23
CryptoZombies_Epilogue  (0) 2019.07.23