본문 바로가기

블록체인

[블록체인] 이더리움 & 솔리디티 기반의 투표 dApp 구현하기

스마트 계약을 컴파일, 블록체인에 배포 경험

과정

  1. 가나슈라는 가짜 블록체인 설치(개발 환경 상에서 애플리케이션 돌릴 준비)
  2. *가나슈는 개발 목적으로만 쓰이는 인 메모리 블록체인
  3. 솔리디티 언어로 스마트 컨트랙트 구현 → 블록체인에 배포
  4. 커맨드 창에서 가나슈와 상호작용 → 웹페이지와 통하도록

블록체인과 상호작용하려면 RPC(Remote Precedure Call)을 통해야 한다.

Web3JS로 RPC 호출하는 라이브러리로 Javascript를 통해 블록체인과 상호작용하게 해주는 역할을 한다. 리액트, 앵귤러같은 프레임워크로 웹앱 만들기도 가능

개발환경 설정

  1. Node.js와 npm 설치
  2. npm으로 가나슈, web3js, 솔리디티컴파일러 설치
mkdir -p ethereum_voting_dapp/chapter1
cd ethereum_voting_dapp/chapter1
npm install ganache-cli web3@0.20.3 solc
node_modules/.bin/ganache-cli

블록체인이 실행되고 테스트 계정 10개가 생김

노드 실행 🔽

Web3 = require('web3')
web3 = new Web3(new Web3.providers.HttpProvider("<http://localhost:8545>")) // 8545는 블록체인이 실행되는 포트
weeb.eth.getAccounts // 계정 10개 출력
web3.eth.getBalance('0x64255d440b08b4eff4a603bdbe2fa0b773dd6600') // 각 계정의 잔고 확인
web3.eth.getBalance('0x64255d440b08b4eff4a603bdbe2fa0b773dd6600').toNumber() // Wei 단위, 1ether = 10^18wei
web3.fromWei('100000000000000000000', 'ether') // ether 단위

솔리디티로 컨트랙트 작성

컨트랙트 기능

  1. 각 후보자들을 초기화한다.
  2. 후보자에 대해 투표한다.
  3. 각 후보자에 대한 득표수를 확인할 수 있어야 한다.

컨트랙트를 구현하기 위한 브라우저 리믹스(Remix) 사용

// SPDX-License-Identifier: UNLICENSED
pragma solidity ^0.8.15;

contract Voting {
    // constructor to initailize candidates
    // vote for candidates
    // get count of votes for each candidates

    bytes32[] public candidateList;
    mapping (bytes32 => uint8) public votesReceived; // 연관배열 = 해시 = mapping, 득표수를 계속 추적하기 위함 // defaultValue = 0
    
	constructor(bytes32[] memory candidateNames) {
        candidateList = candidateNames;
    }

    function voteForCandidate(bytes32 candidate) public {
        require(validCandidate(candidate));
        votesReceived[candidate] += 1;
    }

    // 단순 읽기 지정자(modifier) view
    function totalVotesFor(bytes32 candidate) view public returns(uint8) {
        require(validCandidate(candidate));
        return votesReceived[candidate];
    }

    // 유효한 후보인지 체크
    function validCandidate(bytes32 candidate) view public returns(bool) {
        for(uint i=0; i < candidateList.length; i++) {
            if (candidateList[i] == candidate) {
                return true;
            }
        }
        return false;
    }
}

나중에 컴파일, 블록체인 상호작용에 트러플 프레임워크 사용 → abi 등 직접 다루지 않아도 됨

컨트랙트 컴파일하기

node_modeuls/.bin/solcjs --bin --abi Voting.sol
  • Voting_sol_Voting.abi (Application Binary Interface) 일종의 컨트랙트 템플릿. 컨트랙트 사용자와 상호작용하려면 필요
  • Voting_sol_Voting.bin

위 파일 생성 됨

code = fs.readFileSync('Voting.sol').toString()
solc = require('solc')
compiledCode = solc.compile(code)

컨트랙트를 블록체인에 배포하기

ABI 정의를 전달해서 VotingContract 객체를 만들기

  1. abi 가져오기 → JSON 형태로 파싱 → abi 정의 완료
  2. votingContract 객체를 만들어 abiDefinition에 전달 블록체인에 배포하는 것은 bytecode
  3. 컨트랙트 배포 → 생성자 실행
Web3 = require('web3')
web3 = new Web3(new Web3.providers.HttpProvider("<http://localhost:8545>"));
bytecode = fs.readFileSync('./Voting_sol_Voting.bin').toString()
abi = JSON.parse(fs.readFileSync('./Voting_sol_Voting.abi').toString())
deployedContract = new web3.eth.contract(abi)

강의 밑에

Web3 = require('web3')
web3 = new Web3(new Web3.providers.HttpProvider("<http://localhost:8545>"));
abiDefinition = JSON.parse(compiledCode.contracts[':Voting'].interface)
VotingContract = web3.eth.contract(abiDefinition)
byteCode = compiledCode.contracts[':Voting'].bytecode
// ******** 오류 *********
deployedContract = VotingContract.new(['Rama','Nick','Jose'],{data: byteCode, from: web3.eth.accounts[0], gas: 4700000})
deployedContract.address
'0x0396d2b97871144f75ba9a9c8ae12bf6c019f610' <- Your address will be different