본문 바로가기

Language/Solidity

solidity 기본 문법 2. return, view, pure, Keccak256, event with 크립토좀비

챕터 1-10. 함수 더 알아보기


반환값 ( return )

함수에서 어떤 값을 반환 받으려면 다음과 같이 선언
ex)

string greeting = "What's up dog";

function sayHello() public returns (string) {
  return greeting;
}


함수 선언은 반환값 종류를 포함 ( 이 경우에는 string )

 

함수 제어자



: 어떤 값을 변경하거나 무언가를 쓰지 않을때

view 함수로 선언

이는 해당 함수가 데이터를 보기만 하고 변경하지 않는다는 뜻

위의 예시에서 사용한 함수도 상태를 변화시키지 않으므로, view 함수로 선언해준다

ex)

function sayHello() public view returns (string) {

}



pure 함수

함수가 앱에서 어떤 데이터도 접근하지 않는 것을 의미

ex)

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



앱에서 읽는 것도 하지 않고, 다만 반환값이 함수에 전달된 인자값에 따라서 달라지면 pure 함수로 선언



챕터 1-11. Keccak256


** 우리가 함수의 반환값이 랜덤인 uint가 되기를 원하면, 어떻게 하면 될까?? **

이더리움은 SHA3의 한 버전인 keccak256를 내장 해시 함수로 가진다

해시 함수는 기본적으로 입력 스트링을 랜덤 256비트 16진수로 매핑

스트링에 약간의 변화라도 있으면 해시 값은 크게 달라짐

해시 함수는 이더리움에서 여러 용도로 활용되지만,

여기서는 의사 난수 발생기(pseudo-random number generator)로 이용

** 블록체인에서 안전한 유사 난수 발생기는 매우 어려운 문제 **



유사난수

: 난수를 흉내내기 위해 알고리즘으로 생성되는 값

ex)

//6e91ec6b618bb462a4a6ee5aa2cb0e9cf30f7a052bb467b0ba58b8748c00d2e5
keccak256("aaaab");

//b1f078126895a1424524de5321b339ab00408010b7cf0e6ed451514981e58aa9
keccak256("aaaac");



실습 시작

pragma solidity ^0.4.19;

contract ZombieFactory {

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

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

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

    function _generateRandomDna(string _str) private view returns (uint) {

         // 여기서 시작
//  _str을 이용한 keccak256 해시값을 받아서 의사 난수 16진수를 생성
         uint rand = uint(keccak256(_str));

//우리는 좀비의 DNA가 16자리 숫자이기만을 원하므로
//코드의 두번째 줄에서는 위의 결과 값을 모듈로(%) dnaModulus로 연산한 값을 반환해야 한다
return rand % dnaModulus;
    }

}

 


챕터 1-12. 종합하기


랜덤 좀비 생성기

** 좀비의 이름을 입력값으로 받아 랜덤 DNA를 가진 좀비를 만드는 public 함수를 생성 **

pragma solidity ^0.4.19;

contract ZombieFactory {

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

    struct Zombie {
        string name;
        uint dna;
    }

    Zombie[] public zombies;

    function _createZombie(string _name, uint _dna) private {
        zombies.push(Zombie(_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);
    }

}

 

챕터 1-13. 이벤트 추가하기



이벤트

: 컨트랙트가 블록체인 상의 앱의 사용자 단에서

어떤 액션이 발생했을 때 의사소통하는 방법

컨트랙트는 특정 이벤트가 일어나는지 "귀를 기울이고" 그 이벤트가 발생하면 행동

ex)

// 이벤트를 선언
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;
}

이후, 앱의 사용자 단은 해당 이벤트가 일어나는지 귀기울임
ex)
YourContract.IntegersAdded(function(error, result) {
  // 결과와 관련된 행동을 취한다
})

 


챕터 2-2: 매핑과 주소


** 데이터베이스에 저장된 좀비들에게 주인을 설정하여 게임을 멀티 플레이어 게임만들기 **

mapping은 솔리디티에서 구조화된 데이터를 저장하는 또다른 방법

ex)

// 금융 앱용으로, 유저의 계좌 잔액을 보유하는 uint를 저장
    mapping (address => uint) public accountBalance;

    // 혹은 userID로 유저 이름을 저장/검색하는 데 매핑을 쓸 수도 있다 
    mapping (uint => string) userIdToName;




실습 시작

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;

    // 여기서 매핑 선언

    //좀비 소유자를 추적하는 매핑
    mapping (uint => address) public zombieToOwner;
    mapping (address => uint) ownerZombieCount;


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

}



챕터 2-3 Msg.sender


msg.sender

: 솔리디티에는 모든 함수에서 이용 가능한 특정 전역 변수들이 있다

그 중의 하나가 "현재 함수를 호출한 사람" (혹은 스마트 컨트랙트)의 주소를 가리키는 msg.sender


참고: 솔리디티에서 함수 실행은 항상 외부 호출자가 시작하기 때문에

컨트랙트는 누군가가 컨트랙트의 함수를 호출할 때까지 블록체인 상에서 덩그러니 존재

그러니 항상 호출자인 msg.sender가 있어야 함

msg.sender를 활용하면

이더리움 블록체인의 보안성을 이용할 수 있게 된다

즉, 누군가 다른 사람의 데이터를 변경하려면

해당 이더리움 주소와 관련된 개인키를 훔치는 것 밖에는 다른 방법이 없다



챕터 2-4 require



** 각 플레이어가 이 함수를 한 번만 호출할 수 있도록 만들어보자**

require를 활용하면 특정 조건이 참이 아닐 때 함수가 에러 메시지를 발생하고 실행을 멈추게 된다

ex)

require(ownerZombieCount[msg.sender] == 0);