// 에드센스

오늘의 강의는 뭘까~용


1. 스마트 컨트랙 코드는 실행할때 돈이 든다. 

왜?

나의 트랜잭션을 블록에 넣어줄 마이너는 땅파서 컴퓨터를 돌려주는게 아니기때문.

 

얼마나 들까?

밑에서 대~강 구해봤다.

 

왜 알아야하나?

알아야 나중에 코딩할때 더 값싼 방법으로 코딩할 수 있으니까

 

가스비는 일반적으로 gwei로 표시되며, 이는 ETH의 10억분의 1(0.000000001 ETH)이다

 

이더리움의 수수료

수수료 = gas(gasLimit) * gasPrice

 

예시)

수수료 = gas(21000) * gasPrice(1gwei)

수수료 = 21000000000000gwei

이때, 1ETH = 10 ** 18wei이니까

 

수수료 = 0.00021ETH 가 된다.

 

gas와 gasPrice는 다음과 같은 차이점이 있다.

  • gas(gasLimit) : 본 송금 '작업'에서 소비되는 가스량
    (estimated 한 수치라서 변경가능하다. 하지만 넘 작게하면 거부됨)
  • gasPrice : 내가 가스당 지불할 가격
    (경매처럼 내가 금액을 제안하는 것임)

 

MAX TOTAL : gas * gasPrice 로 형성된 최종지불금액

gasPrice를 높게 잡을수록 이더리움 블록체인에서 마이너들이 내 트랜잭션을 빠르게 채굴해준다.

 

 

 

 

확인해보자

이더스캔에서 아무 트랜잭션이나 한번 봐보자

 

Transaction Fee(0.000739157072325) = gas(21000) * gasPrice(0.000000035197955825)

임을 확인할 수 있다.

 

Gas Limit & Usage by Txn은 뭐냐?

Gas Limit(앞에서 말한 gas와 동일)은 내가 이 값 이상으로는 가스비를 내지 않을 것이다라는 최대한도

Usage는 실제로 사용된 가스비를 의미

이 예시의 경우는 Limit의 100%를 사용했다.

 

넉넉하게 Gas Limit을 주면 알아서 최적의 가스비로 지불이 된다.

너무 GasLimit을 낮게주면 트랜잭션이 실패되니 넉넉하게 주자

 

 

 

 


2. 우리가 작성한 스마트컨트랙이 사용할 Gas를 대~강 계산해보자

가스비가 많이드는 연산: 블록체인의 용량을 늘리는 연산(저장하는 연산)

 

 

참고로 한 블록에서 사용가능한 가스비가 정해져있기에(Block Gas Limit) 무제한으로 용량을 늘리는(정보를 저장하는) 연산을 할 수 없다.

 

이 블록안에 있는 모든 트랜잭션 들이 사용할 수 있는 gas limit은 30,029,295이다.

이 값을 초과할 정도의 연산은 블록에 들어갈 수 없다.

 

이더리움의 가스비는 다음과 같이 정해져있다

  • 32Bytes 저장에 20000gas가 든다
  • 32Bytes 기존 변수에 있는 값을 바꿀때 5000gas
  • 기존변수를 초기화해서 더 이상 쓰지 않을때 10000gas return

 

 

Lottery.sol의 가스비를 파헤쳐보자

우리가 만든 Bet함수를 실행할 때 발생하는 가스비를 계산해보자

truffle console을 통해서 Bet함수를 실행시켜보았고 90846gas가 발생했다

 

 

연속으로 한번 더 실행하면 75846gas가 발생한다.

왜 갑자기 적어졌지? 끝에서 설명하겠다.

 

 

 

 

일단 우리가 작성한 코드를 보자

 

  function bet(bytes challenges) public payable returns (bool result) {
    // 돈이 제대로 왔는지 확인
    // require는 if역할, msg.value는 컨트랙트가 받은금액, 문자열은 조건이 false때 출력할 문구
    require(msg.value == BET_AMOUNT, 'Not Enough ETH');

    // 큐에 베팅정보를 넣기
    require(pushBet(challenges), 'Fail to add a new Bew Info');

    // 이벤트 로그를 찍는다
    // (몇번째 배팅인지, 누가 배팅했는지, 얼마 배팅했는지, 어떤글자로 베팅했는지, 어떤 블록에 정답이 있는지)
    emit BET(_tail - 1, msg.sender, msg.value, challenges, block.number + BET_BLOCK_INTERVAL);
    return true;
  }

 

이러한 Bet함수에서 pushBet을 호출하는 부분이벤트를 emit하는 부분에서 가스비가 든다.

즉, 첫번째 발생한 90846가스로 계산을 시작해보면

90846 = 기본가스(21000) + pushBet(???가스) + emit(대략 5000gas)

 

 

자 그러면 pushBet함수를 보자

  function pushBet(bytes challenges) internal returns (bool) {
    BetInfo memory b; 
    b.bettor = msg.sender; // address형 변수 사용 (1)
    b.answerBlockNumber = block.number + BET_BLOCK_INTERVAL; // uint256형 변수 사용 (2)
    b.challenges = challenges; // bytes형 변수 사용 (3)

    _bets[_tail] = b; // 그닥 크지 않다 (4)
    _tail++; // 32Byte형 변수 사용(5)

    return true;
  }

(1)번은 address형 변수를 사용했으므로 20Byte를 사용한 것

(3)번은 Byte형 변수를 사용했으므로 1Byte를 사용한 것

이더리움 블록체인에서 사용하는 기본저장단위는 32Byte다

 

즉, 20Byte를 사용했든 1Byte를 사용했든 둘 다 32Byte를 사용한 것이므로 64Byte를 사용한 것이 맞으나

작은 단위의 바이트에 대해서는 쪼개서(?) 연산해준다고 한다.

따라서 (1)번과 (3)번 합쳐서 32Byte를 사용한 셈 치면 된다.

(1) + (3) = 20000gas (32Byte)

 

(2)번은 uint256형 변수를 사용했으므로 32Byte 사용한 것

(2) = 20000gas (32Byte)

(4) = 무시

(5) = 20000gas (32Byte)

 

 

즉, pushBet에서 발생한 gas는 (1) + (2) + (3) + (4) + (5) = 60000gas

 

 

90846 = 기본가스(21000) + pushBet(60000gas가스) + emit(대략 5000gas)

90846 = 86000gas + 기타 자잘한 연산들

 

이라고 할 수 있다.

 

그러면 왜 2번째 실행했을때는 75846gas만 발생했느냐?

 

32Bytes 기존 변수에 있는 값을 바꿀때 5000gas가 들기때문이다.

  function pushBet(bytes challenges) internal returns (bool) {
    BetInfo memory b; 
    b.bettor = msg.sender; // 함수 호출한 사람
    b.answerBlockNumber = block.number + BET_BLOCK_INTERVAL; 
    b.challenges = challenges; 

    _bets[_tail] = b;
    _tail++; // 초기 0에서 1되는 것은 20000gas지만 1에서 2되는 것은 수정이므로 5000gas만 든다

    return true;
  }

즉 첫번째 실행보다 15000gas가 덜 발생한다.

90846 - 15000 = 75846

대강 맞는것을 확인할 수 있다.

+ Recent posts