like 은행 계좌 번호
주소를 좀비에 대한 소유권을 나타내는 ID로 활용하자.
배열, 구조체 말고 구조화된 데이터를 저장하는 방법
KEY-VALUE로, 데이터를 저장하고 검색하는데 이용
mapping (address => uint) ownerZombieCount;
mapping (uint => address) public zombieToOwner;
솔리디티에는 모든 함수에서 이용 가능한 특정 전역 변수가 존재
현재 함수를 호출한 사람(스마트 컨트랙트를 호출하던가)의 주소가 msg.sender
솔리디티에서 함수 실행은 무조건 외부 호출자가 시작하기에, 무조건 있음
이더리움 보안성을 이용할 수 있다.
function _createZombie(string _name, uint _dna) private {
uint id = zombies.push(Zombie(_name, _dna)) - 1;
// 여기서 시작
zombieToOwner[id] = msg.sender;
ownerZombieCount[msg.sender]++;
// 요 사이가 답
NewZombie(id, _name, _dna);
}
require를 활용하면 특정 조건이 참이 아닐 때 함수가 에러 메시지를 발생하고 실행을 멈춘다.
Q. 좀비 무한 생성을 막아라, 계정당 딱 1개만 가능
function createRandomZombie(string _name) public {
// 요렇게 세서 파악 가능
require(ownerZombieCount[msg.sender] == 0);
uint randDna = _generateRandomDna(_name);
_createZombie(_name, randDna);
}
긴 코드를 잘 정리해서 관리하게 하는 기능이 상속이지
contract Doge {
function catchphrase() public returns (string) {
return "So Wow CryptoDoge";
}
}
contract BabyDoge is Doge {
function anotherCatchphrase() public returns (string) {
return "Such Moon BabyDoge";
}
}
BabyDoge 컨트랙트는 catchphrase(), anotherCatchphrase() 둘 다 접근 가능
contract ZombieFeeding is ZombieFactory {
}
파일을 나누어 관리하고, import로 불러오면 좋다.
파일만 import하면, 그 안의 컨트랙트, 함수는 그냥 쓰면 된데이
변수를 저장하는 공간이 2개여
storage는 블록체인 상에 영구적으로 저장 (하드)
memory는 임시저장, 컨트랙트 함수 외부 호출이 일어나는 사이 지워짐 (램)
대부분 솔리디티가 알아서 해줌. 함수 외부면 storage, 함수 내부 선언 변수는 memory로 해줌
그런데, 함수 내의 구조체와 배열 처리 시 써줘야 돼
function feedAndMultiply (uint _zombieId, uint _targetDna) public {
require(msg.sender == zombieToOwner[id]);
Zombie storage myZombie = zombies[_zombieId];
}
새로운 좀비의 DNA = (좀비 + 생명체) / 2
인자로 받은 _targetDna를 16자리 이하로 만들고
좀비에서 DNA를 받아서 평균을 내서 새로운 dna를 만들고
좀비 생성 함수를 실행시키자 (이름, dna)
function feedAndMultiply(uint _zombieId, uint _targetDna) public {
require(msg.sender == zombieToOwner[_zombieId]);
Zombie storage myZombie = zombies[_zombieId];
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
_createZombie("NoName", newDna);
}
internal : 상속 컨트랙트에서도 접근 가능 (private은 안됨)
external : 컨트랙트 밖에서만 호출 가능 / 안에서 안돼
좀비의 먹이는 '크립토키티'!
즉 크립토키티의 스마트 컨트랙트에서 DNA를 읽어와야겠지
블록체인에 있는 남의 컨트랙트와 우리 컨트랙트가 상호작용하려면 인터페이스를 정의해야!!!
인터페이스는 컨트랙트 뼈대의 역할, 함수 몸체 정의 x
contract NumberInterface {
function getNum(address _myAddress) public view returns (uint);
}
이렇게 해놓으면 다른 컨트랙트에 대한 정보를 알게 되겠지
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
);
}
반환값 타입만 아니라 변수들도 받아오는구나!
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
// `ckAddress`를 이용하여 여기에 kittyContract를 초기화한다
KittyInterface kittyContract = KittyInterface(ckAddress)
다수의 반환값을 갖는 함수 처리
function multipleReturns() internal returns(uint a, uint b, uint c) {
return (1, 2, 3);
}
function processMultipleReturns() external {
uint a;
uint b;
uint c;
// 다음과 같이 다수 값을 할당한다:
(a, b, c) = multipleReturns();
}
// 혹은 단 하나의 값에만 관심이 있을 경우:
function getLastReturnValue() external {
uint c;
// 다른 필드는 빈칸으로 놓기만 하면 된다:
(,,c) = multipleReturns();
}
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
KittyInterface kittyContract = KittyInterface(ckAddress);
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna);
고양이 좀비는 독특한 외모를 가지게 해보자
DNA 16자리 중 12자리만 사용하니, 고양이 좀비는 마지막 2자리를 99로 설정하자
dna = dna - dna % 100 + 99;
//이렇게 하면 십의자리까지 날라가고 99가 들어간다
//수학 섹시하네
// 여기에 있는 함수 정의를 변경:
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
require(msg.sender == zombieToOwner[_zombieId]);
Zombie storage myZombie = zombies[_zombieId];
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
// 여기에 if 문 추가
if(keccak256(_species) == keccak256("kitty") {
newDna = newDna - newDna % 100 + 99;
})
_createZombie("NoName", newDna);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
// 여기에 있는 함수 호출을 변경:
feedAndMultiply(_zombieId, kittyDna, "kitty");
}
var abi = /* abi generated by the compiler */
var ZombieFeedingContract = web3.eth.contract(abi)
var contractAddress = /* our contract address on Ethereum after deploying */
var ZombieFeeding = ZombieFeedingContract.at(contractAddress)
// 우리 좀비의 ID와 타겟 고양이 ID를 가지고 있다고 가정하면
let zombieId = 1;
let kittyId = 1;
// 크립토키티의 이미지를 얻기 위해 웹 API에 쿼리를 할 필요가 있다.
// 이 정보는 블록체인이 아닌 크립토키티 웹 서버에 저장되어 있다.
// 모든 것이 블록체인에 저장되어 있으면 서버가 다운되거나 크립토키티 API가 바뀌는 것이나
// 크립토키티 회사가 크립토좀비를 싫어해서 고양이 이미지를 로딩하는 걸 막는 등을 걱정할 필요가 없다 ;)
let apiUrl = "https://api.cryptokitties.co/kitties/" + kittyId
$.get(apiUrl, function(data) {
let imgUrl = data.image_url
// 이미지를 제시하기 위해 무언가를 한다
})
// 유저가 고양이를 클릭할 때:
$(".kittyImage").click(function(e) {
// 우리 컨트랙트의 `feedOnKitty` 메소드를 호출한다
ZombieFeeding.feedOnKitty(zombieId, kittyId)
})
// 우리의 컨트랙트에서 발생 가능한 NewZombie 이벤트에 귀를 기울여서 이벤트 발생 시 이벤트를 제시할 수 있도록 한다:
ZombieFactory.NewZombie(function(error, result) {
if (error) return
// 이 함수는 레슨 1에서와 같이 좀비를 제시한다:
generateZombie(result.zombieId, result.name, result.dna)
})
pragma solidity ^0.4.19;
import "./zombiefactory.sol";
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 {
address ckAddress = 0x06012c8cf97BEaD5deAe237070F9587f8E7A266d;
KittyInterface kittyContract = KittyInterface(ckAddress);
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) public {
require(msg.sender == zombieToOwner[_zombieId]);
Zombie storage myZombie = zombies[_zombieId];
_targetDna = _targetDna % dnaModulus;
uint newDna = (myZombie.dna + _targetDna) / 2;
if(keccak256(_species) == keccak256("kitty") {
newDna = newDna - newDna % 100 + 99;
})
_createZombie("NoName", newDna);
}
function feedOnKitty(uint _zombieId, uint _kittyId) public {
uint kittyDna;
(,,,,,,,,,kittyDna) = kittyContract.getKitty(_kittyId);
feedAndMultiply(_zombieId, kittyDna, "kitty");
}
}
import , interface 사용법, 수학 로직 사용법을 배웠다.
백지주고 하라 그러면 절대 못할 거 같다. 쉽지 않다.
포스팅하는데 ㅈㄴ 오래걸린다. 최소 2시간이다. 갈수록 더 어려워질텐데 하 ㅋㅋ