Making the Zombie Factory

nn·2022년 2월 14일
0

크립토좀비

목록 보기
1/8

크립토좀비는 솔리디티로 수집품 게임을 직접 만들어 스마트 컨트렉트를 작성해 보는 프로그램이다.

개요

크립토좀비는 다음과 같은 좀비 공장을 가진다.

  • 이 공장은 군대 내 모든 좀비의 데이터 베이스를 유지한다.
  • 이 공장은 새로운 좀비를 생성하는 함수를 가진다.
  • 각 좀비는 랜덤하고 독특한 외모를 가진다.

좀비 DNA

좀비의 DNA는 8356281049284737 와 같이 16자리의 정수로 표현되며, 이 숫자는 좀비가 가진 개별 특성과 매핑이 된다.


컨트렉트 생성

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
}

pragma

pragma솔리디티의 버전을 명시한다. 0.4.19 버전을 사용했다.

contract

솔리디티는 컨드렉트 안에 싸여있다. 컨트렉트를 ZombieFactory라는 이름으로 생성했다.
컨트렉트는 자바의 클래스 개념을 떠올리면 된다.

컨트렉트 안에 unit타입의 상태변수를 선언했다.
상태변수는 컨트렉트 저장소에 영구적으로 저장된다.
즉 이더리움 블록체인에 기록이 되는 데이터다.

참고: 솔리디티에서 uint는 실제로 uint256, 즉 256비트 부호 없는 정수의 다른 표현. uint8, uint16, uint32 등과 같이 uint를 더 적은 비트로 선언할 수도 있다. 하지만 앞으로의 레슨에서 다루게 될 특수한 경우가 아니라면 일반적으로 단순히 uint를 사용.

struct (구조체)

복잡한 자료형을 만들기 위해서 구조체를 사용한다.

다음과 같이 좀비의 이름과 dna를 저장하는 구조체를 생성했다.

struct Zombie {
        string name;
        uint dna;
    }

배열

솔리디티는 다음과 같이 고정 길이를 가지는 정적배열과, 크기가 변하는 동적배열을 사용할 수 있다.

string[5] stringArray; // 고정 배열으로 5개의 스트링을 담을 수 있다
uint[] dynamicArray; // 동적 배열은 고정된 크기가 없으며 계속 크기가 커질 수 있다.

Public 배열

배열을 public으로 선언 할 수 있다.
이 배열을 사용하기위해 솔리디티는 자동적으로 getter를 생성한다.

public으로 배열을 생성하면 다른 컨트렉트들이 이 배열을 참조해서 사용할 수 있다.

...
Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }
...    

Zombie 라는 구조체를 선언하고, 이 구조체를 배열로 생성했다.
즉 좀비는 배열안에 여러마리가 들어갈 수 있다.
또한 public 이기 때문에 다른 컨트렉트가 좀비에 접근 할 수 있다.

함수

function 을 사용해 함수를 선언할 수 있다.

보통 함수의 인자에는 _(언더스코프)를 사용해 전역변수와 구분한다.
private 키워드를 사용한 함수에도 _(언더스코프)를 사용한다.

view

값을 변경하지 않고, 조회만 하는 함수에는 view 키워드를 사용한다.

function sayHello() public view returns (string) {}

returns

function sayHello() public view returns (string) {}

또한 함수에서 반환 받으려는 반환 값을 위와 같이 사용한다.
위 함수는 반환값을 string으로 정의했다.

pure

함수가 앱에서 어떤 데이터도 접근하지 않는 경우 사용한다.

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

위 함수는 어떤 것을 읽지도 않고, 다른 데이터에 접근하지도 않는다.
전달 된 인자에 대해서만 수행을 하기 때문에 pure 키워드를 사용한다.

다시 코드로 돌아가보자.

좀비의 이름과, dna를 받아서 좀비를 생성하는createZombie 함수를 선언했다.

function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_name, _dna));
    }

함수는 기본적으로 public을 사용해 다른 컨트렉트와 상호작용을 하지만 때에 따라 공격 취약점이 될 수 있다.
다른 컨트렉트가 좀비를 추가하는 것을 막기위해 private 함수로 선언하였다.


Keccak256

이더리움은 SHA3의 한 버전인 keccak256를 내장 해시 함수로 가지고 있다.
해시함수는 기본적으로 입력 스트링을 랜덤 256비트 16진수로 매핑한다.

//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");

//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");

위 예시를 보면 알 수 있듯이 입력값이 하나만 달라져도 완전히 다른 난수가 반환된다.

function _generateRandomDna(string _str) private view returns (uint) {
         uint rand = uint(keccak256(_str));
         return rand % dnaModulus;
    }

좀비의 dna를 생성하는 함수이다.
좀비의 dna는 keccak256를 사용해 난수 16진수를 생성하고 이를 uint으로 형변환하였다.

dna는 16자리 숫자이므로 % 로 계산해서 반환했다.

위 두 함수를 이용해 좀비를 생성하는 함수를 만들 수 있다.

function createRandomZombie(string _name) public {
        uint randDna = _generateRandomDna(_name);
        _createZombie(_name, randDna);
    }

위 함수는 public으로 생성했다.

name을 인자로 받아 dna를 생성하고 이어서 좀비의 이름과, dna를 인자로 가져가 좀비 배열에 추가한다.


이벤트

이벤트는 컨트랙트가 블록체인 상에서 무언가 액션이 발생했을 때 수행한다.
event NewZombie(uint zombieId, string name, uint dna);
위와 같이 이벤트를 정의한다.

이벤트는 새로운 좀비가 추가되었을 떄 수행되어야하므로 _createZombie 함수에 위치한다.

function _createZombie(string _name, uint _dna) private {
        uint id = zombies.push(Zombie(_name, _dna)) - 1;
        NewZombie(id, _name, _dna);
    }

id는 좀비 배열의 인덱스 숫자를 사용했다.
zombies.push() 는 새로 추가된 배열의 길이를 반환하므로 1을 하나 빼줌으로서 지금 추가하는 좀비의 인덱스를 반환하게 했다.


위 코드의 전체 소스는 다음과 같다.

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);
    }

}

생성된 dna에 따라 좀비의 외관이 변경된다.

profile
내가 될 거라고 했잖아

0개의 댓글

관련 채용 정보