2023. 6. 15. 09:59ㆍBlockchain/Ethereum
※ 원글 작성 : 22년 8월 3일
Gas는 ethereum 네트워크를 구성할 시 필수적으로 사용되는 비용이다. Gas의 여러 정보들을 확인해본다.
Gas
Ethereum의 gas란 EVM 상에서 transaction을 동작시키기 위해 소모되는 비용이다.
예를 들어, solidity contract를 작성 후 ethereum 상에 바이트코드를 deploy 하면 해당 바이트코드를 동작하는 OPcode 마다 정해진 gas를 소모한다. 이렇게 OPcode 등의 계산에 대해 수수료를 gas로 요구하면 solidity 내의 무한 루프를 방지하여 계산으로 인한 throughput을 줄여 네트워크 혼잡도를 낮출 수 있고, 악의적으로 네트워크를 스팸하는 것 또한 방지가 가능하다.
Gas는 ethereum의 네이티브 코인인 ETH를 사용하며, 일반적으로 gwei 단위로 표기된다. gwei는 10^-9 ETH이며, 10^9 wei이다.
Transaction 발생 수수료인 gas fee는 gasPrice
와 gasLimit
의 곱으로 계산된다. Transaction을 발생시킨 account가 실행시키기 위해 지불할 의향이 있는 최대 금액이며, gasLimit
은 단위의 개수(unit), gasPrice
는 단위 당 금액으로 생각하면 편하다.
Gas for transaction
먼저, 일반적인 transaction을 처리하는 과정에서 gas가 사용되는 부분을 요약한다.
- 각 user, node가 발생시킨 transaction을 블록에 포함하여 mining 하기 위해 miner들은 Txpool에서 가져온다.
- 수집한 transaction들을 발생시킨 account의 nonce와 transaction 발생 시 설정한
gasPrice
로 순서를 정한다. - Miner는 transaction에 설정한 gas fee (
gasPrice
XgasLimit
)를 transaction 생성 account로 부터 가져온다. (여기서gasLimit
은 일반적인 transaction의 경우 21000 이다.) - Transaction을 실행하며 gas를 사용한다.
- 실행 후 설정된
gasLimit
을 제한 잔여 gas는 transaction 발생시킨 account에게 돌려준다. - 실행한 모든 transaction들을 블록에 담는다. 담은 transaction들의 총
gasLimit
은blockGasLimit
을 초과할 수 없다.
만약 4.에서 transaction 실행 시 gas가 부족하다면 실행 시켰던 것을 취소하고, state 변경이 되지 않는다. 이때 사용된 gas는 account에게 환불되지 않는다. 또한 여기서의 blockGasLimit
이란, 한 블록에 담을 수 있는 gas의 총량을 말한다.
Gas for contract
Solidity contract를 deploy, invoke 시에는 사용되는 gas 계산이 조금 다르다.
Deploy
Deploy에는 기본적으로 많은 gas가 필요하다. 일반적인 transaction이 가지는 gasLimit
뿐만 아니라 그 외에도 여러 gas parameter가 사용되고 등록되는 solidity의 크기, 즉 ABI 상의 function, input, output에 따른 gas fee가 upload하는 contract에 따라 수수료가 천차만별로 다양할 수 있다. 일반적으로 사용되는 gas parameters는 아래와 같다.
- 기본 transaction 비용 = 21000
- contract 시 생성 비용 = 32000
- 배포된 코드의 바이트당 비용 = 200
- constructor (생성자) 비용
- tx 데이터 = 0이아닌 경우 64바이트, 0인경우 4바이트
또한 contract storage를 위해서도 gas가 필요한데, ethereum white paper 상에는 256bit 당 20,000의 gas fee가 소모된다.
Invoke(execute)
Contract 실행시에는 위에서도 언급했던것처럼 OPcode의 마다, solidity 내의 기능 마다 소모되는 gas량이 다르다. OPcode 별 사용되는 gas의 정리는 해당 페이지에서 확인할 수 있다. Remix에서 기본적으로 제공하는 1_Storage.sol 파일의 bytecode를 예시로 본다.
{
...
"object": "608060405234801561001...",
"opcodes": "PUSH1 0x80 PUSH1 0x40 MSTORE CALLVALUE DUP1 ISZERO PUSH2 0x10 JUMPI PUSH1 0x0 ...
...
}
실제로 contract에 등록되는 object
와 이 코드가 어떤 기능을 수행하는지를 확인하는 opcodes
parameter가 존재한다.
OP code | Name | Minimum gas | Description |
---|---|---|---|
60 | PUSH1 | 3 | Place 1 byte item on stack |
52 | MSTORE | 3 | Save word to memory |
34 | CALLVALUE | 2 | Get deposited value by the instruction/transaction responsible for this execution |
... | ... | ... | ... |
JSON에서 확인할 수 있는 opcode 당 사용되는 최소 gas양을 확인할 수 있고, 그에 따라 contract invoke시에 소모되는 gas amount를 지불해야 한다. Bytecode로 인한 gas fee외에도 invoke 자체가 transaction을 발생시켜 contract의 state를 변경시키는 행위이기 때문에 transaction 발생을 위한 gas가 별도로 소모된다.
EIP 1559
Ethereum gas를 얘기할 때 London hardfork를 빼놓을 수 없는데, EIP 1559를 도입한 fork이다. Github-EIP 1559에는 simple summary로
A transaction pricing mechanism that includes fixed-per-block network fee that is burned and dynamically expands/contracts block sizes to deal with transient congestion.
정리되어 있다. 즉, ETH 가격이 폭등하여 gas fee도 덩달아 급증할 시 block size 조절과 fee의 분류(base fee, priority fee, max fee)를 통해 gas fee 안정화로, 예측할 수 있는 gas fee로 조절하겠다는 것이다.
Ethereum block은 모두 동일한 크기를 가져서, transaction이 많이 발생하여 네트워크 혼잡 시 block 생성에 대기하는 transaction이 많아진다. 이로 인해 유저들은 더 많은 gas fee를 제출하고 block에 빨리 포함되도록 하여 transaction confirm 시간을 단축하려 했다. 블록크기를 변동할 수 있게 된다면 transaction이 늘어났을 때 집중되는 거래량이 수용이 되어 위와 같은 현상을 방지할 수 있게 된다.
이전의 gas fee는 miner에게 보상으로 돌아갔지만, EIP 1559를 통해 fee의 분배가 달라졌다. 기본적으로 gas fee에 사용되는 base fee와 miner에게 채굴 보상으로 돌아가는 priority fee로 세분화 되었다. (base fee + priority fee <= max fee) 또한, 추가되는 정책도 존재하여서, EIP 1559를 통해 얻을 수 있는 이점은 여러가지가 있다.
- Base fee는 블록마다 최대 12.5%만 늘어나는 정책에 따라 gas fee 급등을 방지한다.
- Base fee는 소각되고 priority fee만 miner에게 돌아가며, fast transaction을 위한 priority fee에 대해서만 miner간 경쟁으로 gas fee 급등을 방지한다.
- Transaction이 더 많이 발생할 시 base fee가 증가하지만, Base fee가 소각되므로 ETH의 희소 가치는 증가한다.
- Block 크기를 조절하여서 네트워크 혼잡 시에도 gas 값이 요동치지 않는다.
- gas fee의 변동성이 적어지고, 예측 가능한 범위로 측정되기 때문에 유저가 낭비하는 gas량이 줄어든다.
Gas station처럼 빠른 transaction 전송을 위한 필요 priority fee 정보를 제공해주는 사이트도 있기 때문에 ethereum 사용자의 gas fee 낭비가 많이 줄어들었다.
Functions related to gas of go-ethereum
Geth 내에서 gas 계산을 지원하는 부분을 확인해본다.
// go-ethereum/params/protocol_params.go
package params
import "math/big"
const (
GasLimitBoundDivisor uint64 = 1024 // The bound divisor of the gas limit, used in update calculations.
MinGasLimit uint64 = 5000 // Minimum the gas limit may ever be.
MaxGasLimit uint64 = 0x7fffffffffffffff // Maximum the gas limit (2^63-1).
GenesisGasLimit uint64 = 4712388 // Gas limit of the Genesis block.
MaximumExtraDataSize uint64 = 32 // Maximum size extra data may be after Genesis.
ExpByteGas uint64 = 10 // Times ceil(log256(exponent)) for the EXP instruction.
SloadGas uint64 = 50 // Multiplied by the number of 32-byte words that are copied (round up) for any *COPY operation and added.
CallValueTransferGas uint64 = 9000 // Paid for CALL when the value transfer is non-zero.
CallNewAccountGas uint64 = 25000 // Paid for CALL when the destination address didn't exist prior.
TxGas uint64 = 21000 // Per transaction not creating a contract. NOTE: Not payable on data of calls between transactions.
TxGasContractCreation uint64 = 53000 // Per transaction that creates a contract. NOTE: Not payable on data of calls between transactions.
TxDataZeroGas uint64 = 4 // Per byte of data attached to a transaction that equals zero. NOTE: Not payable on data of calls between transactions.
...
Parameter로 지정된 gas 종류만 하더라도 약 100개가 존재한다. 앞서 언급된 기본 transaction gasLimit
이 TxGas
로 정의되어 있고, sodlidity contract 배포 시에 생성 비용인 32000을 더한 53000의 값이 TxGasContractCreate
의 param으로 정의되어 있는 것을 확인할 수 있다.
// go-ethereum/ethclient/ethclient.go
// EstimateGas tries to estimate the gas needed to execute a specific transaction based on
// the current pending state of the backend blockchain. There is no guarantee that this is
// the true gas limit requirement as other transactions may be added or removed by miners,
// but it should provide a basis for setting a reasonable default.
func (ec *Client) EstimateGas(ctx context.Context, msg ethereum.CallMsg) (uint64, error) {
var hex hexutil.Uint64
err := ec.c.CallContext(ctx, &hex, "eth_estimateGas", toCallArg(msg))
if err != nil {
return 0, err
}
return uint64(hex), nil
}
// SuggestGasPrice retrieves the currently suggested gas price to allow a timely
// execution of a transaction.
func (ec *Client) SuggestGasPrice(ctx context.Context) (*big.Int, error) {
var hex hexutil.Big
if err := ec.c.CallContext(ctx, &hex, "eth_gasPrice"); err != nil {
return nil, err
}
return (*big.Int)(&hex), nil
}
ethclient에서는 method로 EstimateGas()
와 SuggestGasPrice()
를 제공한다. EstimateGas
는 주어진 블록 number에서 transaction을 실행하기 위한 gas를 찾고, client에 제공을 해주며, SuggestGasPrice
는 latest 블록에서 부터 일정수의 블록(default 20)을 검색하여 gasPrice
를 query해준다.
Conclusion
Gas의 개념은 플랫폼의 안정성을 보장하기 위한 보안 대책이며, miner에게 보상하여 ethereum governance를 유지할 수 있게 하는 원동력이었다. 하지만 ETH의 가격이 상승함에 따라 gas의 절대적인 price도 증가하게 되었다. Ethereum 구성원에게는 큰 부담으로 작용하고, miner pool만 비대해지며 많은 computing power를 소모하여 환경 문제로까지 번지는 결과를 초래했다. 이러한 문제점들을 개선하기 위한 노력들이 현재까지도 지속되고 있으며, 결과적으로 ethereum 2.0의 PoS 도입 시 miner의 제거까지 바라본다.
PoS 기반의 많은 체인들도 ethereum이 도입한 gas를 transaction 발생 시 사용하고 있다. 결국은, Gas라는 작다면 작은 chain의 구성품이 현재까지 블록체인 생태계를 만든 기초가 되었으리라 생각해본다.
참고
https://ethereum.org/ko/developers/docs/gas/
https://www.preethikasireddy.com/post/how-does-ethereum-work-anyway
https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1559.md
'Blockchain > Ethereum' 카테고리의 다른 글
ENS(Ethereum Name Service) (0) | 2023.06.15 |
---|---|
Ethereum의 PoS 전환을 반기며 (0) | 2023.06.15 |
Ethereum Bootnode 기능 확인 (0) | 2023.06.14 |
Ethereum [5] (Go-Ethereum) (0) | 2023.06.13 |
Ethereum [4] (EVM) (0) | 2023.06.13 |