솔리디티는 시간을 다룰 수 있는 단위를 제공한다 🙂
now
변수를 쓰면 현재의 유닉스 타임스탬프(1970년 1월 1일부터 지금가지의 초단위 합) 값을 얻을 수 있다! 신기하네
유닉스 타임은 전통적으로 32비트 숫자로 저장되네. 이는 유닉스 타임스탬프 값이 32비트로 표시가 되지 않을 만큼 커졌을 때 많은 구형 시스템에 문제가 발생할 "Year 2038" 문제를 일으킬 것이네. 그러니 만약 우리 DApp이 지금부터 20년 이상 운영되길 원한다면, 우리는 64비트 숫자를 써야 할 것이네. 하지만 우리 유저들은 그동안 더 많은 가스를 소모해야 하겠지. 설계를 보고 결정을 해야 하네!
또, 유닉스 타임스탬프 값을 직접 사용하기가 쉽지 않아서,
seconds
, minutes
, hours
, days
, weeks
, years
같은 시간 단위도 제공해준다! 우리가 이런 단위를 써주면, 솔리디티에서 유닉스 초단위로 변환을 해준다.
1 minutes == 60
1 hours == 3600
1 days == 86400
참고로 1을 계산할때도 복수형으로 그냥 써줘야한다..😱
우리는 private
또는 internal
함수의 argument로 구조체의 storage 포인터를 전달할 수 있다.
function _doStuff(Zombie storage _zombie) internal {
// _zombie로 할 수 있는 것들을 처리
}
우리가 전에 만들었던 feedAndMultiply
함수를 다시 보자.
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);
}
이 함수의 제어자를 보면 public
으로 선언돼있어서 어느 사용자든 자신이 가진 좀비에게 먹이를 줄 수 있었다.
하지만 이렇게 되면 게임이 아니잖아..! 🥺
이 함수를 어떻게 사용했었는지 다시 생각해보면,
- 좀비가 크립토 키티를 먹는다.
- 크립토 키티의 dna를 가져온다. 👉🏻
feedOnKitty()
- 좀비의 원래 dna와 크립토 키티의 dna가 합쳐져서 새로운 좀비의 dna가 결정된다. 👉🏻
feedAndMultiply()
- 새로 만들어진 dna로 좀비를 생성한다.
그니까 우리는 feedOnKitty()
안에서만 feedAndMultiply()
가 호출될 수 있게 바꿔줘야겠다 ❗ 그러려면 함수의 제어자를 intermal
로 만드는 방법이 있겠다.
이렇게 ~
function feedAndMultiply(uint _zombieId, uint _targetDna, string _species) internal {
...
}
이전 포스트에서 onlyOwner
라는 간단한 예시를 봤다. 근데 함수제어자는 사실 함수처럼 argument를 받을 수 있다! 🤣
// 사용자의 나이를 저장하기 위한 매핑
mapping (uint => uint) public age;
// 사용자가 특정 나이 이상인지 확인하는 제어자
modifier olderThan(uint _age, uint _userId) {
require (age[_userId] >= _age);
_;
}
// 차를 운전하기 위햐서는 16살 이상이어야 하네(적어도 미국에서는).
// `olderThan` 제어자를 인수와 함께 호출하려면 이렇게 하면 되네:
function driveCar(uint _userId) public olderThan(16, _userId) {
// 필요한 함수 내용들
}
위의 예시에서는 orderThan()
이라는 modifier로 사용자가 특정 나이 이상인지 확인하고, 이 modifier를 사용해 driveCar()
라는 함수를 나이가 16살 이상인 유저만 호출할 수 있도록 만들었다.
신기하다. ✨
제어자는 안의 로직에서 require()
를 많이 사용한다.
require()
로 통과하면 호출한 함수의 내용을 실행할 수 있도록 _;
를 넣어준다.
우리는, 게임에서 특정 레벨 이상인지 확인하는 modifier를 만들어볼 것이다.
다음과 같이 코드를 작성하면 된다!
modifier aboveLevel(uint _level, uint _zombieId) {
require(zombies[_zombieId].level >= _level);
_;
}
그럼 이런식으로 쓸 수 있겠지: 레벨 2이상인 사용자만 좀비의 이름을 바꿀 수 있는 changeName()
호출 가능 💨
function changeName(uint _zombieId, string _newName) external aboveLevel(2, _zombieId) {
require(msg.sender == zombieToOwner[_zombieId]);
zombies[_zombieId].name = _newName;
}
😊