[Blockchain] 크립토 좀비 lesson4 (Solidity)

공효은·2022년 3월 4일
0

Blockchain

목록 보기
9/10
post-thumbnail

지금 까지 꽤 많은 함수 제어자(function modifier)를 다뤘다. 한 번 빠르게 복습해보쟝!

  1. 함수가 언제, 어디서 호출될 수 있는지 제어하는 접근 제어자(visiblilty modifier) 를 알게 되었다.

    private: 컨트랙트 내부의 다른 함수들에서만 호출 될 수 있다.
    internal: private과 비슷하지만, 해당 컨트랙트를 상속하는 컨트랙트에서도 호출 될 수 있다.
    external: 오직 컨트랙트 외부에서만 호출 될 수 있다.
    public: 내 외부 모두에서, 어디든 호출 될 수있다.

  2. 상태 제어자(state modifier) 이 제어자는 블록체인과 상호작용 하는 방법에 대해 알려준다.

    view: 해당 함수를 실행해도 어떤 데이터도 저장/변경 되지 않음을 알려준다.
    pure: 해당 함수가 어떤 데이터도 블록체인에 저장하지 않을 뿐아니라, 블록체인으로부터 어떤 데이터도 읽지 않음
    이들 모두는 컨트랙트 외부에서 불렀을 때 가스를 전혀 소모하지 않는다.(하지만 다른 함수에 의해 내부적으로 호출됐을 경우에는 가스를 소모한다.)

  3. 그리고 사용자 정의 제어자에 대해서도 배웠다. ex (onlyOwner, aboveLevel) 이런 제어자를 사용해서 우린 함수에 이 제어자들이 어떻게 영향을 줄지를 결정하는 우리만의 논리를 구성할 수 있다.

Payable 제어자

payable함수는 솔리디티와 이더리움을 아주 멋지게 만드는것 중 하나다! 이는 이더를 받을 수 있는 특별한 함수 유형이다.

일반적인 웹 서버에서 api 함수를 실행할 때, 함수 호출을 통해서 US달러를 보낼 수 없다. (비트코인도)

하지만 이더리움에서는, 돈(이더), 데이터(transaction payload) 그리고 컨트랙트 코드 자체 모두 이더리움 위에 존재하기 떄문에 함수를 실행하는 동시에 컨트랙트에 돈을 지불하는 것이 가능하다.

이를 통해 굉장히 흥미로운 구성을 만들어 낼 수 있다. 함수를 실행하기 위해 컨트랙트에 일정 금액을 지불하게 하는 것과 깉다.

예시

contract Onlinestore {
  function buySomething() external payable {
    //함수 실행에 0.001 이더가 보내졌는지 확실 히 하기 위해 확인
    require(msg.value == 0.001 ether);
    //보내졌다면, 함수를 호출한 자에게 디지털 아이템을 전달하기 위한 내용 구성
    transferThing(msg.sender);
  }
}

여기서 msg.value는 컨트랙로 이더가 얼마나 보내졌는지 확인하는 방법이고, ether는 기본적으로 포함된 단위이다

여기서 일어난는 일은 누군가 web3.js(DApp의 자바스크립트 프론트엔드)에서 다음과 같이 함수를 실행할 때 발생한다.

//OnlineStore은 이더리움 상의 컨트랙트를 가리킨다고 가정
OlineStore.buySomthing({from:web3.eth.defaultAccount, value: web3.utils.toWei(0.001)})

자바스크립트 함수 호출에서 value 필드를 통해 ether를 얼마 보낼지 결정한다. 트랜잭션을 봉투로 생각하고, 함수 호출에 전달하는 매개 변수를 편지의 내용이라고 생각한다면, value는 봉투안에 현금을 넣는것 과 같다. 편지와 돈이 모두 수령인에게 전달 된다.

만약 함수가 payable로 표시 되지 않았는데 이더를 보내려 한다면, 함수에서 트랜잭션을 거부한다.

출금

컨트랙터에 이더를 보내는 방법을 배웠다. 그럼 이더를 보낸 다음엔 어떤 일이 일어날까?
컨트랙트로 이더를 보내면, 해당 컨트랙트의 이더리움 계좌에 이더가 저장되고 거기에 갇히게 된다. (만약 컨트랙트로 부터 이더를 인출하는 함수를 만들지 않는다면)

contract GetPaid is Ownable{
  function withdraw() external onlyOwner {
    owner.transfer(this.balance);
  }

우리가 Ownable 컨트랙트를 import 했다고 가정하고 owner와 onlyOwner를 사용하고 있다.

transfer 함수를 사용해서 이더를 특정 주소로 전달 할 수 있다. 그리고 this.balance는 컨트랙트에 저장돼있는 전체 잔액을 반환한다. 그러니 100명의 사용자가 우리 컨트랙트에 1이더를 지불했다면, this.balance는 100이더가 된다.

transfer함수를 써서 특정한 이더리움 주소에 돈을 보낼 수 있다. 예를 들어 만약 누군가 한 아이템에 대해 초과 지불을 했다면, 이더를 message.sender로 되돌려주는 함수를 만들 수 있다.

uint itemFee = 0.001 ether;
msg.sender.transfer(msg.value - itemFee);

혹은 구매자와 판매자가 존재하는 컨트랙트에서, 판매자의 주소를 storage에 저장하고, 누군가 판매자의 아이템을 구매하면 구매자로부터 받은 요금을 그에게 전달 할 수도 있다: seller.transfer(msg.value);

난수(Random Numbers)

keccak256을 통한 난수 생성

솔리디티에서 난수를 만들기에 가장 좋은 방법은
keccak256 해시 함수를 쓰는것이다.

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

이 예시에서는 now의 타임스탬프 값, msg.sender, 증가하는 nonce(딱 한 번만 사용되는 숫자, 즉 똑같은 입력으로 두 번 이상 동일한 해시 함수를 실행할 수 없게 함)를 받는다.

그리고 keccak을 사용하여 이 입력들을 임의의 해시 값으로 변환하고, 변환한 해시 값을 uint로 바꾼 후, % 100을 써서 마지막 2자리 숫자만 받는다. 이를 통해 0~99사이에 완전한 난수를 얻을 수 있다.

profile
잼나게 코딩하면서 살고 싶어요 ^O^/

0개의 댓글