본문 바로가기
블록체인/이더리움

[이더리움 dApp] 로또 스마트 컨트랙트 Tutorial

by dev_mac-_- 2019. 8. 10.

1. 개요

블록체인은 기존 중앙 시스템과 달리 분산 원장을 가진다는 장점을 가지고있다. 이 장점을 이용하면 데이터가 여러사람에 의해 무결성을 검증받을 수 있다는 점이다. 

블록체인 기술로 만들어진 이더리움은 블록체인이 가진 장점에 더해 스마트 컨트랙트를 작성할 수 있게 되었다. 

이번 튜토리얼은 로또 스마트컨트랙트를 만들어 보는 내용이다.

로또 스마트 컨트랙트

위 그림은 로또 dApp의 전체적인 구성도이다. 참여자들은 스마트 컨트랙트를 이용해 일정 금액을 모금하고 모금이 완료되면 컨트랙트 생성을 했던 사람은 당첨자 추첨을 진행합니다. 

 

2. 로또 컨트랙트 작성

pragma solidity ^0.5.10;

contract Lottery {

}

기본적인 컨트랙트를 작성합니다. 필요한 변수는 2가지가 필요합니다.

  1. 스마트 컨트랙트 생성자
  2. 로또 참여자 배열
pragma solidity ^0.5.10;

contract Lottery {
	
    address public owner;	// 스마트 컨트랙트 생성한 사람
    
    address payable[] public players;	// 로또 참여자
    
    // 생성자
    constructor() public {
    	owner = msg.sender;
    }
}

constructor() 부분에서는 해당 컨트랙트가 생성시 자동으로 owner 변수에 스마트 컨트랙트를 생성한 사람의 정보가 담깁니다.

이번에는 로또 컨트랙트에 입금하는 함수를 작성해보겠습니다.

function deposit() public payable {

    require(msg.sender >= 1 ether, "Minimum value is 1ETH");
    players.push(msg.sender);
}

해당 함수에는 ETH를 전송하는 기능을 포함해야하므로 payable을 붙여줍니다.

그리고 최소 입금 금액은 1ether이상만 가능하고 로또 응모자로 등록됩니다.

function generateRandomNumber() public view returns (uint) {
    return uint(keccak256(abi.encodePacked(now, block.difficulty, players.length)));
}

해당 함수는 로또 당첨자를 추첨하기 위한 난수 생성함수입니다.

이 부분까지 테스트 하기 위해서 remix에 deploy를 합니다.

http://remix.ethereum.org/

deploy를 하면 작성한 함수 2개 그리고 전역변수 2개를 볼 수 있습니다. 

먼저 해당 로또 컨트랙트를 deploy한 계정주소를 보겠습니다.

deploy한 주소입니다. 이 후 tutorial에서 설명드리겠지만 해당 계정으로만 로또 당첨자 추첨을 진행할 수 있습니다.

generateRandomNumber함수를 통해 얻은 값입니다. 해당 값은 블록 생성시간, 블록 difficulty, 참여자 수를 이용해 난수를 생성한 값입니다. 추후 (로또 당첨자 추첨시 해당 값 % 로또 참여자 수)를 한 나머지 값이 당첨자가 됩니다.

이제 4개의 계정을 이용해 1ETH씩 deposit을 한 후 players 변수 값을 확인해보겠습니다.

총 4명의 참여자가 players 배열변수에 등록되있는 것을 확인해볼 수 있습니다.

마지막으로 로또 추첨을 하는 함수를 작성해보겠습니다.

그 전에 개요부분에서 로또 컨트랙트에서 로또 당첨자 추첨은 스마트컨트랙트 deploy한 계정만 동작시킬 수 있다고 정의하였습니다. 

해당 부분을 구현하기 위해서는 solidity 문법에서 modifier을 사용해야합니다.

modifier OwnerOnly {
    if (msg.sender == owner) {
    	_;
    }
}

트랜잭션을 발생하는 계정이 스마트 컨트랙트가 deploy한 계정일 때만 함수가 호출되게 하는 modifier이다.

function pickWinner() OwnerOnly public {
	
    uint randNum = generateRandomNumber();	// 난수 생성
    uint idx = randNum % players.length;	// 당첨자 index
    
    address payable winner;		// 당첨자 address
    
    winner = players[idx];		
    winner.transfer(address(this).balance);		// 당첨자 address로 모금액 전송
    
    players = new address payable [](0);	// players 배열 초기화
}

해당 함수를 구현 후 pickWinner을 호출하면 로또 당첨금액이 당첨자에게 입금되는 스마트컨트랙트를 만들 수 있다.

 

전체 코드 : https://gist.github.com/dongw00/ed5ef601b85381ec093042aa158d03a3#file-lottery-sol

댓글