#1 블록체인 개발자 되기: 크립토 좀비 cryptozombies lesson1 chapter1~15

in blockchain •  4 years ago 

크립토 좀비 링크

여기 를 누르면 이동합니다.

크립토좀비는 이더리움에서 만든 솔리디티(solidity) 언어의 기본 문법에 익숙해지고, 블록체인의 원리를 이해하는 데 목표로 한다.

게시글 목적

solidity 언어를 정리하며 복습할 때 참고하기 위해 정리를 하게 되었습니다.

챕터2:

  • 개념1: 컨트랙트(contract)

"컨트랙트는 이더리움 애플리케이션의 기본적인 구성 요소로, 모든 변수와 함수는 어느 한 컨트랙트에 속하게 마련이다. -크립토좀비-"

이걸 보고 들었던 생각은 자바의 class 개념이구나 싶었다.

  • 개념2: Version Pragma
progma solidity ^0.4.19;

contract HelloWorld {
} 

'progma solidity ^버전; ' 다음과 같이 적어 이후에 새로운 컴파일러 버전이 나와도 기존 코드가 깨지지 않도록 예방할 수 있다.

챕터 3: 상태 변수 & 정수 // + 자료형

java에 int, char, string ... 다양하게 많던 변수타입들. 솔리디티는 상당히 낯선 문법을 쓰고 있었다.

  • 부호 없는 정수: uint

uint 자료형은 부호 없는 정수로, 값이 음수가 아니어야 한다. 부호 있는 정수를 위한 int자료형도 있다. uint에는 uint8, uint16, uint32 다음과 같이 비트를 뒤에 붙여서 표현하기도 한다. 뒤에 아무것도 없다면 256비트이다.

자잘한 비트들은 특수한 경우가 아니라면 일반적으로 256비트를 사용한다.

이 외의 자료형으로는 string(문자형)이 있다.

챕터 4: 수학 연산

  • 덧셈: x + y
  • 뺄셈: x - y,
  • 곱셈: x * y
  • 나눗셈: x / y
  • 모듈로 / 나머지: x % y (이를테면, 13 % 5는 3이다. 왜냐면 13을 5로 나누면 나머지가 3이기 때문이다)
  • 지수연산: x**y -> x^y

챕터 5: 구조체(sturct)

맨 처음에 구조체가 java의 생성자일까 생각했다. 그런데 전혀 다른 개념이었다.
구조체(structure): 타입이 다른 데이터를 하나로 묶는 방법

챕터 6: 배열

어떤 것의 모음집 = 배열
솔리디티에는 정적배열과 동적배열이라는 두 종류의 배열이 있다.
이것은 java에서 배열과 리스트의 차이를 가지고 있다.

  • 정적배열: 길이제한이 있는 고정된 배열 = java 배열
  • 동적배열: 고정된 크기가 없어 계속 커질 수 있다 = java리스트
uint[2] fixedArray; // 2개의 원소를 담을 수 있는 고정 길이의 배열
uint[] dynamicArray; // 고정된 크기가 없으며 계속 크기가 커지는 배열

챕터 7: 함수 선언

function eatHamburger(string _name, uint _amount){
}

자바 스크립트의 function과 비슷하다. 이더리움 솔리디티 언어가 자바스크립트에 영향을 많이 받았다고 하더니 역시..!

함수 인자값에 (_) 언더스코어가 붙은 것을 볼 수 있다. 전역 변수와 구별하도록 돕는 관례이다(의무 아님).

전역 변수는 흔히 광역 변수라고도 한다. contract 전체에서 쓰이는 함수이고 지역 변수라 하면 메소드나 생성자 혹은 if문 등등 괄호 안에서 생성되어 괄호가 끝나면 사라질 변수들을 의미한다.

챕터 8: 구조체와 배열 활용하기

구조체(struct) 안에는 다른 타입들을 넣을 수 있었다.

struct Person {
 uint age;
 string name;
}

Person[] public people;

밑에 동적배열 people이 만들어졌다. 그런데 동적배열 타입이 구조체인 Person인 것을 볼 수 있다. 즉 구조체를 타입으로 가진다는 것이다. 구조체 안에 있는 변수들로만 배열을 채우겠다는 의미로 보았다.

배열에 값을 추가하려면, java에서 list에 넣을 때 push를 쓰듯, 똑같이 push를 쓰면 된다.

Person grace = Person(170, "grace song");
people.push(grace);

//좀 더 간단한 버전
people.push(Person(170, "grace song"));

챕터 9: Private / Public

java에도 private, public, protected, default가 있었죠. solidity에서도 비슷합니다. 솔리디티에서 함수는 기본적으로 public으로 선언 됩니다.

java에서와 마찬가지로 private는 현재 컨트랙트(contract)에서만 사용될 수 있습니다. 컨트랙트의 보안에 신경 써야할 때 private를 쓰면 좋습니다.

함수를 private로 선언하면, 솔리디티 관례에 의해 함수명을 언더바(_)로 시작합니다.

// 기본 public으로 생략됨.
function itsPublic() { 
}
// private 접근제한자로 함수명이 언더바(_)로 시작
function _itsPrivate() private { 
}

챕터 10: 함수 더 알아보기

  • 반환값

함수에서 어떤 값을 반환 받기 위해 사용됨. java에서 반환(return)값이 있으면 메소드 앞에 반환값 타입을 적었고, 반환값이 없을 시 void를 썼다. (get/set 메소드 생각해보자.)

솔리디티에선 접근제한자 뒤에 반환값이 있을 시 returns 와 반환타입을 괄호 안에 넣게 된다. 반환값이 없을 시엔 위 두개를 포함하지 않는다.

string ex = "hi";

function solidityReturnFn() public returns (string) {
return ex;
}
//public 생략 가능, returns (반환타입)

주의할 점으론 자바에선 return이라 쓰는데 솔리디티는 returns로 복수형으로 쓴다!

  • 함수 제어자

위에서 살펴본 함수 solidityReturnFn()는 솔리디티에서 상태를 변화시키는 요소가 없다. 즉, 어떤 값을 변경하거나 무언가를 쓰지 않는다. 데이터 가공 없이 바로 "hi"를 반환한다.

이 경우엔 view 함수로 선언한다. 이는 함수가 데이터를 보기만 하고 변경하지 않는다는 뜻이다.

솔리디티는 pure 함수도 가지고 있는데, 이는 함수가 앱에서 어떤 데이터도 접근하지 않는 것을 의미한다.

function _multiply(uint a, uint b) private pure returns (uint) {
  return a * b;
}

함수 _multiply()는 반환값이 함수에 전달된 인자값에 따라서 달라진다. 따라서 이 경우엔 pure로 선언한다.

참고로 view와 pure를 헷갈려도 괜찮다. 솔리디티 컴파일러는 어떤 제어자를 써야 하는지 경고 메세지로 알려준다.

챕터 11

  • Keccak256과 형 변환

Keccak256는 솔리디티 내장 해시 함수이다. 즉, 솔리디티 자체에서 가지고 있는 함수이다. 별도의 선언 없이 쓸 수 있다. 해시 함수는 기본적으로 입력 스트링을 랜덤 256비트 16진수로 매핑한다. 스트링에 약간의 변화라도 있으면 해시 값은 크게 달라진다.

// 6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");
// b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");

위 함수 결과를 통해 알 수 있듯이 한 글자가 달라졌음에도 불구하고 반환값이 완전히 달라졌다.

  • 형 변환
uint8 a = 5;
uint b = 6;
// a * b가 uint8이 아닌 uint를 반환하기 때문에 에러 메시지가 난다:
uint8 c = a * b; 
// b를 uint8으로 형 변환해서 코드가 제대로 작동하도록 해야 한다:
uint8 c = a * uint8(b);

java에서 long, int, string 등등 타입에 맞추어 강제타입변환을 할 때가 있듯 솔리디티도 같다.

챕터 12: 종합하기 // 생략

챕터 13: 이벤트

Event란 트랜잭션 내에서 호출될 수 있는 일종의 리턴값이 없는 함수이다. 이벤트를 호출하면 그 호출한 기록이 Transaction Receipt 라 불리는 트랜잭션 결과에 저장된다. 일종의 로그(log)다.
출처: 여기

이벤트는 컨트랙트가 블록체인 상에서 앱의 사용자 단에서 무언가 액션이 발생했을 때 의사소통하는 방법이다.
나중에 truffle로 프로젝트를 만들 때 시도해봐야겠다.

// 이벤트를 선언한다
event IntegersAdded(uint x, uint y, uint result);

function add(uint _x, uint _y) public {
  uint result = _x + _y;
  // 이벤트를 실행하여 앱에게 add 함수가 실행되었음을 알린다:
  IntegersAdded(_x, _y, result);
  return result;
}

챕터 14: Web3.js

솔리디티의 컨트랙트와 상호작용하는 사용자 단의 자바스크립트 코드를 작성해야한다.

이더리움은 Web3.js 라고 하는 자바스크립트 라이브러리를 가지고 있다.

샘플코드

// 여기에 우리가 만든 컨트랙트에 접근하는 방법을 제시한다:
var abi = /* abi generated by the compiler */
var ZombieFactoryContract = web3.eth.contract(abi)
var contractAddress = /* our contract address on Ethereum after deploying */
var ZombieFactory = ZombieFactoryContract.at(contractAddress)
// `ZombieFactory`는 우리 컨트랙트의 public 함수와 이벤트에 접근할 수 있다.

// 일종의 이벤트 리스너가 텍스트 입력값을 취한다:
$("#ourButton").click(function(e) {
  var name = $("#nameInput").val()
  // 우리 컨트랙트의 `createRandomZombie`함수를 호출한다:
  ZombieFactory.createRandomZombie(name)
})

// `NewZombie` 이벤트가 발생하면 사용자 인터페이스를 업데이트한다
var event = ZombieFactory.NewZombie(function(error, result) {
  if (error) return
  generateZombie(result.zombieId, result.name, result.dna)
})

// 좀비 DNA 값을 받아서 이미지를 업데이트한다
function generateZombie(id, name, dna) {
  let dnaStr = String(dna)
  // DNA 값이 16자리 수보다 작은 경우 앞 자리를 0으로 채운다
  while (dnaStr.length < 16)
    dnaStr = "0" + dnaStr

  let zombieDetails = {
    // 첫 2자리는 머리의 타입을 결정한다. 머리 타입에는 7가지가 있다. 그래서 모듈로(%) 7 연산을 하여
    // 0에서 6 중 하나의 값을 얻고 여기에 1을 더해서 1에서 7까지의 숫자를 만든다. 
    // 이를 기초로 "head1.png"에서 "head7.png" 중 하나의 이미지를 불러온다:
    headChoice: dnaStr.substring(0, 2) % 7 + 1,
    // 두번째 2자리는 눈 모양을 결정한다. 눈 모양에는 11가지가 있다:
    eyeChoice: dnaStr.substring(2, 4) % 11 + 1,
    // 셔츠 타입에는 6가지가 있다:
    shirtChoice: dnaStr.substring(4, 6) % 6 + 1,
    // 마지막 6자리는 색깔을 결정하며, 360도(degree)까지 지원하는 CSS의 "filter: hue-rotate"를 이용하여 아래와 같이 업데이트된다:
    skinColorChoice: parseInt(dnaStr.substring(6, 8) / 100 * 360),
    eyeColorChoice: parseInt(dnaStr.substring(8, 10) / 100 * 360),
    clothesColorChoice: parseInt(dnaStr.substring(10, 12) / 100 * 360),
    zombieName: name,
    zombieDescription: "A Level 1 CryptoZombie",
  }
  return zombieDetails
}

여기까지가 lesson1 이였다. 자바와 비슷한 부분도 있고, 완전 다르다고 느낀 부분도 있었다. 헷갈리긴 하지만 모든 언어가 그렇듯 익숙하지 않을 뿐 어렵진 않다. 끊임없이 연습하다 보면 익숙해져있을 것이다.

학습하며 중점을 둔 것은, 가볍게 따라하는 연습이지만 그래도 구조를 생각하려 노력했다. 아무래도 이 게시글을 종종 찾아볼 것 같다.

Authors get paid when people like you upvote their post.
If you enjoyed what you read here, create your account today and start earning FREE STEEM!