CZ 001 - Contract, 자료형, 구조체, 함수, 이벤트
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
});