이더리움 가스에 대한 이해: Gas Price, Gas Limit, Block Gas Limit

조상연
9 min readJul 20, 2018

--

20180722 조상연

개요: 이더리움을 이해하는 핵심 중 하나인 가스와 머클 패트리샤 트리(World State)에 대해서 심도 있게 다뤄본다.

Gas

  1. 가스란 무엇인가
  2. 가스는 어떻게 책정되는가
  3. 우린 가스를 어떻게 설정할까

1. 가스란 무엇인가

가스 = 말 그대로 연료를 의미하며, EVM 상에서 트랜잭션을 동작시키기 위해 소모되는 비용이다. 비트코인의 수수료 개념에서 좀 더 진화된 개념으로 코드의 복잡성에 따라 다르게 측정된다. 기본적으로 21000Gas를 소모한다. 이는 Won으로 따지면 약 10원 정도이다. (ETH 50만원 기준) 어떻게 이런 계산이 나올까? 가스(Gas) 라고 하는 것의 ether의 단위 중 하나인 gwei를 의미한다. 이더의 최소 단위는 소수점이 18인 wei이고, gwei는 1,000,000wei 즉 백만 wei이다. ether랑 비교하자면, 0.1 ^ 9 ether = 1 gwei 이다. 21000 Gas는 21000gwei 이고, 즉 0.000000021 이더이다. 여기에 현 시세를 곱하면 기본 가스비가 측정된다.

1 wei = 0.1¹⁸ ether

1 gwei = 10⁹ wei = 0.1⁹ ether

2. 가스는 어떻게 책정되는가

실제 가스 계산에서 세 가지 개념이 더 필요하다. 바로 Gas Price, Gas Limit, 그리고 Block Gas Limit 이다. 이 셋 중에 앞 2개는 사용자가 설정하며, 후자는 이더리움 마이너들이 각자 설정한다. 이 세 가지 개념을 이해하기 위해선 마이너의 트랜잭션 처리 과정을 가스 사용 측면으로 볼 필요가 있다.

  1. 마이너들이 블록에 담을 트랜잭션들을 TxPool 에서 가져온다.
  2. 트랜잭션 들을 각 주소 별 Nonce(순서)와 GasPrice로 순서를 정한다.
  3. 마이너들이 트랜잭션에 설정된 값 (Gas Limit * Gas Price)만큼을 발신 주소로부터 가스로 가져온다.
  4. 트랜잭션을 실행하며 명령어에 따라 가스를 소모한다. Gas Limit보다 남는 가스는 다시 돌려주지만 가스가 모자랄 경우 돌려주지 않고 실행했던 것을 되돌린다.
  5. 실행된 트랜잭션 들을 블록에 담는다. 이때 이 트랜잭션들의 개별 Gas Limit의 총합은 Block Gas Limit을 넘을 수 없다.

물론 훨씬 더 복잡한 과정이 존재한다. require 문을 통한 Error일 경우엔 다시 가스를 반납해준다는 등 여러 Case가 존재하지만 이번 글에선 여기까지만 다루도록 한다.

위 과정에서 Gas Price는 Gas Limit에서 소모되는 1 Gas 당 가격으로 처음 정렬에 영향을 미치는 것을 볼 수 있다. 즉 Gas Price를 높게 설정하면 그만큼 빠르게 블록에 포함될 수 있지만, n배 만큼 가스비가 늘어난다. Gas Limit은 (Gas Price를 곱하기 전) 소모될 가스비의 예측치이다. Gas Limit을 너무 낮게 설정하면 실제 소모 가스가 Gas Limit을 넘어 Out of Gas문제가 발생할 수 있다. 그렇다고 또 너무 높게 설정한다면 Block Gas Limit으로 인해 블록에 담길 수 없는 문제가 발생한다. 여기서 Block Gas Limit이란 블록에 담길 수 있는 트랜잭션 Gas Limit의 총합으로 현재 약 8백만 Gas 이다. 이론적으로 기본 21000 Gas 트랜잭션이 한 블록에 최대 380개 담길 수 있다는 의미이다. 하지만 실제로는 컨트랙트 코드도 실행되기 때문에 그보다 적다.

정리하자면

Gas Limit: 사용할 가스에 대한 예측치 / 넉넉하면 좋지만, 너무 높을 시 거절 당할 수 있음
Gas Price: Gas Limit에서 1 Gas 당 가격, 높을 수록 빨리 실행된다.
총 비용 : Gas Limit 중 실제 사용량 * Gas Price
Block Gas Limit: 한 블록에 넣을 수 있는 Gas Limit의 총합

Block Gas Limit 현황

최근의 Block Gas Limit의 경향을 보게되면 2017년 말에 상승이후 유지하는 추세이다. 2017년 중반 이전만 하더라도 5백만 언저리였던걸 보면 괄목할 만한 성장이다. 비트코인의 블록 사이즈인 1MB를 두고 늘리느냐 마느냐로 논쟁이 이어지는 것과는 달리 이더리움에선 훨씬 유동적으로 설정이 가능함을 볼 수 있다. 마이너 들은 실제로 채굴기에서 이 값을 조정할 수 있다. 하지만 마음대로 설정하진 않고 마이닝풀에서 투표를 통해 결정하고 있다. 그 결과 마이닝풀별로 Block Gas Limit이 다르다.

채굴자별 Block Gas Limit와 투표 현황

실제 Geth 내 코드를 통해 위 과정을 보면 아래와 같다.

transactions := self.eth.TxPool().GetTransactions()
types.SortByPriceAndNonce(transactions)
work.commitTransactions(self.mux, transactions, self.gasPrice, self.chain)
self.eth.TxPool().RemoveTransactions(work.lowGasTxs)

원본 Github

func SortByPriceAndNonce(txs []*Transaction) {
// Separate the transactions by account and sort by nonce
byNonce := make(map[common.Address][]*Transaction)
for _, tx := range txs {
acc, _ := tx.From() // we only sort valid txs so this cannot fail
byNonce[acc] = append(byNonce[acc], tx)
}
for _, accTxs := range byNonce {
sort.Sort(TxByNonce(accTxs))
}
// Initialize a price based heap with the head transactions
byPrice := make(TxByPrice, 0, len(byNonce))
for acc, accTxs := range byNonce {
byPrice = append(byPrice, accTxs[0])
byNonce[acc] = accTxs[1:]
}
heap.Init(&byPrice)

// Merge by replacing the best with the next from the same account
txs = txs[:0]
for len(byPrice) > 0 {
// Retrieve the next best transaction by price
best := heap.Pop(&byPrice).(*Transaction)

// Push in its place the next transaction from the same account
acc, _ := best.From() // we only sort valid txs so this cannot fail
if accTxs, ok := byNonce[acc]; ok && len(accTxs) > 0 {
heap.Push(&byPrice, accTxs[0])
byNonce[acc] = accTxs[1:]
}
// Accumulate the best priced transaction
txs = append(txs, best)
}
}

3. 우린 가스를 어떻게 측정할까

위 사진은 Etherscan에서 각 블록별 GasUsed / Gas Limit / 평균 Gas Price를 보여주고 있다. 보면 대부분 가스 사용량이 Gas Limit에 대해 99% 근접하고 있다. 몇몇 특이 케이스의 경우 Gas Limit과 Gas Price를 매우 넉넉한 것으로 볼 수 있다.

트랜잭션은 크게 2가지 종류로 단순한 이더리움 송금(transactions)과 Contract를 실행시키는 트랜잭션(contract internal transactions)이 있다. 이더리움 송금은 210000 Gas가 기본으로 100% 사용률이 가능하지만 Contract 실행은 코드의 복잡성에 따라 천차만별이다. 어떻게 이걸 예측해서 Gas Limit을 결정할 수 있을까? 답은 간단하게도 실제로 계산을 해보는 것이다. 명령어별로 이미 Gas Fee는 공개가 되어있으며 개발자는 자신의 Solidity 코드가 어느 정도의 Gas가 들지 예측할 수 있다.

ethereum Yellow Paper Gas Fee Schedule

물론 하나 하나 계산하진 않고, 계산을 도와주는 여러 툴을 이용해 그 값을 예측할 수 있다. 이 계산이 중요한 이유는 개발자의 코드가 실제 서비스 이용료에 큰 영향을 미치기 때문이다. 간단한 예를 들어 보자.

uint256 num1 = 10**18
uint256 num2 = 1000000000000000000

두 변수 중 num1은 18제곱 계산을 하느라 gas를 더 소모하지만 num2는 한번에 그 값을 gas 소모 없이 넣을 수 있다. 단순한 코드 가독성을 넘어 실제 코드의 동작까지 염두해야 한다는 것이다.

결론

이번 글에선 이더리움에서 가스가 무엇인지,그 구성과 측정에 대해서 알아보았다. Gas는 이더리움이 다른 블록체인과 다른 특징 중 하나로 주로 개선점으로 많이 지적되곤 한다. 그만큼 실제 서비스에 이더리움을 사용할 때 주요 장애물로 여겨지고 있으며 비탈릭도 이를 분명히 인식하고 있다. 하지만 Gas는 World Computer 라 불리우는 이더리움에서 코드 실행의 경중을 측정하고 블록 당 트랜잭션 수를 제한하는 기능을 수행하는 매우 중요하고 기발한 아이디어이다. 또한 많은 개발자로 하여금 코드를 최적화하도록 강요하는 매우 강력한 인센티브이며 마이너 들에겐 부가적인 수익 구조이다. 이러한 Gas는 여러 블록체인 플랫폼에게 큰 영감을 주었으며 예를 들어 EOS는 그 비용을 개발자가 치루게 하는 구조를 통해 해결을 꾀하고 있다.

다음은 이더리움의 거대한 저장소 State Trie를 구성하는 머클 패트리샤 트라이를 좀 더 자세히 다룰 예정이다.

머클 패트리샤 트라이

  1. 이더리움의 3가지 트리와 World State
  2. 패트리샤 트라이에 대한 이해
  3. 4가지 노드로 이해하는 머클 패트리샤 트라이

--

--

Responses (2)