Crypto Zombies

CZ 001 - Contract, 자료형, 구조체, 함수, 이벤트

#Solidity

Solidity

Solidity란 이더리움(Ethereum)과 같은 블록체인 플랫폼에서
스마트 컨트랙트를 개발하기 위한 고급 프로그래밍 언어이다.
스마트 컨트랙트는 블록체인 상에서 특정 조건이 충족될 때 자동으로 실행되는 계약을 의미한다.
솔리디티는 이더리움 가상 머신(EVM)에서 구동되도록 설계되었으며,
C++, Python, JavaScript의 영향을 받아 만들어졌다.

Contract

솔리디티의 모든 코드는 Contract 안에 속한다. 즉, 모든 프로젝트의 시작점이라 볼 수 있다.

Version Pragma

모든 Solidity 코드는 version pragma로 시작해야한다.
이는 현재 코드가 어떤 Solidity 버전을 이용하는지 선언하는 것으로 새로운 컴파일러가 나와도 기존 코드가 깨지지 않도록 예방하는 역할을 한다.

pragma solidity ^0.4.19;   // version pragma 선언
 
contract ZombieFactory{    // Contract 선언
 
}

상태 변수 & 정수

상태 변수는 컨트랙트 저장소에 영구적으로 저장된다.
즉, 이더리움 블록체인에 기록된다.(데이터베이스를 사용하는 것과 동일)

uint

uint 자료형은 부호 없는 정수로, 값이 음수가 아닌 수를 의미하는 자료형이다.
(uint256의 다른 표현, 더 작은 자료형인 uint8, uint16, uint32 같은 자료형도 존재한다.)
부호 있는 정수를 위한 int 자료형도 존재한다.

pragma solidity ^0.4.19;
 
contract ZombieFactory{
    uint dnaDigits = 16;
}

string

string은 문자열을 나타내는 자료형이다.

string name = 'bh2980';

수학 연산

대부분의 다른 언어의 수학 연산자와 동일하다.(+, -, *, /, %, **)

pragma solidity ^0.4.19;
 
contract ZombieFactory{
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;  // **를 사용한 연산
}

구조체 (struct)

구조체(struct)를 활용해 복잡한 형태의 자료형을 선언할 수 있다.

pragma solidity ^0.4.19;
 
contract ZombieFactory{
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
 
    struct Zombie{  // 구조체 선언
        string name;
        uint dna;
    }
}

배열

정적 배열과 동적 배열

Solidity에는 정적 배열과 동적 배열이 있다.
정적 배열은 길이가 정해진 배열을 의미하고 정해진 길이 이상으로 요소를 추가할 수 없다.
동적 배열을 길이가 정해지지 않아 원소를 계속 추가할 수 있는 배열을 말한다.

uint[2] fixedArray;   // 길이가 2인 정적 배열
uint[] dynamicArray; // 길이를 정의하지 않은 동적 배열

Public 배열

public으로 배열을 선언할 수 있다.
이렇게 선언된 배열은 getter를 제공하고, 다른 컨트랙트들이 이를 읽을 수 있게 된다.
(수정(setter)은 불가, 읽기(getter)만 가능)
공개 데이터를 저장할 때 유용하다.

추후 나오겠지만, 함수도 그렇고 private, public과 같은 접근자 선언을 타입 선언 이후에 한다.

pragma solidity ^0.4.19;
 
contract ZombieFactory{
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
 
    struct Zombie{
        string name;
        uint dna;
    }
 
    Zombie[] public zombies;  // Zombie 타입의 public 동적 배열 선언
}

함수

함수 선언

함수 선언은 아래와 같이 할 수 있다.
함수 인자 명을 _(언더스코어)로 시작해서 전역 변수와 구분하는 것이 관례이다.

function createZombie(string _name, uint _dna){
 
}

Public 함수과 Private 함수

Solidity에서 함수는 기본적으로 Public으로 선언된다.
(즉, 다른 어떤 컨트랙트가 접근해서 함수 실행 가능)
이를 막기 위해 함수를 private을 사용하여 private 함수로 선언할 수 있다.
특이하게 접근제어자를 함수 선언 다음에 적는다.

private 함수명 역시 public과 구분하기 위해 관례상 _를 붙여준다.

//_ 추가 및 private 선언
function _createZombie(string _name, uint _dna) private {
    zombies.push(Zombie(_name, _dna));
}

반환값

반환값을 받기 위해서는 반환값을 선언해주어야하며 이는 함수 선언 뒤에 작성한다.

// returns ()을 통해 반환값 선언
function _generateRandomDna(string _str) private returns (uint){
 
}

함수 제어자

view

함수가 Contract 내 값을 보기만 하고 변경하지는 않을 때는 view를 사용한다.
(Contract 변수를 참조하긴 하나 변경하지 않음.)

pure

함수가 앱의 어떤 데이터도 접근하지 않을 때 pure를 사용한다.
(순수 함수, Contract 내 값(함수 외부 변수)를 첨조하지 않음.)

// 함수 제어자 view 사용
function _generateRandomDna(string _str) private view returns (uint){
 
}

자료형 변환

function _generateRandomDna(string _str) private view returns (uint) {
    uint rand = uint(keccak(_str));  // uint 형으로의 형 변환
    return rand % dnaModulus;
}

이벤트

이벤트 등록과 발행

이벤트는 내가 정의한 컨트랙트가 블록체인 상에서
앱의 사용자 단에 무언가 애션이 발생했을 때, 의사사통하는 방법이다.
컨트랙트는 특정 이벤트가 일어나는지 듣고 있다가, 해당 이벤트가 발생 시 행동을 취한다.

pragma solidity ^0.4.19;
 
contract ZombieFactory {
    event NewZombie(uint zombieId, string name, uint dna);  // 이벤트 등록
 
    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
 
    struct Zombie {
        string name;
        uint dna;
    }
 
    Zombie[] public zombies;
 
    function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        NewZombie(id, _name, _dna);  // 이벤트 발행
    }
 
    function _generateRandomDna(string _str) private view returns (uint) {
        uint rand = uint(keccak256(_str));
        return rand % dnaModulus;
    }
 
    function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }
 
}
 

예를 들어 위 코드에서는 NewZombie라는 이벤트를 등록하고,
_createZombie 함수에서 이벤트를 발행하는 것을 볼 수 있다.

이벤트 구독

만약 사용자 단의 어플리케이션이 JS로 개발되었다면
아래 코드를 통해 NewZombie 이벤트를 구독할 수 있다.

// JavaScript
MyContract.NewZombie(function (error, result) {
  //callbak function
});