以太坊的 Gas 机制

以太坊对智能合约的影响是深刻的,即使不用以太坊,只要做智能合约开发,就避免不了要学一下以太坊。而学习以太坊的第一天就肯定会碰到的概念就是 Gas ,这个就是咱们今天的主角,理解了 Gas 机制也就基本理解的智能合约的工作原理了。文章中首先介绍以太坊的账户和交易,以便介绍清楚智能合约工作的基本上下文,或者说让大家理解 Gas 使用的场景,接下来聊聊 Gas 的工作原理,让大家理解为啥已经有了以太币还要有 Gas ,最后深入到细节聊聊 gasPrice 和 gasLimit 这些交易参数的实际作用。

账户和交易

先进入第一部分,聊聊以太坊账户的分类,以及通过在各个账户间发交易都能完成哪些工作。

以太坊账户其实是分两类的。一类是普通账户,也被称为外部拥有账户,因为账户的拥有者在以太坊系统本身之外,是自然人。普通账户就类似于比特币账户了,两个普通账户之间可以发交易,但是交易的功能就基本局限于转账了。但是以太坊上还能发一种特殊的交易,叫做合约创建交易,这种交易的特点就是只有发送方,没有接受方,同时发送交易的时候也伴随着有代码上传到区块链。这种交易一旦发出,就会在以太坊系统上创建一个新的账户。这就是我们要介绍的第二类账户了,叫做合约账户。合约账户跟普通账户的区别是,合约账户是以太坊系统所拥有的账户,或者说账户的拥有者是机器,而不是自然人。另外,合约账户最大的特点就是内置代码,你肯定能猜到,这个代码就是智能合约了。发起智能合约创建交易的时候,如果有转账金额,那么这个金额也会存放到合约账户中,注意合约账户是不受自然人控制的。这样就有两点推论,第一点是机器从此实现了经济自由,拥有了自己的财产。第二点就是智能合约真正执行的时候,或者说合约账户要进行转账操作,过程是不受自然人控制的,这就是智能合约之所以可信的原因之一。

接下来详细聊聊交易。交易这个词在区块链领域,就比按咱们日常理解的交易的概念要稍微宽泛一些了。比如刚刚提过通过交易,我们能够实现转账操作,同时也能实现部署合约和创建合约账户的操作。但是,合约部署好了,普通账户跟合约之间如何交互呢,或者说合约跟合约之间如何交互呢?其实也是通过交易。我们知道,合约其实就是一个程序,有很多函数接口提供给外界。而调用这些接口的基本方式,一般就是通过发交易(如果是只读操作,可以不发交易)。而每次交易,其实都是要有交易手续费的,而 Gas 这个概念就是跟交易手续费分不开的。

理解账户和交易,就理解了智能合约运行的基本环境了,也大致知道了 Gas 的使用情形。

Gas 的原理

那么交易手续费为何不直接用以太币结算,为何要专门发明一个 Gas 的概念呢?接下来我们就来聊聊 Gas 的原理。

先来理解一下为何交易要收手续费。交易过程中是要花费以太坊的运算和存储资源的,由于以太坊是一个网络,每次运算,每个字节的存储,都需要全网的计算机共同去参与,所以在以太坊上进行任何的操作,本身就是很昂贵的。由于区块链都是去中心化系统,没有人给网络上的计算机,也就是矿工发工资,所以这部分费用当然要从让交易发出者来出了,具体来讲就是交易发出的时候,交易发出者要明确的去设置一下交易手续费。具体设置的方式,我们后面再细聊,总之交易手续费如果设置的太低,是没有矿工愿意处理这个交易的,所以发送交易也就会失败。那收手续费有没有什么潜在的好处呢?你会说收费是应该的,哪有什么好处啊?还别说,真有。简单来说就是一句话:防止资源浪费。以太坊上是可以执行任意的代码逻辑了,如果我不小心写了个死循环,那是不是代码会一直执行,把大家公有的网络资源都消耗光呢?答案是不会,等到交易手续费都耗光了,那么交易也就自动停止了。具体的原理我们稍后详细聊。

那么手续费为何不直接用以太币,而要发明 Gas 这个概念呢?答案其实很简单,因为以太币的价格是随时变动的,所以不能使用以太币作为手续费的计量单位。手续费应该是跟系统消耗的内存带宽硬盘等硬件资源相当的,所以合理的方式是需要找到一种相对美元稳定的设置手续费的方法。所以才有了 Gas 这个概念,注意 Gas 不是一种新的代币,而只是一个计量单位,也就是说,我不能持有100个 Gas 作为自己的财产。同时,Gas 只是起计价的作用,最终矿工收到的手续费还是以以太币来支付的。

如上所述,我们可以推论出,Gas 应该是跟以太币有一个兑换关系,同时这个兑换关系是浮动的,保证了交易手续费对美元是相对稳定的,而不是跟以太币相对稳定。

GasPrice 和 GasLimit

本文的最后一部分来深入到 Gas 的一些技术细节中,会涉及到 GasPrice 和 GasLimit 等概念。

先来看看以太坊上手续费到底是如何计算的。以太坊在执行智能合约的时候,会把代码分拆成很多个具体的步骤来完成,而每个步骤要消耗几个 Gas ,是系统代码决定的。比如我们看一下以太坊的源码 https://github.com/ethereum/go-ethereum/blob/master/params/protocol_params.go ,可以看到执行一个 copy 需要花3个 Gas ,执行一个 Sha3 哈希需要30个 Gas 。所以矿工最终得到的收费费,就是 Gas 的单价乘以总共消耗 Gas 的数量。也可以这么理解,以太坊系统就是个小时工,如果执行一个 copy 操作,他需要花费3个小时的劳动,而哈希操作要麻烦一些,所以他需要花30个小时才能完成,而一个 Gas 的数额就是交易发起人愿意付给他的每小时的工资的数额。

那么这个每小时工资如何确定呢?交易发起人在发出一个交易的时候,在交易的参数中有一项叫做 GasPrice ,也就是” Gas 价格”。这个价格的单位是 Gwei ,Gwei 是以太坊的一个单位,一个 Gwei 等于10的负九次方个以太币。所以通过 GasPrice 的设置,就能确定本次交易中一个 Gas 到底对应多少以太币了。具体这个值设置多少才比较合适呢,https://ethgasstation.info/ 上会给出此时此刻的参考值,我写本文的时候,一个 Gas 推荐设置是 5.4 Gwei ,大概是2美分。

交易的各项参数中除了 GasPrice 还有另外一项也是跟 Gas 紧密相关,也就是 GasLimit 。GasLimit 的数值就是执行本次交易可以花费的 Gas 的最大数量。比方我设置成1000 ,意味着本次交易中,我愿意的支付的手续费上限就是1000 个 Gas 。如果实际中消耗的 Gas 数量大于1000了,交易就会失败,如果小于1000,就按实际花费的数额去收费。通过 GasLimit 的设置可以防止在程序不小心进入死循环的时候堵塞网络,或者耗尽我账户上的所有以太币。

所以说,了解了交易中设置的 GasPrice 和 GasLimit 就理解了 Gas 的技术细节了。

总结

最后来总结一下本文要点。理解以太坊的账户分普通账户和合约账户两种,并知道账户之间可以通过交易来进行互操作,可以进行转账也可以操纵合约的接口。每次执行合约接口的时候,执行代码和存储数据都是要收费的,这个就体现为本次交易的手续费。手续费的度量单位是 Gas ,每次交易的时候通过设置不同的 GasPrice 来对冲以太币价格的浮动,以便给出一个相对于美元比较稳定的交易手续费。同时可以在发送交易的时候设置 GasLimit ,来限制本次交易花费的 Gas 总数量的上限。