crypto zombie 크립토 좀비 게임(?)으로 이더리움의 대표 언어 solidity 배우기 lesson2
lesson1 보다 더 어렵고 시간도 꽤 걸렸다. 그리고 다 통과를 했어도 lesson1보다 이해가 완전히 되지는 않았다.
다시 재도전해보면서 최종 코드 해석해보자 아좌아좌
이번 레슨에서는 기존 좀비의 DNA와 먹이의 DNA를 합쳐 새로운 좀비 DNA를 만들어 낸다.
새로운 개념인 mapping 과 address라는 새로운 자료형을 배웠다.
Key Points
1) address
* address는 은행 계좌와 같은 이더리움의 계정 주소를 가리키는 고유 식별자이다.
ex) address 형식
0x0cE446255506E92DF41614C46F1d6df9Cc969183
쉽게 말하면 이더리움 지갑 주소이다. 실제로 위의 계좌에 이더리움을 이체 시킬 수 있다 !
2) mapping
* mapping 은 솔리디티에서 구조화 된 데이터를 (key: value) 형식으로 저장하는 방법이다.
mapping (address => unit) public accountBalance;
key - address형식 : value - unit 형식
JavaScript의 객체 { key: value } 와 비슷한듯 하다!
3) msg.sender
* msg.sender = 솔리디티 모든 함수에서 이용 가능한 특정 전역 변수 중 하나. 현재 함수를 호출한 사람 (혹은 스마트 컨트랙트) 의 주소를 가리킨다. msg.sender를 활용하면 이더리움 블록체인의 보안성을 이용할 수 있다.
4) require
* require 는 JavaScript의 if 문과 비슷하다.
솔리디티 언어의 if문은 자바스크립트와 동일하게 사용된다.
5) storage vs memory
* storage : 블록체인 상 영구적으로 저장되는 변수 (솔리디티 변수 선언 시 기초값)
ex) 컴퓨터의 하드 디스크
* memory : 임시적으로 저장되는 변수 - 컨트랙트 함수에 대한 외부 호출들이 일어나는 사이에 지워진다.
ex) 컴퓨터의 RAM
=> 솔리디티는 자동으로 디폴트 값 storage를 적용시키지만 개발자가 직접 위의 storage, memory를 적어줘야하는 때가 있다. => ** 함수 내 구조체와 배열을 처리할 때 **
ex) 출처 : https://cryptozombies.io/ko/lesson/2/chapter/7
contract SandwichFactory {
struct Sandwich {
string name;
string status;
}
Sandwich[] sandwiches;
function eatSandwich(uint _index) public {
// Sandwich mySandwich = sandwiches[_index];
// ^ 꽤 간단해 보이나, 솔리디티는 여기서
// `storage`나 `memory`를 명시적으로 선언해야 한다는 경고 메시지를 발생한다.
// 그러므로 `storage` 키워드를 활용하여 다음과 같이 선언해야 한다:
Sandwich storage mySandwich = sandwiches[_index];
// ...이 경우, `mySandwich`는 저장된 `sandwiches[_index]`를 가리키는 포인터이다.
// 그리고
mySandwich.status = "Eaten!";
// ...이 코드는 블록체인 상에서 `sandwiches[_index]`을 영구적으로 변경한다.
// 단순히 복사를 하고자 한다면 `memory`를 이용하면 된다:
Sandwich memory anotherSandwich = sandwiches[_index + 1];
// ...이 경우, `anotherSandwich`는 단순히 메모리에 데이터를 복사하는 것이 된다.
// 그리고
anotherSandwich.status = "Eaten!";
// ...이 코드는 임시 변수인 `anotherSandwich`를 변경하는 것으로
// `sandwiches[_index + 1]`에는 아무런 영향을 끼치지 않는다. 그러나 다음과 같이 코드를 작성할 수 있다:
sandwiches[_index + 1] = anotherSandwich;
// ...이는 임시 변경한 내용을 블록체인 저장소에 저장하고자 하는 경우이다.
}
}
6) Internal vs External
* Internal 함수 : private과 동일하지만 다른 점은 정의된 컨트랙트를 상속하는 컨트랙트 안에서 접근이 가능하다.
* External 함수 : public과 동일하지만 다른 점은 컨트랙트 바깥에서만 호출될 수 있고 컨트랙트 안에서 다른 함수에 의해 호출될 수 없다.
=> 지금까지 배운 함수의 "함수 접근 제어자" 로는 private, public, internal, external 이 있다.
lesson2를 마무리하고 나온 최종 solidity 코드는 아래와 같다.
파일은 두 개로 나눠진다.
zombiefactory.sol
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;
// key - uint : value - address인 mapping 형식의 zombieToOwner 선언
mapping (uint => address) public zombieToOwner;
// key - address : value - uint인 mapping 형식의 ownerZombieCount 선언
mapping (address => uint) ownerZombieCount;
// * _createZombie 함수가 lesson2에서 private -> interal로 접근 제어자가 변경되었다.
// private처럼 비공개이지만 상속 컨트랙트에서는 해당 함수를 사용할 수 있다.
function _createZombie(string _name, uint _dna) internal {
uint id = zombies.push(Zombie(_name, _dna)) - 1;
// zombieToOwner mapping에 key - id : value - msg.sender(주소) 담기
zombieToOwner[id] = msg.sender;
// 해당 key(주소)의 value 값 1씩 증가시키기
ownerZombieCount[msg.sender]++;
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 {
// zombie가 생성될때마다 함수 호출한 사람의 (msg.sender) 주소에 매핑된 nint 값이 ++ 가 되는
// 점을 이용하여 무한 반복을 예방할 수 있다.
// ownerZombieCount[msg.sender]가 0 일경우 == 좀비 생성이 처음인 경우에만 아래 명령어들이 실행된다.
require(ownerZombieCount[msg.sender] == 0);
uint randDna = _generateRandomDna(_name);
randDna = randDna - randDna % 100;
_createZombie(_name, randDna);
}
}
zombiefeeding.sol
√pragma solidity ^0.4.19;
import "./zombiefactory.sol"; // 같은 위치에 있는 zombiefactory.sol 파일을 불러온다.
// 외부 컨트랙트에 있는 함수를 가져올 때 아래처럼 인터페이스를 선언한다.
// 인터페이스 선언은 컨트랙트처럼 contract ~ 으로 시작하고 안의 함수는 (); 까지 끝낸다.
contract KittyInterface {
function getKitty(uint256 _id) external view returns (
bool isGestating,
bool isReady,
uint256 cooldownIndex,
uint256 nextActionAt,
uint256 siringWithId,
uint256 birthTime,
uint256 matronId,
uint256 sireId,
uint256 generation,
uint256 genes
);
}
contract ZombieFeeding is ZombieFactory { // ZombieFeeding은 ZombieFactory 를 상속 받았다.
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
// 위에서 만든 인터페이스 KittyInterface형인 kittyContract라는 변수를 선언한다.
// 안에는 ckAddress인자값으로 넣은 외부 인터페이스가 된다.
// -> 이제 kittyContract.getKitty() 이렇게 해당 인터페이스 안의 함수를 쓸 수 있다.
KittyInterface kittyContract = KittyInterface(ckAddress);
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
// msg.sender가 좀비 주인과 동일하도록 require(if)를 추가한다.
require(msg.sender == zombieToOwner[_zombieId]);
// Zombie형 myZombie명의 변수를 storage로 선언하고 zombies 배열의 [_zombieId]번째의 값을 부여한다.
Zombie storage myZombie = zombies[_zombieId];
// _targetDna를 16자리수로 맞추기
_targetDna = _targetDna % dnaModulus;
// 새로운 newDna를 myZombie dna와 target(먹이)dna 값을 합한 평균으로 한다.(임의대로! 나중에 복잡하게 바꿀 수 있음)
uint newDna = (myZombie.dna + _targetDna) / 2;
// 만약 해당 함수 인자값의 3번째 _species가 "kitty"와 동일하다면 newDna의 끝 2자리를 99로 맞춰준다.
if (keccak256(_species) == keccak256("kitty")) {
newDna = newDna - newDna % 100 + 99; // 100으로 나눈 나머지로 newDna를 빼면 ~2341100이 된다. 여기에 99를 더하기
}
// 좀비를 create하는 함수를 불러 인자값을 넣어준다. 이름은 일단은 없으니 "NoName"으로 한다.
_createZombie("NoName", newDna);
}
// 위에서 가져온 kitty 인터페이스
function feedOnKitty(uint _zombieId, uint _kittyId) public {
// kittyDna 빈 변수 선언
uint kittyDna;
// kittyContract 안의 getKitty 함수를 불러와 인자값으로 _kittyId를 넣는다.
// return되는 10가지 중 genes는 10 번째 자리에 있다. 10번째에 kittyDna 변수를 놓고 값을 담는다.
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna, "kitty");
}
}
레벨 2를 하고 나서 솔리디티 언어의 느낌 (?) 문법은 이해가 조금 되었다. 블록체인 책을 이번에 e book으로 무료 다운해서 읽기 시작했는데 더 공부하다보면 전반적인 이해도가 높아질 것 같다!
e-book 어플 (pc, mobile) - RIDI 리디북스 / 알라딘 e-book
읽기 시작한 책 : 코어 이더리움 프로그래밍 (저자 : 박재현, 오재훈, 박혜영)
책을 다 읽게되면 책 후기도 써보면 좋을 것 같다.
'Block Chain' 카테고리의 다른 글
[Klaytn] 클레이튼이란? 안전한가? 클레이 코인 시세 (0) | 2022.02.24 |
---|---|
[solidity Ganache-cli web3 solc] smart Contract 만들어 배포하기 (0) | 2022.02.21 |
[SPDX란?] Warning: SPDX license identifier not provided in source file (0) | 2022.02.21 |
블록체인 공부 시작 방법 / 크립토 좀비 / Crypto Zombie / 이더리움 solidity Lesson 1 해석 (0) | 2022.02.10 |
[블록체인] 머클 트리란? (Merkle Trees) (0) | 2021.09.01 |
댓글