커버 이미지의 출처는 다음과 같습니다 : https://cryptozombies.io/ko/

크립토좀비 사이트 내용을 정리하였으며, 컨텐츠 관련 모든 권리는 Loom Network에 있습니다.

4) payable 함수와 DApp 그리고 복습

1. Payable

함수 제어자(function modifier) 복습

접근 제어자(Visibility Modifier)
상태 제어자(State Modifier)
(사용자 정의) 제어자
function test() external view onlyOwner anotherModifier { /* ... */ }

payable 제어자

contract OnlineStore {
  function buySomething() external payable {
    // 함수 실행에 0.001이더가 보내졌는지 확실히 하기 위해 확인:
    require(msg.value == 0.001 ether);
    // 보내졌다면, 함수를 호출한 자에게 디지털 아이템을 전달하기 위한 내용 구성:
    transferThing(msg.sender);
  }
}
// `OnlineStore`는 이더리움 상의 컨트랙트를 가리킨다고 가정:
OnlineStore.buySomething({from: web3.eth.defaultAccount, value: web3.utils.toWei(0.001)})

2. 출금

contract GetPaid is Ownable {
  function withdraw() external onlyOwner {
    owner.transfer(this.balance);
  }
}
uint itemFee = 0.001 ether;
msg.sender.transfer(msg.value - itemFee);
seller.transfer(msg.value);

3. 난수(Random Numbers) - keccak256을 통한 난수 생성

난수 생성 예시

// Generate a random number between 1 and 100:
uint randNonce = 0;
uint random = uint(keccak256(now, msg.sender, randNonce)) % 100;
randNonce++;
uint random2 = uint(keccak256(now, msg.sender, randNonce)) % 100;

위 예시의 문제점

  1. 이더리움에서는 컨트랙트의 함수를 시행하면 트랜잭션(transaction) 으로 네트워크의 노드 하나 또는 여러 노드에 실행을 알림
  2. 그 후, 네트워크의 노드들은 여러 개의 트랜잭션을 모으고, “작업 증명”으로 알려진 계산이 매우 복잡한 수학적 문제를 먼저 풀기 위한 시도를 하게 됨
  3. 그리고 해당 트랜잭션 그룹을 그들의 작업 증명(PoW) 과 함께 블록 으로 네트워크에 배포하게 됨
  4. 한 노드가 어떤 PoW 를 풀면, 다른 노드들은 그 PoW 를 풀려는 시도를 멈추고 해당 노드가 보낸 트랜잭션 목록이 유효한 것인지 검증함
  5. 유효하다면 해당 블록을 받아들이고 다음 블록을 풀기 시작함

아래와 같은 경우가 있어 위의 난수 함수를 취약하게 만듬

  1. 나는 오직 나의 노드에만 트랜잭션을 알리고 이것을 공유하지 않을 수 있음
  2. 그 후 내가 이기는지 확인하기 위해 동전 던지기 함수를 실행함
  3. 만약 내가 진다면, 내가 풀고 있는 다음 블록에 해당 트랜잭션을 포함하지 않는 것을 선택할 수 있음
  4. 이러한 행위를 내가 동전 던지기에서 이기고 다음 블록을 풀 까지 무한대로 반복하여 이득을 볼 수 있음

이더리움에서는 어떻게 난수를 안전하게 만들어 낼 수 있을까?

4. 공통 로직 구조 개선하기(Refactoring)

require(msg.sender == zombieToOwner[_zombieId]);
at4am의 프로필 이미지

at4am

2019년 06월 13일

글쓴이의 더 많은 글 읽어보기