촉촉한초코칩

[Crypto Zombies] Beginner 본문

Study/PBL

[Crypto Zombies] Beginner

햄친구베이컨 2024. 4. 1. 10:54
Ch1

 

좀비 공장 만들기

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

 

좀비 DNA

  • 16자리 정수 형태 
  • 각 숫자는 좀비가 가진 개별 특성과 매핑된다.
    ex) 처음 2자리 : 좀비 머리 타입, 다음 2자리 : 좀비 눈 모양 
더보기

ex) 8356281040284737

첫 2자리 숫자 : 83 > 머리 타입으로 매핑

* 튜토리얼에는 좀비의 머리 타입이 7개만 존재함 

83 % 7 + 1 = 7 > 이 DNA를 가진 좀비는 7번째 좀비 머리 타입을 갖게 됨 

 

Ch2 컨트랙트

 

* 솔리디티 코드는 컨트랙트 안에 싸여 있다.

* 솔리디티 코드는 version pragma로 시작한다. 

 

컨트랙트

  • 이더리움 애플리케이션의 기본적인 구성요소
  • 모든 변수와 함수는 어느 한 컨트랙트에 속한다. 
contract HelloWorld {

}

 

Version Pragma

  • 해당 코드가 이용해야 하는 솔리디티 버전을 선언하여 이후 새로운 컴파일러 버전이 나와도 기존 코드가 깨지지 않도록 한다. 
pragma solidity ^0.4.19;

contract HelloWorld { 

}

 

실습) ZombieFactory라는 기본 컨트랙트 생성하기

pragma solidity ^0.4.19;

contract ZombieFactory {

}

 

Ch3 상태변수 & 정수 

 

상태변수

  • 컨트랙트 저장소(이더리움 블록체인)에 영구적으로 저장된다.
contract Example {
   //myUnsignedInteger라는 uint를 생성하여 100이라는 값을 배정한다. 
   uint myUnsignedInteger = 100;
}

 

정수

  • 부호 없는 정수 : uint 자료형
  • 부호 있는 정수 : int 자료형 

* 솔리디티에서 uint는 실제로 uint256 (256비트 부호 없는 정수)이다. 

* uint256은 uint8, uint16, uint32와 같이 더 적은 비트로 선언 가능하다. 

 

실습) 좀비 DNA는 16자리 숫자로 결정되므로 dnaDigits라는 uint를 선언하여 16이라는 값을 배정한다. 

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;

}

 

Ch4 수학 연산 

 

수학 연산

  • 덧셈, 뺼셈, 곱셈, 나눗셈, 모듈로(나머지) 
  • 지수연산 : ** 

 

실습) DNA 16자리 숫자가 되도록 하기 위해 또다른 uint형 변수를 생성하고 10^16 값을 배정한다. 
이후 모듈로 연산자 %와 함께 이용하여 16자리보다 큰 수를 16자리 숫자로 줄일 수 있다. 

pragma solidity ^0.4.19;

contract ZombieFactory {

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

}

 

Ch5. 구조체

 

* String : 임의의 길이를 가진 UTF-8 데이터를 위해 사용한다. 

 

예시

struct Person {
   uint age;
   string name;
}

 

실습) 좀비를 생성을 위해 다양한 특성을 가진 구조체를 생성한다. 
a. Zombie라는 struct를 생성한다. 
b. Zombie 구조체에는 name(string형)과 dna(uint형) 2가지 특성을 가진다.

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
    
    struct Zombie {
       string name;
       uint dna;
    }

}

 

Ch6. 배열 

 

배열 

  • 종류 : 정적 / 동적
  • 상태변수 > 블록체인에 영구적으로 저장 
    구조체의 동적 배열 생성 > 컨트랙트에 구조화된 데이터 저장하는 데 유용 영구적 저장??인건가? 

public 배열 

  • 솔리디티는 public 배열을 위해 getter 메소드를 자동으로 생성한다. 
  • public으로 생성하면 다른 컨트랙트들이 배열을 읽을 수 있다. (쓰기는 불가능)
  • 컨트랙트에 공개 데이터를 저장할 때 유용하다. 
//정적 배열 
uint[2] fixedArray;
string[5] stringArray;

//동적 배열 > 크키 변경 가능 
uint[] dynamicArray;

//구조체 배열 생성 가능
//동적 배열 > 원소 계속 추가 가능 
Person[] people;

//public 배열 
Person[] public people;

 

실습) Zombie 구조체의 public 배열을 생성하고 이름을 zombies로 한다.

pragma solidity ^0.4.19;

contract ZombieFactory {

    uint dnaDigits = 16;
    uint dnaModulus = 10 ** dnaDigits;
    
    struct Zombie {
       string name;
       uint dna;
    }
    
    Zombie[] public zombies;

}

 

Ch7. 함수 선언 

 

함수 선언 형식 

  • 함수 인자명은 _로 시작하여 전역 변수와 구별한다. 
function 함수명 (데이터타입 _변수명, uint _amout) {

}

 

함수 호출 

함수병("",100);

 

실습) 좀비를 생성할 함수를 만든다.
함수명 : createZombie, 2개의 인자를 전달받는다. (string형의 _name, uint형의 _dna)

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

}

 

Ch8. 구조체와 배열 활용하기

 

새로운 구조체 생성하기 (이전에 만든 구조체 Person과 배열 people 사용)

//새로운 Person을 생성하여 people 배열에 추가한다. 
Person satoshi = Person(172, "Satoshi");

//배열에 추가한다.
people.push(satoshi);

//한줄로 만들기
people.push(Person(16, "Vitalik"));

 

배열 추가 : array.push()

  • 배열 끝에 추가하여 원소가 순서를 유지하도록 한다.

 

실습) creatZombie 함수에 새로운 Zombie를 생성하여 zombies 배열에 추가한다.
새로운 좀비를 위한 name과 dna는 createZombie 함수의 인자값이다. 

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) { 
       zombies.push(Zombie(_name, _dna));
    }

}

 

Ch9. Private / Public 함수 

 

* 함수는 기본적으로 public으로 생성된다.

 

private 함수 생성하는 방법 : 함수인자명과 동일하기 _로 시작한다. 

uint[] numbers;

//private는 컨트랙트 내의 다른 함수들만이 이 함수를 호출하여
//numbers 배열로 무언가를 추가할 수 있다는 것을 의미한다. 
function _addToArray(uint _number) private {
   numbers.push(_number);
}

 

실습) createZombie를 private으로 변경한다. 

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

}

 

Ch10. 함수 더 알아보기 (반환값, 제어자)

 

* 솔리디티에서 함수 선언은 반환값 종류를 포함한다. 

 

함수 반환값 

string greeting = "What's up dog";

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

 

함수 제어자 

  • 함수 sayHello()의 경우, 솔리디티 내에서 상태를 변화(값 변경, 무언가 쓰지 않음)시키지 않는다.
  • 이 경우 함수를 view 함수로 선언 > 함수가 데이터를 읽기만 하고 변경하지 않음
function sayHello() public view returns (string) { 

}

 

* pure 함수 : 함수가 앱에서 어떤 데이터도 접근하지 않는 것을 의미한다. 

//어떤 값도 읽지 않음
function _multiply(uint a, uint b) private pure returns (uint) {
  return a * b;
}

 

실습) 스트링으로부터 랜덤 DNA를 생성할 함수 생성하기
a. _generateRandomDNA라는 private 함수를 생성한다. string형의 _str을 인자로 전달받고 uint을 반환한다.
b. 컨트랙트 변수를 보지만 변경하지는 않으므로 view로 선언한다.

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

}

 

Ch11. Keccak256, 형 변환 

 

_generateRandomDna 함수의 반환값이 (반)랜덤인 uint가 되도록 수정한다. 

* 이더리움은 SHA3의 한 버전인 Keccack256을 내장 해시 함수로 가지고 있다. 

* 해시 함수는 기본적으로 입력스트링을 랜덤 256비트 16진수로 매핑한다. 
(스트링 값 수정되면 해시값도 달라짐)

* 해시 함수는 이더리움에서 여러 용도로 활용되며, 이 문제에서는 의사난수 발생기(pseudo-random number generator)로 이용한다. 

더보기

예시)

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

 

형 변환 

//a * b가 uint8이 아닌 uint를 반환하기 때문에 에러 메시지가 난다.
uint8 a = 5;
uint b = 6;
uint8 c = a * b;
//b를 uint8으로 형 변환한다. 
uint8 c = a * uint8(b);

 

실습) _generatorRandomDna 함수 수정
a. _str을 이용한 keccak256 해시값을 받아서 의사난수 16진수를 생성하고 이를 uint형으로 변환한다. 변환한 값은 uint형의 rand 결과값에 저장한다.
b. 좀비의 DNA가 16자리 숫자이기를 원하므로 위의 결과 값을 모듈로(%) dnaModulus로 연산한 값을 반환한다. 

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

}

 

Ch12. 종합하기 

 

실습) 좀비 이름을 입력받아 랜덤 DNA를 가진 좀비를 생성하는 public 함수 생성
a. createRandomZombie라는 public 함수 생성한다. 함수는 string형의 _name을 인자로 전달받는다. 
b. _name을 전달받은 _generateRandomDna 함수를 호출하고, 이 함수의 반환값을 uint형의 randDna에 저장한다.
c. _createZombie 함수를 호출하고이 함수에 _name과 randDna를 전달한다. 

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

}

 

Ch13. 이벤트 

 

이벤트 

  • 컨트랙트가 블록체인 상에서 앱의 사용자 단에서 액션이 발생했을 때 의사소통하는 방법이다.
  • 컨트랙트는 특정 이벤트가 발생하면 행동을 취해야 한다. > 앱의 사용자 단에서 자바스크립트로 구현 
//이벤트 생성
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;
}

//자바스크립트로 결과에 대한 행동 구현
YourContract.IntegersAdded(function(error, result) {

})

 

실습) 좀비가 생성될 때마다 앱의 사용자 단에서 이에 대해 알고, 이를 표시하는 이벤트를 생성한다. 
a. NewZombie라는 event 생성 
ZombieId(uint형), name(string형), dna(uint형)을 인자로 받는다.
b. _createZombie 함수를 변경하여 새로운 좀비가 zombies 배열에 추가된 후에 NewZombie 이벤트를 실행하도록 한다.
c. 이벤트를 위해 좀비의 id가 필요하다. 
array.push()는 배열의 새로운 길이를 uint형으로 반환한다. 
배열 첫 원소의 인덱스는 0이므로 array.push() - 1은 막 추가된 좀비의 인덱스가 된다.
zombies.push() - 1 의 결과값을 uint형인 id로 저장하고 결과값을 NewZombie 이벤트에 활용한다. 

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

}

 

Ch14. Web3.js

 

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

이더리움은 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
}

자바스크립트 코드가 zombieDetails에서 생성된 값을 받아 웹 브라우저 기반 자바스크립트와 같은 기능(실습에서는 Vue.js 사용)을 활용하여 이미지를 변경하고 CSS 필터를 적용한다. 

 

실습) 이름을 입력하고 어떤 종류의 좀비가 나오는지 확인한다. 

 

Ch15. 

 

https://share.cryptozombies.io/ko/lesson/1/share/%ED%97%AC%EB%A1%9C?id=Y3p8NjE0NjAy

'Study > PBL' 카테고리의 다른 글

Machine Learning 3  (0) 2024.05.28
Machine Learning 2  (0) 2024.05.27
Machine Learning 1 (~학습 및 테스트 세트)  (0) 2024.05.21
MFCC, STFT  (0) 2024.05.20
Tensorflow 강의 정리  (0) 2024.05.15