以太坊 eth gas
Q:gas是什么?
gas是指在以太坊上执行操作所需的燃料。
以太坊提供了虚拟机(EVM,Ethereum Virtual Machine),开发者可以在其上开发各种应用。EVM相对BTC的好处是“图灵完备”,但这带来一个潜在风险,就是一个程序可能无休止的运行下去,对EVM而言,这是不能容忍的。
所以,运行程序要花gas。就好比开车要花油费或电费,油或电用完了,车自然会停下来。
Q:gas、gas价格、gas费是一个东西吗?
太好了,你能注意到这点。汽油和汽油费显然也不一样,对吧。
你使用EVM执行一个交易,需要若干个gas,这被称为gas数。类似于油的升数、电的度数。
而每一个gas都是需要花钱的,gas有价格,称为gasprice。这类似于一升汽油的价格、一度电的价格。
gas费就是gas数乘以gas价格。
比如,你想部署一个合约,需要3,000,000个gas,gasprice是200gwei。那么你要花的钱是:
3* 10^6 * 200 gwei = 3* 10^6 * 200 * 10^(-9) = 0.6 ETH
gasprice的计量单位为:gwei,一个gwei为是1g个wei,即10^9 wei。
由于1 wei = 10^(-18) ETH,所以: 1 gwei = 10^9 wei = 10^(-9) ETH。
wei是ETH的最小单位,以b-money的创造者Wei Dai的名字命名。
gwei的发音为ge wei (音:各位,念快一点:贵)。
Q:gasprice由谁来定?
gas的价格不像我们所想象的,由政府统一定价,No!
也不是由矿工定价。
gas的价格由交易的发送者来指定,在伦敦升级之前,发送者在交易中要指定两个值,一个是gaslimit,一个是gasprice。
Q:为什么以太坊的gasprice这么贵?
因为以太坊流行,很多人都想在上面执行交易,谁出的价格高,谁的交易就更可能被矿工执行并打入区块,矿工显然喜欢更高的gas费。
所以,这更像是一个拍卖,想交易的人给出各种gasprice,矿工优先选择那些出价高的上链。
Q:那么,gaslimit是什么?
越复杂的运算,需要消耗的gas越多。交易发送者有时候也搞不清自己需要花多少gas费来执行操作,所以需要加上一个消耗gas的上限,避免自己的钱一不小心被花光了。
发送者设置一个gaslimit,如果没有花到这个数,会打回剩余的值。
如果gaslimit耗尽还未执行完交易,EVM会抛出异常,结束代码执行,回退发生的变更。不过,但由于矿工们已经干了活,花费了成本,所以,已经花掉的gas是不退的。
所以,gaslimit要宁可高一点,也不要太低,因为高了没关系,没花完的会退回来,低了,一旦out of gas,不仅你想要的操作没有完成,而且消耗的gas也不会退你,可谓鸡飞蛋打一场空。
一个示例:
张三向李四转移1 ETH(也即ether的transfer操作)。 张三将gaslimit设为3万,gasprice设为200 gwei。 以太坊规定,transfer操作花费21000个gas,所以实际发生总费用是: 21,000 * 200 = 4,200,000 gwei,即0.0042 ETH。 这样,张三发送1.006 ETH,李四获得1 ETH,矿工获得0.0042 ETH,然后退还张三0.0018 ETH。 张三虽然将gaslimit设为3万,但实际只花了2.1万个gas,实际支出1.0042 ETH。 但如果张三将gaslimit设置为1万,这个操作就无法完成,而且10000个gas也没了,白白损失10000*200=200万gwei=0.002 ETH。
Q:gas数到底是怎么算的?
具体的计算有点复杂,但有标准可以查。你可以在GitHub上的 evm-opcode 和 DynamicgasCosts 查看。
在EVM里面,每个运算、操作、存储都需要gas的,比如:
- ADD:加法操作 3gas
- MUL:乘法操作 5gas
- SUB:减法操作 3gas
- DIV:除法操作 5gas
- JUMP:跳转操作 8gas
- MSTORE:内容存储操作 3gas
- MLOAD:内容读取操作 3gas
- CREATE:创建合约 32000gas (if tx.to == null)
- SSTORE:存入存储区 20000gas (从0设为非0值)
- SHA3:Keccak256哈希 30gas + 6gas * (size of input in words) + mem_expansion_cost
- 交易基本费用:21000gas (比如Transfer就要这么多)
Q:有没有什么方便的方法让我计算gaslimit?
1、你的钱包会帮你算,你的开发工具会帮你算。
2、Web3有两个内置的函数可以用,web3.eth.getgasprice可以提供gasprice的设置建议,estimategas可以估算一个函数(带参数)需要花的gas。
3、如果你想看看一个合约的函数调用花了多少gas,你可以去etherscan.io这种网站看看已经发生的这样的交易实际花了多少gas(gas Used by Transaction)。
Q:具体交易时,我该如何指定这两个值?
一般而言,钱包或者开发工具,会帮你做好这两件事。
比如,在小狐狸中,供用户选择的有三个选项:高、中、低。
你不需要亲自指定gaslimit和gasprice,你顶多只需要选择高、中、低就好了。
高中低的含义是这样的:
大致的意思就是,如果你想让你的交易快点执行,就选择高费用,如果不着急,就选择低费用。
现在大致展示一下,不同的选择会带来什么变化。
这是一个Transfer交易,在中等费用情况下,是这样的:
如果选择高费用,小狐狸会自动计算提供如下:
如果选择低费用,则如下:
这里面的 “燃料限制” 就是刚才讲过的gaslimit,但是并没有出现刚才说的gasprice,而是出现了最高优先费用(max priority fee)和最高费用(max fee),这是因为在伦敦升级后,gas费有了新的规则,下面会介绍。
Q:不仅仅是交易有gaslimit,区块也有gaslimit?
每个block有gas的上限,即区块内所有交易的gas总数,达到这个上限,就必须出块了,不能再往区块里打入新的交易了。而这个上限,是矿工投票投出来的。
伦敦升级后的上限是30M,即3千万个gas。注意不是30M的存储空间,是30M个gas。
一个区块中包含的gas总数可以称为区块的大小。
Q:伦敦升级到底带来了什么变化?
伦敦升级后,区块的大小是弹性的,目标大小是15M,上限是30M。
伦敦升级后,gas费总额计算仍然是:gaslimit * gasprice。
但gasprice分为两部分:
gasprice = baseFee+ Tip
其中basefee(基本费用)由协议根据区块大小自动计算,但这部分会被烧掉,矿工也拿不到。
矿工只能拿到Tip。Tip就是小费,或者书面一点,称之为优先费用(PriorityFee)。
当区块比15M大的时候,gas的价格就会上升(通过自动调节basefee),目的是让更多的交易望而却步,这样区块大小就会缩回到15M;反之,区块小于15M时,gasprice就会便宜,交易就会增多,这样,区块大小就总是在目标大小左右浮动。
下面是伦敦升级后gas费计算的一个示例:
张三给李四转1个ETH。 gaslimit为21,000,basefee为100 gwei,Tip为10 gwei,可以计算得出gas费为21,000 * (100 + 10) = 2,310,000 gwei,即0.00231 ETH。 当张三汇款时,1.00231 ETH将从张三的账户中扣除。李四将得到1个ETH。基本费用为0.0021 ETH会被烧掉,矿工获得0.00021 ETH的Tip。
Q:这些值如何设置?
当然这些也都由钱包或开发工具帮用户设置了。
basefee不用设置(钱包也不管),是以太坊通过算法,自动根据上一个block的大小和上一个basefee计算出来的。
为了让用户更好地控制自己的钱,实际交易中,设置的是maxfee(愿意给出的最大gasprice)和maxpriorityfee(愿意给出的最大Tip)。
maxfee必须要大于basefee,然后,矿工会按如下的算法计算Tip:
Tip = min(maxpriorityfee, maxfee - basefee)
如果maxfee > basefee + Tip,多余的费用就会被矿工退回交易发送者。
比如:
张三给李四转1个ETH。 gaslimit为21,000,maxfee为150 gwei,maxpriorityfee设为10 gwei。 basefee为100 gwei,所以,Tip= min( 10,150-100) = 10 gwei,可以计算得出gas费为21,000 * (100 + 10) = 2,310,000 gwei,即0.00231 ETH。 当张三汇款时,21000 * 150 = 1.00315 ETH将从张三的账户中扣除。李四将得到1个ETH。基本费用为0.0021 ETH会被烧掉,矿工获得0.00021 ETH的Tip,矿工退回张三0.00084 ETH(即21000 * 40 gwei)。
注意一点:上面说的maxfe、basefee、Tip,都是针对per gas的,计算真正费用的时候,还需要乘上gas数。
你在不同场合看到的这些符号,有些是带pergas的,有些不带,注意要区分一下,一般指的都是pergas的。
还有一点,如果将maxfee和和maxpriorityfee设置为相同的值,maxfee就相当于以前的gasprice了。
Q:那么,basefee究竟是怎么自动计算出来的?
basefee是由以太坊的协议自动计算的,该算法将上一个区块的大小与目标大小(15M)进行比较。如果超过目标块大小,下一个块的基本费用将按照比目标块多出的比例增加,最多将增加12.5%。
比如一个块是30M,达到了最高限,它的大小比目标大小多出一倍,它的basefee就是上一个basefee的112.5%。
如果区块一直保持在30M的大小,每个basefee都比上一个要高出12.5%,这就产生了指数级的增长,basefee高到人们舍不得交易的时候,区块大小自然就会回落。
在EIP-1559中,描述了这个算法的具体细节:
Note: // is integer division, round down. BASE_FEE_MAX_CHANGE_DENOMINATOR = 8 if parent_gas_used == parent_gas_target: expected_base_fee_per_gas = parent_base_fee_per_gas elif parent_gas_used > parent_gas_target: gas_used_delta = parent_gas_used - parent_gas_target base_fee_per_gas_delta = max(parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR, 1) expected_base_fee_per_gas = parent_base_fee_per_gas + base_fee_per_gas_delta else: gas_used_delta = parent_gas_target - parent_gas_used base_fee_per_gas_delta = parent_base_fee_per_gas * gas_used_delta // parent_gas_target // BASE_FEE_MAX_CHANGE_DENOMINATOR expected_base_fee_per_gas = parent_base_fee_per_gas - base_fee_per_gas_delta
Q:交易报文中会体现这些值吗?
会的,下面是一个交易的示例:
{ from: "0xEA674fdDe714fd979de3EdF0F56AA9716B898ec8", to: "0xac03bb73b6a9e108530aff4df5077c2b3d481e5a", gaslimit: "21000", maxFeePergas: "300", maxPriorityFeePergas: "10", nonce: "0", value: "10000000000" }
在传统交易报文中,用户直接指定gasprice;而在如上的EIP-1559交易报文中,用户指定的是MaxFeePerGas和MaxPriorityFeePerGas。
实际上你为每gas支付的单价是:
min( MaxPriorityFeePerGas + basefee, MaxFeePerGas )
值得注意的是,在可预见的未来,用户仍然可以使用传统的交易格式来发送交易,但这种格式可能最终会在协议层被废弃。
下一章:以太坊 指标测量与监控
以太坊使用开源的指标测量工具 go-metrics 来对系统各模块的功能和性能指标进行测量,并对go-metrics的使用做了些简单的封装。指标测量与监控功能,默认关闭。可通过在启动geth时指定参数 --metri ...