오늘의 강의는 뭘까~용
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
대강 맞는것을 확인할 수 있다.
'Block Chain' 카테고리의 다른 글
[BlockChain] 크립토좀비 레슨1 (0) | 2023.02.10 |
---|---|
[BlockChain] Move 언어 (0) | 2023.02.03 |
[Dapp 만들기] 3. 스마트 컨트랙을 테스트해보자 (0) | 2022.06.28 |
[Dapp 만들기] 2. Lottery.sol 작성하기 (0) | 2022.06.28 |
[Dapp 만들기] 1. 앞으로 구현할 Lottery Dapp 미리보기 (1) | 2022.06.28 |